diff --git a/.github/actions/copy_env_files/action.yml b/.github/actions/copy_env_files/action.yml new file mode 100644 index 00000000..eab2b654 --- /dev/null +++ b/.github/actions/copy_env_files/action.yml @@ -0,0 +1,25 @@ +name: Copy Environment Files +description: "Copies environment files based on branch" +runs: + using: "composite" + steps: + - name: Copy Environment Files + shell: bash + run: | + cp ./.github/workflows/models-config.json ./proxy-router/models-config.json + cp ./.github/workflows/models-config.json models-config.json + cp ./.github/workflows/rating-config.json ./proxy-router/rating-config.json + cp ./.github/workflows/rating-config.json rating-config.json + if [[ "${GITHUB_REF}" == "refs/heads/main" ]]; then + cp ./.github/workflows/proxy-router.main.env ./proxy-router/.env + cp ./.github/workflows/proxy-router.main.env .env + cp ./.github/workflows/ui-desktop.main.env ./ui-desktop/.env + elif [[ "${GITHUB_REF}" == "refs/heads/test" ]]; then + cp ./.github/workflows/proxy-router.test.env ./proxy-router/.env + cp ./.github/workflows/proxy-router.test.env .env + cp ./.github/workflows/ui-desktop.test.env ./ui-desktop/.env + else + cp ./.github/workflows/proxy-router.test.env ./proxy-router/.env + cp ./.github/workflows/proxy-router.test.env .env + cp ./.github/workflows/ui-desktop.test.env ./ui-desktop/.env + fi \ No newline at end of file diff --git a/.github/actions/gen_tag_name/action.yml b/.github/actions/gen_tag_name/action.yml new file mode 100644 index 00000000..36bb09ea --- /dev/null +++ b/.github/actions/gen_tag_name/action.yml @@ -0,0 +1,33 @@ +name: Generate Tag Name +description: "Generates a tag name based on branch" +runs: + using: "composite" + steps: + - name: Determine tag name + id: tag + shell: bash + run: | + VMAJ=1 + VMIN=0 + VPAT=0 + set +o pipefail + VLAST=$(git describe --tags --abbrev=0 --match='v[1-9]*' refs/remotes/origin/main 2>/dev/null | cut -c2-) + [ $VLAST ] && declare $(echo $VLAST | awk -F '.' '{print "VMAJ="$1" VMIN="$2" VPAT="$3}') + if [ "$GITHUB_REF_NAME" = "main" ] + then + VPAT=0 + VMIN=$((VMIN+1)) + VFULL=${VMAJ}.${VMIN}.${VPAT} + VTAG=v$VFULL + else + MB=$(git merge-base refs/remotes/origin/main HEAD) + VPAT=$(git rev-list --count --no-merges ${MB}..HEAD) + VFULL=${VMAJ}.${VMIN}.${VPAT} + RNAME=${GITHUB_REF_NAME##*/} + [ "$GITHUB_EVENT_NAME" = "pull_request" ] && RNAME=pr${GITHUB_REF_NAME%/merge} + VTAG=v${VFULL}-${RNAME} + fi + echo "VLAST=$VLAST VMAJ=$VMAJ VMIN=$VMIN VPAT=$VPAT VFULL=$VFULL VTAG=$VTAG" + echo "TAG_NAME=${VTAG}" >> $GITHUB_ENV + echo "VTAG=${VTAG}" >> $GITHUB_ENV + echo "VFULL=${VFULL}" >> $GITHUB_ENV diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 5011c6c1..982f6573 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1,4 +1,4 @@ -name: CI +name: CI-CD on: workflow_dispatch: @@ -7,10 +7,15 @@ on: description: 'Create new release' required: true type: boolean + push: branches: - main + - test + - concom + - dev paths: ['.github/workflows/**', '**/Makefile', '**/*.go', '**/*.json', '**/*.yml', '**/*.ts', '**/*.js'] + pull_request: types: [opened, reopened, synchronize] paths: ['.github/workflows/**', '**/Makefile', '**/*.go', '**/*.json', '**/*.yml', '**/*.ts', '**/*.js'] @@ -22,19 +27,87 @@ concurrency: defaults: run: shell: bash - + jobs: + GitLab-Deploy: + if: ${{ github.repository != 'MorpheusAIs/Morpheus-Lumerin-Node' && (github.event_name == 'push' && (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/test' || github.ref == 'refs/heads/dev')) }} + runs-on: ubuntu-latest + steps: + - name: Clone + id: checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 + fetch-tags: true + + - name: Install dependencies + run: | + sudo apt-get update && sudo apt-get install -y jq + + - name: Generate Tag Name + uses: ./.github/actions/gen_tag_name + + - name: Determine GitLab Target Branch + id: set_target_branch + run: | + if [ "${{ github.ref_name }}" == "dev" ]; then + echo "gitlab_branch=dev" >> $GITHUB_ENV + elif [ "${{ github.ref_name }}" == "test" ]; then + echo "gitlab_branch=stg" >> $GITHUB_ENV + elif [ "${{ github.ref_name }}" == "main" ]; then + echo "gitlab_branch=main" >> $GITHUB_ENV + else + echo "This branch is not configured to trigger GitLab pipelines." + exit 1 + fi + + - name: Trigger GitLab Pipeline + run: | + echo "Triggering GitLab Build and Deploy for branch ${{ github.ref_name }} with tag ${{ env.TAG_NAME }}" + + # Send request to GitLab + response=$(curl --silent \ + --request POST \ + --url "${{ secrets.GITLAB_TRIGGER_URL }}" \ + --form "token=${{ secrets.GITLAB_TRIGGER_TOKEN }}" \ + --form "ref=${{ env.gitlab_branch }}" \ + --form "variables[SOURCE_REPO]=${{ github.repository }}" \ + --form "variables[SOURCE_BRANCH]=${{ github.ref_name }}" \ + --form "variables[GITHUB_VFULL]=${{ env.VFULL }}" \ + --form "variables[GITHUB_TAG]=${{ env.TAG_NAME }}") + + # Parse JSON response using jq + gitlab_status=$(echo "$response" | jq -r '.status // "unknown"') + gitlab_web_url=$(echo "$response" | jq -r '.web_url // "N/A"') + + # Log the response + echo "GitLab Response: $response" + + # Validate the status field + if [[ "$gitlab_status" =~ ^(created|preparing|success|running|scheduled)$ ]]; then + echo "GitLab pipeline triggered successfully! Status: $gitlab_status" + echo "Pipeline details: $gitlab_web_url" + else + echo "GitLab pipeline FAILED. Invalid status: $gitlab_status" + echo "Pipeline details: $gitlab_web_url" + exit 1 + fi + Ubuntu-22-x64: + if: ${{ github.repository != 'MorpheusAIs/Morpheus-Lumerin-Node' }} runs-on: ubuntu-22.04 steps: - name: Clone - uses: actions/checkout@v4 id: checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 + fetch-tags: true - name: Setup Go uses: actions/setup-go@v5 with: - go-version: '1.21.x' + go-version: '1.22.x' cache-dependency-path: | launcher/go.sum proxy-router/go.sum @@ -55,58 +128,66 @@ jobs: cd ../ui-desktop yarn install --network-timeout 600000 + - name: Copy Environment Files + uses: ./.github/actions/copy_env_files + + - name: Generate Tag Name + uses: ./.github/actions/gen_tag_name + - name: Build id: build run: | cd launcher make cd ../proxy-router - cp ./models-config.json.example ../ui-desktop/models-config.json make build cd ../cli make build cd ../ui-desktop - cp ./.env.example .env + echo "Injecting version ${VFULL} into package.json" + sed -i "s/\"version\": \".*\"/\"version\": \"${VFULL}\"/" package.json + cat package.json | grep '"version"' # Optional: Verify the change yarn build:linux - - name: Determine tag name - id: tag - run: | - SHORT_HASH="$(git rev-parse --short=7 HEAD)" - echo "name=${SHORT_HASH}" >> $GITHUB_OUTPUT - - name: Pack artifacts id: pack_artifacts run: | - ARTIFACT=mor-launch-${{ steps.tag.outputs.name }}-ubuntu-x64.zip + VFULL=${VFULL:-0.0.1} + echo "VFULL: $VFULL" + ARTIFACT="mor-launch-$TAG_NAME-ubuntu-x64.zip" + echo "Artifact: $ARTIFACT" LLAMACPP=llama-b3256-bin-ubuntu-x64.zip MODEL=tinyllama-1.1b-chat-v1.0.Q4_K_M.gguf wget -nv https://github.com/ggerganov/llama.cpp/releases/download/b3256/$LLAMACPP wget -nv https://huggingface.co/TheBloke/TinyLlama-1.1B-Chat-v1.0-GGUF/resolve/main/$MODEL unzip -o -j $LLAMACPP build/bin/llama-server - echo '{"run":["./llama-server -m ./'$MODEL'","./proxy-router","./ui-desktop-1.0.0.AppImage"]}' > mor-launch.json - cp ./proxy-router/.env.example .env - cp ./proxy-router/models-config.json.example models-config.json + echo '{"run":["./llama-server -m ./'"$MODEL"'","./proxy-router","./morpheus-ui-'"$VFULL"'-x86_64-linux.AppImage"]}' > mor-launch.json + echo "Contents of mor-launch.json: " + cat mor-launch.json mv ./cli/mor-cli mor-cli - zip -j $ARTIFACT ./LICENSE ./launcher/mor-launch llama-server ./proxy-router/bin/proxy-router .env $MODEL mor-launch.json ./ui-desktop/dist/ui-desktop-1.0.0.AppImage models-config.json mor-cli + zip -j $ARTIFACT ./LICENSE ./launcher/mor-launch llama-server ./proxy-router/bin/proxy-router .env $MODEL mor-launch.json ./ui-desktop/dist/morpheus-ui-$VFULL-x86_64-linux.AppImage models-config.json rating-config.json mor-cli - name: Upload artifacts uses: actions/upload-artifact@v4 with: - path: mor-launch-${{ steps.tag.outputs.name }}-ubuntu-x64.zip + path: mor-launch-${{ env.TAG_NAME }}-ubuntu-x64.zip name: mor-launch-ubuntu-x64.zip - macOS-12-x64: - runs-on: macos-12 + macOS-13-x64: + if: ${{ github.repository != 'MorpheusAIs/Morpheus-Lumerin-Node' }} + runs-on: macos-13 steps: - name: Clone - uses: actions/checkout@v4 id: checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 + fetch-tags: true - name: Setup Go uses: actions/setup-go@v5 with: - go-version: '1.21.x' + go-version: '1.22.x' cache-dependency-path: | launcher/go.sum proxy-router/go.sum @@ -125,62 +206,69 @@ jobs: cd ../proxy-router go mod download cd ../ui-desktop + python3 -m pip install setuptools yarn install --network-timeout 600000 + - name: Copy Environment Files + uses: ./.github/actions/copy_env_files + + - name: Generate Tag Name + uses: ./.github/actions/gen_tag_name + - name: Build id: build run: | cd launcher make cd ../proxy-router - cp ./models-config.json.example ../ui-desktop/models-config.json make build cd ../cli make build cd ../ui-desktop - cp ./.env.example .env + echo "Injecting version ${VFULL} into package.json" + sed -i "" "s/\"version\": \".*\"/\"version\": \"${VFULL}\"/" package.json + cat package.json | grep '"version"' # Optional: Verify the change yarn build:mac - - name: Determine tag name - id: tag - run: | - SHORT_HASH="$(git rev-parse --short=7 HEAD)" - echo "name=${SHORT_HASH}" >> $GITHUB_OUTPUT - - name: Pack artifacts id: pack_artifacts run: | - ARTIFACT=mor-launch-${{ steps.tag.outputs.name }}-macos-x64.zip + ARTIFACT="mor-launch-$TAG_NAME-macos-x64.zip" + echo "Artifact: $ARTIFACT" LLAMACPP=llama-b3256-bin-macos-x64.zip MODEL=tinyllama-1.1b-chat-v1.0.Q4_K_M.gguf wget -nv https://github.com/ggerganov/llama.cpp/releases/download/b3256/$LLAMACPP wget -nv https://huggingface.co/TheBloke/TinyLlama-1.1B-Chat-v1.0-GGUF/resolve/main/$MODEL unzip -o -j $LLAMACPP build/bin/llama-server - echo '{"run":["./llama-server -m ./'$MODEL'","./proxy-router","./ui-desktop.app/Contents/MacOS/ui-desktop"]}' > mor-launch.json - cp ./proxy-router/.env.example .env - cp ./proxy-router/models-config.json.example models-config.json + echo '{"run":["./llama-server -m ./'$MODEL'","./proxy-router","./MorpheusUI.app/Contents/MacOS/MorpheusUI"]}' > mor-launch.json + echo "Contents of mor-launch.json: " + cat mor-launch.json mv ./cli/mor-cli mor-cli - unzip ./ui-desktop/dist/ui-desktop-1.0.0-mac.zip - zip -j $ARTIFACT ./LICENSE ./launcher/mor-launch ./proxy-router/bin/proxy-router .env llama-server $MODEL mor-launch.json models-config.json mor-cli - zip -r $ARTIFACT ui-desktop.app + unzip ./ui-desktop/dist/morpheus-ui-${VFULL}-x64-mac.zip + zip -j $ARTIFACT ./LICENSE ./launcher/mor-launch ./proxy-router/bin/proxy-router .env llama-server $MODEL mor-launch.json models-config.json rating-config.json mor-cli + zip -r $ARTIFACT 'MorpheusUI.app' - name: Upload artifacts uses: actions/upload-artifact@v4 with: - path: mor-launch-${{ steps.tag.outputs.name }}-macos-x64.zip + path: mor-launch-${{ env.TAG_NAME }}-macos-x64.zip name: mor-launch-macos-x64.zip macOS-14-arm64: + if: ${{ github.repository != 'MorpheusAIs/Morpheus-Lumerin-Node' }} runs-on: macos-14 steps: - name: Clone - uses: actions/checkout@v4 id: checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 + fetch-tags: true - name: Setup Go uses: actions/setup-go@v5 with: - go-version: '1.21.x' + go-version: '1.22.x' cache-dependency-path: | launcher/go.sum proxy-router/go.sum @@ -199,62 +287,69 @@ jobs: cd ../proxy-router go mod download cd ../ui-desktop + brew install python-setuptools yarn install --network-timeout 600000 + - name: Copy Environment Files + uses: ./.github/actions/copy_env_files + + - name: Generate Tag Name + uses: ./.github/actions/gen_tag_name + - name: Build id: build run: | cd launcher make cd ../proxy-router - cp ./models-config.json.example ../ui-desktop/models-config.json make build cd ../cli make build cd ../ui-desktop - cp ./.env.example .env + echo "Injecting version ${VFULL}} into package.json" + sed -i "" "s/\"version\": \".*\"/\"version\": \"${VFULL}\"/" package.json + cat package.json | grep '"version"' # Optional: Verify the change yarn build:mac - - name: Determine tag name - id: tag - run: | - SHORT_HASH="$(git rev-parse --short=7 HEAD)" - echo "name=${SHORT_HASH}" >> $GITHUB_OUTPUT - - name: Pack artifacts id: pack_artifacts run: | - ARTIFACT=mor-launch-${{ steps.tag.outputs.name }}-macos-arm64.zip + ARTIFACT="mor-launch-$TAG_NAME-macos-arm64.zip" + echo "Artifact: $ARTIFACT" LLAMACPP=llama-b3256-bin-macos-arm64.zip MODEL=tinyllama-1.1b-chat-v1.0.Q4_K_M.gguf wget -nv https://github.com/ggerganov/llama.cpp/releases/download/b3256/$LLAMACPP wget -nv https://huggingface.co/TheBloke/TinyLlama-1.1B-Chat-v1.0-GGUF/resolve/main/$MODEL unzip -o -j $LLAMACPP build/bin/llama-server - echo '{"run":["./llama-server -m ./'$MODEL'","./proxy-router","./ui-desktop.app/Contents/MacOS/ui-desktop"]}' > mor-launch.json - cp ./proxy-router/.env.example .env - cp ./proxy-router/models-config.json.example models-config.json + echo '{"run":["./llama-server -m ./'$MODEL'","./proxy-router","./MorpheusUI.app/Contents/MacOS/MorpheusUI"]}' > mor-launch.json + echo "Contents of mor-launch.json: " + cat mor-launch.json mv ./cli/mor-cli mor-cli - unzip ./ui-desktop/dist/ui-desktop-1.0.0-arm64-mac.zip - zip -j $ARTIFACT ./LICENSE ./launcher/mor-launch ./proxy-router/bin/proxy-router .env llama-server $MODEL mor-launch.json models-config.json mor-cli - zip -r $ARTIFACT ui-desktop.app + unzip ./ui-desktop/dist/morpheus-ui-${VFULL}-arm64-mac.zip + zip -j $ARTIFACT ./LICENSE ./launcher/mor-launch ./proxy-router/bin/proxy-router .env llama-server $MODEL mor-launch.json models-config.json rating-config.json mor-cli + zip -r $ARTIFACT 'MorpheusUI.app' - name: Upload artifacts uses: actions/upload-artifact@v4 with: - path: mor-launch-${{ steps.tag.outputs.name }}-macos-arm64.zip + path: mor-launch-${{ env.TAG_NAME }}-macos-arm64.zip name: mor-launch-macos-arm64.zip Windows-avx2-x64: + if: ${{ github.repository != 'MorpheusAIs/Morpheus-Lumerin-Node' }} runs-on: windows-latest steps: - name: Clone - uses: actions/checkout@v4 id: checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 + fetch-tags: true - name: Setup Go uses: actions/setup-go@v5 with: - go-version: '1.21.x' + go-version: '1.22.x' cache-dependency-path: | launcher/go.sum proxy-router/go.sum @@ -266,9 +361,10 @@ jobs: cache: 'yarn' cache-dependency-path: ui-desktop/yarn.lock - - name: Install wget + - name: Install wget and sed run: | choco install wget --no-progress + choco install sed --no-progress - name: Install dependencies run: | @@ -279,68 +375,74 @@ jobs: cd ../ui-desktop yarn install --network-timeout 600000 + - name: Copy Environment Files + uses: ./.github/actions/copy_env_files + + - name: Generate Tag Name + uses: ./.github/actions/gen_tag_name + - name: Build id: build run: | cd launcher make cd ../proxy-router - cp ./models-config.json.example ../ui-desktop/models-config.json make build cd ../cli make build cd ../ui-desktop - cp ./.env.example .env + echo "Injecting version ${VFULL} into package.json" + sed -i "s/\"version\": \".*\"/\"version\": \"${VFULL}\"/" package.json + cat package.json | grep '"version"' # Optional: Verify the change yarn build:win - - name: Determine tag name - id: tag - run: | - SHORT_HASH="$(git rev-parse --short=7 HEAD)" - echo "name=${SHORT_HASH}" >> $GITHUB_OUTPUT - - name: Pack artifacts id: pack_artifacts run: | - ARTIFACT=mor-launch-${{ steps.tag.outputs.name }}-win-x64.zip + VFULL=${VFULL:-0.0.1} + echo "VFULL: $VFULL" + ARTIFACT="mor-launch-$TAG_NAME-win-x64.zip" + echo "Artifact: $ARTIFACT" LLAMACPP=llama-b3256-bin-win-avx2-x64.zip MODEL=tinyllama-1.1b-chat-v1.0.Q4_K_M.gguf wget -nv https://github.com/ggerganov/llama.cpp/releases/download/b3256/$LLAMACPP wget -nv https://huggingface.co/TheBloke/TinyLlama-1.1B-Chat-v1.0-GGUF/resolve/main/$MODEL unzip -o -j $LLAMACPP llama-server.exe llama.dll ggml.dll - echo '{"run":["./llama-server.exe -m ./'$MODEL'","./proxy-router.exe","./ui-desktop-1.0.0.exe"]}' > mor-launch.json - cp ./proxy-router/.env.example.win .env - cp ./proxy-router/models-config.json.example models-config.json + echo '{"run":["./llama-server.exe -m ./'"$MODEL"'","./proxy-router.exe","./morpheus-ui-'"$VFULL"'-x64-win.exe"]}' > mor-launch.json + echo "Contents of mor-launch.json: " + cat mor-launch.json + mv .env .env.tmp + sed 's|\./data/|.\\data\\|g' .env.tmp > .env mv ./proxy-router/bin/proxy-router proxy-router.exe mv ./cli/mor-cli mor-cli.exe mv ./launcher/mor-launch mor-launch.exe - mv "./ui-desktop/dist/ui-desktop 1.0.0.exe" ui-desktop-1.0.0.exe - 7z a $ARTIFACT LICENSE mor-launch.exe proxy-router.exe .env llama-server.exe llama.dll ggml.dll $MODEL mor-launch.json ui-desktop-1.0.0.exe models-config.json mor-cli.exe + mv "./ui-desktop/dist/morpheus-ui-$VFULL-x64-win" morpheus-ui-$VFULL-x64-win.exe + 7z a $ARTIFACT LICENSE mor-launch.exe proxy-router.exe .env llama-server.exe llama.dll ggml.dll $MODEL mor-launch.json morpheus-ui-$VFULL-x64-win.exe models-config.json rating-config.json mor-cli.exe - name: Upload artifacts uses: actions/upload-artifact@v4 with: - path: mor-launch-${{ steps.tag.outputs.name }}-win-x64.zip + path: mor-launch-${{ env.TAG_NAME }}-win-x64.zip name: mor-launch-win-x64.zip release: - if: ${{ ( github.event_name == 'push' && github.ref == 'refs/heads/main' ) || github.event.inputs.create_release == 'true' }} + if: ${{ github.repository != 'MorpheusAIs/Morpheus-Lumerin-Node' && (github.event_name == 'push' && (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/test' || github.ref == 'refs/heads/concom' )) || github.event.inputs.create_release == 'true' }} runs-on: ubuntu-latest needs: - Ubuntu-22-x64 - - macOS-12-x64 + - macOS-13-x64 - macOS-14-arm64 - Windows-avx2-x64 steps: - name: Clone id: checkout uses: actions/checkout@v4 + with: + fetch-depth: 0 + fetch-tags: true - - name: Determine tag name - id: tag - run: | - SHORT_HASH="$(git rev-parse --short=7 HEAD)" - echo "name=${SHORT_HASH}" >> $GITHUB_OUTPUT + - name: Generate Tag Name + uses: ./.github/actions/gen_tag_name - name: Download artifacts id: download-artifact @@ -360,7 +462,8 @@ jobs: env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: - tag_name: ${{ steps.tag.outputs.name }} + tag_name: ${{ env.TAG_NAME }} + prerelease: ${{ github.ref != 'refs/heads/main' }} - name: Upload release id: upload_release diff --git a/.github/workflows/models-config.json b/.github/workflows/models-config.json new file mode 100644 index 00000000..49fa043a --- /dev/null +++ b/.github/workflows/models-config.json @@ -0,0 +1,11 @@ +{ + "$schema": "https://raw.githubusercontent.com/Lumerin-protocol/Morpheus-Lumerin-Node/a719073670adb17de6282b12d1852d39d629cb6e/proxy-router/internal/config/models-config-schema.json", + "models": [ + { + "modelId": "0x0000000000000000000000000000000000000000000000000000000000000000", + "modelName": "llama2", + "apiType": "openai", + "apiUrl": "http://localhost:8080/v1" + } + ] +} diff --git a/.github/workflows/proxy-router.main.env b/.github/workflows/proxy-router.main.env new file mode 100644 index 00000000..d786c36e --- /dev/null +++ b/.github/workflows/proxy-router.main.env @@ -0,0 +1,36 @@ +# This file is used to set the environment variables for the cicd workflow +# Contract and Token current as of 11/15/2024 +# Full ENV details can be found in /docs/proxy-router.full.env +# Includes both TestNet and MainNet values, uncomment sections as desired + +# Wallet_Private_Key is not needed if you will be running the MorpheusUI in conjunction with proxy-router +WALLET_PRIVATE_KEY= + +# MAINNET VALUES (only MAINNET or TESTNET section should be uncommented) +DIAMOND_CONTRACT_ADDRESS=0xDE819AaEE474626E3f34Ef0263373357e5a6C71b +MOR_TOKEN_ADDRESS=0x092bAaDB7DEf4C3981454dD9c0A0D7FF07bCFc86 +EXPLORER_API_URL="https://api.arbiscan.io/api" +ETH_NODE_CHAIN_ID=42161 + +# TESTNET VALUES +# DIAMOND_CONTRACT_ADDRESS=0xb8C55cD613af947E73E262F0d3C54b7211Af16CF +# MOR_TOKEN_ADDRESS=0x34a285a1b1c166420df5b6630132542923b5b27e +# EXPLORER_API_URL="https://api-sepolia.arbiscan.io/api" +# ETH_NODE_CHAIN_ID=421614 + +# COMMON +PROXY_ADDRESS=0.0.0.0:3333 +WEB_ADDRESS=0.0.0.0:8082 +WEB_PUBLIC_URL=http://localhost:8082 +MODELS_CONFIG_PATH= +RATING_CONFIG_PATH= +ETH_NODE_USE_SUBSCRIPTIONS=false +ETH_NODE_ADDRESS= +ETH_NODE_LEGACY_TX=false +PROXY_STORE_CHAT_CONTEXT=true +# PROXY_STORAGE_PATH=.\data\ (for windows) +PROXY_STORAGE_PATH=./data/ +LOG_COLOR=true + +# Set to true to reset mac keychain on start (MorpheusUI only on Mac) +APP_RESET_KEYCHAIN=false \ No newline at end of file diff --git a/.github/workflows/proxy-router.test.env b/.github/workflows/proxy-router.test.env new file mode 100644 index 00000000..5adf136f --- /dev/null +++ b/.github/workflows/proxy-router.test.env @@ -0,0 +1,36 @@ +# This file is used to set the environment variables for the cicd workflow +# Contract and Token current as of 11/15/2024 +# Full ENV details can be found in /docs/proxy-router.full.env +# Includes both TestNet and MainNet values, uncomment sections as desired + +# Wallet_Private_Key is not needed if you will be running the MorpheusUI in conjunction with proxy-router +WALLET_PRIVATE_KEY= + +# MAINNET VALUES (only MAINNET or TESTNET section should be uncommented) +# DIAMOND_CONTRACT_ADDRESS=0xDE819AaEE474626E3f34Ef0263373357e5a6C71b +# MOR_TOKEN_ADDRESS=0x092bAaDB7DEf4C3981454dD9c0A0D7FF07bCFc86 +# EXPLORER_API_URL="https://api.arbiscan.io/api" +# ETH_NODE_CHAIN_ID=42161 + +# TESTNET VALUES +DIAMOND_CONTRACT_ADDRESS=0xb8C55cD613af947E73E262F0d3C54b7211Af16CF +MOR_TOKEN_ADDRESS=0x34a285a1b1c166420df5b6630132542923b5b27e +EXPLORER_API_URL="https://api-sepolia.arbiscan.io/api" +ETH_NODE_CHAIN_ID=421614 + +# COMMON +PROXY_ADDRESS=0.0.0.0:3333 +WEB_ADDRESS=0.0.0.0:8082 +WEB_PUBLIC_URL=http://localhost:8082 +MODELS_CONFIG_PATH= +RATING_CONFIG_PATH= +ETH_NODE_USE_SUBSCRIPTIONS=false +ETH_NODE_ADDRESS= +ETH_NODE_LEGACY_TX=false +PROXY_STORE_CHAT_CONTEXT=true +# PROXY_STORAGE_PATH=.\data\ (for windows) +PROXY_STORAGE_PATH=./data/ +LOG_COLOR=true + +# Set to true to reset mac keychain on start (MorpheusUI only on Mac) +APP_RESET_KEYCHAIN=false \ No newline at end of file diff --git a/.github/workflows/rating-config.json b/.github/workflows/rating-config.json new file mode 100644 index 00000000..d780fac1 --- /dev/null +++ b/.github/workflows/rating-config.json @@ -0,0 +1,14 @@ +{ + "$schema": "https://raw.githubusercontent.com/Lumerin-protocol/Morpheus-Lumerin-Node/a719073670adb17de6282b12d1852d39d629cb6e/proxy-router/internal/rating/rating-config-schema.json", + "algorithm": "default", + "providerAllowlist": [], + "params": { + "weights": { + "tps": 0.24, + "ttft": 0.08, + "duration": 0.24, + "success": 0.32, + "stake": 0.12 + } + } +} diff --git a/.github/workflows/ui-desktop.main.env b/.github/workflows/ui-desktop.main.env new file mode 100644 index 00000000..8330145e --- /dev/null +++ b/.github/workflows/ui-desktop.main.env @@ -0,0 +1,32 @@ +# This file is used to set the environment variables for the cicd workflow +# Contract and Token current as of 11/5/2024 + +# MAINNET VALUES +CHAIN_ID=42161 +DIAMOND_ADDRESS=0xDE819AaEE474626E3f34Ef0263373357e5a6C71b +DISPLAY_NAME=Arbitrum +EXPLORER_URL=https://arbiscan.io/tx/{{hash}} +TOKEN_ADDRESS=0x092bAaDB7DEf4C3981454dD9c0A0D7FF07bCFc86 +DEV_TOOLS=false +SYMBOL_ETH=ETH +SYMBOL_COIN=MOR + +# TESTNET VALUES +# CHAIN_ID=421614 +# DIAMOND_ADDRESS=0xb8C55cD613af947E73E262F0d3C54b7211Af16CF +# DISPLAY_NAME=Sepolia Arbitrum +# EXPLORER_URL=https://sepolia.arbiscan.io/tx/{{hash}} +# TOKEN_ADDRESS=0x34a285a1b1c166420df5b6630132542923b5b27e +# DEV_TOOLS=true +# SYMBOL_ETH=ETH +# SYMBOL_COIN=MOR + +# COMMON +BYPASS_AUTH=false +DEBUG=false +DEFAULT_SELLER_CURRENCY=BTC +IGNORE_DEBUG_LOGS=false +PROXY_WEB_DEFAULT_PORT=8082 +SENTRY_DSN= +TRACKING_ID= +FAILOVER_ENABLED= \ No newline at end of file diff --git a/.github/workflows/ui-desktop.test.env b/.github/workflows/ui-desktop.test.env new file mode 100644 index 00000000..75e5707c --- /dev/null +++ b/.github/workflows/ui-desktop.test.env @@ -0,0 +1,32 @@ +# This file is used to set the environment variables for the cicd workflow +# Contract and Token current as of 11/5/2024 + +# MAINNET VALUES +# CHAIN_ID=42161 +# DIAMOND_ADDRESS=0xDE819AaEE474626E3f34Ef0263373357e5a6C71b +# DISPLAY_NAME=Arbitrum +# EXPLORER_URL=https://arbiscan.io/tx/{{hash}} +# TOKEN_ADDRESS=0x092bAaDB7DEf4C3981454dD9c0A0D7FF07bCFc86 +# DEV_TOOLS=false +# SYMBOL_ETH=ETH +# SYMBOL_COIN=MOR + +# TESTNET VALUES +CHAIN_ID=421614 +DIAMOND_ADDRESS=0xb8C55cD613af947E73E262F0d3C54b7211Af16CF +DISPLAY_NAME=Sepolia Arbitrum +EXPLORER_URL=https://sepolia.arbiscan.io/tx/{{hash}} +TOKEN_ADDRESS=0x34a285a1b1c166420df5b6630132542923b5b27e +DEV_TOOLS=true +SYMBOL_ETH=ETH +SYMBOL_COIN=MOR + +# COMMON +BYPASS_AUTH=false +DEBUG=false +DEFAULT_SELLER_CURRENCY=BTC +IGNORE_DEBUG_LOGS=false +PROXY_WEB_DEFAULT_PORT=8082 +SENTRY_DSN= +TRACKING_ID= +FAILOVER_ENABLED= \ No newline at end of file diff --git a/LICENSE b/LICENSE index 5af4dd1c..f5b64120 100644 --- a/LICENSE +++ b/LICENSE @@ -18,4 +18,4 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +SOFTWARE. \ No newline at end of file diff --git a/Makefile b/Makefile deleted file mode 100644 index f2eaeabe..00000000 --- a/Makefile +++ /dev/null @@ -1,7 +0,0 @@ -dev: - docker compose up ollama & - local-run-proxy-router & - cd ui-desktop && npm run dev - -local-run-proxy-router: - docker compose up --build proxy-router \ No newline at end of file diff --git a/cli/chat/client/client.go b/cli/chat/client/client.go index f65ecb38..45466854 100644 --- a/cli/chat/client/client.go +++ b/cli/chat/client/client.go @@ -10,6 +10,7 @@ import ( "net/http" "strings" + "github.com/ethereum/go-ethereum/common" "github.com/sashabaranov/go-openai" ) @@ -313,7 +314,7 @@ func (c *ApiGatewayClient) GetBidsByModelAgent(ctx context.Context, modelAgentId func (c *ApiGatewayClient) ListUserSessions(ctx context.Context, user string) (result []SessionListItem, err error) { response := map[string][]SessionListItem{} - err = c.getRequest(ctx, fmt.Sprintf("/blockchain/sessions?user=%s", user), &response) + err = c.getRequest(ctx, fmt.Sprintf("/blockchain/sessions/user?user=%s", user), &response) if err != nil { return nil, fmt.Errorf("internal error: %v", err) } @@ -324,7 +325,7 @@ func (c *ApiGatewayClient) ListUserSessions(ctx context.Context, user string) (r func (c *ApiGatewayClient) ListProviderSessions(ctx context.Context, provider string) (result []SessionListItem, err error) { response := map[string][]SessionListItem{} - err = c.getRequest(ctx, fmt.Sprintf("/blockchain/sessions?provider=%s", provider), &response) + err = c.getRequest(ctx, fmt.Sprintf("/blockchain/sessions/provider?provider=%s", provider), &response) if err != nil { return nil, fmt.Errorf("internal error: %v", err) } @@ -420,3 +421,20 @@ func (c *ApiGatewayClient) GetBalance(ctx context.Context) (eth string, mor stri return response["eth"], response["mor"], nil } + +func (c *ApiGatewayClient) GetDiamondAddress(ctx context.Context) (common.Address, error) { + response := struct { + Config struct { + Marketplace struct { + DiamondContractAddress string + } + } + }{} + + err := c.getRequest(ctx, "/config", &response) + if err != nil { + return common.Address{}, fmt.Errorf("internal error: %v", err) + } + + return common.HexToAddress(response.Config.Marketplace.DiamondContractAddress), nil +} diff --git a/cli/go.mod b/cli/go.mod index 71caabeb..bf19118e 100644 --- a/cli/go.mod +++ b/cli/go.mod @@ -8,23 +8,18 @@ require ( github.com/charmbracelet/bubbles v0.15.0 github.com/charmbracelet/bubbletea v0.23.2 github.com/charmbracelet/lipgloss v0.7.1 - github.com/go-playground/validator/v10 v10.20.0 + github.com/ethereum/go-ethereum v1.14.11 github.com/sashabaranov/go-openai v1.24.1 github.com/urfave/cli/v2 v2.27.2 ) -// require github.com/MorpheusAIs/Morpheus-Lumerin-Node/cli/chat v1.0.1 - require ( github.com/atotto/clipboard v0.1.4 // indirect github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect github.com/containerd/console v1.0.3 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.4 // indirect - github.com/gabriel-vasile/mimetype v1.4.3 // indirect - github.com/go-playground/locales v0.14.1 // indirect - github.com/go-playground/universal-translator v0.18.1 // indirect + github.com/holiman/uint256 v1.3.1 // indirect github.com/joho/godotenv v1.5.1 - github.com/leodido/go-urn v1.4.0 // indirect github.com/lucasb-eyer/go-colorful v1.2.0 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/mattn/go-localereader v0.0.1 // indirect @@ -35,12 +30,11 @@ require ( github.com/muesli/termenv v0.15.1 // indirect github.com/rivo/uniseg v0.2.0 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect - github.com/stretchr/testify v1.9.0 // indirect + github.com/sahilm/fuzzy v0.1.0 // indirect github.com/xrash/smetrics v0.0.0-20240312152122-5f08fbb34913 // indirect golang.org/x/crypto v0.23.0 // indirect - golang.org/x/net v0.25.0 // indirect - golang.org/x/sync v0.3.0 // indirect - golang.org/x/sys v0.20.0 // indirect + golang.org/x/sync v0.7.0 // indirect + golang.org/x/sys v0.22.0 // indirect golang.org/x/term v0.20.0 // indirect golang.org/x/text v0.15.0 // indirect ) diff --git a/cli/go.sum b/cli/go.sum new file mode 100644 index 00000000..2c3a853d --- /dev/null +++ b/cli/go.sum @@ -0,0 +1,86 @@ +github.com/atotto/clipboard v0.1.4 h1:EH0zSVneZPSuFR11BlR9YppQTVDbh5+16AmcJi4g1z4= +github.com/atotto/clipboard v0.1.4/go.mod h1:ZY9tmq7sm5xIbd9bOK4onWV4S6X0u6GY7Vn0Yu86PYI= +github.com/aymanbagabas/go-osc52 v1.0.3/go.mod h1:zT8H+Rk4VSabYN90pWyugflM3ZhpTZNC7cASDfUCdT4= +github.com/aymanbagabas/go-osc52 v1.2.1/go.mod h1:zT8H+Rk4VSabYN90pWyugflM3ZhpTZNC7cASDfUCdT4= +github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k= +github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8= +github.com/charmbracelet/bubbles v0.15.0 h1:c5vZ3woHV5W2b8YZI1q7v4ZNQaPetfHuoHzx+56Z6TI= +github.com/charmbracelet/bubbles v0.15.0/go.mod h1:Y7gSFbBzlMpUDR/XM9MhZI374Q+1p1kluf1uLl8iK74= +github.com/charmbracelet/bubbletea v0.23.1/go.mod h1:JAfGK/3/pPKHTnAS8JIE2u9f61BjWTQY57RbT25aMXU= +github.com/charmbracelet/bubbletea v0.23.2 h1:vuUJ9HJ7b/COy4I30e8xDVQ+VRDUEFykIjryPfgsdps= +github.com/charmbracelet/bubbletea v0.23.2/go.mod h1:FaP3WUivcTM0xOKNmhciz60M6I+weYLF76mr1JyI7sM= +github.com/charmbracelet/harmonica v0.2.0/go.mod h1:KSri/1RMQOZLbw7AHqgcBycp8pgJnQMYYT8QZRqZ1Ao= +github.com/charmbracelet/lipgloss v0.6.0/go.mod h1:tHh2wr34xcHjC2HCXIlGSG1jaDF0S0atAUvBMP6Ppuk= +github.com/charmbracelet/lipgloss v0.7.1 h1:17WMwi7N1b1rVWOjMT+rCh7sQkvDU75B2hbZpc5Kc1E= +github.com/charmbracelet/lipgloss v0.7.1/go.mod h1:yG0k3giv8Qj8edTCbbg6AlQ5e8KNWpFujkNawKNhE2c= +github.com/containerd/console v1.0.3 h1:lIr7SlA5PxZyMV30bDW0MGbiOPXwc63yRuCP0ARubLw= +github.com/containerd/console v1.0.3/go.mod h1:7LqA/THxQ86k76b8c/EMSiaJ3h1eZkMkXar0TQ1gf3U= +github.com/cpuguy83/go-md2man/v2 v2.0.4 h1:wfIWP927BUkWJb2NmU/kNDYIBTh/ziUX91+lVfRxZq4= +github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/ethereum/go-ethereum v1.14.11 h1:8nFDCUUE67rPc6AKxFj7JKaOa2W/W1Rse3oS6LvvxEY= +github.com/ethereum/go-ethereum v1.14.11/go.mod h1:+l/fr42Mma+xBnhefL/+z11/hcmJ2egl+ScIVPjhc7E= +github.com/holiman/uint256 v1.3.1 h1:JfTzmih28bittyHM8z360dCjIA9dbPIBlcTI6lmctQs= +github.com/holiman/uint256 v1.3.1/go.mod h1:EOMSn4q6Nyt9P6efbI3bueV4e1b3dGlUCXeiRV4ng7E= +github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= +github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= +github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= +github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= +github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY= +github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/mattn/go-localereader v0.0.1 h1:ygSAOl7ZXTx4RdPYinUpg6W99U8jWvWi9Ye2JC/oIi4= +github.com/mattn/go-localereader v0.0.1/go.mod h1:8fBrzywKY7BI3czFoHkuzRoWE9C+EiG4R1k4Cjx5p88= +github.com/mattn/go-runewidth v0.0.10/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk= +github.com/mattn/go-runewidth v0.0.12/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk= +github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +github.com/mattn/go-runewidth v0.0.14 h1:+xnbZSEeDbOIg5/mE6JF0w6n9duR1l3/WmbinWVwUuU= +github.com/mattn/go-runewidth v0.0.14/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +github.com/muesli/ansi v0.0.0-20211018074035-2e021307bc4b h1:1XF24mVaiu7u+CFywTdcDo2ie1pzzhwjt6RHqzpMU34= +github.com/muesli/ansi v0.0.0-20211018074035-2e021307bc4b/go.mod h1:fQuZ0gauxyBcmsdE3ZT4NasjaRdxmbCS0jRHsrWu3Ho= +github.com/muesli/cancelreader v0.2.2 h1:3I4Kt4BQjOR54NavqnDogx/MIoWBFa0StPA8ELUXHmA= +github.com/muesli/cancelreader v0.2.2/go.mod h1:3XuTXfFS2VjM+HTLZY9Ak0l6eUKfijIfMUZ4EgX0QYo= +github.com/muesli/reflow v0.2.1-0.20210115123740-9e1d0d53df68/go.mod h1:Xk+z4oIWdQqJzsxyjgl3P22oYZnHdZ8FFTHAQQt5BMQ= +github.com/muesli/reflow v0.3.0 h1:IFsN6K9NfGtjeggFP+68I4chLZV2yIKsXJFNZ+eWh6s= +github.com/muesli/reflow v0.3.0/go.mod h1:pbwTDkVPibjO2kyvBQRBxTWEEGDGq0FlB1BIKtnHY/8= +github.com/muesli/termenv v0.11.1-0.20220204035834-5ac8409525e0/go.mod h1:Bd5NYQ7pd+SrtBSrSNoBBmXlcY8+Xj4BMJgh8qcZrvs= +github.com/muesli/termenv v0.13.0/go.mod h1:sP1+uffeLaEYpyOTb8pLCUctGcGLnoFjSn4YJK5e2bc= +github.com/muesli/termenv v0.14.0/go.mod h1:kG/pF1E7fh949Xhe156crRUrHNyK221IuGO7Ez60Uc8= +github.com/muesli/termenv v0.15.1 h1:UzuTb/+hhlBugQz28rpzey4ZuKcZ03MeKsoG7IJZIxs= +github.com/muesli/termenv v0.15.1/go.mod h1:HeAQPTzpfs016yGtA4g00CsdYnVLJvxsS4ANqrZs2sQ= +github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= +github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= +github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= +github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= +github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/sahilm/fuzzy v0.1.0 h1:FzWGaw2Opqyu+794ZQ9SYifWv2EIXpwP4q8dY1kDAwI= +github.com/sahilm/fuzzy v0.1.0/go.mod h1:VFvziUEIMCrT6A6tw2RFIXPXXmzXbOsSHF0DOI8ZK9Y= +github.com/sashabaranov/go-openai v1.24.1 h1:DWK95XViNb+agQtuzsn+FyHhn3HQJ7Va8z04DQDJ1MI= +github.com/sashabaranov/go-openai v1.24.1/go.mod h1:lj5b/K+zjTSFxVLijLSTDZuP7adOgerWeFyZLUhAKRg= +github.com/urfave/cli/v2 v2.27.2 h1:6e0H+AkS+zDckwPCUrZkKX38mRaau4nL2uipkJpbkcI= +github.com/urfave/cli/v2 v2.27.2/go.mod h1:g0+79LmHHATl7DAcHO99smiR/T7uGLw84w8Y42x+4eM= +github.com/xrash/smetrics v0.0.0-20240312152122-5f08fbb34913 h1:+qGGcbkzsfDQNPPe9UDgpxAWQrhbbBXOYJFQDq/dtJw= +github.com/xrash/smetrics v0.0.0-20240312152122-5f08fbb34913/go.mod h1:4aEEwZQutDLsQv2Deui4iYQ6DWTxR14g6m8Wv88+Xqk= +golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI= +golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= +golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= +golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220204135822-1c1b9b1eba6a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI= +golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.20.0 h1:VnkxpohqXaOBYJtBmEppKUG6mXpi+4O6purfc2+sMhw= +golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk= +golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= diff --git a/cli/main.go b/cli/main.go index 9816c793..60489c7b 100644 --- a/cli/main.go +++ b/cli/main.go @@ -459,8 +459,16 @@ func (a *actions) createBlockchainProvider(cCtx *cli.Context) error { stake := cCtx.Uint64("stake") endpoint := cCtx.String("endpoint") - providers, err := a.client.CreateNewProvider(cCtx.Context, stake, endpoint) + diamondAddr, err := a.client.GetDiamondAddress(cCtx.Context) + if err != nil { + return err + } + _, err = a.client.ApproveAllowance(cCtx.Context, diamondAddr.Hex(), stake) + if err != nil { + return err + } + providers, err := a.client.CreateNewProvider(cCtx.Context, stake, endpoint) if err != nil { return err } @@ -474,6 +482,15 @@ func (a *actions) createBlockchainProviderBid(cCtx *cli.Context) error { model := cCtx.String("model") pricePerSecond := cCtx.Uint64("pricePerSecond") + diamondAddr, err := a.client.GetDiamondAddress(cCtx.Context) + if err != nil { + return err + } + _, err = a.client.ApproveAllowance(cCtx.Context, diamondAddr.Hex(), 300000000000000000) + if err != nil { + return err + } + result, err := a.client.CreateNewProviderBid(cCtx.Context, model, pricePerSecond) if err != nil { return err diff --git a/docker-compose-startup.sh b/docker-compose-startup.sh deleted file mode 100755 index db5dced3..00000000 --- a/docker-compose-startup.sh +++ /dev/null @@ -1,14 +0,0 @@ -#!/bin/sh - -# Start the 'serve' command in the background -ollama serve & - -# Optionally, wait for 'serve' to be fully ready. Adjust the sleep as necessary. -sleep 10 # This is a simple way. Consider more reliable checking mechanisms. - -# Proceed with other commands -ollama pull llama2 -ollama run llama2 - -# Keep the container running by tailing a file (or another long-running command) -tail -f /dev/null \ No newline at end of file diff --git a/docker-compose.yaml b/docker-compose.yaml deleted file mode 100644 index a76237de..00000000 --- a/docker-compose.yaml +++ /dev/null @@ -1,30 +0,0 @@ -version: '3.8' -services: - proxy-router: - build: - context: ./proxy-router - env_file: - - ./proxy-router/.env - ports: - - 8080:8080 - - 8082:8082 - - 3333:3333 - depends_on: - - ollama - volumes: - - ./proxy-router/logs:/app/logs - - ~/go/pkg/mod:/go/pkg/mod - ollama: - image: ollama/ollama - container_name: ollama - entrypoint: ["/bin/sh", "-c"] - command: ["/docker-compose-startup.sh"] - volumes: - - ollamaconfig:/root/.ollama - - ./docker-compose-startup.sh:/docker-compose-startup.sh - ports: - - "11434:11434" - restart: unless-stopped - -volumes: - ollamaconfig: diff --git a/docs/00-overview.md b/docs/00-overview.md index 6d51da34..5918c87f 100644 --- a/docs/00-overview.md +++ b/docs/00-overview.md @@ -28,8 +28,11 @@ Numbers below reference the circled elements in the diagram above. - In a real-world scenario, this proxy-router would be a separate, small server or even docker container that is not part of the AI Model Server Instance (it can be, but it's nice to separate the architecture either for anonymity or performance) - Installation on the provider side is as simple as setting up the environment variables and running the proxy-router software. - There is a sample `.env.example` file located within the ./proxy-router folder that shoudld be copied to `.env` and edited with the appropriate values. - - Please see [proxy-router .ENV Variables](#proxy-router-env-variables) below for more information on the key values needed in the .env file -- The proxy-router needs to be on both the provider and consumer environment and have access to an Arbitrum Ethereum node via web sockets (WSS) for listening to and posting elements on the blockchain + - Please see [proxy-router .ENV Variables](proxy-router.all.env) for more information on the key values needed in the .env file +- The `models-config.json` file is particularly important as it directs the proxy-router to the provider's model(s) and the endpoint(s) for the model(s) + - This file should be copied from the `./proxy-router/models-config.example.json` to `./proxy-router/models-config.json` and edited with the appropriate values + - Please see [proxy-router models-config.json](proxy-router.models-config.json.md) for more information on the key values needed in the models-config.json file +- The proxy-router needs to be on both the provider and consumer environment and have access to an Arbitrum Ethereum node (default) public ethernet nodes or via web sockets (WSS) for listening to and posting elements on the blockchain ## 3. Provider - setup Provider, Model and Bid on the blockchain - [03-provider-offer.md](03-provider-offer.md) - for more details @@ -46,19 +49,19 @@ Numbers below reference the circled elements in the diagram above. - The components are very similar to the Provider side of things with the exception that the consumer node will typically not be hosting a model, but will be sending prompts to the proxy-router and receiving inference back - In this case, the easiest way to install is to use the packaged releases for your platform on Github and follow the instructions in the README.md file - These packages include 3 different pieces of software - - llama.cpp (llama-server) - a simple example model that can be run on the same machine as the proxy-router and ui-desktop to show how the components work together and run local (free) inference + - llama.cpp (llama-server) - a simple example model that can be run on the same machine as the proxy-router and MorpheusUI to show how the components work together and run local (free) inference - proxy-router - the same software as the provider side, but with different environment variables and a different role - - ui-desktop - Electron GUI that enables the user to interact with the models (via the API) to browse offered bids, purchase and send prompts -- The consumer node will need to have the proxy-router running and the UI-Desktop running to interact with the models and bids on the blockchain + - MorpheusUI - Electron GUI that enables the user to interact with the models (via the API) to browse offered bids, purchase and send prompts +- The consumer node will need to have the proxy-router running and the MorpheusUI running to interact with the models and bids on the blockchain ## 5. Purchase Bid - [05-bid-purchase.md](05-bid-purchase.md) - for more details -- Once the UI-Desktop is up and running, the consumer can browse the available bids on the blockchain +- Once the MorpheusUI is up and running, the consumer can browse the available bids on the blockchain - Select a bid and stake the intended MOR amount (minimum should be shown) ## 6. Prompt & Inference - [06-model-interaction.md](06-model-interaction.md) - for more details -- Once the bid is purchased, the consumer can send prompts to the proxy-router via the UI-Desktop +- Once the bid is purchased, the consumer can send prompts to the proxy-router via the MorpheusUI ## Proxy-Router and Possible LLM Server Configurations - Reference Architecture ![Reference Architecture](images/system-architecture.png) \ No newline at end of file diff --git a/docs/02-provider-setup.md b/docs/02-provider-setup.md index d2d1a9b5..55f31dde 100644 --- a/docs/02-provider-setup.md +++ b/docs/02-provider-setup.md @@ -5,48 +5,57 @@ * Your AI model has been configured, started and made available to the proxy-router server via a private endpoint (IP:PORT or DNS:PORT) eg: `http://mycoolaimodel.domain.com:8080` * Optional * You can use the provided `llama.cpp` and `tinyllama` model to test locally - * If your local model is listening on a different port locally, you will need to modify the `OPENAI_BASE_URL` in the .env file to match the correct port -* You have an existing funded wallet with saMOR and saETH and also have the `private key` for the wallet (this will be needed for the .env file configuration) + * If your local model is listening on a different port locally, you will need to modify the `models-config.json` file to match the correct port +* You have an existing funded wallet with MOR and ETH and also have the `private key` for the wallet (this will be needed for the .env file configuration) * You have created an Alchemy or Infura free account and have a private API key for the Arbitrum Sepolia testnet (wss://arb-sepolia.g.alchemy.com/v2/) -* Your proxy-router must have a publicly accessible endpoint for the provider (ip:port or fqdn:port no protocol) eg: `mycoolmornode.domain.com:3333` - this will be used when creating the provider on the blockchain +* Your proxy-router must have a **publicly accessible endpoint** for the provider (ip:port or fqdn:port no protocol) eg: `mycoolmornode.domain.com:3333` - this will be used when creating the provider on the blockchain ## Installation & Configuration Steps: -1. Download latest release for your operating system: https://github.com/Lumerin-protocol/Morpheus-Lumerin-Node/releases +1. Obtain the software: + 1. Package: Download latest release for your operating system: https://github.com/Lumerin-protocol/Morpheus-Lumerin-Node/releases + * Mainnet releases will be prefixed with `main-*` + * Testnet releases will be prefixed with `test-*` + 2. Source Code: + * Clone the repository: `git clone -b branch https://github.com/Lumerin-protocol/Morpheus-Lumerin-Node.git` + * Mainnet Branch = `main` + * Testnet Branch = `test` + * Development Branch = `dev`(not recommended unless directed by the development team) 1. Extract the zip to a local folder (examples) * Windows: `(%USERPROFILE%)/Downloads/morpheus)` * Linux & MacOS: `~/Downloads/morpheus` * On MacOS you may need to execute `xattr -c proxy-router` in a command window to remove the quarantine flag on MacOS -1. Edit the `.env` file following the guide below [proxy-router .ENV Variables](#proxy-router-env-variables) +1. Environment configuration + * In most cases, the default .env file will work for the proxy-router...In some cases you will want to modify the .env file with advanced capability (log entries, private keys, private endpoints, etc) + * Please see [proxy-router.all.env](proxy-router.all.env) for more information on the key values available in the .env file + 1. Choose OS environment you are working with: + * Linux/Mac: `env.example` or `env.example.win` for Windows + * Change the name of the desired file to `.env` + * Edit values within the file (Wallet_Private_Key, for example) as desired + 2. Choose the **blockchain** you'd like to work on...**Arbitrum MAINNET is the default** + * To operate on the Sepolia Arbitrum TESTNET, + * Edit the .env file and + * Uncomment the `TESTNET VALUES` and comment the `MAINNET VALUES` lines & save the file -1. **(OPTIONAL)** - External Provider or Pass through +1. **(OPTIONAL) - External Provider or Pass through** * In some cases you will want to leverage external or existing AI Providers in the network via their own, private API * Dependencies: * `model-config.json` file in the proxy-router directory - * proxy-router .env file for proxy-router must also be updated to include `MODELS_CONFIG_PATH=/models-config.json` - * Once your provider is up and running, deploy a new model and model bid via the diamond contract (you will need the `model_ID` for the configuration) - * Edit the model-config.json to the following json format ... with - * The JSON ID will be the ModelID that you created above, modelName, apiTYpe, apiURL and apiKey are from the external provider and specific to their offered models - * Once the model-config.json file is updated, the morpheus node will need to be restarted to pick up the new configuration (not all models (eg: image generation can be utilized via the UI-Desktop, but API integration is possible) - * Example model-config.json file for external providers -``` -#model-config.json -{ - "0x4b5d6c2d3e4f5a6b7c8de7f89a0b19e07f4a6e1f2c3a3c28d9d5e6": { - "modelName": "v1-5-specialmodel.modelversion [externalmodel]", - "apiType": "provider_api_type", - "apiUrl": "https://api.externalmodel.com/v1/xyz/generate", - "apiKey": "api-key-from-external-provider" - }, - "0xb2c8a6b2c1d9ed7f0e9a3b4c2d6e5f14f9b8c3a7e5d6a1a0b9c7d8e4f30f4a7b": { - "modelName": "v1-7-specialmodel2.modelversion [externalmodel]", - "apiType": "provider_api_type", - "apiUrl": "https://api.externalmodel.com/v1/abc/generate", - "apiKey": "api-key-from-external-provider" - } -} -``` + * proxy-router .env file for proxy-router must also be edited to adjust `MODELS_CONFIG_PATH=/models-config.json` + * Once your provider is up and running, deploy a new model and model bid via the API interface (you will need the `model_ID` for the configuration) + * Edit the model-config.json to the following json format + * The JSON ID will be the ModelID that you created above, modelName, apiTYpe, apiURL and apiKey are from the external provider and specific to their offered models + * Full explanation of models-config.json can be found here [models-config.json.md](models-config.json.md) + * Once the model-config.json file is updated, the morpheus node will need to be restarted to pick up the new configuration (not all models (eg: image generation can be utilized via the MorpheusUI, but API integration is possible) + +1. **(OPTIONAL) - Weights and Preferred Providers** + * In some cases you will want to adjust the weights of the providers or set a preferred provider for the models you'd like to use + * Edit the `rating-config.json` file located in the proxy-router directory to adjust the weights and preferred providers for the models you'd like to use + * Weights must add up to 1 + * Full explanation of rating-config.json can be found here [rating-config.json.md](rating-config.json.md) + * Add preferred providerIDs to the `providerAllowlist` array for the providers you'd like to use + * **If this array is left blank**, all providers are available ## Start the Proxy Router 1. On your server, launch the proxy-router with the modified .env file shown above @@ -58,40 +67,3 @@ 1. Once the proxy-router is running, you can navigate to the Swagger API Interface (http://localhost:8082/swagger/index.html as example) to validate that the proxy-router is running and listening for blockchain events 1. You can also check the logs in the `./data` directory for any errors or issues that may have occurred during startup 1. Once validated, you can move on and create your provider, model and bid on the blockchain [03-provider-offer.md](03-provider-offer.md) - - ----------------- -### proxy-router .ENV Variables -Key Values in the .env file are (there are others, but these are primarly responsible for connecting to the blockchain, the provider AI model and listening for incoming traffic): -- `WALLET_PRIVATE_KEY=` - - Private Key from your wallet needed for the proxy-router to sign transactions and respond to provided prompts (this is why the proxy router must be secured and the API endpoint protected) -- `ETH_NODE_ADDRESS=wss://arb-sepolia.g.alchemy.com/v2/` - - Ethereum Node Address for the Arbitrum blockchain (via Alchemy or Infura) - - This websocket (wss) address is key for the proxy-router to listen and post to the blockchain - - We recommend using your own private ETH Node Address for better performance (free account setup via Alchemy or Infura) -- `DIAMOND_CONTRACT_ADDRESS=0x8e19288d908b2d9F8D7C539c74C899808AC3dE45` - - This is the key Lumerin Smart Contract (currently Sepolia Arbitrum testnet) - - This is the address of the smart contract that the proxy-router will interact with to post providers, models & bids - - This address will change as the smart-contract is updated and for mainnet contract interaction -- `MOR_TOKEN_ADDRESS=0xc1664f994fd3991f98ae944bc16b9aed673ef5fd` - - This is the Morpheus Token (saMOR) address for Sepolia Arbitrum testnet - - This address will be different for mainnet token -- `WEB_ADDRESS=0.0.0.0:8082` - - This is the local listenting port for your proxy-router API (Swagger) interface - - Based on your local needs, this may need to change (8082 is default) -- `WEB_PUBLIC_URL=localhost:8082` - - If you have or will be exposing your API interface to a local, PRIVATE (or VPN) network, you can change this to the DNS name or IP and port where the API will be available. The default is just on the local machine (localhost) - - The PORT must be the same as in the `WEB_ADDRESS` setting -- `OPENAI_BASE_URL=http://localhost:8080/v1` - - This is where the proxy-router should send OpenAI compatible requests to the provider model. - - By default (and included in the Morpheus-Lumerin software releases) this is set to `http://localhost:8080/v1` for the included llama.cpp model - - In a real-world scenario, this would be the IP address and port of the provider model server or server farm that is hosting the AI model separately from the proxy-router -- `PROXY_STORAGE_PATH=./data/` - - This is the path where the proxy-router will store logs and other data - - This path should be writable by the user running the proxy-router software -- `MODELS_CONFIG_PATH=` - - location of the models-config.json file that contains the models that the proxy-router will be providing. - - it has the capability to also (via private API) call external providers models (like Prodia) -- `PROXY_ADDRESS=0.0.0.0:3333` - - This is the local listening port for the proxy-router to receive prompts and inference requests from the consumer nodes - - This is the port that the consumer nodes will send prompts to and should be available publicly and via the provider definition setup on the blockchain \ No newline at end of file diff --git a/docs/02a-proxy-router-docker.md b/docs/02a-proxy-router-docker.md new file mode 100644 index 00000000..8446e2de --- /dev/null +++ b/docs/02a-proxy-router-docker.md @@ -0,0 +1,76 @@ + +# Proxy-Router Docker Setup: + +**This document describes setting up the proxy-router component of the Morpheus AI Network in a Docker container ONLY and accessing it via the Swagger API Interface...no GUI or Wallet components are included in this setup** + +## Overview: +* The Proxy-Router is a critical component of the Morpheus AI Network. It is responsible for monitoring the blockchain for events and managing the AI models and providers that are available to the network. +* The Proxy-Router is a standalone application that can be run on any server that has access to the blockchain and the AI models. +* This document walks through using Docker to build and run the proxy-router image on your server. + +## Pre-Requisites: +* Your AI model has been configured, started and made available to the proxy-router server via a private endpoint (IP:PORT or DNS:PORT) eg: `http://mycoolaimodel.domain.com:8080` +* You have an existing funded wallet with MOR and ETH and also have the `private key` for the wallet (this will be needed for the .env file configuration) +* Your proxy-router must have a **publicly accessible endpoint** for the provider (ip:port or fqdn:port no protocol) eg: `mycoolmornode.domain.com:3333` - this will be used when creating the provider on the blockchain +* Docker and Git are installed and current on your server +* The three key configuration files are located in the same directory as the proxy-router code: + * .env + * models-config.json + * rating-config.json + +## Installation & Configuration Steps: +1. Clone the source code from the repository: + * `git clone -b main https://github.com/Lumerin-protocol/Morpheus-Lumerin-Node.git` +1. Change to the proxy-router directory: + * `cd Morpheus-Lumerin-Node\proxy-router` +1. Configure the 3 key files for your environment: + 1. Environment file configuration + 1. Copy the example file to .env: + * Linux/Mac: `cp .env.example .env` + * Windows: `copy .env.example.win .env` + 1. Edit values within the .env as desired + * Add your private key to`WALLET_PRIVATE_KEY=` + * Modify the following values to ensure that those files remain "outside of the running container" for persistence and are mounted by the docker-compose.yml file's `volume` directive + * `MODELS_CONFIG_PATH=/app/data/models-config.json` + * `RATING_CONFIG_PATH=/app/data/rating-config.json` + * `PROXY_STORAGE_PATH=/app/data/` + 1. Choose the **blockchain** you'd like to work on...**Arbitrum MAINNET is the default** + * To operate on the Sepolia Arbitrum TESTNET, + * Uncomment the `TESTNET VALUES` and comment the `MAINNET VALUES` lines & save the file + 1. Models Configuration file + 1. Copy the example file to models-config.json: + * Linux/Mac: `cp models-config.json.example models-config.json` + * Windows: `copy models-config.json.example models-config.json` + 1. Edit the models-config.json file to include the models you'd like to use. + 1. Details here: [models-config.json.md](models-config.json.md) + 1. Once your provider is up and running, deploy a new model and model bid via the API interface (you will need to update the `modelId` for the configuration) + 1. Rating Configuration file + 1. Copy the example file to rating-config.json: + * Linux/Mac: `cp rating-config.json.example rating-config.json` + * Windows: `copy rating-config.json.example rating-config.json` + 1. Edit the rating-config.json file to include the weights and preferred providers you'd like to use. + 1. Details here: [rating-config.json.md](rating-config.json.md) + +## Build the proxy-router Docker Image: +1. Build the Docker image using the provided `docker_build.sh` script + * `./docker_build.sh --build` + * This script pulls the current Git tag and version, builds the docker image with all the port and defaults defined in the docker-compose.yml file + +## Running the proxy-router Docker Container: +1. Run the Docker container using the provided `docker_build.sh` script + * `./docker_build.sh --run` + * This script runs the docker container with the port and volume mappings defined in the docker-compose.yml file + * The proxy-router will start and begin listening for blockchain events + +## Validating Steps: +1. Once the proxy-router is running, you can navigate to the Swagger API Interface (http://localhost:8082/swagger/index.html as example) to validate that the proxy-router is running and listening for blockchain events +1. Once validated, you can move on and create your provider, model and bid on the blockchain [03-provider-offer.md](03-provider-offer.md) + +## NOTES: +* We have created docker-compose.yml, Dockerfile and docker_build.sh scripts to ease configuration and deployment of the proxy-router in a containerized environment +* Use these files as guides for applying to your system needs and configurations, private key, eth_node, ports, endpoints, volumes, .env, models-config.json and rating-config.json will need to be adjusted to your specific needs +* In most cases, the default .env file will work for the proxy-router...In some cases you will want to modify the .env file with advanced capability (log entries, private keys, private endpoints, etc) +* Please see the following for more information on these key config files: + * [proxy-router.all.env](proxy-router.all.env) + * [models-config.json.md](models-config.json.md) + * [rating-config.json.md](rating-config.json.md) \ No newline at end of file diff --git a/docs/03-provider-offer.md b/docs/03-provider-offer.md index ee301d2b..f4203522 100644 --- a/docs/03-provider-offer.md +++ b/docs/03-provider-offer.md @@ -1,46 +1,58 @@ # Creating Provider, Model and Bid on the Blockchain: -**Diamond contract:** `0x8e19288d908b2d9F8D7C539c74C899808AC3dE45` +**Contract Minimums** As of 11/22/2024: +* "providerMinStake": `200000000000000000`, (0.2 MOR) +* "modelMinStake": `100000000000000000`, (0.1 MOR) +* "marketplaceBidFee": `300000000000000000`, (0.3 MOR) +* "bidPricePerSeconMin `10000000000`, (0.00000001 MOR) -**Needed information:** -* Provider/Owner: `0x9E26Fea97F7d644BAf62d0e20e4d4b8F836C166c` # Your ERC-20 Wallet with saMOR & saETH -* Endpoint: `server.domain.com:3333` # Internet publicly accessible server/node access point +**Needed information (samples):** +* Provider/Owner: `0x9E26Fea97F7d644BAf62d0e20e4d4b8F836C166c` # Your ERC-20 Wallet with MOR & ETH +* Endpoint: `server.domain.com:3333` # Internet **publicly accessible** server/node access point * Model ID: `0xe1e6e3e77148d140065ef2cd4fba7f4ae59c90e1639184b6df5c84` # Random 32byte/hex that you generate * ipfcCID: `0xc2d3a5e4f9b7c1a2c8f0b1d5e6c78492fa7bcd34e9a3b9c9e18f25d3be47a1f6` # Another 32byte/hex random for future use * Model Name: `CapybaraHermes-v2.5-Mistral-7b` # Human Readable name for the model -* Bid Cost: `200000000000` (1*10^18 or ~7MOR) # What will the model cost per second to use +* Bid Cost: `10000000000` (0.00000001 MOR) # What will the model cost per second to use ## Steps - 1. WEB3/Arbiscan/Metamask: Authorize Diamond Contract to spend on the Provider's behalf - 1. https://sepolia.arbiscan.io/address/0xc1664f994fd3991f98ae944bc16b9aed673ef5fd#writeContract - 1. Connect to Web3 (connect Provider wallet) - 1. Click Approve - 1. Spender Address = Diamond Contract - 1. Authorized Amount = remember that this is in the form 1*10^18 so make sure there's enough MOR 1ranted to cover the contract fees - 1. The Diamond Contract is now authorized to spend MOR on provider's behalf +1. To complete these steps, you will need to be running the proxy-router and also have access to the API Port (default=8082)for the Swagger API Interface + 1. http://localhost:8082/swagger/index.html + +1. Authorize Diamond Contract to spend on the Provider's behalf + 1. http://localhost:8082/swagger/index.html#/transactions/post_blockchain_approve + 1. Spender Address = Diamond Contract + 1. Authorized Amount = remember that this is in the form `1*10^18` so make sure there's enough MOR granted to cover the contract fees + 1. To become a provider, offer a model and offer a bid based on the current minimums, you will need to authorize the contract to spend at least `600000000000000000` (0.6 MOR) on your behalf + 1. The Diamond Contract is now authorized to spend MOR on provider's behalf 1. Create Provider in the Diamond contract via swagger api: - 1. Start proxy-router - 1. http://localhost:8082/swagger/index.html#/providers/post_blockchain_providers - 1. Enter required fields: - 1. addStake = Amount of stake for provider to risk - Stake can be 0 now - 1. Endpoint = Your publicly accessible endpoint for the proxy-router provider (ip:port or fqdn:port no protocol) eg: `mycoolmornode.domain.com:3333` + 1. http://localhost:8082/swagger/index.html#/providers/post_blockchain_providers + 1. addStake = Amount of stake for provider to risk + - Minimum Provider stake is `200000000000000000`, (0.2 MOR) + - Provider stake to become a subnet is `10000000000000000000000`, (10,000 MOR) + 1. Endpoint = Your **publicly accessible endpoint** for the proxy-router provider (ip:port or fqdn:port no protocol) eg: `mycoolmornode.domain.com:3333` 1. Create Model in the contract: 1. Go to http://localhost:8082/swagger/index.html#/models/post_blockchain_models and enter - 1. modelId: random 32byte/hex that will uniquely identify model (uuid) + 1. modelId: random 32byte/hex that will be used in conjunction with providerId to uniquely identify model (uuid) 1. ipfsCID: another random32byte/hex for future use (model library) - 1. Fee: fee for the model usage - 0 for now - 1. addStake: stake for model usage - 0 for now + 1. Fee: fee for the model usage + 1. addStake: "modelMinStake": `100000000000000000`, (0.1 MOR) 1. Owner: Provider Wallet Address 1. name: Human Readable model like "Llama 2.0" or "Mistral 2.5" or "Collective Cognition 1.1" 1. tags: array of tag strings for the model - 1. Capture the `modelID` from the JSON response + 1. Capture the `modelID` from the JSON response + **NOTE** The returned `modelID` is a combination of your requested modelID and your providerID and will be required to update your models-config.json file AND when offering bids + +1. Update the models-config.json file with the new modelID and restart the proxy-router + 1. Navigate to the proxy-router directory and open the `models-config.json` file + 1. Add the new modelID to the JSON array of models + 1. Save the file and restart the proxy-router 1. Offer Model Bid in the contract: 1. Navigate to http://localhost:8082/swagger/index.html#/bids/post_blockchain_bids and enter - 1. modelID: Model ID Created in last step: - 1. pricePerSecond: this is in 1*10^18 format so 100000000000 should make 5 minutes for the session 1round 37.5 saMOR - 1. Click Execute + 1. modelID: Model ID Created above + 1. pricePerSecond: "bidPricePerSeconMin `10000000000`, (0.00000001 MOR) + 1. Click Execute and capture the `bidID` from the JSON response ---------------- \ No newline at end of file diff --git a/docs/04-consumer-setup.md b/docs/04-consumer-setup.md index 18c14b51..449e8aa6 100644 --- a/docs/04-consumer-setup.md +++ b/docs/04-consumer-setup.md @@ -1,19 +1,22 @@ -### Consumer from Release (Local LLM, Proxy-Router & UI-Desktop): +### Consumer from Release (Local LLM, Proxy-Router & MorpheusUI): This is the simplest way to get started with the Morpheus Lumerin Node as a Consumer. This will allow you to interact with the Morpheus network and the models offered on the network as a consumer. It will run 3 different pieces of software on your local machine: -* `llama.cpp` (llama-server) - a simple sample AI model that can be run on the same machine as the proxy-router and ui-desktop to show how the components work together and run local (free) inference +* `llama.cpp` (llama-server) - a simple sample AI model that can be run on the same machine as the proxy-router and MorpheusUI to show how the components work together and run local (free) inference * `proxy-router` - the same software as the provider side, but with different environment variables and a different role -* `ui-desktop` - Electron GUI that enables the user to interact with the models (via the API) to browse offered bids, purchase and send prompts +* `MorpheusUI` - Electron GUI that enables the user to interact with the models (via the API) to browse offered bids, purchase and send prompts ## Installation Steps: -1. Download latest release for your operating system: https://github.com/Lumerin-protocol/Morpheus-Lumerin-Node/releases +1. Obtain the software: + 1. Package: Download latest release for your operating system: https://github.com/Lumerin-protocol/Morpheus-Lumerin-Node/releases + * Mainnet releases will be prefixed with `main-*` + * Testnet releases will be prefixed with `test-*` 1. Extract the zip to a local folder (examples) * Windows: `(%USERPROFILE%)/Downloads/morpheus)` * Linux & MacOS: `~/Downloads/morpheus` - * On MacOS you may need to execute `xattr -c mor-launch proxy-router ui-desktop.app llama-server` in a command window to remove the quarantine flag on MacOS + * On MacOS you may need to execute `xattr -c mor-launch proxy-router MorpheusUI.app llama-server` in a command window to remove the quarantine flag on MacOS 1. Launch the node - this should open a command window to see local LLM model server and proxy-router start and then should launch the user interface * Windows: Double click the `mor-launch.exe` (You will need to tell Windows Defender this is ok to run) @@ -21,7 +24,7 @@ It will run 3 different pieces of software on your local machine: 1. Startup User Interface: 1. Read & accept terms & Conditions - 1. Set a strong password (this is for the UI-Desktop only) + 1. Set a strong password (this is for the MorpheusUI only) 1. Follow the instructions for creating a new wallet (be sure to save the mnemonic in a safe place) 1. **OPTIONAL to use existing Wallet** - Instead of creating an new wallet and if you have the existing wallet's mnemonic, when prompted, select **`Recover your wallet Saved Mnemonic`** instead. @@ -31,8 +34,8 @@ It will run 3 different pieces of software on your local machine: ## Validation Steps: 1. Local Test: Once the UI is up and running, - 1. You should see tokens for saETH and saMOR that you sent to this wallet earlier. - * If this is a new wallet, you will need to send saMOR and saETH to this wallet to be able to interact with the blockchain + 1. You should see tokens for ETH and MOR that you sent to this wallet earlier. + * If this is a new wallet, you will need to send MOR and ETH to this wallet to be able to interact with the blockchain * This can be done externally via metamask or usual Arbitrum testnet faucets 1. Once you have a funded Wallet, you can interact with the local model 1. Click on the `Chat` icon on the left side of the screen @@ -52,9 +55,9 @@ It will run 3 different pieces of software on your local machine: 1. Cleanup/Closeout * Manually End all Remote Sessions: * In the Chat Window, click on the Time icon to the right of the Model line - this will expand and show current sessions, click the "X" next to each one to make sure it's closed - * Closing the UI-Desktop window should leave the CMD window open + * Closing the MorpheusUI window should leave the CMD window open * You’ll have to ctrl-c in the window to kill the local model and proxy-router - * To FULLY delete and force a clean startup of the UI (including forcing new password and mnemonic recovery), delete the ui-desktop folder and start the UI again - * Windows:  `%USERPROFILE%\AppData\Roaming\ui-desktop` - * Linux: `~/.config/ui-desktop` - * MacOS: `~/Library/Application Support/ui-desktop` + * To FULLY delete and force a clean startup of the UI (including forcing new password and mnemonic recovery), delete the MorpheusUI folder and start the UI again + * Windows:  `%USERPROFILE%\AppData\Roaming\MorpheusUI` + * Linux: `~/.config/MorpheusUI` + * MacOS: `~/Library/Application Support/MorpheusUI` diff --git a/docs/04a-consumer-setup-source.md b/docs/04a-consumer-setup-source.md index 3840a6fb..24fc8f1f 100644 --- a/docs/04a-consumer-setup-source.md +++ b/docs/04a-consumer-setup-source.md @@ -2,7 +2,7 @@ This document provides a step-by-step guide to setting up a Consumer Node for the Morepheus Network so that you can setup session and interact with the remote providers. ## Pre-requisites: -* Create or use an existing ERC-20 wallet that has saMOR and saETH (Sepolia Arbitrum) tokens - you can use Metamask (new wallet..not derived) or any other ERC-20 wallet. You will need to have access to the wallet's private key **NEVER SHARE THIS WITH ANYONE** for steps below to authorize the contract to spend on your behalf. +* Create or use an existing ERC-20 wallet that has MOR and ETH (Sepolia Arbitrum) tokens - you can use Metamask (new wallet..not derived) or any other ERC-20 wallet. You will need to have access to the wallet's private key **NEVER SHARE THIS WITH ANYONE** for steps below to authorize the contract to spend on your behalf. ## TL;DR * Install and Configure the proxy-router node (once) @@ -36,16 +36,16 @@ Save the .env file and exit the editor #### 4. Build and start the proxy-router ```bash ./build.sh -go run cmd/main.go +./bin/proxy-router ``` -After the iniial setup, you can execute `git pull` to get the latest updates and re-run the `./build.sh` and `go run cmd/main.go` to update the proxy-router with the latest changes. +After the iniial setup, you can execute `git pull` to get the latest updates and re-run the `./build.sh` and `./bin/proxy-router` to update the proxy-router with the latest changes. #### 5. Confirm that the build is successful and console should show similar to below after started (and listening on specified ports 8082 for Swagger API and 3333 for the proxy-router): You can also test http://localhost:8082/swagger/index.html to confirm the API is running and accessible. ``` -Loaded config: {AIEngine:{OpenAIBaseURL: OpenAIKey:} Blockchain:{EthNodeAddress: EthLegacyTx:false ExplorerApiUrl:} Environment:development Marketplace:{DiamondContractAddress:0x8e19288d908b2d9F8D7C539c74C899808AC3dE45 MorTokenAddress:0xc1664f994Fd3991f98aE944bC16B9aED673eF5fD WalletPrivateKey:} Log:{Color:true FolderPath: IsProd:false JSON:false LevelApp:info LevelConnection:info LevelProxy:info LevelScheduler:info LevelContract:} Proxy:{Address:0.0.0.0:3333 MaxCachedDests:5 StoragePath:} System:{Enable:false LocalPortRange:1024 65535 NetdevMaxBacklog:100000 RlimitHard:524288 RlimitSoft:524288 Somaxconn:100000 TcpMaxSynBacklog:100000} Web:{Address:0.0.0.0:8082 PublicUrl:localhost:8082}} +Loaded config: {AIEngine:{OpenAIBaseURL: OpenAIKey:} Blockchain:{EthNodeAddress: EthLegacyTx:false ExplorerApiUrl:} Environment:development Marketplace:{DiamondContractAddress:0xb8C55cD613af947E73E262F0d3C54b7211Af16CF MorTokenAddress:0x34a285a1b1c166420df5b6630132542923b5b27e WalletPrivateKey:} Log:{Color:true FolderPath: IsProd:false JSON:false LevelApp:info LevelConnection:info LevelProxy:info LevelScheduler:info LevelContract:} Proxy:{Address:0.0.0.0:3333 MaxCachedDests:5 StoragePath:} System:{Enable:false LocalPortRange:1024 65535 NetdevMaxBacklog:100000 RlimitHard:524288 RlimitSoft:524288 Somaxconn:100000 TcpMaxSynBacklog:100000} Web:{Address:0.0.0.0:8082 PublicUrl:localhost:8082}} 2024-07-23T12:58:04.560735 INFO APP proxy-router TO BE SET AT BUILD TIME 2024-07-23T12:58:08.249559 INFO APP connected to ethereum node: wss://arb-sepolia.g.alchemy.com/v2/, chainID: 421614 2024-07-23T12:58:08.278792 INFO BADGER All 0 tables opened in 0s @@ -55,14 +55,14 @@ Loaded config: {AIEngine:{OpenAIBaseURL: OpenAIKey:} Blockchain:{EthNodeAddress: 2024-07-23T12:58:08.290268 INFO proxy state: running 2024-07-23T12:58:08.290507 INFO HTTP http server is listening: 0.0.0.0:8082 2024-07-23T12:58:08.290631 INFO Wallet address: -2024-07-23T12:58:08.290841 INFO started watching events, address 0x8e19288d908b2d9F8D7C539c74C899808AC3dE45 +2024-07-23T12:58:08.290841 INFO started watching events, address 0xb8C55cD613af947E73E262F0d3C54b7211Af16CF 2024-07-23T12:58:08.290866 INFO TCP tcp server is listening: 0.0.0.0:3333 ``` ================================== ### B. Authorize the contract to spend on your behalf Either via the swagger interface http://localhost:8082/swagger/index.html#/wallet/post_blockchain_allowance or following CLI, you can authorize the contract to spend on your behalf. **This only needs to be done once per wallet, or when funds have been depleted.** -`curl -X 'POST' 'http://localhost:8082/blockchain/approve?spender=0x8e19288d908b2d9F8D7C539c74C899808AC3dE45&amount=3' -H 'accept: application/json' -d ''` # Approve the contract to spend 3 saMOR tokens on your behalf +`curl -X 'POST' 'http://localhost:8082/blockchain/approve?spender=0xb8C55cD613af947E73E262F0d3C54b7211Af16CF&amount=3' -H 'accept: application/json' -d ''` # Approve the contract to spend 3 MOR tokens on your behalf ### C. Query the blockchain for various models / providers (Get ModelID) You can query the blockchain for various models and providers to get the ModelID. This can be done via the swagger interface http://localhost:8082/swagger/index.html#/marketplace/get_marketplace_models or following CLI: @@ -144,8 +144,8 @@ curl -X 'POST' \ ### Quick and Dirty Sample: -`curl -X 'POST' 'http://localhost:8082/blockchain/approve?spender=0x8e19288d908b2d9F8D7C539c74C899808AC3dE45&amount=3' -H 'accept: application/json' -d ''` - # approves the smart contract `0x8e19...dE45` to spend 3 saMOR tokens on your behalf +`curl -X 'POST' 'http://localhost:8082/blockchain/approve?spender=0xb8C55cD613af947E73E262F0d3C54b7211Af16CF&amount=3' -H 'accept: application/json' -d ''` + # approves the smart contract `0x8e19...dE45` to spend 3 MOR tokens on your behalf `curl -s -X 'GET' 'http://localhost:8082/wallet' -H 'accept: application/json' | jq .address` # returns the wallet ID (confirm that it matches your wallet) diff --git a/docs/05-bid-purchase.md b/docs/05-bid-purchase.md index c4524170..219040be 100644 --- a/docs/05-bid-purchase.md +++ b/docs/05-bid-purchase.md @@ -1 +1 @@ -# TODO - detail steps for consumer to navigate in the ui-desktop, select & purchase remote model \ No newline at end of file +# TODO - detail steps for consumer to navigate in the MorpheusUI, select & purchase remote model \ No newline at end of file diff --git a/docs/99-troubleshooting.md b/docs/99-troubleshooting.md new file mode 100644 index 00000000..d1af067b --- /dev/null +++ b/docs/99-troubleshooting.md @@ -0,0 +1,41 @@ +# Troubleshooting guides for proxy-router and MorpheusUI desktop applications +* These are some common scenarios and failure modes to watch out for when running the proxy-router and MorpheusUI desktop applications. +* One of the most critical things to remember, especially about the desktop application (MorpheusUI) or the Swagger API (http://localhost:8082/swagger/index.html) is that you **must** have a good startup of the proxy-router. + * If the proxy-router is not running or is not able to connect to the blockchain node, the desktop application will not be able to talk to the blockchain, manage your wallet or send prompts to the provider. + * The proxy-router is the bridge between the blockchain node and the desktop application. It is responsible for routing prompts and responses between the consumer and provider. +* One of the best ways to observe the health of the proxy-router is to start it (either `./proxy-router` or `./mor-launch` for the release) from a terminal or command line session where you can see the output in real-time. +* There are also many options for adding log destination and details of log entries (please see [proxy-router.all.env](./proxy-router.all.env) #Logging Configuration section for more information. + +## Proxy-Router +### Proxy-Router is not starting +* **Expected Result or "How do I know it's good?":** + * The proxy-router should start successfully and be able to connect to the blockchain node and listening on both 8082 and 3333 ports (these are the default ports) + * In the terminal or logs after startup, you should see the following messages with regard to the proxy-router (there will be other messages as well): + ``` + INFO HTTP http server is listening: 0.0.0.0:8082 + INFO TCP tcp server is listening: 0.0.0.0:3333 + ``` + * The other way to verify that the proxy-router has started is to query the Swagger API at http://localhost:8082/swagger/index.html (or whatever url you've set in the .env file for your proxy-router IP or DNS address) and see the API documentation. + +* **Symptoms:** The proxy-router is not starting or is crashing immediately after starting. +* **Possible Causes:** + * **.env file misconfiguration** (e.g. missing or incorrect values) + * These four items MUST be accurate to the chain and your OS., Use the example files `/proxy-router/env.main.example` to make sure you have the correct values: + * `DIAMOND_CONTRACT_ADDRESS=` + * `MOR_TOKEN_ADDRESS=` + * `EXPLORER_API_URL=` + * `ETH_NODE_CHAIN_ID=` + * `PROXY_STORAGE_PATH=` + * If you are running the proxy-router by itself (without the UI), you will need to set the private key of your provider wallet in the `WALLET_PRIVATE_KEY=` + * **IF** you use your own ETH node (Alchemy, Infura, etc.) to communicate with the blockchain, you will need to make sure that the `ETH_NODE_URL=` entry in the .env file is correct for your chain. + * We recommend https:// instead of wss:// for the ETH_NODE_URL ...which also means that `ETH_NODE_USE_SUBSCRIPTIONS=false` should be set in the .env file + + * **models-config.json misconfiguration** (e.g. missing or incorrect values) + * The `models-config.json` file is used to direct the proxy to find the models that the proxy-router will use to route prompts and responses between consumers and providers. + * Ensure that: + * the `MODELS_CONFIG_PATH=` in your .env file is correct and points to the correct directory and file and has the right permissions + * the `models-confi.json` should follow the formatting shown in the example file [models-config.json.md](./models-config.json.md) +* **Resolution:** + * Check the .env and models-config.json file configuration and ensure that the blockchain node is accessible. + * Restart the proxy-router and check the logs for any errors related to the connection. + \ No newline at end of file diff --git a/docs/images/overview.svg b/docs/images/overview.svg index 924e965d..fbbafed1 100644 --- a/docs/images/overview.svg +++ b/docs/images/overview.svg @@ -1,2 +1,2 @@ -
Provider Registration
Provider Registration
Model Registration 
Model Registration 
Bid Offer
Bid Offer
Model Registration 
Model Registration 
Bid Offer
Bid Offer
Bid Offer
Bid Offer
Bid Offer 0x1234...abc
Bid Offer 0x1234...abc
Provider Registration
Provider Registration
Model Registration 
Model Registration 
Bid Offer
Bid Offer
Model Registration 
Model Registration 
Bid Offer
Bid Offer
Bid Offer
Bid Offer
Bid Offer 0x1234...abc
Bid Offer 0x1234...abc
CONSUMER 
CONSUMER 
PROVIDER
PROVIDER
AI Compute Farm or Service
AI Compute Farm or Service
https://mycoolai.serverfarm.io:8080
Private Endpoint exposed only to the Lumerin Proxy-Router
https://mycoolai.serverfarm.io:8080...
models-config.json 
/proxy-router/.env variable
OPENAI_BASE_URL=
models-config.json &...
Lumerin Proxy-Router
Lumerin Proxy-R...
/proxy-router/.env define local address & port
PROXY_ADDRESS=
/proxy-router/.env define local address & port...
http://mycoolproxy.serverfarm.io:3333
Public Provider Endpoint that talks to the Blockchain
and Receives inbound prompts from purchased model bids
http://mycoolproxy.serverfarm.io:3333...
/proxy-router/.env variables
WEB_ADDRESS=0.0.0.0:8082
WEB_PUBLIC_URL=localhost:8082
/proxy-router/.env variables...
http://mycoolproxy.serverfarm.io:8082/swagger/index.html
Private Endpoint that talks to the proxy-router API interface (Access to Wallet Actions-keep secure!)
http://mycoolproxy.serverfarm.io:8082/swagger/index.html...
Arbitrum Ethereum
WebSocket Service Endpoint 
(wss://.......) 

Arbitrum...
/proxy-router/.env variable
ETH_NODE_ADDRESS=wss://
/proxy-router/.env variable...
Provider Registration
Provider Registration
Model Registration 
Model Registration 
Bid Offer
Bid Offer
Model Registration 
Model Registration 
Bid Offer
Bid Offer
Bid Offer
Bid Offer
Bid Offer 0x1234...abc
Bid Offer 0x1234...abc
Local LLama.cpp AI Model
Local...
https://localhost:8080
Internal Node Endpoint exposed only to the Lumerin Proxy-Router
https://localhost:8080...
Lumerin Proxy-Router
Lumerin Proxy-R...
http://localhost:3333
Typically, consumer endpoint would not recieve INBOUND proxy traffic
http://localhost:3333...
http://localhost:8082/swagger/index.html
Private Endpoint that talks to the proxy-router API interface 
(Access to Wallet Actions-keep secure!)
http://localhost:8082/swagger/index.html...
Morpheus-Lumerin GUIUI-Desktop (electron app) 
1
1
2
2
4
4
6
6
5
5
3
3
Blockchain

Blockchain -
Existing / Foundational Elements

Arbitrum BlockChain, Token Contract & Smart Contract
MOR_TOKEN_ADDRESS=0xc1664f994fd3991f98ae944bc16b9aed673ef5fd
DIAMOND_CONTRACT_ADDRESS=0x8e19288d908b2d9F8D7C539c74C899808AC3dE45
Existing / Foundational Elements...
0
0
Text is not SVG - cannot display
\ No newline at end of file +
Provider Registration
Provider Registration
Model Registration 
Model Registration 
Bid Offer
Bid Offer
Model Registration 
Model Registration 
Bid Offer
Bid Offer
Bid Offer
Bid Offer
Bid Offer 0x1234...abc
Bid Offer 0x1234...abc
Provider Registration
Provider Registration
Model Registration 
Model Registration 
Bid Offer
Bid Offer
Model Registration 
Model Registration 
Bid Offer
Bid Offer
Bid Offer
Bid Offer
Bid Offer 0x1234...abc
Bid Offer 0x1234...abc
CONSUMER 
CONSUMER 
PROVIDER
PROVIDER
AI Compute Farm or Service
AI Compute Farm or Service
https://mycoolai.serverfarm.io:8080
Private Endpoint exposed only to the Lumerin Proxy-Router
https://mycoolai.serverfarm.io:8080...
models-config.json 
/proxy-router/.env variable
OPENAI_BASE_URL=
models-config.json &...
Lumerin Proxy-Router
Lumerin Proxy-R...
/proxy-router/.env define local address & port
PROXY_ADDRESS=
/proxy-router/.env define local address & port...
http://mycoolproxy.serverfarm.io:3333
Public Provider Endpoint that talks to the Blockchain
and Receives inbound prompts from purchased model bids
http://mycoolproxy.serverfarm.io:3333...
/proxy-router/.env variables
WEB_ADDRESS=0.0.0.0:8082
WEB_PUBLIC_URL=localhost:8082
/proxy-router/.env variables...
http://mycoolproxy.serverfarm.io:8082/swagger/index.html
Private Endpoint that talks to the proxy-router API interface (Access to Wallet Actions-keep secure!)
http://mycoolproxy.serverfarm.io:8082/swagger/index.html...
Arbitrum Ethereum
WebSocket Service Endpoint 
(wss://.......) 

Arbitrum...
/proxy-router/.env variable
ETH_NODE_ADDRESS=wss://
/proxy-router/.env variable...
Provider Registration
Provider Registration
Model Registration 
Model Registration 
Bid Offer
Bid Offer
Model Registration 
Model Registration 
Bid Offer
Bid Offer
Bid Offer
Bid Offer
Bid Offer 0x1234...abc
Bid Offer 0x1234...abc
Local LLama.cpp AI Model
Local...
https://localhost:8080
Internal Node Endpoint exposed only to the Lumerin Proxy-Router
https://localhost:8080...
Lumerin Proxy-Router
Lumerin Proxy-R...
http://localhost:3333
Typically, consumer endpoint would not recieve INBOUND proxy traffic
http://localhost:3333...
http://localhost:8082/swagger/index.html
Private Endpoint that talks to the proxy-router API interface 
(Access to Wallet Actions-keep secure!)
http://localhost:8082/swagger/index.html...
Morpheus-Lumerin GUIMorpheusUI (electron app) 
1
1
2
2
4
4
6
6
5
5
3
3
Blockchain

Blockchain +
Existing / Foundational Elements

Arbitrum BlockChain, Token Contract & Smart Contract
MOR_TOKEN_ADDRESS=0x34a285a1b1c166420df5b6630132542923b5b27e
DIAMOND_CONTRACT_ADDRESS=0xb8C55cD613af947E73E262F0d3C54b7211Af16CF
Existing / Foundational Elements...
0
0
Text is not SVG - cannot display
\ No newline at end of file diff --git a/docs/mac-boot-strap.md b/docs/mac-boot-strap.md index 724cb5b9..52f3020f 100644 --- a/docs/mac-boot-strap.md +++ b/docs/mac-boot-strap.md @@ -1,7 +1,7 @@ ## "Simple Run From Mac" - 4 terminal windows ### Overview -- This is a simple guide to get the Llama.cpp model, Lumerin proxy-router and ui-desktop from source running on a Mac +- This is a simple guide to get the Llama.cpp model, Lumerin proxy-router and MorpheusUI from source running on a Mac - This is a guide for a developer or someone familiar with the codebase and build process - Wallet: if you’re going to start with an existing wallet from something like MetaMask (recommended)…make sure it’s a tier 1, not a derived or secondary address. Desktop-ui recover from mnemonic won’t work properly if you try to recover a secondary address with the primary mnemonic. - Install & Configure OS-Specific Dependencies @@ -15,7 +15,7 @@ 1. Clone, build select model and run local Llama.cpp model 2. Clone the Morpheus-Lumerin-Node repo from Github 3. Configure, Build and run the proxy-router - 4. Configure, Build and run the ui-desktop + 4. Configure, Build and run the MorpheusUI 5. Configure, Build and run the cli ## **A. LLAMA.CPP** @@ -116,7 +116,7 @@ make run ```sh 2024-08-07T11:35:49.116184 INFO proxy state: running 2024-08-07T11:35:49.116534 INFO Wallet address: -2024-08-07T11:35:49.116652 INFO started watching events, address 0x8e19288d908b2d9F8D7C539c74C899808AC3dE45 +2024-08-07T11:35:49.116652 INFO started watching events, address 0xb8C55cD613af947E73E262F0d3C54b7211Af16CF 2024-08-07T11:35:49.116924 INFO HTTP http server is listening: 0.0.0.0:8082 2024-08-07T11:35:49.116962 INFO TCP tcp server is listening: 0.0.0.0:3333 ``` @@ -124,16 +124,16 @@ make run **- NOTE** if you would like to interact directly with your proxy-router without the UI, see the instructions in [/docs/proxy-router-api-direct.md](/docs/proxy-router-api-direct.md) -## **C. UI-DESKTOP** +## **C. MorpheusUI** * Open third terminal / cli window * You will need to know * TCP port that your proxy-router API interface is listening on (8082 in this example) -**1. Navigate to ui-desktop** -`cd /Morpheus-Lumerin-Node/ui-desktop` +**1. Navigate to MorpheusUI** +`cd /Morpheus-Lumerin-Node/MorpheusUI` **2. Check Environment Variables** -- Within the ui-desktop directory, copy the `.env.example` to `.env` and check the variables as needed +- Within the MorpheusUI directory, copy the `.env.example` to `.env` and check the variables as needed - At the current time, the defaults in the .env file shold be sufficient to operate as long as none of the LLAMA.cpp or proxy-router variables for ports have changed. - Double check that your PROXY_WEB_URL is set to `8082` or what you used for the ASwagger API interface on the proxy-router. - This is what enables the UI to communicate to the proxy-router environment @@ -143,28 +143,28 @@ cp .env.example .env vi .env ``` -**3. Install dependicies, compile and Run the ui-desktop** +**3. Install dependicies, compile and Run the MorpheusUI** ```sh yarn install yarn dev ``` -**4. Validate that the ui-desktop is running:** +**4. Validate that the MorpheusUI is running:** - At this point, the electon app should start and if this is the first time walking through, should run through onboarding - Check the following: - Lower left corner - is this your correct ERC20 Wallet Address? - - On the Wallet tab, do you show saMOR and saETH balances? - - if not, you'll need to convert and transfer some saETH to saMOR to get started + - On the Wallet tab, do you show MOR and ETH balances? + - if not, you'll need to convert and transfer some ETH to MOR to get started - On the Chat tab, your should see your `Provider: (local)` selected by default...use the "Ask me anything..." prompt to run inference - this verifies that all three layers have been setup correctly? - Click the Change Model, select a remote model, click Start and now you should be able to interact with the model through the UI. **Cleaning & Troubleshooting** - Sometimes, due to development changes or dependency issues, you may need to clean and start fresh. - Make sure you know what your WalletPrivate key is and have it saved in a secure location. before cleaning up and restarting the ui or proxy-router - - `rm -rf ./node_modules` from within ui-desktop - - `rm -rf '~/Library/Application Support/ui-desktop'` to clean old ui-desktop cache and start new wallet -- The proxy-router or ui-desktop may not start cleanly because of existing processes or open files from previous runs of the software - - If you need to exit either proxy-router or ui-desktop, you can use `ctrl-c` from the terminal window you started them to kill the processes… + - `rm -rf ./node_modules` from within MorpheusUI + - `rm -rf '~/Library/Application Support/MorpheusUI'` to clean old MorpheusUI cache and start new wallet +- The proxy-router or MorpheusUI may not start cleanly because of existing processes or open files from previous runs of the software + - If you need to exit either proxy-router or MorpheusUI, you can use `ctrl-c` from the terminal window you started them to kill the processes… - **Locked Processes** Doing this may leave "dangling" processes or open files to find them: - Run `ps -ax | grep electron` or `ps -ax | grep proxy-router` which will show you the processes and particualrly the procexss id - Run `kill -9 xxxxx` where `xxxxx` is the process ID of the un-cleaned process @@ -177,7 +177,7 @@ yarn dev * You will need to know * TCP port that your proxy-router API interface is listening on (8082 in this example) -**1. Navigate to ui-desktop** +**1. Navigate to MorpheusUI** `cd /Morpheus-Lumerin-Node/cli` **2. Check Environment Variables** diff --git a/docs/models-config.json.md b/docs/models-config.json.md new file mode 100644 index 00000000..44d5502e --- /dev/null +++ b/docs/models-config.json.md @@ -0,0 +1,77 @@ +# Example models config file. Local model configurations are stored in this file + +- `modelId` (required) is the model id +- `modelName` (required) is the name of the model +- `apiType` (required) is the type of the model api. Currently supported values are "prodia-sd", "prodia-sdxl", "prodia-v2" and "openai" +- `apiUrl` (required) is the url of the LLM server or model API +- `apiKey` (optional) is the api key for the model +- `concurrentSlots` (optional) are number of available distinct chats on the llm server and used for capacity policy +- `capacityPolicy` (optional) can be one of the following: "idle_timeout", "simple" + +## Examples of models-config.json entries + +This file enables the morpheus-proxy-router to route requests to the correct model API. The model API can be hosted on the same server as the morpheus-proxy-router or on an external server. Please refer to the json-schema for descriptions and list of required and optional fields. + +```json +{ + "$schema": "./internal/config/models-config-schema.json", + "models": [ + { + "modelId": "0x0000000000000000000000000000000000000000000000000000000000000000", + "modelName": "llama2", + "apiType": "openai", + "apiUrl": "http://localhost:8080/v1", + "capacityPolicy": "simple", + "concurrentSlots": 2 + }, + { + "modelId": "0x0000000000000000000000000000000000000000000000000000000000000001", + "modelName": "v1-5-pruned-emaonly.safetensors [d7049739]", + "apiType": "prodia-sd", + "apiUrl": "https://api.prodia.com/v1", + "apiKey": "FILL_ME_IN" + } + ] +} +``` + +## Examples of models-config.json entries LEGACY + +- The first key (`0x000...0000`) is the model id of the local default model (llama2) +- The middle two keys are examples of externally hosted and owned models where the morpheus-proxy-router enables proxying requests to the external model API +- The last key is an example of a model hosted on a server owned by the morpheus-proxy-router operator + +```json +{ + "0x0000000000000000000000000000000000000000000000000000000000000000": { + "modelName": "llama2", + "apiType": "openai", + "apiUrl": "http://localhost:8080/v1" + }, + "0x60d5900b10534de1a668fd990bd790fa3fe04df8177e740f249c750023a680fb": { + "modelName": "v1-5-pruned-emaonly.safetensors [d7049739]", + "apiType": "prodia-sd", + "apiUrl": "https://api.prodia.com/v1", + "apiKey": "replace-with-your-api-key" + }, + "0x0d90cf8ca0a811a5cd2347148171e9a2401e9fbc32f683b648c5c1381df91ff7": { + "modelName": "animagineXLV3_v30.safetensors [75f2f05b]", + "apiType": "prodia-sdxl", + "apiUrl": "https://api.prodia.com/v1", + "apiKey": "replace-with-your-api-key" + }, + "0x06c7b502d0b7f14a96bb4fda5f2ba941068601d5f6b90804c9330e96b093b0ce": { + "modelName": "LMR-Collective Cognition Mistral 7B", + "apiType": "openai", + "apiUrl": "http://llmserver.domain.io:8080/v1", + "concurrentSlots": 8, + "capacityPolicy": "simple" + }, + "0xe086adc275c99e32bb10b0aff5e8bfc391aad18cbb184727a75b2569149425c6": { + "apiUrl": "https://inference.prodia.com/v2", + "modelName": "inference.mochi1.txt2vid.v1", + "apiType": "prodia-v2", + "apiKey": "replace-with-your-api-key" + } +} +``` diff --git a/docs/proxy-router-api-direct.md b/docs/proxy-router-api-direct.md index 94c163d6..b0a6aeb6 100644 --- a/docs/proxy-router-api-direct.md +++ b/docs/proxy-router-api-direct.md @@ -1,8 +1,8 @@ -# Direct Consumer interaction with the proxy-router (no ui-desktop) -This document provides a step-by-step flow to query your local proxy router and interact with a remote model using only the API. This is useful for developers or users who want to interact with the model directly without using the UI-Desktop. +# Direct Consumer interaction with the proxy-router (no MorpheusUI) +This document provides a step-by-step flow to query your local proxy router and interact with a remote model using only the API. This is useful for developers or users who want to interact with the model directly without using the MorpheusUI. ## Pre-requisites: -* Create or use an existing ERC-20 wallet that has saMOR and saETH (Sepolia Arbitrum) tokens - you can use Metamask (new wallet..not derived) or any other ERC-20 wallet. +* Create or use an existing ERC-20 wallet that has MOR and ETH (Sepolia Arbitrum) tokens - you can use Metamask (new wallet..not derived) or any other ERC-20 wallet. * You will need to have access to the wallet's private key **NEVER SHARE THIS WITH ANYONE** for steps below to authorize the contract to spend on your behalf. * Install and launch the local llama.cpp and proxy-router from source (see [/docs/mac-boot-strap.md](/docs/mac-boot-strap.md) for instructions) @@ -18,10 +18,10 @@ This document provides a step-by-step flow to query your local proxy router and ### B. Authorize the contract to spend on your behalf Either via the swagger interface http://localhost:8082/swagger/index.html#/wallet/post_blockchain_allowance or following CLI, you can authorize the contract to spend on your behalf. **This only needs to be done once per wallet, or when funds have been depleted.** -Approve the contract to spend 3 saMOR tokens on your behalf +Approve the contract to spend 3 MOR tokens on your behalf ```sh -curl -X 'POST' 'http://localhost:8082/blockchain/approve?spender=0x8e19288d908b2d9F8D7C539c74C899808AC3dE45&amount=3' -H 'accept: application/json' -d '' +curl -X 'POST' 'http://localhost:8082/blockchain/approve?spender=0xb8C55cD613af947E73E262F0d3C54b7211Af16CF&amount=3' -H 'accept: application/json' -d '' ``` ### C. Query the blockchain for various models / providers (Get ModelID) @@ -110,8 +110,8 @@ curl -X 'POST' \ ### Quick and Dirty Sample: -`curl -X 'POST' 'http://localhost:8082/blockchain/approve?spender=0x8e19288d908b2d9F8D7C539c74C899808AC3dE45&amount=3' -H 'accept: application/json' -d ''` - # approves the smart contract `0x8e19...dE45` to spend 3 saMOR tokens on your behalf +`curl -X 'POST' 'http://localhost:8082/blockchain/approve?spender=0xb8C55cD613af947E73E262F0d3C54b7211Af16CF&amount=3' -H 'accept: application/json' -d ''` + # approves the smart contract `0x8e19...dE45` to spend 3 MOR tokens on your behalf `curl -s -X 'GET' 'http://localhost:8082/wallet' -H 'accept: application/json' | jq .address` # returns the wallet ID (confirm that it matches your wallet) diff --git a/docs/proxy-router.all.env b/docs/proxy-router.all.env new file mode 100644 index 00000000..dcb06301 --- /dev/null +++ b/docs/proxy-router.all.env @@ -0,0 +1,93 @@ +# Full set of proxy-router variables based on the proxy-router/internal/config/config.go file +# Includes known TESTNET and MAINNET Values if/when known +# Currently aligned to TESTNET, but after MAINNET launch, will be updated to MAINNET values + +# Application Configurations +# Set to true to reset mac keychain on start +APP_RESET_KEYCHAIN=false + +# Blockchain Configurations +# Ethereum Chain ID (must be a number) +# TESTNET: 421614, MAINNET: 1 +ETH_NODE_CHAIN_ID=421614 +# Ethereum node URL (optional, must be a valid URL) +ETH_NODE_ADDRESS= +# Set to true to disable EIP-1559 transactions +ETH_NODE_LEGACY_TX=false +# Blockchain explorer API URL (required, must be a valid URL) +# TESTNET: https://api-sepolia.arbiscan.io/api, MAINNET: https://api.arbiscan.io/api +EXPLORER_API_URL=https://api-sepolia.arbiscan.io/api +# Delay between retries for blockchain explorer API (defaults to 5s if not set) +EXPLORER_RETRY_DELAY= +# Maximum retries for explorer requests (defaults to 5 if not set) +EXPLORER_MAX_RETRIES= +# Set to true to enable subscriptions/wss for blockchain events, otherwise, http polling will be used +ETH_NODE_USE_SUBSCRIPTIONS=false +# Interval for polling eth node for new events (defaults to 10s if not set) +ETH_NODE_POLLING_INTERVAL= +# Maximum number of reconnect attempts to Ethereum node (defaults to 30 if not set) +ETH_NODE_MAX_RECONNECTS= + +# Environment Configuration +# Environment for the application (default is "development", production is "production") +ENVIRONMENT=development + +# Marketplace Configurations +# Diamond contract address (optional, must be a valid Ethereum address) +# TESTNET: 0xb8C55cD613af947E73E262F0d3C54b7211Af16CF, MAINNET: 0xDE819AaEE474626E3f34Ef0263373357e5a6C71b +DIAMOND_CONTRACT_ADDRESS=0xb8C55cD613af947E73E262F0d3C54b7211Af16CF +# MOR token address (optional, must be a valid Ethereum address) +# TESTNET: 0x34a285a1b1c166420df5b6630132542923b5b27e, MAINNET: 0x092bAaDB7DEf4C3981454dD9c0A0D7FF07bCFc86 +MOR_TOKEN_ADDRESS=0x34a285a1b1c166420df5b6630132542923b5b27e +# Private key for signing transactions; if not set, the system keychain will be used +WALLET_PRIVATE_KEY= + +# Logging Configurations +# Enable colored logging +LOG_COLOR=false +# Enables logging and folder path for log files (must be a valid directory path) +LOG_FOLDER_PATH= +# Set to true for production log format +LOG_IS_PROD=false +# Log format as JSON +LOG_JSON=false +# Log levels for various components (one of debug info warn error dpanic panic fatal) +LOG_LEVEL_APP=debug +LOG_LEVEL_TCP=info +LOG_LEVEL_ETH_RPC=info +LOG_LEVEL_STORAGE=info + +# Proxy Configurations +# Address for the proxy (default is "0.0.0.0:3333" if not set) +PROXY_ADDRESS=0.0.0.0:3333 +# Path for proxy storage (default is "./data/badger/") +PROXY_STORAGE_PATH=./data/badger/ +# Set to true to store chat context in proxy storage +PROXY_STORE_CHAT_CONTEXT=true +# Prepend whole stored message history to the prompt +PROXY_FORWARD_CHAT_CONTEXT=true +# Path to models configuration file +MODELS_CONFIG_PATH= + +# System Configurations +# Enable system-level configuration adjustments +SYS_ENABLE=false +# Local port range (default is "1024 65535") +SYS_LOCAL_PORT_RANGE=1024 65535 +# Max backlog for network devices (default is "100000") +SYS_NET_DEV_MAX_BACKLOG=100000 +# Hard limit for open file descriptors (default is 524288) +SYS_RLIMIT_HARD=524288 +# Soft limit for open file descriptors (default is 524288) +SYS_RLIMIT_SOFT=524288 +# Maximum connections allowed in the queue before they are refused +# (default is "100000" for Linux, "2048" for Darwin/macOS) +SYS_SOMAXCONN=100000 +# Maximum number of half-open connections that can be queued (default is "100000") +SYS_TCP_MAX_SYN_BACKLOG=100000 + +# Web Configurations +# Address for the web server (default is "0.0.0.0:8082" if not set) +WEB_ADDRESS=0.0.0.0:8082 +# Public URL of the proxyrouter (falls back to http://Localhost:WEB_ADDRESS if not set) +WEB_PUBLIC_URL=http://localhost:8082 \ No newline at end of file diff --git a/docs/rating-config.json.md b/docs/rating-config.json.md new file mode 100644 index 00000000..e1fa572e --- /dev/null +++ b/docs/rating-config.json.md @@ -0,0 +1,27 @@ +# Information about rating-config.json configuration file + +This file configures rating system of proxy-router, that is responsible for provider selection. The file should be placed in the root directory of the project. + +- `providerAllowlist` - the list of providers that are allowed to be used by the proxy-router. Keep it empty to allow all providers. + - `"providerAllowlist": ["0x0000000000000000000000000000000000000000"]` will only allow the local, default model to be used +- `algorithm` - the algorithm used for rating calculation. +- `params` - algorithm parameters, like weights for different metrics. Each algorithm has its own set of parameters. + +Please refer to the json schema for the full list of available fields. + +```json +{ + "$schema": "./internal/rating/rating-config-schema.json", + "algorithm": "default", + "providerAllowlist": [], + "params": { + "weights": { + "tps": 0.24, + "ttft": 0.08, + "duration": 0.24, + "success": 0.32, + "stake": 0.12 + } + } +} +``` diff --git a/docs/source/overview.drawio b/docs/source/overview.drawio index 0b9111c9..69117e98 100644 --- a/docs/source/overview.drawio +++ b/docs/source/overview.drawio @@ -153,7 +153,7 @@ - + @@ -218,7 +218,7 @@ - + @@ -261,7 +261,7 @@ - + diff --git a/docs/toc.md b/docs/toc.md index 47a3be4f..321e0212 100644 --- a/docs/toc.md +++ b/docs/toc.md @@ -9,7 +9,7 @@ Document outline: 1. Installation 1. From Binaries, most simplistic to get up and running [install_from_binaries.md](install_from_binaries.md) * Need ETH node solution (Http round robin) from Shev - * Create new Wallet within UI-Desktop + * Create new Wallet within MorpheusUI * Send aETH and aMOR to wallet (from separate wallet or mechanism) * Variations for Mac ARM, Mac Intel, Linux, Windows * Needs to be as easy and as simple as possible (minimal clicks/configuration) diff --git a/docs/ui-desktop.all.env b/docs/ui-desktop.all.env new file mode 100644 index 00000000..470aefe5 --- /dev/null +++ b/docs/ui-desktop.all.env @@ -0,0 +1,57 @@ +# Full set of MorpheusUI variables based on the MorpheusUI/src/main/config/index.ts file +# Includes known TESTNET and MAINNET Values if/when known +# Currently aligned to TESTNET, but after MAINNET launch, will be updated to MAINNET values + +# Chain Configurations +# Enable bypass authentication (set to "true" to bypass authentication) +BYPASS_AUTH=false + +# Chain ID for blockchain network (required) +# Ethereum Chain ID (must be a number) +# TESTNET: 421614, MAINNET: 42161 +CHAIN_ID= + +# Default currency symbol for sellers (default is "BTC") +DEFAULT_SELLER_CURRENCY=BTC + +# Diamond contract address for the chain (required) +# TESTNET: 0xb8C55cD613af947E73E262F0d3C54b7211Af16CF, MAINNET: 0xDE819AaEE474626E3f34Ef0263373357e5a6C71b +DIAMOND_ADDRESS=0xb8C55cD613af947E73E262F0d3C54b7211Af16CF + +# Display name for the application (optional) +DISPLAY_NAME=MorpheusUI + +# Blockchain explorer URL (optional, must be a valid URL) +EXPLORER_URL= + +# Local Proxy Router URL (default is "http://localhost:8082") +# Automatically set based on PROXY_WEB_DEFAULT_PORT or defaults to 8082 +PROXY_WEB_DEFAULT_PORT=8082 + +# Token contract address for the main token (required) +# TESTNET: 0x34a285a1b1c166420df5b6630132542923b5b27e, MAINNET: 0x092bAaDB7DEf4C3981454dD9c0A0D7FF07bCFc86 +TOKEN_ADDRESS=0x34a285a1b1c166420df5b6630132542923b5b27e + +# Symbol for the primary token (default is "MOR") +SYMBOL_COIN=MOR + +# Symbol for Ethereum token (default is "ETH") +SYMBOL_ETH=ETH + +# Debug Configurations +# Enable debug mode (set to "true" to enable debug logging, requires IGNORE_DEBUG_LOGS=false) +DEBUG=false +# Ignore debug logs even if DEBUG is enabled (set to "true" to ignore) +IGNORE_DEBUG_LOGS=false + +# Enable developer tools in the Electron app (set to "true" to enable) +DEV_TOOLS=false + +# Sentry DSN for error tracking (optional) +SENTRY_DSN= + +# Google Analytics tracking ID (optional) +TRACKING_ID= + +# Session Failover Policy Enable (optional) (by default "true") +FAILOVER_ENABLED= \ No newline at end of file diff --git a/go.work b/go.work deleted file mode 100644 index 7cf97849..00000000 --- a/go.work +++ /dev/null @@ -1,5 +0,0 @@ -go 1.22.0 - -use ./launcher -use ./proxy-router -use ./cli \ No newline at end of file diff --git a/go.work.sum b/go.work.sum deleted file mode 100644 index fa557e02..00000000 --- a/go.work.sum +++ /dev/null @@ -1,758 +0,0 @@ -cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= -cloud.google.com/go v0.43.0/go.mod h1:BOSR3VbTLkk6FDC/TcffxP4NF/FFBGA5ku+jvKOP7pg= -cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= -cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= -cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= -cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= -cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= -cloud.google.com/go v0.51.0/go.mod h1:hWtGJ6gnXH+KgDv+V0zFGDvpi07n3z8ZNj3T1RW0Gcw= -cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= -cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= -cloud.google.com/go/bigtable v1.2.0/go.mod h1:JcVAOl45lrTmQfLj7T6TxyMzIN/3FGGcFm+2xVAli2o= -cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= -cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= -cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= -cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= -cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= -collectd.org v0.3.0/go.mod h1:A/8DzQBkF6abtvrT2j/AU/4tiBgJWYyh0y/oB/4MlWE= -dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= -github.com/AndreasBriese/bbloom v0.0.0-20190306092124-e2d15f34fcf9/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8= -github.com/Azure/azure-sdk-for-go/sdk/azcore v0.21.1/go.mod h1:fBF9PQNqB8scdgpZ3ufzaLntG0AG7C1WjPMsiFOmfHM= -github.com/Azure/azure-sdk-for-go/sdk/internal v0.8.3/go.mod h1:KLF4gFr6DcKFZwSuH8w8yEK6DpFl3LP5rhdvAb7Yz5I= -github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v0.3.0/go.mod h1:tPaiy8S5bQ+S5sOiDlINkp7+Ef339+Nz5L5XO+cnOHo= -github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= -github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= -github.com/CloudyKit/fastprinter v0.0.0-20200109182630-33d98a066a53/go.mod h1:+3IMCy2vIlbG1XG/0ggNQv0SvxCAIpPM5b1nCz56Xno= -github.com/CloudyKit/jet/v3 v3.0.0/go.mod h1:HKQPgSJmdK8hdoAbKUUWajkHyHo4RaU5rMdUywE7VMo= -github.com/CloudyKit/jet/v6 v6.1.0/go.mod h1:d3ypHeIRNo2+XyqnGA8s+aphtcVpjP5hPwP/Lzo7Ro4= -github.com/DATA-DOG/go-sqlmock v1.3.3/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM= -github.com/HdrHistogram/hdrhistogram-go v1.1.2/go.mod h1:yDgFjdqOqDEKOvasDdhWNXYg9BVp4O+o5f6V/ehm6Oo= -github.com/Joker/hpp v1.0.0/go.mod h1:8x5n+M1Hp5hC0g8okX3sR3vFQwynaX/UgSOM9MeBKzY= -github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= -github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= -github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= -github.com/Shopify/goreferrer v0.0.0-20181106222321-ec9c9a553398/go.mod h1:a1uqRtAwp2Xwc6WNPJEufxJ7fx3npB4UV/JOLmbu5I0= -github.com/Shopify/goreferrer v0.0.0-20220729165902-8cddb4f5de06/go.mod h1:7erjKLwalezA0k99cWs5L11HWOAPNjdUZ6RxH1BXbbM= -github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg= -github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY= -github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw= -github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= -github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= -github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= -github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= -github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM= -github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8= -github.com/andybalholm/brotli v1.0.4/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= -github.com/apache/arrow/go/arrow v0.0.0-20191024131854-af6fa24be0db/go.mod h1:VTxUBvSJ3s3eHAg65PNgrsn5BtqCRPdmyXh6rAfdxN0= -github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= -github.com/atotto/clipboard v0.1.4 h1:EH0zSVneZPSuFR11BlR9YppQTVDbh5+16AmcJi4g1z4= -github.com/atotto/clipboard v0.1.4/go.mod h1:ZY9tmq7sm5xIbd9bOK4onWV4S6X0u6GY7Vn0Yu86PYI= -github.com/aws/aws-sdk-go-v2 v1.2.0/go.mod h1:zEQs02YRBw1DjK0PoJv3ygDYOFTre1ejlJWl8FwAuQo= -github.com/aws/aws-sdk-go-v2/config v1.1.1/go.mod h1:0XsVy9lBI/BCXm+2Tuvt39YmdHwS5unDQmxZOYe8F5Y= -github.com/aws/aws-sdk-go-v2/credentials v1.1.1/go.mod h1:mM2iIjwl7LULWtS6JCACyInboHirisUUdkBPoTHMOUo= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.0.2/go.mod h1:3hGg3PpiEjHnrkrlasTfxFqUsZ2GCk/fMUn4CbKgSkM= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.0.2/go.mod h1:45MfaXZ0cNbeuT0KQ1XJylq8A6+OpVV2E5kvY/Kq+u8= -github.com/aws/aws-sdk-go-v2/service/route53 v1.1.1/go.mod h1:rLiOUrPLW/Er5kRcQ7NkwbjlijluLsrIbu/iyl35RO4= -github.com/aws/aws-sdk-go-v2/service/sso v1.1.1/go.mod h1:SuZJxklHxLAXgLTc1iFXbEWkXs7QRTQpCLGaKIprQW0= -github.com/aws/aws-sdk-go-v2/service/sts v1.1.1/go.mod h1:Wi0EBZwiz/K44YliU0EKxqTCJGUfYTWXrrBwkq736bM= -github.com/aws/smithy-go v1.1.0/go.mod h1:EzMw8dbp/YJL4A5/sbhGddag+NPT7q084agLbB9LgIw= -github.com/aymanbagabas/go-osc52 v1.0.3/go.mod h1:zT8H+Rk4VSabYN90pWyugflM3ZhpTZNC7cASDfUCdT4= -github.com/aymanbagabas/go-osc52 v1.2.1 h1:q2sWUyDcozPLcLabEMd+a+7Ea2DitxZVN9hTxab9L4E= -github.com/aymanbagabas/go-osc52 v1.2.1/go.mod h1:zT8H+Rk4VSabYN90pWyugflM3ZhpTZNC7cASDfUCdT4= -github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k= -github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8= -github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4= -github.com/aymerick/raymond v2.0.3-0.20180322193309-b565731e1464+incompatible/go.mod h1:osfaiScAUVup+UC9Nfq76eWqDhXlp+4UYaA8uhTBO6g= -github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= -github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= -github.com/bits-and-blooms/bitset v1.7.0/go.mod h1:gIdJ4wp64HaoK2YrL1Q5/N7Y16edYb8uY+O0FJTyyDA= -github.com/bmizerany/pat v0.0.0-20170815010413-6226ea591a40/go.mod h1:8rLXio+WjiTceGBHIoTvn60HIbs7Hm7bcHjyrSqYB9c= -github.com/boltdb/bolt v1.3.1/go.mod h1:clJnj/oiGkjum5o1McbSZDSLxVThjynRyGBgiAx27Ps= -github.com/btcsuite/btcd/btcec/v2 v2.1.2/go.mod h1:ctjw4H1kknNJmRN4iP1R7bTQ+v3GJkZBd6mui8ZsAZE= -github.com/btcsuite/btcd/chaincfg/chainhash v1.0.0/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc= -github.com/btcsuite/goleveldb v1.0.0/go.mod h1:QiK9vBlgftBg6rWQIj6wFzbPfRjiykIEhBH4obrXJ/I= -github.com/btcsuite/snappy-go v1.0.0/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc= -github.com/c-bata/go-prompt v0.2.2/go.mod h1:VzqtzE2ksDBcdln8G7mk2RX9QyGjH+OVqOCSiVIqS34= -github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= -github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= -github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= -github.com/charmbracelet/bubbles v0.15.0 h1:c5vZ3woHV5W2b8YZI1q7v4ZNQaPetfHuoHzx+56Z6TI= -github.com/charmbracelet/bubbles v0.15.0/go.mod h1:Y7gSFbBzlMpUDR/XM9MhZI374Q+1p1kluf1uLl8iK74= -github.com/charmbracelet/bubbletea v0.23.1/go.mod h1:JAfGK/3/pPKHTnAS8JIE2u9f61BjWTQY57RbT25aMXU= -github.com/charmbracelet/bubbletea v0.23.2 h1:vuUJ9HJ7b/COy4I30e8xDVQ+VRDUEFykIjryPfgsdps= -github.com/charmbracelet/bubbletea v0.23.2/go.mod h1:FaP3WUivcTM0xOKNmhciz60M6I+weYLF76mr1JyI7sM= -github.com/charmbracelet/harmonica v0.2.0/go.mod h1:KSri/1RMQOZLbw7AHqgcBycp8pgJnQMYYT8QZRqZ1Ao= -github.com/charmbracelet/lipgloss v0.6.0/go.mod h1:tHh2wr34xcHjC2HCXIlGSG1jaDF0S0atAUvBMP6Ppuk= -github.com/charmbracelet/lipgloss v0.7.1 h1:17WMwi7N1b1rVWOjMT+rCh7sQkvDU75B2hbZpc5Kc1E= -github.com/charmbracelet/lipgloss v0.7.1/go.mod h1:yG0k3giv8Qj8edTCbbg6AlQ5e8KNWpFujkNawKNhE2c= -github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk= -github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= -github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= -github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= -github.com/cloudflare/cloudflare-go v0.14.0/go.mod h1:EnwdgGMaFOruiPZRFSgn+TsQ3hQ7C/YWzIGLeu5c304= -github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= -github.com/cockroachdb/datadriven v1.0.2/go.mod h1:a9RdTaap04u637JoCzcUoIcDmvwSUtcUFtT/C3kJlTU= -github.com/cockroachdb/logtags v0.0.0-20211118104740-dabe8e521a4f/go.mod h1:Vz9DsVWQQhf3vs21MhPMZpMGSht7O/2vFW2xusFUVOs= -github.com/cockroachdb/sentry-go v0.6.1-cockroachdb.2/go.mod h1:8BT+cPK6xvFOcRlk0R8eg+OTkcqI6baNH4xAkpiYVvQ= -github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0/go.mod h1:4Zcjuz89kmFXt9morQgcfYZAYZ5n8WHjt81YYWIwtTM= -github.com/consensys/bavard v0.1.8-0.20210406032232-f3452dc9b572/go.mod h1:Bpd0/3mZuaj6Sj+PqrmIquiOKy397AKGThQPaGzNXAQ= -github.com/consensys/bavard v0.1.13/go.mod h1:9ItSMtA/dXMAiL7BG6bqW2m3NdSEObYWoH223nGHukI= -github.com/consensys/gnark-crypto v0.4.1-0.20210426202927-39ac3d4b3f1f/go.mod h1:815PAHg3wvysy0SyIqanF8gZ0Y1wjk/hrDHD/iT88+Q= -github.com/consensys/gnark-crypto v0.10.0/go.mod h1:Iq/P3HHl0ElSjsg2E1gsMwhAyxnxoKK5nVyZKd+/KhU= -github.com/containerd/console v1.0.3 h1:lIr7SlA5PxZyMV30bDW0MGbiOPXwc63yRuCP0ARubLw= -github.com/containerd/console v1.0.3/go.mod h1:7LqA/THxQ86k76b8c/EMSiaJ3h1eZkMkXar0TQ1gf3U= -github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= -github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= -github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= -github.com/cpuguy83/go-md2man v1.0.10 h1:BSKMNlYxDvnunlTymqtgONjNnaRV1sTpcovwwjF22jk= -github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= -github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= -github.com/cpuguy83/go-md2man/v2 v2.0.4 h1:wfIWP927BUkWJb2NmU/kNDYIBTh/ziUX91+lVfRxZq4= -github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= -github.com/crate-crypto/go-ipa v0.0.0-20220523130400-f11357ae11c7/go.mod h1:gFnFS95y8HstDP6P9pPwzrxOOC5TRDkwbM+ao15ChAI= -github.com/crate-crypto/go-kzg-4844 v0.2.0/go.mod h1:SBP7ikXEgDnUPONgm33HtuDZEDtWa3L4QtN1ocJSEQ4= -github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= -github.com/cyberdelia/templates v0.0.0-20141128023046-ca7fffd4298c/go.mod h1:GyV+0YP4qX0UQ7r2MoYZ+AvYDp12OF5yg4q8rGnyNh4= -github.com/dave/jennifer v1.2.0/go.mod h1:fIb+770HOpJ2fmN9EPPKOqm1vMGhB+TwXKMZhrIygKg= -github.com/deckarep/golang-set v1.8.0 h1:sk9/l/KqpunDwP7pSjUg0keiOOLEnOBHzykLrsPppp4= -github.com/deckarep/golang-set v1.8.0/go.mod h1:5nI87KwE7wgsBU1F4GKAw2Qod7p5kyS383rP6+o6qqo= -github.com/decred/dcrd/lru v1.0.0/go.mod h1:mxKOwFd7lFjN2GZYsiz/ecgqR6kkYAl+0pz0tEMk218= -github.com/deepmap/oapi-codegen v1.6.0/go.mod h1:ryDa9AgbELGeB+YEXE1dR53yAjHwFvE9iAUlWl9Al3M= -github.com/deepmap/oapi-codegen v1.8.2/go.mod h1:YLgSKSDv/bZQB7N4ws6luhozi3cEdRktEqrX88CvjIw= -github.com/dgraph-io/badger v1.6.0 h1:DshxFxZWXUcO0xX476VJC07Xsr6ZCBVRHKZ93Oh7Evo= -github.com/dgraph-io/badger v1.6.0/go.mod h1:zwt7syl517jmP8s94KqSxTlM6IMsdhYy6psNgSztDR4= -github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= -github.com/dgryski/go-bitstream v0.0.0-20180413035011-3522498ce2c8/go.mod h1:VMaSuZ+SZcx/wljOQKvp5srsbCiKDEb6K2wC4+PiBmQ= -github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= -github.com/dlclark/regexp2 v1.4.1-0.20201116162257-a2a8dda75c91/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc= -github.com/dlclark/regexp2 v1.7.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= -github.com/dnaeon/go-vcr v1.1.0/go.mod h1:M7tiix8f0r6mKKJ3Yq/kqU1OYf3MnfmBWVbPx/yU9ko= -github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ= -github.com/docker/docker v1.4.2-0.20180625184442-8e610b2b55bf/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= -github.com/docker/docker v1.6.2/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= -github.com/dop251/goja v0.0.0-20211011172007-d99e4b8cbf48/go.mod h1:R9ET47fwRVRPZnOGvHxxhuZcbrMCuiqOz3Rlrh4KSnk= -github.com/dop251/goja v0.0.0-20211022113120-dc8c55024d06/go.mod h1:R9ET47fwRVRPZnOGvHxxhuZcbrMCuiqOz3Rlrh4KSnk= -github.com/dop251/goja v0.0.0-20230122112309-96b1610dd4f7/go.mod h1:yRkwfj0CBpOGre+TwBsqPV0IH0Pk73e4PXJOeNDboGs= -github.com/dop251/goja_nodejs v0.0.0-20210225215109-d91c329300e7/go.mod h1:hn7BA7c8pLvoGndExHudxTDKZ84Pyvv+90pbBjbTz0Y= -github.com/dop251/goja_nodejs v0.0.0-20211022123610-8dd9abb0616d/go.mod h1:DngW8aVqWbuLRMHItjPUyqdj+HWPvnQe8V8y1nDpIbM= -github.com/eclipse/paho.mqtt.golang v1.2.0/go.mod h1:H9keYFcgq3Qr5OUJm/JZI/i6U7joQ8SYLhZwfeOo6Ts= -github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= -github.com/eknkc/amber v0.0.0-20171010120322-cdade1c07385/go.mod h1:0vRUJqYpeSZifjYj7uP3BG/gKcuzL9xWVV/Y+cK33KM= -github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= -github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= -github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= -github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/etcd-io/bbolt v1.3.3/go.mod h1:ZF2nL25h33cCyBtcyWeZ2/I3HQOfTP+0PIEvHjkjCrw= -github.com/ethereum/c-kzg-4844 v0.2.0/go.mod h1:WI2Nd82DMZAAZI1wV2neKGost9EKjvbpQR9OqE5Qqa8= -github.com/ethereum/go-ethereum v1.10.17/go.mod h1:Lt5WzjM07XlXc95YzrhosmR4J9Ahd6X2wyEV2SvGhk0= -github.com/fasthttp-contrib/websocket v0.0.0-20160511215533-1f3b11f56072/go.mod h1:duJ4Jxv5lDcvg4QuQr0oowTf7dz4/CR8NtyCooz9HL8= -github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= -github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= -github.com/fjl/gencodec v0.0.0-20230517082657-f9840df7b83e/go.mod h1:AzA8Lj6YtixmJWL+wkKoBGsLWy9gFrAzi4g+5bCKwpY= -github.com/flosch/pongo2/v4 v4.0.2/go.mod h1:B5ObFANs/36VwxxlgKpdchIJHMvHB562PW+BWPhwZD8= -github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k= -github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= -github.com/garslo/gogen v0.0.0-20170306192744-1d203ffc1f61/go.mod h1:Q0X6pkwTILDlzrGEckF6HKjXe48EgsY/l7K7vhY4MW8= -github.com/gavv/httpexpect v2.0.0+incompatible/go.mod h1:x+9tiU1YnrOvnB725RkpoLv1M62hOWzwo5OXotisrKc= -github.com/gballet/go-verkle v0.0.0-20220902153445-097bd83b7732/go.mod h1:o/XfIXWi4/GqbQirfRm5uTbXMG5NpqxkxblnbZ+QM9I= -github.com/getkin/kin-openapi v0.53.0/go.mod h1:7Yn5whZr5kJi6t+kShccXS8ae1APpYTW6yheSwk8Yi4= -github.com/getkin/kin-openapi v0.61.0/go.mod h1:7Yn5whZr5kJi6t+kShccXS8ae1APpYTW6yheSwk8Yi4= -github.com/getsentry/sentry-go v0.12.0/go.mod h1:NSap0JBYWzHND8oMbyi0+XZhUalc1TBdRL1M71JZW2c= -github.com/ghemawat/stream v0.0.0-20171120220530-696b145b53b9/go.mod h1:106OIgooyS7OzLDOpUGgm9fA3bQENb/cFSyyBmMoJDs= -github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= -github.com/gin-contrib/sse v0.0.0-20190301062529-5545eab6dad3/go.mod h1:VJ0WA2NBN22VlZ2dKZQPAPnyWw5XTlK1KymzLKsr59s= -github.com/gin-gonic/gin v1.4.0/go.mod h1:OW2EZn3DO8Ln9oIKOvM++LBO+5UPHJJDH72/q/3rZdM= -github.com/gin-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg= -github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU= -github.com/glycerine/go-unsnap-stream v0.0.0-20180323001048-9f0cb55181dd/go.mod h1:/20jfyN9Y5QPEAprSgKAUr+glWDY39ZiUEAYOEv5dsE= -github.com/glycerine/goconvey v0.0.0-20190410193231-58a59202ab31/go.mod h1:Ogl1Tioa0aV7gstGFO7KhffUsb9M4ydbEbbxpcEDc24= -github.com/go-check/check v0.0.0-20180628173108-788fd7840127/go.mod h1:9ES+weclKsC9YodN5RgxqK/VD9HM9JsCSh7rNhMZE98= -github.com/go-chi/chi/v5 v5.0.0/go.mod h1:BBug9lr0cqtdAhsu6R4AAdvufI0/XBzAQSsUqJpoZOs= -github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= -github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og= -github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= -github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= -github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= -github.com/go-kit/log v0.2.1/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0= -github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= -github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= -github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= -github.com/go-martini/martini v0.0.0-20170121215854-22fa46961aab/go.mod h1:/P9AEU963A2AYjv4d1V5eVL1CQbEJq6aCNHDDjibzu8= -github.com/go-ole/go-ole v1.2.1/go.mod h1:7FAglXiTm7HKlQRDeOQ6ZNUHidzCWXuZWq/1dTyBNF8= -github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= -github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= -github.com/go-sourcemap/sourcemap v2.1.3+incompatible/go.mod h1:F8jJfvm2KbVjc5NqelyYJmf/v5J0dwNLS2mL4sNA1Jg= -github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= -github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= -github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo= -github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= -github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM= -github.com/gofrs/uuid v3.3.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= -github.com/gogo/googleapis v0.0.0-20180223154316-0cd9801be74a/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s= -github.com/gogo/googleapis v1.4.1/go.mod h1:2lpHqI5OcWCtVElxXnPt+s8oJvMpySlOyM6xDCrzib4= -github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= -github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= -github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= -github.com/gogo/status v1.1.0/go.mod h1:BFv9nrluPLmrS0EmGVvLaPNmRosr9KapBYd5/hpY1WM= -github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= -github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= -github.com/golang/geo v0.0.0-20190916061304-5b978397cfec/go.mod h1:QZ0nwyI2jOfgRAoBvP+ab5aRr7c9x7lhGEJrKvBwjWI= -github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7 h1:5ZkaAPbicIKTF2I64qf5Fh8Aa83Q/dnOafMYV0OMwjA= -github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= -github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= -github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= -github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= -github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= -github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= -github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= -github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= -github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= -github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= -github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/golangci/lint-1 v0.0.0-20181222135242-d2cdd8c08219/go.mod h1:/X8TswGSh1pIozq4ZwCfxS0WA5JGXguxk94ar/4c87Y= -github.com/gomodule/redigo v1.7.1-0.20190724094224-574c33c3df38/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4= -github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/flatbuffers v1.11.0/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8= -github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= -github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= -github.com/google/gofuzz v1.1.1-0.20200604201612-c04b05f3adfa/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= -github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= -github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4= -github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= -github.com/google/subcommands v1.2.0/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk= -github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= -github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= -github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= -github.com/gorilla/css v1.0.0/go.mod h1:Dn721qIggHpt4+EFCcTLTU/vk5ySda2ReITrtgBl60c= -github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= -github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= -github.com/graph-gophers/graphql-go v1.3.0/go.mod h1:9CQHMSxwO4MprSdzoIEobiHpoLtHm77vfxsvsIN5Vuc= -github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= -github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= -github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= -github.com/holiman/uint256 v1.2.0/go.mod h1:y4ga/t+u+Xwd7CpDgZESaRcWy0I7XMlTMA25ApIH5Jw= -github.com/holiman/uint256 v1.2.2-0.20230321075855-87b91420868c/go.mod h1:SC8Ryt4n+UBbPbIBKaG9zbbDlp4jOru9xFZmPzLUTxw= -github.com/huin/goupnp v1.0.3-0.20220313090229-ca81a64b4204/go.mod h1:ZxNlw5WqJj6wSsRK5+YfflQGXYfccj5VgQsMNixHM7Y= -github.com/huin/goutil v0.0.0-20170803182201-1ca381bf3150/go.mod h1:PpLOETDnJ0o3iZrZfqZzyLl6l7F3c6L1oWn7OICBi6o= -github.com/hydrogen18/memlistener v0.0.0-20200120041712-dcc25e7acd91/go.mod h1:qEIFzExnS6016fRpRfxrExeVn2gbClQA99gQhnIcdhE= -github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= -github.com/imkira/go-interpol v1.1.0/go.mod h1:z0h2/2T3XF8kyEPpRgJ3kmNv+C43p+I/CoI+jC3w2iA= -github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= -github.com/influxdata/flux v0.65.1/go.mod h1:J754/zds0vvpfwuq7Gc2wRdVwEodfpCFM7mYlOw2LqY= -github.com/influxdata/influxdb v1.8.3/go.mod h1:JugdFhsvvI8gadxOI6noqNeeBHvWNTbfYGtiAn+2jhI= -github.com/influxdata/influxdb-client-go/v2 v2.4.0/go.mod h1:vLNHdxTJkIf2mSLvGrpj8TCcISApPoXkaxP8g9uRlW8= -github.com/influxdata/influxdb1-client v0.0.0-20220302092344-a9ab5670611c/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= -github.com/influxdata/influxql v1.1.1-0.20200828144457-65d3ef77d385/go.mod h1:gHp9y86a/pxhjJ+zMjNXiQAA197Xk9wLxaz+fGG+kWk= -github.com/influxdata/line-protocol v0.0.0-20180522152040-32c6aa80de5e/go.mod h1:4kt73NQhadE3daL3WhR5EJ/J2ocX0PZzwxQ0gXJ7oFE= -github.com/influxdata/line-protocol v0.0.0-20200327222509-2487e7298839/go.mod h1:xaLFMmpvUxqXtVkUJfg9QmT88cDaCJ3ZKgdZ78oO8Qo= -github.com/influxdata/line-protocol v0.0.0-20210311194329-9aa0e372d097/go.mod h1:xaLFMmpvUxqXtVkUJfg9QmT88cDaCJ3ZKgdZ78oO8Qo= -github.com/influxdata/promql/v2 v2.12.0/go.mod h1:fxOPu+DY0bqCTCECchSRtWfc+0X19ybifQhZoQNF5D8= -github.com/influxdata/roaring v0.4.13-0.20180809181101-fc520f41fab6/go.mod h1:bSgUQ7q5ZLSO+bKBGqJiCBGAl+9DxyW63zLTujjUlOE= -github.com/influxdata/tdigest v0.0.0-20181121200506-bf2b5ad3c0a9/go.mod h1:Js0mqiSBE6Ffsg94weZZ2c+v/ciT8QRHFOap7EKDrR0= -github.com/influxdata/usage-client v0.0.0-20160829180054-6d3895376368/go.mod h1:Wbbw6tYNvwa5dlB6304Sd+82Z3f7PmVZHVKU637d4po= -github.com/iris-contrib/blackfriday v2.0.0+incompatible/go.mod h1:UzZ2bDEoaSGPbkg6SAB4att1aAwTmVIx/5gCVqeyUdI= -github.com/iris-contrib/go.uuid v2.0.0+incompatible/go.mod h1:iz2lgM/1UnEf1kP0L/+fafWORmlnuysV2EMP8MW+qe0= -github.com/iris-contrib/jade v1.1.3/go.mod h1:H/geBymxJhShH5kecoiOCSssPX7QWYH7UaeZTSWddIk= -github.com/iris-contrib/jade v1.1.4/go.mod h1:EDqR+ur9piDl6DUgs6qRrlfzmlx/D5UybogqrXvJTBE= -github.com/iris-contrib/pongo2 v0.0.1/go.mod h1:Ssh+00+3GAZqSQb30AvBRNxBx7rf0GqwkjqxNd0u65g= -github.com/iris-contrib/schema v0.0.1/go.mod h1:urYA3uvUNG1TIIjOSCzHr9/LmbQo8LrOcOqfqxa4hXw= -github.com/iris-contrib/schema v0.0.6/go.mod h1:iYszG0IOsuIsfzjymw1kMzTL8YQcCWlm65f3wX8J5iA= -github.com/jedisct1/go-minisign v0.0.0-20190909160543-45766022959e/go.mod h1:G1CVv03EnqU1wYL2dFwXxW2An0az9JTl/ZsqXQeBlkU= -github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= -github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= -github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= -github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= -github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= -github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= -github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= -github.com/jsternberg/zap-logfmt v1.0.0/go.mod h1:uvPs/4X51zdkcm5jXl5SYoN+4RK21K8mysFmDaM/h+o= -github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= -github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= -github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= -github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes= -github.com/jwilder/encoding v0.0.0-20170811194829-b4e1701a28ef/go.mod h1:Ct9fl0F6iIOGgxJ5npU/IUOhOhqlVrGjyIZc8/MagT0= -github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88/go.mod h1:3w7q1U84EfirKl04SVQ/s7nPm1ZPhiXd34z40TNz36k= -github.com/karalabe/usb v0.0.2/go.mod h1:Od972xHfMJowv7NGVDiWVxk2zxnWgjLlJzE+F4F7AGU= -github.com/kataras/blocks v0.0.7/go.mod h1:UJIU97CluDo0f+zEjbnbkeMRlvYORtmc1304EeyXf4I= -github.com/kataras/golog v0.0.10/go.mod h1:yJ8YKCmyL+nWjERB90Qwn+bdyBZsaQwU3bTVFgkFIp8= -github.com/kataras/golog v0.1.7/go.mod h1:jOSQ+C5fUqsNSwurB/oAHq1IFSb0KI3l6GMa7xB6dZA= -github.com/kataras/iris/v12 v12.1.8/go.mod h1:LMYy4VlP67TQ3Zgriz8RE2h2kMZV2SgMYbq3UhfoFmE= -github.com/kataras/iris/v12 v12.2.0-beta5/go.mod h1:q26aoWJ0Knx/00iPKg5iizDK7oQQSPjbD8np0XDh6dc= -github.com/kataras/neffos v0.0.14/go.mod h1:8lqADm8PnbeFfL7CLXh1WHw53dG27MC3pgi2R1rmoTE= -github.com/kataras/pio v0.0.2/go.mod h1:hAoW0t9UmXi4R5Oyq5Z4irTbaTsOemSrDGUtaTl7Dro= -github.com/kataras/pio v0.0.11/go.mod h1:38hH6SWH6m4DKSYmRhlrCJ5WItwWgCVrTNU62XZyUvI= -github.com/kataras/sitemap v0.0.5/go.mod h1:KY2eugMKiPwsJgx7+U103YZehfvNGOXURubcGyk0Bz8= -github.com/kataras/sitemap v0.0.6/go.mod h1:dW4dOCNs896OR1HmG+dMLdT7JjDk7mYBzoIRwuj5jA4= -github.com/kataras/tunnel v0.0.4/go.mod h1:9FkU4LaeifdMWqZu7o20ojmW4B7hdhv2CMLwfnHGpYw= -github.com/kilic/bls12-381 v0.1.0/go.mod h1:vDTTHJONJ6G+P2R74EhnyotQDTliQDnFEwhdmfzw1ig= -github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= -github.com/klauspost/compress v1.4.0/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= -github.com/klauspost/compress v1.8.2/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= -github.com/klauspost/compress v1.9.7/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= -github.com/klauspost/cpuid v0.0.0-20170728055534-ae7887de9fa5/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= -github.com/klauspost/cpuid v1.2.1/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= -github.com/klauspost/crc32 v0.0.0-20161016154125-cb6bfca970f6/go.mod h1:+ZoRqAPRLkC4NPOvfYeR5KNOrY6TD+/sAC3HXPZgDYg= -github.com/klauspost/pgzip v1.0.2-0.20170402124221-0bf5dcad4ada/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs= -github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= -github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= -github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= -github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/labstack/echo/v4 v4.2.1/go.mod h1:AA49e0DZ8kk5jTOOCKNuPR6oTnBS0dYiM4FW1e6jwpg= -github.com/labstack/echo/v4 v4.5.0/go.mod h1:czIriw4a0C1dFun+ObrXp7ok03xON0N1awStJ6ArI7Y= -github.com/labstack/echo/v4 v4.9.0/go.mod h1:xkCDAdFCIf8jsFQ5NnbK7oqaF/yU1A1X20Ltm0OvSks= -github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL7NoOu+k= -github.com/labstack/gommon v0.3.1/go.mod h1:uW6kP17uPlLJsD3ijUYn3/M5bAxtlZhMI6m3MFxTMTM= -github.com/leanovate/gopter v0.2.9/go.mod h1:U2L/78B+KVFIx2VmW6onHJQzXtFb+p5y3y2Sh+Jxxv8= -github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= -github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY= -github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= -github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= -github.com/mailgun/raymond/v2 v2.0.46/go.mod h1:lsgvL50kgt1ylcFJYZiULi5fjPBkkhNfj4KA0W54Z18= -github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= -github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= -github.com/matryer/moq v0.0.0-20190312154309-6cfb0558e1bd/go.mod h1:9ELz6aaclSIGnZBoaSLZ3NAl1VTufbOrXBPvtcy6WiQ= -github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= -github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= -github.com/mattn/go-colorable v0.1.7/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= -github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= -github.com/mattn/go-colorable v0.1.11/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= -github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= -github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= -github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= -github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ= -github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= -github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= -github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= -github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= -github.com/mattn/go-localereader v0.0.1 h1:ygSAOl7ZXTx4RdPYinUpg6W99U8jWvWi9Ye2JC/oIi4= -github.com/mattn/go-localereader v0.0.1/go.mod h1:8fBrzywKY7BI3czFoHkuzRoWE9C+EiG4R1k4Cjx5p88= -github.com/mattn/go-runewidth v0.0.3/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= -github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= -github.com/mattn/go-runewidth v0.0.10/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk= -github.com/mattn/go-runewidth v0.0.12/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk= -github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= -github.com/mattn/go-sqlite3 v1.11.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= -github.com/mattn/go-tty v0.0.0-20180907095812-13ff1204f104/go.mod h1:XPvLUNfbS4fJH25nqRHfWLMa1ONC8Amw+mIA639KxkE= -github.com/mattn/goveralls v0.0.2/go.mod h1:8d1ZMHsd7fW6IRPKQh46F2WRpyib5/X4FOpevwGNQEw= -github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= -github.com/mediocregopher/radix/v3 v3.4.2/go.mod h1:8FL3F6UQRXHXIBSPUs5h0RybMF8i4n7wVopoX3x7Bv8= -github.com/microcosm-cc/bluemonday v1.0.2/go.mod h1:iVP4YcDBq+n/5fb23BhYFvIMq/leAFZyRl6bYmGDlGc= -github.com/microcosm-cc/bluemonday v1.0.21/go.mod h1:ytNkv4RrDrLJ2pqlsSI46O6IVXmZOBBD4SaJyDwwTkM= -github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= -github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= -github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= -github.com/mmcloughlin/addchain v0.4.0/go.mod h1:A86O+tHqZLMNO4w6ZZ4FlVQEadcoqkyU72HC5wJ4RlU= -github.com/mmcloughlin/profile v0.1.1/go.mod h1:IhHD7q1ooxgwTgjxQYkACGA77oFTDdFVejUS1/tS/qU= -github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/modocache/gover v0.0.0-20171022184752-b58185e213c5/go.mod h1:caMODM3PzxT8aQXRPkAt8xlV/e7d7w8GM5g0fa5F0D8= -github.com/moul/http2curl v1.0.0/go.mod h1:8UbvGypXm98wA/IqH45anm5Y2Z6ep6O31QGOAZ3H0fQ= -github.com/mschoch/smat v0.0.0-20160514031455-90eadee771ae/go.mod h1:qAyveg+e4CE+eKJXWVjKXM4ck2QobLqTDytGJbLLhJg= -github.com/muesli/ansi v0.0.0-20211018074035-2e021307bc4b h1:1XF24mVaiu7u+CFywTdcDo2ie1pzzhwjt6RHqzpMU34= -github.com/muesli/ansi v0.0.0-20211018074035-2e021307bc4b/go.mod h1:fQuZ0gauxyBcmsdE3ZT4NasjaRdxmbCS0jRHsrWu3Ho= -github.com/muesli/cancelreader v0.2.2 h1:3I4Kt4BQjOR54NavqnDogx/MIoWBFa0StPA8ELUXHmA= -github.com/muesli/cancelreader v0.2.2/go.mod h1:3XuTXfFS2VjM+HTLZY9Ak0l6eUKfijIfMUZ4EgX0QYo= -github.com/muesli/reflow v0.2.1-0.20210115123740-9e1d0d53df68/go.mod h1:Xk+z4oIWdQqJzsxyjgl3P22oYZnHdZ8FFTHAQQt5BMQ= -github.com/muesli/reflow v0.3.0 h1:IFsN6K9NfGtjeggFP+68I4chLZV2yIKsXJFNZ+eWh6s= -github.com/muesli/reflow v0.3.0/go.mod h1:pbwTDkVPibjO2kyvBQRBxTWEEGDGq0FlB1BIKtnHY/8= -github.com/muesli/termenv v0.11.1-0.20220204035834-5ac8409525e0/go.mod h1:Bd5NYQ7pd+SrtBSrSNoBBmXlcY8+Xj4BMJgh8qcZrvs= -github.com/muesli/termenv v0.13.0/go.mod h1:sP1+uffeLaEYpyOTb8pLCUctGcGLnoFjSn4YJK5e2bc= -github.com/muesli/termenv v0.14.0/go.mod h1:kG/pF1E7fh949Xhe156crRUrHNyK221IuGO7Ez60Uc8= -github.com/muesli/termenv v0.15.1 h1:UzuTb/+hhlBugQz28rpzey4ZuKcZ03MeKsoG7IJZIxs= -github.com/muesli/termenv v0.15.1/go.mod h1:HeAQPTzpfs016yGtA4g00CsdYnVLJvxsS4ANqrZs2sQ= -github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= -github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= -github.com/naoina/go-stringutil v0.1.0/go.mod h1:XJ2SJL9jCtBh+P9q5btrd/Ylo8XwT/h1USek5+NqSA0= -github.com/naoina/toml v0.1.2-0.20170918210437-9fafd6967416/go.mod h1:NBIhNtsFMo3G2szEBne+bO4gS192HuIYRqfvOWb4i1E= -github.com/nats-io/jwt v0.3.0/go.mod h1:fRYCDE99xlTsqUzISS1Bi75UBJ6ljOJQOAAu5VglpSg= -github.com/nats-io/nats.go v1.9.1/go.mod h1:ZjDU1L/7fJ09jvUSRVBR2e7+RnLiiIQyqyzEE/Zbp4w= -github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= -github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= -github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= -github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= -github.com/omeid/uconfig v0.5.0 h1:jNI7QgdGvoazDm95yoFNSg7NL+TcjIScTOLn5nk4f4E= -github.com/omeid/uconfig v0.5.0/go.mod h1:a+bL4SpC/ZYQjRQGMkyT8Wk3z8XXGBqwtbNRnCukLP0= -github.com/onsi/ginkgo v1.10.3/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= -github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= -github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= -github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= -github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= -github.com/opentracing/opentracing-go v1.0.3-0.20180606204148-bd9c31933947/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= -github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= -github.com/paulbellamy/ratecounter v0.2.0/go.mod h1:Hfx1hDpSGoqxkVVpBi/IlYD7kChlfo5C6hzIHwPqfFE= -github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc= -github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= -github.com/pelletier/go-toml/v2 v2.2.1 h1:9TA9+T8+8CUCO2+WYnDLCgrYi9+omqKXyjDtosvtEhg= -github.com/pelletier/go-toml/v2 v2.2.1/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs= -github.com/peterh/liner v1.0.1-0.20180619022028-8c1271fcf47f/go.mod h1:xIteQHvHuaLYG9IFj6mSxM0fCKrs34IrEQUhOYuGPHc= -github.com/peterh/liner v1.1.1-0.20190123174540-a2c9a5303de7/go.mod h1:CRroGNssyjTd/qIG2FyxByd2S8JEAZXBl4qUrZf8GS0= -github.com/philhofer/fwd v1.0.0/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG3ZVNU= -github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= -github.com/pingcap/errors v0.11.4/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8= -github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= -github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/term v0.0.0-20180730021639-bffc007b7fd5/go.mod h1:eCbImbZ95eXtAUIbLAuAVnBnwf83mjf6QIVH8SHYwqQ= -github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= -github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= -github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= -github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= -github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= -github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc= -github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= -github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= -github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= -github.com/protolambda/bls12-381-util v0.0.0-20220416220906-d8552aa452c7/go.mod h1:IToEjHuttnUzwZI5KBSM/LOOW3qLbbrHOEfp3SbECGY= -github.com/retailnext/hllpp v1.0.1-0.20180308014038-101a6d2f8b52/go.mod h1:RDpi1RftBQPUCDRw6SmxeaREsAaRKnOclghuzp/WRzc= -github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= -github.com/rjeczalik/notify v0.9.1/go.mod h1:rKwnCoCGeuQnwBtTSPL9Dad03Vh2n40ePRrjvIXnJho= -github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= -github.com/rogpeppe/go-internal v1.8.1/go.mod h1:JeRgkft04UBgHMgCIwADu4Pn6Mtm5d4nPKWu0nJ5d+o= -github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= -github.com/russross/blackfriday v1.5.2 h1:HyvC0ARfnZBqnXwABFeSZHpKvJHJJfPz81GNueLj0oo= -github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= -github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= -github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= -github.com/sahilm/fuzzy v0.1.0 h1:FzWGaw2Opqyu+794ZQ9SYifWv2EIXpwP4q8dY1kDAwI= -github.com/sahilm/fuzzy v0.1.0/go.mod h1:VFvziUEIMCrT6A6tw2RFIXPXXmzXbOsSHF0DOI8ZK9Y= -github.com/sashabaranov/go-openai v1.24.1 h1:DWK95XViNb+agQtuzsn+FyHhn3HQJ7Va8z04DQDJ1MI= -github.com/sashabaranov/go-openai v1.24.1/go.mod h1:lj5b/K+zjTSFxVLijLSTDZuP7adOgerWeFyZLUhAKRg= -github.com/schollz/closestmatch v2.1.0+incompatible/go.mod h1:RtP1ddjLong6gTkbtmuhtR2uUrrJOpYzYRvbcPAid+g= -github.com/segmentio/kafka-go v0.1.0/go.mod h1:X6itGqS9L4jDletMsxZ7Dz+JFWxM6JHfPOCvTvk+EJo= -github.com/segmentio/kafka-go v0.2.0/go.mod h1:X6itGqS9L4jDletMsxZ7Dz+JFWxM6JHfPOCvTvk+EJo= -github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= -github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= -github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= -github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= -github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= -github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= -github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= -github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= -github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= -github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= -github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= -github.com/spf13/cobra v1.5.0/go.mod h1:dWXEIy2H428czQCjInthrTRUg7yKbok+2Qi/yBIJoUM= -github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= -github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= -github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= -github.com/status-im/keycard-go v0.0.0-20190316090335-8537d3370df4/go.mod h1:RZLeN1LMWmRsyYjvAu+I6Dm9QmlDaIIt+Y+4Kd7Tp+Q= -github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/testify v1.2.0/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= -github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= -github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= -github.com/supranational/blst v0.3.11-0.20230406105308-e9dfc5ee724b/go.mod h1:jZJtfjgudtNl4en1tzwPIV3KjUnQUvG3/j+w+fVonLw= -github.com/tdewolff/minify/v2 v2.12.4/go.mod h1:h+SRvSIX3kwgwTFOpSckvSxgax3uy8kZTSF1Ojrr3bk= -github.com/tdewolff/parse/v2 v2.6.4/go.mod h1:woz0cgbLwFdtbjJu8PIKxhW05KplTFQkOdX78o+Jgrs= -github.com/tinylib/msgp v1.0.2/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE= -github.com/tklauser/go-sysconf v0.3.5/go.mod h1:MkWzOF4RMCshBAMXuhXJs64Rte09mITnppBXY/rYEFI= -github.com/tklauser/numcpus v0.2.2/go.mod h1:x3qojaO3uyYt0i56EW/VUYs7uBvdl2fkfZFu0T9wgjM= -github.com/tyler-smith/go-bip39 v1.0.1-0.20181017060643-dbb3b84ba2ef/go.mod h1:sJ5fKU0s6JVwZjjcUEX2zFOnvq0ASQ2K9Zr6cf67kNs= -github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= -github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo= -github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= -github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= -github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= -github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI= -github.com/urfave/cli/v2 v2.27.2 h1:6e0H+AkS+zDckwPCUrZkKX38mRaau4nL2uipkJpbkcI= -github.com/urfave/cli/v2 v2.27.2/go.mod h1:g0+79LmHHATl7DAcHO99smiR/T7uGLw84w8Y42x+4eM= -github.com/urfave/negroni v1.0.0/go.mod h1:Meg73S6kFm/4PpbYdq35yYWoCZ9mS/YSx+lKnmiohz4= -github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= -github.com/valyala/fasthttp v1.6.0/go.mod h1:FstJa9V+Pj9vQ7OJie2qMHdwemEDaDiSdBnvPM1Su9w= -github.com/valyala/fasthttp v1.40.0/go.mod h1:t/G+3rLek+CyY9bnIE+YlMRddxVAAGjhxndDB4i4C0I= -github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8= -github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= -github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio= -github.com/vmihailenco/msgpack/v5 v5.3.5/go.mod h1:7xyJ9e+0+9SaZT0Wt1RGleJXzli6Q/V5KbhBonMG9jc= -github.com/vmihailenco/tagparser/v2 v2.0.0/go.mod h1:Wri+At7QHww0WTrCBeu4J6bNtoV6mEfg5OIWRZA9qds= -github.com/willf/bitset v1.1.3/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4= -github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= -github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= -github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= -github.com/xlab/treeprint v0.0.0-20180616005107-d6fb6747feb6/go.mod h1:ce1O1j6UtZfjr22oyGxGLbauSBp2YVXpARAosm7dHBg= -github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= -github.com/xrash/smetrics v0.0.0-20240312152122-5f08fbb34913 h1:+qGGcbkzsfDQNPPe9UDgpxAWQrhbbBXOYJFQDq/dtJw= -github.com/xrash/smetrics v0.0.0-20240312152122-5f08fbb34913/go.mod h1:4aEEwZQutDLsQv2Deui4iYQ6DWTxR14g6m8Wv88+Xqk= -github.com/yalp/jsonpath v0.0.0-20180802001716-5cc68e5049a0/go.mod h1:/LWChgwKmvncFJFHJ7Gvn9wZArjbV5/FppcK2fKk/tI= -github.com/yosssi/ace v0.0.5/go.mod h1:ALfIzm2vT7t5ZE7uoIZqF3TQ7SAOyupFZnkrF5id+K0= -github.com/yudai/gojsondiff v1.0.0/go.mod h1:AY32+k2cwILAkW1fbgxQ5mUmMiZFgLIV+FBNExI05xg= -github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82/go.mod h1:lgjkn3NuSvDfVJdfcVVdX+jpBxNmX4rDAzaS45IcYoM= -github.com/yudai/pp v2.0.1+incompatible/go.mod h1:PuxR/8QJ7cyCkFp/aUDS+JY727OFEZkTdatxwunjIkc= -github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= -go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= -go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= -go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= -go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= -go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= -golang.org/x/arch v0.7.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys= -golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190909091759-094676da4a83/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20191227163750-53104e6ec876/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= -golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= -golang.org/x/crypto v0.0.0-20220518034528-6f7dac969898/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw= -golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= -golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= -golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= -golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -golang.org/x/exp v0.0.0-20230206171751-46f607a40771/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc= -golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs= -golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= -golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= -golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= -golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= -golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= -golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= -golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= -golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= -golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= -golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/mod v0.9.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190327091125-710a502c58a2/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= -golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200813134508-3edf25e44fcc/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210220033124-5f55cee0dc0d/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= -golang.org/x/net v0.0.0-20210610132358-84b48f89b13b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20211008194852-3b03d305991f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= -golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= -golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.3.0/go.mod h1:rQrIauxkUhJ6CuwEXwymO2/eh4xz2ZWF1nBkcxS+tGk= -golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= -golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200107162124-548cf772de50/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200814200057-3d37ad5750ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200826173525-f9321e4c35a6/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201101102859-da207088b7d1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210316164454-77fc1eacc6aa/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210324051608-47abb6519492/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210420205809-ac73e9fd8988/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210816183151-1e6c022a8912/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211020174200-9d6173849985/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220204135822-1c1b9b1eba6a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE= -golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= -golang.org/x/term v0.20.0 h1:VnkxpohqXaOBYJtBmEppKUG6mXpi+4O6purfc2+sMhw= -golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY= -golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= -golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= -golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20201208040808-7e3f01d25324/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20181221001348-537d06c36207/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190206041539-40960b6deb8e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190327201419-c70d86f8b7cf/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200108203644-89082a384178/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= -golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= -golang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s= -golang.org/x/tools v0.12.1-0.20230815132531-74c255bcf846/go.mod h1:Sc0INKfu04TlqNoRA1hgpFZbhYXHPr4V5DzpSBTPqQM= -golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= -golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= -gonum.org/v1/gonum v0.0.0-20180816165407-929014505bf4/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo= -gonum.org/v1/gonum v0.0.0-20181121035319-3f7ecaa7e8ca/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo= -gonum.org/v1/gonum v0.6.0/go.mod h1:9mxDZsDKxgMAuccQkewq682L+0eCu4dCN2yonUJTCLU= -gonum.org/v1/netlib v0.0.0-20181029234149-ec6d1f5cefe6/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= -gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= -gonum.org/v1/plot v0.0.0-20190515093506-e2840ee46a6b/go.mod h1:Wt8AAjI+ypCyYX3nZBvf6cAIx93T+c/OS2HFAYskSZc= -google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= -google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= -google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= -google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= -google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= -google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/genproto v0.0.0-20180518175338-11a468237815/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= -google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190716160619-c506a9f90610/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= -google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200108215221-bd8f9a0ef82f/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= -google.golang.org/genproto v0.0.0-20210624195500-8bfb893ecb84/go.mod h1:SzzZ/N+nwJDaO1kznhnlzqS8ocJICar6hYhVyhi++24= -google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= -google.golang.org/grpc v1.12.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= -google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= -google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= -google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= -google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= -google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw= -google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= -google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= -google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= -google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= -google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= -google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= -google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= -google.golang.org/protobuf v1.34.0 h1:Qo/qEd2RZPCf2nKuorzksSknv0d3ERwp1vFG38gSmH4= -google.golang.org/protobuf v1.34.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= -gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= -gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE= -gopkg.in/go-playground/validator.v8 v8.18.2/go.mod h1:RX2a/7Ha8BgOhfk7j780h4/u/RRjR0eouCJSH80/M2Y= -gopkg.in/ini.v1 v1.51.1/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= -gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= -gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA= -gopkg.in/olebedev/go-duktape.v3 v3.0.0-20200619000410-60c24ae608a6/go.mod h1:uAJfkITjFhyEEuUfm7bsmCZRbW5WRq8s9EY8HZ6hCns= -gopkg.in/urfave/cli.v1 v1.20.0/go.mod h1:vuBzUtMdQeixQj8LVd+/98pzhxNGQoyuPBlsXHOQNO0= -gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= -gopkg.in/yaml.v3 v3.0.0-20191120175047-4206685974f2/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= -honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= -honnef.co/go/tools v0.1.3/go.mod h1:NgwopIslSNH47DimFoV78dnkksY2EFtX0ajyb3K/las= -rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= -rsc.io/tmplfunc v0.0.3/go.mod h1:AG3sTPzElb1Io3Yg4voV9AGZJuleGAwaVRxL9M49PhA= -sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8= diff --git a/proxy-router/.env.example b/proxy-router/.env.example index 10cd5964..d7aa6ebe 100644 --- a/proxy-router/.env.example +++ b/proxy-router/.env.example @@ -1,29 +1,33 @@ -WALLET_PRIVATE_KEY= # Private Key from your Wallet as Consumer or Provider (needed for the proxy-router to sign transactions) -ETH_NODE_ADDRESS=wss://arb-sepolia.g.alchemy.com/v2/3-pxwBaJ7vilkz1jl-fMmCvZThGxpmo2 # Recommend using your own private ETH Node Address for better performance (via Alchemy or Infura) +# Minimalist ENV File to enable the proxy-router to run, defaults to MAINNET +# Contract and Token current as of 11/15/2024 +# Full ENV details can be found in /docs/proxy-router.full.env +# Includes both TestNet and MainNet values, uncomment sections as desired -DIAMOND_CONTRACT_ADDRESS=0x8e19288d908b2d9f8d7c539c74c899808ac3de45 -MOR_TOKEN_ADDRESS=0xc1664f994fd3991f98ae944bc16b9aed673ef5fd -WEB_ADDRESS=0.0.0.0:8082 # Change to your desired port that your Proxy-router API (Swagger should be listening on) -WEB_PUBLIC_URL=localhost:8082 # Change to your desired port should match WEB_ADDRESS port number -OPENAI_BASE_URL=http://localhost:8080/v1 # Change to your OpenAI API port for local model +WALLET_PRIVATE_KEY= -# MODELS_CONFIG_PATH= -ENVIRONMENT=development -ETH_NODE_LEGACY_TX=false -EXPLORER_API_URL="https://api-sepolia.arbiscan.io/api" -LOG_COLOR=true -LOG_FOLDER_PATH= -LOG_LEVEL_APP=info -LOG_LEVEL_CONNECTION=info -LOG_LEVEL_PROXY=info -LOG_LEVEL_SCHEDULER=info -OPENAI_API_KEY= #optional +# MAINNET VALUES (only MAINNET or TESTNET section should be uncommented) +DIAMOND_CONTRACT_ADDRESS=0xDE819AaEE474626E3f34Ef0263373357e5a6C71b +MOR_TOKEN_ADDRESS=0x092bAaDB7DEf4C3981454dD9c0A0D7FF07bCFc86 +EXPLORER_API_URL="https://api.arbiscan.io/api" +ETH_NODE_CHAIN_ID=42161 +ENVIRONMENT=production + +# TESTNET VALUES +# DIAMOND_CONTRACT_ADDRESS=0xb8C55cD613af947E73E262F0d3C54b7211Af16CF +# MOR_TOKEN_ADDRESS=0x34a285a1b1c166420df5b6630132542923b5b27e +# EXPLORER_API_URL="https://api-sepolia.arbiscan.io/api" +# ETH_NODE_CHAIN_ID=421614 +# ENVIRONMENT=development + +# COMMON PROXY_ADDRESS=0.0.0.0:3333 +WEB_ADDRESS=0.0.0.0:8082 +WEB_PUBLIC_URL=http://localhost:8082 +MODELS_CONFIG_PATH= +RATING_CONFIG_PATH= +ETH_NODE_USE_SUBSCRIPTIONS=false +ETH_NODE_ADDRESS= +ETH_NODE_LEGACY_TX=false +PROXY_STORE_CHAT_CONTEXT=true PROXY_STORAGE_PATH=./data/ -SYS_ENABLE=false -SYS_LOCAL_PORT_RANGE=1024 65535 -SYS_NET_DEV_MAX_BACKLOG=100000 -SYS_RLIMIT_HARD=524288 -SYS_RLIMIT_SOFT=524288 -SYS_SOMAXCONN=100000 -SYS_TCP_MAX_SYN_BACKLOG=100000 \ No newline at end of file +LOG_COLOR=true \ No newline at end of file diff --git a/proxy-router/.env.example.win b/proxy-router/.env.example.win index f0657406..452bd4a6 100644 --- a/proxy-router/.env.example.win +++ b/proxy-router/.env.example.win @@ -1,29 +1,33 @@ -WALLET_PRIVATE_KEY= # Private Key from your Wallet as Consumer or Provider (needed for the proxy-router to sign transactions) -ETH_NODE_ADDRESS=wss://arb-sepolia.g.alchemy.com/v2/3-pxwBaJ7vilkz1jl-fMmCvZThGxpmo2 # Recommend using your own private ETH Node Address for better performance (via Alchemy or Infura) +# Minimalist ENV File to enable the proxy-router to run, defaults to MAINNET +# Contract and Token current as of 11/15/2024 +# Full ENV details can be found in /docs/proxy-router.full.env +# Includes both TestNet and MainNet values, uncomment sections as desired -DIAMOND_CONTRACT_ADDRESS=0x8e19288d908b2d9f8d7c539c74c899808ac3de45 -MOR_TOKEN_ADDRESS=0xc1664f994fd3991f98ae944bc16b9aed673ef5fd -WEB_ADDRESS=0.0.0.0:8082 # Change to your desired port that your Proxy-router API (Swagger should be listening on) -WEB_PUBLIC_URL=localhost:8082 # Change to your desired port should match WEB_ADDRESS port number -OPENAI_BASE_URL=http://localhost:8080/v1 # Change to your OpenAI API port for local model +WALLET_PRIVATE_KEY= -# MODELS_CONFIG_PATH= -ENVIRONMENT=development -ETH_NODE_LEGACY_TX=false -EXPLORER_API_URL="https://api-sepolia.arbiscan.io/api" -LOG_COLOR=true -LOG_FOLDER_PATH= -LOG_LEVEL_APP=info -LOG_LEVEL_CONNECTION=info -LOG_LEVEL_PROXY=info -LOG_LEVEL_SCHEDULER=info -OPENAI_API_KEY= #optional +# MAINNET VALUES (only MAINNET or TESTNET section should be uncommented) +DIAMOND_CONTRACT_ADDRESS=0xDE819AaEE474626E3f34Ef0263373357e5a6C71b +MOR_TOKEN_ADDRESS=0x092bAaDB7DEf4C3981454dD9c0A0D7FF07bCFc86 +EXPLORER_API_URL="https://api.arbiscan.io/api" +ETH_NODE_CHAIN_ID=42161 +ENVIRONMENT=production + +# TESTNET VALUES +# DIAMOND_CONTRACT_ADDRESS=0xb8C55cD613af947E73E262F0d3C54b7211Af16CF +# MOR_TOKEN_ADDRESS=0x34a285a1b1c166420df5b6630132542923b5b27e +# EXPLORER_API_URL="https://api-sepolia.arbiscan.io/api" +# ETH_NODE_CHAIN_ID=421614 +# ENVIRONMENT=development + +# COMMON PROXY_ADDRESS=0.0.0.0:3333 +WEB_ADDRESS=0.0.0.0:8082 +WEB_PUBLIC_URL=http://localhost:8082 +MODELS_CONFIG_PATH= +RATING_CONFIG_PATH= +ETH_NODE_USE_SUBSCRIPTIONS=false +ETH_NODE_ADDRESS= +ETH_NODE_LEGACY_TX=false +PROXY_STORE_CHAT_CONTEXT=true PROXY_STORAGE_PATH=.\data\ -SYS_ENABLE=false -SYS_LOCAL_PORT_RANGE=1024 65535 -SYS_NET_DEV_MAX_BACKLOG=100000 -SYS_RLIMIT_HARD=524288 -SYS_RLIMIT_SOFT=524288 -SYS_SOMAXCONN=100000 -SYS_TCP_MAX_SYN_BACKLOG=100000 \ No newline at end of file +LOG_COLOR=true \ No newline at end of file diff --git a/proxy-router/.gitignore b/proxy-router/.gitignore index 708c6949..381e8305 100644 --- a/proxy-router/.gitignore +++ b/proxy-router/.gitignore @@ -8,6 +8,16 @@ logs dist bin -data +data* -models-config.json \ No newline at end of file +models-config.json +rating-config.json + +#Badger DB +*.vlog +*.mem +DISCARD +KEYREGISTRY +LOCK +MANIFEST +chats/ \ No newline at end of file diff --git a/proxy-router/.gitlab-ci.yml b/proxy-router/.gitlab-ci.yml deleted file mode 100644 index eb31a558..00000000 --- a/proxy-router/.gitlab-ci.yml +++ /dev/null @@ -1,401 +0,0 @@ -variables: # keep this list alphabetically sorted - CI_AWS_TASK: "proxy-router" - ENVIRONMENT: "production" - NODE_DEF: "prt" - WEB_ADDRESS: "0.0.0.0:8080" - -stages: - - test - - build - - deploy - # - e2e-test - - release - -default: - image: registry.gitlab.com/gitlab-org/cloud-deploy/aws-base:latest - -.ecr_login_script: &ecr_login_script | - echo "**************************" - echo "*** ECR Login to Shared Titanio-NET Repo in USE-1" - echo "**************************" - docker system prune -af - aws ecr get-login-password --region $AWS_DEFAULT_REGION | docker login --username AWS --password-stdin $CI_AWS_TitanIO_NET_ECR - -.create_image_tag: &create_image_tag | - echo "**************************" - echo "*** Tag Image " - echo "**************************" - IMAGE_TAG="$(echo $CI_COMMIT_SHA | head -c 8)-$TGT_ENV-$NODE_DEF" - echo $CI_AWS_TitanIO_NET_ECR/$CI_AWS_ECR_REPO:$IMAGE_TAG - -####################### -# TEST STAGE -####################### -lint: - inherit: - default: false - image: golangci/golangci-lint:v1.50.1-alpine - stage: test - only: - - branches - - tags - - merge_requests - script: - - golangci-lint run -v - -test: - inherit: - default: false - image: golang:1.19.3-alpine - stage: test - only: - - branches - - tags - - merge_requests - script: - - apk add --no-cache git make musl-dev gcc - - go version - - go mod download - - make test-unit - -####################### -# BUILD STAGE -####################### -.build_raw_image: &build_raw_image | - echo "**************************" - echo "*** Build RAW Image with no build arguments " - echo "**************************" - docker build \ - --build-arg COMMIT=$CI_COMMIT_SHORT_SHA \ - -t $CI_AWS_TitanIO_NET_ECR/$CI_AWS_ECR_REPO:$IMAGE_TAG --no-cache . - - echo "**************************" - echo "*** Tag Image with $TGT_ENV-latest" - echo "**************************" - docker tag $CI_AWS_TitanIO_NET_ECR/$CI_AWS_ECR_REPO:$IMAGE_TAG $CI_AWS_TitanIO_NET_ECR/$CI_AWS_ECR_REPO:$TGT_ENV-latest - - echo "**************************" - echo "*** Push Images" - echo "**************************" - docker push $CI_AWS_TitanIO_NET_ECR/$CI_AWS_ECR_REPO:$IMAGE_TAG - docker push $CI_AWS_TitanIO_NET_ECR/$CI_AWS_ECR_REPO:$TGT_ENV-latest - -####################### -# BUILD DEVELOPMENT -####################### -bedrock-02-DEV-rawimage: - stage: build - environment: dev - needs: ["test", "lint"] - rules: - - if: $CI_COMMIT_BRANCH == "dev" - when: always - - if: $CI_COMMIT_BRANCH != "dev" - when: never - - if: $CI_MERGE_REQUEST_ID - when: never - tags: - - proxy #devops - - bedrock - - shell - - titanio-dev - variables: - TGT_ACCOUNT: $CI_AWS_ACCOUNT_DEV - TGT_ENV: dev - NODE_DEF: raw - script: - - *ecr_login_script - - *create_image_tag - - *build_raw_image - - echo "$TGT_ENV Raw Image updated" - -####################### -# BUILD STAGING -####################### -bedrock-03-STG-rawimage: - stage: build - environment: stg - needs: ["test", "lint"] - rules: - - if: $CI_COMMIT_BRANCH == "stg" - when: always - - if: $CI_COMMIT_BRANCH != "stg" - when: never - - if: $CI_MERGE_REQUEST_ID - when: never - tags: - - proxy #devops - - bedrock - - shell - - titanio-stg - variables: - TGT_ACCOUNT: $CI_AWS_ACCOUNT_STG - TGT_ENV: stg - NODE_DEF: raw - script: - - *ecr_login_script - - *create_image_tag - - *build_raw_image - - echo "$TGT_ENV Raw Image updated" - -####################### -# BUILD PRODUCTION/MAIN/LMN -####################### -bedrock-04-PRD-rawimage: - stage: build - environment: lmn - needs: ["test", "lint"] - rules: - - if: $CI_COMMIT_BRANCH == "main" - when: always - - if: $CI_COMMIT_BRANCH != "main" - when: never - - if: $CI_MERGE_REQUEST_ID - when: never - tags: - - proxy #devops - - bedrock - - shell - - titanio-lmn - variables: - TGT_ACCOUNT: $CI_AWS_ACCOUNT_LMN - TGT_ENV: lmn - NODE_DEF: raw - script: - - *ecr_login_script - - *create_image_tag - - *build_raw_image - - echo "$TGT_ENV Raw Image updated" - -####################### -# DEPLOY STAGE -####################### -.update_raw_task_definition: &update_raw_task_definition | - echo "**************************" - echo "*** Update Validator Task Definition" - echo "*** Unique elements that should be set in calling module are Web_public_url" - echo "*** CI_WEB_PUBLIC_URL" - echo "**************************" - aws ecs describe-task-definition --region $AWS_DEFAULT_REGION --task-definition tsk-$CI_AWS_TASK > output.json - echo "**************************" - echo "*** Original Task Definition" - echo "**************************" - jq . output.json - # Update the Image, Ulimit and Env Vars - jq '.taskDefinition.containerDefinitions[].image = "'$CI_AWS_TitanIO_NET_ECR/$CI_AWS_ECR_REPO:$TGT_ENV-latest'" | - .taskDefinition.containerDefinitions[].ulimits = [{"name": "nofile", "softLimit": 15000, "hardLimit": 15000}] | - .taskDefinition.containerDefinitions[].environment = [ - { "name": "COMMIT", "value": "'"$(git rev-parse HEAD)"'" }, - { "name": "ETH_NODE_ADDRESS", "value": "'"$CI_ETH_NODE_ADDRESS"'" }, - { "name": "ETH_NODE_LEGACY_TX", "value": "'"$ETH_NODE_LEGACY_TX"'" }, - { "name": "ENVIRONMENT", "value": "'"$ENVIRONMENT"'" }, - { "name": "LOG_COLOR", "value": "'"$LOG_COLOR"'" }, - { "name": "LOG_JSON", "value": "'"$LOG_JSON"'" }, - { "name": "LOG_LEVEL_APP", "value": "'"$LOG_LEVEL_APP"'" }, - { "name": "LOG_LEVEL_CONNECTION", "value": "'"$LOG_LEVEL_CONNECTION"'" }, - { "name": "LOG_LEVEL_PROXY", "value": "'"$LOG_LEVEL_PROXY"'" }, - { "name": "LOG_LEVEL_SCHEDULER", "value": "'"$LOG_LEVEL_SCHEDULER"'" }, - { "name": "LOG_LEVEL_CONTRACT", "value": "'"$LOG_LEVEL_CONTRACT"'" }, - { "name": "PROXY_ADDRESS", "value": "'"$PROXY_ADDRESS"'" }, - { "name": "SYS_ENABLE", "value": "'"$SYS_ENABLE"'" }, - { "name": "SYS_LOCAL_PORT_RANGE", "value": "'"$SYS_LOCAL_PORT_RANGE"'" }, - { "name": "SYS_NET_DEV_MAX_BACKLOG", "value": "'"$SYS_NET_DEV_MAX_BACKLOG"'" }, - { "name": "SYS_RLIMIT_HARD", "value": "'"$SYS_RLIMIT_HARD"'" }, - { "name": "SYS_RLIMIT_SOFT", "value": "'"$SYS_RLIMIT_SOFT"'" }, - { "name": "SYS_SOMAXCONN", "value": "'"$SYS_SOMAXCONN"'" }, - { "name": "SYS_TCP_MAX_SYN_BACKLOG", "value": "'"$SYS_TCP_MAX_SYN_BACKLOG"'" }, - { "name": "WEB_ADDRESS", "value": "'"$WEB_ADDRESS"'" }, - { "name": "WEB_PUBLIC_URL", "value": "'"$CI_WEB_PUBLIC_URL"'" } - ]' output.json > updated.json - # Extract JUST Task Definition from the output.json file - jq '.taskDefinition' updated.json > extracted.json - # Remove sections that are not needed - jq 'del(.taskDefinitionArn, .revision, .status, .requiresAttributes, .compatibilities, .registeredBy, .registeredAt)' extracted.json > input.json - sed -i 's/'$CI_AWS_ACCOUNT_SBX'/'$TGT_ACCOUNT'/g' input.json - echo "**************************" - echo "*** New Task Definition" - echo "**************************" - cat input.json | jq . - -.deploy_new_task_definition: &deploy_new_task_definition | - aws ecs register-task-definition --region $AWS_DEFAULT_REGION --cli-input-json file://input.json - REVISION=$(aws ecs describe-task-definition --task-definition tsk-$CI_AWS_TASK --region $AWS_DEFAULT_REGION | egrep "revision" | tr "/" " " | awk '{print $2}' | sed 's/"$//' | cut -d "," -f 1) - echo "****************************************************" - echo "****************************************************" - echo "*** Update Task: " - echo "*** - AWS Account: Titanio-$TGT_ENV" - echo "*** - Cluster: ecs-$CI_AWS_ECR_REPO-$TGT_ENV-$CI_AWS_ECS_CLUSTER_REGION" - echo "*** - Service: svc-$CI_AWS_TASK-$TGT_ENV-$CI_AWS_ECS_CLUSTER_REGION" - echo "*** - Task: tsk-$CI_AWS_TASK:$REVISION" - echo "*** - Image: $CI_AWS_TitanIO_NET_ECR/$CI_AWS_ECR_REPO:$IMAGE_TAG" - echo "****************************************************" - echo "****************************************************" - aws ecs update-service --region $AWS_DEFAULT_REGION --cluster ecs-$CI_AWS_ECR_REPO-$TGT_ENV-$CI_AWS_ECS_CLUSTER_REGION --service svc-$CI_AWS_TASK-$TGT_ENV-$CI_AWS_ECS_CLUSTER_REGION --task-definition tsk-$CI_AWS_TASK:$REVISION - -.deploy_raw_seller: &deploy_raw_seller - - CI_AWS_TASK="proxy-router" - - CI_WALLET_PRIVATE_KEY=$SELLER_PRIVATEKEY - - CI_WEB_PUBLIC_URL=$WEB_PUBLIC_URL - - CI_ETH_NODE_ADDRESS=$PROXY_ROUTER_ETH_NODE_ADDRESS - - *ecr_login_script - - *update_raw_task_definition - - *deploy_new_task_definition - -####################### -# DEPLOY DEVELOPMENT -####################### -bedrock-02-DEV-seller: - stage: deploy - environment: dev - needs: ["bedrock-02-DEV-rawimage"] - rules: - - if: $CI_COMMIT_BRANCH == "dev" - when: always - - if: $CI_COMMIT_BRANCH != "dev" - when: never - - if: $CI_MERGE_REQUEST_ID - when: never - tags: - - proxy #devops - - bedrock - - shell - - titanio-dev - variables: - TGT_ACCOUNT: $CI_AWS_ACCOUNT_DEV - TGT_ENV: dev - script: - - *deploy_raw_seller - - echo "$TGT_ENV seller updated" - -####################### -# DEPLOY STAGING -####################### -bedrock-03-STG-seller: - stage: deploy - environment: stg - needs: ["bedrock-03-STG-rawimage"] - rules: - - if: $CI_COMMIT_BRANCH == "stg" - when: always - - if: $CI_COMMIT_BRANCH != "stg" - when: never - - if: $CI_MERGE_REQUEST_ID - when: never - tags: - - proxy #devops - - bedrock - - shell - - titanio-stg - variables: - TGT_ACCOUNT: $CI_AWS_ACCOUNT_STG - TGT_ENV: stg - script: - - *deploy_raw_seller - - echo "$TGT_ENV seller updated" - -####################### -# DEPLOY PRODUCTION / MAIN / LMN -####################### -bedrock-04-PRD-seller: - stage: deploy - environment: lmn - needs: ["bedrock-04-PRD-rawimage"] - rules: - - if: $CI_COMMIT_BRANCH == "main" - when: manual - - if: $CI_COMMIT_BRANCH != "main" - when: never - - if: $CI_MERGE_REQUEST_ID - when: never - tags: - - proxy #devops - - bedrock - - shell - - titanio-lmn - variables: - TGT_ACCOUNT: $CI_AWS_ACCOUNT_LMN - TGT_ENV: lmn - PROXY_LOG_STRATUM: "false" - script: - - *deploy_raw_seller - - echo "$TGT_ENV seller updated" - -####################### -# E2E TEST STAGE -####################### -# e2e-test: -# stage: e2e-test -# allow_failure: true -# trigger: -# project: TitanInd/proxy/router-test -# branch: $CI_COMMIT_BRANCH -# strategy: depend - -####################### -# RELEASE STAGE -####################### -.default-release: &default-release - inherit: - default: false - stage: release - needs: ["test", "lint"] - image: - name: goreleaser/goreleaser:v1.19.2 - entrypoint: [""] - -.default-tag: &default-tag - stage: release - needs: ["test", "lint"] - image: node:alpine - before_script: - - export $(grep -v '^#' .version | xargs) - - apk --no-cache add git - - PROJECT_URL=$(echo $CI_PROJECT_URL | sed 's/https:\/\///') - - git remote set-url origin https://oauth2:$CI_TAG_PUSH_TOKEN@$PROJECT_URL - -create_tag: - <<: *default-tag - rules: - - if: $CI_COMMIT_BRANCH == "dev" - when: manual - - if: $CI_COMMIT_BRANCH == "stg" - when: on_success - script: - - git fetch origin -f --prune --prune-tags - - git tag "$VERSION-$CI_COMMIT_BRANCH" - - git push origin --tags - -create_tag_main: - <<: *default-tag - rules: - - if: $CI_COMMIT_BRANCH == "main" - when: on_success - script: - - git fetch origin -f --prune --prune-tags - - git tag "$VERSION-lmn" - - git push origin --tags - -release-internal: - <<: *default-release - variables: - GIT_DEPTH: 0 - GITLAB_TOKEN: $CI_TAG_PUSH_TOKEN - GORELEASER_FORCE_TOKEN: gitlab - only: - - /.*-dev$/ - - /.*-stg$/ - script: - - goreleaser release --clean -f "./.goreleaser-internal.yaml" - artifacts: - paths: - - dist/proxy-router_* - -release-external: - <<: *default-release - variables: - GIT_DEPTH: 0 - GORELEASER_FORCE_TOKEN: github - only: - - /.*-lmn$/ - script: - - goreleaser release --clean \ No newline at end of file diff --git a/proxy-router/.mockery.yaml b/proxy-router/.mockery.yaml new file mode 100644 index 00000000..896ce376 --- /dev/null +++ b/proxy-router/.mockery.yaml @@ -0,0 +1,9 @@ +with-expecter: true +filename: "{{.InterfaceName | snakecase}}_mock.go" +dir: "{{.InterfaceDir}}/mocks" +mockname: "{{.InterfaceName}}Mock" +outpkg: "mocks" +packages: + github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/interfaces: + interfaces: + EthClient: diff --git a/proxy-router/.version b/proxy-router/.version deleted file mode 100644 index 3effbab8..00000000 --- a/proxy-router/.version +++ /dev/null @@ -1 +0,0 @@ -VERSION=0.0.3 diff --git a/proxy-router/Dockerfile b/proxy-router/Dockerfile index 1eda590d..0e558363 100644 --- a/proxy-router/Dockerfile +++ b/proxy-router/Dockerfile @@ -1,24 +1,33 @@ -FROM golang:1.22.3 as base -RUN apt-get update && apt-get install -y procps curl gnupg2 dbus-x11 +# Stage 1: Build +FROM golang:1.22.3-alpine AS builder -FROM base as builder +# Capture the Git tag and commit hash during build +ARG TAG_NAME ARG COMMIT +ENV TAG_NAME=$TAG_NAME ENV COMMIT=$COMMIT -WORKDIR /app +WORKDIR /app COPY . . -RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 ./build.sh +# Build the Go binary (Docker will build automatically to the OS and Arch that is hosting) +RUN CGO_ENABLED=0 \ + TAG_NAME=$TAG_NAME COMMIT=$COMMIT ./build.sh && \ + cp /bin/sh /app/sh && chmod +x /app/sh +# Stage 2: Final Image FROM scratch WORKDIR /app + +# Copy required files and binary COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ COPY --from=builder /app/bin/proxy-router /usr/bin/ -COPY --from=builder /usr/bin/dbus-launch /usr/bin/ -COPY --from=builder /app/.env /app/.env + +# Optional Copy utilities from busybox image COPY --from=busybox /bin /bin COPY --from=busybox /lib /lib SHELL ["/bin/sh", "-c"] -EXPOSE 3333 8080 8082 +EXPOSE 3333 8082 + ENTRYPOINT ["proxy-router"] \ No newline at end of file diff --git a/proxy-router/LICENSE b/proxy-router/LICENSE index 424057e1..5af4dd1c 100644 --- a/proxy-router/LICENSE +++ b/proxy-router/LICENSE @@ -1,20 +1,21 @@ -The MIT License (MIT) +MIT License -Copyright (c) Titan Industries +Copyright (c) 2024 Morpheus -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -the Software, and to permit persons to whom the Software is furnished to do so, -subject to the following conditions: +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/proxy-router/Makefile b/proxy-router/Makefile index ffdc7b6f..78134b8c 100644 --- a/proxy-router/Makefile +++ b/proxy-router/Makefile @@ -35,4 +35,13 @@ test-integration: go test -v ./test/... swagger: - swag fmt -g ./internal/handlers/httphandlers/http.go && swag init -g ./internal/handlers/httphandlers/http.go --parseInternal \ No newline at end of file + swag fmt -g ./internal/handlers/httphandlers/http.go && swag init -g ./internal/handlers/httphandlers/http.go --parseInternal + +mocks: + mockery + +reset-keychain: + go run cmd/main.go -app-reset-keychain + +update-bindings: + cd ../smart-contracts && yarn bindings-go && cp -r bindings/go/contracts/{diamond/facets/*,tokens/*,mock/tokens/*} ../proxy-router/internal/repositories/contracts/bindings diff --git a/proxy-router/build.sh b/proxy-router/build.sh index 3624bebd..9067df06 100755 --- a/proxy-router/build.sh +++ b/proxy-router/build.sh @@ -1,18 +1,29 @@ #!/bin/sh -VERSION=$(grep '^VERSION=' .version | cut -d '=' -f 2-) -echo VERSION=$VERSION +# Check if TAG_NAME is set; if not, use the latest Git tag or fallback to 0.1.0 +if [ -z "$TAG_NAME" ]; then + TAG_NAME=$(git describe --tags --abbrev=0 2>/dev/null || echo "0.1.0") + if [ "$TAG_NAME" = "0.1.0" ]; then + echo "Warning: No Git tags found. Defaulting to TAG_NAME=$TAG_NAME" + else + echo "Using latest Git tag: $TAG_NAME" + fi +fi +VERSION=$TAG_NAME +echo VERSION=$VERSION # if commit is not set, use the latest commit if [ -z "$COMMIT" ]; then COMMIT=$(git rev-parse HEAD) fi echo COMMIT=$COMMIT - +go mod tidy go build \ -tags docker \ -ldflags="-s -w \ -X 'github.com/Lumerin-protocol/Morpheus-Lumerin-Node/proxy-router/internal/config.BuildVersion=$VERSION' \ -X 'github.com/Lumerin-protocol/Morpheus-Lumerin-Node/proxy-router/internal/config.Commit=$COMMIT' \ + -X 'github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/config.BuildVersion=$VERSION' \ + -X 'github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/config.Commit=$COMMIT' \ " \ -o bin/proxy-router cmd/main.go diff --git a/proxy-router/cmd/main.go b/proxy-router/cmd/main.go index 9e90f0b9..21d02700 100644 --- a/proxy-router/cmd/main.go +++ b/proxy-router/cmd/main.go @@ -3,6 +3,7 @@ package main import ( "context" "fmt" + "math/big" "net/url" "os" "os/signal" @@ -13,28 +14,28 @@ import ( "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/aiengine" "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/apibus" "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/blockchainapi" + "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/chatstorage" "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/config" "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/handlers/httphandlers" "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/interfaces" "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/lib" "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/proxyapi" "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/proxyctl" + "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/repositories/contracts" + "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/repositories/ethclient" + "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/repositories/keychain" + "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/repositories/multicall" "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/repositories/registries" + sessionrepo "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/repositories/session" "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/repositories/transport" wlt "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/repositories/wallet" "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/storages" "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/system" "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/walletapi" - "github.com/ethereum/go-ethereum/ethclient" docs "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/docs" ) -const ( - IDLE_READ_CLOSE_TIMEOUT = 10 * time.Minute - IDLE_WRITE_CLOSE_TIMEOUT = 10 * time.Minute -) - var ( ErrConnectToEthNode = fmt.Errorf("cannot connect to ethereum node") ) @@ -85,9 +86,10 @@ func start() error { docs.SwaggerInfo.Host = hostWithoutProtocol } else if cfg.Web.Address != "" { docs.SwaggerInfo.Host = cfg.Web.Address - } else { - docs.SwaggerInfo.Host = "localhost:8082" } + docs.SwaggerInfo.Version = config.BuildVersion + + docs.SwaggerInfo.Version = config.BuildVersion log, err := lib.NewLogger(cfg.Log.LevelApp, cfg.Log.Color, cfg.Log.IsProd, cfg.Log.JSON, mainLogFilePath) if err != nil { @@ -96,40 +98,28 @@ func start() error { appLog := log.Named("APP") - proxyLog, err := lib.NewLogger(cfg.Log.LevelProxy, cfg.Log.Color, cfg.Log.IsProd, cfg.Log.JSON, mainLogFilePath) + tcpLog, err := lib.NewLogger(cfg.Log.LevelTCP, cfg.Log.Color, cfg.Log.IsProd, cfg.Log.JSON, mainLogFilePath) if err != nil { return err } - connLog, err := lib.NewLogger(cfg.Log.LevelConnection, cfg.Log.Color, cfg.Log.IsProd, cfg.Log.JSON, mainLogFilePath) + contractLogStorage := lib.NewCollection[*interfaces.LogStorage]() + + rpcLog, err := lib.NewLogger(cfg.Log.LevelEthRPC, cfg.Log.Color, cfg.Log.IsProd, cfg.Log.JSON, mainLogFilePath) if err != nil { return err } - schedulerLogFactory := func(remoteAddr string) (lib.ILogger, error) { - fp := "" - if logFolderPath != "" { - fp = filepath.Join(logFolderPath, fmt.Sprintf("scheduler-%s.log", lib.SanitizeFilename(remoteAddr))) - } - return lib.NewLogger(cfg.Log.LevelScheduler, cfg.Log.Color, cfg.Log.IsProd, cfg.Log.JSON, fp) + storageLog, err := lib.NewLogger(cfg.Log.LevelStorage, cfg.Log.Color, cfg.Log.IsProd, cfg.Log.JSON, mainLogFilePath) + if err != nil { + return err } - contractLogStorage := lib.NewCollection[*interfaces.LogStorage]() - - // contractLogFactory := func(contractID string) (lib.ILogger, error) { - // logStorage := interfaces.NewLogStorage(contractID) - // contractLogStorage.Store(logStorage) - // fp := "" - // if logFolderPath != "" { - // fp = filepath.Join(logFolderPath, fmt.Sprintf("contract-%s.log", lib.SanitizeFilename(lib.StrShort(contractID)))) - // } - // return lib.NewLoggerMemory(cfg.Log.LevelContract, cfg.Log.Color, cfg.Log.IsProd, cfg.Log.JSON, fp, logStorage.Buffer) - // } - defer func() { - _ = connLog.Close() - _ = proxyLog.Close() + _ = tcpLog.Close() _ = log.Close() + _ = rpcLog.Close() + _ = storageLog.Close() }() appLog.Infof("proxy-router %s", config.BuildVersion) @@ -182,58 +172,106 @@ func start() error { os.Exit(1) }() - ethClient, err := ethclient.DialContext(ctx, cfg.Blockchain.EthNodeAddress) + keychainStorage := keychain.NewKeychain() + + if cfg.App.ResetKeychain { + appLog.Warnf("Resetting keychain...") + wallet := wlt.NewKeychainWallet(keychainStorage) + err = wallet.DeleteWallet() + if err != nil { + appLog.Warnf("Failed to delete wallet\n%s", err) + } else { + appLog.Info("Wallet deleted") + } + + ethNodeStorage := ethclient.NewRPCClientStoreKeychain(keychainStorage, nil, rpcLog.Named("RPC")) + err = ethNodeStorage.RemoveURLs() + if err != nil { + appLog.Warnf("Failed to remove eth node urls\n%s", err) + } else { + appLog.Info("Eth node urls removed") + } + return nil + } + + var ethNodeAddresses []string + if cfg.Blockchain.EthNodeAddress != "" { + ethNodeAddresses = []string{cfg.Blockchain.EthNodeAddress} + } + rpcClientStore, err := ethclient.ConfigureRPCClientStore(keychainStorage, ethNodeAddresses, cfg.Blockchain.ChainID, rpcLog.Named("RPC")) if err != nil { return lib.WrapError(ErrConnectToEthNode, err) } + + ethClient := ethclient.NewClient(rpcClientStore.GetClient()) chainID, err := ethClient.ChainID(ctx) if err != nil { return lib.WrapError(ErrConnectToEthNode, err) } - appLog.Infof("connected to ethereum node: %s, chainID: %d", cfg.Blockchain.EthNodeAddress, chainID) - - publicUrl, err := url.Parse(cfg.Web.PublicUrl) - if err != nil { - return err + if cfg.Blockchain.ChainID != 0 && int(chainID.Uint64()) != cfg.Blockchain.ChainID { + return lib.WrapError(ErrConnectToEthNode, fmt.Errorf("configured chainID (%d) does not match eth node chain ID (%s)", cfg.Blockchain.ChainID, chainID)) } + appLog.Infof("connected to ethereum node: %s, chainID: %d", cfg.Blockchain.EthNodeAddress, chainID) - storage := storages.NewStorage(log, cfg.Proxy.StoragePath) + storage := storages.NewStorage(storageLog, cfg.Proxy.StoragePath) sessionStorage := storages.NewSessionStorage(storage) var wallet interfaces.Wallet if len(*cfg.Marketplace.WalletPrivateKey) > 0 { wallet = wlt.NewEnvWallet(*cfg.Marketplace.WalletPrivateKey) - log.Warnf("Using env wallet. Private key persistance unavailable") + appLog.Warnf("Using env wallet. Private key persistance unavailable") } else { - wallet = wlt.NewKeychainWallet() - log.Infof("Using keychain wallet") + wallet = wlt.NewKeychainWallet(keychainStorage) + appLog.Infof("Using keychain wallet") } - modelConfigLoader := config.NewModelConfigLoader(cfg.Proxy.ModelsConfigPath, log) - err = modelConfigLoader.Init() + var logWatcher contracts.LogWatcher + if cfg.Blockchain.UseSubscriptions { + logWatcher = contracts.NewLogWatcherSubscription(ethClient, cfg.Blockchain.MaxReconnects, rpcLog) + appLog.Infof("using websocket log subscription for blockchain events") + } else { + logWatcher = contracts.NewLogWatcherPolling(ethClient, cfg.Blockchain.PollingInterval, cfg.Blockchain.MaxReconnects, rpcLog) + appLog.Infof("using polling for blockchain events") + } + + scorer, err := config.LoadRating(cfg.Proxy.RatingConfigPath, appLog) if err != nil { - log.Warnf("failed to load model config: %s, run with empty", err) + return err } - proxyRouterApi := proxyapi.NewProxySender(publicUrl, wallet, contractLogStorage, sessionStorage, log) - blockchainApi := blockchainapi.NewBlockchainService(ethClient, *cfg.Marketplace.DiamondContractAddress, *cfg.Marketplace.MorTokenAddress, cfg.Blockchain.ExplorerApiUrl, wallet, sessionStorage, proxyRouterApi, proxyLog, cfg.Blockchain.EthLegacyTx) - aiEngine := aiengine.NewAiEngine(cfg.AIEngine.OpenAIBaseURL, cfg.AIEngine.OpenAIKey, modelConfigLoader, log) + chatStoragePath := filepath.Join(cfg.Proxy.StoragePath, "chats") + chatStorage := chatstorage.NewChatStorage(chatStoragePath) - sessionRouter := registries.NewSessionRouter(*cfg.Marketplace.DiamondContractAddress, ethClient, log) + multicallBackend := multicall.NewMulticall3Custom(ethClient, *cfg.Blockchain.Multicall3Addr) + sessionRouter := registries.NewSessionRouter(*cfg.Marketplace.DiamondContractAddress, ethClient, multicallBackend, rpcLog) + marketplace := registries.NewMarketplace(*cfg.Marketplace.DiamondContractAddress, ethClient, multicallBackend, rpcLog) + sessionRepo := sessionrepo.NewSessionRepositoryCached(sessionStorage, sessionRouter, marketplace) + proxyRouterApi := proxyapi.NewProxySender(chainID, wallet, contractLogStorage, sessionStorage, sessionRepo, appLog) + explorer := blockchainapi.NewExplorerClient(cfg.Blockchain.ExplorerApiUrl, *cfg.Marketplace.MorTokenAddress, cfg.Blockchain.ExplorerRetryDelay, cfg.Blockchain.ExplorerMaxRetries) + blockchainApi := blockchainapi.NewBlockchainService(ethClient, multicallBackend, *cfg.Marketplace.DiamondContractAddress, *cfg.Marketplace.MorTokenAddress, explorer, wallet, proxyRouterApi, sessionRepo, scorer, appLog, rpcLog, cfg.Blockchain.EthLegacyTx) + proxyRouterApi.SetSessionService(blockchainApi) - eventListener := blockchainapi.NewEventsListener(ethClient, sessionStorage, sessionRouter, wallet, modelConfigLoader, log) + modelConfigLoader := config.NewModelConfigLoader(cfg.Proxy.ModelsConfigPath, valid, blockchainApi, &aiengine.ConnectionChecker{}, appLog) + err = modelConfigLoader.Init() + if err != nil { + appLog.Warnf("failed to load model config, running with empty: %s", err) + } + + aiEngine := aiengine.NewAiEngine(proxyRouterApi, chatStorage, modelConfigLoader, appLog) - blockchainController := blockchainapi.NewBlockchainController(blockchainApi, log) + eventListener := blockchainapi.NewEventsListener(sessionRepo, sessionRouter, wallet, logWatcher, appLog) - chatStoragePath := filepath.Join(cfg.Proxy.StoragePath, "chat") - chatStorage := proxyapi.NewChatStorage(chatStoragePath) - proxyController := proxyapi.NewProxyController(proxyRouterApi, aiEngine, chatStorage) + sessionExpiryHandler := blockchainapi.NewSessionExpiryHandler(blockchainApi, sessionStorage, wallet, appLog) + blockchainController := blockchainapi.NewBlockchainController(blockchainApi, appLog) + + ethConnectionValidator := system.NewEthConnectionValidator(*big.NewInt(int64(cfg.Blockchain.ChainID))) + proxyController := proxyapi.NewProxyController(proxyRouterApi, aiEngine, chatStorage, *cfg.Proxy.StoreChatContext.Bool, *cfg.Proxy.ForwardChatContext.Bool, appLog) walletController := walletapi.NewWalletController(wallet) - systemController := system.NewSystemController(&cfg, wallet, sysConfig, appStartTime, chainID, log) + systemController := system.NewSystemController(&cfg, wallet, rpcClientStore, sysConfig, appStartTime, chainID, appLog, ethConnectionValidator) apiBus := apibus.NewApiBus(blockchainController, proxyController, walletController, systemController) - httpHandler := httphandlers.CreateHTTPServer(log, apiBus) - httpServer := transport.NewServer(cfg.Web.Address, httpHandler, log.Named("HTTP")) + httpHandler := httphandlers.CreateHTTPServer(appLog, apiBus) + httpServer := transport.NewServer(cfg.Web.Address, httpHandler, appLog.Named("HTTP")) // http server should shut down latest to keep pprof running serverErrCh := make(chan error, 1) @@ -243,7 +281,9 @@ func start() error { cancel() }() - proxy := proxyctl.NewProxyCtl(eventListener, wallet, chainID, log, connLog, cfg.Proxy.Address, schedulerLogFactory, sessionStorage, modelConfigLoader, valid, aiEngine) + appLog.Infof("API docs available at %s/swagger/index.html", cfg.Web.PublicUrl) + + proxy := proxyctl.NewProxyCtl(eventListener, wallet, chainID, appLog, tcpLog, cfg.Proxy.Address, sessionStorage, modelConfigLoader, valid, aiEngine, blockchainApi, sessionRepo, sessionExpiryHandler) err = proxy.Run(ctx) cancelServer() diff --git a/proxy-router/contracts/marketplace/Marketplace.go b/proxy-router/contracts/marketplace/Marketplace.go deleted file mode 100644 index 17f8ac49..00000000 --- a/proxy-router/contracts/marketplace/Marketplace.go +++ /dev/null @@ -1,994 +0,0 @@ -// Code generated - DO NOT EDIT. -// This file is a generated binding and any manual changes will be lost. - -package marketplace - -import ( - "errors" - "math/big" - "strings" - - ethereum "github.com/ethereum/go-ethereum" - "github.com/ethereum/go-ethereum/accounts/abi" - "github.com/ethereum/go-ethereum/accounts/abi/bind" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/event" -) - -// Reference imports to suppress errors if they are not otherwise used. -var ( - _ = errors.New - _ = big.NewInt - _ = strings.NewReader - _ = ethereum.NotFound - _ = bind.Bind - _ = common.Big1 - _ = types.BloomLookup - _ = event.NewSubscription - _ = abi.ConvertType -) - -// Bid is an auto generated low-level Go binding around an user-defined struct. -type Bid struct { - Provider common.Address - ModelAgentId [32]byte - PricePerSecond *big.Int - Nonce *big.Int - CreatedAt *big.Int - DeletedAt *big.Int -} - -// LibSDSD is an auto generated low-level Go binding around an user-defined struct. -type LibSDSD struct { - Mean int64 - SqSum int64 -} - -// ModelStats is an auto generated low-level Go binding around an user-defined struct. -type ModelStats struct { - TpsScaled1000 LibSDSD - TtftMs LibSDSD - TotalDuration LibSDSD - Count uint32 -} - -// ProviderModelStats is an auto generated low-level Go binding around an user-defined struct. -type ProviderModelStats struct { - TpsScaled1000 LibSDSD - TtftMs LibSDSD - TotalDuration uint32 - SuccessCount uint32 - TotalCount uint32 -} - -// MarketplaceMetaData contains all meta data concerning the Marketplace contract. -var MarketplaceMetaData = &bind.MetaData{ - ABI: "[{\"inputs\":[],\"name\":\"ActiveBidNotFound\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"BidTaken\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"KeyExists\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"KeyNotFound\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ModelOrAgentNotFound\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_user\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_contractOwner\",\"type\":\"address\"}],\"name\":\"NotContractOwner\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NotEnoughBalance\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NotSenderOrOwner\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"PricePerSecondIsZero\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ProviderNotFound\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ZeroKey\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"provider\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"modelAgentId\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"}],\"name\":\"BidDeleted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"provider\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"modelAgentId\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"}],\"name\":\"BidPosted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"bidFee\",\"type\":\"uint256\"}],\"name\":\"FeeUpdated\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"bidFee\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"bidId\",\"type\":\"bytes32\"}],\"name\":\"bidMap\",\"outputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"provider\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"modelAgentId\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"pricePerSecond\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"internalType\":\"uint128\",\"name\":\"createdAt\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"deletedAt\",\"type\":\"uint128\"}],\"internalType\":\"structBid\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"bidId\",\"type\":\"bytes32\"}],\"name\":\"deleteModelAgentBid\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"modelAgentId\",\"type\":\"bytes32\"}],\"name\":\"getActiveBidsByModelAgent\",\"outputs\":[{\"internalType\":\"bytes32[]\",\"name\":\"\",\"type\":\"bytes32[]\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"provider\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"modelAgentId\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"pricePerSecond\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"internalType\":\"uint128\",\"name\":\"createdAt\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"deletedAt\",\"type\":\"uint128\"}],\"internalType\":\"structBid[]\",\"name\":\"\",\"type\":\"tuple[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"provider\",\"type\":\"address\"}],\"name\":\"getActiveBidsByProvider\",\"outputs\":[{\"internalType\":\"bytes32[]\",\"name\":\"\",\"type\":\"bytes32[]\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"provider\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"modelAgentId\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"pricePerSecond\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"internalType\":\"uint128\",\"name\":\"createdAt\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"deletedAt\",\"type\":\"uint128\"}],\"internalType\":\"structBid[]\",\"name\":\"\",\"type\":\"tuple[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"modelAgentId\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"offset\",\"type\":\"uint256\"},{\"internalType\":\"uint8\",\"name\":\"limit\",\"type\":\"uint8\"}],\"name\":\"getActiveBidsRatingByModelAgent\",\"outputs\":[{\"internalType\":\"bytes32[]\",\"name\":\"\",\"type\":\"bytes32[]\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"provider\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"modelAgentId\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"pricePerSecond\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"internalType\":\"uint128\",\"name\":\"createdAt\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"deletedAt\",\"type\":\"uint128\"}],\"internalType\":\"structBid[]\",\"name\":\"\",\"type\":\"tuple[]\"},{\"components\":[{\"components\":[{\"internalType\":\"int64\",\"name\":\"mean\",\"type\":\"int64\"},{\"internalType\":\"int64\",\"name\":\"sqSum\",\"type\":\"int64\"}],\"internalType\":\"structLibSD.SD\",\"name\":\"tpsScaled1000\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"int64\",\"name\":\"mean\",\"type\":\"int64\"},{\"internalType\":\"int64\",\"name\":\"sqSum\",\"type\":\"int64\"}],\"internalType\":\"structLibSD.SD\",\"name\":\"ttftMs\",\"type\":\"tuple\"},{\"internalType\":\"uint32\",\"name\":\"totalDuration\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"successCount\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"totalCount\",\"type\":\"uint32\"}],\"internalType\":\"structProviderModelStats[]\",\"name\":\"\",\"type\":\"tuple[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"modelAgentId\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"offset\",\"type\":\"uint256\"},{\"internalType\":\"uint8\",\"name\":\"limit\",\"type\":\"uint8\"}],\"name\":\"getBidsByModelAgent\",\"outputs\":[{\"internalType\":\"bytes32[]\",\"name\":\"\",\"type\":\"bytes32[]\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"provider\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"modelAgentId\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"pricePerSecond\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"internalType\":\"uint128\",\"name\":\"createdAt\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"deletedAt\",\"type\":\"uint128\"}],\"internalType\":\"structBid[]\",\"name\":\"\",\"type\":\"tuple[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"provider\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"offset\",\"type\":\"uint256\"},{\"internalType\":\"uint8\",\"name\":\"limit\",\"type\":\"uint8\"}],\"name\":\"getBidsByProvider\",\"outputs\":[{\"internalType\":\"bytes32[]\",\"name\":\"\",\"type\":\"bytes32[]\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"provider\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"modelAgentId\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"pricePerSecond\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"internalType\":\"uint128\",\"name\":\"createdAt\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"deletedAt\",\"type\":\"uint128\"}],\"internalType\":\"structBid[]\",\"name\":\"\",\"type\":\"tuple[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"modelID\",\"type\":\"bytes32\"}],\"name\":\"getModelStats\",\"outputs\":[{\"components\":[{\"components\":[{\"internalType\":\"int64\",\"name\":\"mean\",\"type\":\"int64\"},{\"internalType\":\"int64\",\"name\":\"sqSum\",\"type\":\"int64\"}],\"internalType\":\"structLibSD.SD\",\"name\":\"tpsScaled1000\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"int64\",\"name\":\"mean\",\"type\":\"int64\"},{\"internalType\":\"int64\",\"name\":\"sqSum\",\"type\":\"int64\"}],\"internalType\":\"structLibSD.SD\",\"name\":\"ttftMs\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"int64\",\"name\":\"mean\",\"type\":\"int64\"},{\"internalType\":\"int64\",\"name\":\"sqSum\",\"type\":\"int64\"}],\"internalType\":\"structLibSD.SD\",\"name\":\"totalDuration\",\"type\":\"tuple\"},{\"internalType\":\"uint32\",\"name\":\"count\",\"type\":\"uint32\"}],\"internalType\":\"structModelStats\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"providerAddr\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"modelId\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"pricePerSecond\",\"type\":\"uint256\"}],\"name\":\"postModelBid\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"bidId\",\"type\":\"bytes32\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_bidFee\",\"type\":\"uint256\"}],\"name\":\"setBidFee\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"withdraw\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", -} - -// MarketplaceABI is the input ABI used to generate the binding from. -// Deprecated: Use MarketplaceMetaData.ABI instead. -var MarketplaceABI = MarketplaceMetaData.ABI - -// Marketplace is an auto generated Go binding around an Ethereum contract. -type Marketplace struct { - MarketplaceCaller // Read-only binding to the contract - MarketplaceTransactor // Write-only binding to the contract - MarketplaceFilterer // Log filterer for contract events -} - -// MarketplaceCaller is an auto generated read-only Go binding around an Ethereum contract. -type MarketplaceCaller struct { - contract *bind.BoundContract // Generic contract wrapper for the low level calls -} - -// MarketplaceTransactor is an auto generated write-only Go binding around an Ethereum contract. -type MarketplaceTransactor struct { - contract *bind.BoundContract // Generic contract wrapper for the low level calls -} - -// MarketplaceFilterer is an auto generated log filtering Go binding around an Ethereum contract events. -type MarketplaceFilterer struct { - contract *bind.BoundContract // Generic contract wrapper for the low level calls -} - -// MarketplaceSession is an auto generated Go binding around an Ethereum contract, -// with pre-set call and transact options. -type MarketplaceSession struct { - Contract *Marketplace // Generic contract binding to set the session for - CallOpts bind.CallOpts // Call options to use throughout this session - TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session -} - -// MarketplaceCallerSession is an auto generated read-only Go binding around an Ethereum contract, -// with pre-set call options. -type MarketplaceCallerSession struct { - Contract *MarketplaceCaller // Generic contract caller binding to set the session for - CallOpts bind.CallOpts // Call options to use throughout this session -} - -// MarketplaceTransactorSession is an auto generated write-only Go binding around an Ethereum contract, -// with pre-set transact options. -type MarketplaceTransactorSession struct { - Contract *MarketplaceTransactor // Generic contract transactor binding to set the session for - TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session -} - -// MarketplaceRaw is an auto generated low-level Go binding around an Ethereum contract. -type MarketplaceRaw struct { - Contract *Marketplace // Generic contract binding to access the raw methods on -} - -// MarketplaceCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. -type MarketplaceCallerRaw struct { - Contract *MarketplaceCaller // Generic read-only contract binding to access the raw methods on -} - -// MarketplaceTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. -type MarketplaceTransactorRaw struct { - Contract *MarketplaceTransactor // Generic write-only contract binding to access the raw methods on -} - -// NewMarketplace creates a new instance of Marketplace, bound to a specific deployed contract. -func NewMarketplace(address common.Address, backend bind.ContractBackend) (*Marketplace, error) { - contract, err := bindMarketplace(address, backend, backend, backend) - if err != nil { - return nil, err - } - return &Marketplace{MarketplaceCaller: MarketplaceCaller{contract: contract}, MarketplaceTransactor: MarketplaceTransactor{contract: contract}, MarketplaceFilterer: MarketplaceFilterer{contract: contract}}, nil -} - -// NewMarketplaceCaller creates a new read-only instance of Marketplace, bound to a specific deployed contract. -func NewMarketplaceCaller(address common.Address, caller bind.ContractCaller) (*MarketplaceCaller, error) { - contract, err := bindMarketplace(address, caller, nil, nil) - if err != nil { - return nil, err - } - return &MarketplaceCaller{contract: contract}, nil -} - -// NewMarketplaceTransactor creates a new write-only instance of Marketplace, bound to a specific deployed contract. -func NewMarketplaceTransactor(address common.Address, transactor bind.ContractTransactor) (*MarketplaceTransactor, error) { - contract, err := bindMarketplace(address, nil, transactor, nil) - if err != nil { - return nil, err - } - return &MarketplaceTransactor{contract: contract}, nil -} - -// NewMarketplaceFilterer creates a new log filterer instance of Marketplace, bound to a specific deployed contract. -func NewMarketplaceFilterer(address common.Address, filterer bind.ContractFilterer) (*MarketplaceFilterer, error) { - contract, err := bindMarketplace(address, nil, nil, filterer) - if err != nil { - return nil, err - } - return &MarketplaceFilterer{contract: contract}, nil -} - -// bindMarketplace binds a generic wrapper to an already deployed contract. -func bindMarketplace(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { - parsed, err := MarketplaceMetaData.GetAbi() - if err != nil { - return nil, err - } - return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil -} - -// Call invokes the (constant) contract method with params as input values and -// sets the output to result. The result type might be a single field for simple -// returns, a slice of interfaces for anonymous returns and a struct for named -// returns. -func (_Marketplace *MarketplaceRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { - return _Marketplace.Contract.MarketplaceCaller.contract.Call(opts, result, method, params...) -} - -// Transfer initiates a plain transaction to move funds to the contract, calling -// its default method if one is available. -func (_Marketplace *MarketplaceRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { - return _Marketplace.Contract.MarketplaceTransactor.contract.Transfer(opts) -} - -// Transact invokes the (paid) contract method with params as input values. -func (_Marketplace *MarketplaceRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { - return _Marketplace.Contract.MarketplaceTransactor.contract.Transact(opts, method, params...) -} - -// Call invokes the (constant) contract method with params as input values and -// sets the output to result. The result type might be a single field for simple -// returns, a slice of interfaces for anonymous returns and a struct for named -// returns. -func (_Marketplace *MarketplaceCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { - return _Marketplace.Contract.contract.Call(opts, result, method, params...) -} - -// Transfer initiates a plain transaction to move funds to the contract, calling -// its default method if one is available. -func (_Marketplace *MarketplaceTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { - return _Marketplace.Contract.contract.Transfer(opts) -} - -// Transact invokes the (paid) contract method with params as input values. -func (_Marketplace *MarketplaceTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { - return _Marketplace.Contract.contract.Transact(opts, method, params...) -} - -// BidFee is a free data retrieval call binding the contract method 0xe14a2115. -// -// Solidity: function bidFee() view returns(uint256) -func (_Marketplace *MarketplaceCaller) BidFee(opts *bind.CallOpts) (*big.Int, error) { - var out []interface{} - err := _Marketplace.contract.Call(opts, &out, "bidFee") - - if err != nil { - return *new(*big.Int), err - } - - out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - - return out0, err - -} - -// BidFee is a free data retrieval call binding the contract method 0xe14a2115. -// -// Solidity: function bidFee() view returns(uint256) -func (_Marketplace *MarketplaceSession) BidFee() (*big.Int, error) { - return _Marketplace.Contract.BidFee(&_Marketplace.CallOpts) -} - -// BidFee is a free data retrieval call binding the contract method 0xe14a2115. -// -// Solidity: function bidFee() view returns(uint256) -func (_Marketplace *MarketplaceCallerSession) BidFee() (*big.Int, error) { - return _Marketplace.Contract.BidFee(&_Marketplace.CallOpts) -} - -// BidMap is a free data retrieval call binding the contract method 0xf141c9a3. -// -// Solidity: function bidMap(bytes32 bidId) view returns((address,bytes32,uint256,uint256,uint128,uint128)) -func (_Marketplace *MarketplaceCaller) BidMap(opts *bind.CallOpts, bidId [32]byte) (Bid, error) { - var out []interface{} - err := _Marketplace.contract.Call(opts, &out, "bidMap", bidId) - - if err != nil { - return *new(Bid), err - } - - out0 := *abi.ConvertType(out[0], new(Bid)).(*Bid) - - return out0, err - -} - -// BidMap is a free data retrieval call binding the contract method 0xf141c9a3. -// -// Solidity: function bidMap(bytes32 bidId) view returns((address,bytes32,uint256,uint256,uint128,uint128)) -func (_Marketplace *MarketplaceSession) BidMap(bidId [32]byte) (Bid, error) { - return _Marketplace.Contract.BidMap(&_Marketplace.CallOpts, bidId) -} - -// BidMap is a free data retrieval call binding the contract method 0xf141c9a3. -// -// Solidity: function bidMap(bytes32 bidId) view returns((address,bytes32,uint256,uint256,uint128,uint128)) -func (_Marketplace *MarketplaceCallerSession) BidMap(bidId [32]byte) (Bid, error) { - return _Marketplace.Contract.BidMap(&_Marketplace.CallOpts, bidId) -} - -// GetActiveBidsByModelAgent is a free data retrieval call binding the contract method 0x873d94d5. -// -// Solidity: function getActiveBidsByModelAgent(bytes32 modelAgentId) view returns(bytes32[], (address,bytes32,uint256,uint256,uint128,uint128)[]) -func (_Marketplace *MarketplaceCaller) GetActiveBidsByModelAgent(opts *bind.CallOpts, modelAgentId [32]byte) ([][32]byte, []Bid, error) { - var out []interface{} - err := _Marketplace.contract.Call(opts, &out, "getActiveBidsByModelAgent", modelAgentId) - - if err != nil { - return *new([][32]byte), *new([]Bid), err - } - - out0 := *abi.ConvertType(out[0], new([][32]byte)).(*[][32]byte) - out1 := *abi.ConvertType(out[1], new([]Bid)).(*[]Bid) - - return out0, out1, err - -} - -// GetActiveBidsByModelAgent is a free data retrieval call binding the contract method 0x873d94d5. -// -// Solidity: function getActiveBidsByModelAgent(bytes32 modelAgentId) view returns(bytes32[], (address,bytes32,uint256,uint256,uint128,uint128)[]) -func (_Marketplace *MarketplaceSession) GetActiveBidsByModelAgent(modelAgentId [32]byte) ([][32]byte, []Bid, error) { - return _Marketplace.Contract.GetActiveBidsByModelAgent(&_Marketplace.CallOpts, modelAgentId) -} - -// GetActiveBidsByModelAgent is a free data retrieval call binding the contract method 0x873d94d5. -// -// Solidity: function getActiveBidsByModelAgent(bytes32 modelAgentId) view returns(bytes32[], (address,bytes32,uint256,uint256,uint128,uint128)[]) -func (_Marketplace *MarketplaceCallerSession) GetActiveBidsByModelAgent(modelAgentId [32]byte) ([][32]byte, []Bid, error) { - return _Marketplace.Contract.GetActiveBidsByModelAgent(&_Marketplace.CallOpts, modelAgentId) -} - -// GetActiveBidsByProvider is a free data retrieval call binding the contract method 0x9fdaffd0. -// -// Solidity: function getActiveBidsByProvider(address provider) view returns(bytes32[], (address,bytes32,uint256,uint256,uint128,uint128)[]) -func (_Marketplace *MarketplaceCaller) GetActiveBidsByProvider(opts *bind.CallOpts, provider common.Address) ([][32]byte, []Bid, error) { - var out []interface{} - err := _Marketplace.contract.Call(opts, &out, "getActiveBidsByProvider", provider) - - if err != nil { - return *new([][32]byte), *new([]Bid), err - } - - out0 := *abi.ConvertType(out[0], new([][32]byte)).(*[][32]byte) - out1 := *abi.ConvertType(out[1], new([]Bid)).(*[]Bid) - - return out0, out1, err - -} - -// GetActiveBidsByProvider is a free data retrieval call binding the contract method 0x9fdaffd0. -// -// Solidity: function getActiveBidsByProvider(address provider) view returns(bytes32[], (address,bytes32,uint256,uint256,uint128,uint128)[]) -func (_Marketplace *MarketplaceSession) GetActiveBidsByProvider(provider common.Address) ([][32]byte, []Bid, error) { - return _Marketplace.Contract.GetActiveBidsByProvider(&_Marketplace.CallOpts, provider) -} - -// GetActiveBidsByProvider is a free data retrieval call binding the contract method 0x9fdaffd0. -// -// Solidity: function getActiveBidsByProvider(address provider) view returns(bytes32[], (address,bytes32,uint256,uint256,uint128,uint128)[]) -func (_Marketplace *MarketplaceCallerSession) GetActiveBidsByProvider(provider common.Address) ([][32]byte, []Bid, error) { - return _Marketplace.Contract.GetActiveBidsByProvider(&_Marketplace.CallOpts, provider) -} - -// GetActiveBidsRatingByModelAgent is a free data retrieval call binding the contract method 0xa69a4dd4. -// -// Solidity: function getActiveBidsRatingByModelAgent(bytes32 modelAgentId, uint256 offset, uint8 limit) view returns(bytes32[], (address,bytes32,uint256,uint256,uint128,uint128)[], ((int64,int64),(int64,int64),uint32,uint32,uint32)[]) -func (_Marketplace *MarketplaceCaller) GetActiveBidsRatingByModelAgent(opts *bind.CallOpts, modelAgentId [32]byte, offset *big.Int, limit uint8) ([][32]byte, []Bid, []ProviderModelStats, error) { - var out []interface{} - err := _Marketplace.contract.Call(opts, &out, "getActiveBidsRatingByModelAgent", modelAgentId, offset, limit) - - if err != nil { - return *new([][32]byte), *new([]Bid), *new([]ProviderModelStats), err - } - - out0 := *abi.ConvertType(out[0], new([][32]byte)).(*[][32]byte) - out1 := *abi.ConvertType(out[1], new([]Bid)).(*[]Bid) - out2 := *abi.ConvertType(out[2], new([]ProviderModelStats)).(*[]ProviderModelStats) - - return out0, out1, out2, err - -} - -// GetActiveBidsRatingByModelAgent is a free data retrieval call binding the contract method 0xa69a4dd4. -// -// Solidity: function getActiveBidsRatingByModelAgent(bytes32 modelAgentId, uint256 offset, uint8 limit) view returns(bytes32[], (address,bytes32,uint256,uint256,uint128,uint128)[], ((int64,int64),(int64,int64),uint32,uint32,uint32)[]) -func (_Marketplace *MarketplaceSession) GetActiveBidsRatingByModelAgent(modelAgentId [32]byte, offset *big.Int, limit uint8) ([][32]byte, []Bid, []ProviderModelStats, error) { - return _Marketplace.Contract.GetActiveBidsRatingByModelAgent(&_Marketplace.CallOpts, modelAgentId, offset, limit) -} - -// GetActiveBidsRatingByModelAgent is a free data retrieval call binding the contract method 0xa69a4dd4. -// -// Solidity: function getActiveBidsRatingByModelAgent(bytes32 modelAgentId, uint256 offset, uint8 limit) view returns(bytes32[], (address,bytes32,uint256,uint256,uint128,uint128)[], ((int64,int64),(int64,int64),uint32,uint32,uint32)[]) -func (_Marketplace *MarketplaceCallerSession) GetActiveBidsRatingByModelAgent(modelAgentId [32]byte, offset *big.Int, limit uint8) ([][32]byte, []Bid, []ProviderModelStats, error) { - return _Marketplace.Contract.GetActiveBidsRatingByModelAgent(&_Marketplace.CallOpts, modelAgentId, offset, limit) -} - -// GetBidsByModelAgent is a free data retrieval call binding the contract method 0xa87665ec. -// -// Solidity: function getBidsByModelAgent(bytes32 modelAgentId, uint256 offset, uint8 limit) view returns(bytes32[], (address,bytes32,uint256,uint256,uint128,uint128)[]) -func (_Marketplace *MarketplaceCaller) GetBidsByModelAgent(opts *bind.CallOpts, modelAgentId [32]byte, offset *big.Int, limit uint8) ([][32]byte, []Bid, error) { - var out []interface{} - err := _Marketplace.contract.Call(opts, &out, "getBidsByModelAgent", modelAgentId, offset, limit) - - if err != nil { - return *new([][32]byte), *new([]Bid), err - } - - out0 := *abi.ConvertType(out[0], new([][32]byte)).(*[][32]byte) - out1 := *abi.ConvertType(out[1], new([]Bid)).(*[]Bid) - - return out0, out1, err - -} - -// GetBidsByModelAgent is a free data retrieval call binding the contract method 0xa87665ec. -// -// Solidity: function getBidsByModelAgent(bytes32 modelAgentId, uint256 offset, uint8 limit) view returns(bytes32[], (address,bytes32,uint256,uint256,uint128,uint128)[]) -func (_Marketplace *MarketplaceSession) GetBidsByModelAgent(modelAgentId [32]byte, offset *big.Int, limit uint8) ([][32]byte, []Bid, error) { - return _Marketplace.Contract.GetBidsByModelAgent(&_Marketplace.CallOpts, modelAgentId, offset, limit) -} - -// GetBidsByModelAgent is a free data retrieval call binding the contract method 0xa87665ec. -// -// Solidity: function getBidsByModelAgent(bytes32 modelAgentId, uint256 offset, uint8 limit) view returns(bytes32[], (address,bytes32,uint256,uint256,uint128,uint128)[]) -func (_Marketplace *MarketplaceCallerSession) GetBidsByModelAgent(modelAgentId [32]byte, offset *big.Int, limit uint8) ([][32]byte, []Bid, error) { - return _Marketplace.Contract.GetBidsByModelAgent(&_Marketplace.CallOpts, modelAgentId, offset, limit) -} - -// GetBidsByProvider is a free data retrieval call binding the contract method 0x2f817685. -// -// Solidity: function getBidsByProvider(address provider, uint256 offset, uint8 limit) view returns(bytes32[], (address,bytes32,uint256,uint256,uint128,uint128)[]) -func (_Marketplace *MarketplaceCaller) GetBidsByProvider(opts *bind.CallOpts, provider common.Address, offset *big.Int, limit uint8) ([][32]byte, []Bid, error) { - var out []interface{} - err := _Marketplace.contract.Call(opts, &out, "getBidsByProvider", provider, offset, limit) - - if err != nil { - return *new([][32]byte), *new([]Bid), err - } - - out0 := *abi.ConvertType(out[0], new([][32]byte)).(*[][32]byte) - out1 := *abi.ConvertType(out[1], new([]Bid)).(*[]Bid) - - return out0, out1, err - -} - -// GetBidsByProvider is a free data retrieval call binding the contract method 0x2f817685. -// -// Solidity: function getBidsByProvider(address provider, uint256 offset, uint8 limit) view returns(bytes32[], (address,bytes32,uint256,uint256,uint128,uint128)[]) -func (_Marketplace *MarketplaceSession) GetBidsByProvider(provider common.Address, offset *big.Int, limit uint8) ([][32]byte, []Bid, error) { - return _Marketplace.Contract.GetBidsByProvider(&_Marketplace.CallOpts, provider, offset, limit) -} - -// GetBidsByProvider is a free data retrieval call binding the contract method 0x2f817685. -// -// Solidity: function getBidsByProvider(address provider, uint256 offset, uint8 limit) view returns(bytes32[], (address,bytes32,uint256,uint256,uint128,uint128)[]) -func (_Marketplace *MarketplaceCallerSession) GetBidsByProvider(provider common.Address, offset *big.Int, limit uint8) ([][32]byte, []Bid, error) { - return _Marketplace.Contract.GetBidsByProvider(&_Marketplace.CallOpts, provider, offset, limit) -} - -// GetModelStats is a free data retrieval call binding the contract method 0xce535723. -// -// Solidity: function getModelStats(bytes32 modelID) view returns(((int64,int64),(int64,int64),(int64,int64),uint32)) -func (_Marketplace *MarketplaceCaller) GetModelStats(opts *bind.CallOpts, modelID [32]byte) (ModelStats, error) { - var out []interface{} - err := _Marketplace.contract.Call(opts, &out, "getModelStats", modelID) - - if err != nil { - return *new(ModelStats), err - } - - out0 := *abi.ConvertType(out[0], new(ModelStats)).(*ModelStats) - - return out0, err - -} - -// GetModelStats is a free data retrieval call binding the contract method 0xce535723. -// -// Solidity: function getModelStats(bytes32 modelID) view returns(((int64,int64),(int64,int64),(int64,int64),uint32)) -func (_Marketplace *MarketplaceSession) GetModelStats(modelID [32]byte) (ModelStats, error) { - return _Marketplace.Contract.GetModelStats(&_Marketplace.CallOpts, modelID) -} - -// GetModelStats is a free data retrieval call binding the contract method 0xce535723. -// -// Solidity: function getModelStats(bytes32 modelID) view returns(((int64,int64),(int64,int64),(int64,int64),uint32)) -func (_Marketplace *MarketplaceCallerSession) GetModelStats(modelID [32]byte) (ModelStats, error) { - return _Marketplace.Contract.GetModelStats(&_Marketplace.CallOpts, modelID) -} - -// DeleteModelAgentBid is a paid mutator transaction binding the contract method 0x42856b75. -// -// Solidity: function deleteModelAgentBid(bytes32 bidId) returns() -func (_Marketplace *MarketplaceTransactor) DeleteModelAgentBid(opts *bind.TransactOpts, bidId [32]byte) (*types.Transaction, error) { - return _Marketplace.contract.Transact(opts, "deleteModelAgentBid", bidId) -} - -// DeleteModelAgentBid is a paid mutator transaction binding the contract method 0x42856b75. -// -// Solidity: function deleteModelAgentBid(bytes32 bidId) returns() -func (_Marketplace *MarketplaceSession) DeleteModelAgentBid(bidId [32]byte) (*types.Transaction, error) { - return _Marketplace.Contract.DeleteModelAgentBid(&_Marketplace.TransactOpts, bidId) -} - -// DeleteModelAgentBid is a paid mutator transaction binding the contract method 0x42856b75. -// -// Solidity: function deleteModelAgentBid(bytes32 bidId) returns() -func (_Marketplace *MarketplaceTransactorSession) DeleteModelAgentBid(bidId [32]byte) (*types.Transaction, error) { - return _Marketplace.Contract.DeleteModelAgentBid(&_Marketplace.TransactOpts, bidId) -} - -// PostModelBid is a paid mutator transaction binding the contract method 0xede96bb1. -// -// Solidity: function postModelBid(address providerAddr, bytes32 modelId, uint256 pricePerSecond) returns(bytes32 bidId) -func (_Marketplace *MarketplaceTransactor) PostModelBid(opts *bind.TransactOpts, providerAddr common.Address, modelId [32]byte, pricePerSecond *big.Int) (*types.Transaction, error) { - return _Marketplace.contract.Transact(opts, "postModelBid", providerAddr, modelId, pricePerSecond) -} - -// PostModelBid is a paid mutator transaction binding the contract method 0xede96bb1. -// -// Solidity: function postModelBid(address providerAddr, bytes32 modelId, uint256 pricePerSecond) returns(bytes32 bidId) -func (_Marketplace *MarketplaceSession) PostModelBid(providerAddr common.Address, modelId [32]byte, pricePerSecond *big.Int) (*types.Transaction, error) { - return _Marketplace.Contract.PostModelBid(&_Marketplace.TransactOpts, providerAddr, modelId, pricePerSecond) -} - -// PostModelBid is a paid mutator transaction binding the contract method 0xede96bb1. -// -// Solidity: function postModelBid(address providerAddr, bytes32 modelId, uint256 pricePerSecond) returns(bytes32 bidId) -func (_Marketplace *MarketplaceTransactorSession) PostModelBid(providerAddr common.Address, modelId [32]byte, pricePerSecond *big.Int) (*types.Transaction, error) { - return _Marketplace.Contract.PostModelBid(&_Marketplace.TransactOpts, providerAddr, modelId, pricePerSecond) -} - -// SetBidFee is a paid mutator transaction binding the contract method 0x013869bf. -// -// Solidity: function setBidFee(uint256 _bidFee) returns() -func (_Marketplace *MarketplaceTransactor) SetBidFee(opts *bind.TransactOpts, _bidFee *big.Int) (*types.Transaction, error) { - return _Marketplace.contract.Transact(opts, "setBidFee", _bidFee) -} - -// SetBidFee is a paid mutator transaction binding the contract method 0x013869bf. -// -// Solidity: function setBidFee(uint256 _bidFee) returns() -func (_Marketplace *MarketplaceSession) SetBidFee(_bidFee *big.Int) (*types.Transaction, error) { - return _Marketplace.Contract.SetBidFee(&_Marketplace.TransactOpts, _bidFee) -} - -// SetBidFee is a paid mutator transaction binding the contract method 0x013869bf. -// -// Solidity: function setBidFee(uint256 _bidFee) returns() -func (_Marketplace *MarketplaceTransactorSession) SetBidFee(_bidFee *big.Int) (*types.Transaction, error) { - return _Marketplace.Contract.SetBidFee(&_Marketplace.TransactOpts, _bidFee) -} - -// Withdraw is a paid mutator transaction binding the contract method 0xf3fef3a3. -// -// Solidity: function withdraw(address addr, uint256 amount) returns() -func (_Marketplace *MarketplaceTransactor) Withdraw(opts *bind.TransactOpts, addr common.Address, amount *big.Int) (*types.Transaction, error) { - return _Marketplace.contract.Transact(opts, "withdraw", addr, amount) -} - -// Withdraw is a paid mutator transaction binding the contract method 0xf3fef3a3. -// -// Solidity: function withdraw(address addr, uint256 amount) returns() -func (_Marketplace *MarketplaceSession) Withdraw(addr common.Address, amount *big.Int) (*types.Transaction, error) { - return _Marketplace.Contract.Withdraw(&_Marketplace.TransactOpts, addr, amount) -} - -// Withdraw is a paid mutator transaction binding the contract method 0xf3fef3a3. -// -// Solidity: function withdraw(address addr, uint256 amount) returns() -func (_Marketplace *MarketplaceTransactorSession) Withdraw(addr common.Address, amount *big.Int) (*types.Transaction, error) { - return _Marketplace.Contract.Withdraw(&_Marketplace.TransactOpts, addr, amount) -} - -// MarketplaceBidDeletedIterator is returned from FilterBidDeleted and is used to iterate over the raw logs and unpacked data for BidDeleted events raised by the Marketplace contract. -type MarketplaceBidDeletedIterator struct { - Event *MarketplaceBidDeleted // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *MarketplaceBidDeletedIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(MarketplaceBidDeleted) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(MarketplaceBidDeleted) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *MarketplaceBidDeletedIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *MarketplaceBidDeletedIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// MarketplaceBidDeleted represents a BidDeleted event raised by the Marketplace contract. -type MarketplaceBidDeleted struct { - Provider common.Address - ModelAgentId [32]byte - Nonce *big.Int - Raw types.Log // Blockchain specific contextual infos -} - -// FilterBidDeleted is a free log retrieval operation binding the contract event 0x096f970f504563bca8ac4419b4299946965221e396c34aea149ac84947b9242f. -// -// Solidity: event BidDeleted(address indexed provider, bytes32 indexed modelAgentId, uint256 nonce) -func (_Marketplace *MarketplaceFilterer) FilterBidDeleted(opts *bind.FilterOpts, provider []common.Address, modelAgentId [][32]byte) (*MarketplaceBidDeletedIterator, error) { - - var providerRule []interface{} - for _, providerItem := range provider { - providerRule = append(providerRule, providerItem) - } - var modelAgentIdRule []interface{} - for _, modelAgentIdItem := range modelAgentId { - modelAgentIdRule = append(modelAgentIdRule, modelAgentIdItem) - } - - logs, sub, err := _Marketplace.contract.FilterLogs(opts, "BidDeleted", providerRule, modelAgentIdRule) - if err != nil { - return nil, err - } - return &MarketplaceBidDeletedIterator{contract: _Marketplace.contract, event: "BidDeleted", logs: logs, sub: sub}, nil -} - -// WatchBidDeleted is a free log subscription operation binding the contract event 0x096f970f504563bca8ac4419b4299946965221e396c34aea149ac84947b9242f. -// -// Solidity: event BidDeleted(address indexed provider, bytes32 indexed modelAgentId, uint256 nonce) -func (_Marketplace *MarketplaceFilterer) WatchBidDeleted(opts *bind.WatchOpts, sink chan<- *MarketplaceBidDeleted, provider []common.Address, modelAgentId [][32]byte) (event.Subscription, error) { - - var providerRule []interface{} - for _, providerItem := range provider { - providerRule = append(providerRule, providerItem) - } - var modelAgentIdRule []interface{} - for _, modelAgentIdItem := range modelAgentId { - modelAgentIdRule = append(modelAgentIdRule, modelAgentIdItem) - } - - logs, sub, err := _Marketplace.contract.WatchLogs(opts, "BidDeleted", providerRule, modelAgentIdRule) - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(MarketplaceBidDeleted) - if err := _Marketplace.contract.UnpackLog(event, "BidDeleted", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// ParseBidDeleted is a log parse operation binding the contract event 0x096f970f504563bca8ac4419b4299946965221e396c34aea149ac84947b9242f. -// -// Solidity: event BidDeleted(address indexed provider, bytes32 indexed modelAgentId, uint256 nonce) -func (_Marketplace *MarketplaceFilterer) ParseBidDeleted(log types.Log) (*MarketplaceBidDeleted, error) { - event := new(MarketplaceBidDeleted) - if err := _Marketplace.contract.UnpackLog(event, "BidDeleted", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -// MarketplaceBidPostedIterator is returned from FilterBidPosted and is used to iterate over the raw logs and unpacked data for BidPosted events raised by the Marketplace contract. -type MarketplaceBidPostedIterator struct { - Event *MarketplaceBidPosted // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *MarketplaceBidPostedIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(MarketplaceBidPosted) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(MarketplaceBidPosted) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *MarketplaceBidPostedIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *MarketplaceBidPostedIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// MarketplaceBidPosted represents a BidPosted event raised by the Marketplace contract. -type MarketplaceBidPosted struct { - Provider common.Address - ModelAgentId [32]byte - Nonce *big.Int - Raw types.Log // Blockchain specific contextual infos -} - -// FilterBidPosted is a free log retrieval operation binding the contract event 0xd138adff73af2621d26114cd9ee4f20dcd39ed78f9e0004215ed49aa22753ebe. -// -// Solidity: event BidPosted(address indexed provider, bytes32 indexed modelAgentId, uint256 nonce) -func (_Marketplace *MarketplaceFilterer) FilterBidPosted(opts *bind.FilterOpts, provider []common.Address, modelAgentId [][32]byte) (*MarketplaceBidPostedIterator, error) { - - var providerRule []interface{} - for _, providerItem := range provider { - providerRule = append(providerRule, providerItem) - } - var modelAgentIdRule []interface{} - for _, modelAgentIdItem := range modelAgentId { - modelAgentIdRule = append(modelAgentIdRule, modelAgentIdItem) - } - - logs, sub, err := _Marketplace.contract.FilterLogs(opts, "BidPosted", providerRule, modelAgentIdRule) - if err != nil { - return nil, err - } - return &MarketplaceBidPostedIterator{contract: _Marketplace.contract, event: "BidPosted", logs: logs, sub: sub}, nil -} - -// WatchBidPosted is a free log subscription operation binding the contract event 0xd138adff73af2621d26114cd9ee4f20dcd39ed78f9e0004215ed49aa22753ebe. -// -// Solidity: event BidPosted(address indexed provider, bytes32 indexed modelAgentId, uint256 nonce) -func (_Marketplace *MarketplaceFilterer) WatchBidPosted(opts *bind.WatchOpts, sink chan<- *MarketplaceBidPosted, provider []common.Address, modelAgentId [][32]byte) (event.Subscription, error) { - - var providerRule []interface{} - for _, providerItem := range provider { - providerRule = append(providerRule, providerItem) - } - var modelAgentIdRule []interface{} - for _, modelAgentIdItem := range modelAgentId { - modelAgentIdRule = append(modelAgentIdRule, modelAgentIdItem) - } - - logs, sub, err := _Marketplace.contract.WatchLogs(opts, "BidPosted", providerRule, modelAgentIdRule) - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(MarketplaceBidPosted) - if err := _Marketplace.contract.UnpackLog(event, "BidPosted", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// ParseBidPosted is a log parse operation binding the contract event 0xd138adff73af2621d26114cd9ee4f20dcd39ed78f9e0004215ed49aa22753ebe. -// -// Solidity: event BidPosted(address indexed provider, bytes32 indexed modelAgentId, uint256 nonce) -func (_Marketplace *MarketplaceFilterer) ParseBidPosted(log types.Log) (*MarketplaceBidPosted, error) { - event := new(MarketplaceBidPosted) - if err := _Marketplace.contract.UnpackLog(event, "BidPosted", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -// MarketplaceFeeUpdatedIterator is returned from FilterFeeUpdated and is used to iterate over the raw logs and unpacked data for FeeUpdated events raised by the Marketplace contract. -type MarketplaceFeeUpdatedIterator struct { - Event *MarketplaceFeeUpdated // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *MarketplaceFeeUpdatedIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(MarketplaceFeeUpdated) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(MarketplaceFeeUpdated) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *MarketplaceFeeUpdatedIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *MarketplaceFeeUpdatedIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// MarketplaceFeeUpdated represents a FeeUpdated event raised by the Marketplace contract. -type MarketplaceFeeUpdated struct { - BidFee *big.Int - Raw types.Log // Blockchain specific contextual infos -} - -// FilterFeeUpdated is a free log retrieval operation binding the contract event 0x8c4d35e54a3f2ef1134138fd8ea3daee6a3c89e10d2665996babdf70261e2c76. -// -// Solidity: event FeeUpdated(uint256 bidFee) -func (_Marketplace *MarketplaceFilterer) FilterFeeUpdated(opts *bind.FilterOpts) (*MarketplaceFeeUpdatedIterator, error) { - - logs, sub, err := _Marketplace.contract.FilterLogs(opts, "FeeUpdated") - if err != nil { - return nil, err - } - return &MarketplaceFeeUpdatedIterator{contract: _Marketplace.contract, event: "FeeUpdated", logs: logs, sub: sub}, nil -} - -// WatchFeeUpdated is a free log subscription operation binding the contract event 0x8c4d35e54a3f2ef1134138fd8ea3daee6a3c89e10d2665996babdf70261e2c76. -// -// Solidity: event FeeUpdated(uint256 bidFee) -func (_Marketplace *MarketplaceFilterer) WatchFeeUpdated(opts *bind.WatchOpts, sink chan<- *MarketplaceFeeUpdated) (event.Subscription, error) { - - logs, sub, err := _Marketplace.contract.WatchLogs(opts, "FeeUpdated") - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(MarketplaceFeeUpdated) - if err := _Marketplace.contract.UnpackLog(event, "FeeUpdated", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// ParseFeeUpdated is a log parse operation binding the contract event 0x8c4d35e54a3f2ef1134138fd8ea3daee6a3c89e10d2665996babdf70261e2c76. -// -// Solidity: event FeeUpdated(uint256 bidFee) -func (_Marketplace *MarketplaceFilterer) ParseFeeUpdated(log types.Log) (*MarketplaceFeeUpdated, error) { - event := new(MarketplaceFeeUpdated) - if err := _Marketplace.contract.UnpackLog(event, "FeeUpdated", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} diff --git a/proxy-router/contracts/modelregistry/ModelRegistry.go b/proxy-router/contracts/modelregistry/ModelRegistry.go deleted file mode 100644 index be24751f..00000000 --- a/proxy-router/contracts/modelregistry/ModelRegistry.go +++ /dev/null @@ -1,1025 +0,0 @@ -// Code generated - DO NOT EDIT. -// This file is a generated binding and any manual changes will be lost. - -package modelregistry - -import ( - "errors" - "math/big" - "strings" - - ethereum "github.com/ethereum/go-ethereum" - "github.com/ethereum/go-ethereum/accounts/abi" - "github.com/ethereum/go-ethereum/accounts/abi/bind" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/event" -) - -// Reference imports to suppress errors if they are not otherwise used. -var ( - _ = errors.New - _ = big.NewInt - _ = strings.NewReader - _ = ethereum.NotFound - _ = bind.Bind - _ = common.Big1 - _ = types.BloomLookup - _ = event.NewSubscription - _ = abi.ConvertType -) - -// LibSDSD is an auto generated low-level Go binding around an user-defined struct. -type LibSDSD struct { - Mean int64 - SqSum int64 -} - -// Model is an auto generated low-level Go binding around an user-defined struct. -type Model struct { - IpfsCID [32]byte - Fee *big.Int - Stake *big.Int - Owner common.Address - Name string - Tags []string - CreatedAt *big.Int - IsDeleted bool -} - -// ModelStats is an auto generated low-level Go binding around an user-defined struct. -type ModelStats struct { - TpsScaled1000 LibSDSD - TtftMs LibSDSD - TotalDuration LibSDSD - Count uint32 -} - -// ModelRegistryMetaData contains all meta data concerning the ModelRegistry contract. -var ModelRegistryMetaData = &bind.MetaData{ - ABI: "[{\"inputs\":[],\"name\":\"KeyExists\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"KeyNotFound\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ModelHasActiveBids\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ModelNotFound\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_user\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_contractOwner\",\"type\":\"address\"}],\"name\":\"NotContractOwner\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NotSenderOrOwner\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"StakeTooLow\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ZeroKey\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"modelId\",\"type\":\"bytes32\"}],\"name\":\"ModelDeregistered\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newStake\",\"type\":\"uint256\"}],\"name\":\"ModelMinStakeUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"modelId\",\"type\":\"bytes32\"}],\"name\":\"ModelRegisteredUpdated\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"id\",\"type\":\"bytes32\"}],\"name\":\"modelDeregister\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"id\",\"type\":\"bytes32\"}],\"name\":\"modelExists\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"modelGetAll\",\"outputs\":[{\"internalType\":\"bytes32[]\",\"name\":\"\",\"type\":\"bytes32[]\"},{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"ipfsCID\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"fee\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"stake\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"string\",\"name\":\"name\",\"type\":\"string\"},{\"internalType\":\"string[]\",\"name\":\"tags\",\"type\":\"string[]\"},{\"internalType\":\"uint128\",\"name\":\"createdAt\",\"type\":\"uint128\"},{\"internalType\":\"bool\",\"name\":\"isDeleted\",\"type\":\"bool\"}],\"internalType\":\"structModel[]\",\"name\":\"\",\"type\":\"tuple[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"index\",\"type\":\"uint256\"}],\"name\":\"modelGetByIndex\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"modelId\",\"type\":\"bytes32\"},{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"ipfsCID\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"fee\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"stake\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"string\",\"name\":\"name\",\"type\":\"string\"},{\"internalType\":\"string[]\",\"name\":\"tags\",\"type\":\"string[]\"},{\"internalType\":\"uint128\",\"name\":\"createdAt\",\"type\":\"uint128\"},{\"internalType\":\"bool\",\"name\":\"isDeleted\",\"type\":\"bool\"}],\"internalType\":\"structModel\",\"name\":\"model\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"modelGetCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"count\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"modelGetIds\",\"outputs\":[{\"internalType\":\"bytes32[]\",\"name\":\"\",\"type\":\"bytes32[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"id\",\"type\":\"bytes32\"}],\"name\":\"modelMap\",\"outputs\":[{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"ipfsCID\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"fee\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"stake\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"string\",\"name\":\"name\",\"type\":\"string\"},{\"internalType\":\"string[]\",\"name\":\"tags\",\"type\":\"string[]\"},{\"internalType\":\"uint128\",\"name\":\"createdAt\",\"type\":\"uint128\"},{\"internalType\":\"bool\",\"name\":\"isDeleted\",\"type\":\"bool\"}],\"internalType\":\"structModel\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"modelMinStake\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"modelId\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"ipfsCID\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"fee\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"addStake\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"string\",\"name\":\"name\",\"type\":\"string\"},{\"internalType\":\"string[]\",\"name\":\"tags\",\"type\":\"string[]\"}],\"name\":\"modelRegister\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"id\",\"type\":\"bytes32\"}],\"name\":\"modelResetStats\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_minStake\",\"type\":\"uint256\"}],\"name\":\"modelSetMinStake\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"id\",\"type\":\"bytes32\"}],\"name\":\"modelStats\",\"outputs\":[{\"components\":[{\"components\":[{\"internalType\":\"int64\",\"name\":\"mean\",\"type\":\"int64\"},{\"internalType\":\"int64\",\"name\":\"sqSum\",\"type\":\"int64\"}],\"internalType\":\"structLibSD.SD\",\"name\":\"tpsScaled1000\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"int64\",\"name\":\"mean\",\"type\":\"int64\"},{\"internalType\":\"int64\",\"name\":\"sqSum\",\"type\":\"int64\"}],\"internalType\":\"structLibSD.SD\",\"name\":\"ttftMs\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"int64\",\"name\":\"mean\",\"type\":\"int64\"},{\"internalType\":\"int64\",\"name\":\"sqSum\",\"type\":\"int64\"}],\"internalType\":\"structLibSD.SD\",\"name\":\"totalDuration\",\"type\":\"tuple\"},{\"internalType\":\"uint32\",\"name\":\"count\",\"type\":\"uint32\"}],\"internalType\":\"structModelStats\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"index\",\"type\":\"uint256\"}],\"name\":\"models\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]", -} - -// ModelRegistryABI is the input ABI used to generate the binding from. -// Deprecated: Use ModelRegistryMetaData.ABI instead. -var ModelRegistryABI = ModelRegistryMetaData.ABI - -// ModelRegistry is an auto generated Go binding around an Ethereum contract. -type ModelRegistry struct { - ModelRegistryCaller // Read-only binding to the contract - ModelRegistryTransactor // Write-only binding to the contract - ModelRegistryFilterer // Log filterer for contract events -} - -// ModelRegistryCaller is an auto generated read-only Go binding around an Ethereum contract. -type ModelRegistryCaller struct { - contract *bind.BoundContract // Generic contract wrapper for the low level calls -} - -// ModelRegistryTransactor is an auto generated write-only Go binding around an Ethereum contract. -type ModelRegistryTransactor struct { - contract *bind.BoundContract // Generic contract wrapper for the low level calls -} - -// ModelRegistryFilterer is an auto generated log filtering Go binding around an Ethereum contract events. -type ModelRegistryFilterer struct { - contract *bind.BoundContract // Generic contract wrapper for the low level calls -} - -// ModelRegistrySession is an auto generated Go binding around an Ethereum contract, -// with pre-set call and transact options. -type ModelRegistrySession struct { - Contract *ModelRegistry // Generic contract binding to set the session for - CallOpts bind.CallOpts // Call options to use throughout this session - TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session -} - -// ModelRegistryCallerSession is an auto generated read-only Go binding around an Ethereum contract, -// with pre-set call options. -type ModelRegistryCallerSession struct { - Contract *ModelRegistryCaller // Generic contract caller binding to set the session for - CallOpts bind.CallOpts // Call options to use throughout this session -} - -// ModelRegistryTransactorSession is an auto generated write-only Go binding around an Ethereum contract, -// with pre-set transact options. -type ModelRegistryTransactorSession struct { - Contract *ModelRegistryTransactor // Generic contract transactor binding to set the session for - TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session -} - -// ModelRegistryRaw is an auto generated low-level Go binding around an Ethereum contract. -type ModelRegistryRaw struct { - Contract *ModelRegistry // Generic contract binding to access the raw methods on -} - -// ModelRegistryCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. -type ModelRegistryCallerRaw struct { - Contract *ModelRegistryCaller // Generic read-only contract binding to access the raw methods on -} - -// ModelRegistryTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. -type ModelRegistryTransactorRaw struct { - Contract *ModelRegistryTransactor // Generic write-only contract binding to access the raw methods on -} - -// NewModelRegistry creates a new instance of ModelRegistry, bound to a specific deployed contract. -func NewModelRegistry(address common.Address, backend bind.ContractBackend) (*ModelRegistry, error) { - contract, err := bindModelRegistry(address, backend, backend, backend) - if err != nil { - return nil, err - } - return &ModelRegistry{ModelRegistryCaller: ModelRegistryCaller{contract: contract}, ModelRegistryTransactor: ModelRegistryTransactor{contract: contract}, ModelRegistryFilterer: ModelRegistryFilterer{contract: contract}}, nil -} - -// NewModelRegistryCaller creates a new read-only instance of ModelRegistry, bound to a specific deployed contract. -func NewModelRegistryCaller(address common.Address, caller bind.ContractCaller) (*ModelRegistryCaller, error) { - contract, err := bindModelRegistry(address, caller, nil, nil) - if err != nil { - return nil, err - } - return &ModelRegistryCaller{contract: contract}, nil -} - -// NewModelRegistryTransactor creates a new write-only instance of ModelRegistry, bound to a specific deployed contract. -func NewModelRegistryTransactor(address common.Address, transactor bind.ContractTransactor) (*ModelRegistryTransactor, error) { - contract, err := bindModelRegistry(address, nil, transactor, nil) - if err != nil { - return nil, err - } - return &ModelRegistryTransactor{contract: contract}, nil -} - -// NewModelRegistryFilterer creates a new log filterer instance of ModelRegistry, bound to a specific deployed contract. -func NewModelRegistryFilterer(address common.Address, filterer bind.ContractFilterer) (*ModelRegistryFilterer, error) { - contract, err := bindModelRegistry(address, nil, nil, filterer) - if err != nil { - return nil, err - } - return &ModelRegistryFilterer{contract: contract}, nil -} - -// bindModelRegistry binds a generic wrapper to an already deployed contract. -func bindModelRegistry(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { - parsed, err := ModelRegistryMetaData.GetAbi() - if err != nil { - return nil, err - } - return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil -} - -// Call invokes the (constant) contract method with params as input values and -// sets the output to result. The result type might be a single field for simple -// returns, a slice of interfaces for anonymous returns and a struct for named -// returns. -func (_ModelRegistry *ModelRegistryRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { - return _ModelRegistry.Contract.ModelRegistryCaller.contract.Call(opts, result, method, params...) -} - -// Transfer initiates a plain transaction to move funds to the contract, calling -// its default method if one is available. -func (_ModelRegistry *ModelRegistryRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { - return _ModelRegistry.Contract.ModelRegistryTransactor.contract.Transfer(opts) -} - -// Transact invokes the (paid) contract method with params as input values. -func (_ModelRegistry *ModelRegistryRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { - return _ModelRegistry.Contract.ModelRegistryTransactor.contract.Transact(opts, method, params...) -} - -// Call invokes the (constant) contract method with params as input values and -// sets the output to result. The result type might be a single field for simple -// returns, a slice of interfaces for anonymous returns and a struct for named -// returns. -func (_ModelRegistry *ModelRegistryCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { - return _ModelRegistry.Contract.contract.Call(opts, result, method, params...) -} - -// Transfer initiates a plain transaction to move funds to the contract, calling -// its default method if one is available. -func (_ModelRegistry *ModelRegistryTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { - return _ModelRegistry.Contract.contract.Transfer(opts) -} - -// Transact invokes the (paid) contract method with params as input values. -func (_ModelRegistry *ModelRegistryTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { - return _ModelRegistry.Contract.contract.Transact(opts, method, params...) -} - -// ModelExists is a free data retrieval call binding the contract method 0x022964d2. -// -// Solidity: function modelExists(bytes32 id) view returns(bool) -func (_ModelRegistry *ModelRegistryCaller) ModelExists(opts *bind.CallOpts, id [32]byte) (bool, error) { - var out []interface{} - err := _ModelRegistry.contract.Call(opts, &out, "modelExists", id) - - if err != nil { - return *new(bool), err - } - - out0 := *abi.ConvertType(out[0], new(bool)).(*bool) - - return out0, err - -} - -// ModelExists is a free data retrieval call binding the contract method 0x022964d2. -// -// Solidity: function modelExists(bytes32 id) view returns(bool) -func (_ModelRegistry *ModelRegistrySession) ModelExists(id [32]byte) (bool, error) { - return _ModelRegistry.Contract.ModelExists(&_ModelRegistry.CallOpts, id) -} - -// ModelExists is a free data retrieval call binding the contract method 0x022964d2. -// -// Solidity: function modelExists(bytes32 id) view returns(bool) -func (_ModelRegistry *ModelRegistryCallerSession) ModelExists(id [32]byte) (bool, error) { - return _ModelRegistry.Contract.ModelExists(&_ModelRegistry.CallOpts, id) -} - -// ModelGetAll is a free data retrieval call binding the contract method 0xb889c67b. -// -// Solidity: function modelGetAll() view returns(bytes32[], (bytes32,uint256,uint256,address,string,string[],uint128,bool)[]) -func (_ModelRegistry *ModelRegistryCaller) ModelGetAll(opts *bind.CallOpts) ([][32]byte, []Model, error) { - var out []interface{} - err := _ModelRegistry.contract.Call(opts, &out, "modelGetAll") - - if err != nil { - return *new([][32]byte), *new([]Model), err - } - - out0 := *abi.ConvertType(out[0], new([][32]byte)).(*[][32]byte) - out1 := *abi.ConvertType(out[1], new([]Model)).(*[]Model) - - return out0, out1, err - -} - -// ModelGetAll is a free data retrieval call binding the contract method 0xb889c67b. -// -// Solidity: function modelGetAll() view returns(bytes32[], (bytes32,uint256,uint256,address,string,string[],uint128,bool)[]) -func (_ModelRegistry *ModelRegistrySession) ModelGetAll() ([][32]byte, []Model, error) { - return _ModelRegistry.Contract.ModelGetAll(&_ModelRegistry.CallOpts) -} - -// ModelGetAll is a free data retrieval call binding the contract method 0xb889c67b. -// -// Solidity: function modelGetAll() view returns(bytes32[], (bytes32,uint256,uint256,address,string,string[],uint128,bool)[]) -func (_ModelRegistry *ModelRegistryCallerSession) ModelGetAll() ([][32]byte, []Model, error) { - return _ModelRegistry.Contract.ModelGetAll(&_ModelRegistry.CallOpts) -} - -// ModelGetByIndex is a free data retrieval call binding the contract method 0x43119765. -// -// Solidity: function modelGetByIndex(uint256 index) view returns(bytes32 modelId, (bytes32,uint256,uint256,address,string,string[],uint128,bool) model) -func (_ModelRegistry *ModelRegistryCaller) ModelGetByIndex(opts *bind.CallOpts, index *big.Int) (struct { - ModelId [32]byte - Model Model -}, error) { - var out []interface{} - err := _ModelRegistry.contract.Call(opts, &out, "modelGetByIndex", index) - - outstruct := new(struct { - ModelId [32]byte - Model Model - }) - if err != nil { - return *outstruct, err - } - - outstruct.ModelId = *abi.ConvertType(out[0], new([32]byte)).(*[32]byte) - outstruct.Model = *abi.ConvertType(out[1], new(Model)).(*Model) - - return *outstruct, err - -} - -// ModelGetByIndex is a free data retrieval call binding the contract method 0x43119765. -// -// Solidity: function modelGetByIndex(uint256 index) view returns(bytes32 modelId, (bytes32,uint256,uint256,address,string,string[],uint128,bool) model) -func (_ModelRegistry *ModelRegistrySession) ModelGetByIndex(index *big.Int) (struct { - ModelId [32]byte - Model Model -}, error) { - return _ModelRegistry.Contract.ModelGetByIndex(&_ModelRegistry.CallOpts, index) -} - -// ModelGetByIndex is a free data retrieval call binding the contract method 0x43119765. -// -// Solidity: function modelGetByIndex(uint256 index) view returns(bytes32 modelId, (bytes32,uint256,uint256,address,string,string[],uint128,bool) model) -func (_ModelRegistry *ModelRegistryCallerSession) ModelGetByIndex(index *big.Int) (struct { - ModelId [32]byte - Model Model -}, error) { - return _ModelRegistry.Contract.ModelGetByIndex(&_ModelRegistry.CallOpts, index) -} - -// ModelGetCount is a free data retrieval call binding the contract method 0x807b8975. -// -// Solidity: function modelGetCount() view returns(uint256 count) -func (_ModelRegistry *ModelRegistryCaller) ModelGetCount(opts *bind.CallOpts) (*big.Int, error) { - var out []interface{} - err := _ModelRegistry.contract.Call(opts, &out, "modelGetCount") - - if err != nil { - return *new(*big.Int), err - } - - out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - - return out0, err - -} - -// ModelGetCount is a free data retrieval call binding the contract method 0x807b8975. -// -// Solidity: function modelGetCount() view returns(uint256 count) -func (_ModelRegistry *ModelRegistrySession) ModelGetCount() (*big.Int, error) { - return _ModelRegistry.Contract.ModelGetCount(&_ModelRegistry.CallOpts) -} - -// ModelGetCount is a free data retrieval call binding the contract method 0x807b8975. -// -// Solidity: function modelGetCount() view returns(uint256 count) -func (_ModelRegistry *ModelRegistryCallerSession) ModelGetCount() (*big.Int, error) { - return _ModelRegistry.Contract.ModelGetCount(&_ModelRegistry.CallOpts) -} - -// ModelGetIds is a free data retrieval call binding the contract method 0x9f9877fc. -// -// Solidity: function modelGetIds() view returns(bytes32[]) -func (_ModelRegistry *ModelRegistryCaller) ModelGetIds(opts *bind.CallOpts) ([][32]byte, error) { - var out []interface{} - err := _ModelRegistry.contract.Call(opts, &out, "modelGetIds") - - if err != nil { - return *new([][32]byte), err - } - - out0 := *abi.ConvertType(out[0], new([][32]byte)).(*[][32]byte) - - return out0, err - -} - -// ModelGetIds is a free data retrieval call binding the contract method 0x9f9877fc. -// -// Solidity: function modelGetIds() view returns(bytes32[]) -func (_ModelRegistry *ModelRegistrySession) ModelGetIds() ([][32]byte, error) { - return _ModelRegistry.Contract.ModelGetIds(&_ModelRegistry.CallOpts) -} - -// ModelGetIds is a free data retrieval call binding the contract method 0x9f9877fc. -// -// Solidity: function modelGetIds() view returns(bytes32[]) -func (_ModelRegistry *ModelRegistryCallerSession) ModelGetIds() ([][32]byte, error) { - return _ModelRegistry.Contract.ModelGetIds(&_ModelRegistry.CallOpts) -} - -// ModelMap is a free data retrieval call binding the contract method 0x6e5cbd85. -// -// Solidity: function modelMap(bytes32 id) view returns((bytes32,uint256,uint256,address,string,string[],uint128,bool)) -func (_ModelRegistry *ModelRegistryCaller) ModelMap(opts *bind.CallOpts, id [32]byte) (Model, error) { - var out []interface{} - err := _ModelRegistry.contract.Call(opts, &out, "modelMap", id) - - if err != nil { - return *new(Model), err - } - - out0 := *abi.ConvertType(out[0], new(Model)).(*Model) - - return out0, err - -} - -// ModelMap is a free data retrieval call binding the contract method 0x6e5cbd85. -// -// Solidity: function modelMap(bytes32 id) view returns((bytes32,uint256,uint256,address,string,string[],uint128,bool)) -func (_ModelRegistry *ModelRegistrySession) ModelMap(id [32]byte) (Model, error) { - return _ModelRegistry.Contract.ModelMap(&_ModelRegistry.CallOpts, id) -} - -// ModelMap is a free data retrieval call binding the contract method 0x6e5cbd85. -// -// Solidity: function modelMap(bytes32 id) view returns((bytes32,uint256,uint256,address,string,string[],uint128,bool)) -func (_ModelRegistry *ModelRegistryCallerSession) ModelMap(id [32]byte) (Model, error) { - return _ModelRegistry.Contract.ModelMap(&_ModelRegistry.CallOpts, id) -} - -// ModelMinStake is a free data retrieval call binding the contract method 0xe41a6823. -// -// Solidity: function modelMinStake() view returns(uint256) -func (_ModelRegistry *ModelRegistryCaller) ModelMinStake(opts *bind.CallOpts) (*big.Int, error) { - var out []interface{} - err := _ModelRegistry.contract.Call(opts, &out, "modelMinStake") - - if err != nil { - return *new(*big.Int), err - } - - out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - - return out0, err - -} - -// ModelMinStake is a free data retrieval call binding the contract method 0xe41a6823. -// -// Solidity: function modelMinStake() view returns(uint256) -func (_ModelRegistry *ModelRegistrySession) ModelMinStake() (*big.Int, error) { - return _ModelRegistry.Contract.ModelMinStake(&_ModelRegistry.CallOpts) -} - -// ModelMinStake is a free data retrieval call binding the contract method 0xe41a6823. -// -// Solidity: function modelMinStake() view returns(uint256) -func (_ModelRegistry *ModelRegistryCallerSession) ModelMinStake() (*big.Int, error) { - return _ModelRegistry.Contract.ModelMinStake(&_ModelRegistry.CallOpts) -} - -// ModelStats is a free data retrieval call binding the contract method 0x99644b2c. -// -// Solidity: function modelStats(bytes32 id) view returns(((int64,int64),(int64,int64),(int64,int64),uint32)) -func (_ModelRegistry *ModelRegistryCaller) ModelStats(opts *bind.CallOpts, id [32]byte) (ModelStats, error) { - var out []interface{} - err := _ModelRegistry.contract.Call(opts, &out, "modelStats", id) - - if err != nil { - return *new(ModelStats), err - } - - out0 := *abi.ConvertType(out[0], new(ModelStats)).(*ModelStats) - - return out0, err - -} - -// ModelStats is a free data retrieval call binding the contract method 0x99644b2c. -// -// Solidity: function modelStats(bytes32 id) view returns(((int64,int64),(int64,int64),(int64,int64),uint32)) -func (_ModelRegistry *ModelRegistrySession) ModelStats(id [32]byte) (ModelStats, error) { - return _ModelRegistry.Contract.ModelStats(&_ModelRegistry.CallOpts, id) -} - -// ModelStats is a free data retrieval call binding the contract method 0x99644b2c. -// -// Solidity: function modelStats(bytes32 id) view returns(((int64,int64),(int64,int64),(int64,int64),uint32)) -func (_ModelRegistry *ModelRegistryCallerSession) ModelStats(id [32]byte) (ModelStats, error) { - return _ModelRegistry.Contract.ModelStats(&_ModelRegistry.CallOpts, id) -} - -// Models is a free data retrieval call binding the contract method 0x6a030ca9. -// -// Solidity: function models(uint256 index) view returns(bytes32) -func (_ModelRegistry *ModelRegistryCaller) Models(opts *bind.CallOpts, index *big.Int) ([32]byte, error) { - var out []interface{} - err := _ModelRegistry.contract.Call(opts, &out, "models", index) - - if err != nil { - return *new([32]byte), err - } - - out0 := *abi.ConvertType(out[0], new([32]byte)).(*[32]byte) - - return out0, err - -} - -// Models is a free data retrieval call binding the contract method 0x6a030ca9. -// -// Solidity: function models(uint256 index) view returns(bytes32) -func (_ModelRegistry *ModelRegistrySession) Models(index *big.Int) ([32]byte, error) { - return _ModelRegistry.Contract.Models(&_ModelRegistry.CallOpts, index) -} - -// Models is a free data retrieval call binding the contract method 0x6a030ca9. -// -// Solidity: function models(uint256 index) view returns(bytes32) -func (_ModelRegistry *ModelRegistryCallerSession) Models(index *big.Int) ([32]byte, error) { - return _ModelRegistry.Contract.Models(&_ModelRegistry.CallOpts, index) -} - -// ModelDeregister is a paid mutator transaction binding the contract method 0xd5a245f1. -// -// Solidity: function modelDeregister(bytes32 id) returns() -func (_ModelRegistry *ModelRegistryTransactor) ModelDeregister(opts *bind.TransactOpts, id [32]byte) (*types.Transaction, error) { - return _ModelRegistry.contract.Transact(opts, "modelDeregister", id) -} - -// ModelDeregister is a paid mutator transaction binding the contract method 0xd5a245f1. -// -// Solidity: function modelDeregister(bytes32 id) returns() -func (_ModelRegistry *ModelRegistrySession) ModelDeregister(id [32]byte) (*types.Transaction, error) { - return _ModelRegistry.Contract.ModelDeregister(&_ModelRegistry.TransactOpts, id) -} - -// ModelDeregister is a paid mutator transaction binding the contract method 0xd5a245f1. -// -// Solidity: function modelDeregister(bytes32 id) returns() -func (_ModelRegistry *ModelRegistryTransactorSession) ModelDeregister(id [32]byte) (*types.Transaction, error) { - return _ModelRegistry.Contract.ModelDeregister(&_ModelRegistry.TransactOpts, id) -} - -// ModelRegister is a paid mutator transaction binding the contract method 0x82806227. -// -// Solidity: function modelRegister(bytes32 modelId, bytes32 ipfsCID, uint256 fee, uint256 addStake, address owner, string name, string[] tags) returns() -func (_ModelRegistry *ModelRegistryTransactor) ModelRegister(opts *bind.TransactOpts, modelId [32]byte, ipfsCID [32]byte, fee *big.Int, addStake *big.Int, owner common.Address, name string, tags []string) (*types.Transaction, error) { - return _ModelRegistry.contract.Transact(opts, "modelRegister", modelId, ipfsCID, fee, addStake, owner, name, tags) -} - -// ModelRegister is a paid mutator transaction binding the contract method 0x82806227. -// -// Solidity: function modelRegister(bytes32 modelId, bytes32 ipfsCID, uint256 fee, uint256 addStake, address owner, string name, string[] tags) returns() -func (_ModelRegistry *ModelRegistrySession) ModelRegister(modelId [32]byte, ipfsCID [32]byte, fee *big.Int, addStake *big.Int, owner common.Address, name string, tags []string) (*types.Transaction, error) { - return _ModelRegistry.Contract.ModelRegister(&_ModelRegistry.TransactOpts, modelId, ipfsCID, fee, addStake, owner, name, tags) -} - -// ModelRegister is a paid mutator transaction binding the contract method 0x82806227. -// -// Solidity: function modelRegister(bytes32 modelId, bytes32 ipfsCID, uint256 fee, uint256 addStake, address owner, string name, string[] tags) returns() -func (_ModelRegistry *ModelRegistryTransactorSession) ModelRegister(modelId [32]byte, ipfsCID [32]byte, fee *big.Int, addStake *big.Int, owner common.Address, name string, tags []string) (*types.Transaction, error) { - return _ModelRegistry.Contract.ModelRegister(&_ModelRegistry.TransactOpts, modelId, ipfsCID, fee, addStake, owner, name, tags) -} - -// ModelResetStats is a paid mutator transaction binding the contract method 0x9971035a. -// -// Solidity: function modelResetStats(bytes32 id) returns() -func (_ModelRegistry *ModelRegistryTransactor) ModelResetStats(opts *bind.TransactOpts, id [32]byte) (*types.Transaction, error) { - return _ModelRegistry.contract.Transact(opts, "modelResetStats", id) -} - -// ModelResetStats is a paid mutator transaction binding the contract method 0x9971035a. -// -// Solidity: function modelResetStats(bytes32 id) returns() -func (_ModelRegistry *ModelRegistrySession) ModelResetStats(id [32]byte) (*types.Transaction, error) { - return _ModelRegistry.Contract.ModelResetStats(&_ModelRegistry.TransactOpts, id) -} - -// ModelResetStats is a paid mutator transaction binding the contract method 0x9971035a. -// -// Solidity: function modelResetStats(bytes32 id) returns() -func (_ModelRegistry *ModelRegistryTransactorSession) ModelResetStats(id [32]byte) (*types.Transaction, error) { - return _ModelRegistry.Contract.ModelResetStats(&_ModelRegistry.TransactOpts, id) -} - -// ModelSetMinStake is a paid mutator transaction binding the contract method 0x78998329. -// -// Solidity: function modelSetMinStake(uint256 _minStake) returns() -func (_ModelRegistry *ModelRegistryTransactor) ModelSetMinStake(opts *bind.TransactOpts, _minStake *big.Int) (*types.Transaction, error) { - return _ModelRegistry.contract.Transact(opts, "modelSetMinStake", _minStake) -} - -// ModelSetMinStake is a paid mutator transaction binding the contract method 0x78998329. -// -// Solidity: function modelSetMinStake(uint256 _minStake) returns() -func (_ModelRegistry *ModelRegistrySession) ModelSetMinStake(_minStake *big.Int) (*types.Transaction, error) { - return _ModelRegistry.Contract.ModelSetMinStake(&_ModelRegistry.TransactOpts, _minStake) -} - -// ModelSetMinStake is a paid mutator transaction binding the contract method 0x78998329. -// -// Solidity: function modelSetMinStake(uint256 _minStake) returns() -func (_ModelRegistry *ModelRegistryTransactorSession) ModelSetMinStake(_minStake *big.Int) (*types.Transaction, error) { - return _ModelRegistry.Contract.ModelSetMinStake(&_ModelRegistry.TransactOpts, _minStake) -} - -// ModelRegistryModelDeregisteredIterator is returned from FilterModelDeregistered and is used to iterate over the raw logs and unpacked data for ModelDeregistered events raised by the ModelRegistry contract. -type ModelRegistryModelDeregisteredIterator struct { - Event *ModelRegistryModelDeregistered // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *ModelRegistryModelDeregisteredIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(ModelRegistryModelDeregistered) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(ModelRegistryModelDeregistered) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *ModelRegistryModelDeregisteredIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *ModelRegistryModelDeregisteredIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// ModelRegistryModelDeregistered represents a ModelDeregistered event raised by the ModelRegistry contract. -type ModelRegistryModelDeregistered struct { - Owner common.Address - ModelId [32]byte - Raw types.Log // Blockchain specific contextual infos -} - -// FilterModelDeregistered is a free log retrieval operation binding the contract event 0x79a9f3017f26694a70f688c1e37f4add042a050660c62fc8351f760b153b888b. -// -// Solidity: event ModelDeregistered(address indexed owner, bytes32 indexed modelId) -func (_ModelRegistry *ModelRegistryFilterer) FilterModelDeregistered(opts *bind.FilterOpts, owner []common.Address, modelId [][32]byte) (*ModelRegistryModelDeregisteredIterator, error) { - - var ownerRule []interface{} - for _, ownerItem := range owner { - ownerRule = append(ownerRule, ownerItem) - } - var modelIdRule []interface{} - for _, modelIdItem := range modelId { - modelIdRule = append(modelIdRule, modelIdItem) - } - - logs, sub, err := _ModelRegistry.contract.FilterLogs(opts, "ModelDeregistered", ownerRule, modelIdRule) - if err != nil { - return nil, err - } - return &ModelRegistryModelDeregisteredIterator{contract: _ModelRegistry.contract, event: "ModelDeregistered", logs: logs, sub: sub}, nil -} - -// WatchModelDeregistered is a free log subscription operation binding the contract event 0x79a9f3017f26694a70f688c1e37f4add042a050660c62fc8351f760b153b888b. -// -// Solidity: event ModelDeregistered(address indexed owner, bytes32 indexed modelId) -func (_ModelRegistry *ModelRegistryFilterer) WatchModelDeregistered(opts *bind.WatchOpts, sink chan<- *ModelRegistryModelDeregistered, owner []common.Address, modelId [][32]byte) (event.Subscription, error) { - - var ownerRule []interface{} - for _, ownerItem := range owner { - ownerRule = append(ownerRule, ownerItem) - } - var modelIdRule []interface{} - for _, modelIdItem := range modelId { - modelIdRule = append(modelIdRule, modelIdItem) - } - - logs, sub, err := _ModelRegistry.contract.WatchLogs(opts, "ModelDeregistered", ownerRule, modelIdRule) - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(ModelRegistryModelDeregistered) - if err := _ModelRegistry.contract.UnpackLog(event, "ModelDeregistered", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// ParseModelDeregistered is a log parse operation binding the contract event 0x79a9f3017f26694a70f688c1e37f4add042a050660c62fc8351f760b153b888b. -// -// Solidity: event ModelDeregistered(address indexed owner, bytes32 indexed modelId) -func (_ModelRegistry *ModelRegistryFilterer) ParseModelDeregistered(log types.Log) (*ModelRegistryModelDeregistered, error) { - event := new(ModelRegistryModelDeregistered) - if err := _ModelRegistry.contract.UnpackLog(event, "ModelDeregistered", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -// ModelRegistryModelMinStakeUpdatedIterator is returned from FilterModelMinStakeUpdated and is used to iterate over the raw logs and unpacked data for ModelMinStakeUpdated events raised by the ModelRegistry contract. -type ModelRegistryModelMinStakeUpdatedIterator struct { - Event *ModelRegistryModelMinStakeUpdated // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *ModelRegistryModelMinStakeUpdatedIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(ModelRegistryModelMinStakeUpdated) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(ModelRegistryModelMinStakeUpdated) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *ModelRegistryModelMinStakeUpdatedIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *ModelRegistryModelMinStakeUpdatedIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// ModelRegistryModelMinStakeUpdated represents a ModelMinStakeUpdated event raised by the ModelRegistry contract. -type ModelRegistryModelMinStakeUpdated struct { - NewStake *big.Int - Raw types.Log // Blockchain specific contextual infos -} - -// FilterModelMinStakeUpdated is a free log retrieval operation binding the contract event 0xa7facdcb561b9b7c3091d6bea4b06c48f97f719dade07ba7510a687109161f6e. -// -// Solidity: event ModelMinStakeUpdated(uint256 newStake) -func (_ModelRegistry *ModelRegistryFilterer) FilterModelMinStakeUpdated(opts *bind.FilterOpts) (*ModelRegistryModelMinStakeUpdatedIterator, error) { - - logs, sub, err := _ModelRegistry.contract.FilterLogs(opts, "ModelMinStakeUpdated") - if err != nil { - return nil, err - } - return &ModelRegistryModelMinStakeUpdatedIterator{contract: _ModelRegistry.contract, event: "ModelMinStakeUpdated", logs: logs, sub: sub}, nil -} - -// WatchModelMinStakeUpdated is a free log subscription operation binding the contract event 0xa7facdcb561b9b7c3091d6bea4b06c48f97f719dade07ba7510a687109161f6e. -// -// Solidity: event ModelMinStakeUpdated(uint256 newStake) -func (_ModelRegistry *ModelRegistryFilterer) WatchModelMinStakeUpdated(opts *bind.WatchOpts, sink chan<- *ModelRegistryModelMinStakeUpdated) (event.Subscription, error) { - - logs, sub, err := _ModelRegistry.contract.WatchLogs(opts, "ModelMinStakeUpdated") - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(ModelRegistryModelMinStakeUpdated) - if err := _ModelRegistry.contract.UnpackLog(event, "ModelMinStakeUpdated", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// ParseModelMinStakeUpdated is a log parse operation binding the contract event 0xa7facdcb561b9b7c3091d6bea4b06c48f97f719dade07ba7510a687109161f6e. -// -// Solidity: event ModelMinStakeUpdated(uint256 newStake) -func (_ModelRegistry *ModelRegistryFilterer) ParseModelMinStakeUpdated(log types.Log) (*ModelRegistryModelMinStakeUpdated, error) { - event := new(ModelRegistryModelMinStakeUpdated) - if err := _ModelRegistry.contract.UnpackLog(event, "ModelMinStakeUpdated", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -// ModelRegistryModelRegisteredUpdatedIterator is returned from FilterModelRegisteredUpdated and is used to iterate over the raw logs and unpacked data for ModelRegisteredUpdated events raised by the ModelRegistry contract. -type ModelRegistryModelRegisteredUpdatedIterator struct { - Event *ModelRegistryModelRegisteredUpdated // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *ModelRegistryModelRegisteredUpdatedIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(ModelRegistryModelRegisteredUpdated) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(ModelRegistryModelRegisteredUpdated) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *ModelRegistryModelRegisteredUpdatedIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *ModelRegistryModelRegisteredUpdatedIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// ModelRegistryModelRegisteredUpdated represents a ModelRegisteredUpdated event raised by the ModelRegistry contract. -type ModelRegistryModelRegisteredUpdated struct { - Owner common.Address - ModelId [32]byte - Raw types.Log // Blockchain specific contextual infos -} - -// FilterModelRegisteredUpdated is a free log retrieval operation binding the contract event 0xda9282a68d90c36d31d780a69a65da6c35191a5d8cdd37bd1a1a5aa9fb168e77. -// -// Solidity: event ModelRegisteredUpdated(address indexed owner, bytes32 indexed modelId) -func (_ModelRegistry *ModelRegistryFilterer) FilterModelRegisteredUpdated(opts *bind.FilterOpts, owner []common.Address, modelId [][32]byte) (*ModelRegistryModelRegisteredUpdatedIterator, error) { - - var ownerRule []interface{} - for _, ownerItem := range owner { - ownerRule = append(ownerRule, ownerItem) - } - var modelIdRule []interface{} - for _, modelIdItem := range modelId { - modelIdRule = append(modelIdRule, modelIdItem) - } - - logs, sub, err := _ModelRegistry.contract.FilterLogs(opts, "ModelRegisteredUpdated", ownerRule, modelIdRule) - if err != nil { - return nil, err - } - return &ModelRegistryModelRegisteredUpdatedIterator{contract: _ModelRegistry.contract, event: "ModelRegisteredUpdated", logs: logs, sub: sub}, nil -} - -// WatchModelRegisteredUpdated is a free log subscription operation binding the contract event 0xda9282a68d90c36d31d780a69a65da6c35191a5d8cdd37bd1a1a5aa9fb168e77. -// -// Solidity: event ModelRegisteredUpdated(address indexed owner, bytes32 indexed modelId) -func (_ModelRegistry *ModelRegistryFilterer) WatchModelRegisteredUpdated(opts *bind.WatchOpts, sink chan<- *ModelRegistryModelRegisteredUpdated, owner []common.Address, modelId [][32]byte) (event.Subscription, error) { - - var ownerRule []interface{} - for _, ownerItem := range owner { - ownerRule = append(ownerRule, ownerItem) - } - var modelIdRule []interface{} - for _, modelIdItem := range modelId { - modelIdRule = append(modelIdRule, modelIdItem) - } - - logs, sub, err := _ModelRegistry.contract.WatchLogs(opts, "ModelRegisteredUpdated", ownerRule, modelIdRule) - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(ModelRegistryModelRegisteredUpdated) - if err := _ModelRegistry.contract.UnpackLog(event, "ModelRegisteredUpdated", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// ParseModelRegisteredUpdated is a log parse operation binding the contract event 0xda9282a68d90c36d31d780a69a65da6c35191a5d8cdd37bd1a1a5aa9fb168e77. -// -// Solidity: event ModelRegisteredUpdated(address indexed owner, bytes32 indexed modelId) -func (_ModelRegistry *ModelRegistryFilterer) ParseModelRegisteredUpdated(log types.Log) (*ModelRegistryModelRegisteredUpdated, error) { - event := new(ModelRegistryModelRegisteredUpdated) - if err := _ModelRegistry.contract.UnpackLog(event, "ModelRegisteredUpdated", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} diff --git a/proxy-router/contracts/providerregistry/ProviderRegistry.go b/proxy-router/contracts/providerregistry/ProviderRegistry.go deleted file mode 100644 index 48c90be2..00000000 --- a/proxy-router/contracts/providerregistry/ProviderRegistry.go +++ /dev/null @@ -1,960 +0,0 @@ -// Code generated - DO NOT EDIT. -// This file is a generated binding and any manual changes will be lost. - -package providerregistry - -import ( - "errors" - "math/big" - "strings" - - ethereum "github.com/ethereum/go-ethereum" - "github.com/ethereum/go-ethereum/accounts/abi" - "github.com/ethereum/go-ethereum/accounts/abi/bind" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/event" -) - -// Reference imports to suppress errors if they are not otherwise used. -var ( - _ = errors.New - _ = big.NewInt - _ = strings.NewReader - _ = ethereum.NotFound - _ = bind.Bind - _ = common.Big1 - _ = types.BloomLookup - _ = event.NewSubscription - _ = abi.ConvertType -) - -// Provider is an auto generated low-level Go binding around an user-defined struct. -type Provider struct { - Endpoint string - Stake *big.Int - CreatedAt *big.Int - LimitPeriodEnd *big.Int - LimitPeriodEarned *big.Int - IsDeleted bool -} - -// ProviderRegistryMetaData contains all meta data concerning the ProviderRegistry contract. -var ProviderRegistryMetaData = &bind.MetaData{ - ABI: "[{\"inputs\":[],\"name\":\"ErrNoStake\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ErrNoWithdrawableStake\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ErrProviderNotDeleted\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"KeyExists\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"KeyNotFound\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_user\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_contractOwner\",\"type\":\"address\"}],\"name\":\"NotContractOwner\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NotSenderOrOwner\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ProviderHasActiveBids\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"StakeTooLow\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ZeroKey\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"provider\",\"type\":\"address\"}],\"name\":\"ProviderDeregistered\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newStake\",\"type\":\"uint256\"}],\"name\":\"ProviderMinStakeUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"provider\",\"type\":\"address\"}],\"name\":\"ProviderRegisteredUpdated\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"}],\"name\":\"providerDeregister\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"}],\"name\":\"providerExists\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"providerGetAll\",\"outputs\":[{\"internalType\":\"address[]\",\"name\":\"\",\"type\":\"address[]\"},{\"components\":[{\"internalType\":\"string\",\"name\":\"endpoint\",\"type\":\"string\"},{\"internalType\":\"uint256\",\"name\":\"stake\",\"type\":\"uint256\"},{\"internalType\":\"uint128\",\"name\":\"createdAt\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"limitPeriodEnd\",\"type\":\"uint128\"},{\"internalType\":\"uint256\",\"name\":\"limitPeriodEarned\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"isDeleted\",\"type\":\"bool\"}],\"internalType\":\"structProvider[]\",\"name\":\"\",\"type\":\"tuple[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"index\",\"type\":\"uint256\"}],\"name\":\"providerGetByIndex\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"string\",\"name\":\"endpoint\",\"type\":\"string\"},{\"internalType\":\"uint256\",\"name\":\"stake\",\"type\":\"uint256\"},{\"internalType\":\"uint128\",\"name\":\"createdAt\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"limitPeriodEnd\",\"type\":\"uint128\"},{\"internalType\":\"uint256\",\"name\":\"limitPeriodEarned\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"isDeleted\",\"type\":\"bool\"}],\"internalType\":\"structProvider\",\"name\":\"provider\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"providerGetCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"count\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"providerGetIds\",\"outputs\":[{\"internalType\":\"address[]\",\"name\":\"\",\"type\":\"address[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"}],\"name\":\"providerMap\",\"outputs\":[{\"components\":[{\"internalType\":\"string\",\"name\":\"endpoint\",\"type\":\"string\"},{\"internalType\":\"uint256\",\"name\":\"stake\",\"type\":\"uint256\"},{\"internalType\":\"uint128\",\"name\":\"createdAt\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"limitPeriodEnd\",\"type\":\"uint128\"},{\"internalType\":\"uint256\",\"name\":\"limitPeriodEarned\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"isDeleted\",\"type\":\"bool\"}],\"internalType\":\"structProvider\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"providerMinStake\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"addStake\",\"type\":\"uint256\"},{\"internalType\":\"string\",\"name\":\"endpoint\",\"type\":\"string\"}],\"name\":\"providerRegister\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_minStake\",\"type\":\"uint256\"}],\"name\":\"providerSetMinStake\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"}],\"name\":\"providerWithdrawStake\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"index\",\"type\":\"uint256\"}],\"name\":\"providers\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]", -} - -// ProviderRegistryABI is the input ABI used to generate the binding from. -// Deprecated: Use ProviderRegistryMetaData.ABI instead. -var ProviderRegistryABI = ProviderRegistryMetaData.ABI - -// ProviderRegistry is an auto generated Go binding around an Ethereum contract. -type ProviderRegistry struct { - ProviderRegistryCaller // Read-only binding to the contract - ProviderRegistryTransactor // Write-only binding to the contract - ProviderRegistryFilterer // Log filterer for contract events -} - -// ProviderRegistryCaller is an auto generated read-only Go binding around an Ethereum contract. -type ProviderRegistryCaller struct { - contract *bind.BoundContract // Generic contract wrapper for the low level calls -} - -// ProviderRegistryTransactor is an auto generated write-only Go binding around an Ethereum contract. -type ProviderRegistryTransactor struct { - contract *bind.BoundContract // Generic contract wrapper for the low level calls -} - -// ProviderRegistryFilterer is an auto generated log filtering Go binding around an Ethereum contract events. -type ProviderRegistryFilterer struct { - contract *bind.BoundContract // Generic contract wrapper for the low level calls -} - -// ProviderRegistrySession is an auto generated Go binding around an Ethereum contract, -// with pre-set call and transact options. -type ProviderRegistrySession struct { - Contract *ProviderRegistry // Generic contract binding to set the session for - CallOpts bind.CallOpts // Call options to use throughout this session - TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session -} - -// ProviderRegistryCallerSession is an auto generated read-only Go binding around an Ethereum contract, -// with pre-set call options. -type ProviderRegistryCallerSession struct { - Contract *ProviderRegistryCaller // Generic contract caller binding to set the session for - CallOpts bind.CallOpts // Call options to use throughout this session -} - -// ProviderRegistryTransactorSession is an auto generated write-only Go binding around an Ethereum contract, -// with pre-set transact options. -type ProviderRegistryTransactorSession struct { - Contract *ProviderRegistryTransactor // Generic contract transactor binding to set the session for - TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session -} - -// ProviderRegistryRaw is an auto generated low-level Go binding around an Ethereum contract. -type ProviderRegistryRaw struct { - Contract *ProviderRegistry // Generic contract binding to access the raw methods on -} - -// ProviderRegistryCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. -type ProviderRegistryCallerRaw struct { - Contract *ProviderRegistryCaller // Generic read-only contract binding to access the raw methods on -} - -// ProviderRegistryTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. -type ProviderRegistryTransactorRaw struct { - Contract *ProviderRegistryTransactor // Generic write-only contract binding to access the raw methods on -} - -// NewProviderRegistry creates a new instance of ProviderRegistry, bound to a specific deployed contract. -func NewProviderRegistry(address common.Address, backend bind.ContractBackend) (*ProviderRegistry, error) { - contract, err := bindProviderRegistry(address, backend, backend, backend) - if err != nil { - return nil, err - } - return &ProviderRegistry{ProviderRegistryCaller: ProviderRegistryCaller{contract: contract}, ProviderRegistryTransactor: ProviderRegistryTransactor{contract: contract}, ProviderRegistryFilterer: ProviderRegistryFilterer{contract: contract}}, nil -} - -// NewProviderRegistryCaller creates a new read-only instance of ProviderRegistry, bound to a specific deployed contract. -func NewProviderRegistryCaller(address common.Address, caller bind.ContractCaller) (*ProviderRegistryCaller, error) { - contract, err := bindProviderRegistry(address, caller, nil, nil) - if err != nil { - return nil, err - } - return &ProviderRegistryCaller{contract: contract}, nil -} - -// NewProviderRegistryTransactor creates a new write-only instance of ProviderRegistry, bound to a specific deployed contract. -func NewProviderRegistryTransactor(address common.Address, transactor bind.ContractTransactor) (*ProviderRegistryTransactor, error) { - contract, err := bindProviderRegistry(address, nil, transactor, nil) - if err != nil { - return nil, err - } - return &ProviderRegistryTransactor{contract: contract}, nil -} - -// NewProviderRegistryFilterer creates a new log filterer instance of ProviderRegistry, bound to a specific deployed contract. -func NewProviderRegistryFilterer(address common.Address, filterer bind.ContractFilterer) (*ProviderRegistryFilterer, error) { - contract, err := bindProviderRegistry(address, nil, nil, filterer) - if err != nil { - return nil, err - } - return &ProviderRegistryFilterer{contract: contract}, nil -} - -// bindProviderRegistry binds a generic wrapper to an already deployed contract. -func bindProviderRegistry(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { - parsed, err := ProviderRegistryMetaData.GetAbi() - if err != nil { - return nil, err - } - return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil -} - -// Call invokes the (constant) contract method with params as input values and -// sets the output to result. The result type might be a single field for simple -// returns, a slice of interfaces for anonymous returns and a struct for named -// returns. -func (_ProviderRegistry *ProviderRegistryRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { - return _ProviderRegistry.Contract.ProviderRegistryCaller.contract.Call(opts, result, method, params...) -} - -// Transfer initiates a plain transaction to move funds to the contract, calling -// its default method if one is available. -func (_ProviderRegistry *ProviderRegistryRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { - return _ProviderRegistry.Contract.ProviderRegistryTransactor.contract.Transfer(opts) -} - -// Transact invokes the (paid) contract method with params as input values. -func (_ProviderRegistry *ProviderRegistryRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { - return _ProviderRegistry.Contract.ProviderRegistryTransactor.contract.Transact(opts, method, params...) -} - -// Call invokes the (constant) contract method with params as input values and -// sets the output to result. The result type might be a single field for simple -// returns, a slice of interfaces for anonymous returns and a struct for named -// returns. -func (_ProviderRegistry *ProviderRegistryCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { - return _ProviderRegistry.Contract.contract.Call(opts, result, method, params...) -} - -// Transfer initiates a plain transaction to move funds to the contract, calling -// its default method if one is available. -func (_ProviderRegistry *ProviderRegistryTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { - return _ProviderRegistry.Contract.contract.Transfer(opts) -} - -// Transact invokes the (paid) contract method with params as input values. -func (_ProviderRegistry *ProviderRegistryTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { - return _ProviderRegistry.Contract.contract.Transact(opts, method, params...) -} - -// ProviderExists is a free data retrieval call binding the contract method 0xdfc03505. -// -// Solidity: function providerExists(address addr) view returns(bool) -func (_ProviderRegistry *ProviderRegistryCaller) ProviderExists(opts *bind.CallOpts, addr common.Address) (bool, error) { - var out []interface{} - err := _ProviderRegistry.contract.Call(opts, &out, "providerExists", addr) - - if err != nil { - return *new(bool), err - } - - out0 := *abi.ConvertType(out[0], new(bool)).(*bool) - - return out0, err - -} - -// ProviderExists is a free data retrieval call binding the contract method 0xdfc03505. -// -// Solidity: function providerExists(address addr) view returns(bool) -func (_ProviderRegistry *ProviderRegistrySession) ProviderExists(addr common.Address) (bool, error) { - return _ProviderRegistry.Contract.ProviderExists(&_ProviderRegistry.CallOpts, addr) -} - -// ProviderExists is a free data retrieval call binding the contract method 0xdfc03505. -// -// Solidity: function providerExists(address addr) view returns(bool) -func (_ProviderRegistry *ProviderRegistryCallerSession) ProviderExists(addr common.Address) (bool, error) { - return _ProviderRegistry.Contract.ProviderExists(&_ProviderRegistry.CallOpts, addr) -} - -// ProviderGetAll is a free data retrieval call binding the contract method 0x86af8fdc. -// -// Solidity: function providerGetAll() view returns(address[], (string,uint256,uint128,uint128,uint256,bool)[]) -func (_ProviderRegistry *ProviderRegistryCaller) ProviderGetAll(opts *bind.CallOpts) ([]common.Address, []Provider, error) { - var out []interface{} - err := _ProviderRegistry.contract.Call(opts, &out, "providerGetAll") - - if err != nil { - return *new([]common.Address), *new([]Provider), err - } - - out0 := *abi.ConvertType(out[0], new([]common.Address)).(*[]common.Address) - out1 := *abi.ConvertType(out[1], new([]Provider)).(*[]Provider) - - return out0, out1, err - -} - -// ProviderGetAll is a free data retrieval call binding the contract method 0x86af8fdc. -// -// Solidity: function providerGetAll() view returns(address[], (string,uint256,uint128,uint128,uint256,bool)[]) -func (_ProviderRegistry *ProviderRegistrySession) ProviderGetAll() ([]common.Address, []Provider, error) { - return _ProviderRegistry.Contract.ProviderGetAll(&_ProviderRegistry.CallOpts) -} - -// ProviderGetAll is a free data retrieval call binding the contract method 0x86af8fdc. -// -// Solidity: function providerGetAll() view returns(address[], (string,uint256,uint128,uint128,uint256,bool)[]) -func (_ProviderRegistry *ProviderRegistryCallerSession) ProviderGetAll() ([]common.Address, []Provider, error) { - return _ProviderRegistry.Contract.ProviderGetAll(&_ProviderRegistry.CallOpts) -} - -// ProviderGetByIndex is a free data retrieval call binding the contract method 0xb8eed333. -// -// Solidity: function providerGetByIndex(uint256 index) view returns(address addr, (string,uint256,uint128,uint128,uint256,bool) provider) -func (_ProviderRegistry *ProviderRegistryCaller) ProviderGetByIndex(opts *bind.CallOpts, index *big.Int) (struct { - Addr common.Address - Provider Provider -}, error) { - var out []interface{} - err := _ProviderRegistry.contract.Call(opts, &out, "providerGetByIndex", index) - - outstruct := new(struct { - Addr common.Address - Provider Provider - }) - if err != nil { - return *outstruct, err - } - - outstruct.Addr = *abi.ConvertType(out[0], new(common.Address)).(*common.Address) - outstruct.Provider = *abi.ConvertType(out[1], new(Provider)).(*Provider) - - return *outstruct, err - -} - -// ProviderGetByIndex is a free data retrieval call binding the contract method 0xb8eed333. -// -// Solidity: function providerGetByIndex(uint256 index) view returns(address addr, (string,uint256,uint128,uint128,uint256,bool) provider) -func (_ProviderRegistry *ProviderRegistrySession) ProviderGetByIndex(index *big.Int) (struct { - Addr common.Address - Provider Provider -}, error) { - return _ProviderRegistry.Contract.ProviderGetByIndex(&_ProviderRegistry.CallOpts, index) -} - -// ProviderGetByIndex is a free data retrieval call binding the contract method 0xb8eed333. -// -// Solidity: function providerGetByIndex(uint256 index) view returns(address addr, (string,uint256,uint128,uint128,uint256,bool) provider) -func (_ProviderRegistry *ProviderRegistryCallerSession) ProviderGetByIndex(index *big.Int) (struct { - Addr common.Address - Provider Provider -}, error) { - return _ProviderRegistry.Contract.ProviderGetByIndex(&_ProviderRegistry.CallOpts, index) -} - -// ProviderGetCount is a free data retrieval call binding the contract method 0x91d2b7eb. -// -// Solidity: function providerGetCount() view returns(uint256 count) -func (_ProviderRegistry *ProviderRegistryCaller) ProviderGetCount(opts *bind.CallOpts) (*big.Int, error) { - var out []interface{} - err := _ProviderRegistry.contract.Call(opts, &out, "providerGetCount") - - if err != nil { - return *new(*big.Int), err - } - - out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - - return out0, err - -} - -// ProviderGetCount is a free data retrieval call binding the contract method 0x91d2b7eb. -// -// Solidity: function providerGetCount() view returns(uint256 count) -func (_ProviderRegistry *ProviderRegistrySession) ProviderGetCount() (*big.Int, error) { - return _ProviderRegistry.Contract.ProviderGetCount(&_ProviderRegistry.CallOpts) -} - -// ProviderGetCount is a free data retrieval call binding the contract method 0x91d2b7eb. -// -// Solidity: function providerGetCount() view returns(uint256 count) -func (_ProviderRegistry *ProviderRegistryCallerSession) ProviderGetCount() (*big.Int, error) { - return _ProviderRegistry.Contract.ProviderGetCount(&_ProviderRegistry.CallOpts) -} - -// ProviderGetIds is a free data retrieval call binding the contract method 0x2e888fe1. -// -// Solidity: function providerGetIds() view returns(address[]) -func (_ProviderRegistry *ProviderRegistryCaller) ProviderGetIds(opts *bind.CallOpts) ([]common.Address, error) { - var out []interface{} - err := _ProviderRegistry.contract.Call(opts, &out, "providerGetIds") - - if err != nil { - return *new([]common.Address), err - } - - out0 := *abi.ConvertType(out[0], new([]common.Address)).(*[]common.Address) - - return out0, err - -} - -// ProviderGetIds is a free data retrieval call binding the contract method 0x2e888fe1. -// -// Solidity: function providerGetIds() view returns(address[]) -func (_ProviderRegistry *ProviderRegistrySession) ProviderGetIds() ([]common.Address, error) { - return _ProviderRegistry.Contract.ProviderGetIds(&_ProviderRegistry.CallOpts) -} - -// ProviderGetIds is a free data retrieval call binding the contract method 0x2e888fe1. -// -// Solidity: function providerGetIds() view returns(address[]) -func (_ProviderRegistry *ProviderRegistryCallerSession) ProviderGetIds() ([]common.Address, error) { - return _ProviderRegistry.Contract.ProviderGetIds(&_ProviderRegistry.CallOpts) -} - -// ProviderMap is a free data retrieval call binding the contract method 0xa6c87915. -// -// Solidity: function providerMap(address addr) view returns((string,uint256,uint128,uint128,uint256,bool)) -func (_ProviderRegistry *ProviderRegistryCaller) ProviderMap(opts *bind.CallOpts, addr common.Address) (Provider, error) { - var out []interface{} - err := _ProviderRegistry.contract.Call(opts, &out, "providerMap", addr) - - if err != nil { - return *new(Provider), err - } - - out0 := *abi.ConvertType(out[0], new(Provider)).(*Provider) - - return out0, err - -} - -// ProviderMap is a free data retrieval call binding the contract method 0xa6c87915. -// -// Solidity: function providerMap(address addr) view returns((string,uint256,uint128,uint128,uint256,bool)) -func (_ProviderRegistry *ProviderRegistrySession) ProviderMap(addr common.Address) (Provider, error) { - return _ProviderRegistry.Contract.ProviderMap(&_ProviderRegistry.CallOpts, addr) -} - -// ProviderMap is a free data retrieval call binding the contract method 0xa6c87915. -// -// Solidity: function providerMap(address addr) view returns((string,uint256,uint128,uint128,uint256,bool)) -func (_ProviderRegistry *ProviderRegistryCallerSession) ProviderMap(addr common.Address) (Provider, error) { - return _ProviderRegistry.Contract.ProviderMap(&_ProviderRegistry.CallOpts, addr) -} - -// ProviderMinStake is a free data retrieval call binding the contract method 0xbcd5641e. -// -// Solidity: function providerMinStake() view returns(uint256) -func (_ProviderRegistry *ProviderRegistryCaller) ProviderMinStake(opts *bind.CallOpts) (*big.Int, error) { - var out []interface{} - err := _ProviderRegistry.contract.Call(opts, &out, "providerMinStake") - - if err != nil { - return *new(*big.Int), err - } - - out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - - return out0, err - -} - -// ProviderMinStake is a free data retrieval call binding the contract method 0xbcd5641e. -// -// Solidity: function providerMinStake() view returns(uint256) -func (_ProviderRegistry *ProviderRegistrySession) ProviderMinStake() (*big.Int, error) { - return _ProviderRegistry.Contract.ProviderMinStake(&_ProviderRegistry.CallOpts) -} - -// ProviderMinStake is a free data retrieval call binding the contract method 0xbcd5641e. -// -// Solidity: function providerMinStake() view returns(uint256) -func (_ProviderRegistry *ProviderRegistryCallerSession) ProviderMinStake() (*big.Int, error) { - return _ProviderRegistry.Contract.ProviderMinStake(&_ProviderRegistry.CallOpts) -} - -// Providers is a free data retrieval call binding the contract method 0x50f3fc81. -// -// Solidity: function providers(uint256 index) view returns(address) -func (_ProviderRegistry *ProviderRegistryCaller) Providers(opts *bind.CallOpts, index *big.Int) (common.Address, error) { - var out []interface{} - err := _ProviderRegistry.contract.Call(opts, &out, "providers", index) - - if err != nil { - return *new(common.Address), err - } - - out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) - - return out0, err - -} - -// Providers is a free data retrieval call binding the contract method 0x50f3fc81. -// -// Solidity: function providers(uint256 index) view returns(address) -func (_ProviderRegistry *ProviderRegistrySession) Providers(index *big.Int) (common.Address, error) { - return _ProviderRegistry.Contract.Providers(&_ProviderRegistry.CallOpts, index) -} - -// Providers is a free data retrieval call binding the contract method 0x50f3fc81. -// -// Solidity: function providers(uint256 index) view returns(address) -func (_ProviderRegistry *ProviderRegistryCallerSession) Providers(index *big.Int) (common.Address, error) { - return _ProviderRegistry.Contract.Providers(&_ProviderRegistry.CallOpts, index) -} - -// ProviderDeregister is a paid mutator transaction binding the contract method 0x2ca36c49. -// -// Solidity: function providerDeregister(address addr) returns() -func (_ProviderRegistry *ProviderRegistryTransactor) ProviderDeregister(opts *bind.TransactOpts, addr common.Address) (*types.Transaction, error) { - return _ProviderRegistry.contract.Transact(opts, "providerDeregister", addr) -} - -// ProviderDeregister is a paid mutator transaction binding the contract method 0x2ca36c49. -// -// Solidity: function providerDeregister(address addr) returns() -func (_ProviderRegistry *ProviderRegistrySession) ProviderDeregister(addr common.Address) (*types.Transaction, error) { - return _ProviderRegistry.Contract.ProviderDeregister(&_ProviderRegistry.TransactOpts, addr) -} - -// ProviderDeregister is a paid mutator transaction binding the contract method 0x2ca36c49. -// -// Solidity: function providerDeregister(address addr) returns() -func (_ProviderRegistry *ProviderRegistryTransactorSession) ProviderDeregister(addr common.Address) (*types.Transaction, error) { - return _ProviderRegistry.Contract.ProviderDeregister(&_ProviderRegistry.TransactOpts, addr) -} - -// ProviderRegister is a paid mutator transaction binding the contract method 0x365700cb. -// -// Solidity: function providerRegister(address addr, uint256 addStake, string endpoint) returns() -func (_ProviderRegistry *ProviderRegistryTransactor) ProviderRegister(opts *bind.TransactOpts, addr common.Address, addStake *big.Int, endpoint string) (*types.Transaction, error) { - return _ProviderRegistry.contract.Transact(opts, "providerRegister", addr, addStake, endpoint) -} - -// ProviderRegister is a paid mutator transaction binding the contract method 0x365700cb. -// -// Solidity: function providerRegister(address addr, uint256 addStake, string endpoint) returns() -func (_ProviderRegistry *ProviderRegistrySession) ProviderRegister(addr common.Address, addStake *big.Int, endpoint string) (*types.Transaction, error) { - return _ProviderRegistry.Contract.ProviderRegister(&_ProviderRegistry.TransactOpts, addr, addStake, endpoint) -} - -// ProviderRegister is a paid mutator transaction binding the contract method 0x365700cb. -// -// Solidity: function providerRegister(address addr, uint256 addStake, string endpoint) returns() -func (_ProviderRegistry *ProviderRegistryTransactorSession) ProviderRegister(addr common.Address, addStake *big.Int, endpoint string) (*types.Transaction, error) { - return _ProviderRegistry.Contract.ProviderRegister(&_ProviderRegistry.TransactOpts, addr, addStake, endpoint) -} - -// ProviderSetMinStake is a paid mutator transaction binding the contract method 0x0b7f94d6. -// -// Solidity: function providerSetMinStake(uint256 _minStake) returns() -func (_ProviderRegistry *ProviderRegistryTransactor) ProviderSetMinStake(opts *bind.TransactOpts, _minStake *big.Int) (*types.Transaction, error) { - return _ProviderRegistry.contract.Transact(opts, "providerSetMinStake", _minStake) -} - -// ProviderSetMinStake is a paid mutator transaction binding the contract method 0x0b7f94d6. -// -// Solidity: function providerSetMinStake(uint256 _minStake) returns() -func (_ProviderRegistry *ProviderRegistrySession) ProviderSetMinStake(_minStake *big.Int) (*types.Transaction, error) { - return _ProviderRegistry.Contract.ProviderSetMinStake(&_ProviderRegistry.TransactOpts, _minStake) -} - -// ProviderSetMinStake is a paid mutator transaction binding the contract method 0x0b7f94d6. -// -// Solidity: function providerSetMinStake(uint256 _minStake) returns() -func (_ProviderRegistry *ProviderRegistryTransactorSession) ProviderSetMinStake(_minStake *big.Int) (*types.Transaction, error) { - return _ProviderRegistry.Contract.ProviderSetMinStake(&_ProviderRegistry.TransactOpts, _minStake) -} - -// ProviderWithdrawStake is a paid mutator transaction binding the contract method 0x8209d9ed. -// -// Solidity: function providerWithdrawStake(address addr) returns() -func (_ProviderRegistry *ProviderRegistryTransactor) ProviderWithdrawStake(opts *bind.TransactOpts, addr common.Address) (*types.Transaction, error) { - return _ProviderRegistry.contract.Transact(opts, "providerWithdrawStake", addr) -} - -// ProviderWithdrawStake is a paid mutator transaction binding the contract method 0x8209d9ed. -// -// Solidity: function providerWithdrawStake(address addr) returns() -func (_ProviderRegistry *ProviderRegistrySession) ProviderWithdrawStake(addr common.Address) (*types.Transaction, error) { - return _ProviderRegistry.Contract.ProviderWithdrawStake(&_ProviderRegistry.TransactOpts, addr) -} - -// ProviderWithdrawStake is a paid mutator transaction binding the contract method 0x8209d9ed. -// -// Solidity: function providerWithdrawStake(address addr) returns() -func (_ProviderRegistry *ProviderRegistryTransactorSession) ProviderWithdrawStake(addr common.Address) (*types.Transaction, error) { - return _ProviderRegistry.Contract.ProviderWithdrawStake(&_ProviderRegistry.TransactOpts, addr) -} - -// ProviderRegistryProviderDeregisteredIterator is returned from FilterProviderDeregistered and is used to iterate over the raw logs and unpacked data for ProviderDeregistered events raised by the ProviderRegistry contract. -type ProviderRegistryProviderDeregisteredIterator struct { - Event *ProviderRegistryProviderDeregistered // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *ProviderRegistryProviderDeregisteredIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(ProviderRegistryProviderDeregistered) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(ProviderRegistryProviderDeregistered) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *ProviderRegistryProviderDeregisteredIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *ProviderRegistryProviderDeregisteredIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// ProviderRegistryProviderDeregistered represents a ProviderDeregistered event raised by the ProviderRegistry contract. -type ProviderRegistryProviderDeregistered struct { - Provider common.Address - Raw types.Log // Blockchain specific contextual infos -} - -// FilterProviderDeregistered is a free log retrieval operation binding the contract event 0xf04091b4a187e321a42001e46961e45b6a75b203fc6fb766b7e05505f6080abb. -// -// Solidity: event ProviderDeregistered(address indexed provider) -func (_ProviderRegistry *ProviderRegistryFilterer) FilterProviderDeregistered(opts *bind.FilterOpts, provider []common.Address) (*ProviderRegistryProviderDeregisteredIterator, error) { - - var providerRule []interface{} - for _, providerItem := range provider { - providerRule = append(providerRule, providerItem) - } - - logs, sub, err := _ProviderRegistry.contract.FilterLogs(opts, "ProviderDeregistered", providerRule) - if err != nil { - return nil, err - } - return &ProviderRegistryProviderDeregisteredIterator{contract: _ProviderRegistry.contract, event: "ProviderDeregistered", logs: logs, sub: sub}, nil -} - -// WatchProviderDeregistered is a free log subscription operation binding the contract event 0xf04091b4a187e321a42001e46961e45b6a75b203fc6fb766b7e05505f6080abb. -// -// Solidity: event ProviderDeregistered(address indexed provider) -func (_ProviderRegistry *ProviderRegistryFilterer) WatchProviderDeregistered(opts *bind.WatchOpts, sink chan<- *ProviderRegistryProviderDeregistered, provider []common.Address) (event.Subscription, error) { - - var providerRule []interface{} - for _, providerItem := range provider { - providerRule = append(providerRule, providerItem) - } - - logs, sub, err := _ProviderRegistry.contract.WatchLogs(opts, "ProviderDeregistered", providerRule) - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(ProviderRegistryProviderDeregistered) - if err := _ProviderRegistry.contract.UnpackLog(event, "ProviderDeregistered", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// ParseProviderDeregistered is a log parse operation binding the contract event 0xf04091b4a187e321a42001e46961e45b6a75b203fc6fb766b7e05505f6080abb. -// -// Solidity: event ProviderDeregistered(address indexed provider) -func (_ProviderRegistry *ProviderRegistryFilterer) ParseProviderDeregistered(log types.Log) (*ProviderRegistryProviderDeregistered, error) { - event := new(ProviderRegistryProviderDeregistered) - if err := _ProviderRegistry.contract.UnpackLog(event, "ProviderDeregistered", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -// ProviderRegistryProviderMinStakeUpdatedIterator is returned from FilterProviderMinStakeUpdated and is used to iterate over the raw logs and unpacked data for ProviderMinStakeUpdated events raised by the ProviderRegistry contract. -type ProviderRegistryProviderMinStakeUpdatedIterator struct { - Event *ProviderRegistryProviderMinStakeUpdated // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *ProviderRegistryProviderMinStakeUpdatedIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(ProviderRegistryProviderMinStakeUpdated) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(ProviderRegistryProviderMinStakeUpdated) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *ProviderRegistryProviderMinStakeUpdatedIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *ProviderRegistryProviderMinStakeUpdatedIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// ProviderRegistryProviderMinStakeUpdated represents a ProviderMinStakeUpdated event raised by the ProviderRegistry contract. -type ProviderRegistryProviderMinStakeUpdated struct { - NewStake *big.Int - Raw types.Log // Blockchain specific contextual infos -} - -// FilterProviderMinStakeUpdated is a free log retrieval operation binding the contract event 0x1ee852018221ad3e0f9b96b4d6f870d0e1393c4060f626c01ad1e09a1917d818. -// -// Solidity: event ProviderMinStakeUpdated(uint256 newStake) -func (_ProviderRegistry *ProviderRegistryFilterer) FilterProviderMinStakeUpdated(opts *bind.FilterOpts) (*ProviderRegistryProviderMinStakeUpdatedIterator, error) { - - logs, sub, err := _ProviderRegistry.contract.FilterLogs(opts, "ProviderMinStakeUpdated") - if err != nil { - return nil, err - } - return &ProviderRegistryProviderMinStakeUpdatedIterator{contract: _ProviderRegistry.contract, event: "ProviderMinStakeUpdated", logs: logs, sub: sub}, nil -} - -// WatchProviderMinStakeUpdated is a free log subscription operation binding the contract event 0x1ee852018221ad3e0f9b96b4d6f870d0e1393c4060f626c01ad1e09a1917d818. -// -// Solidity: event ProviderMinStakeUpdated(uint256 newStake) -func (_ProviderRegistry *ProviderRegistryFilterer) WatchProviderMinStakeUpdated(opts *bind.WatchOpts, sink chan<- *ProviderRegistryProviderMinStakeUpdated) (event.Subscription, error) { - - logs, sub, err := _ProviderRegistry.contract.WatchLogs(opts, "ProviderMinStakeUpdated") - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(ProviderRegistryProviderMinStakeUpdated) - if err := _ProviderRegistry.contract.UnpackLog(event, "ProviderMinStakeUpdated", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// ParseProviderMinStakeUpdated is a log parse operation binding the contract event 0x1ee852018221ad3e0f9b96b4d6f870d0e1393c4060f626c01ad1e09a1917d818. -// -// Solidity: event ProviderMinStakeUpdated(uint256 newStake) -func (_ProviderRegistry *ProviderRegistryFilterer) ParseProviderMinStakeUpdated(log types.Log) (*ProviderRegistryProviderMinStakeUpdated, error) { - event := new(ProviderRegistryProviderMinStakeUpdated) - if err := _ProviderRegistry.contract.UnpackLog(event, "ProviderMinStakeUpdated", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -// ProviderRegistryProviderRegisteredUpdatedIterator is returned from FilterProviderRegisteredUpdated and is used to iterate over the raw logs and unpacked data for ProviderRegisteredUpdated events raised by the ProviderRegistry contract. -type ProviderRegistryProviderRegisteredUpdatedIterator struct { - Event *ProviderRegistryProviderRegisteredUpdated // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *ProviderRegistryProviderRegisteredUpdatedIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(ProviderRegistryProviderRegisteredUpdated) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(ProviderRegistryProviderRegisteredUpdated) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *ProviderRegistryProviderRegisteredUpdatedIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *ProviderRegistryProviderRegisteredUpdatedIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// ProviderRegistryProviderRegisteredUpdated represents a ProviderRegisteredUpdated event raised by the ProviderRegistry contract. -type ProviderRegistryProviderRegisteredUpdated struct { - Provider common.Address - Raw types.Log // Blockchain specific contextual infos -} - -// FilterProviderRegisteredUpdated is a free log retrieval operation binding the contract event 0xe041bebe929cc665c6c558e3ad7913156fef3abc77ac6a2a4f0182e6dcb11193. -// -// Solidity: event ProviderRegisteredUpdated(address indexed provider) -func (_ProviderRegistry *ProviderRegistryFilterer) FilterProviderRegisteredUpdated(opts *bind.FilterOpts, provider []common.Address) (*ProviderRegistryProviderRegisteredUpdatedIterator, error) { - - var providerRule []interface{} - for _, providerItem := range provider { - providerRule = append(providerRule, providerItem) - } - - logs, sub, err := _ProviderRegistry.contract.FilterLogs(opts, "ProviderRegisteredUpdated", providerRule) - if err != nil { - return nil, err - } - return &ProviderRegistryProviderRegisteredUpdatedIterator{contract: _ProviderRegistry.contract, event: "ProviderRegisteredUpdated", logs: logs, sub: sub}, nil -} - -// WatchProviderRegisteredUpdated is a free log subscription operation binding the contract event 0xe041bebe929cc665c6c558e3ad7913156fef3abc77ac6a2a4f0182e6dcb11193. -// -// Solidity: event ProviderRegisteredUpdated(address indexed provider) -func (_ProviderRegistry *ProviderRegistryFilterer) WatchProviderRegisteredUpdated(opts *bind.WatchOpts, sink chan<- *ProviderRegistryProviderRegisteredUpdated, provider []common.Address) (event.Subscription, error) { - - var providerRule []interface{} - for _, providerItem := range provider { - providerRule = append(providerRule, providerItem) - } - - logs, sub, err := _ProviderRegistry.contract.WatchLogs(opts, "ProviderRegisteredUpdated", providerRule) - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(ProviderRegistryProviderRegisteredUpdated) - if err := _ProviderRegistry.contract.UnpackLog(event, "ProviderRegisteredUpdated", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// ParseProviderRegisteredUpdated is a log parse operation binding the contract event 0xe041bebe929cc665c6c558e3ad7913156fef3abc77ac6a2a4f0182e6dcb11193. -// -// Solidity: event ProviderRegisteredUpdated(address indexed provider) -func (_ProviderRegistry *ProviderRegistryFilterer) ParseProviderRegisteredUpdated(log types.Log) (*ProviderRegistryProviderRegisteredUpdated, error) { - event := new(ProviderRegistryProviderRegisteredUpdated) - if err := _ProviderRegistry.contract.UnpackLog(event, "ProviderRegisteredUpdated", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} diff --git a/proxy-router/contracts/sessionrouter/SessionRouter.go b/proxy-router/contracts/sessionrouter/SessionRouter.go deleted file mode 100644 index 65e6a0a1..00000000 --- a/proxy-router/contracts/sessionrouter/SessionRouter.go +++ /dev/null @@ -1,1259 +0,0 @@ -// Code generated - DO NOT EDIT. -// This file is a generated binding and any manual changes will be lost. - -package sessionrouter - -import ( - "errors" - "math/big" - "strings" - - ethereum "github.com/ethereum/go-ethereum" - "github.com/ethereum/go-ethereum/accounts/abi" - "github.com/ethereum/go-ethereum/accounts/abi/bind" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/event" -) - -// Reference imports to suppress errors if they are not otherwise used. -var ( - _ = errors.New - _ = big.NewInt - _ = strings.NewReader - _ = ethereum.NotFound - _ = bind.Bind - _ = common.Big1 - _ = types.BloomLookup - _ = event.NewSubscription - _ = abi.ConvertType -) - -// Pool is an auto generated low-level Go binding around an user-defined struct. -type Pool struct { - InitialReward *big.Int - RewardDecrease *big.Int - PayoutStart *big.Int - DecreaseInterval *big.Int -} - -// Session is an auto generated low-level Go binding around an user-defined struct. -type Session struct { - Id [32]byte - User common.Address - Provider common.Address - ModelAgentId [32]byte - BidID [32]byte - Stake *big.Int - PricePerSecond *big.Int - CloseoutReceipt []byte - CloseoutType *big.Int - ProviderWithdrawnAmount *big.Int - OpenedAt *big.Int - EndsAt *big.Int - ClosedAt *big.Int -} - -// SessionRouterMetaData contains all meta data concerning the SessionRouter contract. -var SessionRouterMetaData = &bind.MetaData{ - ABI: "[{\"inputs\":[],\"name\":\"ApprovedForAnotherUser\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"BidNotFound\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"CannotDecodeAbi\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DuplicateApproval\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ECDSAInvalidSignature\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"length\",\"type\":\"uint256\"}],\"name\":\"ECDSAInvalidSignatureLength\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"s\",\"type\":\"bytes32\"}],\"name\":\"ECDSAInvalidSignatureS\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"KeyExists\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"KeyNotFound\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_user\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_contractOwner\",\"type\":\"address\"}],\"name\":\"NotContractOwner\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NotEnoughWithdrawableBalance\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NotSenderOrOwner\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ProviderSignatureMismatch\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"SessionAlreadyClosed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"SessionNotClosed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"SessionNotFound\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"SessionTooShort\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"SignatureExpired\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"WithdrawableBalanceLimitByStakeReached\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"WrongChaidId\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"userAddress\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"sessionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"providerId\",\"type\":\"address\"}],\"name\":\"SessionClosed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"userAddress\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"sessionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"providerId\",\"type\":\"address\"}],\"name\":\"SessionOpened\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"MAX_SESSION_DURATION\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"MIN_SESSION_DURATION\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"SIGNATURE_TTL\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"activeSessionsCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"sessionId\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"amountToWithdraw\",\"type\":\"uint256\"}],\"name\":\"claimProviderBalance\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"receiptEncoded\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"signature\",\"type\":\"bytes\"}],\"name\":\"closeSession\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"sessionId\",\"type\":\"bytes32\"}],\"name\":\"deleteHistory\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"provider\",\"type\":\"address\"}],\"name\":\"getActiveSessionsByProvider\",\"outputs\":[{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"id\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"user\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"provider\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"modelAgentId\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"bidID\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"stake\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"pricePerSecond\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"closeoutReceipt\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"closeoutType\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"providerWithdrawnAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"openedAt\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"endsAt\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"closedAt\",\"type\":\"uint256\"}],\"internalType\":\"structSession[]\",\"name\":\"\",\"type\":\"tuple[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"user\",\"type\":\"address\"}],\"name\":\"getActiveSessionsByUser\",\"outputs\":[{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"id\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"user\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"provider\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"modelAgentId\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"bidID\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"stake\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"pricePerSecond\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"closeoutReceipt\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"closeoutType\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"providerWithdrawnAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"openedAt\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"endsAt\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"closedAt\",\"type\":\"uint256\"}],\"internalType\":\"structSession[]\",\"name\":\"\",\"type\":\"tuple[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"timestamp\",\"type\":\"uint256\"}],\"name\":\"getComputeBalance\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"sessionId\",\"type\":\"bytes32\"}],\"name\":\"getProviderClaimableBalance\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"sessionId\",\"type\":\"bytes32\"}],\"name\":\"getSession\",\"outputs\":[{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"id\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"user\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"provider\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"modelAgentId\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"bidID\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"stake\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"pricePerSecond\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"closeoutReceipt\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"closeoutType\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"providerWithdrawnAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"openedAt\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"endsAt\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"closedAt\",\"type\":\"uint256\"}],\"internalType\":\"structSession\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"modelId\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"offset\",\"type\":\"uint256\"},{\"internalType\":\"uint8\",\"name\":\"limit\",\"type\":\"uint8\"}],\"name\":\"getSessionsByModel\",\"outputs\":[{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"id\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"user\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"provider\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"modelAgentId\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"bidID\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"stake\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"pricePerSecond\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"closeoutReceipt\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"closeoutType\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"providerWithdrawnAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"openedAt\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"endsAt\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"closedAt\",\"type\":\"uint256\"}],\"internalType\":\"structSession[]\",\"name\":\"\",\"type\":\"tuple[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"provider\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"offset\",\"type\":\"uint256\"},{\"internalType\":\"uint8\",\"name\":\"limit\",\"type\":\"uint8\"}],\"name\":\"getSessionsByProvider\",\"outputs\":[{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"id\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"user\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"provider\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"modelAgentId\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"bidID\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"stake\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"pricePerSecond\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"closeoutReceipt\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"closeoutType\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"providerWithdrawnAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"openedAt\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"endsAt\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"closedAt\",\"type\":\"uint256\"}],\"internalType\":\"structSession[]\",\"name\":\"\",\"type\":\"tuple[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"user\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"offset\",\"type\":\"uint256\"},{\"internalType\":\"uint8\",\"name\":\"limit\",\"type\":\"uint8\"}],\"name\":\"getSessionsByUser\",\"outputs\":[{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"id\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"user\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"provider\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"modelAgentId\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"bidID\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"stake\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"pricePerSecond\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"closeoutReceipt\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"closeoutType\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"providerWithdrawnAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"openedAt\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"endsAt\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"closedAt\",\"type\":\"uint256\"}],\"internalType\":\"structSession[]\",\"name\":\"\",\"type\":\"tuple[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"timestamp\",\"type\":\"uint256\"}],\"name\":\"getTodaysBudget\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_stake\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"providerApproval\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"signature\",\"type\":\"bytes\"}],\"name\":\"openSession\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"sessionId\",\"type\":\"bytes32\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"sessionsCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"index\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"initialReward\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"rewardDecrease\",\"type\":\"uint256\"},{\"internalType\":\"uint128\",\"name\":\"payoutStart\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"decreaseInterval\",\"type\":\"uint128\"}],\"internalType\":\"structPool\",\"name\":\"pool\",\"type\":\"tuple\"}],\"name\":\"setPoolConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"sessionStake\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"timestamp\",\"type\":\"uint256\"}],\"name\":\"stakeToStipend\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"stipend\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"timestamp\",\"type\":\"uint256\"}],\"name\":\"stipendToStake\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"timestamp\",\"type\":\"uint256\"}],\"name\":\"totalMORSupply\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"sessionStake\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"pricePerSecond\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"openedAt\",\"type\":\"uint256\"}],\"name\":\"whenSessionEnds\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"amountToWithdraw\",\"type\":\"uint256\"},{\"internalType\":\"uint8\",\"name\":\"iterations\",\"type\":\"uint8\"}],\"name\":\"withdrawUserStake\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"userAddr\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"offset\",\"type\":\"uint256\"},{\"internalType\":\"uint8\",\"name\":\"limit\",\"type\":\"uint8\"}],\"name\":\"withdrawableUserStake\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"avail\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"hold\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]", -} - -// SessionRouterABI is the input ABI used to generate the binding from. -// Deprecated: Use SessionRouterMetaData.ABI instead. -var SessionRouterABI = SessionRouterMetaData.ABI - -// SessionRouter is an auto generated Go binding around an Ethereum contract. -type SessionRouter struct { - SessionRouterCaller // Read-only binding to the contract - SessionRouterTransactor // Write-only binding to the contract - SessionRouterFilterer // Log filterer for contract events -} - -// SessionRouterCaller is an auto generated read-only Go binding around an Ethereum contract. -type SessionRouterCaller struct { - contract *bind.BoundContract // Generic contract wrapper for the low level calls -} - -// SessionRouterTransactor is an auto generated write-only Go binding around an Ethereum contract. -type SessionRouterTransactor struct { - contract *bind.BoundContract // Generic contract wrapper for the low level calls -} - -// SessionRouterFilterer is an auto generated log filtering Go binding around an Ethereum contract events. -type SessionRouterFilterer struct { - contract *bind.BoundContract // Generic contract wrapper for the low level calls -} - -// SessionRouterSession is an auto generated Go binding around an Ethereum contract, -// with pre-set call and transact options. -type SessionRouterSession struct { - Contract *SessionRouter // Generic contract binding to set the session for - CallOpts bind.CallOpts // Call options to use throughout this session - TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session -} - -// SessionRouterCallerSession is an auto generated read-only Go binding around an Ethereum contract, -// with pre-set call options. -type SessionRouterCallerSession struct { - Contract *SessionRouterCaller // Generic contract caller binding to set the session for - CallOpts bind.CallOpts // Call options to use throughout this session -} - -// SessionRouterTransactorSession is an auto generated write-only Go binding around an Ethereum contract, -// with pre-set transact options. -type SessionRouterTransactorSession struct { - Contract *SessionRouterTransactor // Generic contract transactor binding to set the session for - TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session -} - -// SessionRouterRaw is an auto generated low-level Go binding around an Ethereum contract. -type SessionRouterRaw struct { - Contract *SessionRouter // Generic contract binding to access the raw methods on -} - -// SessionRouterCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. -type SessionRouterCallerRaw struct { - Contract *SessionRouterCaller // Generic read-only contract binding to access the raw methods on -} - -// SessionRouterTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. -type SessionRouterTransactorRaw struct { - Contract *SessionRouterTransactor // Generic write-only contract binding to access the raw methods on -} - -// NewSessionRouter creates a new instance of SessionRouter, bound to a specific deployed contract. -func NewSessionRouter(address common.Address, backend bind.ContractBackend) (*SessionRouter, error) { - contract, err := bindSessionRouter(address, backend, backend, backend) - if err != nil { - return nil, err - } - return &SessionRouter{SessionRouterCaller: SessionRouterCaller{contract: contract}, SessionRouterTransactor: SessionRouterTransactor{contract: contract}, SessionRouterFilterer: SessionRouterFilterer{contract: contract}}, nil -} - -// NewSessionRouterCaller creates a new read-only instance of SessionRouter, bound to a specific deployed contract. -func NewSessionRouterCaller(address common.Address, caller bind.ContractCaller) (*SessionRouterCaller, error) { - contract, err := bindSessionRouter(address, caller, nil, nil) - if err != nil { - return nil, err - } - return &SessionRouterCaller{contract: contract}, nil -} - -// NewSessionRouterTransactor creates a new write-only instance of SessionRouter, bound to a specific deployed contract. -func NewSessionRouterTransactor(address common.Address, transactor bind.ContractTransactor) (*SessionRouterTransactor, error) { - contract, err := bindSessionRouter(address, nil, transactor, nil) - if err != nil { - return nil, err - } - return &SessionRouterTransactor{contract: contract}, nil -} - -// NewSessionRouterFilterer creates a new log filterer instance of SessionRouter, bound to a specific deployed contract. -func NewSessionRouterFilterer(address common.Address, filterer bind.ContractFilterer) (*SessionRouterFilterer, error) { - contract, err := bindSessionRouter(address, nil, nil, filterer) - if err != nil { - return nil, err - } - return &SessionRouterFilterer{contract: contract}, nil -} - -// bindSessionRouter binds a generic wrapper to an already deployed contract. -func bindSessionRouter(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { - parsed, err := SessionRouterMetaData.GetAbi() - if err != nil { - return nil, err - } - return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil -} - -// Call invokes the (constant) contract method with params as input values and -// sets the output to result. The result type might be a single field for simple -// returns, a slice of interfaces for anonymous returns and a struct for named -// returns. -func (_SessionRouter *SessionRouterRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { - return _SessionRouter.Contract.SessionRouterCaller.contract.Call(opts, result, method, params...) -} - -// Transfer initiates a plain transaction to move funds to the contract, calling -// its default method if one is available. -func (_SessionRouter *SessionRouterRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { - return _SessionRouter.Contract.SessionRouterTransactor.contract.Transfer(opts) -} - -// Transact invokes the (paid) contract method with params as input values. -func (_SessionRouter *SessionRouterRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { - return _SessionRouter.Contract.SessionRouterTransactor.contract.Transact(opts, method, params...) -} - -// Call invokes the (constant) contract method with params as input values and -// sets the output to result. The result type might be a single field for simple -// returns, a slice of interfaces for anonymous returns and a struct for named -// returns. -func (_SessionRouter *SessionRouterCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { - return _SessionRouter.Contract.contract.Call(opts, result, method, params...) -} - -// Transfer initiates a plain transaction to move funds to the contract, calling -// its default method if one is available. -func (_SessionRouter *SessionRouterTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { - return _SessionRouter.Contract.contract.Transfer(opts) -} - -// Transact invokes the (paid) contract method with params as input values. -func (_SessionRouter *SessionRouterTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { - return _SessionRouter.Contract.contract.Transact(opts, method, params...) -} - -// MAXSESSIONDURATION is a free data retrieval call binding the contract method 0xcd8cd4ad. -// -// Solidity: function MAX_SESSION_DURATION() view returns(uint32) -func (_SessionRouter *SessionRouterCaller) MAXSESSIONDURATION(opts *bind.CallOpts) (uint32, error) { - var out []interface{} - err := _SessionRouter.contract.Call(opts, &out, "MAX_SESSION_DURATION") - - if err != nil { - return *new(uint32), err - } - - out0 := *abi.ConvertType(out[0], new(uint32)).(*uint32) - - return out0, err - -} - -// MAXSESSIONDURATION is a free data retrieval call binding the contract method 0xcd8cd4ad. -// -// Solidity: function MAX_SESSION_DURATION() view returns(uint32) -func (_SessionRouter *SessionRouterSession) MAXSESSIONDURATION() (uint32, error) { - return _SessionRouter.Contract.MAXSESSIONDURATION(&_SessionRouter.CallOpts) -} - -// MAXSESSIONDURATION is a free data retrieval call binding the contract method 0xcd8cd4ad. -// -// Solidity: function MAX_SESSION_DURATION() view returns(uint32) -func (_SessionRouter *SessionRouterCallerSession) MAXSESSIONDURATION() (uint32, error) { - return _SessionRouter.Contract.MAXSESSIONDURATION(&_SessionRouter.CallOpts) -} - -// MINSESSIONDURATION is a free data retrieval call binding the contract method 0x7d980286. -// -// Solidity: function MIN_SESSION_DURATION() view returns(uint32) -func (_SessionRouter *SessionRouterCaller) MINSESSIONDURATION(opts *bind.CallOpts) (uint32, error) { - var out []interface{} - err := _SessionRouter.contract.Call(opts, &out, "MIN_SESSION_DURATION") - - if err != nil { - return *new(uint32), err - } - - out0 := *abi.ConvertType(out[0], new(uint32)).(*uint32) - - return out0, err - -} - -// MINSESSIONDURATION is a free data retrieval call binding the contract method 0x7d980286. -// -// Solidity: function MIN_SESSION_DURATION() view returns(uint32) -func (_SessionRouter *SessionRouterSession) MINSESSIONDURATION() (uint32, error) { - return _SessionRouter.Contract.MINSESSIONDURATION(&_SessionRouter.CallOpts) -} - -// MINSESSIONDURATION is a free data retrieval call binding the contract method 0x7d980286. -// -// Solidity: function MIN_SESSION_DURATION() view returns(uint32) -func (_SessionRouter *SessionRouterCallerSession) MINSESSIONDURATION() (uint32, error) { - return _SessionRouter.Contract.MINSESSIONDURATION(&_SessionRouter.CallOpts) -} - -// SIGNATURETTL is a free data retrieval call binding the contract method 0xe7d791d0. -// -// Solidity: function SIGNATURE_TTL() view returns(uint32) -func (_SessionRouter *SessionRouterCaller) SIGNATURETTL(opts *bind.CallOpts) (uint32, error) { - var out []interface{} - err := _SessionRouter.contract.Call(opts, &out, "SIGNATURE_TTL") - - if err != nil { - return *new(uint32), err - } - - out0 := *abi.ConvertType(out[0], new(uint32)).(*uint32) - - return out0, err - -} - -// SIGNATURETTL is a free data retrieval call binding the contract method 0xe7d791d0. -// -// Solidity: function SIGNATURE_TTL() view returns(uint32) -func (_SessionRouter *SessionRouterSession) SIGNATURETTL() (uint32, error) { - return _SessionRouter.Contract.SIGNATURETTL(&_SessionRouter.CallOpts) -} - -// SIGNATURETTL is a free data retrieval call binding the contract method 0xe7d791d0. -// -// Solidity: function SIGNATURE_TTL() view returns(uint32) -func (_SessionRouter *SessionRouterCallerSession) SIGNATURETTL() (uint32, error) { - return _SessionRouter.Contract.SIGNATURETTL(&_SessionRouter.CallOpts) -} - -// ActiveSessionsCount is a free data retrieval call binding the contract method 0x782ea85c. -// -// Solidity: function activeSessionsCount() view returns(uint256) -func (_SessionRouter *SessionRouterCaller) ActiveSessionsCount(opts *bind.CallOpts) (*big.Int, error) { - var out []interface{} - err := _SessionRouter.contract.Call(opts, &out, "activeSessionsCount") - - if err != nil { - return *new(*big.Int), err - } - - out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - - return out0, err - -} - -// ActiveSessionsCount is a free data retrieval call binding the contract method 0x782ea85c. -// -// Solidity: function activeSessionsCount() view returns(uint256) -func (_SessionRouter *SessionRouterSession) ActiveSessionsCount() (*big.Int, error) { - return _SessionRouter.Contract.ActiveSessionsCount(&_SessionRouter.CallOpts) -} - -// ActiveSessionsCount is a free data retrieval call binding the contract method 0x782ea85c. -// -// Solidity: function activeSessionsCount() view returns(uint256) -func (_SessionRouter *SessionRouterCallerSession) ActiveSessionsCount() (*big.Int, error) { - return _SessionRouter.Contract.ActiveSessionsCount(&_SessionRouter.CallOpts) -} - -// GetActiveSessionsByProvider is a free data retrieval call binding the contract method 0xcba645ab. -// -// Solidity: function getActiveSessionsByProvider(address provider) view returns((bytes32,address,address,bytes32,bytes32,uint256,uint256,bytes,uint256,uint256,uint256,uint256,uint256)[]) -func (_SessionRouter *SessionRouterCaller) GetActiveSessionsByProvider(opts *bind.CallOpts, provider common.Address) ([]Session, error) { - var out []interface{} - err := _SessionRouter.contract.Call(opts, &out, "getActiveSessionsByProvider", provider) - - if err != nil { - return *new([]Session), err - } - - out0 := *abi.ConvertType(out[0], new([]Session)).(*[]Session) - - return out0, err - -} - -// GetActiveSessionsByProvider is a free data retrieval call binding the contract method 0xcba645ab. -// -// Solidity: function getActiveSessionsByProvider(address provider) view returns((bytes32,address,address,bytes32,bytes32,uint256,uint256,bytes,uint256,uint256,uint256,uint256,uint256)[]) -func (_SessionRouter *SessionRouterSession) GetActiveSessionsByProvider(provider common.Address) ([]Session, error) { - return _SessionRouter.Contract.GetActiveSessionsByProvider(&_SessionRouter.CallOpts, provider) -} - -// GetActiveSessionsByProvider is a free data retrieval call binding the contract method 0xcba645ab. -// -// Solidity: function getActiveSessionsByProvider(address provider) view returns((bytes32,address,address,bytes32,bytes32,uint256,uint256,bytes,uint256,uint256,uint256,uint256,uint256)[]) -func (_SessionRouter *SessionRouterCallerSession) GetActiveSessionsByProvider(provider common.Address) ([]Session, error) { - return _SessionRouter.Contract.GetActiveSessionsByProvider(&_SessionRouter.CallOpts, provider) -} - -// GetActiveSessionsByUser is a free data retrieval call binding the contract method 0xb3da8c38. -// -// Solidity: function getActiveSessionsByUser(address user) view returns((bytes32,address,address,bytes32,bytes32,uint256,uint256,bytes,uint256,uint256,uint256,uint256,uint256)[]) -func (_SessionRouter *SessionRouterCaller) GetActiveSessionsByUser(opts *bind.CallOpts, user common.Address) ([]Session, error) { - var out []interface{} - err := _SessionRouter.contract.Call(opts, &out, "getActiveSessionsByUser", user) - - if err != nil { - return *new([]Session), err - } - - out0 := *abi.ConvertType(out[0], new([]Session)).(*[]Session) - - return out0, err - -} - -// GetActiveSessionsByUser is a free data retrieval call binding the contract method 0xb3da8c38. -// -// Solidity: function getActiveSessionsByUser(address user) view returns((bytes32,address,address,bytes32,bytes32,uint256,uint256,bytes,uint256,uint256,uint256,uint256,uint256)[]) -func (_SessionRouter *SessionRouterSession) GetActiveSessionsByUser(user common.Address) ([]Session, error) { - return _SessionRouter.Contract.GetActiveSessionsByUser(&_SessionRouter.CallOpts, user) -} - -// GetActiveSessionsByUser is a free data retrieval call binding the contract method 0xb3da8c38. -// -// Solidity: function getActiveSessionsByUser(address user) view returns((bytes32,address,address,bytes32,bytes32,uint256,uint256,bytes,uint256,uint256,uint256,uint256,uint256)[]) -func (_SessionRouter *SessionRouterCallerSession) GetActiveSessionsByUser(user common.Address) ([]Session, error) { - return _SessionRouter.Contract.GetActiveSessionsByUser(&_SessionRouter.CallOpts, user) -} - -// GetComputeBalance is a free data retrieval call binding the contract method 0x76738e9e. -// -// Solidity: function getComputeBalance(uint256 timestamp) view returns(uint256) -func (_SessionRouter *SessionRouterCaller) GetComputeBalance(opts *bind.CallOpts, timestamp *big.Int) (*big.Int, error) { - var out []interface{} - err := _SessionRouter.contract.Call(opts, &out, "getComputeBalance", timestamp) - - if err != nil { - return *new(*big.Int), err - } - - out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - - return out0, err - -} - -// GetComputeBalance is a free data retrieval call binding the contract method 0x76738e9e. -// -// Solidity: function getComputeBalance(uint256 timestamp) view returns(uint256) -func (_SessionRouter *SessionRouterSession) GetComputeBalance(timestamp *big.Int) (*big.Int, error) { - return _SessionRouter.Contract.GetComputeBalance(&_SessionRouter.CallOpts, timestamp) -} - -// GetComputeBalance is a free data retrieval call binding the contract method 0x76738e9e. -// -// Solidity: function getComputeBalance(uint256 timestamp) view returns(uint256) -func (_SessionRouter *SessionRouterCallerSession) GetComputeBalance(timestamp *big.Int) (*big.Int, error) { - return _SessionRouter.Contract.GetComputeBalance(&_SessionRouter.CallOpts, timestamp) -} - -// GetProviderClaimableBalance is a free data retrieval call binding the contract method 0xa8ca6323. -// -// Solidity: function getProviderClaimableBalance(bytes32 sessionId) view returns(uint256) -func (_SessionRouter *SessionRouterCaller) GetProviderClaimableBalance(opts *bind.CallOpts, sessionId [32]byte) (*big.Int, error) { - var out []interface{} - err := _SessionRouter.contract.Call(opts, &out, "getProviderClaimableBalance", sessionId) - - if err != nil { - return *new(*big.Int), err - } - - out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - - return out0, err - -} - -// GetProviderClaimableBalance is a free data retrieval call binding the contract method 0xa8ca6323. -// -// Solidity: function getProviderClaimableBalance(bytes32 sessionId) view returns(uint256) -func (_SessionRouter *SessionRouterSession) GetProviderClaimableBalance(sessionId [32]byte) (*big.Int, error) { - return _SessionRouter.Contract.GetProviderClaimableBalance(&_SessionRouter.CallOpts, sessionId) -} - -// GetProviderClaimableBalance is a free data retrieval call binding the contract method 0xa8ca6323. -// -// Solidity: function getProviderClaimableBalance(bytes32 sessionId) view returns(uint256) -func (_SessionRouter *SessionRouterCallerSession) GetProviderClaimableBalance(sessionId [32]byte) (*big.Int, error) { - return _SessionRouter.Contract.GetProviderClaimableBalance(&_SessionRouter.CallOpts, sessionId) -} - -// GetSession is a free data retrieval call binding the contract method 0x39b240bd. -// -// Solidity: function getSession(bytes32 sessionId) view returns((bytes32,address,address,bytes32,bytes32,uint256,uint256,bytes,uint256,uint256,uint256,uint256,uint256)) -func (_SessionRouter *SessionRouterCaller) GetSession(opts *bind.CallOpts, sessionId [32]byte) (Session, error) { - var out []interface{} - err := _SessionRouter.contract.Call(opts, &out, "getSession", sessionId) - - if err != nil { - return *new(Session), err - } - - out0 := *abi.ConvertType(out[0], new(Session)).(*Session) - - return out0, err - -} - -// GetSession is a free data retrieval call binding the contract method 0x39b240bd. -// -// Solidity: function getSession(bytes32 sessionId) view returns((bytes32,address,address,bytes32,bytes32,uint256,uint256,bytes,uint256,uint256,uint256,uint256,uint256)) -func (_SessionRouter *SessionRouterSession) GetSession(sessionId [32]byte) (Session, error) { - return _SessionRouter.Contract.GetSession(&_SessionRouter.CallOpts, sessionId) -} - -// GetSession is a free data retrieval call binding the contract method 0x39b240bd. -// -// Solidity: function getSession(bytes32 sessionId) view returns((bytes32,address,address,bytes32,bytes32,uint256,uint256,bytes,uint256,uint256,uint256,uint256,uint256)) -func (_SessionRouter *SessionRouterCallerSession) GetSession(sessionId [32]byte) (Session, error) { - return _SessionRouter.Contract.GetSession(&_SessionRouter.CallOpts, sessionId) -} - -// GetSessionsByModel is a free data retrieval call binding the contract method 0x67a057f6. -// -// Solidity: function getSessionsByModel(bytes32 modelId, uint256 offset, uint8 limit) view returns((bytes32,address,address,bytes32,bytes32,uint256,uint256,bytes,uint256,uint256,uint256,uint256,uint256)[]) -func (_SessionRouter *SessionRouterCaller) GetSessionsByModel(opts *bind.CallOpts, modelId [32]byte, offset *big.Int, limit uint8) ([]Session, error) { - var out []interface{} - err := _SessionRouter.contract.Call(opts, &out, "getSessionsByModel", modelId, offset, limit) - - if err != nil { - return *new([]Session), err - } - - out0 := *abi.ConvertType(out[0], new([]Session)).(*[]Session) - - return out0, err - -} - -// GetSessionsByModel is a free data retrieval call binding the contract method 0x67a057f6. -// -// Solidity: function getSessionsByModel(bytes32 modelId, uint256 offset, uint8 limit) view returns((bytes32,address,address,bytes32,bytes32,uint256,uint256,bytes,uint256,uint256,uint256,uint256,uint256)[]) -func (_SessionRouter *SessionRouterSession) GetSessionsByModel(modelId [32]byte, offset *big.Int, limit uint8) ([]Session, error) { - return _SessionRouter.Contract.GetSessionsByModel(&_SessionRouter.CallOpts, modelId, offset, limit) -} - -// GetSessionsByModel is a free data retrieval call binding the contract method 0x67a057f6. -// -// Solidity: function getSessionsByModel(bytes32 modelId, uint256 offset, uint8 limit) view returns((bytes32,address,address,bytes32,bytes32,uint256,uint256,bytes,uint256,uint256,uint256,uint256,uint256)[]) -func (_SessionRouter *SessionRouterCallerSession) GetSessionsByModel(modelId [32]byte, offset *big.Int, limit uint8) ([]Session, error) { - return _SessionRouter.Contract.GetSessionsByModel(&_SessionRouter.CallOpts, modelId, offset, limit) -} - -// GetSessionsByProvider is a free data retrieval call binding the contract method 0x8ea1ac0e. -// -// Solidity: function getSessionsByProvider(address provider, uint256 offset, uint8 limit) view returns((bytes32,address,address,bytes32,bytes32,uint256,uint256,bytes,uint256,uint256,uint256,uint256,uint256)[]) -func (_SessionRouter *SessionRouterCaller) GetSessionsByProvider(opts *bind.CallOpts, provider common.Address, offset *big.Int, limit uint8) ([]Session, error) { - var out []interface{} - err := _SessionRouter.contract.Call(opts, &out, "getSessionsByProvider", provider, offset, limit) - - if err != nil { - return *new([]Session), err - } - - out0 := *abi.ConvertType(out[0], new([]Session)).(*[]Session) - - return out0, err - -} - -// GetSessionsByProvider is a free data retrieval call binding the contract method 0x8ea1ac0e. -// -// Solidity: function getSessionsByProvider(address provider, uint256 offset, uint8 limit) view returns((bytes32,address,address,bytes32,bytes32,uint256,uint256,bytes,uint256,uint256,uint256,uint256,uint256)[]) -func (_SessionRouter *SessionRouterSession) GetSessionsByProvider(provider common.Address, offset *big.Int, limit uint8) ([]Session, error) { - return _SessionRouter.Contract.GetSessionsByProvider(&_SessionRouter.CallOpts, provider, offset, limit) -} - -// GetSessionsByProvider is a free data retrieval call binding the contract method 0x8ea1ac0e. -// -// Solidity: function getSessionsByProvider(address provider, uint256 offset, uint8 limit) view returns((bytes32,address,address,bytes32,bytes32,uint256,uint256,bytes,uint256,uint256,uint256,uint256,uint256)[]) -func (_SessionRouter *SessionRouterCallerSession) GetSessionsByProvider(provider common.Address, offset *big.Int, limit uint8) ([]Session, error) { - return _SessionRouter.Contract.GetSessionsByProvider(&_SessionRouter.CallOpts, provider, offset, limit) -} - -// GetSessionsByUser is a free data retrieval call binding the contract method 0xb954275b. -// -// Solidity: function getSessionsByUser(address user, uint256 offset, uint8 limit) view returns((bytes32,address,address,bytes32,bytes32,uint256,uint256,bytes,uint256,uint256,uint256,uint256,uint256)[]) -func (_SessionRouter *SessionRouterCaller) GetSessionsByUser(opts *bind.CallOpts, user common.Address, offset *big.Int, limit uint8) ([]Session, error) { - var out []interface{} - err := _SessionRouter.contract.Call(opts, &out, "getSessionsByUser", user, offset, limit) - - if err != nil { - return *new([]Session), err - } - - out0 := *abi.ConvertType(out[0], new([]Session)).(*[]Session) - - return out0, err - -} - -// GetSessionsByUser is a free data retrieval call binding the contract method 0xb954275b. -// -// Solidity: function getSessionsByUser(address user, uint256 offset, uint8 limit) view returns((bytes32,address,address,bytes32,bytes32,uint256,uint256,bytes,uint256,uint256,uint256,uint256,uint256)[]) -func (_SessionRouter *SessionRouterSession) GetSessionsByUser(user common.Address, offset *big.Int, limit uint8) ([]Session, error) { - return _SessionRouter.Contract.GetSessionsByUser(&_SessionRouter.CallOpts, user, offset, limit) -} - -// GetSessionsByUser is a free data retrieval call binding the contract method 0xb954275b. -// -// Solidity: function getSessionsByUser(address user, uint256 offset, uint8 limit) view returns((bytes32,address,address,bytes32,bytes32,uint256,uint256,bytes,uint256,uint256,uint256,uint256,uint256)[]) -func (_SessionRouter *SessionRouterCallerSession) GetSessionsByUser(user common.Address, offset *big.Int, limit uint8) ([]Session, error) { - return _SessionRouter.Contract.GetSessionsByUser(&_SessionRouter.CallOpts, user, offset, limit) -} - -// GetTodaysBudget is a free data retrieval call binding the contract method 0x351ffeb0. -// -// Solidity: function getTodaysBudget(uint256 timestamp) view returns(uint256) -func (_SessionRouter *SessionRouterCaller) GetTodaysBudget(opts *bind.CallOpts, timestamp *big.Int) (*big.Int, error) { - var out []interface{} - err := _SessionRouter.contract.Call(opts, &out, "getTodaysBudget", timestamp) - - if err != nil { - return *new(*big.Int), err - } - - out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - - return out0, err - -} - -// GetTodaysBudget is a free data retrieval call binding the contract method 0x351ffeb0. -// -// Solidity: function getTodaysBudget(uint256 timestamp) view returns(uint256) -func (_SessionRouter *SessionRouterSession) GetTodaysBudget(timestamp *big.Int) (*big.Int, error) { - return _SessionRouter.Contract.GetTodaysBudget(&_SessionRouter.CallOpts, timestamp) -} - -// GetTodaysBudget is a free data retrieval call binding the contract method 0x351ffeb0. -// -// Solidity: function getTodaysBudget(uint256 timestamp) view returns(uint256) -func (_SessionRouter *SessionRouterCallerSession) GetTodaysBudget(timestamp *big.Int) (*big.Int, error) { - return _SessionRouter.Contract.GetTodaysBudget(&_SessionRouter.CallOpts, timestamp) -} - -// SessionsCount is a free data retrieval call binding the contract method 0x312f6307. -// -// Solidity: function sessionsCount() view returns(uint256) -func (_SessionRouter *SessionRouterCaller) SessionsCount(opts *bind.CallOpts) (*big.Int, error) { - var out []interface{} - err := _SessionRouter.contract.Call(opts, &out, "sessionsCount") - - if err != nil { - return *new(*big.Int), err - } - - out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - - return out0, err - -} - -// SessionsCount is a free data retrieval call binding the contract method 0x312f6307. -// -// Solidity: function sessionsCount() view returns(uint256) -func (_SessionRouter *SessionRouterSession) SessionsCount() (*big.Int, error) { - return _SessionRouter.Contract.SessionsCount(&_SessionRouter.CallOpts) -} - -// SessionsCount is a free data retrieval call binding the contract method 0x312f6307. -// -// Solidity: function sessionsCount() view returns(uint256) -func (_SessionRouter *SessionRouterCallerSession) SessionsCount() (*big.Int, error) { - return _SessionRouter.Contract.SessionsCount(&_SessionRouter.CallOpts) -} - -// StakeToStipend is a free data retrieval call binding the contract method 0x0a23b21f. -// -// Solidity: function stakeToStipend(uint256 sessionStake, uint256 timestamp) view returns(uint256) -func (_SessionRouter *SessionRouterCaller) StakeToStipend(opts *bind.CallOpts, sessionStake *big.Int, timestamp *big.Int) (*big.Int, error) { - var out []interface{} - err := _SessionRouter.contract.Call(opts, &out, "stakeToStipend", sessionStake, timestamp) - - if err != nil { - return *new(*big.Int), err - } - - out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - - return out0, err - -} - -// StakeToStipend is a free data retrieval call binding the contract method 0x0a23b21f. -// -// Solidity: function stakeToStipend(uint256 sessionStake, uint256 timestamp) view returns(uint256) -func (_SessionRouter *SessionRouterSession) StakeToStipend(sessionStake *big.Int, timestamp *big.Int) (*big.Int, error) { - return _SessionRouter.Contract.StakeToStipend(&_SessionRouter.CallOpts, sessionStake, timestamp) -} - -// StakeToStipend is a free data retrieval call binding the contract method 0x0a23b21f. -// -// Solidity: function stakeToStipend(uint256 sessionStake, uint256 timestamp) view returns(uint256) -func (_SessionRouter *SessionRouterCallerSession) StakeToStipend(sessionStake *big.Int, timestamp *big.Int) (*big.Int, error) { - return _SessionRouter.Contract.StakeToStipend(&_SessionRouter.CallOpts, sessionStake, timestamp) -} - -// StipendToStake is a free data retrieval call binding the contract method 0xac3c19ce. -// -// Solidity: function stipendToStake(uint256 stipend, uint256 timestamp) view returns(uint256) -func (_SessionRouter *SessionRouterCaller) StipendToStake(opts *bind.CallOpts, stipend *big.Int, timestamp *big.Int) (*big.Int, error) { - var out []interface{} - err := _SessionRouter.contract.Call(opts, &out, "stipendToStake", stipend, timestamp) - - if err != nil { - return *new(*big.Int), err - } - - out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - - return out0, err - -} - -// StipendToStake is a free data retrieval call binding the contract method 0xac3c19ce. -// -// Solidity: function stipendToStake(uint256 stipend, uint256 timestamp) view returns(uint256) -func (_SessionRouter *SessionRouterSession) StipendToStake(stipend *big.Int, timestamp *big.Int) (*big.Int, error) { - return _SessionRouter.Contract.StipendToStake(&_SessionRouter.CallOpts, stipend, timestamp) -} - -// StipendToStake is a free data retrieval call binding the contract method 0xac3c19ce. -// -// Solidity: function stipendToStake(uint256 stipend, uint256 timestamp) view returns(uint256) -func (_SessionRouter *SessionRouterCallerSession) StipendToStake(stipend *big.Int, timestamp *big.Int) (*big.Int, error) { - return _SessionRouter.Contract.StipendToStake(&_SessionRouter.CallOpts, stipend, timestamp) -} - -// TotalMORSupply is a free data retrieval call binding the contract method 0xf1d5440c. -// -// Solidity: function totalMORSupply(uint256 timestamp) view returns(uint256) -func (_SessionRouter *SessionRouterCaller) TotalMORSupply(opts *bind.CallOpts, timestamp *big.Int) (*big.Int, error) { - var out []interface{} - err := _SessionRouter.contract.Call(opts, &out, "totalMORSupply", timestamp) - - if err != nil { - return *new(*big.Int), err - } - - out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - - return out0, err - -} - -// TotalMORSupply is a free data retrieval call binding the contract method 0xf1d5440c. -// -// Solidity: function totalMORSupply(uint256 timestamp) view returns(uint256) -func (_SessionRouter *SessionRouterSession) TotalMORSupply(timestamp *big.Int) (*big.Int, error) { - return _SessionRouter.Contract.TotalMORSupply(&_SessionRouter.CallOpts, timestamp) -} - -// TotalMORSupply is a free data retrieval call binding the contract method 0xf1d5440c. -// -// Solidity: function totalMORSupply(uint256 timestamp) view returns(uint256) -func (_SessionRouter *SessionRouterCallerSession) TotalMORSupply(timestamp *big.Int) (*big.Int, error) { - return _SessionRouter.Contract.TotalMORSupply(&_SessionRouter.CallOpts, timestamp) -} - -// WhenSessionEnds is a free data retrieval call binding the contract method 0x9bc08456. -// -// Solidity: function whenSessionEnds(uint256 sessionStake, uint256 pricePerSecond, uint256 openedAt) view returns(uint256) -func (_SessionRouter *SessionRouterCaller) WhenSessionEnds(opts *bind.CallOpts, sessionStake *big.Int, pricePerSecond *big.Int, openedAt *big.Int) (*big.Int, error) { - var out []interface{} - err := _SessionRouter.contract.Call(opts, &out, "whenSessionEnds", sessionStake, pricePerSecond, openedAt) - - if err != nil { - return *new(*big.Int), err - } - - out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - - return out0, err - -} - -// WhenSessionEnds is a free data retrieval call binding the contract method 0x9bc08456. -// -// Solidity: function whenSessionEnds(uint256 sessionStake, uint256 pricePerSecond, uint256 openedAt) view returns(uint256) -func (_SessionRouter *SessionRouterSession) WhenSessionEnds(sessionStake *big.Int, pricePerSecond *big.Int, openedAt *big.Int) (*big.Int, error) { - return _SessionRouter.Contract.WhenSessionEnds(&_SessionRouter.CallOpts, sessionStake, pricePerSecond, openedAt) -} - -// WhenSessionEnds is a free data retrieval call binding the contract method 0x9bc08456. -// -// Solidity: function whenSessionEnds(uint256 sessionStake, uint256 pricePerSecond, uint256 openedAt) view returns(uint256) -func (_SessionRouter *SessionRouterCallerSession) WhenSessionEnds(sessionStake *big.Int, pricePerSecond *big.Int, openedAt *big.Int) (*big.Int, error) { - return _SessionRouter.Contract.WhenSessionEnds(&_SessionRouter.CallOpts, sessionStake, pricePerSecond, openedAt) -} - -// WithdrawableUserStake is a free data retrieval call binding the contract method 0x13796cae. -// -// Solidity: function withdrawableUserStake(address userAddr, uint256 offset, uint8 limit) view returns(uint256 avail, uint256 hold) -func (_SessionRouter *SessionRouterCaller) WithdrawableUserStake(opts *bind.CallOpts, userAddr common.Address, offset *big.Int, limit uint8) (struct { - Avail *big.Int - Hold *big.Int -}, error) { - var out []interface{} - err := _SessionRouter.contract.Call(opts, &out, "withdrawableUserStake", userAddr, offset, limit) - - outstruct := new(struct { - Avail *big.Int - Hold *big.Int - }) - if err != nil { - return *outstruct, err - } - - outstruct.Avail = *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - outstruct.Hold = *abi.ConvertType(out[1], new(*big.Int)).(**big.Int) - - return *outstruct, err - -} - -// WithdrawableUserStake is a free data retrieval call binding the contract method 0x13796cae. -// -// Solidity: function withdrawableUserStake(address userAddr, uint256 offset, uint8 limit) view returns(uint256 avail, uint256 hold) -func (_SessionRouter *SessionRouterSession) WithdrawableUserStake(userAddr common.Address, offset *big.Int, limit uint8) (struct { - Avail *big.Int - Hold *big.Int -}, error) { - return _SessionRouter.Contract.WithdrawableUserStake(&_SessionRouter.CallOpts, userAddr, offset, limit) -} - -// WithdrawableUserStake is a free data retrieval call binding the contract method 0x13796cae. -// -// Solidity: function withdrawableUserStake(address userAddr, uint256 offset, uint8 limit) view returns(uint256 avail, uint256 hold) -func (_SessionRouter *SessionRouterCallerSession) WithdrawableUserStake(userAddr common.Address, offset *big.Int, limit uint8) (struct { - Avail *big.Int - Hold *big.Int -}, error) { - return _SessionRouter.Contract.WithdrawableUserStake(&_SessionRouter.CallOpts, userAddr, offset, limit) -} - -// ClaimProviderBalance is a paid mutator transaction binding the contract method 0xf42d165a. -// -// Solidity: function claimProviderBalance(bytes32 sessionId, uint256 amountToWithdraw) returns() -func (_SessionRouter *SessionRouterTransactor) ClaimProviderBalance(opts *bind.TransactOpts, sessionId [32]byte, amountToWithdraw *big.Int) (*types.Transaction, error) { - return _SessionRouter.contract.Transact(opts, "claimProviderBalance", sessionId, amountToWithdraw) -} - -// ClaimProviderBalance is a paid mutator transaction binding the contract method 0xf42d165a. -// -// Solidity: function claimProviderBalance(bytes32 sessionId, uint256 amountToWithdraw) returns() -func (_SessionRouter *SessionRouterSession) ClaimProviderBalance(sessionId [32]byte, amountToWithdraw *big.Int) (*types.Transaction, error) { - return _SessionRouter.Contract.ClaimProviderBalance(&_SessionRouter.TransactOpts, sessionId, amountToWithdraw) -} - -// ClaimProviderBalance is a paid mutator transaction binding the contract method 0xf42d165a. -// -// Solidity: function claimProviderBalance(bytes32 sessionId, uint256 amountToWithdraw) returns() -func (_SessionRouter *SessionRouterTransactorSession) ClaimProviderBalance(sessionId [32]byte, amountToWithdraw *big.Int) (*types.Transaction, error) { - return _SessionRouter.Contract.ClaimProviderBalance(&_SessionRouter.TransactOpts, sessionId, amountToWithdraw) -} - -// CloseSession is a paid mutator transaction binding the contract method 0x42f77a31. -// -// Solidity: function closeSession(bytes receiptEncoded, bytes signature) returns() -func (_SessionRouter *SessionRouterTransactor) CloseSession(opts *bind.TransactOpts, receiptEncoded []byte, signature []byte) (*types.Transaction, error) { - return _SessionRouter.contract.Transact(opts, "closeSession", receiptEncoded, signature) -} - -// CloseSession is a paid mutator transaction binding the contract method 0x42f77a31. -// -// Solidity: function closeSession(bytes receiptEncoded, bytes signature) returns() -func (_SessionRouter *SessionRouterSession) CloseSession(receiptEncoded []byte, signature []byte) (*types.Transaction, error) { - return _SessionRouter.Contract.CloseSession(&_SessionRouter.TransactOpts, receiptEncoded, signature) -} - -// CloseSession is a paid mutator transaction binding the contract method 0x42f77a31. -// -// Solidity: function closeSession(bytes receiptEncoded, bytes signature) returns() -func (_SessionRouter *SessionRouterTransactorSession) CloseSession(receiptEncoded []byte, signature []byte) (*types.Transaction, error) { - return _SessionRouter.Contract.CloseSession(&_SessionRouter.TransactOpts, receiptEncoded, signature) -} - -// DeleteHistory is a paid mutator transaction binding the contract method 0xf074ca6b. -// -// Solidity: function deleteHistory(bytes32 sessionId) returns() -func (_SessionRouter *SessionRouterTransactor) DeleteHistory(opts *bind.TransactOpts, sessionId [32]byte) (*types.Transaction, error) { - return _SessionRouter.contract.Transact(opts, "deleteHistory", sessionId) -} - -// DeleteHistory is a paid mutator transaction binding the contract method 0xf074ca6b. -// -// Solidity: function deleteHistory(bytes32 sessionId) returns() -func (_SessionRouter *SessionRouterSession) DeleteHistory(sessionId [32]byte) (*types.Transaction, error) { - return _SessionRouter.Contract.DeleteHistory(&_SessionRouter.TransactOpts, sessionId) -} - -// DeleteHistory is a paid mutator transaction binding the contract method 0xf074ca6b. -// -// Solidity: function deleteHistory(bytes32 sessionId) returns() -func (_SessionRouter *SessionRouterTransactorSession) DeleteHistory(sessionId [32]byte) (*types.Transaction, error) { - return _SessionRouter.Contract.DeleteHistory(&_SessionRouter.TransactOpts, sessionId) -} - -// OpenSession is a paid mutator transaction binding the contract method 0x1f71815e. -// -// Solidity: function openSession(uint256 _stake, bytes providerApproval, bytes signature) returns(bytes32 sessionId) -func (_SessionRouter *SessionRouterTransactor) OpenSession(opts *bind.TransactOpts, _stake *big.Int, providerApproval []byte, signature []byte) (*types.Transaction, error) { - return _SessionRouter.contract.Transact(opts, "openSession", _stake, providerApproval, signature) -} - -// OpenSession is a paid mutator transaction binding the contract method 0x1f71815e. -// -// Solidity: function openSession(uint256 _stake, bytes providerApproval, bytes signature) returns(bytes32 sessionId) -func (_SessionRouter *SessionRouterSession) OpenSession(_stake *big.Int, providerApproval []byte, signature []byte) (*types.Transaction, error) { - return _SessionRouter.Contract.OpenSession(&_SessionRouter.TransactOpts, _stake, providerApproval, signature) -} - -// OpenSession is a paid mutator transaction binding the contract method 0x1f71815e. -// -// Solidity: function openSession(uint256 _stake, bytes providerApproval, bytes signature) returns(bytes32 sessionId) -func (_SessionRouter *SessionRouterTransactorSession) OpenSession(_stake *big.Int, providerApproval []byte, signature []byte) (*types.Transaction, error) { - return _SessionRouter.Contract.OpenSession(&_SessionRouter.TransactOpts, _stake, providerApproval, signature) -} - -// SetPoolConfig is a paid mutator transaction binding the contract method 0xd7178753. -// -// Solidity: function setPoolConfig(uint256 index, (uint256,uint256,uint128,uint128) pool) returns() -func (_SessionRouter *SessionRouterTransactor) SetPoolConfig(opts *bind.TransactOpts, index *big.Int, pool Pool) (*types.Transaction, error) { - return _SessionRouter.contract.Transact(opts, "setPoolConfig", index, pool) -} - -// SetPoolConfig is a paid mutator transaction binding the contract method 0xd7178753. -// -// Solidity: function setPoolConfig(uint256 index, (uint256,uint256,uint128,uint128) pool) returns() -func (_SessionRouter *SessionRouterSession) SetPoolConfig(index *big.Int, pool Pool) (*types.Transaction, error) { - return _SessionRouter.Contract.SetPoolConfig(&_SessionRouter.TransactOpts, index, pool) -} - -// SetPoolConfig is a paid mutator transaction binding the contract method 0xd7178753. -// -// Solidity: function setPoolConfig(uint256 index, (uint256,uint256,uint128,uint128) pool) returns() -func (_SessionRouter *SessionRouterTransactorSession) SetPoolConfig(index *big.Int, pool Pool) (*types.Transaction, error) { - return _SessionRouter.Contract.SetPoolConfig(&_SessionRouter.TransactOpts, index, pool) -} - -// WithdrawUserStake is a paid mutator transaction binding the contract method 0x0fd2c44e. -// -// Solidity: function withdrawUserStake(uint256 amountToWithdraw, uint8 iterations) returns() -func (_SessionRouter *SessionRouterTransactor) WithdrawUserStake(opts *bind.TransactOpts, amountToWithdraw *big.Int, iterations uint8) (*types.Transaction, error) { - return _SessionRouter.contract.Transact(opts, "withdrawUserStake", amountToWithdraw, iterations) -} - -// WithdrawUserStake is a paid mutator transaction binding the contract method 0x0fd2c44e. -// -// Solidity: function withdrawUserStake(uint256 amountToWithdraw, uint8 iterations) returns() -func (_SessionRouter *SessionRouterSession) WithdrawUserStake(amountToWithdraw *big.Int, iterations uint8) (*types.Transaction, error) { - return _SessionRouter.Contract.WithdrawUserStake(&_SessionRouter.TransactOpts, amountToWithdraw, iterations) -} - -// WithdrawUserStake is a paid mutator transaction binding the contract method 0x0fd2c44e. -// -// Solidity: function withdrawUserStake(uint256 amountToWithdraw, uint8 iterations) returns() -func (_SessionRouter *SessionRouterTransactorSession) WithdrawUserStake(amountToWithdraw *big.Int, iterations uint8) (*types.Transaction, error) { - return _SessionRouter.Contract.WithdrawUserStake(&_SessionRouter.TransactOpts, amountToWithdraw, iterations) -} - -// SessionRouterSessionClosedIterator is returned from FilterSessionClosed and is used to iterate over the raw logs and unpacked data for SessionClosed events raised by the SessionRouter contract. -type SessionRouterSessionClosedIterator struct { - Event *SessionRouterSessionClosed // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *SessionRouterSessionClosedIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(SessionRouterSessionClosed) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(SessionRouterSessionClosed) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *SessionRouterSessionClosedIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *SessionRouterSessionClosedIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// SessionRouterSessionClosed represents a SessionClosed event raised by the SessionRouter contract. -type SessionRouterSessionClosed struct { - UserAddress common.Address - SessionId [32]byte - ProviderId common.Address - Raw types.Log // Blockchain specific contextual infos -} - -// FilterSessionClosed is a free log retrieval operation binding the contract event 0x337fbb0a41a596db800dc836595a57815f967185e3596615c646f2455ac3914a. -// -// Solidity: event SessionClosed(address indexed userAddress, bytes32 indexed sessionId, address indexed providerId) -func (_SessionRouter *SessionRouterFilterer) FilterSessionClosed(opts *bind.FilterOpts, userAddress []common.Address, sessionId [][32]byte, providerId []common.Address) (*SessionRouterSessionClosedIterator, error) { - - var userAddressRule []interface{} - for _, userAddressItem := range userAddress { - userAddressRule = append(userAddressRule, userAddressItem) - } - var sessionIdRule []interface{} - for _, sessionIdItem := range sessionId { - sessionIdRule = append(sessionIdRule, sessionIdItem) - } - var providerIdRule []interface{} - for _, providerIdItem := range providerId { - providerIdRule = append(providerIdRule, providerIdItem) - } - - logs, sub, err := _SessionRouter.contract.FilterLogs(opts, "SessionClosed", userAddressRule, sessionIdRule, providerIdRule) - if err != nil { - return nil, err - } - return &SessionRouterSessionClosedIterator{contract: _SessionRouter.contract, event: "SessionClosed", logs: logs, sub: sub}, nil -} - -// WatchSessionClosed is a free log subscription operation binding the contract event 0x337fbb0a41a596db800dc836595a57815f967185e3596615c646f2455ac3914a. -// -// Solidity: event SessionClosed(address indexed userAddress, bytes32 indexed sessionId, address indexed providerId) -func (_SessionRouter *SessionRouterFilterer) WatchSessionClosed(opts *bind.WatchOpts, sink chan<- *SessionRouterSessionClosed, userAddress []common.Address, sessionId [][32]byte, providerId []common.Address) (event.Subscription, error) { - - var userAddressRule []interface{} - for _, userAddressItem := range userAddress { - userAddressRule = append(userAddressRule, userAddressItem) - } - var sessionIdRule []interface{} - for _, sessionIdItem := range sessionId { - sessionIdRule = append(sessionIdRule, sessionIdItem) - } - var providerIdRule []interface{} - for _, providerIdItem := range providerId { - providerIdRule = append(providerIdRule, providerIdItem) - } - - logs, sub, err := _SessionRouter.contract.WatchLogs(opts, "SessionClosed", userAddressRule, sessionIdRule, providerIdRule) - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(SessionRouterSessionClosed) - if err := _SessionRouter.contract.UnpackLog(event, "SessionClosed", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// ParseSessionClosed is a log parse operation binding the contract event 0x337fbb0a41a596db800dc836595a57815f967185e3596615c646f2455ac3914a. -// -// Solidity: event SessionClosed(address indexed userAddress, bytes32 indexed sessionId, address indexed providerId) -func (_SessionRouter *SessionRouterFilterer) ParseSessionClosed(log types.Log) (*SessionRouterSessionClosed, error) { - event := new(SessionRouterSessionClosed) - if err := _SessionRouter.contract.UnpackLog(event, "SessionClosed", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -// SessionRouterSessionOpenedIterator is returned from FilterSessionOpened and is used to iterate over the raw logs and unpacked data for SessionOpened events raised by the SessionRouter contract. -type SessionRouterSessionOpenedIterator struct { - Event *SessionRouterSessionOpened // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *SessionRouterSessionOpenedIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(SessionRouterSessionOpened) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(SessionRouterSessionOpened) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *SessionRouterSessionOpenedIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *SessionRouterSessionOpenedIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// SessionRouterSessionOpened represents a SessionOpened event raised by the SessionRouter contract. -type SessionRouterSessionOpened struct { - UserAddress common.Address - SessionId [32]byte - ProviderId common.Address - Raw types.Log // Blockchain specific contextual infos -} - -// FilterSessionOpened is a free log retrieval operation binding the contract event 0x2bd7c890baf595977d256a6e784512c873ac58ba612b4895dbb7f784bfbf4839. -// -// Solidity: event SessionOpened(address indexed userAddress, bytes32 indexed sessionId, address indexed providerId) -func (_SessionRouter *SessionRouterFilterer) FilterSessionOpened(opts *bind.FilterOpts, userAddress []common.Address, sessionId [][32]byte, providerId []common.Address) (*SessionRouterSessionOpenedIterator, error) { - - var userAddressRule []interface{} - for _, userAddressItem := range userAddress { - userAddressRule = append(userAddressRule, userAddressItem) - } - var sessionIdRule []interface{} - for _, sessionIdItem := range sessionId { - sessionIdRule = append(sessionIdRule, sessionIdItem) - } - var providerIdRule []interface{} - for _, providerIdItem := range providerId { - providerIdRule = append(providerIdRule, providerIdItem) - } - - logs, sub, err := _SessionRouter.contract.FilterLogs(opts, "SessionOpened", userAddressRule, sessionIdRule, providerIdRule) - if err != nil { - return nil, err - } - return &SessionRouterSessionOpenedIterator{contract: _SessionRouter.contract, event: "SessionOpened", logs: logs, sub: sub}, nil -} - -// WatchSessionOpened is a free log subscription operation binding the contract event 0x2bd7c890baf595977d256a6e784512c873ac58ba612b4895dbb7f784bfbf4839. -// -// Solidity: event SessionOpened(address indexed userAddress, bytes32 indexed sessionId, address indexed providerId) -func (_SessionRouter *SessionRouterFilterer) WatchSessionOpened(opts *bind.WatchOpts, sink chan<- *SessionRouterSessionOpened, userAddress []common.Address, sessionId [][32]byte, providerId []common.Address) (event.Subscription, error) { - - var userAddressRule []interface{} - for _, userAddressItem := range userAddress { - userAddressRule = append(userAddressRule, userAddressItem) - } - var sessionIdRule []interface{} - for _, sessionIdItem := range sessionId { - sessionIdRule = append(sessionIdRule, sessionIdItem) - } - var providerIdRule []interface{} - for _, providerIdItem := range providerId { - providerIdRule = append(providerIdRule, providerIdItem) - } - - logs, sub, err := _SessionRouter.contract.WatchLogs(opts, "SessionOpened", userAddressRule, sessionIdRule, providerIdRule) - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(SessionRouterSessionOpened) - if err := _SessionRouter.contract.UnpackLog(event, "SessionOpened", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// ParseSessionOpened is a log parse operation binding the contract event 0x2bd7c890baf595977d256a6e784512c873ac58ba612b4895dbb7f784bfbf4839. -// -// Solidity: event SessionOpened(address indexed userAddress, bytes32 indexed sessionId, address indexed providerId) -func (_SessionRouter *SessionRouterFilterer) ParseSessionOpened(log types.Log) (*SessionRouterSessionOpened, error) { - event := new(SessionRouterSessionOpened) - if err := _SessionRouter.contract.UnpackLog(event, "SessionOpened", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} diff --git a/proxy-router/docker-compose.yml b/proxy-router/docker-compose.yml index 64ff1c4d..2819466a 100644 --- a/proxy-router/docker-compose.yml +++ b/proxy-router/docker-compose.yml @@ -1,8 +1,15 @@ services: proxy-router: - build: . + build: + context: . + args: + COMMIT: ${COMMIT:-unknown} + TAG_NAME: ${TAG_NAME:-latest} + image: proxy-router:${TAG_NAME} env_file: - .env ports: - - 8080:8080 - - 3333:3333 \ No newline at end of file + - "8082:8082" + - "3333:3333" + volumes: + - .:/app/data \ No newline at end of file diff --git a/proxy-router/docker_build.sh b/proxy-router/docker_build.sh new file mode 100755 index 00000000..282b98c1 --- /dev/null +++ b/proxy-router/docker_build.sh @@ -0,0 +1,43 @@ +#!/bin/sh + +# This script assumes you've cloned the repository and want to build with proper commit and version numbers +# It will use the latest Git tag as the version number and the latest short commit hash as the commit number +# It also leverages the docker-compose.yml file to build the Docker image + +# Pre-requisites: Docker & Git installed + +# Assumptions: +# - properly formatted .env in current directory +# - properly formatted models-config.json in current directory +# - properly formatted rating-config.json in current directory + +# Check if TAG_NAME is set; if not, use the latest Git tag +if [ -z "$TAG_NAME" ]; then + VLAST=$(git describe --tags --abbrev=0 --match='v[1-9]*' refs/remotes/origin/main 2>/dev/null | cut -c2-) + [ $VLAST ] && declare $(echo $VLAST | awk -F '.' '{print "VMAJ="$1" VMIN="$2" VPAT="$3}') + MB=$(git merge-base refs/remotes/origin/main HEAD) + VPAT=$(git rev-list --count --no-merges ${MB}..HEAD) + TAG_NAME=${VMAJ}.${VMIN}.${VPAT} +fi +VERSION=$TAG_NAME +echo VERSION=$VERSION + +# if commit is not set, use the latest commit +if [ -z "$COMMIT" ]; then + SHORT_COMMIT=$(git rev-parse --short HEAD) +fi +COMMIT=$SHORT_COMMIT +echo COMMIT=$COMMIT +export VERSION COMMIT TAG_NAME + +# Check if the user wants to build or run the Docker image +if [ "$1" = "--build" ]; then + echo "Building Docker image..." + docker-compose build + docker tag proxy-router:$VERSION proxy-router:latest +elif [ "$1" = "--run" ]; then + echo "Running Docker container..." + docker-compose up +else + echo "Usage: $0 [--build | --run]" +fi \ No newline at end of file diff --git a/proxy-router/docs/docs.go b/proxy-router/docs/docs.go index bede38e7..a10b7116 100644 --- a/proxy-router/docs/docs.go +++ b/proxy-router/docs/docs.go @@ -260,6 +260,32 @@ const docTemplate = `{ "models" ], "summary": "Get models list", + "parameters": [ + { + "minimum": 1, + "type": "integer", + "example": 10, + "name": "limit", + "in": "query" + }, + { + "minLength": 0, + "type": "string", + "example": "0", + "name": "offset", + "in": "query" + }, + { + "enum": [ + "asc", + "desc" + ], + "type": "string", + "example": "asc", + "name": "order", + "in": "query" + } + ], "responses": { "200": { "description": "OK", @@ -270,6 +296,7 @@ const docTemplate = `{ } }, "post": { + "description": "If you provide ID in request it will be used as \"Base Id\" for generation of new model ID. So actual ID will be generated from it, and you will get it in response.", "consumes": [ "application/json" ], @@ -346,6 +373,30 @@ const docTemplate = `{ "name": "id", "in": "path", "required": true + }, + { + "minimum": 1, + "type": "integer", + "example": 10, + "name": "limit", + "in": "query" + }, + { + "minLength": 0, + "type": "string", + "example": "0", + "name": "offset", + "in": "query" + }, + { + "enum": [ + "asc", + "desc" + ], + "type": "string", + "example": "asc", + "name": "order", + "in": "query" } ], "responses": { @@ -407,7 +458,7 @@ const docTemplate = `{ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/structs.OpenSessionWithDurationRequest" + "$ref": "#/definitions/structs.OpenSessionWithFailover" } }, { @@ -438,6 +489,32 @@ const docTemplate = `{ "providers" ], "summary": "Get providers list", + "parameters": [ + { + "minimum": 1, + "type": "integer", + "example": 10, + "name": "limit", + "in": "query" + }, + { + "minLength": 0, + "type": "string", + "example": "0", + "name": "offset", + "in": "query" + }, + { + "enum": [ + "asc", + "desc" + ], + "type": "string", + "example": "asc", + "name": "order", + "in": "query" + } + ], "responses": { "200": { "description": "OK", @@ -491,7 +568,7 @@ const docTemplate = `{ "parameters": [ { "type": "string", - "description": "Provider Address", + "description": "Provider ID", "name": "id", "in": "path", "required": true @@ -520,22 +597,34 @@ const docTemplate = `{ "parameters": [ { "type": "string", - "description": "Offset", - "name": "offset", + "description": "Provider ID", + "name": "id", + "in": "path", + "required": true + }, + { + "minimum": 1, + "type": "integer", + "example": 10, + "name": "limit", "in": "query" }, { + "minLength": 0, "type": "string", - "description": "Limit", - "name": "limit", + "example": "0", + "name": "offset", "in": "query" }, { + "enum": [ + "asc", + "desc" + ], "type": "string", - "description": "Provider ID", - "name": "id", - "in": "path", - "required": true + "example": "asc", + "name": "order", + "in": "query" } ], "responses": { @@ -565,6 +654,30 @@ const docTemplate = `{ "name": "id", "in": "path", "required": true + }, + { + "minimum": 1, + "type": "integer", + "example": 10, + "name": "limit", + "in": "query" + }, + { + "minLength": 0, + "type": "string", + "example": "0", + "name": "offset", + "in": "query" + }, + { + "enum": [ + "asc", + "desc" + ], + "type": "string", + "example": "asc", + "name": "order", + "in": "query" } ], "responses": { @@ -640,39 +753,100 @@ const docTemplate = `{ } }, "/blockchain/sessions": { + "post": { + "description": "Sends transaction in blockchain to open a session", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "sessions" + ], + "summary": "Open Session with Provider in blockchain", + "parameters": [ + { + "description": "Open session", + "name": "opensession", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/structs.OpenSessionRequest" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/structs.OpenSessionRes" + } + } + } + } + }, + "/blockchain/sessions/budget": { "get": { - "description": "Get sessions from blockchain by user or provider", + "description": "Get todays budget from blockchain", "produces": [ "application/json" ], "tags": [ "sessions" ], - "summary": "Get Sessions", + "summary": "Get Todays Budget", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/structs.BudgetRes" + } + } + } + } + }, + "/blockchain/sessions/provider": { + "get": { + "description": "Get sessions from blockchain by provider", + "produces": [ + "application/json" + ], + "tags": [ + "sessions" + ], + "summary": "Get Sessions for Provider", "parameters": [ { - "type": "string", - "description": "Offset", - "name": "offset", + "minimum": 1, + "type": "integer", + "example": 10, + "name": "limit", "in": "query" }, { + "minLength": 0, "type": "string", - "description": "Limit", - "name": "limit", + "example": "0", + "name": "offset", "in": "query" }, { + "enum": [ + "asc", + "desc" + ], "type": "string", - "description": "Provider address", - "name": "provider", + "example": "asc", + "name": "order", "in": "query" }, { "type": "string", - "description": "User address", - "name": "user", - "in": "query" + "description": "Provider address", + "name": "provider", + "in": "query", + "required": true } ], "responses": { @@ -683,55 +857,109 @@ const docTemplate = `{ } } } - }, - "post": { - "description": "Sends transaction in blockchain to open a session", - "consumes": [ - "application/json" - ], + } + }, + "/blockchain/sessions/user": { + "get": { + "description": "Get sessions from blockchain by user", "produces": [ "application/json" ], "tags": [ "sessions" ], - "summary": "Open Session with Provider in blockchain", + "summary": "Get Sessions for User", "parameters": [ { - "description": "Open session", - "name": "opensession", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/structs.OpenSessionRequest" - } + "type": "string", + "description": "User address", + "name": "user", + "in": "query", + "required": true + }, + { + "minimum": 1, + "type": "integer", + "example": 10, + "name": "limit", + "in": "query" + }, + { + "minLength": 0, + "type": "string", + "example": "0", + "name": "offset", + "in": "query" + }, + { + "enum": [ + "asc", + "desc" + ], + "type": "string", + "example": "asc", + "name": "order", + "in": "query" } ], "responses": { "200": { "description": "OK", "schema": { - "$ref": "#/definitions/structs.OpenSessionRes" + "$ref": "#/definitions/structs.SessionsRes" } } } } }, - "/blockchain/sessions/budget": { + "/blockchain/sessions/user/ids": { "get": { - "description": "Get todays budget from blockchain", + "description": "Get sessions from blockchain by user", "produces": [ "application/json" ], "tags": [ "sessions" ], - "summary": "Get Todays Budget", + "summary": "Get Sessions for User", + "parameters": [ + { + "type": "string", + "description": "User address", + "name": "user", + "in": "query", + "required": true + }, + { + "minimum": 1, + "type": "integer", + "example": 10, + "name": "limit", + "in": "query" + }, + { + "minLength": 0, + "type": "string", + "example": "0", + "name": "offset", + "in": "query" + }, + { + "enum": [ + "asc", + "desc" + ], + "type": "string", + "example": "asc", + "name": "order", + "in": "query" + } + ], "responses": { "200": { "description": "OK", "schema": { - "$ref": "#/definitions/structs.BudgetRes" + "$ref": "#/definitions/structs.SessionsRes" } } } @@ -856,7 +1084,7 @@ const docTemplate = `{ "application/json" ], "tags": [ - "healthcheck" + "system" ], "summary": "Get Config", "responses": { @@ -869,6 +1097,58 @@ const docTemplate = `{ } } }, + "/config/ethNode": { + "post": { + "description": "Set the Eth Node URLs", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "system" + ], + "summary": "Set Eth Node URLs", + "parameters": [ + { + "description": "URLs", + "name": "urls", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/system.SetEthNodeURLReq" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/system.StatusRes" + } + } + } + }, + "delete": { + "description": "Delete the Eth Node URLs", + "produces": [ + "application/json" + ], + "tags": [ + "system" + ], + "summary": "Delete Eth Node URLs", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/system.StatusRes" + } + } + } + } + }, "/files": { "get": { "description": "Returns opened files", @@ -876,7 +1156,7 @@ const docTemplate = `{ "application/json" ], "tags": [ - "healthcheck" + "system" ], "summary": "Get files", "responses": { @@ -899,7 +1179,7 @@ const docTemplate = `{ "application/json" ], "tags": [ - "healthcheck" + "system" ], "summary": "Healthcheck example", "responses": { @@ -912,6 +1192,37 @@ const docTemplate = `{ } } }, + "/proxy/provider/ping": { + "post": { + "description": "sends a ping to the provider on the RPC level", + "produces": [ + "application/json" + ], + "tags": [ + "chat" + ], + "summary": "Ping Provider", + "parameters": [ + { + "description": "Ping Request", + "name": "pingReq", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/proxyapi.PingReq" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/proxyapi.PingRes" + } + } + } + } + }, "/proxy/sessions/initiate": { "post": { "description": "sends a handshake to the provider", @@ -954,15 +1265,6 @@ const docTemplate = `{ ], "summary": "Claim Provider Balance", "parameters": [ - { - "description": "Claim", - "name": "claim", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/structs.AmountReq" - } - }, { "type": "string", "description": "Session ID", @@ -1035,21 +1337,139 @@ const docTemplate = `{ "name": "model_id", "in": "header" }, + { + "type": "string", + "format": "hex32", + "description": "Chat ID", + "name": "chat_id", + "in": "header" + }, { "description": "Prompt", "name": "prompt", "in": "body", "required": true, "schema": { - "$ref": "#/definitions/proxyapi.OpenAiCompletitionRequest" + "$ref": "#/definitions/proxyapi.ChatCompletionRequestSwaggerExample" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "string" } } + } + } + }, + "/v1/chats": { + "get": { + "produces": [ + "application/json" + ], + "tags": [ + "chat" + ], + "summary": "Get all chats stored in the system", + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/genericchatstorage.Chat" + } + } + } + } + } + }, + "/v1/chats/{id}": { + "get": { + "produces": [ + "application/json" + ], + "tags": [ + "chat" + ], + "summary": "Get chat by id", + "parameters": [ + { + "type": "string", + "description": "Chat ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/genericchatstorage.ChatHistory" + } + } + } + }, + "post": { + "produces": [ + "application/json" + ], + "tags": [ + "chat" + ], + "summary": "Update chat title by id", + "parameters": [ + { + "type": "string", + "description": "Chat ID", + "name": "id", + "in": "path", + "required": true + }, + { + "description": "Chat Title", + "name": "title", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/proxyapi.UpdateChatTitleReq" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/proxyapi.ResultResponse" + } + } + } + }, + "delete": { + "produces": [ + "application/json" + ], + "tags": [ + "chat" + ], + "summary": "Delete chat by id from storage", + "parameters": [ + { + "type": "string", + "description": "Chat ID", + "name": "id", + "in": "path", + "required": true + } ], "responses": { "200": { "description": "OK", "schema": { - "$ref": "#/definitions/proxyapi.ChatCompletionResponse" + "$ref": "#/definitions/proxyapi.ResultResponse" } } } @@ -1061,7 +1481,7 @@ const docTemplate = `{ "application/json" ], "tags": [ - "chat" + "system" ], "summary": "Get local models", "responses": { @@ -1192,82 +1612,52 @@ const docTemplate = `{ "apiType": { "type": "string" }, - "id": { - "type": "string" - }, - "model": { + "apiUrl": { "type": "string" }, - "name": { - "type": "string" - } - } - }, - "morrpcmesssage.SessionRes": { - "type": "object", - "required": [ - "approval", - "approvalSig", - "message", - "signature", - "timestamp", - "user" - ], - "properties": { - "approval": { + "capacityPolicy": { "type": "string" }, - "approvalSig": { + "id": { "type": "string" }, - "message": { + "model": { "type": "string" }, - "signature": { + "name": { "type": "string" }, - "timestamp": { + "slots": { "type": "integer" - }, - "user": { - "type": "string" } } }, - "proxyapi.ChatCompletionChoice": { + "genericchatstorage.Chat": { "type": "object", "properties": { - "finish_reason": { - "description": "FinishReason\nstop: API returned complete message,\nor a message terminated by one of the stop sequences provided via the stop parameter\nlength: Incomplete model output due to max_tokens parameter or token limit\nfunction_call: The model decided to call a function\ncontent_filter: Omitted content due to a flag from our content filters\nnull: API response still in progress or incomplete", - "allOf": [ - { - "$ref": "#/definitions/proxyapi.FinishReason" - } - ] + "chatId": { + "type": "string" }, - "index": { + "createdAt": { "type": "integer" }, - "logprobs": { - "$ref": "#/definitions/proxyapi.LogProbs" + "isLocal": { + "type": "boolean" }, - "message": { - "$ref": "#/definitions/proxyapi.ChatCompletionMessage" + "modelId": { + "type": "string" + }, + "title": { + "type": "string" } } }, - "proxyapi.ChatCompletionMessage": { + "genericchatstorage.ChatCompletionMessage": { "type": "object", "properties": { "content": { "type": "string" }, - "multiContent": { - "type": "array", - "items": { - "$ref": "#/definitions/proxyapi.ChatMessagePart" - } - }, "name": { "description": "This property isn't in the official documentation, but it's in\nthe documentation for the official library for python:\n- https://github.com/openai/openai-python/blob/main/chatml.md\n- https://github.com/openai/openai-cookbook/blob/main/examples/How_to_count_tokens_with_tiktoken.ipynb", "type": "string" @@ -1281,36 +1671,7 @@ const docTemplate = `{ } } }, - "proxyapi.ChatCompletionResponse": { - "type": "object", - "properties": { - "choices": { - "type": "array", - "items": { - "$ref": "#/definitions/proxyapi.ChatCompletionChoice" - } - }, - "created": { - "type": "integer" - }, - "id": { - "type": "string" - }, - "model": { - "type": "string" - }, - "object": { - "type": "string" - }, - "system_fingerprint": { - "type": "string" - }, - "usage": { - "$ref": "#/definitions/proxyapi.Usage" - } - } - }, - "proxyapi.ChatCompletionResponseFormat": { + "genericchatstorage.ChatCompletionResponseFormat": { "type": "object", "properties": { "type": { @@ -1318,129 +1679,50 @@ const docTemplate = `{ } } }, - "proxyapi.ChatMessageImageURL": { + "genericchatstorage.ChatHistory": { "type": "object", "properties": { - "detail": { - "$ref": "#/definitions/proxyapi.ImageURLDetail" + "isLocal": { + "type": "boolean" }, - "url": { - "type": "string" - } - } - }, - "proxyapi.ChatMessagePart": { - "type": "object", - "properties": { - "image_url": { - "$ref": "#/definitions/proxyapi.ChatMessageImageURL" + "messages": { + "type": "array", + "items": { + "$ref": "#/definitions/genericchatstorage.ChatMessage" + } }, - "text": { + "modelId": { "type": "string" }, - "type": { - "$ref": "#/definitions/proxyapi.ChatMessagePartType" + "title": { + "type": "string" } } }, - "proxyapi.ChatMessagePartType": { - "type": "string", - "enum": [ - "text", - "image_url" - ], - "x-enum-varnames": [ - "ChatMessagePartTypeText", - "ChatMessagePartTypeImageURL" - ] - }, - "proxyapi.FinishReason": { - "type": "string", - "enum": [ - "stop" - ], - "x-enum-varnames": [ - "FinishReasonStop" - ] - }, - "proxyapi.ImageURLDetail": { - "type": "string", - "enum": [ - "high", - "low", - "auto" - ], - "x-enum-varnames": [ - "ImageURLDetailHigh", - "ImageURLDetailLow", - "ImageURLDetailAuto" - ] - }, - "proxyapi.InitiateSessionReq": { + "genericchatstorage.ChatMessage": { "type": "object", - "required": [ - "bidId", - "provider", - "providerUrl", - "spend", - "user" - ], "properties": { - "bidId": { - "type": "string" - }, - "provider": { - "type": "string" - }, - "providerUrl": { - "type": "string" + "isImageContent": { + "type": "boolean" }, - "spend": { - "type": "string" + "isVideoRawContent": { + "type": "boolean" }, - "user": { - "type": "string" - } - } - }, - "proxyapi.LogProb": { - "type": "object", - "properties": { - "bytes": { - "description": "Omitting the field if it is null", - "type": "array", - "items": { - "type": "integer" - } + "prompt": { + "$ref": "#/definitions/genericchatstorage.OpenAiCompletionRequest" }, - "logprob": { - "type": "number" + "promptAt": { + "type": "integer" }, - "token": { + "response": { "type": "string" }, - "top_logprobs": { - "description": "TopLogProbs is a list of the most likely tokens and their log probability, at this token position.\nIn rare cases, there may be fewer than the number of requested top_logprobs returned.", - "type": "array", - "items": { - "$ref": "#/definitions/proxyapi.TopLogProbs" - } - } - } - }, - "proxyapi.LogProbs": { - "type": "object", - "properties": { - "content": { - "description": "Content is a list of message content tokens with log probability information.", - "type": "array", - "items": { - "$ref": "#/definitions/proxyapi.LogProb" - } + "responseAt": { + "type": "integer" } } }, - "proxyapi.OpenAiCompletitionRequest": { + "genericchatstorage.OpenAiCompletionRequest": { "type": "object", "properties": { "frequency_penalty": { @@ -1466,7 +1748,7 @@ const docTemplate = `{ "messages": { "type": "array", "items": { - "$ref": "#/definitions/proxyapi.ChatCompletionMessage" + "$ref": "#/definitions/genericchatstorage.ChatCompletionMessage" } }, "model": { @@ -1479,7 +1761,7 @@ const docTemplate = `{ "type": "number" }, "response_format": { - "$ref": "#/definitions/proxyapi.ChatCompletionResponseFormat" + "$ref": "#/definitions/genericchatstorage.ChatCompletionResponseFormat" }, "seed": { "type": "integer" @@ -1511,57 +1793,139 @@ const docTemplate = `{ } } }, - "proxyapi.TopLogProbs": { + "morrpcmesssage.SessionRes": { + "type": "object", + "required": [ + "approval", + "approvalSig", + "message", + "signature", + "timestamp", + "user" + ], + "properties": { + "approval": { + "type": "string" + }, + "approvalSig": { + "type": "string" + }, + "message": { + "type": "string" + }, + "signature": { + "type": "string" + }, + "timestamp": { + "type": "integer" + }, + "user": { + "type": "string" + } + } + }, + "proxyapi.ChatCompletionRequestSwaggerExample": { "type": "object", "properties": { - "bytes": { + "messages": { "type": "array", "items": { - "type": "integer" + "type": "object", + "properties": { + "content": { + "type": "string", + "example": "tell me a joke" + }, + "role": { + "type": "string", + "example": "user" + } + } } }, - "logprob": { - "type": "number" + "stream": { + "type": "boolean" + } + } + }, + "proxyapi.InitiateSessionReq": { + "type": "object", + "required": [ + "bidId", + "provider", + "providerUrl", + "spend", + "user" + ], + "properties": { + "bidId": { + "type": "string" + }, + "provider": { + "type": "string" + }, + "providerUrl": { + "type": "string" + }, + "spend": { + "type": "string" }, - "token": { + "user": { "type": "string" } } }, - "proxyapi.Usage": { + "proxyapi.PingReq": { "type": "object", + "required": [ + "providerAddr", + "providerUrl" + ], "properties": { - "completion_tokens": { - "type": "integer" - }, - "prompt_tokens": { - "type": "integer" + "providerAddr": { + "type": "string" }, - "total_tokens": { + "providerUrl": { + "type": "string" + } + } + }, + "proxyapi.PingRes": { + "type": "object", + "properties": { + "ping": { "type": "integer" } } }, - "structs.AllowanceRes": { + "proxyapi.ResultResponse": { "type": "object", "properties": { - "allowance": { - "type": "string", - "example": "100000000" + "result": { + "type": "boolean" } } }, - "structs.AmountReq": { + "proxyapi.UpdateChatTitleReq": { "type": "object", "required": [ - "amount" + "title" ], "properties": { - "amount": { + "title": { "type": "string" } } }, + "structs.AllowanceRes": { + "type": "object", + "properties": { + "allowance": { + "type": "string", + "example": "100000000" + } + } + }, "structs.BalanceRes": { "type": "object", "properties": { @@ -1779,6 +2143,9 @@ const docTemplate = `{ "format": "hex", "example": "0x1234" }, + "directPayment": { + "type": "boolean" + }, "stake": { "type": "string", "example": "123000000000" @@ -1802,6 +2169,20 @@ const docTemplate = `{ } } }, + "structs.OpenSessionWithFailover": { + "type": "object", + "properties": { + "directPayment": { + "type": "boolean" + }, + "failover": { + "type": "boolean" + }, + "sessionDuration": { + "type": "string" + } + } + }, "structs.Provider": { "type": "object", "properties": { @@ -2091,6 +2472,28 @@ const docTemplate = `{ "type": "string" } } + }, + "system.SetEthNodeURLReq": { + "type": "object", + "required": [ + "urls" + ], + "properties": { + "urls": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "system.StatusRes": { + "type": "object", + "properties": { + "status": { + "type": "string" + } + } } }, "externalDocs": { @@ -2101,7 +2504,7 @@ const docTemplate = `{ // SwaggerInfo holds exported Swagger Info so clients can modify it var SwaggerInfo = &swag.Spec{ - Version: "1.0", + Version: "", Host: "", BasePath: "/", Schemes: []string{}, diff --git a/proxy-router/docs/swagger.json b/proxy-router/docs/swagger.json index 45a112c9..f6431ffe 100644 --- a/proxy-router/docs/swagger.json +++ b/proxy-router/docs/swagger.json @@ -4,8 +4,7 @@ "description": "API for Morpheus Lumerin Node", "title": "Morpheus Lumerin Node API", "termsOfService": "http://swagger.io/terms/", - "contact": {}, - "version": "1.0" + "contact": {} }, "basePath": "/", "paths": { @@ -253,6 +252,32 @@ "models" ], "summary": "Get models list", + "parameters": [ + { + "minimum": 1, + "type": "integer", + "example": 10, + "name": "limit", + "in": "query" + }, + { + "minLength": 0, + "type": "string", + "example": "0", + "name": "offset", + "in": "query" + }, + { + "enum": [ + "asc", + "desc" + ], + "type": "string", + "example": "asc", + "name": "order", + "in": "query" + } + ], "responses": { "200": { "description": "OK", @@ -263,6 +288,7 @@ } }, "post": { + "description": "If you provide ID in request it will be used as \"Base Id\" for generation of new model ID. So actual ID will be generated from it, and you will get it in response.", "consumes": [ "application/json" ], @@ -339,6 +365,30 @@ "name": "id", "in": "path", "required": true + }, + { + "minimum": 1, + "type": "integer", + "example": 10, + "name": "limit", + "in": "query" + }, + { + "minLength": 0, + "type": "string", + "example": "0", + "name": "offset", + "in": "query" + }, + { + "enum": [ + "asc", + "desc" + ], + "type": "string", + "example": "asc", + "name": "order", + "in": "query" } ], "responses": { @@ -400,7 +450,7 @@ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/structs.OpenSessionWithDurationRequest" + "$ref": "#/definitions/structs.OpenSessionWithFailover" } }, { @@ -431,6 +481,32 @@ "providers" ], "summary": "Get providers list", + "parameters": [ + { + "minimum": 1, + "type": "integer", + "example": 10, + "name": "limit", + "in": "query" + }, + { + "minLength": 0, + "type": "string", + "example": "0", + "name": "offset", + "in": "query" + }, + { + "enum": [ + "asc", + "desc" + ], + "type": "string", + "example": "asc", + "name": "order", + "in": "query" + } + ], "responses": { "200": { "description": "OK", @@ -484,7 +560,7 @@ "parameters": [ { "type": "string", - "description": "Provider Address", + "description": "Provider ID", "name": "id", "in": "path", "required": true @@ -513,22 +589,34 @@ "parameters": [ { "type": "string", - "description": "Offset", - "name": "offset", + "description": "Provider ID", + "name": "id", + "in": "path", + "required": true + }, + { + "minimum": 1, + "type": "integer", + "example": 10, + "name": "limit", "in": "query" }, { + "minLength": 0, "type": "string", - "description": "Limit", - "name": "limit", + "example": "0", + "name": "offset", "in": "query" }, { + "enum": [ + "asc", + "desc" + ], "type": "string", - "description": "Provider ID", - "name": "id", - "in": "path", - "required": true + "example": "asc", + "name": "order", + "in": "query" } ], "responses": { @@ -558,6 +646,30 @@ "name": "id", "in": "path", "required": true + }, + { + "minimum": 1, + "type": "integer", + "example": 10, + "name": "limit", + "in": "query" + }, + { + "minLength": 0, + "type": "string", + "example": "0", + "name": "offset", + "in": "query" + }, + { + "enum": [ + "asc", + "desc" + ], + "type": "string", + "example": "asc", + "name": "order", + "in": "query" } ], "responses": { @@ -633,39 +745,100 @@ } }, "/blockchain/sessions": { + "post": { + "description": "Sends transaction in blockchain to open a session", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "sessions" + ], + "summary": "Open Session with Provider in blockchain", + "parameters": [ + { + "description": "Open session", + "name": "opensession", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/structs.OpenSessionRequest" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/structs.OpenSessionRes" + } + } + } + } + }, + "/blockchain/sessions/budget": { "get": { - "description": "Get sessions from blockchain by user or provider", + "description": "Get todays budget from blockchain", "produces": [ "application/json" ], "tags": [ "sessions" ], - "summary": "Get Sessions", + "summary": "Get Todays Budget", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/structs.BudgetRes" + } + } + } + } + }, + "/blockchain/sessions/provider": { + "get": { + "description": "Get sessions from blockchain by provider", + "produces": [ + "application/json" + ], + "tags": [ + "sessions" + ], + "summary": "Get Sessions for Provider", "parameters": [ { - "type": "string", - "description": "Offset", - "name": "offset", + "minimum": 1, + "type": "integer", + "example": 10, + "name": "limit", "in": "query" }, { + "minLength": 0, "type": "string", - "description": "Limit", - "name": "limit", + "example": "0", + "name": "offset", "in": "query" }, { + "enum": [ + "asc", + "desc" + ], "type": "string", - "description": "Provider address", - "name": "provider", + "example": "asc", + "name": "order", "in": "query" }, { "type": "string", - "description": "User address", - "name": "user", - "in": "query" + "description": "Provider address", + "name": "provider", + "in": "query", + "required": true } ], "responses": { @@ -676,55 +849,109 @@ } } } - }, - "post": { - "description": "Sends transaction in blockchain to open a session", - "consumes": [ - "application/json" - ], + } + }, + "/blockchain/sessions/user": { + "get": { + "description": "Get sessions from blockchain by user", "produces": [ "application/json" ], "tags": [ "sessions" ], - "summary": "Open Session with Provider in blockchain", + "summary": "Get Sessions for User", "parameters": [ { - "description": "Open session", - "name": "opensession", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/structs.OpenSessionRequest" - } + "type": "string", + "description": "User address", + "name": "user", + "in": "query", + "required": true + }, + { + "minimum": 1, + "type": "integer", + "example": 10, + "name": "limit", + "in": "query" + }, + { + "minLength": 0, + "type": "string", + "example": "0", + "name": "offset", + "in": "query" + }, + { + "enum": [ + "asc", + "desc" + ], + "type": "string", + "example": "asc", + "name": "order", + "in": "query" } ], "responses": { "200": { "description": "OK", "schema": { - "$ref": "#/definitions/structs.OpenSessionRes" + "$ref": "#/definitions/structs.SessionsRes" } } } } }, - "/blockchain/sessions/budget": { + "/blockchain/sessions/user/ids": { "get": { - "description": "Get todays budget from blockchain", + "description": "Get sessions from blockchain by user", "produces": [ "application/json" ], "tags": [ "sessions" ], - "summary": "Get Todays Budget", + "summary": "Get Sessions for User", + "parameters": [ + { + "type": "string", + "description": "User address", + "name": "user", + "in": "query", + "required": true + }, + { + "minimum": 1, + "type": "integer", + "example": 10, + "name": "limit", + "in": "query" + }, + { + "minLength": 0, + "type": "string", + "example": "0", + "name": "offset", + "in": "query" + }, + { + "enum": [ + "asc", + "desc" + ], + "type": "string", + "example": "asc", + "name": "order", + "in": "query" + } + ], "responses": { "200": { "description": "OK", "schema": { - "$ref": "#/definitions/structs.BudgetRes" + "$ref": "#/definitions/structs.SessionsRes" } } } @@ -849,7 +1076,7 @@ "application/json" ], "tags": [ - "healthcheck" + "system" ], "summary": "Get Config", "responses": { @@ -862,6 +1089,58 @@ } } }, + "/config/ethNode": { + "post": { + "description": "Set the Eth Node URLs", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "system" + ], + "summary": "Set Eth Node URLs", + "parameters": [ + { + "description": "URLs", + "name": "urls", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/system.SetEthNodeURLReq" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/system.StatusRes" + } + } + } + }, + "delete": { + "description": "Delete the Eth Node URLs", + "produces": [ + "application/json" + ], + "tags": [ + "system" + ], + "summary": "Delete Eth Node URLs", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/system.StatusRes" + } + } + } + } + }, "/files": { "get": { "description": "Returns opened files", @@ -869,7 +1148,7 @@ "application/json" ], "tags": [ - "healthcheck" + "system" ], "summary": "Get files", "responses": { @@ -892,7 +1171,7 @@ "application/json" ], "tags": [ - "healthcheck" + "system" ], "summary": "Healthcheck example", "responses": { @@ -905,6 +1184,37 @@ } } }, + "/proxy/provider/ping": { + "post": { + "description": "sends a ping to the provider on the RPC level", + "produces": [ + "application/json" + ], + "tags": [ + "chat" + ], + "summary": "Ping Provider", + "parameters": [ + { + "description": "Ping Request", + "name": "pingReq", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/proxyapi.PingReq" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/proxyapi.PingRes" + } + } + } + } + }, "/proxy/sessions/initiate": { "post": { "description": "sends a handshake to the provider", @@ -947,15 +1257,6 @@ ], "summary": "Claim Provider Balance", "parameters": [ - { - "description": "Claim", - "name": "claim", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/structs.AmountReq" - } - }, { "type": "string", "description": "Session ID", @@ -1028,21 +1329,139 @@ "name": "model_id", "in": "header" }, + { + "type": "string", + "format": "hex32", + "description": "Chat ID", + "name": "chat_id", + "in": "header" + }, { "description": "Prompt", "name": "prompt", "in": "body", "required": true, "schema": { - "$ref": "#/definitions/proxyapi.OpenAiCompletitionRequest" + "$ref": "#/definitions/proxyapi.ChatCompletionRequestSwaggerExample" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "string" } } + } + } + }, + "/v1/chats": { + "get": { + "produces": [ + "application/json" + ], + "tags": [ + "chat" + ], + "summary": "Get all chats stored in the system", + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/genericchatstorage.Chat" + } + } + } + } + } + }, + "/v1/chats/{id}": { + "get": { + "produces": [ + "application/json" + ], + "tags": [ + "chat" + ], + "summary": "Get chat by id", + "parameters": [ + { + "type": "string", + "description": "Chat ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/genericchatstorage.ChatHistory" + } + } + } + }, + "post": { + "produces": [ + "application/json" + ], + "tags": [ + "chat" + ], + "summary": "Update chat title by id", + "parameters": [ + { + "type": "string", + "description": "Chat ID", + "name": "id", + "in": "path", + "required": true + }, + { + "description": "Chat Title", + "name": "title", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/proxyapi.UpdateChatTitleReq" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/proxyapi.ResultResponse" + } + } + } + }, + "delete": { + "produces": [ + "application/json" + ], + "tags": [ + "chat" + ], + "summary": "Delete chat by id from storage", + "parameters": [ + { + "type": "string", + "description": "Chat ID", + "name": "id", + "in": "path", + "required": true + } ], "responses": { "200": { "description": "OK", "schema": { - "$ref": "#/definitions/proxyapi.ChatCompletionResponse" + "$ref": "#/definitions/proxyapi.ResultResponse" } } } @@ -1054,7 +1473,7 @@ "application/json" ], "tags": [ - "chat" + "system" ], "summary": "Get local models", "responses": { @@ -1185,82 +1604,52 @@ "apiType": { "type": "string" }, - "id": { - "type": "string" - }, - "model": { + "apiUrl": { "type": "string" }, - "name": { - "type": "string" - } - } - }, - "morrpcmesssage.SessionRes": { - "type": "object", - "required": [ - "approval", - "approvalSig", - "message", - "signature", - "timestamp", - "user" - ], - "properties": { - "approval": { + "capacityPolicy": { "type": "string" }, - "approvalSig": { + "id": { "type": "string" }, - "message": { + "model": { "type": "string" }, - "signature": { + "name": { "type": "string" }, - "timestamp": { + "slots": { "type": "integer" - }, - "user": { - "type": "string" } } }, - "proxyapi.ChatCompletionChoice": { + "genericchatstorage.Chat": { "type": "object", "properties": { - "finish_reason": { - "description": "FinishReason\nstop: API returned complete message,\nor a message terminated by one of the stop sequences provided via the stop parameter\nlength: Incomplete model output due to max_tokens parameter or token limit\nfunction_call: The model decided to call a function\ncontent_filter: Omitted content due to a flag from our content filters\nnull: API response still in progress or incomplete", - "allOf": [ - { - "$ref": "#/definitions/proxyapi.FinishReason" - } - ] + "chatId": { + "type": "string" }, - "index": { + "createdAt": { "type": "integer" }, - "logprobs": { - "$ref": "#/definitions/proxyapi.LogProbs" + "isLocal": { + "type": "boolean" }, - "message": { - "$ref": "#/definitions/proxyapi.ChatCompletionMessage" + "modelId": { + "type": "string" + }, + "title": { + "type": "string" } } }, - "proxyapi.ChatCompletionMessage": { + "genericchatstorage.ChatCompletionMessage": { "type": "object", "properties": { "content": { "type": "string" }, - "multiContent": { - "type": "array", - "items": { - "$ref": "#/definitions/proxyapi.ChatMessagePart" - } - }, "name": { "description": "This property isn't in the official documentation, but it's in\nthe documentation for the official library for python:\n- https://github.com/openai/openai-python/blob/main/chatml.md\n- https://github.com/openai/openai-cookbook/blob/main/examples/How_to_count_tokens_with_tiktoken.ipynb", "type": "string" @@ -1274,36 +1663,7 @@ } } }, - "proxyapi.ChatCompletionResponse": { - "type": "object", - "properties": { - "choices": { - "type": "array", - "items": { - "$ref": "#/definitions/proxyapi.ChatCompletionChoice" - } - }, - "created": { - "type": "integer" - }, - "id": { - "type": "string" - }, - "model": { - "type": "string" - }, - "object": { - "type": "string" - }, - "system_fingerprint": { - "type": "string" - }, - "usage": { - "$ref": "#/definitions/proxyapi.Usage" - } - } - }, - "proxyapi.ChatCompletionResponseFormat": { + "genericchatstorage.ChatCompletionResponseFormat": { "type": "object", "properties": { "type": { @@ -1311,129 +1671,50 @@ } } }, - "proxyapi.ChatMessageImageURL": { + "genericchatstorage.ChatHistory": { "type": "object", "properties": { - "detail": { - "$ref": "#/definitions/proxyapi.ImageURLDetail" + "isLocal": { + "type": "boolean" }, - "url": { - "type": "string" - } - } - }, - "proxyapi.ChatMessagePart": { - "type": "object", - "properties": { - "image_url": { - "$ref": "#/definitions/proxyapi.ChatMessageImageURL" + "messages": { + "type": "array", + "items": { + "$ref": "#/definitions/genericchatstorage.ChatMessage" + } }, - "text": { + "modelId": { "type": "string" }, - "type": { - "$ref": "#/definitions/proxyapi.ChatMessagePartType" + "title": { + "type": "string" } } }, - "proxyapi.ChatMessagePartType": { - "type": "string", - "enum": [ - "text", - "image_url" - ], - "x-enum-varnames": [ - "ChatMessagePartTypeText", - "ChatMessagePartTypeImageURL" - ] - }, - "proxyapi.FinishReason": { - "type": "string", - "enum": [ - "stop" - ], - "x-enum-varnames": [ - "FinishReasonStop" - ] - }, - "proxyapi.ImageURLDetail": { - "type": "string", - "enum": [ - "high", - "low", - "auto" - ], - "x-enum-varnames": [ - "ImageURLDetailHigh", - "ImageURLDetailLow", - "ImageURLDetailAuto" - ] - }, - "proxyapi.InitiateSessionReq": { + "genericchatstorage.ChatMessage": { "type": "object", - "required": [ - "bidId", - "provider", - "providerUrl", - "spend", - "user" - ], "properties": { - "bidId": { - "type": "string" - }, - "provider": { - "type": "string" - }, - "providerUrl": { - "type": "string" + "isImageContent": { + "type": "boolean" }, - "spend": { - "type": "string" + "isVideoRawContent": { + "type": "boolean" }, - "user": { - "type": "string" - } - } - }, - "proxyapi.LogProb": { - "type": "object", - "properties": { - "bytes": { - "description": "Omitting the field if it is null", - "type": "array", - "items": { - "type": "integer" - } + "prompt": { + "$ref": "#/definitions/genericchatstorage.OpenAiCompletionRequest" }, - "logprob": { - "type": "number" + "promptAt": { + "type": "integer" }, - "token": { + "response": { "type": "string" }, - "top_logprobs": { - "description": "TopLogProbs is a list of the most likely tokens and their log probability, at this token position.\nIn rare cases, there may be fewer than the number of requested top_logprobs returned.", - "type": "array", - "items": { - "$ref": "#/definitions/proxyapi.TopLogProbs" - } - } - } - }, - "proxyapi.LogProbs": { - "type": "object", - "properties": { - "content": { - "description": "Content is a list of message content tokens with log probability information.", - "type": "array", - "items": { - "$ref": "#/definitions/proxyapi.LogProb" - } + "responseAt": { + "type": "integer" } } }, - "proxyapi.OpenAiCompletitionRequest": { + "genericchatstorage.OpenAiCompletionRequest": { "type": "object", "properties": { "frequency_penalty": { @@ -1459,7 +1740,7 @@ "messages": { "type": "array", "items": { - "$ref": "#/definitions/proxyapi.ChatCompletionMessage" + "$ref": "#/definitions/genericchatstorage.ChatCompletionMessage" } }, "model": { @@ -1472,7 +1753,7 @@ "type": "number" }, "response_format": { - "$ref": "#/definitions/proxyapi.ChatCompletionResponseFormat" + "$ref": "#/definitions/genericchatstorage.ChatCompletionResponseFormat" }, "seed": { "type": "integer" @@ -1504,57 +1785,139 @@ } } }, - "proxyapi.TopLogProbs": { + "morrpcmesssage.SessionRes": { + "type": "object", + "required": [ + "approval", + "approvalSig", + "message", + "signature", + "timestamp", + "user" + ], + "properties": { + "approval": { + "type": "string" + }, + "approvalSig": { + "type": "string" + }, + "message": { + "type": "string" + }, + "signature": { + "type": "string" + }, + "timestamp": { + "type": "integer" + }, + "user": { + "type": "string" + } + } + }, + "proxyapi.ChatCompletionRequestSwaggerExample": { "type": "object", "properties": { - "bytes": { + "messages": { "type": "array", "items": { - "type": "integer" + "type": "object", + "properties": { + "content": { + "type": "string", + "example": "tell me a joke" + }, + "role": { + "type": "string", + "example": "user" + } + } } }, - "logprob": { - "type": "number" + "stream": { + "type": "boolean" + } + } + }, + "proxyapi.InitiateSessionReq": { + "type": "object", + "required": [ + "bidId", + "provider", + "providerUrl", + "spend", + "user" + ], + "properties": { + "bidId": { + "type": "string" + }, + "provider": { + "type": "string" + }, + "providerUrl": { + "type": "string" + }, + "spend": { + "type": "string" }, - "token": { + "user": { "type": "string" } } }, - "proxyapi.Usage": { + "proxyapi.PingReq": { "type": "object", + "required": [ + "providerAddr", + "providerUrl" + ], "properties": { - "completion_tokens": { - "type": "integer" - }, - "prompt_tokens": { - "type": "integer" + "providerAddr": { + "type": "string" }, - "total_tokens": { + "providerUrl": { + "type": "string" + } + } + }, + "proxyapi.PingRes": { + "type": "object", + "properties": { + "ping": { "type": "integer" } } }, - "structs.AllowanceRes": { + "proxyapi.ResultResponse": { "type": "object", "properties": { - "allowance": { - "type": "string", - "example": "100000000" + "result": { + "type": "boolean" } } }, - "structs.AmountReq": { + "proxyapi.UpdateChatTitleReq": { "type": "object", "required": [ - "amount" + "title" ], "properties": { - "amount": { + "title": { "type": "string" } } }, + "structs.AllowanceRes": { + "type": "object", + "properties": { + "allowance": { + "type": "string", + "example": "100000000" + } + } + }, "structs.BalanceRes": { "type": "object", "properties": { @@ -1772,6 +2135,9 @@ "format": "hex", "example": "0x1234" }, + "directPayment": { + "type": "boolean" + }, "stake": { "type": "string", "example": "123000000000" @@ -1795,6 +2161,20 @@ } } }, + "structs.OpenSessionWithFailover": { + "type": "object", + "properties": { + "directPayment": { + "type": "boolean" + }, + "failover": { + "type": "boolean" + }, + "sessionDuration": { + "type": "string" + } + } + }, "structs.Provider": { "type": "object", "properties": { @@ -2084,6 +2464,28 @@ "type": "string" } } + }, + "system.SetEthNodeURLReq": { + "type": "object", + "required": [ + "urls" + ], + "properties": { + "urls": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "system.StatusRes": { + "type": "object", + "properties": { + "status": { + "type": "string" + } + } } }, "externalDocs": { diff --git a/proxy-router/docs/swagger.yaml b/proxy-router/docs/swagger.yaml index ee876b25..d33dbaff 100644 --- a/proxy-router/docs/swagger.yaml +++ b/proxy-router/docs/swagger.yaml @@ -4,63 +4,36 @@ definitions: properties: apiType: type: string + apiUrl: + type: string + capacityPolicy: + type: string id: type: string model: type: string name: type: string + slots: + type: integer type: object - morrpcmesssage.SessionRes: + genericchatstorage.Chat: properties: - approval: - type: string - approvalSig: + chatId: type: string - message: - type: string - signature: - type: string - timestamp: + createdAt: type: integer - user: + isLocal: + type: boolean + modelId: + type: string + title: type: string - required: - - approval - - approvalSig - - message - - signature - - timestamp - - user - type: object - proxyapi.ChatCompletionChoice: - properties: - finish_reason: - allOf: - - $ref: '#/definitions/proxyapi.FinishReason' - description: |- - FinishReason - stop: API returned complete message, - or a message terminated by one of the stop sequences provided via the stop parameter - length: Incomplete model output due to max_tokens parameter or token limit - function_call: The model decided to call a function - content_filter: Omitted content due to a flag from our content filters - null: API response still in progress or incomplete - index: - type: integer - logprobs: - $ref: '#/definitions/proxyapi.LogProbs' - message: - $ref: '#/definitions/proxyapi.ChatCompletionMessage' type: object - proxyapi.ChatCompletionMessage: + genericchatstorage.ChatCompletionMessage: properties: content: type: string - multiContent: - items: - $ref: '#/definitions/proxyapi.ChatMessagePart' - type: array name: description: |- This property isn't in the official documentation, but it's in @@ -75,118 +48,40 @@ definitions: assistant's prior request to call a tool. type: string type: object - proxyapi.ChatCompletionResponse: - properties: - choices: - items: - $ref: '#/definitions/proxyapi.ChatCompletionChoice' - type: array - created: - type: integer - id: - type: string - model: - type: string - object: - type: string - system_fingerprint: - type: string - usage: - $ref: '#/definitions/proxyapi.Usage' - type: object - proxyapi.ChatCompletionResponseFormat: + genericchatstorage.ChatCompletionResponseFormat: properties: type: type: string type: object - proxyapi.ChatMessageImageURL: - properties: - detail: - $ref: '#/definitions/proxyapi.ImageURLDetail' - url: - type: string - type: object - proxyapi.ChatMessagePart: - properties: - image_url: - $ref: '#/definitions/proxyapi.ChatMessageImageURL' - text: - type: string - type: - $ref: '#/definitions/proxyapi.ChatMessagePartType' - type: object - proxyapi.ChatMessagePartType: - enum: - - text - - image_url - type: string - x-enum-varnames: - - ChatMessagePartTypeText - - ChatMessagePartTypeImageURL - proxyapi.FinishReason: - enum: - - stop - type: string - x-enum-varnames: - - FinishReasonStop - proxyapi.ImageURLDetail: - enum: - - high - - low - - auto - type: string - x-enum-varnames: - - ImageURLDetailHigh - - ImageURLDetailLow - - ImageURLDetailAuto - proxyapi.InitiateSessionReq: - properties: - bidId: - type: string - provider: - type: string - providerUrl: - type: string - spend: - type: string - user: - type: string - required: - - bidId - - provider - - providerUrl - - spend - - user - type: object - proxyapi.LogProb: + genericchatstorage.ChatHistory: properties: - bytes: - description: Omitting the field if it is null + isLocal: + type: boolean + messages: items: - type: integer + $ref: '#/definitions/genericchatstorage.ChatMessage' type: array - logprob: - type: number - token: + modelId: + type: string + title: type: string - top_logprobs: - description: |- - TopLogProbs is a list of the most likely tokens and their log probability, at this token position. - In rare cases, there may be fewer than the number of requested top_logprobs returned. - items: - $ref: '#/definitions/proxyapi.TopLogProbs' - type: array type: object - proxyapi.LogProbs: + genericchatstorage.ChatMessage: properties: - content: - description: Content is a list of message content tokens with log probability - information. - items: - $ref: '#/definitions/proxyapi.LogProb' - type: array + isImageContent: + type: boolean + isVideoRawContent: + type: boolean + prompt: + $ref: '#/definitions/genericchatstorage.OpenAiCompletionRequest' + promptAt: + type: integer + response: + type: string + responseAt: + type: integer type: object - proxyapi.OpenAiCompletitionRequest: + genericchatstorage.OpenAiCompletionRequest: properties: frequency_penalty: type: number @@ -210,7 +105,7 @@ definitions: type: integer messages: items: - $ref: '#/definitions/proxyapi.ChatCompletionMessage' + $ref: '#/definitions/genericchatstorage.ChatCompletionMessage' type: array model: type: string @@ -219,7 +114,7 @@ definitions: presence_penalty: type: number response_format: - $ref: '#/definitions/proxyapi.ChatCompletionResponseFormat' + $ref: '#/definitions/genericchatstorage.ChatCompletionResponseFormat' seed: type: integer stop: @@ -243,38 +138,95 @@ definitions: user: type: string type: object - proxyapi.TopLogProbs: + morrpcmesssage.SessionRes: properties: - bytes: + approval: + type: string + approvalSig: + type: string + message: + type: string + signature: + type: string + timestamp: + type: integer + user: + type: string + required: + - approval + - approvalSig + - message + - signature + - timestamp + - user + type: object + proxyapi.ChatCompletionRequestSwaggerExample: + properties: + messages: items: - type: integer + properties: + content: + example: tell me a joke + type: string + role: + example: user + type: string + type: object type: array - logprob: - type: number - token: + stream: + type: boolean + type: object + proxyapi.InitiateSessionReq: + properties: + bidId: + type: string + provider: + type: string + providerUrl: + type: string + spend: + type: string + user: + type: string + required: + - bidId + - provider + - providerUrl + - spend + - user + type: object + proxyapi.PingReq: + properties: + providerAddr: type: string + providerUrl: + type: string + required: + - providerAddr + - providerUrl type: object - proxyapi.Usage: + proxyapi.PingRes: properties: - completion_tokens: - type: integer - prompt_tokens: - type: integer - total_tokens: + ping: type: integer type: object - structs.AllowanceRes: + proxyapi.ResultResponse: properties: - allowance: - example: "100000000" - type: string + result: + type: boolean type: object - structs.AmountReq: + proxyapi.UpdateChatTitleReq: properties: - amount: + title: type: string required: - - amount + - title + type: object + structs.AllowanceRes: + properties: + allowance: + example: "100000000" + type: string type: object structs.BalanceRes: properties: @@ -421,6 +373,8 @@ definitions: example: "0x1234" format: hex type: string + directPayment: + type: boolean stake: example: "123000000000" type: string @@ -440,6 +394,15 @@ definitions: sessionDuration: type: string type: object + structs.OpenSessionWithFailover: + properties: + directPayment: + type: boolean + failover: + type: boolean + sessionDuration: + type: string + type: object structs.Provider: properties: address: @@ -630,6 +593,20 @@ definitions: version: type: string type: object + system.SetEthNodeURLReq: + properties: + urls: + items: + type: string + type: array + required: + - urls + type: object + system.StatusRes: + properties: + status: + type: string + type: object externalDocs: description: OpenAPI url: https://swagger.io/resources/open-api/ @@ -638,7 +615,6 @@ info: description: API for Morpheus Lumerin Node termsOfService: http://swagger.io/terms/ title: Morpheus Lumerin Node API - version: "1.0" paths: /blockchain/allowance: get: @@ -796,6 +772,24 @@ paths: /blockchain/models: get: description: Get models list from blokchain + parameters: + - example: 10 + in: query + minimum: 1 + name: limit + type: integer + - example: "0" + in: query + minLength: 0 + name: offset + type: string + - enum: + - asc + - desc + example: asc + in: query + name: order + type: string produces: - application/json responses: @@ -809,6 +803,9 @@ paths: post: consumes: - application/json + description: If you provide ID in request it will be used as "Base Id" for generation + of new model ID. So actual ID will be generated from it, and you will get + it in response. parameters: - description: Model in: body @@ -853,6 +850,23 @@ paths: name: id required: true type: string + - example: 10 + in: query + minimum: 1 + name: limit + type: integer + - example: "0" + in: query + minLength: 0 + name: offset + type: string + - enum: + - asc + - desc + example: asc + in: query + name: order + type: string produces: - application/json responses: @@ -893,7 +907,7 @@ paths: name: opensession required: true schema: - $ref: '#/definitions/structs.OpenSessionWithDurationRequest' + $ref: '#/definitions/structs.OpenSessionWithFailover' - description: Model ID in: path name: id @@ -912,6 +926,24 @@ paths: /blockchain/providers: get: description: Get providers list from blokchain + parameters: + - example: 10 + in: query + minimum: 1 + name: limit + type: integer + - example: "0" + in: query + minLength: 0 + name: offset + type: string + - enum: + - asc + - desc + example: asc + in: query + name: order + type: string produces: - application/json responses: @@ -945,7 +977,7 @@ paths: /blockchain/providers/{id}: delete: parameters: - - description: Provider Address + - description: Provider ID in: path name: id required: true @@ -964,19 +996,28 @@ paths: get: description: Get bids from blockchain by provider parameters: - - description: Offset - in: query - name: offset - type: string - - description: Limit - in: query - name: limit - type: string - description: Provider ID in: path name: id required: true type: string + - example: 10 + in: query + minimum: 1 + name: limit + type: integer + - example: "0" + in: query + minLength: 0 + name: offset + type: string + - enum: + - asc + - desc + example: asc + in: query + name: order + type: string produces: - application/json responses: @@ -996,6 +1037,23 @@ paths: name: id required: true type: string + - example: 10 + in: query + minimum: 1 + name: limit + type: integer + - example: "0" + in: query + minLength: 0 + name: offset + type: string + - enum: + - asc + - desc + example: asc + in: query + name: order + type: string produces: - application/json responses: @@ -1047,35 +1105,6 @@ paths: tags: - transactions /blockchain/sessions: - get: - description: Get sessions from blockchain by user or provider - parameters: - - description: Offset - in: query - name: offset - type: string - - description: Limit - in: query - name: limit - type: string - - description: Provider address - in: query - name: provider - type: string - - description: User address - in: query - name: user - type: string - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/structs.SessionsRes' - summary: Get Sessions - tags: - - sessions post: consumes: - application/json @@ -1148,6 +1177,114 @@ paths: summary: Get Todays Budget tags: - sessions + /blockchain/sessions/provider: + get: + description: Get sessions from blockchain by provider + parameters: + - example: 10 + in: query + minimum: 1 + name: limit + type: integer + - example: "0" + in: query + minLength: 0 + name: offset + type: string + - enum: + - asc + - desc + example: asc + in: query + name: order + type: string + - description: Provider address + in: query + name: provider + required: true + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/structs.SessionsRes' + summary: Get Sessions for Provider + tags: + - sessions + /blockchain/sessions/user: + get: + description: Get sessions from blockchain by user + parameters: + - description: User address + in: query + name: user + required: true + type: string + - example: 10 + in: query + minimum: 1 + name: limit + type: integer + - example: "0" + in: query + minLength: 0 + name: offset + type: string + - enum: + - asc + - desc + example: asc + in: query + name: order + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/structs.SessionsRes' + summary: Get Sessions for User + tags: + - sessions + /blockchain/sessions/user/ids: + get: + description: Get sessions from blockchain by user + parameters: + - description: User address + in: query + name: user + required: true + type: string + - example: 10 + in: query + minimum: 1 + name: limit + type: integer + - example: "0" + in: query + minLength: 0 + name: offset + type: string + - enum: + - asc + - desc + example: asc + in: query + name: order + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/structs.SessionsRes' + summary: Get Sessions for User + tags: + - sessions /blockchain/token/supply: get: description: Get MOR token supply from blockchain @@ -1195,7 +1332,41 @@ paths: $ref: '#/definitions/system.ConfigResponse' summary: Get Config tags: - - healthcheck + - system + /config/ethNode: + delete: + description: Delete the Eth Node URLs + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/system.StatusRes' + summary: Delete Eth Node URLs + tags: + - system + post: + consumes: + - application/json + description: Set the Eth Node URLs + parameters: + - description: URLs + in: body + name: urls + required: true + schema: + $ref: '#/definitions/system.SetEthNodeURLReq' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/system.StatusRes' + summary: Set Eth Node URLs + tags: + - system /files: get: description: Returns opened files @@ -1210,7 +1381,7 @@ paths: type: array summary: Get files tags: - - healthcheck + - system /healthcheck: get: description: do ping @@ -1223,17 +1394,31 @@ paths: $ref: '#/definitions/system.HealthCheckResponse' summary: Healthcheck example tags: - - healthcheck - /proxy/sessions/{id}/providerClaim: + - system + /proxy/provider/ping: post: - description: Claim provider balance from session + description: sends a ping to the provider on the RPC level parameters: - - description: Claim + - description: Ping Request in: body - name: claim + name: pingReq required: true schema: - $ref: '#/definitions/structs.AmountReq' + $ref: '#/definitions/proxyapi.PingReq' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/proxyapi.PingRes' + summary: Ping Provider + tags: + - chat + /proxy/sessions/{id}/providerClaim: + post: + description: Claim provider balance from session + parameters: - description: Session ID in: path name: id @@ -1302,22 +1487,99 @@ paths: in: header name: model_id type: string + - description: Chat ID + format: hex32 + in: header + name: chat_id + type: string - description: Prompt in: body name: prompt required: true schema: - $ref: '#/definitions/proxyapi.OpenAiCompletitionRequest' + $ref: '#/definitions/proxyapi.ChatCompletionRequestSwaggerExample' produces: - text/event-stream responses: "200": description: OK schema: - $ref: '#/definitions/proxyapi.ChatCompletionResponse' + type: string summary: Send Local Or Remote Prompt tags: - chat + /v1/chats: + get: + produces: + - application/json + responses: + "200": + description: OK + schema: + items: + $ref: '#/definitions/genericchatstorage.Chat' + type: array + summary: Get all chats stored in the system + tags: + - chat + /v1/chats/{id}: + delete: + parameters: + - description: Chat ID + in: path + name: id + required: true + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/proxyapi.ResultResponse' + summary: Delete chat by id from storage + tags: + - chat + get: + parameters: + - description: Chat ID + in: path + name: id + required: true + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/genericchatstorage.ChatHistory' + summary: Get chat by id + tags: + - chat + post: + parameters: + - description: Chat ID + in: path + name: id + required: true + type: string + - description: Chat Title + in: body + name: title + required: true + schema: + $ref: '#/definitions/proxyapi.UpdateChatTitleReq' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/proxyapi.ResultResponse' + summary: Update chat title by id + tags: + - chat /v1/models: get: produces: @@ -1331,7 +1593,7 @@ paths: type: array summary: Get local models tags: - - chat + - system /wallet: delete: description: Remove wallet from proxy storage diff --git a/proxy-router/go.mod b/proxy-router/go.mod index 74ade76e..74d5a3f0 100644 --- a/proxy-router/go.mod +++ b/proxy-router/go.mod @@ -5,46 +5,52 @@ go 1.22.0 toolchain go1.22.3 require ( + github.com/btcsuite/btcd v0.22.1 + github.com/btcsuite/btcutil v1.0.3-0.20201208143702-a53e38424cce github.com/dgraph-io/badger/v4 v4.2.0 - github.com/ethereum/go-ethereum v1.12.0 + github.com/ethereum/go-ethereum v1.13.15 github.com/gin-contrib/cors v1.7.2 github.com/gin-gonic/gin v1.10.0 github.com/go-playground/validator/v10 v10.20.0 github.com/joho/godotenv v1.5.1 - github.com/miguelmota/go-ethereum-hdwallet v0.1.2 github.com/omeid/uconfig v0.7.0 github.com/sashabaranov/go-openai v1.24.1 github.com/shirou/gopsutil/v3 v3.23.11 github.com/stretchr/testify v1.9.0 github.com/swaggo/files v1.0.1 github.com/swaggo/gin-swagger v1.6.0 - github.com/swaggo/swag v1.16.3 + github.com/swaggo/swag v1.16.4 + github.com/tyler-smith/go-bip39 v1.1.0 github.com/zalando/go-keyring v0.2.4 go.uber.org/multierr v1.6.0 go.uber.org/zap v1.24.0 - golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63 + golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa golang.org/x/sync v0.7.0 ) require ( github.com/KyleBanks/depth v1.2.1 // indirect + github.com/Microsoft/go-winio v0.6.1 // indirect github.com/StackExchange/wmi v1.2.1 // indirect github.com/alessio/shellescape v1.4.1 // indirect - github.com/btcsuite/btcd v0.22.1 // indirect + github.com/bits-and-blooms/bitset v1.10.0 // indirect github.com/btcsuite/btcd/btcec/v2 v2.2.0 // indirect github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1 // indirect - github.com/btcsuite/btcutil v1.0.3-0.20201208143702-a53e38424cce // indirect github.com/bytedance/sonic v1.11.6 // indirect github.com/bytedance/sonic/loader v0.1.1 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/cloudwego/base64x v0.1.4 // indirect github.com/cloudwego/iasm v0.2.0 // indirect + github.com/consensys/bavard v0.1.13 // indirect + github.com/consensys/gnark-crypto v0.12.1 // indirect + github.com/crate-crypto/go-kzg-4844 v0.7.0 // indirect github.com/danieljoos/wincred v1.2.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/deckarep/golang-set/v2 v2.1.0 // indirect github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 // indirect github.com/dgraph-io/ristretto v0.1.1 // indirect github.com/dustin/go-humanize v1.0.0 // indirect + github.com/ethereum/c-kzg-4844 v0.4.0 // indirect github.com/fsnotify/fsnotify v1.6.0 // indirect github.com/gabriel-vasile/mimetype v1.4.3 // indirect github.com/gin-contrib/sse v0.1.0 // indirect @@ -55,13 +61,12 @@ require ( github.com/go-openapi/swag v0.23.0 // indirect github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect - github.com/go-stack/stack v1.8.1 // indirect github.com/goccy/go-json v0.10.2 // indirect github.com/godbus/dbus/v5 v5.1.0 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/golang/glog v1.0.0 // indirect github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6 // indirect - github.com/golang/protobuf v1.5.2 // indirect + github.com/golang/protobuf v1.5.3 // indirect github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb // indirect github.com/google/flatbuffers v1.12.1 // indirect github.com/google/uuid v1.3.0 // indirect @@ -77,6 +82,7 @@ require ( github.com/mattn/go-isatty v0.0.20 // indirect github.com/mattn/go-runewidth v0.0.14 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/mmcloughlin/addchain v0.4.0 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/pelletier/go-toml/v2 v2.2.2 // indirect @@ -85,21 +91,23 @@ require ( github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible // indirect github.com/shoenig/go-m1cpu v0.1.6 // indirect + github.com/stretchr/objx v0.5.2 // indirect + github.com/supranational/blst v0.3.11 // indirect github.com/tklauser/go-sysconf v0.3.12 // indirect github.com/tklauser/numcpus v0.6.1 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect - github.com/tyler-smith/go-bip39 v1.1.0 // indirect github.com/ugorji/go/codec v1.2.12 // indirect github.com/yusufpapurcu/wmi v1.2.3 // indirect go.opencensus.io v0.22.5 // indirect go.uber.org/atomic v1.11.0 // indirect golang.org/x/arch v0.8.0 // indirect golang.org/x/crypto v0.23.0 // indirect + golang.org/x/mod v0.17.0 // indirect golang.org/x/net v0.25.0 // indirect golang.org/x/sys v0.20.0 // indirect golang.org/x/text v0.15.0 // indirect golang.org/x/tools v0.21.0 // indirect google.golang.org/protobuf v1.34.1 // indirect - gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce // indirect gopkg.in/yaml.v3 v3.0.1 // indirect + rsc.io/tmplfunc v0.0.3 // indirect ) diff --git a/proxy-router/go.sum b/proxy-router/go.sum index e9764740..9a1d2778 100644 --- a/proxy-router/go.sum +++ b/proxy-router/go.sum @@ -1,13 +1,15 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/DataDog/zstd v1.5.2 h1:vUG4lAyuPCXO0TLbXvPv7EB7cNK1QV/luu55UHLrrn8= -github.com/DataDog/zstd v1.5.2/go.mod h1:g4AWEaM3yOg3HYfnJ3YIawPnVdXJh9QME85blwSAmyw= +github.com/DataDog/zstd v1.4.5 h1:EndNeuB0l9syBZhut0wns3gV1hL8zX8LIu6ZiVHWLIQ= +github.com/DataDog/zstd v1.4.5/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo= github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc= github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE= +github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow= +github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= github.com/StackExchange/wmi v1.2.1 h1:VIkavFPXSjcnS+O8yTq7NI32k0R5Aj+v39y29VYDOSA= github.com/StackExchange/wmi v1.2.1/go.mod h1:rcmrprowKIVzvc+NUiLncP2uuArMWLCbu9SBzvHz7e8= -github.com/VictoriaMetrics/fastcache v1.6.0 h1:C/3Oi3EiBCqufydp1neRZkqcwmEiuRT9c3fqvvgKm5o= -github.com/VictoriaMetrics/fastcache v1.6.0/go.mod h1:0qHz5QP0GMX4pfmMA/zt5RgfNuXJrTP0zS7DqpHGGTw= +github.com/VictoriaMetrics/fastcache v1.12.1 h1:i0mICQuojGDL3KblA7wUNlY5lOK6a4bwt3uRKnkZU40= +github.com/VictoriaMetrics/fastcache v1.12.1/go.mod h1:tX04vaqcNoQeGLD+ra5pU5sWkuxnzWhEzLwhP9w653o= github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII= github.com/alessio/shellescape v1.4.1 h1:V7yhSDDn8LP4lc4jS8pFkt0zCnzVJlG5JXy9BVKJUX0= github.com/alessio/shellescape v1.4.1/go.mod h1:PZAiSCk0LJaZkiCSkPv8qIobYglO3FPpyFjDCtHLS30= @@ -15,6 +17,8 @@ github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLj github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bits-and-blooms/bitset v1.10.0 h1:ePXTeiPEazB5+opbv5fr8umg2R/1NlzgDsyepwsSr88= +github.com/bits-and-blooms/bitset v1.10.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8= github.com/btcsuite/btcd v0.20.1-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ= github.com/btcsuite/btcd v0.22.1 h1:CnwP9LM/M9xuRrGSCGeMVs9iv09uMqwsVX7EeIpgV2c= github.com/btcsuite/btcd v0.22.1/go.mod h1:wqgTSL29+50LRkmOVknEdmt8ZojIzhuWvgu/iptuN7Y= @@ -45,16 +49,28 @@ github.com/cloudwego/base64x v0.1.4 h1:jwCgWpFanWmN8xoIUHa2rtzmkd5J2plF/dnLS6Xd/ github.com/cloudwego/base64x v0.1.4/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w= github.com/cloudwego/iasm v0.2.0 h1:1KNIy1I1H9hNNFEEH3DVnI4UujN+1zjpuk6gwHLTssg= github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY= -github.com/cockroachdb/errors v1.9.1 h1:yFVvsI0VxmRShfawbt/laCIDy/mtTqqnvoNgiy5bEV8= -github.com/cockroachdb/errors v1.9.1/go.mod h1:2sxOtL2WIc096WSZqZ5h8fa17rdDq9HZOZLBCor4mBk= -github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b h1:r6VH0faHjZeQy818SGhaone5OnYfxFR/+AzdY3sf5aE= -github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b/go.mod h1:Vz9DsVWQQhf3vs21MhPMZpMGSht7O/2vFW2xusFUVOs= -github.com/cockroachdb/pebble v0.0.0-20230209160836-829675f94811 h1:ytcWPaNPhNoGMWEhDvS3zToKcDpRsLuRolQJBVGdozk= -github.com/cockroachdb/pebble v0.0.0-20230209160836-829675f94811/go.mod h1:Nb5lgvnQ2+oGlE/EyZy4+2/CxRh9KfvCXnag1vtpxVM= -github.com/cockroachdb/redact v1.1.3 h1:AKZds10rFSIj7qADf0g46UixK8NNLwWTNdCIGS5wfSQ= -github.com/cockroachdb/redact v1.1.3/go.mod h1:BVNblN9mBWFyMyqK1k3AAiSxhvhfK2oOZZ2lK+dpvRg= +github.com/cockroachdb/errors v1.8.1 h1:A5+txlVZfOqFBDa4mGz2bUWSp0aHElvHX2bKkdbQu+Y= +github.com/cockroachdb/errors v1.8.1/go.mod h1:qGwQn6JmZ+oMjuLwjWzUNqblqk0xl4CVV3SQbGwK7Ac= +github.com/cockroachdb/logtags v0.0.0-20190617123548-eb05cc24525f h1:o/kfcElHqOiXqcou5a3rIlMc7oJbMQkeLk0VQJ7zgqY= +github.com/cockroachdb/logtags v0.0.0-20190617123548-eb05cc24525f/go.mod h1:i/u985jwjWRlyHXQbwatDASoW0RMlZ/3i9yJHE2xLkI= +github.com/cockroachdb/pebble v0.0.0-20230928194634-aa077af62593 h1:aPEJyR4rPBvDmeyi+l/FS/VtA00IWvjeFvjen1m1l1A= +github.com/cockroachdb/pebble v0.0.0-20230928194634-aa077af62593/go.mod h1:6hk1eMY/u5t+Cf18q5lFMUA1Rc+Sm5I6Ra1QuPyxXCo= +github.com/cockroachdb/redact v1.0.8 h1:8QG/764wK+vmEYoOlfobpe12EQcS81ukx/a4hdVMxNw= +github.com/cockroachdb/redact v1.0.8/go.mod h1:BVNblN9mBWFyMyqK1k3AAiSxhvhfK2oOZZ2lK+dpvRg= +github.com/cockroachdb/sentry-go v0.6.1-cockroachdb.2 h1:IKgmqgMQlVJIZj19CdocBeSfSaiCbEBZGKODaixqtHM= +github.com/cockroachdb/sentry-go v0.6.1-cockroachdb.2/go.mod h1:8BT+cPK6xvFOcRlk0R8eg+OTkcqI6baNH4xAkpiYVvQ= +github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06 h1:zuQyyAKVxetITBuuhv3BI9cMrmStnpT18zmgmTxunpo= +github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06/go.mod h1:7nc4anLGjupUW/PeY5qiNYsdNXj7zopG+eqsS7To5IQ= +github.com/consensys/bavard v0.1.13 h1:oLhMLOFGTLdlda/kma4VOJazblc7IM5y5QPd2A/YjhQ= +github.com/consensys/bavard v0.1.13/go.mod h1:9ItSMtA/dXMAiL7BG6bqW2m3NdSEObYWoH223nGHukI= +github.com/consensys/gnark-crypto v0.12.1 h1:lHH39WuuFgVHONRl3J0LRBtuYdQTumFSDtJF7HpyG8M= +github.com/consensys/gnark-crypto v0.12.1/go.mod h1:v2Gy7L/4ZRosZ7Ivs+9SfUDr0f5UlG+EM5t7MPHiLuY= github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w= github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/crate-crypto/go-ipa v0.0.0-20231025140028-3c0104f4b233 h1:d28BXYi+wUpz1KBmiF9bWrjEMacUEREV6MBi2ODnrfQ= +github.com/crate-crypto/go-ipa v0.0.0-20231025140028-3c0104f4b233/go.mod h1:geZJZH3SzKCqnz5VT0q/DyIG/tvu/dZk+VIfXicupJs= +github.com/crate-crypto/go-kzg-4844 v0.7.0 h1:C0vgZRk4q4EZ/JgPfzuSoxdCq3C3mOZMBShovmncxvA= +github.com/crate-crypto/go-kzg-4844 v0.7.0/go.mod h1:1kMhvPgI0Ky3yIa+9lFySEBUBXkYxeOi8ZF1sYioxhc= github.com/danieljoos/wincred v1.2.0 h1:ozqKHaLK0W/ii4KVbbvluM91W2H3Sh0BncbUNPS7jLE= github.com/danieljoos/wincred v1.2.0/go.mod h1:FzQLLMKBFdvu+osBrnFODiv32YGwCfx0SkRa/eYHgec= github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -75,10 +91,12 @@ github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2 h1:tdlZCpZ/P9DhczC github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= -github.com/ethereum/go-ethereum v1.12.0 h1:bdnhLPtqETd4m3mS8BGMNvBTf36bO5bx/hxE2zljOa0= -github.com/ethereum/go-ethereum v1.12.0/go.mod h1:/oo2X/dZLJjf2mJ6YT9wcWxa4nNJDBKDBU6sFIpx1Gs= -github.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5 h1:FtmdgXiUlNeRsoNMFlKLDt+S+6hbjVMEW6RGQ7aUf7c= -github.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5/go.mod h1:VvhXpOYNQvB+uIk2RvXzuaQtkQJzzIx6lSBe1xv7hi0= +github.com/ethereum/c-kzg-4844 v0.4.0 h1:3MS1s4JtA868KpJxroZoepdV0ZKBp3u/O5HcZ7R3nlY= +github.com/ethereum/c-kzg-4844 v0.4.0/go.mod h1:VewdlzQmpT5QSrVhbBuGoCdFJkpaJlO1aQputP83wc0= +github.com/ethereum/go-ethereum v1.13.15 h1:U7sSGYGo4SPjP6iNIifNoyIAiNjrmQkz6EwQG+/EZWo= +github.com/ethereum/go-ethereum v1.13.15/go.mod h1:TN8ZiHrdJwSe8Cb6x+p0hs5CxhJZPbqB7hHkaUXcmIU= +github.com/fjl/memsize v0.0.2 h1:27txuSD9or+NZlnOWdKUxeBzTAUkWCVh+4Gf2dWFOzA= +github.com/fjl/memsize v0.0.2/go.mod h1:VvhXpOYNQvB+uIk2RvXzuaQtkQJzzIx6lSBe1xv7hi0= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= @@ -86,8 +104,8 @@ github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uq github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk= github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff h1:tY80oXqGNY4FhTFhk+o9oFHGINQ/+vhlm8HFzi6znCI= github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff/go.mod h1:x7DCsMOv1taUwEWCzT4cmDeAkigA5/QCwUodaVOe8Ww= -github.com/getsentry/sentry-go v0.18.0 h1:MtBW5H9QgdcJabtZcuJG80BMOwaBpkRDZkxRkNC1sN0= -github.com/getsentry/sentry-go v0.18.0/go.mod h1:Kgon4Mby+FJ7ZWHFUAZgVaIa8sxHtnRJRLTXZr51aKQ= +github.com/gballet/go-verkle v0.1.1-0.20231031103413-a67434b50f46 h1:BAIP2GihuqhwdILrV+7GJel5lyPV3u1+PgzrWLc0TkE= +github.com/gballet/go-verkle v0.1.1-0.20231031103413-a67434b50f46/go.mod h1:QNpY22eby74jVhqH4WhDLDwxc/vqsern6pW+u2kbkpc= github.com/gin-contrib/cors v1.7.2 h1:oLDHxdg8W/XDoN/8zamqk/Drgt4oVZDvaV0YmvVICQw= github.com/gin-contrib/cors v1.7.2/go.mod h1:SUJVARKgQ40dmrzgXEVxj2m7Ig1v1qIboQkPDTQ9t2E= github.com/gin-contrib/gzip v0.0.6 h1:NjcunTcGAj5CO1gn4N8jHOSIeRFHIbn51z6K+xaN4d4= @@ -116,8 +134,6 @@ github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJn github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= github.com/go-playground/validator/v10 v10.20.0 h1:K9ISHbSaI0lyB2eWMPJo+kOS/FBExVwjEviJTixqxL8= github.com/go-playground/validator/v10 v10.20.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM= -github.com/go-stack/stack v1.8.1 h1:ntEHSVwIt7PNXNpgPmVfMrNhLtgjlmnZha2kOpuRiDw= -github.com/go-stack/stack v1.8.1/go.mod h1:dcoOX6HbPZSZptuspn9bctJ+N/CnF5gGygcUP3XYfe4= github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU= github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk= @@ -126,8 +142,8 @@ github.com/gofrs/flock v0.8.1 h1:+gYjHKf32LDeiEEFhQaotPbLuUXjY5ZqxKgXy7n59aw= github.com/gofrs/flock v0.8.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= -github.com/golang-jwt/jwt/v4 v4.3.0 h1:kHL1vqdqWNfATmA0FNMdmZNMyZI1U6O31X4rlIPoBog= -github.com/golang-jwt/jwt/v4 v4.3.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg= +github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg= +github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/glog v1.0.0 h1:nfP3RFugxnNRyKgeWd4oI1nYvXpxrx8ck8ZrcizshdQ= github.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4= @@ -137,8 +153,8 @@ github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfb github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= -github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= -github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= +github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb h1:PBC98N2aIaM3XXiurYmW7fx4GZkL8feAMVq7nEjURHk= github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/flatbuffers v1.12.1 h1:MVlul7pQNoDzWRLTw5imwYsl+usrS1TXG2H4jg6ImGw= @@ -150,19 +166,24 @@ github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeN github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= +github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/subcommands v1.2.0/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk= github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/hashicorp/go-bexpr v0.1.10 h1:9kuI5PFotCboP3dkDYFr/wi0gg0QVbSNz5oFRpxn4uE= github.com/hashicorp/go-bexpr v0.1.10/go.mod h1:oxlubA2vC/gFVfX1A6JGp7ls7uCDlfJn732ehYYg+g0= +github.com/holiman/billy v0.0.0-20240216141850-2abb0c79d3c4 h1:X4egAf/gcS1zATw6wn4Ej8vjuVGxeHdan+bRb2ebyv4= +github.com/holiman/billy v0.0.0-20240216141850-2abb0c79d3c4/go.mod h1:5GuXa7vkL8u9FkFuWdVvfR5ix8hRB7DbOAaYULamFpc= github.com/holiman/bloomfilter/v2 v2.0.3 h1:73e0e/V0tCydx14a0SCYS/EWCxgwLZ18CZcZKVu0fao= github.com/holiman/bloomfilter/v2 v2.0.3/go.mod h1:zpoh+gs7qcpqrHr3dB55AMiJwo0iURXE7ZOP9L9hSkA= github.com/holiman/uint256 v1.2.4 h1:jUc4Nk8fm9jZabQuqr2JzednajVmBpC+oiTiXZJEApU= github.com/holiman/uint256 v1.2.4/go.mod h1:EOMSn4q6Nyt9P6efbI3bueV4e1b3dGlUCXeiRV4ng7E= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= -github.com/huin/goupnp v1.0.3 h1:N8No57ls+MnjlB+JPiCVSOyy/ot7MJTqlo7rn+NYSqQ= -github.com/huin/goupnp v1.0.3/go.mod h1:ZxNlw5WqJj6wSsRK5+YfflQGXYfccj5VgQsMNixHM7Y= +github.com/huin/goupnp v1.3.0 h1:UvLUlWDNpoUdYzb2TCn+MuTWtcjXKSza2n6CBdQ0xXc= +github.com/huin/goupnp v1.3.0/go.mod h1:gnGPsThkYa7bFi/KWmEysQRf48l2dvR5bxr2OFckNX8= github.com/jackpal/go-nat-pmp v1.0.2 h1:KzKSgb7qkJvOUTqYl9/Hg/me3pWgBmERKrTGD7BdWus= github.com/jackpal/go-nat-pmp v1.0.2/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc= github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= @@ -188,6 +209,8 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= +github.com/leanovate/gopter v0.2.9 h1:fQjYxZaynp97ozCzfOyOuAGOU4aU/z37zf/tOujFk7c= +github.com/leanovate/gopter v0.2.9/go.mod h1:U2L/78B+KVFIx2VmW6onHJQzXtFb+p5y3y2Sh+Jxxv8= github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ= github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI= github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ81pIr0yLvtUWk2if982qA3F3QD6H4= @@ -200,14 +223,15 @@ github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWE github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-runewidth v0.0.14 h1:+xnbZSEeDbOIg5/mE6JF0w6n9duR1l3/WmbinWVwUuU= github.com/mattn/go-runewidth v0.0.14/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= -github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= -github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= -github.com/miguelmota/go-ethereum-hdwallet v0.1.2 h1:mz9LO6V7QCRkLYb0AH17t5R8KeqCe3E+hx9YXpmZeXA= -github.com/miguelmota/go-ethereum-hdwallet v0.1.2/go.mod h1:fdNwFSoBFVBPnU0xpOd6l2ueqsPSH/Gch5kIvSvTGk8= +github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 h1:I0XW9+e1XWDxdcEniV4rQAIOPUGDq67JSCiRCgGCZLI= +github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/pointerstructure v1.2.0 h1:O+i9nHnXS3l/9Wu7r4NrEdwA2VFTicjUEN1uBnDo34A= github.com/mitchellh/pointerstructure v1.2.0/go.mod h1:BRAsLI5zgXmw97Lf6s25bs8ohIXc3tViBH44KcwB2g4= +github.com/mmcloughlin/addchain v0.4.0 h1:SobOdjm2xLj1KkXN5/n0xTIWyZA2+s99UCY1iPfkHRY= +github.com/mmcloughlin/addchain v0.4.0/go.mod h1:A86O+tHqZLMNO4w6ZZ4FlVQEadcoqkyU72HC5wJ4RlU= +github.com/mmcloughlin/profile v0.1.1/go.mod h1:IhHD7q1ooxgwTgjxQYkACGA77oFTDdFVejUS1/tS/qU= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -228,14 +252,14 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c h1:ncq/mPwQF4JjgDlrVEn3C11VoGHZN7m8qihwgMEtzYw= github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= -github.com/prometheus/client_golang v1.14.0 h1:nJdhIvne2eSX/XRAFV9PcvFFRbrjbcTUj0VP62TMhnw= -github.com/prometheus/client_golang v1.14.0/go.mod h1:8vpkKitgIVNcqrRBWh1C4TIUQgYNtG/XQE4E/Zae36Y= -github.com/prometheus/client_model v0.3.0 h1:UBgGFHqYdG/TPFD1B1ogZywDqEkwp3fBMvqdiQ7Xew4= -github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w= -github.com/prometheus/common v0.39.0 h1:oOyhkDq05hPZKItWVBkJ6g6AtGxi+fy7F4JvUV8uhsI= -github.com/prometheus/common v0.39.0/go.mod h1:6XBZ7lYdLCbkAVhwRsWTZn+IN5AB9F/NXd5w0BbEX0Y= -github.com/prometheus/procfs v0.9.0 h1:wzCHvIvM5SxWqYvwgVL7yJY8Lz3PKn49KQtpgMYJfhI= -github.com/prometheus/procfs v0.9.0/go.mod h1:+pB4zwohETzFnmlpe6yd2lSc+0/46IYZRB/chUwxUZY= +github.com/prometheus/client_golang v1.12.0 h1:C+UIj/QWtmqY13Arb8kwMt5j34/0Z2iKamrJ+ryC0Gg= +github.com/prometheus/client_golang v1.12.0/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= +github.com/prometheus/client_model v0.2.1-0.20210607210712-147c58e9608a h1:CmF68hwI0XsOQ5UwlBopMi2Ow4Pbg32akc4KIVCOm+Y= +github.com/prometheus/client_model v0.2.1-0.20210607210712-147c58e9608a/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w= +github.com/prometheus/common v0.32.1 h1:hWIdL3N2HoUx3B8j3YN9mWor0qhY/NlEKZEaXxuIRh4= +github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= +github.com/prometheus/procfs v0.7.3 h1:4jVXhlkAyzOScmCkXBTOLRLTz8EeU+eyjrwB/EPq0VU= +github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= @@ -244,8 +268,8 @@ github.com/rs/cors v1.7.0 h1:+88SsELBHx5r+hZ8TCkggzSstaWNbDvThkVK8H6f9ik= github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= -github.com/sashabaranov/go-openai v1.21.0 h1:isAf3zPSD3VLd0pC2/2Q6ZyRK7jzPAaz+X3rjsviaYQ= -github.com/sashabaranov/go-openai v1.21.0/go.mod h1:lj5b/K+zjTSFxVLijLSTDZuP7adOgerWeFyZLUhAKRg= +github.com/sashabaranov/go-openai v1.24.1 h1:DWK95XViNb+agQtuzsn+FyHhn3HQJ7Va8z04DQDJ1MI= +github.com/sashabaranov/go-openai v1.24.1/go.mod h1:lj5b/K+zjTSFxVLijLSTDZuP7adOgerWeFyZLUhAKRg= github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible h1:Bn1aCHHRnjv4Bl16T8rcaFjYSrGrIZvpiGO6P3Q4GpU= github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= github.com/shirou/gopsutil/v3 v3.23.11 h1:i3jP9NjCPUz7FiZKxlMnODZkdSIp2gnzfrvsu9CuWEQ= @@ -270,12 +294,14 @@ github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/supranational/blst v0.3.11 h1:LyU6FolezeWAhvQk0k6O/d49jqgO52MSDDfYgbeoEm4= +github.com/supranational/blst v0.3.11/go.mod h1:jZJtfjgudtNl4en1tzwPIV3KjUnQUvG3/j+w+fVonLw= github.com/swaggo/files v1.0.1 h1:J1bVJ4XHZNq0I46UU90611i9/YzdrF7x92oX1ig5IdE= github.com/swaggo/files v1.0.1/go.mod h1:0qXmMNH6sXNf+73t65aKeB+ApmgxdnkQzVTAj2uaMUg= github.com/swaggo/gin-swagger v1.6.0 h1:y8sxvQ3E20/RCyrXeFfg60r6H0Z+SwpTjMYsMm+zy8M= github.com/swaggo/gin-swagger v1.6.0/go.mod h1:BG00cCEy294xtVpyIAHG6+e2Qzj/xKlRdOqDkvq0uzo= -github.com/swaggo/swag v1.16.3 h1:PnCYjPCah8FK4I26l2F/KQ4yz3sILcVUN3cTlBFA9Pg= -github.com/swaggo/swag v1.16.3/go.mod h1:DImHIuOFXKpMFAQjcC7FG4m3Dg4+QuUgUzJmKjI/gRk= +github.com/swaggo/swag v1.16.4 h1:clWJtd9LStiG3VeijiCfOVODP6VpHtKdQy9ELFG3s1A= +github.com/swaggo/swag v1.16.4/go.mod h1:VBsHJRsDvfYvqoiMKnsdwhNV9LEMHgEDZcyVYX0sxPg= github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 h1:epCh84lMvA70Z7CTTCmYQn2CKbY8j86K7/FAIr141uY= github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7/go.mod h1:q4W45IWZaF22tdD+VEXcAWRA037jwmWEB5VWYORlTpc= github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFAEVmqU= @@ -288,8 +314,8 @@ github.com/tyler-smith/go-bip39 v1.1.0 h1:5eUemwrMargf3BSLRRCalXT93Ns6pQJIjYQN2n github.com/tyler-smith/go-bip39 v1.1.0/go.mod h1:gUYDtqQw1JS3ZJ8UWVcGTGqqr6YIN3CWg+kkNaLt55U= github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE= github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= -github.com/urfave/cli/v2 v2.17.2-0.20221006022127-8f469abc00aa h1:5SqCsI/2Qya2bCzK15ozrqo2sZxkh0FHynJZOTVoV6Q= -github.com/urfave/cli/v2 v2.17.2-0.20221006022127-8f469abc00aa/go.mod h1:1CNUng3PtjQMtRzJO4FMXBQvkGtuYRxxiR9xMa7jMwI= +github.com/urfave/cli/v2 v2.25.7 h1:VAzn5oq403l5pHjc4OhD54+XGO9cdKVL/7lDjF+iKUs= +github.com/urfave/cli/v2 v2.25.7/go.mod h1:8qnjx1vcq5s2/wpsqoZFndg2CE5tNFyrTvS6SinrnYQ= github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU= github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= @@ -322,8 +348,8 @@ golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5y golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI= golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63 h1:m64FZMko/V45gv0bNmrNYoDEq8U5YUhetc9cBWKS1TQ= -golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63/go.mod h1:0v4NqG35kSWCMzLaMeX+IQrlSnVE/bqGSyC2cz/9Le8= +golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa h1:FRnLl4eNAQl8hwxVVC17teOw8kdjVDVAiFMtgUdTSRQ= +golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa/go.mod h1:zk2irFbV9DP96SEBUUAy67IdHUaZuSnrz1n472HUCLE= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= @@ -387,8 +413,8 @@ golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk= golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= -golang.org/x/time v0.0.0-20220922220347-f3bd1da661af h1:Yx9k8YCG3dvF87UAn2tu2HQLf2dt/eR1bXxpLMWeH+Y= -golang.org/x/time v0.0.0-20220922220347-f3bd1da661af/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= +golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= @@ -419,14 +445,16 @@ gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EV gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/natefinch/lumberjack.v2 v2.0.0 h1:1Lc07Kr7qY4U2YPouBjpCLxpiyxIVoxqXgkXLknAOE8= gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= -gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce h1:+JknDZhAj8YMt7GC73Ei8pv4MzjDUNPHgQWJdtMAaDU= -gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce/go.mod h1:5AcXVHNjg+BDxry382+8OKon8SEWiKktQR07RKPsv1c= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50= rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= +rsc.io/tmplfunc v0.0.3 h1:53XFQh69AfOa8Tw0Jm7t+GV7KZhOi6jzsCzTtKbMvzU= +rsc.io/tmplfunc v0.0.3/go.mod h1:AG3sTPzElb1Io3Yg4voV9AGZJuleGAwaVRxL9M49PhA= diff --git a/proxy-router/internal/aiengine/ai_engine.go b/proxy-router/internal/aiengine/ai_engine.go index 5d8c7e3f..475c5fd9 100644 --- a/proxy-router/internal/aiengine/ai_engine.go +++ b/proxy-router/internal/aiengine/ai_engine.go @@ -1,32 +1,21 @@ package aiengine import ( - "bufio" - "bytes" "context" - "encoding/json" "errors" - "io" - "net/http" - "strings" - "time" "fmt" - c "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal" - constants "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal" + gcs "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/chatstorage/genericchatstorage" "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/config" "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/lib" - "github.com/gin-gonic/gin" - "github.com/sashabaranov/go-openai" - api "github.com/sashabaranov/go-openai" + "github.com/ethereum/go-ethereum/common" ) type AiEngine struct { - client *api.Client - baseURL string - apiKey string modelsConfigLoader *config.ModelConfigLoader + service ProxyService + storage gcs.ChatStorageInterface log lib.ILogger } @@ -38,250 +27,46 @@ var ( ErrJobFailed = errors.New("job failed") ) -func NewAiEngine(apiBaseURL, apiKey string, modelsConfigLoader *config.ModelConfigLoader, log lib.ILogger) *AiEngine { +func NewAiEngine(service ProxyService, storage gcs.ChatStorageInterface, modelsConfigLoader *config.ModelConfigLoader, log lib.ILogger) *AiEngine { return &AiEngine{ modelsConfigLoader: modelsConfigLoader, - baseURL: apiBaseURL, - apiKey: apiKey, - client: api.NewClientWithConfig(api.ClientConfig{ - BaseURL: apiBaseURL, - APIType: api.APITypeOpenAI, - HTTPClient: &http.Client{}, - }), - log: log, + service: service, + storage: storage, + log: log, } } -func (a *AiEngine) Prompt(ctx context.Context, request *api.ChatCompletionRequest) (*api.ChatCompletionResponse, error) { - response, err := a.client.CreateChatCompletion( - ctx, - *request, - ) - - if err != nil { - err = lib.WrapError(ErrChatCompletion, err) - a.log.Error(err) - return nil, err - } - return &response, nil -} - -func (a *AiEngine) PromptProdiaImage(ctx context.Context, request *ProdiaGenerationRequest, chunkCallback CompletionCallback) error { - url := request.ApiUrl - apiKey := request.ApiKey - - body := map[string]string{ - "model": request.Model, - "prompt": request.Prompt, - } - payload, err := json.Marshal(body) - if err != nil { - err = lib.WrapError(ErrImageGenerationInvalidRequest, err) - a.log.Error(err) - return err - } - - req, _ := http.NewRequest("POST", url, bytes.NewReader(payload)) - - req.Header.Add("accept", constants.CONTENT_TYPE_JSON) - req.Header.Add("content-type", constants.CONTENT_TYPE_JSON) - req.Header.Add("X-Prodia-Key", apiKey) - - res, err := http.DefaultClient.Do(req) - if err != nil { - err = lib.WrapError(ErrImageGenerationRequest, err) - a.log.Error(err) - return err - } - - defer res.Body.Close() - response, _ := io.ReadAll(res.Body) - - bodyStr := string(response) - if strings.Contains(bodyStr, "Invalid Generation Parameters") { - return ErrImageGenerationInvalidRequest - } - - result := ProdiaGenerationResult{} - err = json.Unmarshal(response, &result) - if err != nil { - err = lib.WrapError(ErrImageGenerationRequest, err) - a.log.Error(err) - return err - } - - job, err := a.waitJobResult(ctx, result.Job, apiKey) - if err != nil { - err = lib.WrapError(ErrImageGenerationRequest, err) - a.log.Error(err) - return err - } - - return chunkCallback(job) -} - -func (a *AiEngine) waitJobResult(ctx context.Context, jobID string, apiKey string) (*ProdiaGenerationResult, error) { - url := fmt.Sprintf("https://api.prodia.com/v1/job/%s", jobID) - - req, err := http.NewRequestWithContext(ctx, "GET", url, nil) - if err != nil { - err = lib.WrapError(ErrJobCheckRequest, err) - a.log.Error(err) - return nil, err - } - - req.Header.Add("accept", constants.CONTENT_TYPE_JSON) - req.Header.Add("X-Prodia-Key", apiKey) - - res, err := http.DefaultClient.Do(req) - if err != nil { - err = lib.WrapError(ErrJobCheckRequest, err) - a.log.Error(err) - return nil, err - } - - defer res.Body.Close() - body, err := io.ReadAll(res.Body) - if err != nil { - err = lib.WrapError(ErrJobCheckRequest, err) - a.log.Error(err) - return nil, err - } - - var result ProdiaGenerationResult - err = json.Unmarshal(body, &result) - if err != nil { - err = lib.WrapError(ErrJobCheckRequest, err) - a.log.Error(err) - return nil, err - } - - if result.Status == "succeeded" { - return &result, nil - } - - if result.Status == "failed" { - return nil, ErrJobFailed - } - - select { - case <-ctx.Done(): - return nil, ctx.Err() - case <-time.After(1 * time.Second): - } - return a.waitJobResult(ctx, jobID, apiKey) -} - -func (a *AiEngine) PromptStream(ctx context.Context, request *api.ChatCompletionRequest, chunkCallback CompletionCallback) (*api.ChatCompletionStreamResponse, error) { - resp, err := a.requestChatCompletionStream(ctx, request, chunkCallback) - - if err != nil { - err = lib.WrapError(ErrChatCompletion, err) - a.log.Error(err) - return nil, err - } - - return resp, nil -} - -func (a *AiEngine) PromptCb(ctx *gin.Context, body *openai.ChatCompletionRequest) (interface{}, error) { - chunks := []interface{}{} - if body.Stream { - response, err := a.PromptStream(ctx, body, func(response interface{}) error { - marshalledResponse, err := json.Marshal(response) - if err != nil { - return err - } - - ctx.Writer.Header().Set(c.HEADER_CONTENT_TYPE, c.CONTENT_TYPE_EVENT_STREAM) - - _, err = ctx.Writer.Write([]byte(fmt.Sprintf("data: %s\n\n", marshalledResponse))) - if err != nil { - return err - } - - chunks = append(chunks, response) - - ctx.Writer.Flush() - return nil - }) - - if err != nil { - ctx.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) - return "", err +func (a *AiEngine) GetAdapter(ctx context.Context, chatID, modelID, sessionID common.Hash, storeChatContext, forwardChatContext bool) (AIEngineStream, error) { + var engine AIEngineStream + if sessionID == (common.Hash{}) { + // local model + modelConfig := a.modelsConfigLoader.ModelConfigFromID(modelID.Hex()) + if modelConfig == nil { + return nil, fmt.Errorf("model not found: %s", modelID.Hex()) } - - ctx.JSON(http.StatusOK, response) - return chunks, nil - } else { - response, err := a.Prompt(ctx, body) - if err != nil { - ctx.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) - return "", err + var ok bool + engine, ok = ApiAdapterFactory(modelConfig.ApiType, modelConfig.ModelName, modelConfig.ApiURL, modelConfig.ApiKey, modelConfig.Parameters, a.log) + if !ok { + return nil, fmt.Errorf("api adapter not found: %s", modelConfig.ApiType) } - chunks = append(chunks, response) - ctx.JSON(http.StatusOK, response) - return chunks, nil - } -} - -func (a *AiEngine) requestChatCompletionStream(ctx context.Context, request *api.ChatCompletionRequest, callback CompletionCallback) (*api.ChatCompletionStreamResponse, error) { - requestBody, err := json.Marshal(request) - if err != nil { - return nil, fmt.Errorf("failed to encode request: %v", err) - } - - req, err := http.NewRequestWithContext(ctx, "POST", a.baseURL+"/chat/completions", bytes.NewReader(requestBody)) - if err != nil { - return nil, fmt.Errorf("failed to create request: %v", err) - } - - if a.apiKey != "" { - req.Header.Set(c.HEADER_AUTHORIZATION, fmt.Sprintf("%s %s", c.BEARER, a.apiKey)) - } - req.Header.Set(c.HEADER_CONTENT_TYPE, c.CONTENT_TYPE_JSON) - req.Header.Set(c.HEADER_ACCEPT, c.CONTENT_TYPE_EVENT_STREAM) - req.Header.Set(c.HEADER_CONNECTION, c.CONNECTION_KEEP_ALIVE) - - client := &http.Client{} - resp, err := client.Do(req) - if err != nil { - return nil, fmt.Errorf("failed to send request: %v", err) + } else { + // remote model + engine = &RemoteModel{sessionID: sessionID, service: a.service} } - defer resp.Body.Close() - scanner := bufio.NewScanner(resp.Body) - for scanner.Scan() { - line := scanner.Text() - - if strings.HasPrefix(line, "data: ") { - data := line[6:] // Skip the "data: " prefix - var completion api.ChatCompletionStreamResponse - if err := json.Unmarshal([]byte(data), &completion); err != nil { - if strings.Index(data, "[DONE]") != -1 { - a.log.Debugf("reached end of the response") - } else { - a.log.Errorf("error decoding response: %s\n%s", err, line) - } - continue - } - // Call the callback function with the unmarshalled completion - err := callback(&completion) + if storeChatContext { + var actualModelID common.Hash + if modelID == (common.Hash{}) { + modelID, err := a.service.GetModelIdSession(ctx, sessionID) if err != nil { - return nil, fmt.Errorf("callback failed: %v", err) + return nil, err } + actualModelID = modelID } + engine = NewHistory(engine, a.storage, chatID, actualModelID, forwardChatContext, a.log) } - if err := scanner.Err(); err != nil { - return nil, fmt.Errorf("error reading stream: %v", err) - } - - return nil, err -} - -func (a *AiEngine) GetModelsConfig() ([]string, []config.ModelConfig) { - return a.modelsConfigLoader.GetAll() + return engine, nil } func (a *AiEngine) GetLocalModels() ([]LocalModel, error) { @@ -290,10 +75,13 @@ func (a *AiEngine) GetLocalModels() ([]LocalModel, error) { IDs, modelsFromConfig := a.modelsConfigLoader.GetAll() for i, model := range modelsFromConfig { models = append(models, LocalModel{ - Id: IDs[i], - Name: model.ModelName, - Model: model.ModelName, - ApiType: model.ApiType, + Id: IDs[i].Hex(), + Name: model.ModelName, + Model: model.ModelName, + ApiType: model.ApiType, + ApiUrl: model.ApiURL, + Slots: model.ConcurrentSlots, + CapacityPolicy: model.CapacityPolicy, }) } diff --git a/proxy-router/internal/aiengine/conn_checker.go b/proxy-router/internal/aiengine/conn_checker.go new file mode 100644 index 00000000..9298fe74 --- /dev/null +++ b/proxy-router/internal/aiengine/conn_checker.go @@ -0,0 +1,53 @@ +package aiengine + +import ( + "context" + "errors" + "net" + "net/url" + "time" + + "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/lib" +) + +const ( + TimeoutConnectDefault = 3 * time.Second +) + +var ( + ErrCannotParseURL = errors.New("cannot parse URL") + ErrCannotConnect = errors.New("cannot connect") + ErrConnectTimeout = errors.New("connection timeout") +) + +type ConnectionChecker struct{} + +func (*ConnectionChecker) TryConnect(ctx context.Context, URL string) error { + if _, ok := ctx.Deadline(); !ok { + var cancel context.CancelFunc + ctx, cancel = context.WithTimeoutCause(ctx, TimeoutConnectDefault, ErrConnectTimeout) + defer cancel() + } + u, err := url.Parse(URL) + if err != nil { + return lib.WrapError(ErrCannotParseURL, err) + } + + var host string + if u.Port() == "" { + host = net.JoinHostPort(u.Hostname(), "443") + } else { + host = u.Host + } + + dialer := net.Dialer{} + + conn, err := dialer.DialContext(ctx, "tcp", host) + if err != nil { + return lib.WrapError(ErrCannotConnect, err) + } + + defer conn.Close() + + return nil +} diff --git a/proxy-router/internal/aiengine/factory.go b/proxy-router/internal/aiengine/factory.go new file mode 100644 index 00000000..b710529e --- /dev/null +++ b/proxy-router/internal/aiengine/factory.go @@ -0,0 +1,19 @@ +package aiengine + +import "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/lib" + +func ApiAdapterFactory(apiType string, modelName string, url string, apikey string, parameters ModelParameters, log lib.ILogger) (AIEngineStream, bool) { + switch apiType { + case API_TYPE_OPENAI: + return NewOpenAIEngine(modelName, url, apikey, log), true + case API_TYPE_PRODIA_SD: + return NewProdiaSDEngine(modelName, url, apikey, log), true + case API_TYPE_PRODIA_SDXL: + return NewProdiaSDXLEngine(modelName, url, apikey, log), true + case API_TYPE_PRODIA_V2: + return NewProdiaV2Engine(modelName, url, apikey, log), true + case API_TYPE_HYPERBOLIC_SD: + return NewHyperbolicSDEngine(modelName, url, apikey, parameters, log), true + } + return nil, false +} diff --git a/proxy-router/internal/aiengine/history.go b/proxy-router/internal/aiengine/history.go new file mode 100644 index 00000000..362ca71c --- /dev/null +++ b/proxy-router/internal/aiengine/history.go @@ -0,0 +1,69 @@ +package aiengine + +import ( + "context" + "time" + + gcs "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/chatstorage/genericchatstorage" + "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/lib" + "github.com/ethereum/go-ethereum/common" + "github.com/sashabaranov/go-openai" +) + +type History struct { + engine AIEngineStream + storage gcs.ChatStorageInterface + chatID common.Hash + modelID common.Hash + forwardChatContext bool + log lib.ILogger +} + +func NewHistory(engine AIEngineStream, storage gcs.ChatStorageInterface, chatID, modelID common.Hash, forwardChatContext bool, log lib.ILogger) *History { + return &History{ + engine: engine, + storage: storage, + chatID: chatID, + modelID: modelID, + forwardChatContext: forwardChatContext, + log: log, + } +} + +func (h *History) Prompt(ctx context.Context, prompt *openai.ChatCompletionRequest, cb gcs.CompletionCallback) error { + isLocal := h.engine.ApiType() != "remote" + completions := make([]gcs.Chunk, 0) + startTime := time.Now() + + history, err := h.storage.LoadChatFromFile(h.chatID.Hex()) + if err != nil { + h.log.Warnf("failed to load chat history: %v", err) + } + + adjustedPrompt := prompt + if h.forwardChatContext { + adjustedPrompt = history.AppendChatHistory(prompt) + } + + err = h.engine.Prompt(ctx, adjustedPrompt, func(ctx context.Context, completion gcs.Chunk) error { + completions = append(completions, completion) + return cb(ctx, completion) + }) + if err != nil { + return err + } + endTime := time.Now() + + err = h.storage.StorePromptResponseToFile(h.chatID.Hex(), isLocal, h.modelID.Hex(), prompt, completions, startTime, endTime) + if err != nil { + h.log.Errorf("failed to store prompt response: %v", err) + } + + return err +} + +func (h *History) ApiType() string { + return h.engine.ApiType() +} + +var _ AIEngineStream = &History{} diff --git a/proxy-router/internal/aiengine/hyperbolic_sd.go b/proxy-router/internal/aiengine/hyperbolic_sd.go new file mode 100644 index 00000000..868ee2c5 --- /dev/null +++ b/proxy-router/internal/aiengine/hyperbolic_sd.go @@ -0,0 +1,115 @@ +package aiengine + +import ( + "bytes" + "context" + "encoding/json" + "fmt" + "io" + "net/http" + + c "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal" + gcs "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/chatstorage/genericchatstorage" + "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/lib" + "github.com/sashabaranov/go-openai" +) + +const API_TYPE_HYPERBOLIC_SD = "hyperbolic-sd" +const HYPERBOLIC_DEFAULT_BASE_URL = "https://api.hyperbolic.xyz/v1" + +type HyperbolicSD struct { + modelName string + apiURL string + apiKey string + parameters ModelParameters + + log lib.ILogger +} + +type HyperbolicImageGenerationResult struct { + Images []Image `json:"images"` +} + +type Image struct { + Image string `json:"image"` +} + +func NewHyperbolicSDEngine(modelName, apiURL, apiKey string, parameters ModelParameters, log lib.ILogger) *HyperbolicSD { + if apiURL == "" { + apiURL = HYPERBOLIC_DEFAULT_BASE_URL + } + return &HyperbolicSD{ + modelName: modelName, + apiURL: apiURL, + apiKey: apiKey, + log: log, + parameters: parameters, + } +} + +func (s *HyperbolicSD) Prompt(ctx context.Context, prompt *openai.ChatCompletionRequest, cb gcs.CompletionCallback) error { + body := map[string]string{ + "model_name": s.modelName, + "prompt": prompt.Messages[len(prompt.Messages)-1].Content, + "height": "512", + "width": "512", + "backend": "auto", + } + + for key, value := range s.parameters { + body[key] = value + } + + payload, err := json.Marshal(body) + if err != nil { + err = lib.WrapError(ErrImageGenerationInvalidRequest, err) + s.log.Error(err) + return err + } + + req, err := http.NewRequest("POST", fmt.Sprintf("%s/image/generation", s.apiURL), bytes.NewReader(payload)) + if err != nil { + err = lib.WrapError(ErrImageGenerationRequest, err) + s.log.Error(err) + } + + req.Header.Add(c.HEADER_ACCEPT, c.CONTENT_TYPE_JSON) + req.Header.Add(c.HEADER_CONTENT_TYPE, c.CONTENT_TYPE_JSON) + req.Header.Add(c.HEADER_AUTHORIZATION, fmt.Sprintf("%s %s", c.BEARER, s.apiKey)) + + res, err := http.DefaultClient.Do(req) + if err != nil { + err = lib.WrapError(ErrImageGenerationRequest, err) + s.log.Error(err) + return err + } + + defer res.Body.Close() + response, err := io.ReadAll(res.Body) + if err != nil { + err = lib.WrapError(ErrImageGenerationRequest, err) + s.log.Error(err) + return err + } + + result := HyperbolicImageGenerationResult{} + err = json.Unmarshal(response, &result) + if err != nil { + err = lib.WrapError(ErrImageGenerationRequest, err) + s.log.Error(err) + return err + } + + dataPrefix := "data:image/png;base64," + chunk := gcs.NewChunkImageRawContent(&gcs.ImageRawContentResult{ + ImageRawContent: dataPrefix + result.Images[0].Image, + }) + + return cb(ctx, chunk) +} + +func (s *HyperbolicSD) ApiType() string { + return API_TYPE_HYPERBOLIC_SD +} + +var _ AIEngineStream = &HyperbolicSD{} diff --git a/proxy-router/internal/aiengine/interfaces.go b/proxy-router/internal/aiengine/interfaces.go index 8b454dfe..1396cbde 100644 --- a/proxy-router/internal/aiengine/interfaces.go +++ b/proxy-router/internal/aiengine/interfaces.go @@ -1,34 +1,15 @@ package aiengine import ( - "net/http" -) - -type ResponderFlusher interface { - http.ResponseWriter - http.Flusher -} + "context" -type ProdiaGenerationResult struct { - Job string `json:"job"` - Status string `json:"status"` - ImageUrl string `json:"imageUrl" binding:"omitempty"` -} + "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/chatstorage/genericchatstorage" + "github.com/sashabaranov/go-openai" +) -type ProdiaGenerationRequest struct { - Model string `json:"model"` - Prompt string `json:"prompt"` - ApiUrl string `json:"apiUrl"` - ApiKey string `json:"apiKey"` +type AIEngineStream interface { + Prompt(ctx context.Context, prompt *openai.ChatCompletionRequest, cb genericchatstorage.CompletionCallback) error + ApiType() string } -type CompletionCallback func(completion interface{}) error - -type ProdiaImageGenerationCallback func(completion *ProdiaGenerationResult) error - -type LocalModel struct { - Id string - Name string - Model string - ApiType string -} +type ModelParameters map[string]string diff --git a/proxy-router/internal/aiengine/openai.go b/proxy-router/internal/aiengine/openai.go new file mode 100644 index 00000000..72136aaa --- /dev/null +++ b/proxy-router/internal/aiengine/openai.go @@ -0,0 +1,143 @@ +package aiengine + +import ( + "bufio" + "bytes" + "context" + "encoding/json" + "fmt" + "io" + "net/http" + "strings" + + c "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal" + gcs "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/chatstorage/genericchatstorage" + "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/lib" + "github.com/sashabaranov/go-openai" +) + +const API_TYPE_OPENAI = "openai" + +type OpenAI struct { + baseURL string + apiKey string + modelName string + client *http.Client + log lib.ILogger +} + +func NewOpenAIEngine(modelName, baseURL, apiKey string, log lib.ILogger) *OpenAI { + return &OpenAI{ + baseURL: baseURL, + modelName: modelName, + apiKey: apiKey, + client: &http.Client{}, + log: log, + } +} + +func (a *OpenAI) Prompt(ctx context.Context, compl *openai.ChatCompletionRequest, cb gcs.CompletionCallback) error { + compl.Model = a.modelName + requestBody, err := json.Marshal(compl) + if err != nil { + return fmt.Errorf("failed to encode request: %v", err) + } + + req, err := http.NewRequestWithContext(ctx, "POST", a.baseURL+"/chat/completions", bytes.NewReader(requestBody)) + if err != nil { + return fmt.Errorf("failed to create request: %v", err) + } + + if a.apiKey != "" { + req.Header.Set(c.HEADER_AUTHORIZATION, fmt.Sprintf("%s %s", c.BEARER, a.apiKey)) + } + req.Header.Set(c.HEADER_CONTENT_TYPE, c.CONTENT_TYPE_JSON) + req.Header.Set(c.HEADER_CONNECTION, c.CONNECTION_KEEP_ALIVE) + if compl.Stream { + req.Header.Set(c.HEADER_ACCEPT, c.CONTENT_TYPE_EVENT_STREAM) + } + resp, err := a.client.Do(req) + if err != nil { + return fmt.Errorf("failed to send request: %v", err) + } + defer resp.Body.Close() + + if isContentTypeStream(resp.Header) { + return a.readStream(ctx, resp.Body, cb) + } + + return a.readResponse(ctx, resp.Body, cb) +} + +func (a *OpenAI) readResponse(ctx context.Context, body io.Reader, cb gcs.CompletionCallback) error { + var compl openai.ChatCompletionResponse + if err := json.NewDecoder(body).Decode(&compl); err != nil { + return fmt.Errorf("failed to decode response: %v", err) + } + + text := make([]string, len(compl.Choices)) + for i, choice := range compl.Choices { + text[i] = choice.Message.Content + } + + chunk := gcs.NewChunkText(&compl) + err := cb(ctx, chunk) + if err != nil { + return fmt.Errorf("callback failed: %v", err) + } + + return nil +} + +func (a *OpenAI) readStream(ctx context.Context, body io.Reader, cb gcs.CompletionCallback) error { + scanner := bufio.NewScanner(body) + for scanner.Scan() { + line := scanner.Text() + + if strings.HasPrefix(line, StreamDataPrefix) { + data := line[len(StreamDataPrefix):] // Skip the "data: " prefix + var compl openai.ChatCompletionStreamResponse + if err := json.Unmarshal([]byte(data), &compl); err != nil { + if isStreamFinished(data) { + return nil + } else { + return fmt.Errorf("error decoding response: %s\n%s", err, line) + } + } + // Call the callback function with the unmarshalled completion + chunk := gcs.NewChunkStreaming(&compl) + err := cb(ctx, chunk) + if err != nil { + return fmt.Errorf("callback failed: %v", err) + } + } + } + + if err := scanner.Err(); err != nil { + return fmt.Errorf("error reading stream: %v", err) + } + + return nil +} + +func (a *OpenAI) ApiType() string { + return API_TYPE_OPENAI +} + +func isStreamFinished(data string) bool { + return strings.Index(data, StreamDone) != -1 +} + +func isContentTypeStream(header http.Header) bool { + contentType := header.Get(c.HEADER_CONTENT_TYPE) + cTypeParams := strings.Split(contentType, ";") + cType := strings.TrimSpace(cTypeParams[0]) + return cType == c.CONTENT_TYPE_EVENT_STREAM +} + +const ( + StreamDone = "[DONE]" + StreamDataPrefix = "data: " +) + +var _ AIEngineStream = &OpenAI{} diff --git a/proxy-router/internal/aiengine/prodia.go b/proxy-router/internal/aiengine/prodia.go new file mode 100644 index 00000000..5699cb95 --- /dev/null +++ b/proxy-router/internal/aiengine/prodia.go @@ -0,0 +1,71 @@ +package aiengine + +import ( + "context" + "encoding/json" + "fmt" + "io" + "net/http" + "time" + + c "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal" + "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/lib" +) + +const HEADER_PRODIA_KEY = "X-Prodia-Key" +const PRODIA_DEFAULT_BASE_URL = "https://api.prodia.com/v1" + +type ProdiaGenerationResult struct { + Job string `json:"job"` + Status string `json:"status"` + ImageUrl string `json:"imageUrl" binding:"omitempty"` +} + +func waitJobResult(ctx context.Context, apiURL, apiKey, jobID string) (*ProdiaGenerationResult, error) { + url := fmt.Sprintf("%s/job/%s", apiURL, jobID) + + req, err := http.NewRequestWithContext(ctx, "GET", url, nil) + if err != nil { + err = lib.WrapError(ErrJobCheckRequest, err) + return nil, err + } + + req.Header.Add(c.HEADER_ACCEPT, c.CONTENT_TYPE_JSON) + req.Header.Add(HEADER_PRODIA_KEY, apiKey) + + res, err := http.DefaultClient.Do(req) + if err != nil { + err = lib.WrapError(ErrJobCheckRequest, err) + return nil, err + } + + defer res.Body.Close() + body, err := io.ReadAll(res.Body) + if err != nil { + err = lib.WrapError(ErrJobCheckRequest, err) + return nil, err + } + + var result ProdiaGenerationResult + err = json.Unmarshal(body, &result) + if err != nil { + err = lib.WrapError(ErrJobCheckRequest, err) + return nil, err + } + + if result.Status == "succeeded" { + return &result, nil + } + + if result.Status == "failed" { + return nil, ErrJobFailed + } + + select { + case <-ctx.Done(): + return nil, ctx.Err() + case <-time.After(1 * time.Second): + } + + return waitJobResult(ctx, apiURL, apiKey, jobID) +} diff --git a/proxy-router/internal/aiengine/prodia_sd.go b/proxy-router/internal/aiengine/prodia_sd.go new file mode 100644 index 00000000..1b4adae0 --- /dev/null +++ b/proxy-router/internal/aiengine/prodia_sd.go @@ -0,0 +1,111 @@ +package aiengine + +import ( + "bytes" + "context" + "encoding/json" + "fmt" + "io" + "net/http" + "strings" + + c "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal" + gcs "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/chatstorage/genericchatstorage" + "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/lib" + "github.com/sashabaranov/go-openai" +) + +const API_TYPE_PRODIA_SD = "prodia-sd" + +type ProdiaSD struct { + modelName string + apiURL string + apiKey string + + log lib.ILogger +} + +func NewProdiaSDEngine(modelName, apiURL, apiKey string, log lib.ILogger) *ProdiaSD { + if apiURL == "" { + apiURL = PRODIA_DEFAULT_BASE_URL + } + return &ProdiaSD{ + modelName: modelName, + apiURL: apiURL, + apiKey: apiKey, + log: log, + } +} + +func (s *ProdiaSD) Prompt(ctx context.Context, prompt *openai.ChatCompletionRequest, cb gcs.CompletionCallback) error { + body := map[string]string{ + "model": s.modelName, + "prompt": prompt.Messages[len(prompt.Messages)-1].Content, + } + + payload, err := json.Marshal(body) + if err != nil { + err = lib.WrapError(ErrImageGenerationInvalidRequest, err) + s.log.Error(err) + return err + } + + req, err := http.NewRequest("POST", fmt.Sprintf("%s/sd/generate", s.apiURL), bytes.NewReader(payload)) + if err != nil { + err = lib.WrapError(ErrImageGenerationRequest, err) + s.log.Error(err) + } + + req.Header.Add(c.HEADER_ACCEPT, c.CONTENT_TYPE_JSON) + req.Header.Add(c.HEADER_CONTENT_TYPE, c.CONTENT_TYPE_JSON) + req.Header.Add(HEADER_PRODIA_KEY, s.apiKey) + + res, err := http.DefaultClient.Do(req) + if err != nil { + err = lib.WrapError(ErrImageGenerationRequest, err) + s.log.Error(err) + return err + } + + defer res.Body.Close() + response, err := io.ReadAll(res.Body) + if err != nil { + err = lib.WrapError(ErrImageGenerationRequest, err) + s.log.Error(err) + return err + } + + bodyStr := string(response) + if strings.Contains(bodyStr, "Invalid Generation Parameters") { + return lib.WrapError(ErrImageGenerationRequest, fmt.Errorf(bodyStr)) + } + + result := ProdiaGenerationResult{} + err = json.Unmarshal(response, &result) + if err != nil { + err = lib.WrapError(ErrImageGenerationRequest, err) + s.log.Error(err) + return err + } + + job, err := waitJobResult(ctx, s.apiURL, s.apiKey, result.Job) + if err != nil { + err = lib.WrapError(ErrImageGenerationRequest, err) + s.log.Error(err) + return err + } + + chunk := gcs.NewChunkImage(&gcs.ImageGenerationResult{ + Job: job.Job, + ImageUrl: job.ImageUrl, + Status: job.Status, + }) + + return cb(ctx, chunk) +} + +func (s *ProdiaSD) ApiType() string { + return API_TYPE_PRODIA_SD +} + +var _ AIEngineStream = &ProdiaSD{} diff --git a/proxy-router/internal/aiengine/prodia_sdxl.go b/proxy-router/internal/aiengine/prodia_sdxl.go new file mode 100644 index 00000000..8f227343 --- /dev/null +++ b/proxy-router/internal/aiengine/prodia_sdxl.go @@ -0,0 +1,111 @@ +package aiengine + +import ( + "bytes" + "context" + "encoding/json" + "fmt" + "io" + "net/http" + "strings" + + c "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal" + gcs "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/chatstorage/genericchatstorage" + "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/lib" + "github.com/sashabaranov/go-openai" +) + +const API_TYPE_PRODIA_SDXL = "prodia-sdxl" + +type ProdiaSDXL struct { + modelName string + apiURL string + apiKey string + + log lib.ILogger +} + +func NewProdiaSDXLEngine(modelName, apiURL, apiKey string, log lib.ILogger) *ProdiaSDXL { + if apiURL == "" { + apiURL = PRODIA_DEFAULT_BASE_URL + } + return &ProdiaSDXL{ + modelName: modelName, + apiURL: apiURL, + apiKey: apiKey, + log: log, + } +} + +func (s *ProdiaSDXL) Prompt(ctx context.Context, prompt *openai.ChatCompletionRequest, cb gcs.CompletionCallback) error { + body := map[string]string{ + "model": s.modelName, + "prompt": prompt.Messages[len(prompt.Messages)-1].Content, + } + + payload, err := json.Marshal(body) + if err != nil { + err = lib.WrapError(ErrImageGenerationInvalidRequest, err) + s.log.Error(err) + return err + } + + req, err := http.NewRequest("POST", fmt.Sprintf("%s/sdxl/generate", s.apiURL), bytes.NewReader(payload)) + if err != nil { + err = lib.WrapError(ErrImageGenerationRequest, err) + s.log.Error(err) + } + + req.Header.Add(c.HEADER_ACCEPT, c.CONTENT_TYPE_JSON) + req.Header.Add(c.HEADER_CONTENT_TYPE, c.CONTENT_TYPE_JSON) + req.Header.Add(HEADER_PRODIA_KEY, s.apiKey) + + res, err := http.DefaultClient.Do(req) + if err != nil { + err = lib.WrapError(ErrImageGenerationRequest, err) + s.log.Error(err) + return err + } + + defer res.Body.Close() + response, err := io.ReadAll(res.Body) + if err != nil { + err = lib.WrapError(ErrImageGenerationRequest, err) + s.log.Error(err) + return err + } + + bodyStr := string(response) + if strings.Contains(bodyStr, "Invalid Generation Parameters") { + return lib.WrapError(ErrImageGenerationRequest, fmt.Errorf(bodyStr)) + } + + result := ProdiaGenerationResult{} + err = json.Unmarshal(response, &result) + if err != nil { + err = lib.WrapError(ErrImageGenerationRequest, err) + s.log.Error(err) + return err + } + + job, err := waitJobResult(ctx, s.apiURL, s.apiKey, result.Job) + if err != nil { + err = lib.WrapError(ErrImageGenerationRequest, err) + s.log.Error(err) + return err + } + + chunk := gcs.NewChunkImage(&gcs.ImageGenerationResult{ + Job: job.Job, + ImageUrl: job.ImageUrl, + Status: job.Status, + }) + + return cb(ctx, chunk) +} + +func (s *ProdiaSDXL) ApiType() string { + return API_TYPE_PRODIA_SDXL +} + +var _ AIEngineStream = &ProdiaSDXL{} diff --git a/proxy-router/internal/aiengine/prodia_v2.go b/proxy-router/internal/aiengine/prodia_v2.go new file mode 100644 index 00000000..9606b63f --- /dev/null +++ b/proxy-router/internal/aiengine/prodia_v2.go @@ -0,0 +1,108 @@ +package aiengine + +import ( + "bytes" + "context" + b64 "encoding/base64" + "encoding/json" + "errors" + "fmt" + "io" + "net/http" + + c "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal" + gcs "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/chatstorage/genericchatstorage" + "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/lib" + "github.com/sashabaranov/go-openai" +) + +const API_TYPE_PRODIA_V2 = "prodia-v2" +const PRODIA_V2_DEFAULT_BASE_URL = "https://inference.prodia.com/v2" + +var ( + ErrCapacity = errors.New("unable to schedule job with current token") + ErrBadResponse = errors.New("bad response") + ErrVideoGenerationRequest = errors.New("video generation error") +) + +type ProdiaV2 struct { + modelName string + apiURL string + apiKey string + + log lib.ILogger +} + +func NewProdiaV2Engine(modelName, apiURL, apiKey string, log lib.ILogger) *ProdiaV2 { + if apiURL == "" { + apiURL = PRODIA_V2_DEFAULT_BASE_URL + } + return &ProdiaV2{ + modelName: modelName, + apiURL: apiURL, + apiKey: apiKey, + log: log, + } +} + +func (s *ProdiaV2) Prompt(ctx context.Context, prompt *openai.ChatCompletionRequest, cb gcs.CompletionCallback) error { + body := map[string]interface{}{ + "type": s.modelName, + "config": map[string]string{ + "prompt": prompt.Messages[len(prompt.Messages)-1].Content, + }, + } + + payload, err := json.Marshal(body) + if err != nil { + err = lib.WrapError(ErrImageGenerationInvalidRequest, err) + s.log.Error(err) + return err + } + + req, err := http.NewRequest("POST", fmt.Sprintf("%s/job", s.apiURL), bytes.NewReader(payload)) + if err != nil { + err = lib.WrapError(ErrImageGenerationRequest, err) + s.log.Error(err) + } + + req.Header.Add(c.HEADER_ACCEPT, c.CONTENT_TYPE_VIDEO_MP4) + req.Header.Add(c.HEADER_CONTENT_TYPE, c.CONTENT_TYPE_JSON) + req.Header.Add(c.HEADER_AUTHORIZATION, fmt.Sprintf("Bearer %s", s.apiKey)) + + res, err := http.DefaultClient.Do(req) + if err != nil { + err = lib.WrapError(ErrImageGenerationRequest, err) + s.log.Error(err) + return err + } + defer res.Body.Close() + + if res.StatusCode == http.StatusTooManyRequests { + return ErrCapacity + } else if res.StatusCode < http.StatusOK || res.StatusCode >= http.StatusMultipleChoices { + return lib.WrapError(ErrBadResponse, fmt.Errorf("status code: %d", res.StatusCode)) + } + + response, err := io.ReadAll(res.Body) + if err != nil { + err = lib.WrapError(ErrVideoGenerationRequest, err) + s.log.Error(err) + return err + } + + sEnc := b64.StdEncoding.EncodeToString(response) + + dataPrefix := "data:video/mp4;base64," + chunk := gcs.NewChunkVideo(&gcs.VideoGenerationResult{ + VideoRawContent: dataPrefix + sEnc, + }) + + return cb(ctx, chunk) +} + +func (s *ProdiaV2) ApiType() string { + return API_TYPE_PRODIA_V2 +} + +var _ AIEngineStream = &ProdiaV2{} diff --git a/proxy-router/internal/aiengine/remote.go b/proxy-router/internal/aiengine/remote.go new file mode 100644 index 00000000..ba958b2a --- /dev/null +++ b/proxy-router/internal/aiengine/remote.go @@ -0,0 +1,30 @@ +package aiengine + +import ( + "context" + + gcs "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/chatstorage/genericchatstorage" + "github.com/ethereum/go-ethereum/common" + "github.com/sashabaranov/go-openai" +) + +type RemoteModel struct { + service ProxyService + sessionID common.Hash +} + +type ProxyService interface { + SendPromptV2(ctx context.Context, sessionID common.Hash, prompt *openai.ChatCompletionRequest, cb gcs.CompletionCallback) (interface{}, error) + GetModelIdSession(ctx context.Context, sessionID common.Hash) (common.Hash, error) +} + +func (p *RemoteModel) Prompt(ctx context.Context, prompt *openai.ChatCompletionRequest, cb gcs.CompletionCallback) error { + _, err := p.service.SendPromptV2(ctx, p.sessionID, prompt, cb) + return err +} + +func (p *RemoteModel) ApiType() string { + return "remote" +} + +var _ AIEngineStream = &RemoteModel{} diff --git a/proxy-router/internal/aiengine/structs.go b/proxy-router/internal/aiengine/structs.go new file mode 100644 index 00000000..7af26081 --- /dev/null +++ b/proxy-router/internal/aiengine/structs.go @@ -0,0 +1,11 @@ +package aiengine + +type LocalModel struct { + Id string + Name string + Model string + ApiType string + ApiUrl string + Slots int + CapacityPolicy string +} diff --git a/proxy-router/internal/blockchainapi/controller.go b/proxy-router/internal/blockchainapi/controller.go index e3666759..e26124b5 100644 --- a/proxy-router/internal/blockchainapi/controller.go +++ b/proxy-router/internal/blockchainapi/controller.go @@ -2,13 +2,13 @@ package blockchainapi import ( "crypto/rand" - "fmt" "math/big" "net/http" "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/blockchainapi/structs" "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/interfaces" "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/lib" + "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/repositories/registries" "github.com/ethereum/go-ethereum/common" "github.com/gin-gonic/gin" ) @@ -60,7 +60,9 @@ func (c *BlockchainController) RegisterRoutes(r interfaces.Router) { // sessions r.GET("/proxy/sessions/:id/providerClaimableBalance", c.getProviderClaimableBalance) r.POST("/proxy/sessions/:id/providerClaim", c.claimProviderBalance) - r.GET("/blockchain/sessions", c.getSessions) + r.GET("/blockchain/sessions/user", c.getSessionsForUser) + r.GET("/blockchain/sessions/user/ids", c.getSessionsIdsForUser) + r.GET("/blockchain/sessions/provider", c.getSessionsForProvider) r.GET("/blockchain/sessions/:id", c.getSession) r.POST("/blockchain/sessions", c.openSession) r.POST("/blockchain/bids/:id/session", c.openSessionByBid) @@ -84,13 +86,13 @@ func (c *BlockchainController) getProviderClaimableBalance(ctx *gin.Context) { err := ctx.ShouldBindUri(¶ms) if err != nil { c.log.Error(err) - ctx.JSON(http.StatusBadRequest, structs.ErrRes{Error: err}) + ctx.JSON(http.StatusBadRequest, structs.ErrRes{Error: err.Error()}) return } balance, err := c.service.GetProviderClaimableBalance(ctx, params.ID.Hash) if err != nil { - ctx.JSON(http.StatusInternalServerError, structs.ErrRes{Error: err}) + ctx.JSON(http.StatusInternalServerError, structs.ErrRes{Error: err.Error()}) return } @@ -104,30 +106,22 @@ func (c *BlockchainController) getProviderClaimableBalance(ctx *gin.Context) { // @Description Claim provider balance from session // @Tags sessions // @Produce json -// @Param claim body structs.AmountReq true "Claim" -// @Param id path string true "Session ID" -// @Success 200 {object} structs.TxRes +// @Param id path string true "Session ID" +// @Success 200 {object} structs.TxRes // @Router /proxy/sessions/{id}/providerClaim [post] func (c *BlockchainController) claimProviderBalance(ctx *gin.Context) { var params structs.PathHex32ID err := ctx.ShouldBindUri(¶ms) if err != nil { c.log.Error(err) - ctx.JSON(http.StatusBadRequest, structs.ErrRes{Error: err}) + ctx.JSON(http.StatusBadRequest, structs.ErrRes{Error: err.Error()}) return } - _, amount, err := c.getSendParams(ctx) + txHash, err := c.service.ClaimProviderBalance(ctx, params.ID.Hash) if err != nil { c.log.Error(err) - ctx.JSON(http.StatusBadRequest, structs.ErrRes{Error: err}) - return - } - - txHash, err := c.service.ClaimProviderBalance(ctx, params.ID.Hash, amount) - if err != nil { - c.log.Error(err) - ctx.JSON(http.StatusInternalServerError, structs.ErrRes{Error: err}) + ctx.JSON(http.StatusInternalServerError, structs.ErrRes{Error: err.Error()}) return } @@ -141,13 +135,30 @@ func (c *BlockchainController) claimProviderBalance(ctx *gin.Context) { // @Description Get providers list from blokchain // @Tags providers // @Produce json -// @Success 200 {object} structs.ProvidersRes +// @Param request query structs.QueryOffsetLimitOrderNoDefault true "Query Params" +// @Success 200 {object} structs.ProvidersRes // @Router /blockchain/providers [get] func (c *BlockchainController) getAllProviders(ctx *gin.Context) { - providers, err := c.service.GetAllProviders(ctx) + offset, limit, order, err := getOffsetLimitOrderNoDefault(ctx) if err != nil { c.log.Error(err) - ctx.JSON(http.StatusBadRequest, structs.ErrRes{Error: err}) + ctx.JSON(http.StatusBadRequest, structs.ErrRes{Error: err.Error()}) + return + } + + var providers []*structs.Provider + + if limit == 0 { + // if pagination is not used return all providers + // TODO: deprecate this + providers, err = c.service.GetAllProviders(ctx) + } else { + // if pagination is used return providers with offset and limit + providers, err = c.service.GetProviders(ctx, offset, limit, order) + } + if err != nil { + c.log.Error(err) + ctx.JSON(http.StatusBadRequest, structs.ErrRes{Error: err.Error()}) return } @@ -168,14 +179,14 @@ func (c *BlockchainController) sendETH(ctx *gin.Context) { to, amount, err := c.getSendParams(ctx) if err != nil { c.log.Error(err) - ctx.JSON(http.StatusBadRequest, structs.ErrRes{Error: err}) + ctx.JSON(http.StatusBadRequest, structs.ErrRes{Error: err.Error()}) return } txHash, err := c.service.SendETH(ctx, to, amount) if err != nil { c.log.Error(err) - ctx.JSON(http.StatusInternalServerError, structs.ErrRes{Error: err}) + ctx.JSON(http.StatusInternalServerError, structs.ErrRes{Error: err.Error()}) return } @@ -196,13 +207,13 @@ func (c *BlockchainController) sendMOR(ctx *gin.Context) { to, amount, err := c.getSendParams(ctx) if err != nil { c.log.Error(err) - ctx.JSON(http.StatusBadRequest, structs.ErrRes{Error: err}) + ctx.JSON(http.StatusBadRequest, structs.ErrRes{Error: err.Error()}) return } txhash, err := c.service.SendMOR(ctx, to, amount) if err != nil { c.log.Error(err) - ctx.JSON(http.StatusBadRequest, structs.ErrRes{Error: err}) + ctx.JSON(http.StatusBadRequest, structs.ErrRes{Error: err.Error()}) return } @@ -216,9 +227,8 @@ func (c *BlockchainController) sendMOR(ctx *gin.Context) { // @Description Get bids from blockchain by provider // @Tags bids // @Produce json -// @Param offset query string false "Offset" -// @Param limit query string false "Limit" -// @Param id path string true "Provider ID" +// @Param id path string true "Provider ID" +// @Param request query structs.QueryOffsetLimitOrder true "Query Params" // @Success 200 {object} structs.BidsRes // @Router /blockchain/providers/{id}/bids [get] func (c *BlockchainController) getBidsByProvider(ctx *gin.Context) { @@ -226,21 +236,21 @@ func (c *BlockchainController) getBidsByProvider(ctx *gin.Context) { err := ctx.ShouldBindUri(¶ms) if err != nil { c.log.Error(err) - ctx.JSON(http.StatusBadRequest, structs.ErrRes{Error: err}) + ctx.JSON(http.StatusBadRequest, structs.ErrRes{Error: err.Error()}) return } - offset, limit, err := getOffsetLimit(ctx) + offset, limit, order, err := getOffsetLimitOrder(ctx) if err != nil { c.log.Error(err) - ctx.JSON(http.StatusBadRequest, structs.ErrRes{Error: err}) + ctx.JSON(http.StatusBadRequest, structs.ErrRes{Error: err.Error()}) return } - bids, err := c.service.GetBidsByProvider(ctx, params.ID.Address, offset, limit) + bids, err := c.service.GetBidsByProvider(ctx, params.ID.Address, offset, limit, order) if err != nil { c.log.Error(err) - ctx.JSON(http.StatusInternalServerError, structs.ErrRes{Error: err}) + ctx.JSON(http.StatusInternalServerError, structs.ErrRes{Error: err.Error()}) return } @@ -254,22 +264,30 @@ func (c *BlockchainController) getBidsByProvider(ctx *gin.Context) { // @Description Get bids from blockchain by provider // @Tags bids // @Produce json -// @Param id path string true "Provider ID" -// @Success 200 {object} structs.BidsRes +// @Param id path string true "Provider ID" +// @Param request query structs.QueryOffsetLimitOrder true "Query Params" +// @Success 200 {object} structs.BidsRes // @Router /blockchain/providers/{id}/bids/active [get] func (c *BlockchainController) getActiveBidsByProvider(ctx *gin.Context) { var params structs.PathEthAddrID err := ctx.ShouldBindUri(¶ms) if err != nil { c.log.Error(err) - ctx.JSON(http.StatusBadRequest, structs.ErrRes{Error: err}) + ctx.JSON(http.StatusBadRequest, structs.ErrRes{Error: err.Error()}) + return + } + + offset, limit, order, err := getOffsetLimitOrder(ctx) + if err != nil { + c.log.Error(err) + ctx.JSON(http.StatusBadRequest, structs.ErrRes{Error: err.Error()}) return } - bids, err := c.service.GetActiveBidsByProvider(ctx, params.ID.Address) + bids, err := c.service.GetActiveBidsByProvider(ctx, params.ID.Address, offset, limit, order) if err != nil { c.log.Error(err) - ctx.JSON(http.StatusInternalServerError, structs.ErrRes{Error: err}) + ctx.JSON(http.StatusInternalServerError, structs.ErrRes{Error: err.Error()}) return } @@ -283,13 +301,29 @@ func (c *BlockchainController) getActiveBidsByProvider(ctx *gin.Context) { // @Description Get models list from blokchain // @Tags models // @Produce json -// @Success 200 {object} structs.ModelsRes +// @Param request query structs.QueryOffsetLimitOrderNoDefault true "Query Params" +// @Success 200 {object} structs.ModelsRes // @Router /blockchain/models [get] func (c *BlockchainController) getAllModels(ctx *gin.Context) { - models, err := c.service.GetAllModels(ctx) + offset, limit, order, err := getOffsetLimitOrderNoDefault(ctx) + if err != nil { + c.log.Error(err) + ctx.JSON(http.StatusBadRequest, structs.ErrRes{Error: err.Error()}) + return + } + + var models []*structs.Model + if limit == 0 { + // if pagination is not used return all models + // TODO: deprecate this + models, err = c.service.GetAllModels(ctx) + } else { + // if pagination is used return models with offset and limit + models, err = c.service.GetModels(ctx, offset, limit, order) + } if err != nil { c.log.Error(err) - ctx.JSON(http.StatusBadRequest, structs.ErrRes{Error: err}) + ctx.JSON(http.StatusBadRequest, structs.ErrRes{Error: err.Error()}) return } @@ -303,9 +337,8 @@ func (c *BlockchainController) getAllModels(ctx *gin.Context) { // @Description Get bids from blockchain by model agent // @Tags bids // @Produce json -// @Param offset query string false "Offset" -// @Param limit query string false "Limit" -// @Param id path string true "ModelAgent ID" +// @Param id path string true "ModelAgent ID" +// @Param request query structs.QueryOffsetLimitOrder true "Query Params" // @Success 200 {object} structs.BidsRes // @Router /blockchain/models/{id}/bids [get] func (c *BlockchainController) getBidsByModelAgent(ctx *gin.Context) { @@ -313,21 +346,21 @@ func (c *BlockchainController) getBidsByModelAgent(ctx *gin.Context) { err := ctx.ShouldBindUri(¶ms) if err != nil { c.log.Error(err) - ctx.JSON(http.StatusBadRequest, structs.ErrRes{Error: err}) + ctx.JSON(http.StatusBadRequest, structs.ErrRes{Error: err.Error()}) return } - offset, limit, err := getOffsetLimit(ctx) + offset, limit, order, err := getOffsetLimitOrder(ctx) if err != nil { c.log.Error(err) - ctx.JSON(http.StatusBadRequest, structs.ErrRes{Error: err}) + ctx.JSON(http.StatusBadRequest, structs.ErrRes{Error: err.Error()}) return } - bids, err := c.service.GetBidsByModelAgent(ctx, params.ID.Hash, offset, limit) + bids, err := c.service.GetBidsByModelAgent(ctx, params.ID.Hash, offset, limit, order) if err != nil { c.log.Error(err) - ctx.JSON(http.StatusInternalServerError, structs.ErrRes{Error: err}) + ctx.JSON(http.StatusInternalServerError, structs.ErrRes{Error: err.Error()}) return } @@ -341,22 +374,30 @@ func (c *BlockchainController) getBidsByModelAgent(ctx *gin.Context) { // @Description Get bids from blockchain by model agent // @Tags bids // @Produce json -// @Param id path string true "ModelAgent ID" -// @Success 200 {object} structs.BidsRes +// @Param id path string true "ModelAgent ID" +// @Param request query structs.QueryOffsetLimitOrder true "Query Params" +// @Success 200 {object} structs.BidsRes // @Router /blockchain/models/{id}/bids [get] func (c *BlockchainController) getActiveBidsByModel(ctx *gin.Context) { var params structs.PathHex32ID err := ctx.ShouldBindUri(¶ms) if err != nil { c.log.Error(err) - ctx.JSON(http.StatusBadRequest, structs.ErrRes{Error: err}) + ctx.JSON(http.StatusBadRequest, structs.ErrRes{Error: err.Error()}) return } - bids, err := c.service.GetActiveBidsByModel(ctx, params.ID.Hash) + offset, limit, order, err := getOffsetLimitOrder(ctx) if err != nil { c.log.Error(err) - ctx.JSON(http.StatusInternalServerError, structs.ErrRes{Error: err}) + ctx.JSON(http.StatusBadRequest, structs.ErrRes{Error: err.Error()}) + return + } + + bids, err := c.service.GetActiveBidsByModel(ctx, params.ID.Hash, offset, limit, order) + if err != nil { + c.log.Error(err) + ctx.JSON(http.StatusInternalServerError, structs.ErrRes{Error: err.Error()}) return } @@ -376,7 +417,7 @@ func (s *BlockchainController) getBalance(ctx *gin.Context) { ethBalance, morBalance, err := s.service.GetBalance(ctx) if err != nil { s.log.Error(err) - ctx.JSON(http.StatusInternalServerError, structs.ErrRes{Error: err}) + ctx.JSON(http.StatusInternalServerError, structs.ErrRes{Error: err.Error()}) return } @@ -401,14 +442,14 @@ func (c *BlockchainController) getTransactions(ctx *gin.Context) { page, limit, err := getPageLimit(ctx) if err != nil { c.log.Error(err) - ctx.JSON(http.StatusBadRequest, structs.ErrRes{Error: err}) + ctx.JSON(http.StatusBadRequest, structs.ErrRes{Error: err.Error()}) return } txs, err := c.service.GetTransactions(ctx, page, limit) if err != nil { c.log.Error(err) - ctx.JSON(http.StatusInternalServerError, structs.ErrRes{Error: err}) + ctx.JSON(http.StatusInternalServerError, structs.ErrRes{Error: err.Error()}) return } @@ -429,14 +470,14 @@ func (c *BlockchainController) getAllowance(ctx *gin.Context) { err := ctx.ShouldBindQuery(&query) if err != nil { c.log.Error(err) - ctx.JSON(http.StatusBadRequest, structs.ErrRes{Error: err}) + ctx.JSON(http.StatusBadRequest, structs.ErrRes{Error: err.Error()}) return } allowance, err := c.service.GetAllowance(ctx, query.Spender.Address) if err != nil { c.log.Error(err) - ctx.JSON(http.StatusInternalServerError, structs.ErrRes{Error: err}) + ctx.JSON(http.StatusInternalServerError, structs.ErrRes{Error: err.Error()}) return } @@ -459,14 +500,14 @@ func (c *BlockchainController) approve(ctx *gin.Context) { err := ctx.ShouldBindQuery(&query) if err != nil { c.log.Error(err) - ctx.JSON(http.StatusBadRequest, structs.ErrRes{Error: err}) + ctx.JSON(http.StatusBadRequest, structs.ErrRes{Error: err.Error()}) return } tx, err := c.service.Approve(ctx, query.Spender.Address, query.Amount.Unpack()) if err != nil { c.log.Error(err) - ctx.JSON(http.StatusInternalServerError, structs.ErrRes{Error: err}) + ctx.JSON(http.StatusInternalServerError, structs.ErrRes{Error: err.Error()}) return } @@ -488,14 +529,14 @@ func (c *BlockchainController) openSession(ctx *gin.Context) { var reqPayload structs.OpenSessionRequest if err := ctx.ShouldBindJSON(&reqPayload); err != nil { c.log.Error(err) - ctx.JSON(http.StatusBadRequest, structs.ErrRes{Error: err}) + ctx.JSON(http.StatusBadRequest, structs.ErrRes{Error: err.Error()}) return } - sessionId, err := c.service.OpenSession(ctx, reqPayload.Approval, reqPayload.ApprovalSig, reqPayload.Stake.Unpack()) + sessionId, err := c.service.OpenSession(ctx, reqPayload.Approval, reqPayload.ApprovalSig, reqPayload.Stake.Unpack(), reqPayload.DirectPayment) if err != nil { c.log.Error(err) - ctx.JSON(http.StatusInternalServerError, structs.ErrRes{Error: err}) + ctx.JSON(http.StatusInternalServerError, structs.ErrRes{Error: err.Error()}) return } @@ -517,20 +558,20 @@ func (c *BlockchainController) openSession(ctx *gin.Context) { func (s *BlockchainController) openSessionByBid(ctx *gin.Context) { var reqPayload structs.OpenSessionWithDurationRequest if err := ctx.ShouldBindJSON(&reqPayload); err != nil { - ctx.JSON(http.StatusBadRequest, structs.ErrRes{Error: err}) + ctx.JSON(http.StatusBadRequest, structs.ErrRes{Error: err.Error()}) return } var params structs.PathHex32ID err := ctx.ShouldBindUri(¶ms) if err != nil { - ctx.JSON(http.StatusBadRequest, structs.ErrRes{Error: err}) + ctx.JSON(http.StatusBadRequest, structs.ErrRes{Error: err.Error()}) return } sessionId, err := s.service.openSessionByBid(ctx, params.ID.Hash, reqPayload.SessionDuration.Unpack()) if err != nil { - ctx.JSON(http.StatusInternalServerError, structs.ErrRes{Error: err}) + ctx.JSON(http.StatusInternalServerError, structs.ErrRes{Error: err.Error()}) return } @@ -545,15 +586,15 @@ func (s *BlockchainController) openSessionByBid(ctx *gin.Context) { // @Tags sessions // @Produce json // @Accept json -// @Param opensession body structs.OpenSessionWithDurationRequest true "Open session" -// @Param id path string true "Model ID" +// @Param opensession body structs.OpenSessionWithFailover true "Open session" +// @Param id path string true "Model ID" // @Success 200 {object} structs.OpenSessionRes // @Router /blockchain/models/{id}/session [post] func (s *BlockchainController) openSessionByModelId(ctx *gin.Context) { - var reqPayload structs.OpenSessionWithDurationRequest + var reqPayload structs.OpenSessionWithFailover if err := ctx.ShouldBindJSON(&reqPayload); err != nil { s.log.Error(err) - ctx.JSON(http.StatusBadRequest, structs.ErrRes{Error: err}) + ctx.JSON(http.StatusBadRequest, structs.ErrRes{Error: err.Error()}) return } @@ -565,10 +606,11 @@ func (s *BlockchainController) openSessionByModelId(ctx *gin.Context) { return } - sessionId, err := s.service.OpenSessionByModelId(ctx, params.ID.Hash, reqPayload.SessionDuration.Unpack()) + isFailoverEnabled := reqPayload.Failover + sessionId, err := s.service.OpenSessionByModelId(ctx, params.ID.Hash, reqPayload.SessionDuration.Unpack(), reqPayload.DirectPayment, isFailoverEnabled, common.Address{}) if err != nil { s.log.Error(err) - ctx.JSON(http.StatusInternalServerError, structs.ErrRes{Error: err}) + ctx.JSON(http.StatusInternalServerError, structs.ErrRes{Error: err.Error()}) return } @@ -590,14 +632,14 @@ func (c *BlockchainController) closeSession(ctx *gin.Context) { err := ctx.ShouldBindUri(¶ms) if err != nil { c.log.Error(err) - ctx.JSON(http.StatusBadRequest, structs.ErrRes{Error: err}) + ctx.JSON(http.StatusBadRequest, structs.ErrRes{Error: err.Error()}) return } txHash, err := c.service.CloseSession(ctx, params.ID.Hash) if err != nil { c.log.Error(err) - ctx.JSON(http.StatusInternalServerError, structs.ErrRes{Error: err}) + ctx.JSON(http.StatusInternalServerError, structs.ErrRes{Error: err.Error()}) return } @@ -619,14 +661,14 @@ func (c *BlockchainController) getSession(ctx *gin.Context) { err := ctx.ShouldBindUri(¶ms) if err != nil { c.log.Error(err) - ctx.JSON(http.StatusBadRequest, structs.ErrRes{Error: err}) + ctx.JSON(http.StatusBadRequest, structs.ErrRes{Error: err.Error()}) return } session, err := c.service.GetSession(ctx, params.ID.Hash) if err != nil { c.log.Error(err) - ctx.JSON(http.StatusInternalServerError, structs.ErrRes{Error: err}) + ctx.JSON(http.StatusInternalServerError, structs.ErrRes{Error: err.Error()}) return } @@ -636,50 +678,108 @@ func (c *BlockchainController) getSession(ctx *gin.Context) { // GetSessions godoc // -// @Summary Get Sessions -// @Description Get sessions from blockchain by user or provider +// @Summary Get Sessions for User +// @Description Get sessions from blockchain by user // @Tags sessions // @Produce json -// @Param offset query string false "Offset" -// @Param limit query string false "Limit" -// @Param provider query string false "Provider address" -// @Param user query string false "User address" -// @Success 200 {object} structs.SessionsRes -// @Router /blockchain/sessions [get] -func (c *BlockchainController) getSessions(ctx *gin.Context) { - offset, limit, err := getOffsetLimit(ctx) +// @Param user query string true "User address" +// @Param request query structs.QueryOffsetLimitOrder true "Query Params" +// @Success 200 {object} structs.SessionsRes +// @Router /blockchain/sessions/user [get] +func (c *BlockchainController) getSessionsForUser(ctx *gin.Context) { + offset, limit, order, err := getOffsetLimitOrder(ctx) if err != nil { c.log.Error(err) - ctx.JSON(http.StatusBadRequest, structs.ErrRes{Error: err}) + ctx.JSON(http.StatusBadRequest, structs.ErrRes{Error: err.Error()}) return } - var req structs.QueryUserOrProvider + var req structs.QueryUser err = ctx.ShouldBindQuery(&req) if err != nil { c.log.Error(err) - ctx.JSON(http.StatusBadRequest, structs.ErrRes{Error: err}) + ctx.JSON(http.StatusBadRequest, structs.ErrRes{Error: err.Error()}) + return + } + + sessions, err := c.service.GetSessions(ctx, req.User.Address, common.Address{}, offset, limit, order) + if err != nil { + c.log.Error(err) + ctx.JSON(http.StatusInternalServerError, structs.ErrRes{Error: err.Error()}) return } - hasUser := req.User != lib.Address{} - hasProvider := req.Provider != lib.Address{} + ctx.JSON(http.StatusOK, structs.SessionsRes{Sessions: sessions}) + return +} - if !hasUser && !hasProvider { +// GetSessionsIds godoc +// +// @Summary Get Sessions for User +// @Description Get sessions from blockchain by user +// @Tags sessions +// @Produce json +// @Param user query string true "User address" +// @Param request query structs.QueryOffsetLimitOrder true "Query Params" +// @Success 200 {object} structs.SessionsRes +// @Router /blockchain/sessions/user/ids [get] +func (c *BlockchainController) getSessionsIdsForUser(ctx *gin.Context) { + offset, limit, order, err := getOffsetLimitOrder(ctx) + if err != nil { c.log.Error(err) - ctx.JSON(http.StatusBadRequest, structs.ErrRes{Error: fmt.Errorf("user or provider is required")}) + ctx.JSON(http.StatusBadRequest, structs.ErrRes{Error: err.Error()}) return } - if hasUser && hasProvider { + + var req structs.QueryUser + err = ctx.ShouldBindQuery(&req) + if err != nil { c.log.Error(err) - ctx.JSON(http.StatusBadRequest, structs.ErrRes{Error: fmt.Errorf("only one of user or provider is allowed")}) + ctx.JSON(http.StatusBadRequest, structs.ErrRes{Error: err.Error()}) return } - sessions, err := c.service.GetSessions(ctx, req.User.Address, req.Provider.Address, offset, limit) + sessionsIds, err := c.service.GetSessionsIds(ctx, req.User.Address, common.Address{}, offset, limit, order) if err != nil { c.log.Error(err) - ctx.JSON(http.StatusInternalServerError, structs.ErrRes{Error: err}) + ctx.JSON(http.StatusInternalServerError, structs.ErrRes{Error: err.Error()}) + return + } + + ctx.JSON(http.StatusOK, sessionsIds) + return +} + +// GetSessions godoc +// +// @Summary Get Sessions for Provider +// @Description Get sessions from blockchain by provider +// @Tags sessions +// @Produce json +// @Param request query structs.QueryOffsetLimitOrder true "Query Params" +// @Param provider query string true "Provider address" +// @Success 200 {object} structs.SessionsRes +// @Router /blockchain/sessions/provider [get] +func (c *BlockchainController) getSessionsForProvider(ctx *gin.Context) { + offset, limit, order, err := getOffsetLimitOrder(ctx) + if err != nil { + c.log.Error(err) + ctx.JSON(http.StatusBadRequest, structs.ErrRes{Error: err.Error()}) + return + } + + var req structs.QueryProvider + err = ctx.ShouldBindQuery(&req) + if err != nil { + c.log.Error(err) + ctx.JSON(http.StatusBadRequest, structs.ErrRes{Error: err.Error()}) + return + } + + sessions, err := c.service.GetSessions(ctx, common.Address{}, req.Provider.Address, offset, limit, order) + if err != nil { + c.log.Error(err) + ctx.JSON(http.StatusInternalServerError, structs.ErrRes{Error: err.Error()}) return } @@ -699,7 +799,7 @@ func (s *BlockchainController) getBudget(ctx *gin.Context) { budget, err := s.service.GetTodaysBudget(ctx) if err != nil { s.log.Error(err) - ctx.JSON(http.StatusInternalServerError, structs.ErrRes{Error: err}) + ctx.JSON(http.StatusInternalServerError, structs.ErrRes{Error: err.Error()}) return } @@ -719,7 +819,7 @@ func (s *BlockchainController) getSupply(ctx *gin.Context) { supply, err := s.service.GetTokenSupply(ctx) if err != nil { s.log.Error(err) - ctx.JSON(http.StatusInternalServerError, structs.ErrRes{Error: err}) + ctx.JSON(http.StatusInternalServerError, structs.ErrRes{Error: err.Error()}) return } @@ -739,7 +839,7 @@ func (c *BlockchainController) getLatestBlock(ctx *gin.Context) { block, err := c.service.GetLatestBlock(ctx) if err != nil { c.log.Error(err) - ctx.JSON(http.StatusInternalServerError, structs.ErrRes{Error: err}) + ctx.JSON(http.StatusInternalServerError, structs.ErrRes{Error: err.Error()}) return } ctx.JSON(http.StatusOK, structs.BlockRes{Block: block}) @@ -760,14 +860,14 @@ func (c *BlockchainController) getBidByID(ctx *gin.Context) { err := ctx.ShouldBindUri(¶ms) if err != nil { c.log.Error(err) - ctx.JSON(http.StatusBadRequest, structs.ErrRes{Error: err}) + ctx.JSON(http.StatusBadRequest, structs.ErrRes{Error: err.Error()}) return } bid, err := c.service.GetBidByID(ctx, params.ID.Hash) if err != nil { c.log.Error(err) - ctx.JSON(http.StatusInternalServerError, structs.ErrRes{Error: err}) + ctx.JSON(http.StatusInternalServerError, structs.ErrRes{Error: err.Error()}) return } @@ -789,14 +889,14 @@ func (c *BlockchainController) getRatedBids(ctx *gin.Context) { err := ctx.ShouldBindUri(¶ms) if err != nil { c.log.Error(err) - ctx.JSON(http.StatusBadRequest, structs.ErrRes{Error: err}) + ctx.JSON(http.StatusBadRequest, structs.ErrRes{Error: err.Error()}) return } bids, err := c.service.GetRatedBids(ctx, params.ID.Hash) if err != nil { c.log.Error(err) - ctx.JSON(http.StatusInternalServerError, structs.ErrRes{Error: err}) + ctx.JSON(http.StatusInternalServerError, structs.ErrRes{Error: err.Error()}) return } @@ -817,14 +917,14 @@ func (c *BlockchainController) createProvider(ctx *gin.Context) { var provider structs.CreateProviderRequest if err := ctx.ShouldBindJSON(&provider); err != nil { c.log.Error(err) - ctx.JSON(http.StatusBadRequest, structs.ErrRes{Error: err}) + ctx.JSON(http.StatusBadRequest, structs.ErrRes{Error: err.Error()}) return } result, err := c.service.CreateNewProvider(ctx, provider.Stake, provider.Endpoint) if err != nil { c.log.Error(err) - ctx.JSON(http.StatusInternalServerError, structs.ErrRes{Error: err}) + ctx.JSON(http.StatusInternalServerError, structs.ErrRes{Error: err.Error()}) return } @@ -837,22 +937,14 @@ func (c *BlockchainController) createProvider(ctx *gin.Context) { // @Summary Deregister Provider // @Tags providers // @Produce json -// @Param id path string true "Provider Address" +// @Param id path string true "Provider ID" // @Success 200 {object} structs.TxRes // @Router /blockchain/providers/{id} [delete] func (c *BlockchainController) deregisterProvider(ctx *gin.Context) { - var params structs.PathEthAddrID - err := ctx.ShouldBindUri(¶ms) + txHash, err := c.service.DeregisterProdiver(ctx) if err != nil { c.log.Error(err) - ctx.JSON(http.StatusBadRequest, structs.ErrRes{Error: err}) - return - } - - txHash, err := c.service.DeregisterProdiver(ctx, params.ID.Address) - if err != nil { - c.log.Error(err) - ctx.JSON(http.StatusInternalServerError, structs.ErrRes{Error: err}) + ctx.JSON(http.StatusInternalServerError, structs.ErrRes{Error: err.Error()}) return } @@ -862,18 +954,19 @@ func (c *BlockchainController) deregisterProvider(ctx *gin.Context) { // CreateNewModel godoc // -// @Summary Creates model in blockchain -// @Tags models -// @Produce json -// @Accept json -// @Param model body structs.CreateModelRequest true "Model" -// @Success 200 {object} structs.ModelRes -// @Router /blockchain/models [post] +// @Summary Creates model in blockchain +// @Description If you provide ID in request it will be used as "Base Id" for generation of new model ID. So actual ID will be generated from it, and you will get it in response. +// @Tags models +// @Produce json +// @Accept json +// @Param model body structs.CreateModelRequest true "Model" +// @Success 200 {object} structs.ModelRes +// @Router /blockchain/models [post] func (c *BlockchainController) createNewModel(ctx *gin.Context) { var model structs.CreateModelRequest if err := ctx.ShouldBindJSON(&model); err != nil { c.log.Error(err) - ctx.JSON(http.StatusBadRequest, structs.ErrRes{Error: err}) + ctx.JSON(http.StatusBadRequest, structs.ErrRes{Error: err.Error()}) return } @@ -883,7 +976,7 @@ func (c *BlockchainController) createNewModel(ctx *gin.Context) { _, err := rand.Read(hash[:]) if err != nil { c.log.Error(err) - ctx.JSON(http.StatusInternalServerError, structs.ErrRes{Error: err}) + ctx.JSON(http.StatusInternalServerError, structs.ErrRes{Error: err.Error()}) return } modelId = hash @@ -895,7 +988,7 @@ func (c *BlockchainController) createNewModel(ctx *gin.Context) { result, err := c.service.CreateNewModel(ctx, modelId, ipsfHash, model.Fee, model.Stake, model.Name, model.Tags) if err != nil { c.log.Error(err) - ctx.JSON(http.StatusInternalServerError, structs.ErrRes{Error: err}) + ctx.JSON(http.StatusInternalServerError, structs.ErrRes{Error: err.Error()}) return } @@ -917,14 +1010,14 @@ func (c *BlockchainController) deregisterModel(ctx *gin.Context) { err := ctx.ShouldBindUri(¶ms) if err != nil { c.log.Error(err) - ctx.JSON(http.StatusBadRequest, structs.ErrRes{Error: err}) + ctx.JSON(http.StatusBadRequest, structs.ErrRes{Error: err.Error()}) return } txHash, err := c.service.DeregisterModel(ctx, params.ID.Hash) if err != nil { c.log.Error(err) - ctx.JSON(http.StatusInternalServerError, structs.ErrRes{Error: err}) + ctx.JSON(http.StatusInternalServerError, structs.ErrRes{Error: err.Error()}) return } @@ -945,7 +1038,7 @@ func (c *BlockchainController) createNewBid(ctx *gin.Context) { var bid structs.CreateBidRequest if err := ctx.ShouldBindJSON(&bid); err != nil { c.log.Error(err) - ctx.JSON(http.StatusBadRequest, structs.ErrRes{Error: err}) + ctx.JSON(http.StatusBadRequest, structs.ErrRes{Error: err.Error()}) return } @@ -953,7 +1046,7 @@ func (c *BlockchainController) createNewBid(ctx *gin.Context) { result, err := c.service.CreateNewBid(ctx, modelId, bid.PricePerSecond) if err != nil { c.log.Error(err) - ctx.JSON(http.StatusInternalServerError, structs.ErrRes{Error: err}) + ctx.JSON(http.StatusInternalServerError, structs.ErrRes{Error: err.Error()}) return } @@ -974,14 +1067,14 @@ func (c *BlockchainController) deleteBid(ctx *gin.Context) { err := ctx.ShouldBindUri(¶ms) if err != nil { c.log.Error(err) - ctx.JSON(http.StatusBadRequest, structs.ErrRes{Error: err}) + ctx.JSON(http.StatusBadRequest, structs.ErrRes{Error: err.Error()}) return } txHash, err := c.service.DeleteBid(ctx, params.ID.Hash) if err != nil { c.log.Error(err) - ctx.JSON(http.StatusInternalServerError, structs.ErrRes{Error: err}) + ctx.JSON(http.StatusInternalServerError, structs.ErrRes{Error: err.Error()}) return } @@ -999,15 +1092,26 @@ func (s *BlockchainController) getSendParams(ctx *gin.Context) (to common.Addres return body.To, body.Amount.Unpack(), nil } -func getOffsetLimit(ctx *gin.Context) (offset *big.Int, limit uint8, err error) { - var paging structs.QueryOffsetLimit +func getOffsetLimitOrder(ctx *gin.Context) (offset *big.Int, limit uint8, order registries.Order, err error) { + var paging structs.QueryOffsetLimitOrder + + err = ctx.ShouldBindQuery(&paging) + if err != nil { + return nil, 0, false, err + } + + return paging.Offset.Unpack(), paging.Limit, mapOrder(paging.Order), nil +} + +func getOffsetLimitOrderNoDefault(ctx *gin.Context) (offset *big.Int, limit uint8, order registries.Order, err error) { + var paging structs.QueryOffsetLimitOrderNoDefault err = ctx.ShouldBindQuery(&paging) if err != nil { - return nil, 0, err + return nil, 0, false, err } - return paging.Offset.Unpack(), paging.Limit, nil + return paging.Offset.Unpack(), paging.Limit, mapOrder(paging.Order), nil } func getPageLimit(ctx *gin.Context) (page uint64, limit uint8, err error) { diff --git a/proxy-router/internal/blockchainapi/event_listener.go b/proxy-router/internal/blockchainapi/event_listener.go index 606bd96c..e8949a65 100644 --- a/proxy-router/internal/blockchainapi/event_listener.go +++ b/proxy-router/internal/blockchainapi/event_listener.go @@ -3,34 +3,34 @@ package blockchainapi import ( "context" - "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/contracts/sessionrouter" - "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/config" "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/interfaces" "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/lib" "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/repositories/contracts" + "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/repositories/contracts/bindings/sessionrouter" "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/repositories/registries" - "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/storages" - "github.com/ethereum/go-ethereum/ethclient" + sessionrepo "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/repositories/session" + "github.com/ethereum/go-ethereum/common" ) type EventsListener struct { - sessionRouter *registries.SessionRouter - store *storages.SessionStorage - tsk *lib.Task - log *lib.Logger - client *ethclient.Client - wallet interfaces.Wallet - modelConfigLoader *config.ModelConfigLoader + sessionRouter *registries.SessionRouter + sessionRepo *sessionrepo.SessionRepositoryCached + tsk *lib.Task + log lib.ILogger + wallet interfaces.Wallet + logWatcher contracts.LogWatcher + + //internal state + addr common.Address } -func NewEventsListener(client *ethclient.Client, store *storages.SessionStorage, sessionRouter *registries.SessionRouter, wallet interfaces.Wallet, modelConfigLoader *config.ModelConfigLoader, log *lib.Logger) *EventsListener { +func NewEventsListener(sessionRepo *sessionrepo.SessionRepositoryCached, sessionRouter *registries.SessionRouter, wallet interfaces.Wallet, logWatcher contracts.LogWatcher, log lib.ILogger) *EventsListener { return &EventsListener{ - store: store, - log: log, - sessionRouter: sessionRouter, - client: client, - wallet: wallet, - modelConfigLoader: modelConfigLoader, + log: log, + sessionRouter: sessionRouter, + sessionRepo: sessionRepo, + wallet: wallet, + logWatcher: logWatcher, } } @@ -39,7 +39,19 @@ func (e *EventsListener) Run(ctx context.Context) error { _ = e.log.Close() }() - sub, err := contracts.WatchContractEvents(ctx, e.client, e.sessionRouter.GetContractAddress(), contracts.CreateEventMapper(contracts.BlockchainEventFactory, e.sessionRouter.GetABI()), e.log) + addr, err := e.getWalletAddress() + if err != nil { + return err + } + e.addr = addr + + //TODO: filter events by user/provider address + sub, err := e.logWatcher.Watch( + ctx, + e.sessionRouter.GetContractAddress(), + contracts.CreateEventMapper(contracts.SessionRouterEventFactory, + e.sessionRouter.GetABI(), + ), nil) if err != nil { return err } @@ -53,11 +65,11 @@ func (e *EventsListener) Run(ctx context.Context) error { case event := <-sub.Events(): err := e.controller(event) if err != nil { - e.log.Errorf("error loading data: %s", err) + e.log.Errorf("error handling event: %s", err) } case err := <-sub.Err(): e.log.Errorf("error in event listener: %s", err) - // return err + return err } } } @@ -73,66 +85,35 @@ func (e *EventsListener) controller(event interface{}) error { } func (e *EventsListener) handleSessionOpened(event *sessionrouter.SessionRouterSessionOpened) error { - sessionId := lib.BytesToString(event.SessionId[:]) - e.log.Debugf("received open session router event, sessionId %s", sessionId) - - session, err := e.sessionRouter.GetSession(context.Background(), event.SessionId) - if err != nil { - e.log.Errorf("failed to get session from blockchain: %s, sessionId %s", err, sessionId) - return err - } - - privateKey, err := e.wallet.GetPrivateKey() - if err != nil { - e.log.Errorf("failed to get private key: %s", err) - return err - } - - address, err := lib.PrivKeyBytesToAddr(privateKey) - if err != nil { - e.log.Errorf("failed to get address from private key: %s", err) - return err - } - - if session.Provider.Hex() != address.Hex() && event.UserAddress.Hex() != address.Hex() { - e.log.Debugf("session provider/user is not me, skipping, sessionId %s", sessionId) + if !e.filter(event.ProviderId, event.User) { return nil } - - modelID := lib.BytesToString(session.ModelAgentId[:]) - modelConfig := e.modelConfigLoader.ModelConfigFromID(modelID) - - err = e.store.AddSession(&storages.Session{ - Id: sessionId, - UserAddr: event.UserAddress.Hex(), - ProviderAddr: session.Provider.Hex(), - EndsAt: session.EndsAt, - ModelID: modelID, - ModelName: modelConfig.ModelName, - ModelApiType: modelConfig.ApiType, - }) - if err != nil { - return err - } - - return nil + e.log.Debugf("received open session event, sessionId %s", lib.BytesToString(event.SessionId[:])) + return e.sessionRepo.RefreshSession(context.Background(), event.SessionId) } func (e *EventsListener) handleSessionClosed(event *sessionrouter.SessionRouterSessionClosed) error { - sessionId := lib.BytesToString(event.SessionId[:]) - e.log.Debugf("received close session router event, sessionId %s", sessionId) - - _, ok := e.store.GetSession(sessionId) - if !ok { - e.log.Debugf("session not found in storage, sessionId %s", sessionId) + if !e.filter(event.ProviderId, event.User) { return nil } + e.log.Debugf("received close session event, sessionId %s", lib.BytesToString(event.SessionId[:])) + return e.sessionRepo.RemoveSession(context.Background(), event.SessionId) +} - err := e.store.RemoveSession(sessionId) +// getWalletAddress returns the wallet address from the wallet +func (e *EventsListener) getWalletAddress() (common.Address, error) { + prkey, err := e.wallet.GetPrivateKey() if err != nil { - e.log.Errorf("failed to remove session from storage: %s, sessionId %s", err, sessionId) - return err + return common.Address{}, err } + return lib.PrivKeyStringToAddr(prkey.Hex()) +} - return nil +// filter returns true if the event is for the user or provider +func (e *EventsListener) filter(provider, user common.Address) bool { + ret := provider.Hex() == e.addr.Hex() || user.Hex() == e.addr.Hex() + if !ret { + e.log.Debugf("received event for another user/provider, skipping") + } + return ret } diff --git a/proxy-router/internal/blockchainapi/explorer_client.go b/proxy-router/internal/blockchainapi/explorer_client.go index f9bd8b8c..a1263030 100644 --- a/proxy-router/internal/blockchainapi/explorer_client.go +++ b/proxy-router/internal/blockchainapi/explorer_client.go @@ -1,9 +1,11 @@ package blockchainapi import ( + "context" "encoding/json" "fmt" "net/http" + "time" "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/blockchainapi/structs" "github.com/ethereum/go-ethereum/common" @@ -11,40 +13,48 @@ import ( type ExplorerClient struct { explorerApiUrl string - morTokenAddr string + morTokenAddr common.Address + retryDelay time.Duration + maxRetries uint8 } -func NewExplorerClient(explorerApiUrl string, morTokenAddr string) *ExplorerClient { +func NewExplorerClient(explorerApiUrl string, morTokenAddr common.Address, retryDelay time.Duration, maxRetries uint8) *ExplorerClient { return &ExplorerClient{ explorerApiUrl: explorerApiUrl, morTokenAddr: morTokenAddr, + retryDelay: retryDelay, + maxRetries: maxRetries, } } -func (e *ExplorerClient) GetEthTransactions(address common.Address, page uint64, limit uint8) ([]structs.RawTransaction, error) { +func (e *ExplorerClient) GetEthTransactions(ctx context.Context, address common.Address, page uint64, limit uint8) ([]structs.RawTransaction, error) { query := fmt.Sprintf("?module=account&action=txlist&address=%s&page=%d&offset=%d&sort=desc", address.Hex(), page, limit) url := e.explorerApiUrl + query - transactions, err := e.doRequest(url) + transactions, err := e.doRequest(ctx, url) if err != nil { return nil, err } return transactions, nil } -func (e *ExplorerClient) GetTokenTransactions(address common.Address, page uint64, limit uint8) ([]structs.RawTransaction, error) { - query := fmt.Sprintf("?module=account&action=tokentx&contractaddress=%s&address=%s&page=%d&offset=%d&sort=desc", e.morTokenAddr, address.Hex(), page, limit) +func (e *ExplorerClient) GetTokenTransactions(ctx context.Context, address common.Address, page uint64, limit uint8) ([]structs.RawTransaction, error) { + query := fmt.Sprintf("?module=account&action=tokentx&contractaddress=%s&address=%s&page=%d&offset=%d&sort=desc", e.morTokenAddr.Hex(), address.Hex(), page, limit) url := e.explorerApiUrl + query - transactions, err := e.doRequest(url) + transactions, err := e.doRequest(ctx, url) if err != nil { return nil, err } return transactions, nil } -func (e *ExplorerClient) doRequest(url string) ([]structs.RawTransaction, error) { - req, err := http.NewRequest("GET", url, nil) +func (e *ExplorerClient) doRequest(ctx context.Context, url string) ([]structs.RawTransaction, error) { + return e.doRequestRetry(ctx, url, e.maxRetries) +} + +func (e *ExplorerClient) doRequestRetry(ctx context.Context, url string, retriesLeft uint8) ([]structs.RawTransaction, error) { + req, err := http.NewRequestWithContext(ctx, "GET", url, nil) if err != nil { return nil, err } @@ -57,20 +67,38 @@ func (e *ExplorerClient) doRequest(url string) ([]structs.RawTransaction, error) defer resp.Body.Close() if resp.StatusCode != http.StatusOK { - return nil, fmt.Errorf("failed to fetch eth transactions, HTTP status code: %d", resp.StatusCode) + return nil, fmt.Errorf("failed to fetch transactions, HTTP status code: %d", resp.StatusCode) } var response structs.RawEthTransactionResponse - if err := json.NewDecoder(resp.Body).Decode(&response); err != nil { - return nil, err + + decoder := json.NewDecoder(resp.Body) + if err := decoder.Decode(&response); err != nil { + return nil, fmt.Errorf("failed to decode transactions response: url %s, err %w", url, err) } + if response.Status == "0" { - return make([]structs.RawTransaction, 0), nil + if response.Message == "No transactions found" { + return make([]structs.RawTransaction, 0), nil + } + if retriesLeft == 0 { + return nil, fmt.Errorf("failed to fetch transactions, response message: %s, result %s", response.Message, string(response.Result)) + } + select { + case <-ctx.Done(): + return nil, ctx.Err() + case <-time.After(e.retryDelay): + } + return e.doRequestRetry(ctx, url, retriesLeft-1) } - if response.Status != "1" { - return nil, fmt.Errorf("failed to fetch eth transactions, response status: %s", response.Result) + return nil, fmt.Errorf("failed to fetch transactions, response status: %s", response.Result) + } + + var transactions []structs.RawTransaction + if err := json.Unmarshal(response.Result, &transactions); err != nil { + return nil, fmt.Errorf("failed to unmarshal transactions: %w", err) } - return response.Result, nil + return transactions, nil } diff --git a/proxy-router/internal/blockchainapi/mappers.go b/proxy-router/internal/blockchainapi/mappers.go index 139fbe69..659bbaeb 100644 --- a/proxy-router/internal/blockchainapi/mappers.go +++ b/proxy-router/internal/blockchainapi/mappers.go @@ -3,14 +3,17 @@ package blockchainapi import ( "encoding/hex" - "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/contracts/marketplace" - "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/contracts/sessionrouter" "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/blockchainapi/structs" "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/lib" + m "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/repositories/contracts/bindings/marketplace" + "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/repositories/contracts/bindings/modelregistry" + pr "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/repositories/contracts/bindings/providerregistry" + s "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/repositories/contracts/bindings/sessionrouter" + "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/repositories/registries" "github.com/ethereum/go-ethereum/common" ) -func mapBids(bidIDs [][32]byte, bids []marketplace.Bid) []*structs.Bid { +func mapBids(bidIDs [][32]byte, bids []m.IBidStorageBid) []*structs.Bid { result := make([]*structs.Bid, len(bidIDs)) for i, value := range bids { result[i] = mapBid(bidIDs[i], value) @@ -18,10 +21,10 @@ func mapBids(bidIDs [][32]byte, bids []marketplace.Bid) []*structs.Bid { return result } -func mapBid(bidID common.Hash, bid marketplace.Bid) *structs.Bid { +func mapBid(bidID common.Hash, bid m.IBidStorageBid) *structs.Bid { return &structs.Bid{ Id: bidID, - ModelAgentId: bid.ModelAgentId, + ModelAgentId: bid.ModelId, Provider: bid.Provider, Nonce: &lib.BigInt{Int: *bid.Nonce}, CreatedAt: &lib.BigInt{Int: *bid.CreatedAt}, @@ -30,28 +33,75 @@ func mapBid(bidID common.Hash, bid marketplace.Bid) *structs.Bid { } } -func mapSessions(sessions []sessionrouter.Session) []*structs.Session { - result := make([]*structs.Session, len(sessions)) - for i, value := range sessions { - result[i] = mapSession(value) +func mapSessions(sessionIDs [][32]byte, sessions []s.ISessionStorageSession, bids []m.IBidStorageBid) []*structs.Session { + result := make([]*structs.Session, len(sessionIDs)) + for i := 0; i < len(sessionIDs); i++ { + result[i] = mapSession(sessionIDs[i], sessions[i], bids[i]) } return result } -func mapSession(s sessionrouter.Session) *structs.Session { +func mapSession(ID common.Hash, ses s.ISessionStorageSession, bid m.IBidStorageBid) *structs.Session { return &structs.Session{ - Id: lib.BytesToString(s.Id[:]), - Provider: s.Provider, - User: s.User, - ModelAgentId: lib.BytesToString(s.ModelAgentId[:]), - BidID: lib.BytesToString(s.BidID[:]), - Stake: s.Stake, - PricePerSecond: s.PricePerSecond, - CloseoutReceipt: hex.EncodeToString(s.CloseoutReceipt), - CloseoutType: s.CloseoutType, - ProviderWithdrawnAmount: s.ProviderWithdrawnAmount, - OpenedAt: s.OpenedAt, - EndsAt: s.EndsAt, - ClosedAt: s.ClosedAt, + Id: lib.BytesToString(ID[:]), + Provider: bid.Provider, + User: ses.User, + ModelAgentId: lib.BytesToString(bid.ModelId[:]), + BidID: lib.BytesToString(ses.BidId[:]), + Stake: ses.Stake, + PricePerSecond: bid.PricePerSecond, + CloseoutReceipt: hex.EncodeToString(ses.CloseoutReceipt), + CloseoutType: ses.CloseoutType, + ProviderWithdrawnAmount: ses.ProviderWithdrawnAmount, + OpenedAt: ses.OpenedAt, + EndsAt: ses.EndsAt, + ClosedAt: ses.ClosedAt, } } + +func mapModels(ids [][32]byte, models []modelregistry.IModelStorageModel) []*structs.Model { + result := make([]*structs.Model, len(ids)) + for i, value := range models { + result[i] = mapModel(ids[i], value) + } + return result +} + +func mapModel(id [32]byte, model modelregistry.IModelStorageModel) *structs.Model { + return &structs.Model{ + Id: id, + IpfsCID: model.IpfsCID, + Fee: model.Fee, + Stake: model.Stake, + Owner: model.Owner, + Name: model.Name, + Tags: model.Tags, + CreatedAt: model.CreatedAt, + IsDeleted: model.IsDeleted, + } +} + +func mapProviders(addrs []common.Address, providers []pr.IProviderStorageProvider) []*structs.Provider { + result := make([]*structs.Provider, len(addrs)) + for i, value := range providers { + result[i] = mapProvider(addrs[i], value) + } + return result +} + +func mapProvider(addr common.Address, provider pr.IProviderStorageProvider) *structs.Provider { + return &structs.Provider{ + Address: addr, + Endpoint: provider.Endpoint, + Stake: &lib.BigInt{Int: *provider.Stake}, + IsDeleted: provider.IsDeleted, + CreatedAt: &lib.BigInt{Int: *provider.CreatedAt}, + } +} + +func mapOrder(order string) registries.Order { + if order == "desc" { + return registries.OrderDESC + } + return registries.OrderASC +} diff --git a/proxy-router/internal/blockchainapi/rating.go b/proxy-router/internal/blockchainapi/rating.go deleted file mode 100644 index 46c63562..00000000 --- a/proxy-router/internal/blockchainapi/rating.go +++ /dev/null @@ -1,103 +0,0 @@ -package blockchainapi - -import ( - "math" - "sort" - - m "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/contracts/marketplace" - "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/blockchainapi/structs" - "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/lib" -) - -func rateBids(bidIds [][32]byte, bids []m.Bid, pmStats []m.ProviderModelStats, mStats m.ModelStats, log lib.ILogger) []structs.ScoredBid { - scoredBids := make([]structs.ScoredBid, len(bids)) - - for i := range bids { - score := getScore(bids[i], pmStats[i], mStats) - if math.IsNaN(score) || math.IsInf(score, 0) { - log.Errorf("provider score is not valid %d for bid %v, pmStats %v, mStats %v", score, bidIds[i], pmStats[i], mStats) - score = 0 - } - scoredBid := structs.ScoredBid{ - Bid: structs.Bid{ - Id: bidIds[i], - Provider: bids[i].Provider, - ModelAgentId: bids[i].ModelAgentId, - PricePerSecond: &lib.BigInt{Int: *(bids[i].PricePerSecond)}, - Nonce: &lib.BigInt{Int: *(bids[i].Nonce)}, - CreatedAt: &lib.BigInt{Int: *(bids[i].CreatedAt)}, - DeletedAt: &lib.BigInt{Int: *(bids[i].DeletedAt)}, - }, - Score: score, - } - scoredBids[i] = scoredBid - } - - sort.Slice(scoredBids, func(i, j int) bool { - return scoredBids[i].Score > scoredBids[j].Score - }) - - return scoredBids -} - -func getScore(bid m.Bid, pmStats m.ProviderModelStats, mStats m.ModelStats) float64 { - tpsWeight, ttftWeight, durationWeight, successWeight := 0.27, 0.11, 0.27, 0.35 - count := int64(mStats.Count) - - tpsScore := tpsWeight * normRange(normZIndex(pmStats.TpsScaled1000.Mean, mStats.TpsScaled1000, count), 3.0) - // ttft impact is negative - ttftScore := ttftWeight * normRange(-1*normZIndex(pmStats.TtftMs.Mean, mStats.TtftMs, count), 3.0) - durationScore := durationWeight * normRange(normZIndex(int64(pmStats.TotalDuration), mStats.TotalDuration, count), 3.0) - successScore := successWeight * math.Pow(ratioScore(pmStats.SuccessCount, pmStats.TotalCount), 2) - - priceFloatDecimal, _ := bid.PricePerSecond.Float64() - priceFloat := priceFloatDecimal / math.Pow10(18) - - result := (tpsScore + ttftScore + durationScore + successScore) / priceFloat - - return result -} - -func ratioScore(num, denom uint32) float64 { - if denom == 0 { - return 0 - } - return float64(num) / float64(denom) -} - -// normZIndex normalizes the value using z-index -func normZIndex(pmMean int64, mSD m.LibSDSD, obsNum int64) float64 { - sd := getSD(mSD, obsNum) - if sd == 0 { - return 0 - } - // TODO: consider variance(SD) of provider model stats - return float64(pmMean-mSD.Mean) / getSD(mSD, obsNum) -} - -// normRange normalizes the incoming data within the range [-normRange, normRange] -// to the range [0, 1] cutting off the values outside the range -func normRange(input float64, normRange float64) float64 { - return cutRange01((input + normRange) / (2.0 * normRange)) -} - -func getSD(sd m.LibSDSD, obsNum int64) float64 { - return math.Sqrt(getVariance(sd, obsNum)) -} - -func getVariance(sd m.LibSDSD, obsNum int64) float64 { - if obsNum <= 1 { - return 0 - } - return float64(sd.SqSum) / float64(obsNum-1) -} - -func cutRange01(val float64) float64 { - if val > 1 { - return 1 - } - if val < 0 { - return 0 - } - return val -} diff --git a/proxy-router/internal/blockchainapi/rating_mock.go b/proxy-router/internal/blockchainapi/rating_mock.go index 31ca684e..00214906 100644 --- a/proxy-router/internal/blockchainapi/rating_mock.go +++ b/proxy-router/internal/blockchainapi/rating_mock.go @@ -4,11 +4,19 @@ import ( "math" "math/big" - m "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/contracts/marketplace" + m "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/repositories/contracts/bindings/marketplace" + s "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/repositories/contracts/bindings/sessionrouter" "github.com/ethereum/go-ethereum/common" ) -func sampleDataTPS() ([][32]byte, []m.Bid, []m.ProviderModelStats, m.ModelStats) { +type ModelStats struct { + TpsScaled1000 s.LibSDSD + TtftMs s.LibSDSD + TotalDuration s.LibSDSD + Count int +} + +func sampleDataTPS() ([][32]byte, []m.IBidStorageBid, []s.IStatsStorageProviderModelStats, *s.IStatsStorageModelStats) { modelID := common.HexToHash("0x01") bidIds := [][32]byte{ {0x01}, @@ -16,11 +24,11 @@ func sampleDataTPS() ([][32]byte, []m.Bid, []m.ProviderModelStats, m.ModelStats) {0x03}, } - bids := []m.Bid{ + bids := []m.IBidStorageBid{ { PricePerSecond: ToDecimal(10, DecimalsMOR), Provider: common.HexToAddress("0x01"), - ModelAgentId: modelID, + ModelId: modelID, Nonce: common.Big0, CreatedAt: common.Big1, DeletedAt: common.Big0, @@ -28,7 +36,7 @@ func sampleDataTPS() ([][32]byte, []m.Bid, []m.ProviderModelStats, m.ModelStats) { PricePerSecond: ToDecimal(10, DecimalsMOR), Provider: common.HexToAddress("0x02"), - ModelAgentId: modelID, + ModelId: modelID, Nonce: common.Big0, CreatedAt: common.Big1, DeletedAt: common.Big0, @@ -36,39 +44,39 @@ func sampleDataTPS() ([][32]byte, []m.Bid, []m.ProviderModelStats, m.ModelStats) { PricePerSecond: ToDecimal(10, DecimalsMOR), Provider: common.HexToAddress("0x03"), - ModelAgentId: modelID, + ModelId: modelID, Nonce: common.Big0, CreatedAt: common.Big1, DeletedAt: common.Big0, }, } - pmStats := []m.ProviderModelStats{ + pmStats := []s.IStatsStorageProviderModelStats{ { - TpsScaled1000: m.LibSDSD{Mean: 10, SqSum: 100}, - TtftMs: m.LibSDSD{Mean: 20, SqSum: 200}, + TpsScaled1000: s.LibSDSD{Mean: 10, SqSum: 100}, + TtftMs: s.LibSDSD{Mean: 20, SqSum: 200}, TotalDuration: 30, SuccessCount: 6, TotalCount: 10, }, { - TpsScaled1000: m.LibSDSD{Mean: 20, SqSum: 100}, - TtftMs: m.LibSDSD{Mean: 20, SqSum: 200}, + TpsScaled1000: s.LibSDSD{Mean: 20, SqSum: 100}, + TtftMs: s.LibSDSD{Mean: 20, SqSum: 200}, TotalDuration: 30, SuccessCount: 6, TotalCount: 10, }, { - TpsScaled1000: m.LibSDSD{Mean: 30, SqSum: 100}, - TtftMs: m.LibSDSD{Mean: 20, SqSum: 200}, + TpsScaled1000: s.LibSDSD{Mean: 30, SqSum: 100}, + TtftMs: s.LibSDSD{Mean: 20, SqSum: 200}, TotalDuration: 30, SuccessCount: 6, TotalCount: 10, }, } - mStats := m.ModelStats{ - TpsScaled1000: m.LibSDSD{Mean: 20, SqSum: 100}, - TtftMs: m.LibSDSD{Mean: 20, SqSum: 200}, - TotalDuration: m.LibSDSD{Mean: 30, SqSum: 300}, + mStats := &s.IStatsStorageModelStats{ + TpsScaled1000: s.LibSDSD{Mean: 20, SqSum: 100}, + TtftMs: s.LibSDSD{Mean: 20, SqSum: 200}, + TotalDuration: s.LibSDSD{Mean: 30, SqSum: 300}, Count: 3, } diff --git a/proxy-router/internal/blockchainapi/rating_test.go b/proxy-router/internal/blockchainapi/rating_test.go index 0e3ef73d..f91ff726 100644 --- a/proxy-router/internal/blockchainapi/rating_test.go +++ b/proxy-router/internal/blockchainapi/rating_test.go @@ -1,49 +1,25 @@ package blockchainapi import ( - "math" + "math/big" "testing" - m "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/contracts/marketplace" "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/lib" + "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/rating" + "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/repositories/contracts/bindings/providerregistry" "github.com/stretchr/testify/require" ) func TestRating(t *testing.T) { bidIds, bids, pmStats, mStats := sampleDataTPS() - scoredBids := rateBids(bidIds, bids, pmStats, mStats, lib.NewTestLogger()) - - for i := 1; i < len(scoredBids); i++ { - require.GreaterOrEqual(t, scoredBids[i-1].Score, scoredBids[i].Score, "scoredBids not sorted") + bs := BlockchainService{ + rating: rating.NewRating(rating.NewScorerMock(), nil, lib.NewTestLogger()), } -} -func TestGetScoreZeroObservations(t *testing.T) { - _, bids, _, _ := sampleDataTPS() - score := getScore(bids[0], m.ProviderModelStats{}, m.ModelStats{}) - if math.IsNaN(score) { - require.Fail(t, "score is NaN") - } -} + scoredBids := bs.rateBids(bidIds, bids, pmStats, []providerregistry.IProviderStorageProvider{}, mStats, big.NewInt(0), lib.NewTestLogger()) -func TestGetScoreSingleObservation(t *testing.T) { - _, bids, _, _ := sampleDataTPS() - pmStats := m.ProviderModelStats{ - TpsScaled1000: m.LibSDSD{Mean: 1000, SqSum: 0}, - TtftMs: m.LibSDSD{Mean: 1000, SqSum: 0}, - TotalDuration: 1000, - SuccessCount: 1, - TotalCount: 1, - } - mStats := m.ModelStats{ - TpsScaled1000: m.LibSDSD{Mean: 1000, SqSum: 0}, - TtftMs: m.LibSDSD{Mean: 1000, SqSum: 0}, - TotalDuration: m.LibSDSD{Mean: 1000, SqSum: 0}, - Count: 1, - } - score := getScore(bids[0], pmStats, mStats) - if math.IsNaN(score) { - require.Fail(t, "score is NaN") + for i := 1; i < len(scoredBids); i++ { + require.GreaterOrEqual(t, scoredBids[i-1].Score, scoredBids[i].Score, "scoredBids not sorted") } } diff --git a/proxy-router/internal/blockchainapi/service.go b/proxy-router/internal/blockchainapi/service.go index fd0b010e..ed1341f6 100644 --- a/proxy-router/internal/blockchainapi/service.go +++ b/proxy-router/internal/blockchainapi/service.go @@ -1,57 +1,71 @@ package blockchainapi import ( + "bytes" "context" + "encoding/json" "errors" "fmt" "math/big" + "net" + "net/http" "sort" "strconv" + "time" - "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/contracts/sessionrouter" "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/blockchainapi/structs" - "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/interfaces" + i "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/interfaces" "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/lib" "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/proxyapi" - "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/repositories/registries" - "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/storages" - "github.com/gin-gonic/gin" + "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/rating" + m "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/repositories/contracts/bindings/marketplace" + pr "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/repositories/contracts/bindings/providerregistry" + s "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/repositories/contracts/bindings/sessionrouter" + sr "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/repositories/contracts/bindings/sessionrouter" + "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/repositories/multicall" + r "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/repositories/registries" + sessionrepo "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/repositories/session" "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/ethclient" ) +// basefeeWiggleMultiplier is a multiplier for the basefee to set the maxFeePerGas +const basefeeWiggleMultiplier = 2 + type BlockchainService struct { - ethClient *ethclient.Client - providerRegistry *registries.ProviderRegistry - modelRegistry *registries.ModelRegistry - marketplace *registries.Marketplace - sessionRouter *registries.SessionRouter - morToken *registries.MorToken + ethClient i.EthClient + providerRegistry *r.ProviderRegistry + modelRegistry *r.ModelRegistry + marketplace *r.Marketplace + sessionRouter *r.SessionRouter + morToken *r.MorToken explorerClient *ExplorerClient - sessionStorage *storages.SessionStorage + sessionRepo *sessionrepo.SessionRepositoryCached proxyService *proxyapi.ProxyServiceSender diamonContractAddr common.Address + rating *rating.Rating + minStake *big.Int legacyTx bool - privateKey interfaces.PrKeyProvider + privateKey i.PrKeyProvider log lib.ILogger } var ( - ErrPrKey = errors.New("cannot get private key") - ErrTxOpts = errors.New("failed to get transactOpts") - ErrNonce = errors.New("failed to get nonce") - ErrEstimateGas = errors.New("failed to estimate gas") - ErrSignTx = errors.New("failed to sign transaction") - ErrSendTx = errors.New("failed to send transaction") - ErrWaitMined = errors.New("failed to wait for transaction to be mined") - ErrSessionStore = errors.New("failed to store session") - ErrSessionReport = errors.New("failed to get session report from provider") + ErrPrKey = errors.New("cannot get private key") + ErrTxOpts = errors.New("failed to get transactOpts") + ErrNonce = errors.New("failed to get nonce") + ErrEstimateGas = errors.New("failed to estimate gas") + ErrSignTx = errors.New("failed to sign transaction") + ErrSendTx = errors.New("failed to send transaction") + ErrWaitMined = errors.New("failed to wait for transaction to be mined") + ErrSessionStore = errors.New("failed to store session") + ErrSessionReport = errors.New("failed to get session report from provider") + ErrSessionUserReport = errors.New("failed to get session report from user") ErrBid = errors.New("failed to get bid") ErrProvider = errors.New("failed to get provider") @@ -59,31 +73,34 @@ var ( ErrBudget = errors.New("failed to parse token budget") ErrMyAddress = errors.New("failed to get my address") ErrInitSession = errors.New("failed to initiate session") - ErrApprove = errors.New("failed to approve") + ErrApprove = errors.New("failed to approve funds") ErrMarshal = errors.New("failed to marshal open session payload") + ErrOpenOwnBid = errors.New("cannot open session with own bid") ErrNoBid = errors.New("no bids available") ErrModel = errors.New("can't get model") ) func NewBlockchainService( - ethClient *ethclient.Client, + ethClient i.EthClient, + mc multicall.MulticallBackend, diamonContractAddr common.Address, morTokenAddr common.Address, - explorerApiUrl string, - privateKey interfaces.PrKeyProvider, - sessionStorage *storages.SessionStorage, + explorer *ExplorerClient, + privateKey i.PrKeyProvider, proxyService *proxyapi.ProxyServiceSender, + sessionRepo *sessionrepo.SessionRepositoryCached, + scorerAlgo *rating.Rating, log lib.ILogger, + logEthRpc lib.ILogger, legacyTx bool, ) *BlockchainService { - providerRegistry := registries.NewProviderRegistry(diamonContractAddr, ethClient, log) - modelRegistry := registries.NewModelRegistry(diamonContractAddr, ethClient, log) - marketplace := registries.NewMarketplace(diamonContractAddr, ethClient, log) - sessionRouter := registries.NewSessionRouter(diamonContractAddr, ethClient, log) - morToken := registries.NewMorToken(morTokenAddr, ethClient, log) + providerRegistry := r.NewProviderRegistry(diamonContractAddr, ethClient, mc, logEthRpc) + modelRegistry := r.NewModelRegistry(diamonContractAddr, ethClient, mc, logEthRpc) + marketplace := r.NewMarketplace(diamonContractAddr, ethClient, mc, logEthRpc) + sessionRouter := r.NewSessionRouter(diamonContractAddr, ethClient, mc, logEthRpc) + morToken := r.NewMorToken(morTokenAddr, ethClient, logEthRpc) - explorerClient := NewExplorerClient(explorerApiUrl, morTokenAddr.String()) return &BlockchainService{ ethClient: ethClient, providerRegistry: providerRegistry, @@ -93,10 +110,11 @@ func NewBlockchainService( legacyTx: legacyTx, privateKey: privateKey, morToken: morToken, - explorerClient: explorerClient, + explorerClient: explorer, proxyService: proxyService, - sessionStorage: sessionStorage, diamonContractAddr: diamonContractAddr, + sessionRepo: sessionRepo, + rating: scorerAlgo, log: log, } } @@ -111,18 +129,34 @@ func (s *BlockchainService) GetAllProviders(ctx context.Context) ([]*structs.Pro return nil, err } - result := make([]*structs.Provider, len(addrs)) - for i, value := range providers { - result[i] = &structs.Provider{ - Address: addrs[i], - Endpoint: value.Endpoint, - Stake: &lib.BigInt{Int: *value.Stake}, - IsDeleted: value.IsDeleted, - CreatedAt: &lib.BigInt{Int: *value.CreatedAt}, - } + return mapProviders(addrs, providers), nil +} + +func (s *BlockchainService) GetProviders(ctx context.Context, offset *big.Int, limit uint8, order r.Order) ([]*structs.Provider, error) { + addrs, providers, err := s.providerRegistry.GetProviders(ctx, offset, limit, order) + if err != nil { + return nil, err } - return result, nil + return mapProviders(addrs, providers), nil +} + +// GetMyAddress returns the provider by its wallet address, returns nil if provider is not registered +func (s *BlockchainService) GetProvider(ctx context.Context, providerAddr common.Address) (*structs.Provider, error) { + provider, err := s.providerRegistry.GetProviderById(ctx, providerAddr) + if err != nil { + return nil, err + } + + if provider.IsDeleted { + return nil, nil + } + + if provider.CreatedAt.Cmp(big.NewInt(0)) == 0 { + return nil, nil + } + + return mapProvider(providerAddr, *provider), nil } func (s *BlockchainService) GetAllModels(ctx context.Context) ([]*structs.Model, error) { @@ -131,26 +165,20 @@ func (s *BlockchainService) GetAllModels(ctx context.Context) ([]*structs.Model, return nil, err } - result := make([]*structs.Model, len(ids)) - for i, value := range models { - result[i] = &structs.Model{ - Id: ids[i], - IpfsCID: value.IpfsCID, - Fee: value.Fee, - Stake: value.Stake, - Owner: value.Owner, - Name: value.Name, - Tags: value.Tags, - CreatedAt: value.CreatedAt, - IsDeleted: value.IsDeleted, - } + return mapModels(ids, models), nil +} + +func (s *BlockchainService) GetModels(ctx context.Context, offset *big.Int, limit uint8, order r.Order) ([]*structs.Model, error) { + ids, models, err := s.modelRegistry.GetModels(ctx, offset, limit, order) + if err != nil { + return nil, err } - return result, nil + return mapModels(ids, models), nil } -func (s *BlockchainService) GetBidsByProvider(ctx context.Context, providerAddr common.Address, offset *big.Int, limit uint8) ([]*structs.Bid, error) { - ids, bids, err := s.marketplace.GetBidsByProvider(ctx, providerAddr, offset, limit) +func (s *BlockchainService) GetBidsByProvider(ctx context.Context, providerAddr common.Address, offset *big.Int, limit uint8, order r.Order) ([]*structs.Bid, error) { + ids, bids, err := s.marketplace.GetBidsByProvider(ctx, providerAddr, offset, limit, order) if err != nil { return nil, err } @@ -158,8 +186,8 @@ func (s *BlockchainService) GetBidsByProvider(ctx context.Context, providerAddr return mapBids(ids, bids), nil } -func (s *BlockchainService) GetBidsByModelAgent(ctx context.Context, modelId [32]byte, offset *big.Int, limit uint8) ([]*structs.Bid, error) { - ids, bids, err := s.marketplace.GetBidsByModelAgent(ctx, modelId, offset, limit) +func (s *BlockchainService) GetBidsByModelAgent(ctx context.Context, modelId [32]byte, offset *big.Int, limit uint8, order r.Order) ([]*structs.Bid, error) { + ids, bids, err := s.marketplace.GetBidsByModelAgent(ctx, modelId, offset, limit, order) if err != nil { return nil, err } @@ -167,8 +195,8 @@ func (s *BlockchainService) GetBidsByModelAgent(ctx context.Context, modelId [32 return mapBids(ids, bids), nil } -func (s *BlockchainService) GetActiveBidsByModel(ctx context.Context, modelId common.Hash) ([]*structs.Bid, error) { - ids, bids, err := s.marketplace.GetActiveBidsByModel(ctx, modelId) +func (s *BlockchainService) GetActiveBidsByModel(ctx context.Context, modelId common.Hash, offset *big.Int, limit uint8, order r.Order) ([]*structs.Bid, error) { + ids, bids, err := s.marketplace.GetActiveBidsByModel(ctx, modelId, offset, limit, order) if err != nil { return nil, err } @@ -176,8 +204,12 @@ func (s *BlockchainService) GetActiveBidsByModel(ctx context.Context, modelId co return mapBids(ids, bids), nil } -func (s *BlockchainService) GetActiveBidsByProvider(ctx context.Context, provider common.Address) ([]*structs.Bid, error) { - ids, bids, err := s.marketplace.GetActiveBidsByProvider(ctx, provider) +func (s *BlockchainService) GetActiveBidsByProviderCount(ctx context.Context, provider common.Address) (*big.Int, error) { + return s.marketplace.GetActiveBidsByProviderCount(ctx, provider) +} + +func (s *BlockchainService) GetActiveBidsByProvider(ctx context.Context, provider common.Address, offset *big.Int, limit uint8, order r.Order) ([]*structs.Bid, error) { + ids, bids, err := s.marketplace.GetActiveBidsByProvider(ctx, provider, offset, limit, order) if err != nil { return nil, err } @@ -195,33 +227,89 @@ func (s *BlockchainService) GetBidByID(ctx context.Context, ID common.Hash) (*st } func (s *BlockchainService) GetRatedBids(ctx context.Context, modelID common.Hash) ([]structs.ScoredBid, error) { - modelStats, err := s.marketplace.GetModelStats(ctx, modelID) + modelStats, err := s.sessionRouter.GetModelStats(ctx, modelID) if err != nil { return nil, err } - bidIDs, bids, providerModelStats, err := s.marketplace.GetAllBidsWithRating(ctx, modelID) + bidIDs, bids, providerModelStats, provider, err := s.GetAllBidsWithRating(ctx, modelID) if err != nil { return nil, err } + minStake, err := s.getMinStakeCached(ctx) + if err != nil { + return nil, fmt.Errorf("failed to get min stake: %w", err) + } - ratedBids := rateBids(bidIDs, bids, providerModelStats, modelStats, s.log) + ratedBids := s.rateBids(bidIDs, bids, providerModelStats, provider, modelStats, minStake, s.log) return ratedBids, nil } -func (s *BlockchainService) OpenSession(ctx context.Context, approval, approvalSig []byte, stake *big.Int) (common.Hash, error) { +func (s *BlockchainService) rateBids(bidIds [][32]byte, bids []m.IBidStorageBid, pmStats []s.IStatsStorageProviderModelStats, provider []pr.IProviderStorageProvider, mStats *s.IStatsStorageModelStats, minStake *big.Int, log lib.ILogger) []structs.ScoredBid { + ratingInputs := make([]rating.RatingInput, len(bids)) + bidIDIndexMap := make(map[common.Hash]int) + + for i := range bids { + ratingInputs[i] = rating.RatingInput{ + ScoreInput: rating.ScoreInput{ + ProviderModel: &pmStats[i], + Model: mStats, + ProviderStake: provider[i].Stake, + PricePerSecond: bids[i].PricePerSecond, + MinStake: minStake, + }, + BidID: bidIds[i], + ModelID: bids[i].ModelId, + ProviderID: bids[i].Provider, + } + bidIDIndexMap[bidIds[i]] = i + } + + result := s.rating.RateBids(ratingInputs, log) + scoredBids := make([]structs.ScoredBid, len(result)) + + for i, score := range result { + inputBidIndex := bidIDIndexMap[score.BidID] + scoredBid := structs.ScoredBid{ + Bid: structs.Bid{ + Id: bidIds[inputBidIndex], + Provider: bids[inputBidIndex].Provider, + ModelAgentId: bids[inputBidIndex].ModelId, + PricePerSecond: &lib.BigInt{Int: *(bids[inputBidIndex].PricePerSecond)}, + Nonce: &lib.BigInt{Int: *(bids[inputBidIndex].Nonce)}, + CreatedAt: &lib.BigInt{Int: *(bids[inputBidIndex].CreatedAt)}, + DeletedAt: &lib.BigInt{Int: *(bids[inputBidIndex].DeletedAt)}, + }, + Score: score.Score, + } + scoredBids[i] = scoredBid + } + + sort.Slice(scoredBids, func(i, j int) bool { + return scoredBids[i].Score > scoredBids[j].Score + }) + + return scoredBids +} + +func (s *BlockchainService) OpenSession(ctx context.Context, approval, approvalSig []byte, stake *big.Int, directPayment bool) (common.Hash, error) { prKey, err := s.privateKey.GetPrivateKey() if err != nil { return common.Hash{}, lib.WrapError(ErrPrKey, err) } + _, err = s.Approve(ctx, s.diamonContractAddr, stake) + if err != nil { + return common.Hash{}, lib.WrapError(ErrApprove, err) + } + transactOpt, err := s.getTransactOpts(ctx, prKey) if err != nil { return common.Hash{}, lib.WrapError(ErrTxOpts, err) } - sessionID, _, _, err := s.sessionRouter.OpenSession(transactOpt, approval, approvalSig, stake, prKey) + sessionID, _, _, err := s.sessionRouter.OpenSession(transactOpt, approval, approvalSig, stake, directPayment, prKey) if err != nil { return common.Hash{}, lib.WrapError(ErrSendTx, err) } @@ -240,7 +328,12 @@ func (s *BlockchainService) CreateNewProvider(ctx context.Context, stake *lib.Bi return nil, lib.WrapError(ErrTxOpts, err) } - err = s.providerRegistry.CreateNewProvider(transactOpt, transactOpt.From, stake, endpoint) + _, err = s.Approve(ctx, s.diamonContractAddr, &stake.Int) + if err != nil { + return nil, lib.WrapError(ErrApprove, err) + } + + err = s.providerRegistry.CreateNewProvider(transactOpt, stake, endpoint) if err != nil { return nil, lib.WrapError(ErrSendTx, err) } @@ -270,18 +363,28 @@ func (s *BlockchainService) CreateNewModel(ctx context.Context, modelID common.H return nil, lib.WrapError(ErrTxOpts, err) } - err = s.modelRegistry.CreateNewModel(transactOpt, modelID, ipfsID, fee, stake, transactOpt.From, name, tags) + _, err = s.Approve(ctx, s.diamonContractAddr, &stake.Int) + if err != nil { + return nil, lib.WrapError(ErrApprove, err) + } + + err = s.modelRegistry.CreateNewModel(transactOpt, modelID, ipfsID, fee, stake, name, tags) if err != nil { return nil, lib.WrapError(ErrSendTx, err) } - model, err := s.modelRegistry.GetModelById(ctx, modelID) + ID, err := s.modelRegistry.GetModelId(ctx, transactOpt.From, modelID) + if err != nil { + return nil, lib.WrapError(ErrModel, err) + } + + model, err := s.modelRegistry.GetModelById(ctx, ID) if err != nil { return nil, lib.WrapError(ErrModel, err) } return &structs.Model{ - Id: modelID, + Id: ID, IpfsCID: model.IpfsCID, Fee: model.Fee, Stake: model.Stake, @@ -312,7 +415,33 @@ func (s *BlockchainService) DeregisterModel(ctx context.Context, modelId common. return tx, nil } +func (s *BlockchainService) ModelExists(ctx context.Context, modelID common.Hash) (bool, error) { + m, err := s.modelRegistry.GetModelById(ctx, modelID) + + // cannot pull blockchain data + if err != nil { + return false, err + } + + // model never existed + if m.CreatedAt.Cmp(big.NewInt(0)) == 0 { + return false, nil + } + + // model was deleted + if m.IsDeleted { + return false, nil + } + + return true, nil +} + func (s *BlockchainService) CreateNewBid(ctx context.Context, modelID common.Hash, pricePerSecond *lib.BigInt) (*structs.Bid, error) { + fee, err := s.marketplace.GetBidFee(ctx) + if err != nil { + return nil, err + } + prKey, err := s.privateKey.GetPrivateKey() if err != nil { return nil, lib.WrapError(ErrPrKey, err) @@ -323,21 +452,22 @@ func (s *BlockchainService) CreateNewBid(ctx context.Context, modelID common.Has return nil, lib.WrapError(ErrTxOpts, err) } - err = s.marketplace.PostModelBid(transactOpt, transactOpt.From, modelID, &pricePerSecond.Int) + _, err = s.Approve(ctx, s.diamonContractAddr, fee) if err != nil { - return nil, lib.WrapError(ErrSendTx, err) + return nil, lib.WrapError(ErrApprove, err) } - ids, bids, err := s.marketplace.GetBidsByProvider(ctx, transactOpt.From, big.NewInt(0), 1) + newBidId, err := s.marketplace.PostModelBid(transactOpt, modelID, &pricePerSecond.Int) if err != nil { - return nil, err + return nil, lib.WrapError(ErrSendTx, err) } - if len(ids) == 0 { - return nil, ErrNoBid + bid, err := s.GetBidByID(ctx, newBidId) + if err != nil { + return nil, lib.WrapError(ErrBid, err) } - return mapBid(ids[0], bids[0]), nil + return bid, nil } func (s *BlockchainService) DeleteBid(ctx context.Context, bidId common.Hash) (common.Hash, error) { @@ -359,7 +489,7 @@ func (s *BlockchainService) DeleteBid(ctx context.Context, bidId common.Hash) (c return tx, nil } -func (s *BlockchainService) DeregisterProdiver(ctx context.Context, provider common.Address) (common.Hash, error) { +func (s *BlockchainService) DeregisterProdiver(ctx context.Context) (common.Hash, error) { prKey, err := s.privateKey.GetPrivateKey() if err != nil { return common.Hash{}, lib.WrapError(ErrPrKey, err) @@ -370,7 +500,7 @@ func (s *BlockchainService) DeregisterProdiver(ctx context.Context, provider com return common.Hash{}, lib.WrapError(ErrTxOpts, err) } - tx, err := s.providerRegistry.DeregisterProvider(transactOpt, provider) + tx, err := s.providerRegistry.DeregisterProvider(transactOpt) if err != nil { return common.Hash{}, lib.WrapError(ErrSendTx, err) } @@ -384,9 +514,21 @@ func (s *BlockchainService) CloseSession(ctx context.Context, sessionID common.H return common.Hash{}, lib.WrapError(ErrPrKey, err) } - report, err := s.proxyService.GetSessionReport(ctx, sessionID) + var reportMessage []byte + var signedReport []byte + + report, err := s.proxyService.GetSessionReportFromProvider(ctx, sessionID) if err != nil { - return common.Hash{}, lib.WrapError(ErrSessionReport, err) + s.log.Warnf("failed to get provider's report: %s", err) + + s.log.Info("using user report") + reportMessage, signedReport, err = s.proxyService.GetSessionReportFromUser(ctx, sessionID) + if err != nil { + return common.Hash{}, lib.WrapError(ErrSessionUserReport, err) + } + } else { + reportMessage = report.Message + signedReport = report.SignedReport } transactOpt, err := s.getTransactOpts(ctx, prKey) @@ -394,7 +536,7 @@ func (s *BlockchainService) CloseSession(ctx context.Context, sessionID common.H return common.Hash{}, lib.WrapError(ErrTxOpts, err) } - tx, err := s.sessionRouter.CloseSession(transactOpt, sessionID, report.Message, report.SignedReport, prKey) + tx, err := s.sessionRouter.CloseSession(transactOpt, sessionID, reportMessage, signedReport, prKey) if err != nil { return common.Hash{}, lib.WrapError(ErrSendTx, err) } @@ -402,19 +544,23 @@ func (s *BlockchainService) CloseSession(ctx context.Context, sessionID common.H return tx, nil } -func (s *BlockchainService) GetSession(ctx *gin.Context, sessionID common.Hash) (*structs.Session, error) { +func (s *BlockchainService) GetSession(ctx context.Context, sessionID common.Hash) (*structs.Session, error) { ses, err := s.sessionRouter.GetSession(ctx, sessionID) if err != nil { return nil, err } - return mapSession(*ses), nil + bid, err := s.marketplace.GetBidById(ctx, ses.BidId) + if err != nil { + return nil, err + } + return mapSession(sessionID, *ses, *bid), nil } -func (s *BlockchainService) GetProviderClaimableBalance(ctx *gin.Context, sessionID common.Hash) (*big.Int, error) { +func (s *BlockchainService) GetProviderClaimableBalance(ctx context.Context, sessionID common.Hash) (*big.Int, error) { return s.sessionRouter.GetProviderClaimableBalance(ctx, sessionID) } -func (s *BlockchainService) GetBalance(ctx *gin.Context) (*big.Int, *big.Int, error) { +func (s *BlockchainService) GetBalance(ctx context.Context) (eth *big.Int, mor *big.Int, err error) { prKey, err := s.privateKey.GetPrivateKey() if err != nil { return nil, nil, lib.WrapError(ErrPrKey, err) @@ -438,51 +584,87 @@ func (s *BlockchainService) GetBalance(ctx *gin.Context) (*big.Int, *big.Int, er return ethBalance, morBalance, nil } -func (s *BlockchainService) SendETH(ctx *gin.Context, to common.Address, amount *big.Int) (common.Hash, error) { +func (s *BlockchainService) SendETH(ctx context.Context, to common.Address, amount *big.Int) (common.Hash, error) { + signedTx, err := s.createSignedTransaction(ctx, &types.DynamicFeeTx{ + To: &to, + Value: amount, + }) + + err = s.ethClient.SendTransaction(ctx, signedTx) + if err != nil { + return common.Hash{}, lib.WrapError(ErrSendTx, err) + } + + _, err = bind.WaitMined(ctx, s.ethClient, signedTx) + if err != nil { + return common.Hash{}, lib.WrapError(ErrWaitMined, err) + } + + return signedTx.Hash(), nil +} + +func (s *BlockchainService) createSignedTransaction(ctx context.Context, txdata *types.DynamicFeeTx) (*types.Transaction, error) { prKey, err := s.privateKey.GetPrivateKey() if err != nil { - return common.Hash{}, lib.WrapError(ErrPrKey, err) + return nil, lib.WrapError(ErrPrKey, err) + } + addr, err := lib.PrivKeyBytesToAddr(prKey) + if err != nil { + return nil, err } - transactOpt, err := s.getTransactOpts(ctx, prKey) + gasTipCap, err := s.ethClient.SuggestGasTipCap(ctx) if err != nil { - return common.Hash{}, lib.WrapError(ErrTxOpts, err) + return nil, err } - nonce, err := s.ethClient.PendingNonceAt(ctx, transactOpt.From) + head, err := s.ethClient.HeaderByNumber(ctx, nil) if err != nil { - return common.Hash{}, lib.WrapError(ErrNonce, err) + return nil, err } - estimatedGas, err := s.ethClient.EstimateGas(ctx, ethereum.CallMsg{ - From: transactOpt.From, - To: &to, - Value: amount, - }) + nonce, err := s.ethClient.PendingNonceAt(ctx, addr) if err != nil { - return common.Hash{}, lib.WrapError(ErrEstimateGas, err) + return nil, err } - //TODO: check if this is the right way to calculate gas - gas := float64(estimatedGas) * 1.5 - tx := types.NewTransaction(nonce, to, amount, uint64(gas), transactOpt.GasPrice, nil) - signedTx, err := s.signTx(ctx, tx, prKey) + gasFeeCap := new(big.Int).Add( + gasTipCap, + new(big.Int).Mul(head.BaseFee, big.NewInt(basefeeWiggleMultiplier)), + ) + + gas, err := s.ethClient.EstimateGas(ctx, ethereum.CallMsg{ + From: addr, + To: txdata.To, + Value: txdata.Value, + }) + + chainID, err := s.ethClient.ChainID(ctx) if err != nil { - return common.Hash{}, lib.WrapError(ErrSignTx, err) + return nil, err } - err = s.ethClient.SendTransaction(ctx, signedTx) + tx := types.NewTx(&types.DynamicFeeTx{ + ChainID: chainID, + Nonce: nonce, + GasTipCap: gasTipCap, + GasFeeCap: gasFeeCap, + Gas: gas, + To: txdata.To, + Value: txdata.Value, + }) + + privateKey, err := crypto.ToECDSA(prKey) if err != nil { - return common.Hash{}, lib.WrapError(ErrSendTx, err) + return nil, err } - // Wait for the transaction receipt - _, err = bind.WaitMined(ctx, s.ethClient, signedTx) + signedTx, err := types.SignTx(tx, types.LatestSignerForChainID(tx.ChainId()), privateKey) if err != nil { - return common.Hash{}, lib.WrapError(ErrWaitMined, err) + return nil, lib.WrapError(ErrSignTx, err) } - return signedTx.Hash(), nil + return signedTx, nil } func (s *BlockchainService) SendMOR(ctx context.Context, to common.Address, amount *big.Int) (common.Hash, error) { @@ -542,11 +724,7 @@ func (s *BlockchainService) Approve(ctx context.Context, spender common.Address, return tx.Hash(), nil } -func (s *BlockchainService) GetTodaysBudget(ctx context.Context) (*big.Int, error) { - return s.sessionRouter.GetTodaysBudget(ctx) -} - -func (s *BlockchainService) ClaimProviderBalance(ctx context.Context, sessionID [32]byte, amount *big.Int) (common.Hash, error) { +func (s *BlockchainService) ClaimProviderBalance(ctx context.Context, sessionID [32]byte) (common.Hash, error) { prKey, err := s.privateKey.GetPrivateKey() if err != nil { return common.Hash{}, lib.WrapError(ErrPrKey, err) @@ -557,7 +735,7 @@ func (s *BlockchainService) ClaimProviderBalance(ctx context.Context, sessionID return common.Hash{}, lib.WrapError(ErrTxOpts, err) } - txHash, err := s.sessionRouter.ClaimProviderBalance(transactOpt, sessionID, amount) + txHash, err := s.sessionRouter.ClaimProviderBalance(transactOpt, sessionID) if err != nil { return common.Hash{}, err } @@ -566,28 +744,58 @@ func (s *BlockchainService) ClaimProviderBalance(ctx context.Context, sessionID } func (s *BlockchainService) GetTokenSupply(ctx context.Context) (*big.Int, error) { - return s.morToken.GetTotalSupply(ctx) + return s.sessionRouter.GetTotalMORSupply(ctx, big.NewInt(time.Now().Unix())) } -func (s *BlockchainService) GetSessions(ctx *gin.Context, user, provider common.Address, offset *big.Int, limit uint8) ([]*structs.Session, error) { +func (s *BlockchainService) GetTodaysBudget(ctx context.Context) (*big.Int, error) { + return s.sessionRouter.GetTodaysBudget(ctx, big.NewInt(time.Now().Unix())) +} + +func (s *BlockchainService) GetSessions(ctx context.Context, user, provider common.Address, offset *big.Int, limit uint8, order r.Order) ([]*structs.Session, error) { var ( - sessions []sessionrouter.Session + ids [][32]byte + sessions []sr.ISessionStorageSession err error ) if (user != common.Address{}) { - sessions, err = s.sessionRouter.GetSessionsByUser(ctx, common.HexToAddress(ctx.Query("user")), offset, limit) + ids, sessions, err = s.sessionRouter.GetSessionsByUser(ctx, user, offset, limit, order) } else { // hasProvider - sessions, err = s.sessionRouter.GetSessionsByProvider(ctx, common.HexToAddress(ctx.Query("provider")), offset, limit) + ids, sessions, err = s.sessionRouter.GetSessionsByProvider(ctx, provider, offset, limit, order) } if err != nil { return nil, err } - return mapSessions(sessions), nil + + bidIDs := make([][32]byte, len(sessions)) + for i := 0; i < len(sessions); i++ { + bidIDs[i] = sessions[i].BidId + } + + _, bids, err := s.marketplace.GetMultipleBids(ctx, bidIDs) + if err != nil { + return nil, err + } + + return mapSessions(ids, sessions, bids), nil } -func (s *BlockchainService) GetTransactions(ctx context.Context, page uint64, limit uint8) ([]structs.RawTransaction, error) { +func (s *BlockchainService) GetSessionsIds(ctx context.Context, user, provider common.Address, offset *big.Int, limit uint8, order r.Order) ([]common.Hash, error) { + ids, err := s.sessionRouter.GetSessionsIdsByUser(ctx, user, offset, limit, order) + + if err != nil { + return nil, err + } + bidIDs := make([]common.Hash, len(ids)) + for i := 0; i < len(ids); i++ { + bidIDs[i] = ids[i] + } + + return bidIDs, nil +} + +func (s *BlockchainService) GetTransactions(ctx context.Context, page uint64, limit uint8) ([]structs.RawTransaction, error) { prKey, err := s.privateKey.GetPrivateKey() if err != nil { return nil, lib.WrapError(ErrPrKey, err) @@ -599,12 +807,15 @@ func (s *BlockchainService) GetTransactions(ctx context.Context, page uint64, li } address := transactOpt.From - ethTrxs, err := s.explorerClient.GetEthTransactions(address, page, limit) + morTrxs, err := s.explorerClient.GetTokenTransactions(ctx, address, page, limit) if err != nil { + s.log.Errorf("failed to get mor transactions: %s", err.Error()) return nil, err } - morTrxs, err := s.explorerClient.GetTokenTransactions(address, page, limit) + + ethTrxs, err := s.explorerClient.GetEthTransactions(ctx, address, page, limit) if err != nil { + s.log.Errorf("failed to get eth transactions: %s", err.Error()) return nil, err } @@ -636,38 +847,25 @@ func (s *BlockchainService) openSessionByBid(ctx context.Context, bidID common.H return common.Hash{}, lib.WrapError(ErrBudget, err) } - bid, err := s.marketplace.GetBidById(ctx, bidID) + bid, err := s.GetBidByID(ctx, bidID) if err != nil { return common.Hash{}, lib.WrapError(ErrBid, err) } - totalCost := duration.Mul(bid.PricePerSecond, duration) - stake := totalCost.Div(totalCost.Mul(supply, totalCost), budget) - userAddr, err := s.GetMyAddress(ctx) if err != nil { return common.Hash{}, lib.WrapError(ErrMyAddress, err) } - provider, err := s.providerRegistry.GetProviderById(ctx, bid.Provider) - if err != nil { - return common.Hash{}, lib.WrapError(ErrProvider, err) - } - - initRes, err := s.proxyService.InitiateSession(ctx, userAddr, bid.Provider, stake, bidID, provider.Endpoint) - if err != nil { - return common.Hash{}, lib.WrapError(ErrInitSession, err) - } - - _, err = s.Approve(ctx, s.diamonContractAddr, stake) - if err != nil { - return common.Hash{}, lib.WrapError(ErrApprove, err) + if bid.Provider == userAddr { + return common.Hash{}, ErrOpenOwnBid } - return s.OpenSession(ctx, initRes.Approval, initRes.ApprovalSig, stake) + hash, _, err := s.tryOpenSession(ctx, bid, duration, supply, budget, userAddr, false, false) + return hash, err } -func (s *BlockchainService) OpenSessionByModelId(ctx context.Context, modelID common.Hash, duration *big.Int) (common.Hash, error) { +func (s *BlockchainService) OpenSessionByModelId(ctx context.Context, modelID common.Hash, duration *big.Int, directPayment bool, isFailoverEnabled bool, omitProvider common.Address) (common.Hash, error) { supply, err := s.GetTokenSupply(ctx) if err != nil { return common.Hash{}, lib.WrapError(ErrTokenSupply, err) @@ -678,12 +876,12 @@ func (s *BlockchainService) OpenSessionByModelId(ctx context.Context, modelID co return common.Hash{}, lib.WrapError(ErrBudget, err) } - modelStats, err := s.marketplace.GetModelStats(ctx, modelID) + modelStats, err := s.sessionRouter.GetModelStats(ctx, modelID) if err != nil { return common.Hash{}, lib.WrapError(ErrModel, err) } - bidIDs, bids, providerStats, err := s.marketplace.GetAllBidsWithRating(ctx, modelID) + bidIDs, bids, providerStats, providers, err := s.GetAllBidsWithRating(ctx, modelID) if err != nil { return common.Hash{}, lib.WrapError(ErrBid, err) } @@ -697,39 +895,142 @@ func (s *BlockchainService) OpenSessionByModelId(ctx context.Context, modelID co return common.Hash{}, lib.WrapError(ErrMyAddress, err) } - scoredBids := rateBids(bidIDs, bids, providerStats, modelStats, s.log) + minStake, err := s.getMinStakeCached(ctx) + if err != nil { + return common.Hash{}, fmt.Errorf("failed to get min stake: %w", err) + } + + scoredBids := s.rateBids(bidIDs, bids, providerStats, providers, modelStats, minStake, s.log) for i, bid := range scoredBids { + providerAddr := bid.Bid.Provider + if providerAddr == omitProvider { + s.log.Infof("skipping provider #%d %s", i, providerAddr.String()) + continue + } + + if providerAddr == userAddr { + s.log.Infof("skipping own bid #%d %s", i, bid.Bid.Id) + continue + } + s.log.Infof("trying to open session with provider #%d %s", i, bid.Bid.Provider.String()) - hash, err := s.tryOpenSession(ctx, bid, duration, supply, budget, userAddr) - if err == nil { - return hash, nil + durationCopy := new(big.Int).Set(duration) + + hash, tryNext, err := s.tryOpenSession(ctx, &bid.Bid, durationCopy, supply, budget, userAddr, directPayment, isFailoverEnabled) + if err != nil { + s.log.Errorf("failed to open session with provider %s: %s", bid.Bid.Provider.String(), err.Error()) + if tryNext { + continue + } else { + return common.Hash{}, err + } } - s.log.Errorf("failed to open session with provider %s: %s", bid.Bid.Provider.String(), err.Error()) + + return hash, nil } return common.Hash{}, fmt.Errorf("no provider accepting session") } -func (s *BlockchainService) tryOpenSession(ctx context.Context, bid structs.ScoredBid, duration *big.Int, supply *big.Int, budget *big.Int, userAddr common.Address) (common.Hash, error) { - provider, err := s.providerRegistry.GetProviderById(ctx, bid.Bid.Provider) +func (s *BlockchainService) GetAllBidsWithRating(ctx context.Context, modelAgentID [32]byte) ([][32]byte, []m.IBidStorageBid, []sr.IStatsStorageProviderModelStats, []pr.IProviderStorageProvider, error) { + batchSize := uint8(255) + offset := big.NewInt(0) + bids := make([]m.IBidStorageBid, 0) + ids := make([][32]byte, 0) + providerModelStats := make([]sr.IStatsStorageProviderModelStats, 0) + providers := make([]pr.IProviderStorageProvider, 0) + + for { + if ctx.Err() != nil { + return nil, nil, nil, nil, ctx.Err() + } + + idsBatch, bidsBatch, err := s.marketplace.GetActiveBidsByModel(ctx, modelAgentID, offset, batchSize, r.OrderASC) + if err != nil { + return nil, nil, nil, nil, err + } + + ids = append(ids, idsBatch...) + bids = append(bids, bidsBatch...) + + for _, bid := range bidsBatch { + //TODO: replace with multicall + providerModelStat, err := s.sessionRouter.GetProviderModelStats(ctx, modelAgentID, bid.Provider) + if err != nil { + return nil, nil, nil, nil, err + } + provider, err := s.providerRegistry.GetProviderById(ctx, bid.Provider) + if err != nil { + return nil, nil, nil, nil, err + } + providerModelStats = append(providerModelStats, *providerModelStat) + providers = append(providers, *provider) + } + + if len(bidsBatch) < int(batchSize) { + break + } + + offset.Add(offset, big.NewInt(int64(batchSize))) + } + + return ids, bids, providerModelStats, providers, nil +} + +func (s *BlockchainService) tryOpenSession(ctx context.Context, bid *structs.Bid, duration, supply, budget *big.Int, userAddr common.Address, directPayment bool, failoverEnabled bool) (common.Hash, bool, error) { + provider, err := s.providerRegistry.GetProviderById(ctx, bid.Provider) if err != nil { - return common.Hash{}, lib.WrapError(ErrProvider, err) + return common.Hash{}, false, lib.WrapError(ErrProvider, err) } + sessionCost := (&big.Int{}).Mul(&bid.PricePerSecond.Int, duration) + + var amountTransferred = new(big.Int) + if directPayment { + // amount transferred is the session cost + amountTransferred = sessionCost + } else { + // amount transferred is the stake + stake := (&big.Int{}).Div((&big.Int{}).Mul(supply, sessionCost), budget) + amountTransferred = stake + } + + s.log.Infof("attempting to initiate session %s", map[string]string{ + "provider": bid.Provider.String(), + "directPayment": strconv.FormatBool(directPayment), + "duration": duration.String(), + "bid": bid.Id.String(), + "endpoint": provider.Endpoint, + "amountTransferred": amountTransferred.String(), + }) - totalCost := duration.Mul(&bid.Bid.PricePerSecond.Int, duration) - stake := totalCost.Div(totalCost.Mul(supply, totalCost), budget) + initRes, err := s.proxyService.InitiateSession(ctx, userAddr, bid.Provider, amountTransferred, bid.Id, provider.Endpoint) + if err != nil { + return common.Hash{}, true, lib.WrapError(ErrInitSession, err) + } - initRes, err := s.proxyService.InitiateSession(ctx, userAddr, bid.Bid.Provider, stake, bid.Bid.Id, provider.Endpoint) + _, err = s.Approve(ctx, s.diamonContractAddr, amountTransferred) if err != nil { - return common.Hash{}, lib.WrapError(ErrInitSession, err) + return common.Hash{}, false, lib.WrapError(ErrApprove, err) } - _, err = s.Approve(ctx, s.diamonContractAddr, stake) + hash, err := s.OpenSession(ctx, initRes.Approval, initRes.ApprovalSig, amountTransferred, directPayment) if err != nil { - return common.Hash{}, lib.WrapError(ErrApprove, err) + return common.Hash{}, false, err + } + + session, err := s.sessionRepo.GetSession(ctx, hash) + if err != nil { + return hash, false, fmt.Errorf("failed to get session: %s", err.Error()) } - return s.OpenSession(ctx, initRes.Approval, initRes.ApprovalSig, stake) + session.SetFailoverEnabled(failoverEnabled) + + err = s.sessionRepo.SaveSession(ctx, session) + if err != nil { + return hash, false, fmt.Errorf("failed to store session: %s", err.Error()) + } + + return hash, false, nil } func (s *BlockchainService) GetMyAddress(ctx context.Context) (common.Address, error) { @@ -741,6 +1042,69 @@ func (s *BlockchainService) GetMyAddress(ctx context.Context) (common.Address, e return lib.PrivKeyBytesToAddr(prKey) } +func (s *BlockchainService) CheckConnectivity(ctx context.Context, url string, addr common.Address) (time.Duration, error) { + return s.proxyService.Ping(ctx, url, addr) +} + +func (s *BlockchainService) CheckPortOpen(ctx context.Context, urlStr string) (bool, error) { + host, port, err := net.SplitHostPort(urlStr) + if err != nil { + return false, err + } + portInt, err := strconv.ParseInt(port, 10, 0) + if err != nil { + return false, err + } + + body, _ := json.Marshal(struct { + Host string `json:"host"` + Ports []int64 `json:"ports"` + }{ + Host: host, + Ports: []int64{portInt}, + }) + + req, err := http.NewRequestWithContext(ctx, "POST", "https://portchecker.io/api/query", bytes.NewBuffer(body)) + if err != nil { + return false, err + } + + res, err := http.DefaultClient.Do(req) + if err != nil { + return false, err + } + defer res.Body.Close() + + if res.StatusCode != http.StatusOK { + return false, fmt.Errorf("unexpected status code: %d", res.StatusCode) + } + + var response struct { + Error bool + Msg string + Check []struct { + Port int + Status bool + } + Host string + } + + err = json.NewDecoder(res.Body).Decode(&response) + if err != nil { + return false, err + } + + if response.Error { + return false, fmt.Errorf("portchecker.io error: %s", response.Msg) + } + + if len(response.Check) != 1 { + return false, fmt.Errorf("unexpected response from portchecker.io") + } + + return response.Check[0].Status, nil +} + func (s *BlockchainService) getTransactOpts(ctx context.Context, privKey lib.HexString) (*bind.TransactOpts, error) { privateKey, err := crypto.ToECDSA(privKey) if err != nil { @@ -785,3 +1149,16 @@ func (s *BlockchainService) signTx(ctx context.Context, tx *types.Transaction, p return types.SignTx(tx, types.NewEIP155Signer(chainId), privateKey) } + +func (s *BlockchainService) getMinStakeCached(ctx context.Context) (*big.Int, error) { + if s.minStake != nil { + return s.minStake, nil + } + + minStake, err := s.providerRegistry.GetMinStake(ctx) + if err != nil { + return nil, err + } + s.minStake = minStake + return minStake, nil +} diff --git a/proxy-router/internal/blockchainapi/session_expiry_handler.go b/proxy-router/internal/blockchainapi/session_expiry_handler.go new file mode 100644 index 00000000..c5d4906b --- /dev/null +++ b/proxy-router/internal/blockchainapi/session_expiry_handler.go @@ -0,0 +1,94 @@ +package blockchainapi + +import ( + "context" + "time" + + "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/interfaces" + "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/lib" + "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/storages" +) + +type SessionExpiryHandler struct { + blockchainService *BlockchainService + sessionStorage *storages.SessionStorage + wallet interfaces.Wallet + log lib.ILogger +} + +func NewSessionExpiryHandler(blockchainService *BlockchainService, sessionStorage *storages.SessionStorage, wallet interfaces.Wallet, log lib.ILogger) *SessionExpiryHandler { + return &SessionExpiryHandler{ + blockchainService: blockchainService, + sessionStorage: sessionStorage, + wallet: wallet, + log: log.Named("SESSION_CLOSER"), + } +} + +func (s *SessionExpiryHandler) getWalletAddress() (string, error) { + privateKey, err := s.wallet.GetPrivateKey() + if err != nil { + return "", err + } + + addr, err := lib.PrivKeyBytesToAddr(privateKey) + if err != nil { + return "", err + } + + return addr.Hex(), nil +} + +// Run starts the session autoclose process, checking every minute if any session has ended and closes it. +func (s *SessionExpiryHandler) Run(ctx context.Context) error { + ticker := time.NewTicker(1 * time.Minute) + defer ticker.Stop() + + s.log.Info("Session autoclose started") + for { + select { + case <-ctx.Done(): + return ctx.Err() + case <-ticker.C: + sessions, err := s.sessionStorage.GetSessions() + if err != nil { + s.log.Error(err) + continue + } + + addr, err := s.getWalletAddress() + if err != nil { + s.log.Error(err) + continue + } + + for _, session := range sessions { + if session.UserAddr == addr && session.EndsAt.Int64() < time.Now().Unix() { + sessionId, err := lib.HexToHash(session.Id) + if err != nil { + s.log.Error(err) + continue + } + sessionData, err := s.blockchainService.GetSession(ctx, sessionId) + if err != nil { + s.log.Error(err) + continue + } + if sessionData.ClosedAt.Int64() != 0 { + s.log.Infof("Session %s already closed", session.Id) + s.sessionStorage.RemoveSession(session.Id) + continue + } + + s.log.Infof("Closing session %s", session.Id) + _, err = s.blockchainService.CloseSession(ctx, sessionId) + if err != nil { + s.log.Warnf("cannot close session: %s", err.Error()) + continue + } + s.sessionStorage.RemoveSession(session.Id) + } + } + } + } +} diff --git a/proxy-router/internal/blockchainapi/structs/req.go b/proxy-router/internal/blockchainapi/structs/req.go index dad1284d..8500ebe5 100644 --- a/proxy-router/internal/blockchainapi/structs/req.go +++ b/proxy-router/internal/blockchainapi/structs/req.go @@ -6,9 +6,10 @@ import ( ) type OpenSessionRequest struct { - Approval lib.HexString `json:"approval" binding:"required" validate:"hexadecimal" format:"hex" example:"0x1234"` - ApprovalSig lib.HexString `json:"approvalSig" binding:"required" validate:"hexadecimal" format:"hex" example:"0x1234"` - Stake *lib.BigInt `json:"stake" binding:"required" validate:"number,gt=0" example:"123000000000"` + Approval lib.HexString `json:"approval" binding:"required" validate:"hexadecimal" format:"hex" example:"0x1234"` + ApprovalSig lib.HexString `json:"approvalSig" binding:"required" validate:"hexadecimal" format:"hex" example:"0x1234"` + Stake *lib.BigInt `json:"stake" binding:"required" validate:"number,gt=0" example:"123000000000"` + DirectPayment bool `json:"directPayment" binding:"omitempty"` } type AmountReq struct { @@ -28,9 +29,16 @@ type PathEthAddrID struct { ID lib.Address `uri:"id" binding:"required" validate:"eth_addr"` } -type QueryOffsetLimit struct { - Offset lib.BigInt `form:"offset,default=0" binding:"omitempty" validate:"number"` - Limit uint8 `form:"limit,default=10" binding:"omitempty" validate:"number"` +type QueryOffsetLimitOrder struct { + Offset lib.BigInt `form:"offset,default=0" binding:"omitempty" validate:"number,gte=0" example:"0"` + Limit uint8 `form:"limit,default=10" binding:"omitempty" validate:"number,gte=1" example:"10"` + Order string `form:"order,default=asc" binding:"omitempty" validate:"oneof=asc desc" example:"asc"` +} + +type QueryOffsetLimitOrderNoDefault struct { + Offset lib.BigInt `form:"offset,default=0" binding:"omitempty" validate:"number,gte=0" example:"0"` + Limit uint8 `form:"limit,default=0" binding:"omitempty" validate:"number,gte=1" example:"10"` + Order string `form:"order,default=asc" binding:"omitempty" validate:"oneof=asc desc" example:"asc"` } type QueryPageLimit struct { @@ -47,15 +55,24 @@ type QueryApprove struct { Amount *lib.BigInt `form:"amount" binding:"required" validate:"number,gt=0"` } -type QueryUserOrProvider struct { - User lib.Address `form:"user" binding:"omitempty" validate:"eth_addr"` - Provider lib.Address `form:"provider" binding:"omitempty" validate:"eth_addr"` +type QueryUser struct { + User lib.Address `form:"user" binding:"required" validate:"eth_addr"` +} + +type QueryProvider struct { + Provider lib.Address `form:"provider" binding:"required" validate:"eth_addr"` } type OpenSessionWithDurationRequest struct { SessionDuration *lib.BigInt `json:"sessionDuration"` } +type OpenSessionWithFailover struct { + SessionDuration *lib.BigInt `json:"sessionDuration"` + DirectPayment bool `json:"directPayment" binding:"omitempty"` + Failover bool `json:"failover" binding:"omitempty"` +} + type CreateBidRequest struct { ModelID string `json:"modelID" binding:"required" validate:"hex32"` PricePerSecond *lib.BigInt `json:"pricePerSecond" binding:"required" validate:"number,gt=0"` diff --git a/proxy-router/internal/blockchainapi/structs/res.go b/proxy-router/internal/blockchainapi/structs/res.go index 0d976c01..64783bb2 100644 --- a/proxy-router/internal/blockchainapi/structs/res.go +++ b/proxy-router/internal/blockchainapi/structs/res.go @@ -14,7 +14,7 @@ type TxRes struct { } type ErrRes struct { - Error error `json:"error" example:"error message"` + Error string `json:"error" example:"error message"` } type OpenSessionRes struct { diff --git a/proxy-router/internal/blockchainapi/structs/transaction.go b/proxy-router/internal/blockchainapi/structs/transaction.go index db1aefaf..02b3f711 100644 --- a/proxy-router/internal/blockchainapi/structs/transaction.go +++ b/proxy-router/internal/blockchainapi/structs/transaction.go @@ -1,9 +1,11 @@ package structs +import "encoding/json" + type RawEthTransactionResponse struct { - Status string `json:"status"` - Message string `json:"message"` - Result []RawTransaction `json:"result"` + Status string `json:"status"` + Message string `json:"message"` + Result json.RawMessage `json:"result"` } type RawTransaction struct { diff --git a/proxy-router/internal/chatstorage/file_chat_storage.go b/proxy-router/internal/chatstorage/file_chat_storage.go new file mode 100644 index 00000000..964baa4f --- /dev/null +++ b/proxy-router/internal/chatstorage/file_chat_storage.go @@ -0,0 +1,209 @@ +package chatstorage + +import ( + "encoding/json" + "os" + "path/filepath" + "strings" + "sync" + "time" + + gcs "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/chatstorage/genericchatstorage" + "github.com/sashabaranov/go-openai" +) + +// ChatStorage handles storing conversations to files. +type ChatStorage struct { + dirPath string // Directory path to store the files + fileMutexes map[string]*sync.Mutex // Map to store mutexes for each file + forwardChatContext bool +} + +// NewChatStorage creates a new instance of ChatStorage. +func NewChatStorage(dirPath string) *ChatStorage { + return &ChatStorage{ + dirPath: dirPath, + fileMutexes: make(map[string]*sync.Mutex), + } +} + +// StorePromptResponseToFile stores the prompt and response to a file. +func (cs *ChatStorage) StorePromptResponseToFile(identifier string, isLocal bool, modelId string, prompt *openai.ChatCompletionRequest, responses []gcs.Chunk, promptAt time.Time, responseAt time.Time) error { + if err := os.MkdirAll(cs.dirPath, os.ModePerm); err != nil { + return err + } + + filePath := filepath.Join(cs.dirPath, identifier+".json") + cs.initFileMutex(filePath) + + // Lock the file mutex + cs.fileMutexes[filePath].Lock() + defer cs.fileMutexes[filePath].Unlock() + + var chatHistory gcs.ChatHistory + if _, err := os.Stat(filePath); err == nil { + fileContent, err := os.ReadFile(filePath) + if err != nil { + return err + } + if err := json.Unmarshal(fileContent, &chatHistory); err != nil { + return err + } + } + + messages := make([]gcs.ChatCompletionMessage, 0) + for _, r := range prompt.Messages { + messages = append(messages, gcs.ChatCompletionMessage{ + Content: r.Content, + Role: r.Role, + }) + } + + p := gcs.OpenAiCompletionRequest{ + Messages: messages, + Model: prompt.Model, + MaxTokens: prompt.MaxTokens, + Temperature: prompt.Temperature, + TopP: prompt.TopP, + FrequencyPenalty: prompt.FrequencyPenalty, + PresencePenalty: prompt.PresencePenalty, + Stop: prompt.Stop, + } + + resps := make([]string, len(responses)) + for i, r := range responses { + resps[i] = r.String() + } + + isImageContent := false + isVideoRawContent := false + if len(responses) > 0 { + isImageContent = responses[0].Type() == gcs.ChunkTypeImage + isVideoRawContent = responses[0].Type() == gcs.ChunkTypeVideo + } + + newEntry := gcs.ChatMessage{ + Prompt: p, + Response: strings.Join(resps, ""), + PromptAt: promptAt.Unix(), + ResponseAt: responseAt.Unix(), + IsImageContent: isImageContent, + IsVideoRawContent: isVideoRawContent, + } + + if chatHistory.Messages == nil && len(chatHistory.Messages) == 0 { + chatHistory.ModelId = modelId + chatHistory.Title = prompt.Messages[0].Content + chatHistory.IsLocal = isLocal + } + + newMessages := append(chatHistory.Messages, newEntry) + chatHistory.Messages = newMessages + + updatedContent, err := json.MarshalIndent(chatHistory, "", " ") + if err != nil { + return err + } + + if err := os.WriteFile(filePath, updatedContent, 0644); err != nil { + return err + } + + return nil +} + +func (cs *ChatStorage) GetChats() []gcs.Chat { + var chats []gcs.Chat + files, err := os.ReadDir(cs.dirPath) + if err != nil { + return chats + } + + for _, file := range files { + if file.IsDir() { + continue + } + + chatID := file.Name() + chatID = chatID[:len(chatID)-5] + + fileContent, err := cs.LoadChatFromFile(chatID) + if err != nil { + continue + } + chats = append(chats, gcs.Chat{ + ChatID: chatID, + Title: fileContent.Title, + CreatedAt: fileContent.Messages[0].PromptAt, + ModelID: fileContent.ModelId, + IsLocal: fileContent.IsLocal, + }) + } + + return chats +} + +func (cs *ChatStorage) DeleteChat(identifier string) error { + filePath := filepath.Join(cs.dirPath, identifier+".json") + cs.initFileMutex(filePath) + + cs.fileMutexes[filePath].Lock() + defer cs.fileMutexes[filePath].Unlock() + + if err := os.Remove(filePath); err != nil { + return err + } + return nil +} + +func (cs *ChatStorage) UpdateChatTitle(identifier string, title string) error { + chat, err := cs.LoadChatFromFile(identifier) + if err != nil { + return err + } + chat.Title = title + + filePath := filepath.Join(cs.dirPath, identifier+".json") + cs.initFileMutex(filePath) + + cs.fileMutexes[filePath].Lock() + defer cs.fileMutexes[filePath].Unlock() + + updatedContent, err := json.MarshalIndent(chat, "", " ") + if err != nil { + return err + } + + if err := os.WriteFile(filePath, updatedContent, 0644); err != nil { + return err + } + + return nil +} + +func (cs *ChatStorage) LoadChatFromFile(identifier string) (*gcs.ChatHistory, error) { + filePath := filepath.Join(cs.dirPath, identifier+".json") + cs.initFileMutex(filePath) + + cs.fileMutexes[filePath].Lock() + defer cs.fileMutexes[filePath].Unlock() + + var data gcs.ChatHistory + fileContent, err := os.ReadFile(filePath) + if err != nil { + return &data, err + } + + if err := json.Unmarshal(fileContent, &data); err != nil { + return nil, err + } + + return &data, nil +} + +// initFileMutex initializes a mutex for the file if not already present. +func (cs *ChatStorage) initFileMutex(filePath string) { + if _, exists := cs.fileMutexes[filePath]; !exists { + cs.fileMutexes[filePath] = &sync.Mutex{} + } +} diff --git a/proxy-router/internal/chatstorage/genericchatstorage/chat_requests.go b/proxy-router/internal/chatstorage/genericchatstorage/chat_requests.go new file mode 100644 index 00000000..f958da4e --- /dev/null +++ b/proxy-router/internal/chatstorage/genericchatstorage/chat_requests.go @@ -0,0 +1,42 @@ +package genericchatstorage + +type ChatMessagePartType string + +const ( + ChatMessagePartTypeText ChatMessagePartType = "text" + ChatMessagePartTypeImageURL ChatMessagePartType = "image_url" +) + +type ImageURLDetail string + +const ( + ImageURLDetailHigh ImageURLDetail = "high" + ImageURLDetailLow ImageURLDetail = "low" + ImageURLDetailAuto ImageURLDetail = "auto" +) + +type ChatCompletionMessage struct { + Role string `json:"role"` + Content string `json:"content"` + // MultiContent []ChatMessagePart `json:"multiContent",omitempty` + + // This property isn't in the official documentation, but it's in + // the documentation for the official library for python: + // - https://github.com/openai/openai-python/blob/main/chatml.md + // - https://github.com/openai/openai-cookbook/blob/main/examples/How_to_count_tokens_with_tiktoken.ipynb + Name string `json:"name,omitempty"` + + // For Role=tool prompts this should be set to the ID given in the assistant's prior request to call a tool. + ToolCallID string `json:"tool_call_id,omitempty"` +} + +type ChatCompletionDelta struct { + Content string `json:"content"` + Role string `json:"role"` +} + +type ChatCompletionResponseFormat struct { + Type ChatCompletionResponseFormatType `json:"type,omitempty"` +} + +type ChatCompletionResponseFormatType string diff --git a/proxy-router/internal/proxyapi/chat_responses.go b/proxy-router/internal/chatstorage/genericchatstorage/chat_responses.go similarity index 88% rename from proxy-router/internal/proxyapi/chat_responses.go rename to proxy-router/internal/chatstorage/genericchatstorage/chat_responses.go index 76622cd3..dfd65121 100644 --- a/proxy-router/internal/proxyapi/chat_responses.go +++ b/proxy-router/internal/chatstorage/genericchatstorage/chat_responses.go @@ -1,4 +1,4 @@ -package proxyapi +package genericchatstorage import ( "net/http" @@ -131,3 +131,23 @@ func newRateLimitHeaders(h http.Header) RateLimitHeaders { } const FinishReasonStop FinishReason = "stop" + +type ImageGenerationResult struct { + Job string `json:"job"` + Status string `json:"status"` + ImageUrl string `json:"imageUrl" binding:"omitempty"` +} + +type ImageGenerationCallback func(completion *ImageGenerationResult) error + +type ImageRawContentResult struct { + ImageRawContent string `json:"imageRawContent"` +} + +type ImageRawContentCallback func(completion *ImageRawContentResult) error + +type VideoGenerationResult struct { + VideoRawContent string `json:"videoRawContent"` +} + +type VideoGenerationCallback func(completion *VideoGenerationResult) error diff --git a/proxy-router/internal/chatstorage/genericchatstorage/completion.go b/proxy-router/internal/chatstorage/genericchatstorage/completion.go new file mode 100644 index 00000000..fd75519d --- /dev/null +++ b/proxy-router/internal/chatstorage/genericchatstorage/completion.go @@ -0,0 +1,215 @@ +package genericchatstorage + +import ( + "context" + + "github.com/sashabaranov/go-openai" +) + +type CompletionCallback func(ctx context.Context, completion Chunk) error + +type ChunkType string + +const ( + ChunkTypeText ChunkType = "text" + ChunkTypeImage ChunkType = "image" + ChunkTypeVideo ChunkType = "video" + ChunkTypeControl ChunkType = "control-message" +) + +type ChunkText struct { + data *openai.ChatCompletionResponse + isStreaming bool + tokenCount int +} + +func NewChunkText(data *openai.ChatCompletionResponse) *ChunkText { + return &ChunkText{ + data: data, + } +} + +func (c *ChunkText) IsStreaming() bool { + return false +} + +func (c *ChunkText) Tokens() int { + return c.data.Usage.CompletionTokens +} + +func (c *ChunkText) Type() ChunkType { + return ChunkTypeText +} + +func (c *ChunkText) String() string { + return c.data.Choices[0].Message.Content +} + +func (c *ChunkText) Data() interface{} { + return c.data +} + +type ChunkStreaming struct { + data *openai.ChatCompletionStreamResponse +} + +func NewChunkStreaming(data *openai.ChatCompletionStreamResponse) *ChunkStreaming { + return &ChunkStreaming{ + data: data, + } +} + +func (c *ChunkStreaming) IsStreaming() bool { + return true +} + +func (c *ChunkStreaming) Tokens() int { + return len(c.data.Choices) +} + +func (c *ChunkStreaming) Type() ChunkType { + return ChunkTypeText +} + +func (c *ChunkStreaming) String() string { + return c.data.Choices[0].Delta.Content +} + +func (c *ChunkStreaming) Data() interface{} { + return c.data +} + +type ChunkControl struct { + message string +} + +func NewChunkControl(message string) *ChunkControl { + return &ChunkControl{ + message: message, + } +} + +func (c *ChunkControl) IsStreaming() bool { + return true +} + +func (c *ChunkControl) Tokens() int { + return 0 +} + +func (c *ChunkControl) Type() ChunkType { + return ChunkTypeControl +} + +func (c *ChunkControl) String() string { + return "" +} + +func (c *ChunkControl) Data() interface{} { + return c.message +} + +type ChunkImage struct { + data *ImageGenerationResult +} + +func NewChunkImage(data *ImageGenerationResult) *ChunkImage { + return &ChunkImage{ + data: data, + } +} + +func (c *ChunkImage) IsStreaming() bool { + return false +} + +func (c *ChunkImage) Tokens() int { + return 1 +} + +func (c *ChunkImage) Type() ChunkType { + return ChunkTypeImage +} + +func (c *ChunkImage) String() string { + return c.data.ImageUrl +} + +func (c *ChunkImage) Data() interface{} { + return c.data +} + +type ChunkVideo struct { + data *VideoGenerationResult +} + +func NewChunkVideo(data *VideoGenerationResult) *ChunkVideo { + return &ChunkVideo{ + data: data, + } +} + +func (c *ChunkVideo) IsStreaming() bool { + return false +} + +func (c *ChunkVideo) Tokens() int { + return 1 +} + +func (c *ChunkVideo) Type() ChunkType { + return ChunkTypeVideo +} + +func (c *ChunkVideo) String() string { + return c.data.VideoRawContent +} + +func (c *ChunkVideo) Data() interface{} { + return c.data +} + +type ChunkImageRawContent struct { + data *ImageRawContentResult +} + +func NewChunkImageRawContent(data *ImageRawContentResult) *ChunkImageRawContent { + return &ChunkImageRawContent{ + data: data, + } +} + +func (c *ChunkImageRawContent) IsStreaming() bool { + return false +} + +func (c *ChunkImageRawContent) Tokens() int { + return 1 +} + +func (c *ChunkImageRawContent) Type() ChunkType { + return ChunkTypeImage +} + +func (c *ChunkImageRawContent) String() string { + return c.data.ImageRawContent +} + +func (c *ChunkImageRawContent) Data() interface{} { + return c.data +} + +type Chunk interface { + IsStreaming() bool + Tokens() int + Type() ChunkType + String() string + Data() interface{} +} + +var _ Chunk = &ChunkText{} +var _ Chunk = &ChunkImage{} +var _ Chunk = &ChunkControl{} +var _ Chunk = &ChunkStreaming{} +var _ Chunk = &ChunkVideo{} +var _ Chunk = &ChunkImageRawContent{} diff --git a/proxy-router/internal/proxyapi/chat_requests.go b/proxy-router/internal/chatstorage/genericchatstorage/interface.go similarity index 50% rename from proxy-router/internal/proxyapi/chat_requests.go rename to proxy-router/internal/chatstorage/genericchatstorage/interface.go index 23ccb273..bc2cf9d9 100644 --- a/proxy-router/internal/proxyapi/chat_requests.go +++ b/proxy-router/internal/chatstorage/genericchatstorage/interface.go @@ -1,58 +1,69 @@ -package proxyapi +package genericchatstorage -type ChatMessagePartType string +import ( + "time" -const ( - ChatMessagePartTypeText ChatMessagePartType = "text" - ChatMessagePartTypeImageURL ChatMessagePartType = "image_url" + "github.com/sashabaranov/go-openai" ) -type ImageURLDetail string - -const ( - ImageURLDetailHigh ImageURLDetail = "high" - ImageURLDetailLow ImageURLDetail = "low" - ImageURLDetailAuto ImageURLDetail = "auto" -) - -type ChatMessageImageURL struct { - URL string `json:"url,omitempty"` - Detail ImageURLDetail `json:"detail,omitempty"` +type ChatStorageInterface interface { + LoadChatFromFile(chatID string) (*ChatHistory, error) + StorePromptResponseToFile(chatID string, isLocal bool, modelID string, prompt *openai.ChatCompletionRequest, responses []Chunk, promptAt time.Time, responseAt time.Time) error + GetChats() []Chat + DeleteChat(chatID string) error + UpdateChatTitle(chatID string, title string) error } -type ChatMessagePart struct { - Type ChatMessagePartType `json:"type,omitempty"` - Text string `json:"text,omitempty"` - ImageURL *ChatMessageImageURL `json:"image_url,omitempty"` +type ChatHistory struct { + Title string `json:"title"` + ModelId string `json:"modelId"` + IsLocal bool `json:"isLocal"` + Messages []ChatMessage `json:"messages"` } -type ChatCompletionMessage struct { - Role string `json:"role"` - Content string `json:"content"` - MultiContent []ChatMessagePart +func (h *ChatHistory) AppendChatHistory(req *openai.ChatCompletionRequest) *openai.ChatCompletionRequest { + if h == nil { + return req + } - // This property isn't in the official documentation, but it's in - // the documentation for the official library for python: - // - https://github.com/openai/openai-python/blob/main/chatml.md - // - https://github.com/openai/openai-cookbook/blob/main/examples/How_to_count_tokens_with_tiktoken.ipynb - Name string `json:"name,omitempty"` + messagesWithHistory := make([]openai.ChatCompletionMessage, 0) + for _, chat := range h.Messages { + messagesWithHistory = append(messagesWithHistory, openai.ChatCompletionMessage{ + Role: chat.Prompt.Messages[0].Role, + Content: chat.Prompt.Messages[0].Content, + }) + messagesWithHistory = append(messagesWithHistory, openai.ChatCompletionMessage{ + Role: "assistant", + Content: chat.Response, + }) + } - // For Role=tool prompts this should be set to the ID given in the assistant's prior request to call a tool. - ToolCallID string `json:"tool_call_id,omitempty"` -} + messagesWithHistory = append(messagesWithHistory, req.Messages...) -type ChatCompletionDelta struct { - Content string `json:"content"` - Role string `json:"role"` + // superficial copy to avoid modifying the original request + newReq := *req + newReq.Messages = messagesWithHistory + return &newReq } -type ChatCompletionResponseFormat struct { - Type ChatCompletionResponseFormatType `json:"type,omitempty"` +type ChatMessage struct { + Prompt OpenAiCompletionRequest `json:"prompt"` + Response string `json:"response"` + PromptAt int64 `json:"promptAt"` + ResponseAt int64 `json:"responseAt"` + IsImageContent bool `json:"isImageContent"` + IsVideoRawContent bool `json:"isVideoRawContent"` } -type ChatCompletionResponseFormatType string +type Chat struct { + ChatID string `json:"chatId"` + ModelID string `json:"modelId"` + Title string `json:"title"` + IsLocal bool `json:"isLocal"` + CreatedAt int64 `json:"createdAt"` +} -type OpenAiCompletitionRequest struct { +type OpenAiCompletionRequest struct { Model string `json:"model"` Messages []ChatCompletionMessage `json:"messages"` MaxTokens int `json:"max_tokens,omitempty"` diff --git a/proxy-router/internal/config/config.go b/proxy-router/internal/config/config.go index 3fcf7510..66bdc89b 100644 --- a/proxy-router/internal/config/config.go +++ b/proxy-router/internal/config/config.go @@ -4,26 +4,36 @@ import ( "fmt" "math/big" "runtime" + "strings" + "time" "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/lib" + "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/repositories/multicall" "github.com/ethereum/go-ethereum/common" ) type DerivedConfig struct { WalletAddress common.Address ChainID *big.Int + EthNodeURLs []string } // Validation tags described here: https://pkg.go.dev/github.com/go-playground/validator/v10 type Config struct { - AIEngine struct { - OpenAIBaseURL string `env:"OPENAI_BASE_URL" flag:"open-ai-base-url" validate:"required,url"` - OpenAIKey string `env:"OPENAI_API_KEY" flag:"open-ai-api-key"` + App struct { + ResetKeychain bool `env:"APP_RESET_KEYCHAIN" flag:"app-reset-keychain" desc:"reset keychain on start"` } Blockchain struct { - EthNodeAddress string `env:"ETH_NODE_ADDRESS" flag:"eth-node-address" validate:"required,url"` - EthLegacyTx bool `env:"ETH_NODE_LEGACY_TX" flag:"eth-node-legacy-tx" desc:"use it to disable EIP-1559 transactions"` - ExplorerApiUrl string `env:"EXPLORER_API_URL" flag:"explorer-api-url" validate:"required,url"` + ChainID int `env:"ETH_NODE_CHAIN_ID" flag:"eth-node-chain-id" validate:"number"` + EthNodeAddress string `env:"ETH_NODE_ADDRESS" flag:"eth-node-address" validate:"omitempty,url"` + EthLegacyTx bool `env:"ETH_NODE_LEGACY_TX" flag:"eth-node-legacy-tx" desc:"use it to disable EIP-1559 transactions"` + ExplorerApiUrl string `env:"EXPLORER_API_URL" flag:"explorer-api-url" validate:"required,url"` + ExplorerRetryDelay time.Duration `env:"EXPLORER_RETRY_DELAY" flag:"explorer-retry-delay" validate:"omitempty,duration" desc:"delay between retries"` + ExplorerMaxRetries uint8 `env:"EXPLORER_MAX_RETRIES" flag:"explorer-max-retries" validate:"omitempty,gte=0" desc:"max retries for explorer requests"` + UseSubscriptions bool `env:"ETH_NODE_USE_SUBSCRIPTIONS" flag:"eth-node-use-subscriptions" desc:"set it to true to enable subscriptions for blockchain events, otherwise default polling will be used"` + PollingInterval time.Duration `env:"ETH_NODE_POLLING_INTERVAL" flag:"eth-node-polling-interval" validate:"omitempty,duration" desc:"interval for polling eth node for new events"` + MaxReconnects int `env:"ETH_NODE_MAX_RECONNECTS" flag:"eth-node-max-reconnects" validate:"omitempty,gte=0" desc:"max reconnects to eth node"` + Multicall3Addr *common.Address `env:"MULTICALL3_ADDR" flag:"multicall3-addr" validate:"omitempty,eth_addr" desc:"multicall3 custom contract address"` } Environment string `env:"ENVIRONMENT" flag:"environment"` Marketplace struct { @@ -32,21 +42,22 @@ type Config struct { WalletPrivateKey *lib.HexString `env:"WALLET_PRIVATE_KEY" flag:"wallet-private-key" desc:"if set, will use this private key to sign transactions, otherwise it will be retrieved from the system keychain"` } Log struct { - Color bool `env:"LOG_COLOR" flag:"log-color"` - FolderPath string `env:"LOG_FOLDER_PATH" flag:"log-folder-path" validate:"omitempty,dirpath" desc:"enables file logging and sets the folder path"` - IsProd bool `env:"LOG_IS_PROD" flag:"log-is-prod" validate:"" desc:"affects the format of the log output"` - JSON bool `env:"LOG_JSON" flag:"log-json"` - LevelApp string `env:"LOG_LEVEL_APP" flag:"log-level-app" validate:"omitempty,oneof=debug info warn error dpanic panic fatal"` - LevelConnection string `env:"LOG_LEVEL_CONNECTION" flag:"log-level-connection" validate:"omitempty,oneof=debug info warn error dpanic panic fatal"` - LevelProxy string `env:"LOG_LEVEL_PROXY" flag:"log-level-proxy" validate:"omitempty,oneof=debug info warn error dpanic panic fatal"` - LevelScheduler string `env:"LOG_LEVEL_SCHEDULER" flag:"log-level-scheduler" validate:"omitempty,oneof=debug info warn error dpanic panic fatal"` - LevelContract string `env:"LOG_LEVEL_CONTRACT" flag:"log-level-contract" validate:"omitempty,oneof=debug info warn error dpanic panic fatal"` + Color bool `env:"LOG_COLOR" flag:"log-color"` + FolderPath string `env:"LOG_FOLDER_PATH" flag:"log-folder-path" validate:"omitempty,dirpath" desc:"enables file logging and sets the folder path"` + IsProd bool `env:"LOG_IS_PROD" flag:"log-is-prod" validate:"" desc:"affects the format of the log output"` + JSON bool `env:"LOG_JSON" flag:"log-json"` + LevelApp string `env:"LOG_LEVEL_APP" flag:"log-level-app" validate:"omitempty,oneof=debug info warn error dpanic panic fatal"` + LevelTCP string `env:"LOG_LEVEL_TCP" flag:"log-level-tcp" validate:"omitempty,oneof=debug info warn error dpanic panic fatal"` + LevelEthRPC string `env:"LOG_LEVEL_ETH_RPC" flag:"log-level-eth-rpc" validate:"omitempty,oneof=debug info warn error dpanic panic fatal"` + LevelStorage string `env:"LOG_LEVEL_STORAGE" flag:"log-level-storage" validate:"omitempty,oneof=debug info warn error dpanic panic fatal"` } Proxy struct { - Address string `env:"PROXY_ADDRESS" flag:"proxy-address" validate:"required,hostname_port"` - MaxCachedDests int `env:"PROXY_MAX_CACHED_DESTS" flag:"proxy-max-cached-dests" validate:"required,number" desc:"maximum number of cached destinations per proxy"` - StoragePath string `env:"PROXY_STORAGE_PATH" flag:"proxy-storage-path" validate:"omitempty,dirpath" desc:"enables file storage and sets the folder path"` - ModelsConfigPath string `env:"MODELS_CONFIG_PATH" flag:"models-config-path" validate:"omitempty"` + Address string `env:"PROXY_ADDRESS" flag:"proxy-address" validate:"required,hostname_port"` + StoragePath string `env:"PROXY_STORAGE_PATH" flag:"proxy-storage-path" validate:"omitempty,dirpath" desc:"enables file storage and sets the folder path"` + StoreChatContext *lib.Bool `env:"PROXY_STORE_CHAT_CONTEXT" flag:"proxy-store-chat-context" desc:"store chat context in the proxy storage"` + ForwardChatContext *lib.Bool `env:"PROXY_FORWARD_CHAT_CONTEXT" flag:"proxy-forward-chat-context" desc:"prepend whole stored message history to the prompt"` + ModelsConfigPath string `env:"MODELS_CONFIG_PATH" flag:"models-config-path" validate:"omitempty"` + RatingConfigPath string `env:"RATING_CONFIG_PATH" flag:"rating-config-path" validate:"omitempty" desc:"path to the rating config file"` } System struct { Enable bool `env:"SYS_ENABLE" flag:"sys-enable" desc:"enable system level configuration adjustments"` @@ -68,33 +79,40 @@ func (cfg *Config) SetDefaults() { cfg.Environment = "development" } - // Log - - if cfg.Log.LevelConnection == "" { - cfg.Log.LevelConnection = "info" + // Blockchain + if cfg.Blockchain.MaxReconnects == 0 { + cfg.Blockchain.MaxReconnects = 30 + } + if cfg.Blockchain.PollingInterval == 0 { + cfg.Blockchain.PollingInterval = 10 * time.Second + } + if cfg.Blockchain.Multicall3Addr.Cmp(common.Address{}) == 0 { + cfg.Blockchain.Multicall3Addr = &multicall.MULTICALL3_ADDR } - if cfg.Log.LevelProxy == "" { - cfg.Log.LevelProxy = "info" + if cfg.Blockchain.ExplorerRetryDelay == 0 { + cfg.Blockchain.ExplorerRetryDelay = 5 * time.Second } - if cfg.Log.LevelScheduler == "" { - cfg.Log.LevelScheduler = "info" + if cfg.Blockchain.ExplorerMaxRetries == 0 { + cfg.Blockchain.ExplorerMaxRetries = 5 } - if cfg.Log.LevelContract == "" { - cfg.Log.LevelContract = "debug" + + // Log + + if cfg.Log.LevelTCP == "" { + cfg.Log.LevelTCP = "info" } if cfg.Log.LevelApp == "" { cfg.Log.LevelApp = "debug" } - - // Proxy - if cfg.Proxy.MaxCachedDests == 0 { - cfg.Proxy.MaxCachedDests = 5 + if cfg.Log.LevelEthRPC == "" { + cfg.Log.LevelEthRPC = "info" + } + if cfg.Log.LevelStorage == "" { + cfg.Log.LevelStorage = "info" } // System - // cfg.System.Enable = true // TODO: Temporary override, remove this line - if cfg.System.LocalPortRange == "" { cfg.System.LocalPortRange = "1024 65535" } @@ -126,15 +144,30 @@ func (cfg *Config) SetDefaults() { cfg.Proxy.Address = "0.0.0.0:3333" } if cfg.Web.Address == "" { - cfg.Web.Address = "0.0.0.0:8080" + cfg.Web.Address = "0.0.0.0:8082" } if cfg.Web.PublicUrl == "" { - cfg.Web.PublicUrl = fmt.Sprintf("http://%s", cfg.Web.Address) + // handle cases without domain (ex: :8082) + if string(cfg.Web.Address[0]) == ":" { + cfg.Web.PublicUrl = fmt.Sprintf("http://localhost%s", cfg.Web.Address) + } else { + cfg.Web.PublicUrl = fmt.Sprintf("http://%s", strings.Replace(cfg.Web.Address, "0.0.0.0", "localhost", -1)) + } } - if cfg.Proxy.StoragePath == "" { cfg.Proxy.StoragePath = "./data/badger/" } + if cfg.Proxy.StoreChatContext.Bool == nil { + val := true + cfg.Proxy.StoreChatContext = &lib.Bool{Bool: &val} + } + if cfg.Proxy.ForwardChatContext.Bool == nil { + val := true + cfg.Proxy.ForwardChatContext = &lib.Bool{Bool: &val} + } + if cfg.Proxy.RatingConfigPath == "" { + cfg.Proxy.RatingConfigPath = "./rating-config.json" + } } // GetSanitized returns a copy of the config with sensitive data removed @@ -143,6 +176,12 @@ func (cfg *Config) GetSanitized() interface{} { publicCfg := Config{} publicCfg.Blockchain.EthLegacyTx = cfg.Blockchain.EthLegacyTx + publicCfg.Blockchain.ChainID = cfg.Blockchain.ChainID + publicCfg.Blockchain.MaxReconnects = cfg.Blockchain.MaxReconnects + publicCfg.Blockchain.PollingInterval = cfg.Blockchain.PollingInterval + publicCfg.Blockchain.UseSubscriptions = cfg.Blockchain.UseSubscriptions + publicCfg.Blockchain.ExplorerApiUrl = cfg.Blockchain.ExplorerApiUrl + publicCfg.Environment = cfg.Environment publicCfg.Marketplace.DiamondContractAddress = cfg.Marketplace.DiamondContractAddress @@ -153,12 +192,15 @@ func (cfg *Config) GetSanitized() interface{} { publicCfg.Log.IsProd = cfg.Log.IsProd publicCfg.Log.JSON = cfg.Log.JSON publicCfg.Log.LevelApp = cfg.Log.LevelApp - publicCfg.Log.LevelConnection = cfg.Log.LevelConnection - publicCfg.Log.LevelProxy = cfg.Log.LevelProxy - publicCfg.Log.LevelScheduler = cfg.Log.LevelScheduler + publicCfg.Log.LevelTCP = cfg.Log.LevelTCP + publicCfg.Log.LevelEthRPC = cfg.Log.LevelEthRPC publicCfg.Proxy.Address = cfg.Proxy.Address - publicCfg.Proxy.MaxCachedDests = cfg.Proxy.MaxCachedDests + publicCfg.Proxy.ModelsConfigPath = cfg.Proxy.ModelsConfigPath + publicCfg.Proxy.StoragePath = cfg.Proxy.StoragePath + publicCfg.Proxy.StoreChatContext = cfg.Proxy.StoreChatContext + publicCfg.Proxy.ForwardChatContext = cfg.Proxy.ForwardChatContext + publicCfg.Proxy.RatingConfigPath = cfg.Proxy.RatingConfigPath publicCfg.System.Enable = cfg.System.Enable publicCfg.System.LocalPortRange = cfg.System.LocalPortRange diff --git a/proxy-router/internal/config/loader.go b/proxy-router/internal/config/loader.go index 22c097b5..73cd5b6c 100644 --- a/proxy-router/internal/config/loader.go +++ b/proxy-router/internal/config/loader.go @@ -60,6 +60,8 @@ func LoadConfig(cfg ConfigInterface, osArgs *[]string, validator Validator) erro envValue := os.Getenv(envName) _ = field.Set(envValue) // if err != nil { + // replace all bool envs to lib.Bool to uncomment this and error on invalid env var configuration + // fmt.Printf("invalid value for env variable %s: %s. Error: %s\n", envName, envValue, err) // TODO: set default value on error // return lib.WrapError(ErrEnvParse, fmt.Errorf("%s: %w", envName, err)) // } @@ -106,7 +108,9 @@ func LoadConfig(cfg ConfigInterface, osArgs *[]string, validator Validator) erro if !isErrFlagNotDefined(err) { return lib.WrapError(ErrFlagParse, err) } - + if len(flagset.Args()) == 0 { + break + } args = flagset.Args()[1:] } diff --git a/proxy-router/internal/config/models-config-schema.json b/proxy-router/internal/config/models-config-schema.json new file mode 100644 index 00000000..1149026c --- /dev/null +++ b/proxy-router/internal/config/models-config-schema.json @@ -0,0 +1,65 @@ +{ + "$schema": "https://json-schema.org/draft-07/schema", + "type": "object", + "properties": { + "models": { + "type": "array", + "items": { + "type": "object", + "properties": { + "modelId": { + "title": "Model ID", + "description": "The model ID from blockchain", + "type": "string", + "pattern": "^(0x)?[0-9a-fA-F]{64}$", + "examples": ["0x0000000000000000000000000000000000000000000000000000000000000001"] + }, + "modelName": { + "title": "Model Name", + "description": "The name of the model to be used from this provider", + "type": "string", + "minLength": 1 + }, + "apiType": { + "title": "API Type", + "description": "Defines the type of API to be used with this model", + "type": "string", + "enum": ["openai", "prodia-sd", "prodia-sdxl", "prodia-v2", "hyperbolic-sd"] + }, + "apiUrl": { + "title": "API URL", + "description": "The URL of the API to be used with this model", + "type": "string", + "format": "uri", + "examples": ["http://localhost:11434/v1"] + }, + "apiKey": { + "title": "API Key", + "description": "Optional API key", + "type": "string", + "minLength": 1 + }, + "parameters": { + "title": "Configuration parameters for model", + "description": "Optional parameters that can be passed to model", + "type": "object", + "additionalProperties": { "type": "string" } + }, + "concurrentSlots": { + "title": "Concurrent Slots", + "description": "The number of concurrent slots to be used with this model", + "type": "integer", + "minimum": 1 + }, + "capacityPolicy": { + "title": "Capacity Policy", + "description": "The policy to be used for capacity management", + "type": "string", + "enum": ["simple", "idle_timeout"] + } + }, + "required": ["modelId", "modelName", "apiType", "apiUrl"] + } + } + } +} diff --git a/proxy-router/internal/config/models_config.go b/proxy-router/internal/config/models_config.go index 942e95c4..89c0e73e 100644 --- a/proxy-router/internal/config/models_config.go +++ b/proxy-router/internal/config/models_config.go @@ -1,57 +1,121 @@ package config import ( + "context" "encoding/json" + "errors" + "fmt" "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/lib" + "github.com/ethereum/go-ethereum/common" ) +const ( + ConfigPathDefault = "models-config.json" +) + +var ( + ErrModelNotFound = errors.New("model not found in blockchain, local-only") + ErrValidate = errors.New("cannot perform validation") + ErrConnect = errors.New("cannot connect to the model") +) + +type BlockchainChecker interface { + ModelExists(ctx context.Context, ID common.Hash) (bool, error) +} + +type ConnectionChecker interface { + TryConnect(ctx context.Context, url string) error +} + type ModelConfigLoader struct { - log *lib.Logger - modelConfigs ModelConfigs - path string + log lib.ILogger + modelConfigs ModelConfigs + validator Validator + blockchainChecker BlockchainChecker + connectionChecker ConnectionChecker + configPath string } type ModelConfig struct { - ModelName string `json:"modelName"` - ApiType string `json:"apiType"` - ApiURL string `json:"apiUrl"` - ApiKey string `json:"apiKey"` + ModelName string `json:"modelName" validate:"required"` + ApiType string `json:"apiType" validate:"required"` + ApiURL string `json:"apiUrl" validate:"required,url"` + ApiKey string `json:"apiKey"` + ConcurrentSlots int `json:"concurrentSlots" validate:"number"` + CapacityPolicy string `json:"capacityPolicy"` + Parameters map[string]string `json:"parameters"` } type ModelConfigs map[string]ModelConfig +type ModelConfigsV2 struct { + Models []struct { + ID string `json:"modelId"` + ModelConfig + } `json:"models"` +} -func NewModelConfigLoader(path string, log *lib.Logger) *ModelConfigLoader { +func NewModelConfigLoader(configPath string, validator Validator, blockchainChecker BlockchainChecker, connectionChecker ConnectionChecker, log lib.ILogger) *ModelConfigLoader { return &ModelConfigLoader{ - log: log, - modelConfigs: ModelConfigs{}, - path: path, + log: log.Named("MODEL_LOADER"), + modelConfigs: ModelConfigs{}, + validator: validator, + blockchainChecker: blockchainChecker, + connectionChecker: connectionChecker, + configPath: configPath, } } func (e *ModelConfigLoader) Init() error { - filePath := "models-config.json" - if e.path != "" { - filePath = e.path + filePath := ConfigPathDefault + if e.configPath != "" { + filePath = e.configPath } - e.log.Warnf("loading models config from file: %s", filePath) modelsConfig, err := lib.ReadJSONFile(filePath) if err != nil { e.log.Errorf("failed to read models config file: %s", err) - e.log.Warn("trying to load models config from persistent storage") // TODO: load models config from persistent storage + // e.log.Warn("trying to load models config from persistent storage") return err } + e.log.Infof("models config loaded from file: %s", filePath) + // check config format + var cfgMap map[string]json.RawMessage + err = json.Unmarshal([]byte(modelsConfig), &cfgMap) + if err != nil { + return fmt.Errorf("invalid models config format: %s", err) + } + if cfgMap["models"] != nil { + var modelConfigsV2 ModelConfigsV2 + err = json.Unmarshal([]byte(modelsConfig), &modelConfigsV2) + if err != nil { + return fmt.Errorf("invalid models config V2 format: %s", err) + } + for _, v := range modelConfigsV2.Models { + e.modelConfigs[v.ID] = v.ModelConfig + _ = e.Validate(context.Background(), common.HexToHash(v.ID), v.ModelConfig) + } + return nil + } + + e.log.Warnf("failed to unmarshal to new models config, trying legacy") + + // try old config format var modelConfigs ModelConfigs err = json.Unmarshal([]byte(modelsConfig), &modelConfigs) if err != nil { - e.log.Errorf("failed to unmarshal models config: %s", err) - return err + return fmt.Errorf("invalid models config: %w", err) + } + + err = e.validator.Struct(modelConfigs) + if err != nil { + return fmt.Errorf("invalid models config: %w", err) } + e.modelConfigs = modelConfigs return nil } @@ -62,21 +126,53 @@ func (e *ModelConfigLoader) ModelConfigFromID(ID string) *ModelConfig { } modelConfig := e.modelConfigs[ID] - if modelConfig == (ModelConfig{}) { - e.log.Errorf("model config not found for ID: %s", ID) + if modelConfig.ModelName == "" { + e.log.Warnf("model config not found for ID: %s", ID) return &ModelConfig{} } return &modelConfig } -func (e *ModelConfigLoader) GetAll() ([]string, []ModelConfig) { +func (e *ModelConfigLoader) GetAll() ([]common.Hash, []ModelConfig) { var modelConfigs []ModelConfig - var modelIDs []string + var modelIDs []common.Hash for ID, v := range e.modelConfigs { modelConfigs = append(modelConfigs, v) - modelIDs = append(modelIDs, ID) + modelIDs = append(modelIDs, common.HexToHash(ID)) } return modelIDs, modelConfigs } + +func (e *ModelConfigLoader) Validate(ctx context.Context, modelID common.Hash, cfg ModelConfig) error { + // check if model exists + exists, err := e.blockchainChecker.ModelExists(ctx, modelID) + if err != nil { + err = lib.WrapError(ErrValidate, err) + } else if !exists { + err = ErrModelNotFound + } + + if err != nil { + e.log.Warnf(e.formatLogPrefix(modelID, cfg)+"%s", err) + } + + // try to connect to the model + err = e.connectionChecker.TryConnect(ctx, cfg.ApiURL) + if err != nil { + err = lib.WrapError(ErrConnect, err) + e.log.Warnf(e.formatLogPrefix(modelID, cfg)+"%s", err) + } + + if exists && err == nil { + e.log.Infof(e.formatLogPrefix(modelID, cfg) + "loaded and validated") + } + + return nil +} + +func (e *ModelConfigLoader) formatLogPrefix(modelID common.Hash, config ModelConfig) string { + return fmt.Sprintf("modelID %s, name %s: ", + lib.Short(modelID), config.ModelName) +} diff --git a/proxy-router/internal/config/rating_config.go b/proxy-router/internal/config/rating_config.go new file mode 100644 index 00000000..65aa512a --- /dev/null +++ b/proxy-router/internal/config/rating_config.go @@ -0,0 +1,45 @@ +package config + +import ( + "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/lib" + "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/rating" +) + +const ( + DefaultRatingConfigPath = "rating-config.json" + RatingConfigDefault = ` + { + "$schema": "./internal/rating/rating-config-schema.json", + "algorithm": "default", + "providerAllowlist": [], + "params": { + "weights": { + "tps": 0.24, + "ttft": 0.08, + "duration": 0.24, + "success": 0.32, + "stake": 0.12 + } + } + } + ` +) + +func LoadRating(path string, log lib.ILogger) (*rating.Rating, error) { + log = log.Named("RATING_LOADER") + + filePath := DefaultRatingConfigPath + if path != "" { + filePath = path + } + + config, err := lib.ReadJSONFile(filePath) + if err != nil { + log.Warnf("failed to load rating config file, using defaults") + config = RatingConfigDefault + } else { + log.Infof("rating config loaded from file: %s", filePath) + } + + return rating.NewRatingFromConfig([]byte(config), log) +} diff --git a/proxy-router/internal/constants.go b/proxy-router/internal/constants.go index 8efcb1ff..1ee3288e 100644 --- a/proxy-router/internal/constants.go +++ b/proxy-router/internal/constants.go @@ -5,6 +5,7 @@ const ( CONTENT_TYPE_JSON = "application/json" CONTENT_TYPE_EVENT_STREAM = "text/event-stream" + CONTENT_TYPE_VIDEO_MP4 = "video/mp4" CONNECTION_KEEP_ALIVE = "keep-alive" diff --git a/proxy-router/internal/handlers/httphandlers/http.go b/proxy-router/internal/handlers/httphandlers/http.go index 6f96504d..128956d1 100644 --- a/proxy-router/internal/handlers/httphandlers/http.go +++ b/proxy-router/internal/handlers/httphandlers/http.go @@ -22,7 +22,6 @@ type Registrable interface { } // @title Morpheus Lumerin Node API -// @version 1.0 // @description API for Morpheus Lumerin Node // @termsOfService http://swagger.io/terms/ @@ -49,17 +48,16 @@ func CreateHTTPServer(log lib.ILogger, controllers ...Registrable) *gin.Engine { panic(err) } - // gin.SetMode(gin.ReleaseMode) + gin.SetMode(gin.ReleaseMode) r := gin.New() + r.Use(RequestLogger(log)) r.Use(cors.New(cors.Config{ AllowOrigins: []string{"*"}, - AllowHeaders: []string{"session_id", "model_id"}, + AllowHeaders: []string{"session_id", "model_id", "chat_id"}, })) - // r.Use(RequestLogger(log)) - r.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler)) // r.Any("/debug/pprof/*action", gin.WrapF(pprof.Index)) diff --git a/proxy-router/internal/handlers/httphandlers/logging.go b/proxy-router/internal/handlers/httphandlers/logging.go index a6eb2f6b..650a9a0b 100644 --- a/proxy-router/internal/handlers/httphandlers/logging.go +++ b/proxy-router/internal/handlers/httphandlers/logging.go @@ -1,6 +1,8 @@ package httphandlers import ( + "time" + "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/lib" "github.com/gin-gonic/gin" ) @@ -12,6 +14,12 @@ func RequestLogger(logger lib.ILogger) gin.HandlerFunc { path := c.Request.URL.Path raw := c.Request.URL.RawQuery + start := time.Now() + logger.Debugf("[HTTP-REQ] %s %s", + c.Request.Method, + path, + ) + // Process request c.Next() @@ -20,11 +28,13 @@ func RequestLogger(logger lib.ILogger) gin.HandlerFunc { } // Log details - logger.Infof("[REQ] %s %s [%d] \n [ERROR]: %s", + status := c.Writer.Status() + latency := time.Since(start).Round(time.Millisecond) + logger.Debugf("[HTTP-RES] %s %s [%d] %v", c.Request.Method, path, - c.Writer.Status(), - c.Errors.ByType(gin.ErrorTypePrivate).String(), + status, + latency, ) } } diff --git a/proxy-router/internal/handlers/tcphandlers/tcp.go b/proxy-router/internal/handlers/tcphandlers/tcp.go index 92e54142..92982ae8 100644 --- a/proxy-router/internal/handlers/tcphandlers/tcp.go +++ b/proxy-router/internal/handlers/tcphandlers/tcp.go @@ -13,33 +13,32 @@ import ( ) func NewTCPHandler( - log, connLog lib.ILogger, - schedulerLogFactory func(contractID string) (lib.ILogger, error), + tcpLog lib.ILogger, morRpcHandler *proxyapi.MORRPCController, ) transport.Handler { return func(ctx context.Context, conn net.Conn) { addr := conn.RemoteAddr().String() - sourceLog := connLog.Named("SRC").With("SrcAddr", addr) + sourceLog := tcpLog.Named("TCP").With("SrcAddr", addr) defer func() { - sourceLog.Info("Closing connection") + sourceLog.Debugf("closing connection") conn.Close() }() msg, err := getMessage(conn) if err != nil { - sourceLog.Error("Error reading message", err) + sourceLog.Error("error reading message", err) return } err = morRpcHandler.Handle(ctx, *msg, sourceLog, func(resp *morrpc.RpcResponse) error { + sourceLog.Debugf("sending TCP response for method: %s", msg.Method) _, err := sendMsg(conn, resp) if err != nil { sourceLog.Errorf("Error sending message: %s", err) return err } - sourceLog.Debug("sent message") - return err + return nil }) if err != nil { sourceLog.Errorf("Error handling message: %s\nMessage: %s\n", err, msg) diff --git a/proxy-router/internal/interfaces/ethclient.go b/proxy-router/internal/interfaces/ethclient.go new file mode 100644 index 00000000..993d1731 --- /dev/null +++ b/proxy-router/internal/interfaces/ethclient.go @@ -0,0 +1,29 @@ +package interfaces + +import ( + "context" + "math/big" + + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/common" +) + +type EthClient interface { + ClientBackend + ContractBackend +} + +// ContractWaiter used to do a read/write operation on a contract and wait for the transaction to be mined +type ContractBackend interface { + bind.ContractCaller + bind.ContractFilterer + bind.ContractTransactor + bind.DeployBackend +} + +// ClientBackend used to perform non-contract related read operations on blockchain +type ClientBackend interface { + BlockNumber(context.Context) (uint64, error) + BalanceAt(context.Context, common.Address, *big.Int) (*big.Int, error) + ChainID(context.Context) (*big.Int, error) +} diff --git a/proxy-router/internal/interfaces/keychain.go b/proxy-router/internal/interfaces/keychain.go new file mode 100644 index 00000000..7a6857af --- /dev/null +++ b/proxy-router/internal/interfaces/keychain.go @@ -0,0 +1,9 @@ +package interfaces + +type KeyValueStorage interface { + Get(key string) (string, error) + Insert(key string, value string) error + Upsert(key string, value string) error + Delete(key string) error + DeleteIfExists(key string) error +} diff --git a/proxy-router/internal/interfaces/mocks/eth_client_mock.go b/proxy-router/internal/interfaces/mocks/eth_client_mock.go new file mode 100644 index 00000000..08c7b500 --- /dev/null +++ b/proxy-router/internal/interfaces/mocks/eth_client_mock.go @@ -0,0 +1,910 @@ +// Code generated by mockery v2.46.2. DO NOT EDIT. + +package mocks + +import ( + context "context" + big "math/big" + + common "github.com/ethereum/go-ethereum/common" + + ethereum "github.com/ethereum/go-ethereum" + + mock "github.com/stretchr/testify/mock" + + types "github.com/ethereum/go-ethereum/core/types" +) + +// EthClientMock is an autogenerated mock type for the EthClient type +type EthClientMock struct { + mock.Mock +} + +type EthClientMock_Expecter struct { + mock *mock.Mock +} + +func (_m *EthClientMock) EXPECT() *EthClientMock_Expecter { + return &EthClientMock_Expecter{mock: &_m.Mock} +} + +// BalanceAt provides a mock function with given fields: _a0, _a1, _a2 +func (_m *EthClientMock) BalanceAt(_a0 context.Context, _a1 common.Address, _a2 *big.Int) (*big.Int, error) { + ret := _m.Called(_a0, _a1, _a2) + + if len(ret) == 0 { + panic("no return value specified for BalanceAt") + } + + var r0 *big.Int + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, common.Address, *big.Int) (*big.Int, error)); ok { + return rf(_a0, _a1, _a2) + } + if rf, ok := ret.Get(0).(func(context.Context, common.Address, *big.Int) *big.Int); ok { + r0 = rf(_a0, _a1, _a2) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*big.Int) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, common.Address, *big.Int) error); ok { + r1 = rf(_a0, _a1, _a2) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// EthClientMock_BalanceAt_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'BalanceAt' +type EthClientMock_BalanceAt_Call struct { + *mock.Call +} + +// BalanceAt is a helper method to define mock.On call +// - _a0 context.Context +// - _a1 common.Address +// - _a2 *big.Int +func (_e *EthClientMock_Expecter) BalanceAt(_a0 interface{}, _a1 interface{}, _a2 interface{}) *EthClientMock_BalanceAt_Call { + return &EthClientMock_BalanceAt_Call{Call: _e.mock.On("BalanceAt", _a0, _a1, _a2)} +} + +func (_c *EthClientMock_BalanceAt_Call) Run(run func(_a0 context.Context, _a1 common.Address, _a2 *big.Int)) *EthClientMock_BalanceAt_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(common.Address), args[2].(*big.Int)) + }) + return _c +} + +func (_c *EthClientMock_BalanceAt_Call) Return(_a0 *big.Int, _a1 error) *EthClientMock_BalanceAt_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *EthClientMock_BalanceAt_Call) RunAndReturn(run func(context.Context, common.Address, *big.Int) (*big.Int, error)) *EthClientMock_BalanceAt_Call { + _c.Call.Return(run) + return _c +} + +// BlockNumber provides a mock function with given fields: _a0 +func (_m *EthClientMock) BlockNumber(_a0 context.Context) (uint64, error) { + ret := _m.Called(_a0) + + if len(ret) == 0 { + panic("no return value specified for BlockNumber") + } + + var r0 uint64 + var r1 error + if rf, ok := ret.Get(0).(func(context.Context) (uint64, error)); ok { + return rf(_a0) + } + if rf, ok := ret.Get(0).(func(context.Context) uint64); ok { + r0 = rf(_a0) + } else { + r0 = ret.Get(0).(uint64) + } + + if rf, ok := ret.Get(1).(func(context.Context) error); ok { + r1 = rf(_a0) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// EthClientMock_BlockNumber_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'BlockNumber' +type EthClientMock_BlockNumber_Call struct { + *mock.Call +} + +// BlockNumber is a helper method to define mock.On call +// - _a0 context.Context +func (_e *EthClientMock_Expecter) BlockNumber(_a0 interface{}) *EthClientMock_BlockNumber_Call { + return &EthClientMock_BlockNumber_Call{Call: _e.mock.On("BlockNumber", _a0)} +} + +func (_c *EthClientMock_BlockNumber_Call) Run(run func(_a0 context.Context)) *EthClientMock_BlockNumber_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context)) + }) + return _c +} + +func (_c *EthClientMock_BlockNumber_Call) Return(_a0 uint64, _a1 error) *EthClientMock_BlockNumber_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *EthClientMock_BlockNumber_Call) RunAndReturn(run func(context.Context) (uint64, error)) *EthClientMock_BlockNumber_Call { + _c.Call.Return(run) + return _c +} + +// CallContract provides a mock function with given fields: ctx, call, blockNumber +func (_m *EthClientMock) CallContract(ctx context.Context, call ethereum.CallMsg, blockNumber *big.Int) ([]byte, error) { + ret := _m.Called(ctx, call, blockNumber) + + if len(ret) == 0 { + panic("no return value specified for CallContract") + } + + var r0 []byte + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, ethereum.CallMsg, *big.Int) ([]byte, error)); ok { + return rf(ctx, call, blockNumber) + } + if rf, ok := ret.Get(0).(func(context.Context, ethereum.CallMsg, *big.Int) []byte); ok { + r0 = rf(ctx, call, blockNumber) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]byte) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, ethereum.CallMsg, *big.Int) error); ok { + r1 = rf(ctx, call, blockNumber) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// EthClientMock_CallContract_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'CallContract' +type EthClientMock_CallContract_Call struct { + *mock.Call +} + +// CallContract is a helper method to define mock.On call +// - ctx context.Context +// - call ethereum.CallMsg +// - blockNumber *big.Int +func (_e *EthClientMock_Expecter) CallContract(ctx interface{}, call interface{}, blockNumber interface{}) *EthClientMock_CallContract_Call { + return &EthClientMock_CallContract_Call{Call: _e.mock.On("CallContract", ctx, call, blockNumber)} +} + +func (_c *EthClientMock_CallContract_Call) Run(run func(ctx context.Context, call ethereum.CallMsg, blockNumber *big.Int)) *EthClientMock_CallContract_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(ethereum.CallMsg), args[2].(*big.Int)) + }) + return _c +} + +func (_c *EthClientMock_CallContract_Call) Return(_a0 []byte, _a1 error) *EthClientMock_CallContract_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *EthClientMock_CallContract_Call) RunAndReturn(run func(context.Context, ethereum.CallMsg, *big.Int) ([]byte, error)) *EthClientMock_CallContract_Call { + _c.Call.Return(run) + return _c +} + +// ChainID provides a mock function with given fields: _a0 +func (_m *EthClientMock) ChainID(_a0 context.Context) (*big.Int, error) { + ret := _m.Called(_a0) + + if len(ret) == 0 { + panic("no return value specified for ChainID") + } + + var r0 *big.Int + var r1 error + if rf, ok := ret.Get(0).(func(context.Context) (*big.Int, error)); ok { + return rf(_a0) + } + if rf, ok := ret.Get(0).(func(context.Context) *big.Int); ok { + r0 = rf(_a0) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*big.Int) + } + } + + if rf, ok := ret.Get(1).(func(context.Context) error); ok { + r1 = rf(_a0) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// EthClientMock_ChainID_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ChainID' +type EthClientMock_ChainID_Call struct { + *mock.Call +} + +// ChainID is a helper method to define mock.On call +// - _a0 context.Context +func (_e *EthClientMock_Expecter) ChainID(_a0 interface{}) *EthClientMock_ChainID_Call { + return &EthClientMock_ChainID_Call{Call: _e.mock.On("ChainID", _a0)} +} + +func (_c *EthClientMock_ChainID_Call) Run(run func(_a0 context.Context)) *EthClientMock_ChainID_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context)) + }) + return _c +} + +func (_c *EthClientMock_ChainID_Call) Return(_a0 *big.Int, _a1 error) *EthClientMock_ChainID_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *EthClientMock_ChainID_Call) RunAndReturn(run func(context.Context) (*big.Int, error)) *EthClientMock_ChainID_Call { + _c.Call.Return(run) + return _c +} + +// CodeAt provides a mock function with given fields: ctx, contract, blockNumber +func (_m *EthClientMock) CodeAt(ctx context.Context, contract common.Address, blockNumber *big.Int) ([]byte, error) { + ret := _m.Called(ctx, contract, blockNumber) + + if len(ret) == 0 { + panic("no return value specified for CodeAt") + } + + var r0 []byte + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, common.Address, *big.Int) ([]byte, error)); ok { + return rf(ctx, contract, blockNumber) + } + if rf, ok := ret.Get(0).(func(context.Context, common.Address, *big.Int) []byte); ok { + r0 = rf(ctx, contract, blockNumber) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]byte) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, common.Address, *big.Int) error); ok { + r1 = rf(ctx, contract, blockNumber) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// EthClientMock_CodeAt_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'CodeAt' +type EthClientMock_CodeAt_Call struct { + *mock.Call +} + +// CodeAt is a helper method to define mock.On call +// - ctx context.Context +// - contract common.Address +// - blockNumber *big.Int +func (_e *EthClientMock_Expecter) CodeAt(ctx interface{}, contract interface{}, blockNumber interface{}) *EthClientMock_CodeAt_Call { + return &EthClientMock_CodeAt_Call{Call: _e.mock.On("CodeAt", ctx, contract, blockNumber)} +} + +func (_c *EthClientMock_CodeAt_Call) Run(run func(ctx context.Context, contract common.Address, blockNumber *big.Int)) *EthClientMock_CodeAt_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(common.Address), args[2].(*big.Int)) + }) + return _c +} + +func (_c *EthClientMock_CodeAt_Call) Return(_a0 []byte, _a1 error) *EthClientMock_CodeAt_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *EthClientMock_CodeAt_Call) RunAndReturn(run func(context.Context, common.Address, *big.Int) ([]byte, error)) *EthClientMock_CodeAt_Call { + _c.Call.Return(run) + return _c +} + +// EstimateGas provides a mock function with given fields: ctx, call +func (_m *EthClientMock) EstimateGas(ctx context.Context, call ethereum.CallMsg) (uint64, error) { + ret := _m.Called(ctx, call) + + if len(ret) == 0 { + panic("no return value specified for EstimateGas") + } + + var r0 uint64 + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, ethereum.CallMsg) (uint64, error)); ok { + return rf(ctx, call) + } + if rf, ok := ret.Get(0).(func(context.Context, ethereum.CallMsg) uint64); ok { + r0 = rf(ctx, call) + } else { + r0 = ret.Get(0).(uint64) + } + + if rf, ok := ret.Get(1).(func(context.Context, ethereum.CallMsg) error); ok { + r1 = rf(ctx, call) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// EthClientMock_EstimateGas_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'EstimateGas' +type EthClientMock_EstimateGas_Call struct { + *mock.Call +} + +// EstimateGas is a helper method to define mock.On call +// - ctx context.Context +// - call ethereum.CallMsg +func (_e *EthClientMock_Expecter) EstimateGas(ctx interface{}, call interface{}) *EthClientMock_EstimateGas_Call { + return &EthClientMock_EstimateGas_Call{Call: _e.mock.On("EstimateGas", ctx, call)} +} + +func (_c *EthClientMock_EstimateGas_Call) Run(run func(ctx context.Context, call ethereum.CallMsg)) *EthClientMock_EstimateGas_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(ethereum.CallMsg)) + }) + return _c +} + +func (_c *EthClientMock_EstimateGas_Call) Return(_a0 uint64, _a1 error) *EthClientMock_EstimateGas_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *EthClientMock_EstimateGas_Call) RunAndReturn(run func(context.Context, ethereum.CallMsg) (uint64, error)) *EthClientMock_EstimateGas_Call { + _c.Call.Return(run) + return _c +} + +// FilterLogs provides a mock function with given fields: ctx, q +func (_m *EthClientMock) FilterLogs(ctx context.Context, q ethereum.FilterQuery) ([]types.Log, error) { + ret := _m.Called(ctx, q) + + if len(ret) == 0 { + panic("no return value specified for FilterLogs") + } + + var r0 []types.Log + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, ethereum.FilterQuery) ([]types.Log, error)); ok { + return rf(ctx, q) + } + if rf, ok := ret.Get(0).(func(context.Context, ethereum.FilterQuery) []types.Log); ok { + r0 = rf(ctx, q) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]types.Log) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, ethereum.FilterQuery) error); ok { + r1 = rf(ctx, q) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// EthClientMock_FilterLogs_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'FilterLogs' +type EthClientMock_FilterLogs_Call struct { + *mock.Call +} + +// FilterLogs is a helper method to define mock.On call +// - ctx context.Context +// - q ethereum.FilterQuery +func (_e *EthClientMock_Expecter) FilterLogs(ctx interface{}, q interface{}) *EthClientMock_FilterLogs_Call { + return &EthClientMock_FilterLogs_Call{Call: _e.mock.On("FilterLogs", ctx, q)} +} + +func (_c *EthClientMock_FilterLogs_Call) Run(run func(ctx context.Context, q ethereum.FilterQuery)) *EthClientMock_FilterLogs_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(ethereum.FilterQuery)) + }) + return _c +} + +func (_c *EthClientMock_FilterLogs_Call) Return(_a0 []types.Log, _a1 error) *EthClientMock_FilterLogs_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *EthClientMock_FilterLogs_Call) RunAndReturn(run func(context.Context, ethereum.FilterQuery) ([]types.Log, error)) *EthClientMock_FilterLogs_Call { + _c.Call.Return(run) + return _c +} + +// HeaderByNumber provides a mock function with given fields: ctx, number +func (_m *EthClientMock) HeaderByNumber(ctx context.Context, number *big.Int) (*types.Header, error) { + ret := _m.Called(ctx, number) + + if len(ret) == 0 { + panic("no return value specified for HeaderByNumber") + } + + var r0 *types.Header + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *big.Int) (*types.Header, error)); ok { + return rf(ctx, number) + } + if rf, ok := ret.Get(0).(func(context.Context, *big.Int) *types.Header); ok { + r0 = rf(ctx, number) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*types.Header) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *big.Int) error); ok { + r1 = rf(ctx, number) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// EthClientMock_HeaderByNumber_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'HeaderByNumber' +type EthClientMock_HeaderByNumber_Call struct { + *mock.Call +} + +// HeaderByNumber is a helper method to define mock.On call +// - ctx context.Context +// - number *big.Int +func (_e *EthClientMock_Expecter) HeaderByNumber(ctx interface{}, number interface{}) *EthClientMock_HeaderByNumber_Call { + return &EthClientMock_HeaderByNumber_Call{Call: _e.mock.On("HeaderByNumber", ctx, number)} +} + +func (_c *EthClientMock_HeaderByNumber_Call) Run(run func(ctx context.Context, number *big.Int)) *EthClientMock_HeaderByNumber_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(*big.Int)) + }) + return _c +} + +func (_c *EthClientMock_HeaderByNumber_Call) Return(_a0 *types.Header, _a1 error) *EthClientMock_HeaderByNumber_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *EthClientMock_HeaderByNumber_Call) RunAndReturn(run func(context.Context, *big.Int) (*types.Header, error)) *EthClientMock_HeaderByNumber_Call { + _c.Call.Return(run) + return _c +} + +// PendingCodeAt provides a mock function with given fields: ctx, account +func (_m *EthClientMock) PendingCodeAt(ctx context.Context, account common.Address) ([]byte, error) { + ret := _m.Called(ctx, account) + + if len(ret) == 0 { + panic("no return value specified for PendingCodeAt") + } + + var r0 []byte + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, common.Address) ([]byte, error)); ok { + return rf(ctx, account) + } + if rf, ok := ret.Get(0).(func(context.Context, common.Address) []byte); ok { + r0 = rf(ctx, account) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]byte) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, common.Address) error); ok { + r1 = rf(ctx, account) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// EthClientMock_PendingCodeAt_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'PendingCodeAt' +type EthClientMock_PendingCodeAt_Call struct { + *mock.Call +} + +// PendingCodeAt is a helper method to define mock.On call +// - ctx context.Context +// - account common.Address +func (_e *EthClientMock_Expecter) PendingCodeAt(ctx interface{}, account interface{}) *EthClientMock_PendingCodeAt_Call { + return &EthClientMock_PendingCodeAt_Call{Call: _e.mock.On("PendingCodeAt", ctx, account)} +} + +func (_c *EthClientMock_PendingCodeAt_Call) Run(run func(ctx context.Context, account common.Address)) *EthClientMock_PendingCodeAt_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(common.Address)) + }) + return _c +} + +func (_c *EthClientMock_PendingCodeAt_Call) Return(_a0 []byte, _a1 error) *EthClientMock_PendingCodeAt_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *EthClientMock_PendingCodeAt_Call) RunAndReturn(run func(context.Context, common.Address) ([]byte, error)) *EthClientMock_PendingCodeAt_Call { + _c.Call.Return(run) + return _c +} + +// PendingNonceAt provides a mock function with given fields: ctx, account +func (_m *EthClientMock) PendingNonceAt(ctx context.Context, account common.Address) (uint64, error) { + ret := _m.Called(ctx, account) + + if len(ret) == 0 { + panic("no return value specified for PendingNonceAt") + } + + var r0 uint64 + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, common.Address) (uint64, error)); ok { + return rf(ctx, account) + } + if rf, ok := ret.Get(0).(func(context.Context, common.Address) uint64); ok { + r0 = rf(ctx, account) + } else { + r0 = ret.Get(0).(uint64) + } + + if rf, ok := ret.Get(1).(func(context.Context, common.Address) error); ok { + r1 = rf(ctx, account) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// EthClientMock_PendingNonceAt_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'PendingNonceAt' +type EthClientMock_PendingNonceAt_Call struct { + *mock.Call +} + +// PendingNonceAt is a helper method to define mock.On call +// - ctx context.Context +// - account common.Address +func (_e *EthClientMock_Expecter) PendingNonceAt(ctx interface{}, account interface{}) *EthClientMock_PendingNonceAt_Call { + return &EthClientMock_PendingNonceAt_Call{Call: _e.mock.On("PendingNonceAt", ctx, account)} +} + +func (_c *EthClientMock_PendingNonceAt_Call) Run(run func(ctx context.Context, account common.Address)) *EthClientMock_PendingNonceAt_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(common.Address)) + }) + return _c +} + +func (_c *EthClientMock_PendingNonceAt_Call) Return(_a0 uint64, _a1 error) *EthClientMock_PendingNonceAt_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *EthClientMock_PendingNonceAt_Call) RunAndReturn(run func(context.Context, common.Address) (uint64, error)) *EthClientMock_PendingNonceAt_Call { + _c.Call.Return(run) + return _c +} + +// SendTransaction provides a mock function with given fields: ctx, tx +func (_m *EthClientMock) SendTransaction(ctx context.Context, tx *types.Transaction) error { + ret := _m.Called(ctx, tx) + + if len(ret) == 0 { + panic("no return value specified for SendTransaction") + } + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, *types.Transaction) error); ok { + r0 = rf(ctx, tx) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// EthClientMock_SendTransaction_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SendTransaction' +type EthClientMock_SendTransaction_Call struct { + *mock.Call +} + +// SendTransaction is a helper method to define mock.On call +// - ctx context.Context +// - tx *types.Transaction +func (_e *EthClientMock_Expecter) SendTransaction(ctx interface{}, tx interface{}) *EthClientMock_SendTransaction_Call { + return &EthClientMock_SendTransaction_Call{Call: _e.mock.On("SendTransaction", ctx, tx)} +} + +func (_c *EthClientMock_SendTransaction_Call) Run(run func(ctx context.Context, tx *types.Transaction)) *EthClientMock_SendTransaction_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(*types.Transaction)) + }) + return _c +} + +func (_c *EthClientMock_SendTransaction_Call) Return(_a0 error) *EthClientMock_SendTransaction_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *EthClientMock_SendTransaction_Call) RunAndReturn(run func(context.Context, *types.Transaction) error) *EthClientMock_SendTransaction_Call { + _c.Call.Return(run) + return _c +} + +// SubscribeFilterLogs provides a mock function with given fields: ctx, q, ch +func (_m *EthClientMock) SubscribeFilterLogs(ctx context.Context, q ethereum.FilterQuery, ch chan<- types.Log) (ethereum.Subscription, error) { + ret := _m.Called(ctx, q, ch) + + if len(ret) == 0 { + panic("no return value specified for SubscribeFilterLogs") + } + + var r0 ethereum.Subscription + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, ethereum.FilterQuery, chan<- types.Log) (ethereum.Subscription, error)); ok { + return rf(ctx, q, ch) + } + if rf, ok := ret.Get(0).(func(context.Context, ethereum.FilterQuery, chan<- types.Log) ethereum.Subscription); ok { + r0 = rf(ctx, q, ch) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(ethereum.Subscription) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, ethereum.FilterQuery, chan<- types.Log) error); ok { + r1 = rf(ctx, q, ch) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// EthClientMock_SubscribeFilterLogs_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SubscribeFilterLogs' +type EthClientMock_SubscribeFilterLogs_Call struct { + *mock.Call +} + +// SubscribeFilterLogs is a helper method to define mock.On call +// - ctx context.Context +// - q ethereum.FilterQuery +// - ch chan<- types.Log +func (_e *EthClientMock_Expecter) SubscribeFilterLogs(ctx interface{}, q interface{}, ch interface{}) *EthClientMock_SubscribeFilterLogs_Call { + return &EthClientMock_SubscribeFilterLogs_Call{Call: _e.mock.On("SubscribeFilterLogs", ctx, q, ch)} +} + +func (_c *EthClientMock_SubscribeFilterLogs_Call) Run(run func(ctx context.Context, q ethereum.FilterQuery, ch chan<- types.Log)) *EthClientMock_SubscribeFilterLogs_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(ethereum.FilterQuery), args[2].(chan<- types.Log)) + }) + return _c +} + +func (_c *EthClientMock_SubscribeFilterLogs_Call) Return(_a0 ethereum.Subscription, _a1 error) *EthClientMock_SubscribeFilterLogs_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *EthClientMock_SubscribeFilterLogs_Call) RunAndReturn(run func(context.Context, ethereum.FilterQuery, chan<- types.Log) (ethereum.Subscription, error)) *EthClientMock_SubscribeFilterLogs_Call { + _c.Call.Return(run) + return _c +} + +// SuggestGasPrice provides a mock function with given fields: ctx +func (_m *EthClientMock) SuggestGasPrice(ctx context.Context) (*big.Int, error) { + ret := _m.Called(ctx) + + if len(ret) == 0 { + panic("no return value specified for SuggestGasPrice") + } + + var r0 *big.Int + var r1 error + if rf, ok := ret.Get(0).(func(context.Context) (*big.Int, error)); ok { + return rf(ctx) + } + if rf, ok := ret.Get(0).(func(context.Context) *big.Int); ok { + r0 = rf(ctx) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*big.Int) + } + } + + if rf, ok := ret.Get(1).(func(context.Context) error); ok { + r1 = rf(ctx) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// EthClientMock_SuggestGasPrice_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SuggestGasPrice' +type EthClientMock_SuggestGasPrice_Call struct { + *mock.Call +} + +// SuggestGasPrice is a helper method to define mock.On call +// - ctx context.Context +func (_e *EthClientMock_Expecter) SuggestGasPrice(ctx interface{}) *EthClientMock_SuggestGasPrice_Call { + return &EthClientMock_SuggestGasPrice_Call{Call: _e.mock.On("SuggestGasPrice", ctx)} +} + +func (_c *EthClientMock_SuggestGasPrice_Call) Run(run func(ctx context.Context)) *EthClientMock_SuggestGasPrice_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context)) + }) + return _c +} + +func (_c *EthClientMock_SuggestGasPrice_Call) Return(_a0 *big.Int, _a1 error) *EthClientMock_SuggestGasPrice_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *EthClientMock_SuggestGasPrice_Call) RunAndReturn(run func(context.Context) (*big.Int, error)) *EthClientMock_SuggestGasPrice_Call { + _c.Call.Return(run) + return _c +} + +// SuggestGasTipCap provides a mock function with given fields: ctx +func (_m *EthClientMock) SuggestGasTipCap(ctx context.Context) (*big.Int, error) { + ret := _m.Called(ctx) + + if len(ret) == 0 { + panic("no return value specified for SuggestGasTipCap") + } + + var r0 *big.Int + var r1 error + if rf, ok := ret.Get(0).(func(context.Context) (*big.Int, error)); ok { + return rf(ctx) + } + if rf, ok := ret.Get(0).(func(context.Context) *big.Int); ok { + r0 = rf(ctx) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*big.Int) + } + } + + if rf, ok := ret.Get(1).(func(context.Context) error); ok { + r1 = rf(ctx) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// EthClientMock_SuggestGasTipCap_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SuggestGasTipCap' +type EthClientMock_SuggestGasTipCap_Call struct { + *mock.Call +} + +// SuggestGasTipCap is a helper method to define mock.On call +// - ctx context.Context +func (_e *EthClientMock_Expecter) SuggestGasTipCap(ctx interface{}) *EthClientMock_SuggestGasTipCap_Call { + return &EthClientMock_SuggestGasTipCap_Call{Call: _e.mock.On("SuggestGasTipCap", ctx)} +} + +func (_c *EthClientMock_SuggestGasTipCap_Call) Run(run func(ctx context.Context)) *EthClientMock_SuggestGasTipCap_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context)) + }) + return _c +} + +func (_c *EthClientMock_SuggestGasTipCap_Call) Return(_a0 *big.Int, _a1 error) *EthClientMock_SuggestGasTipCap_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *EthClientMock_SuggestGasTipCap_Call) RunAndReturn(run func(context.Context) (*big.Int, error)) *EthClientMock_SuggestGasTipCap_Call { + _c.Call.Return(run) + return _c +} + +// TransactionReceipt provides a mock function with given fields: ctx, txHash +func (_m *EthClientMock) TransactionReceipt(ctx context.Context, txHash common.Hash) (*types.Receipt, error) { + ret := _m.Called(ctx, txHash) + + if len(ret) == 0 { + panic("no return value specified for TransactionReceipt") + } + + var r0 *types.Receipt + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, common.Hash) (*types.Receipt, error)); ok { + return rf(ctx, txHash) + } + if rf, ok := ret.Get(0).(func(context.Context, common.Hash) *types.Receipt); ok { + r0 = rf(ctx, txHash) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*types.Receipt) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, common.Hash) error); ok { + r1 = rf(ctx, txHash) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// EthClientMock_TransactionReceipt_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'TransactionReceipt' +type EthClientMock_TransactionReceipt_Call struct { + *mock.Call +} + +// TransactionReceipt is a helper method to define mock.On call +// - ctx context.Context +// - txHash common.Hash +func (_e *EthClientMock_Expecter) TransactionReceipt(ctx interface{}, txHash interface{}) *EthClientMock_TransactionReceipt_Call { + return &EthClientMock_TransactionReceipt_Call{Call: _e.mock.On("TransactionReceipt", ctx, txHash)} +} + +func (_c *EthClientMock_TransactionReceipt_Call) Run(run func(ctx context.Context, txHash common.Hash)) *EthClientMock_TransactionReceipt_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(common.Hash)) + }) + return _c +} + +func (_c *EthClientMock_TransactionReceipt_Call) Return(_a0 *types.Receipt, _a1 error) *EthClientMock_TransactionReceipt_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *EthClientMock_TransactionReceipt_Call) RunAndReturn(run func(context.Context, common.Hash) (*types.Receipt, error)) *EthClientMock_TransactionReceipt_Call { + _c.Call.Return(run) + return _c +} + +// NewEthClientMock creates a new instance of EthClientMock. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewEthClientMock(t interface { + mock.TestingT + Cleanup(func()) +}) *EthClientMock { + mock := &EthClientMock{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/proxy-router/internal/interfaces/rpc_multi.go b/proxy-router/internal/interfaces/rpc_multi.go new file mode 100644 index 00000000..d6ad8dc9 --- /dev/null +++ b/proxy-router/internal/interfaces/rpc_multi.go @@ -0,0 +1,8 @@ +package interfaces + +type RPCEndpoints interface { + GetURLs() []string + SetURLs(urls []string) error + SetURLsNoPersist(urls []string) error + RemoveURLs() error +} diff --git a/proxy-router/internal/lib/addr.go b/proxy-router/internal/lib/addr.go index 5d49f3df..4535decc 100644 --- a/proxy-router/internal/lib/addr.go +++ b/proxy-router/internal/lib/addr.go @@ -21,6 +21,15 @@ func AddrShort(addr string) string { return StrShortConf(addr, 5, 3) } +type Hexable interface { + Hex() string +} + +// Short returns a short representation of a Hexable in "0x123..567" format +func Short(s Hexable) string { + return StrShortConf(s.Hex(), 5, 3) +} + func RemoveHexPrefix(s string) string { if len(s) >= 2 && s[0:2] == "0x" { return s[2:] diff --git a/proxy-router/internal/lib/bool.go b/proxy-router/internal/lib/bool.go new file mode 100644 index 00000000..12f4618d --- /dev/null +++ b/proxy-router/internal/lib/bool.go @@ -0,0 +1,45 @@ +package lib + +import ( + "errors" + "strings" +) + +type Bool struct { + Bool *bool +} + +func (b *Bool) UnmarshalText(data []byte) error { + normalized := strings.ToLower(strings.TrimSpace(string(data))) + if normalized == "true" { + val := true + *b = Bool{Bool: &val} + return nil + } + + if normalized == "false" { + val := false + *b = Bool{Bool: &val} + return nil + } + + if normalized == "" { + *b = Bool{Bool: nil} + return nil + } + + return errors.New("invalid boolean value") +} + +func (b *Bool) String() string { + if b == nil { + return "nil" + } + if b.Bool == nil { + return "nil" + } + if *b.Bool { + return "true" + } + return "false" +} diff --git a/proxy-router/internal/lib/crypto.go b/proxy-router/internal/lib/crypto.go index 4361a41a..be1f6caf 100644 --- a/proxy-router/internal/lib/crypto.go +++ b/proxy-router/internal/lib/crypto.go @@ -151,3 +151,24 @@ func VerifySignature(params []byte, signature []byte, publicKeyBytes []byte) boo signatureNoRecoverID := signature[:len(signature)-1] // remove recovery ID return crypto.VerifySignature(publicKeyBytes, hash.Bytes(), signatureNoRecoverID) } + +func VerifySignatureAddr(params []byte, signature []byte, addr common.Address) bool { + hash := crypto.Keccak256Hash(params) + if len(signature) == 0 { + return false + } + // signature = signature[:len(signature)-1] // remove recovery ID + + recoveredPubKey, err := crypto.Ecrecover(hash.Bytes(), signature) + if err != nil { + return false + } + + pubKey, err := crypto.UnmarshalPubkey(recoveredPubKey) + if err != nil { + return false + } + + recoveredAddress := crypto.PubkeyToAddress(*pubKey) + return recoveredAddress == addr +} diff --git a/proxy-router/internal/lib/ethclient.go b/proxy-router/internal/lib/ethclient.go index 9128d660..7c4f4abb 100644 --- a/proxy-router/internal/lib/ethclient.go +++ b/proxy-router/internal/lib/ethclient.go @@ -1,12 +1,15 @@ package lib import ( - "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/contracts/lumerintoken" - "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/contracts/marketplace" - "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/contracts/modelregistry" - "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/contracts/morpheustoken" - "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/contracts/providerregistry" - "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/contracts/sessionrouter" + "fmt" + "reflect" + + "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/repositories/contracts/bindings/lumerintoken" + "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/repositories/contracts/bindings/marketplace" + "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/repositories/contracts/bindings/modelregistry" + "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/repositories/contracts/bindings/morpheustoken" + "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/repositories/contracts/bindings/providerregistry" + "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/repositories/contracts/bindings/sessionrouter" "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/common" ) @@ -31,11 +34,24 @@ type EVMError struct { } func (e EVMError) Error() string { - idBytes := e.Abi.ID.Bytes() - if len(idBytes) > 4 { - idBytes = idBytes[:4] + return fmt.Sprintf("EVM error: %s %+v", e.Abi.Sig, e.Args) +} + +// Implement As() method to check if EVMError can be converted to another type. +func (e EVMError) As(target interface{}) bool { + // Ensure that the target is a pointer. + if reflect.TypeOf(target).Kind() != reflect.Ptr { + // As target should be a pointer + return false + } + + switch v := target.(type) { + case *EVMError: + *v = e // Assign the concrete EVMError to the target + return true + default: + return false } - return "EVM error: " + e.Abi.Sig + " " + common.BytesToHash(idBytes).Hex() } // TryConvertGethError attempts to convert geth error to an EVMError, otherwise just returns original error diff --git a/proxy-router/internal/lib/hash.go b/proxy-router/internal/lib/hash.go index b2568fcc..f3c90070 100644 --- a/proxy-router/internal/lib/hash.go +++ b/proxy-router/internal/lib/hash.go @@ -1,6 +1,7 @@ package lib import ( + "crypto/rand" "encoding/hex" "errors" @@ -64,3 +65,10 @@ func HexToHash(s string) (common.Hash, error) { func has0xPrefix(str string) bool { return len(str) >= 2 && str[0] == '0' && (str[1] == 'x' || str[1] == 'X') } + +func GetRandomHash() (Hash, error) { + // generate random bytes + bytes := make([]byte, common.HashLength) + _, err := rand.Read(bytes) + return Hash{common.BytesToHash(bytes)}, err +} diff --git a/proxy-router/internal/lib/number.go b/proxy-router/internal/lib/number.go index 44d7fae6..ced5475d 100644 --- a/proxy-router/internal/lib/number.go +++ b/proxy-router/internal/lib/number.go @@ -32,3 +32,7 @@ func NewRat(numerator, denominator *big.Int) *big.Rat { bFloat := new(big.Rat).SetInt(denominator) return new(big.Rat).Quo(aFloat, bFloat) } + +func Exp10(exp int) *big.Int { + return big.NewInt(0).Exp(big.NewInt(10), big.NewInt(int64(exp)), nil) +} diff --git a/proxy-router/internal/proxyapi/capacity_manager.go b/proxy-router/internal/proxyapi/capacity_manager.go new file mode 100644 index 00000000..d27c23b2 --- /dev/null +++ b/proxy-router/internal/proxyapi/capacity_manager.go @@ -0,0 +1,113 @@ +package proxyapi + +import ( + "time" + + "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/config" + "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/lib" + "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/storages" +) + +type CapacityManagerInterface interface { + HasCapacity(modelID string) bool +} + +type SimpleCapacityManager struct { + storage *storages.SessionStorage + modelConfig *config.ModelConfig + log lib.ILogger +} + +func NewSimpleCapacityManager(modelConfig *config.ModelConfig, storage *storages.SessionStorage, log lib.ILogger) *SimpleCapacityManager { + return &SimpleCapacityManager{ + storage: storage, + modelConfig: modelConfig, + log: log, + } +} + +func (scm *SimpleCapacityManager) HasCapacity(modelID string) bool { + if scm.modelConfig.ConcurrentSlots == 0 { + return true + } + + sessions, err := scm.storage.GetSessionsForModel(modelID) + if err != nil { + scm.log.Error(err) + return false + } + + activeSessions := 0 + for _, session := range sessions { + s, ok := scm.storage.GetSession(session) + if !ok { + continue + } + if s.EndsAt.Int64() > time.Now().Unix() { + activeSessions++ + } + } + + return activeSessions < scm.modelConfig.ConcurrentSlots +} + +type IdleTimeoutCapacityManager struct { + storage *storages.SessionStorage + modelConfig *config.ModelConfig + log lib.ILogger +} + +func NewIdleTimeoutCapacityManager(modelConfig *config.ModelConfig, storage *storages.SessionStorage, log lib.ILogger) *IdleTimeoutCapacityManager { + return &IdleTimeoutCapacityManager{ + storage: storage, + modelConfig: modelConfig, + log: log, + } +} + +func (idcm *IdleTimeoutCapacityManager) HasCapacity(modelID string) bool { + IDLE_TIMEOUT := 15 * 60 // 15 min + + if idcm.modelConfig.ConcurrentSlots == 0 { + return true + } + + activities, err := idcm.storage.GetActivities(modelID) + if err != nil { + idcm.log.Error(err) + return false + } + + activeSessions := 0 + for _, activity := range activities { + session, ok := idcm.storage.GetSession(activity.SessionID) + if !ok { + continue + } + if session.EndsAt.Int64() < time.Now().Unix() { + continue + } + if activity.EndTime > time.Now().Unix()-int64(IDLE_TIMEOUT) { + activeSessions++ + } + } + + REMOTE_IDLE_TIMEOUT := 60 * 60 // 60 min + err = idcm.storage.RemoveOldActivities(modelID, time.Now().Unix()-int64(REMOTE_IDLE_TIMEOUT)) + if err != nil { + idcm.log.Warnf("Failed to remove old activities: %s", err) + } + + return activeSessions < idcm.modelConfig.ConcurrentSlots +} + +func CreateCapacityManager(modelConfig *config.ModelConfig, storage *storages.SessionStorage, log lib.ILogger) CapacityManagerInterface { + switch modelConfig.CapacityPolicy { + case "simple": + return NewSimpleCapacityManager(modelConfig, storage, log) + case "idle_timeout": + return NewIdleTimeoutCapacityManager(modelConfig, storage, log) + default: + return NewSimpleCapacityManager(modelConfig, storage, log) + } +} diff --git a/proxy-router/internal/proxyapi/chat_storage.go b/proxy-router/internal/proxyapi/chat_storage.go deleted file mode 100644 index 7c2c442d..00000000 --- a/proxy-router/internal/proxyapi/chat_storage.go +++ /dev/null @@ -1,107 +0,0 @@ -package proxyapi - -import ( - "encoding/json" - "fmt" - "os" - "path/filepath" - "sync" - "time" - - "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/aiengine" - "github.com/sashabaranov/go-openai" -) - -// ChatStorage handles storing conversations to files. -type ChatStorage struct { - dirPath string // Directory path to store the files - fileMutexes map[string]*sync.Mutex // Map to store mutexes for each file -} - -// NewChatStorage creates a new instance of ChatStorage. -func NewChatStorage(dirPath string) *ChatStorage { - return &ChatStorage{ - dirPath: dirPath, - fileMutexes: make(map[string]*sync.Mutex), - } -} - -// StorePromptResponseToFile stores the prompt and response to a file. -func (cs *ChatStorage) StorePromptResponseToFile(identifier string, isSession bool, prompt interface{}, responses []interface{}, promptAt, responseAt time.Time) error { - var dir string - if isSession { - dir = "sessions" - } else { - dir = "models" - } - - path := filepath.Join(cs.dirPath, dir) - if err := os.MkdirAll(path, os.ModePerm); err != nil { - return err - } - - filePath := filepath.Join(path, identifier+".json") - cs.initFileMutex(filePath) - - // Lock the file mutex - cs.fileMutexes[filePath].Lock() - defer cs.fileMutexes[filePath].Unlock() - - var data []map[string]interface{} - if _, err := os.Stat(filePath); err == nil { - fileContent, err := os.ReadFile(filePath) - if err != nil { - return err - } - if err := json.Unmarshal(fileContent, &data); err != nil { - return err - } - } - - response := "" - for _, r := range responses { - switch v := r.(type) { - case ChatCompletionResponse: - response += fmt.Sprintf("%v", v.Choices[0].Delta.Content) - case *openai.ChatCompletionStreamResponse: - response += fmt.Sprintf("%v", v.Choices[0].Delta.Content) - case aiengine.ProdiaGenerationResult: - response += fmt.Sprintf("%v", v.ImageUrl) - case *aiengine.ProdiaGenerationResult: - response += fmt.Sprintf("%v", v.ImageUrl) - default: - return fmt.Errorf("unknown response type") - } - } - - switch p := prompt.(type) { - case *aiengine.ProdiaGenerationRequest: - p.ApiKey = "REDACTED" - } - - newEntry := map[string]interface{}{ - "prompt": prompt, - "response": response, - "promptAt": promptAt.UnixMilli(), - "responseAt": responseAt.UnixMilli(), - } - - data = append(data, newEntry) - updatedContent, err := json.MarshalIndent(data, "", " ") - if err != nil { - return err - } - - if err := os.WriteFile(filePath, updatedContent, 0644); err != nil { - return err - } - - return nil -} - -// initFileMutex initializes a mutex for the file if not already present. -func (cs *ChatStorage) initFileMutex(filePath string) { - if _, exists := cs.fileMutexes[filePath]; !exists { - cs.fileMutexes[filePath] = &sync.Mutex{} - } -} diff --git a/proxy-router/internal/proxyapi/controller_http.go b/proxy-router/internal/proxyapi/controller_http.go index 3d1e38a4..3516008e 100644 --- a/proxy-router/internal/proxyapi/controller_http.go +++ b/proxy-router/internal/proxyapi/controller_http.go @@ -1,39 +1,83 @@ package proxyapi import ( + "context" "encoding/json" "fmt" "net/http" - "time" constants "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal" "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/aiengine" + "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/blockchainapi/structs" + "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/chatstorage/genericchatstorage" "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/interfaces" "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/lib" + "github.com/ethereum/go-ethereum/common" "github.com/gin-gonic/gin" "github.com/sashabaranov/go-openai" ) +type AIEngine interface { + GetLocalModels() ([]aiengine.LocalModel, error) + GetAdapter(ctx context.Context, chatID, modelID, sessionID common.Hash, storeContext, forwardContext bool) (aiengine.AIEngineStream, error) +} + type ProxyController struct { - service *ProxyServiceSender - aiEngine *aiengine.AiEngine - chatStorage *ChatStorage + service *ProxyServiceSender + aiEngine AIEngine + chatStorage genericchatstorage.ChatStorageInterface + storeChatContext bool + forwardChatContext bool + log lib.ILogger } -func NewProxyController(service *ProxyServiceSender, aiEngine *aiengine.AiEngine, chatStorage *ChatStorage) *ProxyController { +func NewProxyController(service *ProxyServiceSender, aiEngine AIEngine, chatStorage genericchatstorage.ChatStorageInterface, storeChatContext, forwardChatContext bool, log lib.ILogger) *ProxyController { c := &ProxyController{ - service: service, - aiEngine: aiEngine, - chatStorage: chatStorage, + service: service, + aiEngine: aiEngine, + chatStorage: chatStorage, + storeChatContext: storeChatContext, + forwardChatContext: forwardChatContext, + log: log, } return c } func (s *ProxyController) RegisterRoutes(r interfaces.Router) { + r.POST("/proxy/provider/ping", s.Ping) r.POST("/proxy/sessions/initiate", s.InitiateSession) r.POST("/v1/chat/completions", s.Prompt) r.GET("/v1/models", s.Models) + r.GET("/v1/chats", s.GetChats) + r.GET("/v1/chats/:id", s.GetChat) + r.DELETE("/v1/chats/:id", s.DeleteChat) + r.POST("/v1/chats/:id", s.UpdateChatTitle) +} + +// Ping godoc +// +// @Summary Ping Provider +// @Description sends a ping to the provider on the RPC level +// @Tags chat +// @Produce json +// @Param pingReq body proxyapi.PingReq true "Ping Request" +// @Success 200 {object} proxyapi.PingRes +// @Router /proxy/provider/ping [post] +func (s *ProxyController) Ping(ctx *gin.Context) { + var req *PingReq + if err := ctx.ShouldBindJSON(&req); err != nil { + ctx.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) + return + } + + ping, err := s.service.Ping(ctx, req.ProviderURL, req.ProviderAddr) + if err != nil { + ctx.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + return + } + + ctx.JSON(http.StatusOK, &PingRes{PingMs: ping.Milliseconds()}) } // InitiateSession godoc @@ -68,17 +112,17 @@ func (s *ProxyController) InitiateSession(ctx *gin.Context) { // @Description Send prompt to a local or remote model based on session id in header // @Tags chat // @Produce text/event-stream -// @Param session_id header string false "Session ID" format(hex32) -// @Param model_id header string false "Model ID" format(hex32) -// @Param prompt body proxyapi.OpenAiCompletitionRequest true "Prompt" -// @Success 200 {object} proxyapi.ChatCompletionResponse +// @Param session_id header string false "Session ID" format(hex32) +// @Param model_id header string false "Model ID" format(hex32) +// @Param chat_id header string false "Chat ID" format(hex32) +// @Param prompt body proxyapi.ChatCompletionRequestSwaggerExample true "Prompt" +// @Success 200 {object} string // @Router /v1/chat/completions [post] func (c *ProxyController) Prompt(ctx *gin.Context) { var ( body openai.ChatCompletionRequest head PromptHead ) - var responses []interface{} if err := ctx.ShouldBindHeader(&head); err != nil { ctx.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) @@ -89,66 +133,57 @@ func (c *ProxyController) Prompt(ctx *gin.Context) { return } - // Record the prompt time - promptAt := time.Now() + chatID := head.ChatID + if chatID == (lib.Hash{}) { + var err error + chatID, err = lib.GetRandomHash() + if err != nil { + ctx.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + return + } + } - if (head.SessionID == lib.Hash{}) { - body.Stream = ctx.GetHeader(constants.HEADER_ACCEPT) == constants.CONTENT_TYPE_JSON - modelId := head.ModelID.Hex() + adapter, err := c.aiEngine.GetAdapter(ctx, chatID.Hash, head.ModelID.Hash, head.SessionID.Hash, c.storeChatContext, c.forwardChatContext) + if err != nil { + ctx.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + return + } - prompt, t := c.GetBodyForLocalPrompt(modelId, &body) - responseAt := time.Now() + var contentType string + if body.Stream { + contentType = constants.CONTENT_TYPE_EVENT_STREAM + } else { + contentType = constants.CONTENT_TYPE_JSON + } - if t == "openai" { - res, _ := c.aiEngine.PromptCb(ctx, &body) - responses = res.([]interface{}) - if err := c.chatStorage.StorePromptResponseToFile(modelId, false, prompt, responses, promptAt, responseAt); err != nil { - fmt.Println("Error storing prompt and responses:", err) - } + ctx.Writer.Header().Set(constants.HEADER_CONTENT_TYPE, contentType) + + err = adapter.Prompt(ctx, &body, func(cbctx context.Context, completion genericchatstorage.Chunk) error { + marshalledResponse, err := json.Marshal(completion.Data()) + if err != nil { + return err } - if t == "prodia" { - var prodiaResponses []interface{} - c.aiEngine.PromptProdiaImage(ctx, prompt.(*aiengine.ProdiaGenerationRequest), func(completion interface{}) error { - ctx.Writer.Header().Set(constants.HEADER_CONTENT_TYPE, constants.CONTENT_TYPE_EVENT_STREAM) - marshalledResponse, err := json.Marshal(completion) - if err != nil { - return err - } - _, err = ctx.Writer.Write([]byte(fmt.Sprintf("data: %s\n\n", marshalledResponse))) - if err != nil { - return err - } - ctx.Writer.Flush() - - prodiaResponses = append(prodiaResponses, completion) - if err := c.chatStorage.StorePromptResponseToFile(modelId, false, prompt, prodiaResponses, promptAt, responseAt); err != nil { - fmt.Println("Error storing prompt and responses:", err) - } - return nil - }) + + _, err = ctx.Writer.Write([]byte(fmt.Sprintf("data: %s\n\n", marshalledResponse))) + if err != nil { + return err } - return - } - res, err := c.service.SendPrompt(ctx, ctx.Writer, &body, head.SessionID.Hash) + ctx.Writer.Flush() + return nil + }) + if err != nil { + c.log.Errorf("error sending prompt: %s", err) ctx.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) return } - - responses = res.([]interface{}) - responseAt := time.Now() - sessionIdStr := head.SessionID.Hex() - if err := c.chatStorage.StorePromptResponseToFile(sessionIdStr, true, body, responses, promptAt, responseAt); err != nil { - fmt.Println("Error storing prompt and responses:", err) - } - return } // GetLocalModels godoc // // @Summary Get local models -// @Tags chat +// @Tags system // @Produce json // @Success 200 {object} []aiengine.LocalModel // @Router /v1/models [get] @@ -161,35 +196,101 @@ func (c *ProxyController) Models(ctx *gin.Context) { ctx.JSON(http.StatusOK, models) } -func (c *ProxyController) GetBodyForLocalPrompt(modelId string, req *openai.ChatCompletionRequest) (interface{}, string) { - if modelId == "" { - req.Model = "llama2" - return req, "openai" +// GetChats godoc +// +// @Summary Get all chats stored in the system +// @Tags chat +// @Produce json +// @Success 200 {object} []genericchatstorage.Chat +// @Router /v1/chats [get] +func (c *ProxyController) GetChats(ctx *gin.Context) { + chats := c.chatStorage.GetChats() + + if chats == nil { + ctx.JSON(http.StatusOK, make([]struct{}, 0)) + return } - ids, models := c.aiEngine.GetModelsConfig() + ctx.JSON(http.StatusOK, chats) +} - for i, model := range models { - if ids[i] == modelId { - if model.ApiType == "openai" { - req.Model = model.ModelName - return req, model.ApiType - } +// GetChat godoc +// +// @Summary Get chat by id +// @Tags chat +// @Produce json +// @Param id path string true "Chat ID" +// @Success 200 {object} genericchatstorage.ChatHistory +// @Router /v1/chats/{id} [get] +func (c *ProxyController) GetChat(ctx *gin.Context) { + var params structs.PathHex32ID + err := ctx.ShouldBindUri(¶ms) + if err != nil { + ctx.JSON(http.StatusBadRequest, structs.ErrRes{Error: err.Error()}) + return + } - if model.ApiType == "prodia" { - prompt := &aiengine.ProdiaGenerationRequest{ - Model: model.ModelName, - Prompt: req.Messages[0].Content, - ApiUrl: model.ApiURL, - ApiKey: model.ApiKey, - } - return prompt, model.ApiType - } + chat, err := c.chatStorage.LoadChatFromFile(params.ID.Hex()) + if err != nil { + ctx.JSON(http.StatusInternalServerError, structs.ErrRes{Error: err.Error()}) + return + } + ctx.JSON(http.StatusOK, chat) +} - return req, "openai" - } +// DeleteChat godoc +// +// @Summary Delete chat by id from storage +// @Tags chat +// @Produce json +// @Param id path string true "Chat ID" +// @Success 200 {object} proxyapi.ResultResponse +// @Router /v1/chats/{id} [delete] +func (c *ProxyController) DeleteChat(ctx *gin.Context) { + var params structs.PathHex32ID + err := ctx.ShouldBindUri(¶ms) + if err != nil { + ctx.JSON(http.StatusBadRequest, structs.ErrRes{Error: err.Error()}) + return + } + + err = c.chatStorage.DeleteChat(params.ID.Hex()) + if err != nil { + ctx.JSON(http.StatusInternalServerError, structs.ErrRes{Error: err.Error()}) + return + } + ctx.JSON(http.StatusOK, gin.H{"result": true}) +} + +// UpdateChatTitle godoc +// +// @Summary Update chat title by id +// @Tags chat +// @Produce json +// @Param id path string true "Chat ID" +// @Param title body proxyapi.UpdateChatTitleReq true "Chat Title" +// @Success 200 {object} proxyapi.ResultResponse +// @Router /v1/chats/{id} [post] +func (c *ProxyController) UpdateChatTitle(ctx *gin.Context) { + var params structs.PathHex32ID + err := ctx.ShouldBindUri(¶ms) + if err != nil { + ctx.JSON(http.StatusBadRequest, structs.ErrRes{Error: err.Error()}) + return } - req.Model = "llama2" - return req, "openai" + var req UpdateChatTitleReq + err = ctx.ShouldBindJSON(&req) + if err != nil { + c.service.log.Errorf("error binding json: %s", err) + ctx.JSON(http.StatusBadRequest, structs.ErrRes{Error: err.Error()}) + return + } + + err = c.chatStorage.UpdateChatTitle(params.ID.Hex(), req.Title) + if err != nil { + ctx.JSON(http.StatusInternalServerError, structs.ErrRes{Error: err.Error()}) + return + } + ctx.JSON(http.StatusOK, gin.H{"result": true}) } diff --git a/proxy-router/internal/proxyapi/controller_morrpc.go b/proxy-router/internal/proxyapi/controller_morrpc.go index 81b3454f..c2e947e6 100644 --- a/proxy-router/internal/proxyapi/controller_morrpc.go +++ b/proxy-router/internal/proxyapi/controller_morrpc.go @@ -9,15 +9,18 @@ import ( "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/lib" m "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/proxyapi/morrpcmessage" msg "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/proxyapi/morrpcmessage" + sessionrepo "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/repositories/session" "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/storages" "github.com/go-playground/validator/v10" ) type MORRPCController struct { service *ProxyReceiver + sessionRepo *sessionrepo.SessionRepositoryCached validator *validator.Validate sessionStorage *storages.SessionStorage morRpc *m.MORRPCMessage + prKey lib.HexString } type SendResponse func(*msg.RpcResponse) error @@ -26,19 +29,24 @@ var ( ErrUnknownMethod = fmt.Errorf("unknown method") ) -func NewMORRPCController(service *ProxyReceiver, validator *validator.Validate, sessionStorage *storages.SessionStorage) *MORRPCController { +func NewMORRPCController(service *ProxyReceiver, validator *validator.Validate, sessionRepo *sessionrepo.SessionRepositoryCached, sessionStorage *storages.SessionStorage, prKey lib.HexString) *MORRPCController { c := &MORRPCController{ service: service, validator: validator, sessionStorage: sessionStorage, + sessionRepo: sessionRepo, morRpc: m.NewMorRpc(), + prKey: prKey, } return c } func (s *MORRPCController) Handle(ctx context.Context, msg m.RPCMessage, sourceLog lib.ILogger, sendResponse SendResponse) error { + sourceLog.Debugf("received TCP message with method %s", msg.Method) switch msg.Method { + case "network.ping": + return s.networkPing(ctx, msg, sendResponse, sourceLog) case "session.request": return s.sessionRequest(ctx, msg, sendResponse, sourceLog) case "session.prompt": @@ -56,6 +64,26 @@ var ( ErrGenerateReport = fmt.Errorf("failed to generate report") ) +func (s *MORRPCController) networkPing(_ context.Context, msg m.RPCMessage, sendResponse SendResponse, sourceLog lib.ILogger) error { + var req m.PingReq + err := json.Unmarshal(msg.Params, &req) + if err != nil { + return lib.WrapError(ErrUnmarshal, err) + } + + if err := s.validator.Struct(req); err != nil { + return lib.WrapError(ErrValidation, err) + } + + res, err := s.morRpc.PongResponce(msg.ID, s.prKey, req.Nonce) + if err != nil { + sourceLog.Error(err) + return err + } + + return sendResponse(res) +} + func (s *MORRPCController) sessionRequest(ctx context.Context, msg m.RPCMessage, sendResponse SendResponse, sourceLog lib.ILogger) error { var req m.SessionReq err := json.Unmarshal(msg.Params, &req) @@ -88,42 +116,32 @@ func (s *MORRPCController) sessionPrompt(ctx context.Context, msg m.RPCMessage, var req m.SessionPromptReq err := json.Unmarshal(msg.Params, &req) if err != nil { - err := lib.WrapError(ErrUnmarshal, err) - sourceLog.Error(err) - return err + return lib.WrapError(ErrUnmarshal, err) } if err := s.validator.Struct(req); err != nil { - err := lib.WrapError(ErrValidation, err) - sourceLog.Error(err) - return err + return lib.WrapError(ErrValidation, err) } - sourceLog.Debugf("Received prompt from session %s, timestamp: %s", req.SessionID, req.Timestamp) - session, ok := s.sessionStorage.GetSession(req.SessionID.Hex()) - if !ok { - err := fmt.Errorf("session not found") - sourceLog.Error(err) - return err + sourceLog.Debugf("received prompt from session %s, timestamp: %d", req.SessionID, req.Timestamp) + session, err := s.sessionRepo.GetSession(ctx, req.SessionID) + if err != nil { + return fmt.Errorf("session cannot be loaded %s", err) } - isSessionExpired := session.EndsAt.Uint64()*1000 < req.Timestamp + isSessionExpired := session.EndsAt().Uint64()*1000 < req.Timestamp if isSessionExpired { - err := fmt.Errorf("session expired") - sourceLog.Error(err) - return err + return fmt.Errorf("session expired") } - user, ok := s.sessionStorage.GetUser(session.UserAddr) + user, ok := s.sessionStorage.GetUser(session.UserAddr().Hex()) if !ok { - err := fmt.Errorf("user not found") - sourceLog.Error(err) - return err + return fmt.Errorf("user not found") } + pubKeyHex, err := lib.StringToHexString(user.PubKey) if err != nil { - sourceLog.Error(err) - return err + return fmt.Errorf("invalid pubkey %s", err) } sig := req.Signature @@ -144,14 +162,18 @@ func (s *MORRPCController) sessionPrompt(ctx context.Context, msg m.RPCMessage, } requestDuration := int(time.Now().Unix() - now) - session.TTFTMsArr = append(session.TTFTMsArr, ttftMs) - session.TPSScaled1000Arr = append(session.TPSScaled1000Arr, totalTokens*1000/requestDuration) - err = s.sessionStorage.AddSession(session) + if requestDuration == 0 { + requestDuration = 1 + } + + tpsScaled1000 := totalTokens * 1000 / requestDuration + session.AddStats(tpsScaled1000, ttftMs) + + err = s.sessionRepo.SaveSession(ctx, session) if err != nil { - sourceLog.Error(err) - return err + return fmt.Errorf("failed to save session %s", err) } - return err + return nil } func (s *MORRPCController) sessionReport(ctx context.Context, msg m.RPCMessage, sendResponse SendResponse, sourceLog lib.ILogger) error { diff --git a/proxy-router/internal/proxyapi/interfaces.go b/proxy-router/internal/proxyapi/interfaces.go index b57ec1a5..3a7ded26 100644 --- a/proxy-router/internal/proxyapi/interfaces.go +++ b/proxy-router/internal/proxyapi/interfaces.go @@ -1,8 +1,24 @@ package proxyapi -import "net/http" +import ( + "context" + "math/big" + "net/http" + + "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/blockchainapi/structs" + "github.com/ethereum/go-ethereum/common" +) type ResponderFlusher interface { http.ResponseWriter http.Flusher } + +type BidGetter interface { + GetBidByID(ctx context.Context, ID common.Hash) (*structs.Bid, error) +} + +type SessionService interface { + OpenSessionByModelId(ctx context.Context, modelID common.Hash, duration *big.Int, isDirectPayment, isFailoverEnabled bool, omitProvider common.Address) (common.Hash, error) + CloseSession(ctx context.Context, sessionID common.Hash) (common.Hash, error) +} diff --git a/proxy-router/internal/proxyapi/morrpcmessage/mor_rpc.go b/proxy-router/internal/proxyapi/morrpcmessage/mor_rpc.go index ab804ff1..3bbf3a5b 100644 --- a/proxy-router/internal/proxyapi/morrpcmessage/mor_rpc.go +++ b/proxy-router/internal/proxyapi/morrpcmessage/mor_rpc.go @@ -2,7 +2,6 @@ package morrpcmesssage import ( "encoding/json" - "fmt" "math/big" "time" @@ -19,6 +18,30 @@ func NewMorRpc() *MORRPCMessage { // RESPONSES +func (m *MORRPCMessage) PongResponce(requestId string, providerPrKey lib.HexString, nonce lib.HexString) (*RpcResponse, error) { + params := PongRes{ + Nonce: nonce, + } + signature, err := m.generateSignature(params, providerPrKey) + if err != nil { + return &RpcResponse{}, err + } + + params.Signature = signature + + paramsBytes, err := json.Marshal(params) + if err != nil { + return &RpcResponse{}, err + } + + paramsJSON := json.RawMessage(paramsBytes) + + return &RpcResponse{ + ID: requestId, + Result: ¶msJSON, + }, nil +} + func (m *MORRPCMessage) InitiateSessionResponse(providerPubKey lib.HexString, userAddr common.Address, bidID common.Hash, providerPrivateKeyHex lib.HexString, requestID string, chainID *big.Int) (*RpcResponse, error) { timestamp := m.generateTimestamp() @@ -59,7 +82,7 @@ func (m *MORRPCMessage) InitiateSessionResponse(providerPubKey lib.HexString, us }, nil } -func (m *MORRPCMessage) SessionReportResponse(providerPubKey lib.HexString, tps uint32, ttfp uint32, sessionID common.Hash, providerPrivateKeyHex lib.HexString, requestID string, chainID *big.Int) (*RpcResponse, error) { +func (m *MORRPCMessage) SessionReportResponse(tps uint32, ttfp uint32, sessionID common.Hash, providerPrivateKeyHex lib.HexString, requestID string, chainID *big.Int) (*RpcResponse, error) { timestamp := m.generateTimestamp() report, err := lib.EncodeAbiParameters(sessionReportAbi, []interface{}{sessionID, chainID, big.NewInt(int64(timestamp)), tps, ttfp}) @@ -196,6 +219,28 @@ func (m *MORRPCMessage) SpendLimitError(privateKeyHex lib.HexString, requestId s // REQUESTS +func (m *MORRPCMessage) PingRequest(requestId string, userPrivateKeyHex lib.HexString, nonce lib.HexString) (*RPCMessage, error) { + params := PingReq{ + Nonce: nonce, + } + signature, err := m.generateSignature(params, userPrivateKeyHex) + if err != nil { + return &RPCMessage{}, err + } + params.Signature = signature + + serializedParams, err := json.Marshal(params) + if err != nil { + return &RPCMessage{}, err + } + + return &RPCMessage{ + ID: requestId, + Method: "network.ping", + Params: serializedParams, + }, nil +} + func (m *MORRPCMessage) InitiateSessionRequest(user common.Address, provider common.Address, spend *big.Int, bidID common.Hash, userPrivateKeyHex lib.HexString, requestId string) (*RPCMessage, error) { method := "session.request" pbKey, err := lib.PubKeyFromPrivate(userPrivateKeyHex) @@ -283,7 +328,6 @@ func (m *MORRPCMessage) SessionReportRequest(sessionID common.Hash, userPrivateK func (m *MORRPCMessage) VerifySignature(params any, signature lib.HexString, publicKey lib.HexString, sourceLog lib.ILogger) bool { paramsBytes, err := json.Marshal(params) - fmt.Println("\n\nOUTPUT: ", string(paramsBytes)) if err != nil { sourceLog.Error("Error marshalling params", err) return false @@ -292,6 +336,16 @@ func (m *MORRPCMessage) VerifySignature(params any, signature lib.HexString, pub return lib.VerifySignature(paramsBytes, signature, publicKey) } +func (m *MORRPCMessage) VerifySignatureAddr(params any, signature lib.HexString, addr common.Address, sourceLog lib.ILogger) bool { + paramsBytes, err := json.Marshal(params) + if err != nil { + sourceLog.Error("Error marshalling params", err) + return false + } + + return lib.VerifySignatureAddr(paramsBytes, signature, addr) +} + func (m *MORRPCMessage) generateTimestamp() uint64 { now := time.Now() return uint64(now.UnixMilli()) @@ -312,5 +366,6 @@ func (m *MORRPCMessage) generateSignature(params any, privateKeyHex lib.HexStrin if err != nil { return nil, err } + return signature, nil } diff --git a/proxy-router/internal/proxyapi/morrpcmessage/request.go b/proxy-router/internal/proxyapi/morrpcmessage/request.go index 46e6f289..95f01619 100644 --- a/proxy-router/internal/proxyapi/morrpcmessage/request.go +++ b/proxy-router/internal/proxyapi/morrpcmessage/request.go @@ -96,3 +96,13 @@ type ReqObject struct { Res uint `json:"res"` Toks uint `json:"toks"` } + +type PingReq struct { + Nonce lib.HexString `json:"nonce" validate:"required,hexadecimal"` + Signature lib.HexString `json:"signature" validate:"required,hexadecimal"` +} + +type PongRes struct { + Nonce lib.HexString `json:"nonce" validate:"required,hexadecimal"` + Signature lib.HexString `json:"signature" validate:"required,hexadecimal"` +} diff --git a/proxy-router/internal/proxyapi/proxy_receiver.go b/proxy-router/internal/proxyapi/proxy_receiver.go index 11182487..43272750 100644 --- a/proxy-router/internal/proxyapi/proxy_receiver.go +++ b/proxy-router/internal/proxyapi/proxy_receiver.go @@ -8,10 +8,12 @@ import ( "time" "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/aiengine" + "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/chatstorage/genericchatstorage" "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/config" "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/lib" m "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/proxyapi/morrpcmessage" msg "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/proxyapi/morrpcmessage" + sessionrepo "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/repositories/session" "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/storages" "github.com/ethereum/go-ethereum/common" "github.com/sashabaranov/go-openai" @@ -25,17 +27,21 @@ type ProxyReceiver struct { sessionStorage *storages.SessionStorage aiEngine *aiengine.AiEngine modelConfigLoader *config.ModelConfigLoader + service BidGetter + sessionRepo *sessionrepo.SessionRepositoryCached } -func NewProxyReceiver(privateKeyHex, publicKeyHex lib.HexString, sessionStorage *storages.SessionStorage, aiEngine *aiengine.AiEngine, chainID *big.Int, modelConfigLoader *config.ModelConfigLoader) *ProxyReceiver { +func NewProxyReceiver(privateKeyHex, publicKeyHex lib.HexString, sessionStorage *storages.SessionStorage, aiEngine *aiengine.AiEngine, chainID *big.Int, modelConfigLoader *config.ModelConfigLoader, blockchainService BidGetter, sessionRepo *sessionrepo.SessionRepositoryCached) *ProxyReceiver { return &ProxyReceiver{ privateKeyHex: privateKeyHex, publicKeyHex: publicKeyHex, morRpc: m.NewMorRpc(), - sessionStorage: sessionStorage, aiEngine: aiEngine, chainID: chainID, modelConfigLoader: modelConfigLoader, + service: blockchainService, + sessionStorage: sessionStorage, + sessionRepo: sessionRepo, } } @@ -49,8 +55,8 @@ func (s *ProxyReceiver) SessionPrompt(ctx context.Context, requestID string, use return 0, 0, err } - session, ok := s.sessionStorage.GetSession(rq.SessionID.Hex()) - if !ok { + session, err := s.sessionRepo.GetSession(ctx, rq.SessionID) + if err != nil { err := lib.WrapError(fmt.Errorf("failed to get session"), err) sourceLog.Error(err) return 0, 0, err @@ -60,24 +66,21 @@ func (s *ProxyReceiver) SessionPrompt(ctx context.Context, requestID string, use totalTokens := 0 now := time.Now().UnixMilli() - responseCb := func(response interface{}) error { - openAiResponse, ok := response.(*openai.ChatCompletionStreamResponse) - if ok { - totalTokens += len(openAiResponse.Choices) - } else { - _, ok := response.(*aiengine.ProdiaGenerationResult) - if ok { - totalTokens += 1 - } else { - return fmt.Errorf("unknown response type") - } - } + adapter, err := s.aiEngine.GetAdapter(ctx, common.Hash{}, session.ModelID(), common.Hash{}, false, false) + if err != nil { + err := lib.WrapError(fmt.Errorf("failed to get adapter"), err) + sourceLog.Error(err) + return 0, 0, err + } + + err = adapter.Prompt(ctx, req, func(ctx context.Context, completion genericchatstorage.Chunk) error { + totalTokens += completion.Tokens() if ttftMs == 0 { ttftMs = int(time.Now().UnixMilli() - now) } - marshalledResponse, err := json.Marshal(response) + marshalledResponse, err := json.Marshal(completion.Data()) if err != nil { return err } @@ -99,41 +102,44 @@ func (s *ProxyReceiver) SessionPrompt(ctx context.Context, requestID string, use return err } return sendResponse(r) - } - - if session.ModelApiType == "prodia" { - modelConfig := s.modelConfigLoader.ModelConfigFromID(session.ModelID) - prodiaReq := &aiengine.ProdiaGenerationRequest{ - Prompt: req.Messages[0].Content, - Model: session.ModelName, - ApiUrl: modelConfig.ApiURL, - ApiKey: modelConfig.ApiKey, - } - - err = s.aiEngine.PromptProdiaImage(ctx, prodiaReq, responseCb) - } else { - req.Model = session.ModelName - if req.Model == "" { - req.Model = "llama2" - } - _, err = s.aiEngine.PromptStream(ctx, req, responseCb) - } - + }) if err != nil { err := lib.WrapError(fmt.Errorf("failed to prompt"), err) sourceLog.Error(err) return 0, 0, err } + + activity := storages.PromptActivity{ + SessionID: session.ID().Hex(), + StartTime: now, + EndTime: time.Now().Unix(), + } + err = s.sessionStorage.AddActivity(session.ModelID().Hex(), &activity) + if err != nil { + sourceLog.Warnf("failed to store activity: %s", err) + } + return ttftMs, totalTokens, nil } -func (s *ProxyReceiver) SessionRequest(ctx context.Context, msgID string, reqID string, req *m.SessionReq, sourceLog lib.ILogger) (*msg.RpcResponse, error) { - sourceLog.Debugf("Received session request from %s, timestamp: %s", req.User, req.Timestamp) +func (s *ProxyReceiver) SessionRequest(ctx context.Context, msgID string, reqID string, req *m.SessionReq, log lib.ILogger) (*msg.RpcResponse, error) { + log.Debugf("Received session request from %s, timestamp: %s", req.User, req.Timestamp) - hasCapacity := true // check if there is capacity + bid, err := s.service.GetBidByID(ctx, req.BidID) + if err != nil { + err := lib.WrapError(fmt.Errorf("failed to get bid"), err) + log.Error(err) + return nil, err + } + + modelID := bid.ModelAgentId.String() + modelConfig := s.modelConfigLoader.ModelConfigFromID(modelID) + capacityManager := CreateCapacityManager(modelConfig, s.sessionStorage, log) + + hasCapacity := capacityManager.HasCapacity(modelID) if !hasCapacity { err := fmt.Errorf("no capacity") - sourceLog.Error(err) + log.Error(err) return nil, err } @@ -148,7 +154,7 @@ func (s *ProxyReceiver) SessionRequest(ctx context.Context, msgID string, reqID ) if err != nil { err := lib.WrapError(fmt.Errorf("failed to create response"), err) - sourceLog.Error(err) + log.Error(err) return nil, err } @@ -160,14 +166,15 @@ func (s *ProxyReceiver) SessionRequest(ctx context.Context, msgID string, reqID err = s.sessionStorage.AddUser(&user) if err != nil { err := lib.WrapError(fmt.Errorf("failed store user"), err) - sourceLog.Error(err) + log.Error(err) return nil, err } + return response, nil } func (s *ProxyReceiver) SessionReport(ctx context.Context, msgID string, reqID string, session *storages.Session, sourceLog lib.ILogger) (*msg.RpcResponse, error) { - sourceLog.Debugf("Received session report request for %s, timestamp: %s", session.Id) + sourceLog.Debugf("received session report request for %s", session.Id) tps := 0 ttft := 0 @@ -186,7 +193,6 @@ func (s *ProxyReceiver) SessionReport(ctx context.Context, msgID string, reqID s } response, err := s.morRpc.SessionReportResponse( - s.publicKeyHex, uint32(tps), uint32(ttft), common.HexToHash(session.Id), diff --git a/proxy-router/internal/proxyapi/proxy_sender.go b/proxy-router/internal/proxyapi/proxy_sender.go index 4bf31a7a..876c55bc 100644 --- a/proxy-router/internal/proxyapi/proxy_sender.go +++ b/proxy-router/internal/proxyapi/proxy_sender.go @@ -2,22 +2,25 @@ package proxyapi import ( "bufio" + "bytes" "context" + "crypto/rand" "encoding/json" "fmt" + "io" "math/big" "net" "net/http" - "net/url" + "strconv" + "time" - constants "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal" - "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/aiengine" + gcs "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/chatstorage/genericchatstorage" "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/interfaces" "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/lib" msgs "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/proxyapi/morrpcmessage" + sessionrepo "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/repositories/session" "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/storages" "github.com/ethereum/go-ethereum/common" - "github.com/gin-gonic/gin" "github.com/gin-gonic/gin/binding" "github.com/sashabaranov/go-openai" ) @@ -34,29 +37,96 @@ var ( ErrMasrshalFailed = fmt.Errorf("failed to marshal response") ErrDecode = fmt.Errorf("failed to decode response") ErrSessionNotFound = fmt.Errorf("session not found") + ErrSessionExpired = fmt.Errorf("session expired") ErrProviderNotFound = fmt.Errorf("provider not found") + ErrEmpty = fmt.Errorf("empty result and no error") + ErrConnectProvider = fmt.Errorf("failed to connect to provider") + ErrWriteProvider = fmt.Errorf("failed to write to provider") +) + +const ( + TimeoutPingDefault = 5 * time.Second ) type ProxyServiceSender struct { - publicUrl *url.URL + chainID *big.Int privateKey interfaces.PrKeyProvider logStorage *lib.Collection[*interfaces.LogStorage] sessionStorage *storages.SessionStorage + sessionRepo *sessionrepo.SessionRepositoryCached morRPC *msgs.MORRPCMessage + sessionService SessionService log lib.ILogger } -func NewProxySender(publicUrl *url.URL, privateKey interfaces.PrKeyProvider, logStorage *lib.Collection[*interfaces.LogStorage], sessionStorage *storages.SessionStorage, log lib.ILogger) *ProxyServiceSender { +func NewProxySender(chainID *big.Int, privateKey interfaces.PrKeyProvider, logStorage *lib.Collection[*interfaces.LogStorage], sessionStorage *storages.SessionStorage, sessionRepo *sessionrepo.SessionRepositoryCached, log lib.ILogger) *ProxyServiceSender { return &ProxyServiceSender{ - publicUrl: publicUrl, + chainID: chainID, privateKey: privateKey, logStorage: logStorage, sessionStorage: sessionStorage, + sessionRepo: sessionRepo, morRPC: msgs.NewMorRpc(), log: log, } } +func (p *ProxyServiceSender) SetSessionService(service SessionService) { + p.sessionService = service +} + +func (p *ProxyServiceSender) Ping(ctx context.Context, providerURL string, providerAddr common.Address) (time.Duration, error) { + prKey, err := p.privateKey.GetPrivateKey() + if err != nil { + return 0, ErrMissingPrKey + } + + // check if context has timeout set + if _, ok := ctx.Deadline(); !ok { + subCtx, cancel := context.WithTimeout(ctx, TimeoutPingDefault) + defer cancel() + ctx = subCtx + } + + nonce := make([]byte, 8) + _, err = rand.Read(nonce) + if err != nil { + return 0, lib.WrapError(ErrCreateReq, err) + } + + msg, err := p.morRPC.PingRequest("0", prKey, nonce) + if err != nil { + return 0, lib.WrapError(ErrCreateReq, err) + } + + reqStartTime := time.Now() + res, code, err := p.rpcRequest(providerURL, msg) + if err != nil { + return 0, lib.WrapError(ErrProvider, fmt.Errorf("code: %d, msg: %v, error: %s", code, res, err)) + } + pingDuration := time.Since(reqStartTime) + + var typedMsg *msgs.PongRes + err = json.Unmarshal(*res.Result, &typedMsg) + if err != nil { + return pingDuration, lib.WrapError(ErrInvalidResponse, fmt.Errorf("expected PongRes, got %s", res.Result)) + } + + err = binding.Validator.ValidateStruct(typedMsg) + if err != nil { + return pingDuration, lib.WrapError(ErrInvalidResponse, err) + } + + signature := typedMsg.Signature + typedMsg.Signature = lib.HexString{} + + if !p.morRPC.VerifySignatureAddr(typedMsg, signature, providerAddr, p.log) { + return pingDuration, ErrInvalidSig + } + + return pingDuration, nil +} + func (p *ProxyServiceSender) InitiateSession(ctx context.Context, user common.Address, provider common.Address, spend *big.Int, bidID common.Hash, providerURL string) (*msgs.SessionRes, error) { requestID := "1" @@ -70,9 +140,9 @@ func (p *ProxyServiceSender) InitiateSession(ctx context.Context, user common.Ad return nil, lib.WrapError(ErrCreateReq, err) } - msg, code, ginErr := p.rpcRequest(providerURL, initiateSessionRequest) - if ginErr != nil { - return nil, lib.WrapError(ErrProvider, fmt.Errorf("code: %d, msg: %v, error: %s", code, msg, ginErr)) + msg, code, err := p.rpcRequest(providerURL, initiateSessionRequest) + if err != nil { + return nil, lib.WrapError(ErrProvider, fmt.Errorf("code: %d, msg: %v, error: %s", code, msg, err)) } if msg.Error != nil { @@ -80,7 +150,7 @@ func (p *ProxyServiceSender) InitiateSession(ctx context.Context, user common.Ad return nil, lib.WrapError(ErrResponseErr, fmt.Errorf("error: %v, result: %v", msg.Error.Message, msg.Error.Data)) } if msg.Result == nil { - return nil, lib.WrapError(ErrInvalidResponse, fmt.Errorf("empty result and no error")) + return nil, lib.WrapError(ErrInvalidResponse, ErrEmpty) } var typedMsg *msgs.SessionRes @@ -114,7 +184,7 @@ func (p *ProxyServiceSender) InitiateSession(ctx context.Context, user common.Ad return typedMsg, nil } -func (p *ProxyServiceSender) GetSessionReport(ctx context.Context, sessionID common.Hash) (*msgs.SessionReportRes, error) { +func (p *ProxyServiceSender) GetSessionReportFromProvider(ctx context.Context, sessionID common.Hash) (*msgs.SessionReportRes, error) { requestID := "1" prKey, err := p.privateKey.GetPrivateKey() @@ -122,11 +192,11 @@ func (p *ProxyServiceSender) GetSessionReport(ctx context.Context, sessionID com return nil, ErrMissingPrKey } - session, ok := p.sessionStorage.GetSession(sessionID.Hex()) - if !ok { + session, err := p.sessionRepo.GetSession(ctx, sessionID) + if err != nil { return nil, ErrSessionNotFound } - provider, ok := p.sessionStorage.GetUser(session.ProviderAddr) + provider, ok := p.sessionStorage.GetUser(session.ProviderAddr().Hex()) if !ok { return nil, ErrProviderNotFound } @@ -136,9 +206,9 @@ func (p *ProxyServiceSender) GetSessionReport(ctx context.Context, sessionID com return nil, lib.WrapError(ErrCreateReq, err) } - msg, code, ginErr := p.rpcRequest(provider.Url, getSessionReportRequest) - if ginErr != nil { - return nil, lib.WrapError(ErrProvider, fmt.Errorf("code: %d, msg: %v, error: %s", code, msg, ginErr)) + msg, code, err := p.rpcRequest(provider.Url, getSessionReportRequest) + if err != nil { + return nil, lib.WrapError(ErrProvider, fmt.Errorf("code: %d, msg: %v, error: %s", code, msg, err)) } if msg.Error != nil { @@ -146,7 +216,7 @@ func (p *ProxyServiceSender) GetSessionReport(ctx context.Context, sessionID com return nil, lib.WrapError(ErrResponseErr, fmt.Errorf("error: %v, result: %v", msg.Error.Message, msg.Error.Data)) } if msg.Result == nil { - return nil, lib.WrapError(ErrInvalidResponse, fmt.Errorf("empty result and no error")) + return nil, lib.WrapError(ErrInvalidResponse, ErrEmpty) } var typedMsg *msgs.SessionReportRes @@ -175,57 +245,83 @@ func (p *ProxyServiceSender) GetSessionReport(ctx context.Context, sessionID com return typedMsg, nil } -func (p *ProxyServiceSender) SendPrompt(ctx context.Context, resWriter ResponderFlusher, prompt *openai.ChatCompletionRequest, sessionID common.Hash) (interface{}, error) { - session, ok := p.sessionStorage.GetSession(sessionID.Hex()) - if !ok { - return nil, ErrSessionNotFound +func (p *ProxyServiceSender) GetSessionReportFromUser(ctx context.Context, sessionID common.Hash) (lib.HexString, lib.HexString, error) { + session, err := p.sessionRepo.GetSession(ctx, sessionID) + if err != nil { + return nil, nil, ErrSessionNotFound } - // TODO: add check for session expiration + TPSScaled1000Arr, TTFTMsArr := session.GetStats() - provider, ok := p.sessionStorage.GetUser(session.ProviderAddr) - if !ok { - return nil, ErrProviderNotFound + tps := 0 + ttft := 0 + for _, tpsVal := range TPSScaled1000Arr { + tps += tpsVal + } + for _, ttftVal := range TTFTMsArr { + ttft += ttftVal + } + + if len(TPSScaled1000Arr) != 0 { + tps /= len(TPSScaled1000Arr) + } + if len(TTFTMsArr) != 0 { + ttft /= len(TTFTMsArr) } prKey, err := p.privateKey.GetPrivateKey() if err != nil { - return nil, ErrMissingPrKey + return nil, nil, ErrMissingPrKey } - requestID := "1" - pubKey, err := lib.StringToHexString(provider.PubKey) + response, err := p.morRPC.SessionReportResponse( + uint32(tps), + uint32(ttft), + sessionID, + prKey, + "1", + p.chainID, + ) + if err != nil { - return nil, lib.WrapError(ErrCreateReq, err) + return nil, nil, lib.WrapError(ErrGenerateReport, err) } - promptRequest, err := p.morRPC.SessionPromptRequest(sessionID, prompt, pubKey, prKey, requestID) + + var typedMsg *msgs.SessionReportRes + err = json.Unmarshal(*response.Result, &typedMsg) if err != nil { - return nil, lib.WrapError(ErrCreateReq, err) + return nil, nil, lib.WrapError(ErrInvalidResponse, fmt.Errorf("expected SessionReportRespose, got %s", response.Result)) } - return p.rpcRequestStream(ctx, resWriter, provider.Url, promptRequest, pubKey) + return typedMsg.Message, typedMsg.SignedReport, nil } -func (p *ProxyServiceSender) rpcRequest(url string, rpcMessage *msgs.RPCMessage) (*msgs.RpcResponse, int, gin.H) { - conn, err := net.Dial("tcp", url) +func (p *ProxyServiceSender) rpcRequest(url string, rpcMessage *msgs.RPCMessage) (*msgs.RpcResponse, int, error) { + // TODO: enable request-response matching by using requestID + // TODO: add context cancellation + + TIMEOUT_TO_ESTABLISH_CONNECTION := time.Second * 3 + dialer := net.Dialer{Timeout: TIMEOUT_TO_ESTABLISH_CONNECTION} + + conn, err := dialer.Dial("tcp", url) if err != nil { - err = lib.WrapError(fmt.Errorf("failed to connect to provider"), err) - p.log.Errorf("%s", err) - return nil, http.StatusInternalServerError, gin.H{"error": err.Error()} + err = lib.WrapError(ErrConnectProvider, err) + p.log.Warnf(err.Error()) + return nil, http.StatusInternalServerError, err } defer conn.Close() msgJSON, err := json.Marshal(rpcMessage) if err != nil { - err = lib.WrapError(fmt.Errorf("failed to marshal request"), err) + err = lib.WrapError(ErrMasrshalFailed, err) p.log.Errorf("%s", err) - return nil, http.StatusInternalServerError, gin.H{"error": err.Error()} + return nil, http.StatusInternalServerError, err } _, err = conn.Write(msgJSON) if err != nil { - err = lib.WrapError(fmt.Errorf("failed to write request"), err) + err = lib.WrapError(ErrWriteProvider, err) p.log.Errorf("%s", err) - return nil, http.StatusInternalServerError, gin.H{"error": err.Error()} + return nil, http.StatusInternalServerError, err } // read response @@ -235,123 +331,360 @@ func (p *ProxyServiceSender) rpcRequest(url string, rpcMessage *msgs.RPCMessage) var msg *msgs.RpcResponse err = d.Decode(&msg) if err != nil { - err = lib.WrapError(fmt.Errorf("failed to decode response"), err) + err = lib.WrapError(ErrDecode, err) p.log.Errorf("%s", err) - return nil, http.StatusBadRequest, gin.H{"error": err.Error()} + return nil, http.StatusBadRequest, err } return msg, 0, nil } -func (p *ProxyServiceSender) rpcRequestStream(ctx context.Context, resWriter ResponderFlusher, url string, rpcMessage *msgs.RPCMessage, providerPublicKey lib.HexString) (interface{}, error) { +func (p *ProxyServiceSender) validateMsgSignature(result any, signature lib.HexString, providerPubicKey lib.HexString) bool { + return p.morRPC.VerifySignature(result, signature, providerPubicKey, p.log) +} + +func (p *ProxyServiceSender) GetModelIdSession(ctx context.Context, sessionID common.Hash) (common.Hash, error) { + session, err := p.sessionRepo.GetSession(ctx, sessionID) + if err != nil { + return common.Hash{}, ErrSessionNotFound + } + return session.ModelID(), nil +} + +func (p *ProxyServiceSender) validateMsgSignatureAddr(result any, signature lib.HexString, providerAddr common.Address) bool { + return p.morRPC.VerifySignatureAddr(result, signature, providerAddr, p.log) +} + +func (p *ProxyServiceSender) SendPromptV2(ctx context.Context, sessionID common.Hash, prompt *openai.ChatCompletionRequest, cb gcs.CompletionCallback) (interface{}, error) { + session, err := p.sessionRepo.GetSession(ctx, sessionID) + if err != nil { + return nil, ErrSessionNotFound + } + + isExpired := session.EndsAt().Int64()-time.Now().Unix() < 0 + if isExpired { + return nil, ErrSessionExpired + } + + provider, ok := p.sessionStorage.GetUser(session.ProviderAddr().Hex()) + if !ok { + return nil, ErrProviderNotFound + } + prKey, err := p.privateKey.GetPrivateKey() if err != nil { return nil, ErrMissingPrKey } - conn, err := net.Dial("tcp", url) + requestID := "1" + pubKey, err := lib.StringToHexString(provider.PubKey) if err != nil { - err = lib.WrapError(fmt.Errorf("failed to connect to provider"), err) - p.log.Errorf("%s", err) - return nil, err + return nil, lib.WrapError(ErrCreateReq, err) + } + promptRequest, err := p.morRPC.SessionPromptRequest(sessionID, prompt, pubKey, prKey, requestID) + if err != nil { + return nil, lib.WrapError(ErrCreateReq, err) + } + + now := time.Now().Unix() + result, ttftMs, totalTokens, err := p.rpcRequestStreamV2(ctx, cb, provider.Url, promptRequest, pubKey) + if err != nil { + if !session.FailoverEnabled() { + return nil, lib.WrapError(ErrProvider, err) + } + + _, err := p.sessionService.CloseSession(ctx, sessionID) + if err != nil { + return nil, err + } + + err = cb(ctx, gcs.NewChunkControl("provider failed, failover enabled")) + if err != nil { + return nil, err + } + + duration := session.EndsAt().Int64() - time.Now().Unix() + + newSessionID, err := p.sessionService.OpenSessionByModelId( + ctx, + session.ModelID(), + big.NewInt(duration), + session.DirectPayment(), + session.FailoverEnabled(), + session.ProviderAddr(), + ) + if err != nil { + return nil, err + } + + msg := fmt.Sprintf("new session opened: %s", newSessionID.Hex()) + err = cb(ctx, gcs.NewChunkControl(msg)) + if err != nil { + return nil, err + } + + return p.SendPromptV2(ctx, newSessionID, prompt, cb) + } + + requestDuration := int(time.Now().Unix() - now) + if requestDuration == 0 { + requestDuration = 1 + } + session.AddStats(totalTokens*1000/requestDuration, ttftMs) + + err = p.sessionRepo.SaveSession(ctx, session) + if err != nil { + p.log.Error(`failed to update session report stats`, err) + } + + return result, nil +} +func (p *ProxyServiceSender) rpcRequestStreamV2( + ctx context.Context, + cb gcs.CompletionCallback, + url string, + rpcMessage *msgs.RPCMessage, + providerPublicKey lib.HexString, +) (interface{}, int, int, error) { + const ( + TIMEOUT_TO_ESTABLISH_CONNECTION = time.Second * 3 + TIMEOUT_TO_RECEIVE_FIRST_RESPONSE = time.Second * 30 + MAX_RETRIES = 5 + ) + + dialer := net.Dialer{Timeout: TIMEOUT_TO_ESTABLISH_CONNECTION} + + prKey, err := p.privateKey.GetPrivateKey() + if err != nil { + return nil, 0, 0, ErrMissingPrKey + } + + conn, err := dialer.Dial("tcp", url) + if err != nil { + err = lib.WrapError(ErrConnectProvider, err) + p.log.Warnf(err.Error()) + return nil, 0, 0, err } defer conn.Close() + // Set initial read deadline + _ = conn.SetReadDeadline(time.Now().Add(TIMEOUT_TO_RECEIVE_FIRST_RESPONSE)) + msgJSON, err := json.Marshal(rpcMessage) if err != nil { - return nil, lib.WrapError(ErrMasrshalFailed, err) + return nil, 0, 0, lib.WrapError(ErrMasrshalFailed, err) } + + ttftMs := 0 + totalTokens := 0 + now := time.Now().UnixMilli() + _, err = conn.Write(msgJSON) if err != nil { - return nil, err + return nil, ttftMs, totalTokens, err } - // read response reader := bufio.NewReader(conn) - d := json.NewDecoder(reader) - resWriter.Header().Set(constants.HEADER_CONTENT_TYPE, constants.CONTENT_TYPE_EVENT_STREAM) + // We need to recreate the decoder if it becomes invalid + var d *json.Decoder responses := make([]interface{}, 0) + retryCount := 0 + for { if ctx.Err() != nil { - return nil, ctx.Err() + return nil, ttftMs, totalTokens, ctx.Err() + } + + // Initialize or reset the decoder + if d == nil { + d = json.NewDecoder(reader) } + var msg *msgs.RpcResponse err = d.Decode(&msg) - p.log.Debugf("Received stream msg:", msg) if err != nil { - p.log.Warnf("Failed to decode response: %v", err) - return responses, nil + if netErr, ok := err.(net.Error); ok && netErr.Timeout() { + p.log.Warnf("Read operation timed out: %v", err) + if retryCount < MAX_RETRIES { + alive, availErr := checkProviderAvailability(url) + if availErr != nil { + p.log.Warnf("Provider availability check failed: %v", availErr) + return nil, ttftMs, totalTokens, fmt.Errorf("provider availability check failed: %w", availErr) + } + if alive { + retryCount++ + p.log.Infof("Provider is alive, retrying (%d/%d)...", retryCount, MAX_RETRIES) + // Reset the read deadline + conn.SetReadDeadline(time.Now().Add(TIMEOUT_TO_RECEIVE_FIRST_RESPONSE)) + // Clear the error state by reading any remaining data + reader.Discard(reader.Buffered()) + // Reset the decoder + d = nil + continue + } else { + return nil, ttftMs, totalTokens, fmt.Errorf("provider is not available") + } + } else { + return nil, ttftMs, totalTokens, fmt.Errorf("read timed out after %d retries: %w", retryCount, err) + } + } else if err == io.EOF { + p.log.Warnf("Connection closed by provider") + return nil, ttftMs, totalTokens, fmt.Errorf("connection closed by provider") + } else { + p.log.Warnf("Failed to decode response: %v", err) + return nil, ttftMs, totalTokens, lib.WrapError(ErrInvalidResponse, err) + } } if msg.Error != nil { - return nil, lib.WrapError(ErrResponseErr, fmt.Errorf("error: %v, data: %v", msg.Error.Message, msg.Error.Data)) + return nil, ttftMs, totalTokens, lib.WrapError(ErrResponseErr, fmt.Errorf("error: %v, data: %v", msg.Error.Message, msg.Error.Data)) } if msg.Result == nil { - return nil, lib.WrapError(ErrInvalidResponse, fmt.Errorf("empty result and no error")) + return nil, ttftMs, totalTokens, lib.WrapError(ErrInvalidResponse, ErrEmpty) + } + + if ttftMs == 0 { + ttftMs = int(time.Now().UnixMilli() - now) + _ = conn.SetReadDeadline(time.Time{}) // Clear read deadline } var inferenceRes InferenceRes - err := json.Unmarshal(*msg.Result, &inferenceRes) + err = json.Unmarshal(*msg.Result, &inferenceRes) if err != nil { - return nil, lib.WrapError(ErrInvalidResponse, err) + return nil, ttftMs, totalTokens, lib.WrapError(ErrInvalidResponse, err) } sig := inferenceRes.Signature inferenceRes.Signature = []byte{} if !p.validateMsgSignature(inferenceRes, sig, providerPublicKey) { - return nil, ErrInvalidSig + return nil, ttftMs, totalTokens, ErrInvalidSig } var message lib.HexString err = json.Unmarshal(inferenceRes.Message, &message) if err != nil { - return nil, lib.WrapError(ErrInvalidResponse, err) + return nil, ttftMs, totalTokens, lib.WrapError(ErrInvalidResponse, err) } aiResponse, err := lib.DecryptBytes(message, prKey) if err != nil { - return nil, lib.WrapError(ErrDecrFailed, err) + return nil, ttftMs, totalTokens, lib.WrapError(ErrDecrFailed, err) } - var payload ChatCompletionResponse + var payload openai.ChatCompletionStreamResponse err = json.Unmarshal(aiResponse, &payload) var stop = true + var chunk gcs.Chunk if err == nil && len(payload.Choices) > 0 { stop = false choices := payload.Choices for _, choice := range choices { - if choice.FinishReason == FinishReasonStop { + if choice.FinishReason == openai.FinishReasonStop { stop = true } } + totalTokens += len(choices) responses = append(responses, payload) + chunk = gcs.NewChunkStreaming(&payload) } else { - var prodiaPayload aiengine.ProdiaGenerationResult - err = json.Unmarshal(aiResponse, &prodiaPayload) - if err != nil { - return nil, lib.WrapError(ErrInvalidResponse, err) + var imageGenerationResult gcs.ImageGenerationResult + err = json.Unmarshal(aiResponse, &imageGenerationResult) + if err == nil && imageGenerationResult.ImageUrl != "" { + totalTokens += 1 + responses = append(responses, imageGenerationResult) + chunk = gcs.NewChunkImage(&imageGenerationResult) + } else { + var videoGenerationResult gcs.VideoGenerationResult + err = json.Unmarshal(aiResponse, &videoGenerationResult) + if err == nil && videoGenerationResult.VideoRawContent != "" { + totalTokens += 1 + responses = append(responses, videoGenerationResult) + chunk = gcs.NewChunkVideo(&videoGenerationResult) + } else { + var imageGenerationResult gcs.ImageRawContentResult + err = json.Unmarshal(aiResponse, &imageGenerationResult) + if err == nil && imageGenerationResult.ImageRawContent != "" { + totalTokens += 1 + responses = append(responses, imageGenerationResult) + chunk = gcs.NewChunkImageRawContent(&imageGenerationResult) + } else { + return nil, ttftMs, totalTokens, lib.WrapError(ErrInvalidResponse, err) + } + } } - responses = append(responses, prodiaPayload) } if ctx.Err() != nil { - return nil, ctx.Err() + return nil, ttftMs, totalTokens, ctx.Err() } - _, err = resWriter.Write([]byte(fmt.Sprintf("data: %s\n\n", aiResponse))) + err = cb(ctx, chunk) if err != nil { - return nil, err + return nil, ttftMs, totalTokens, lib.WrapError(ErrResponseErr, err) } - resWriter.Flush() if stop { break } } - return responses, nil + return responses, ttftMs, totalTokens, nil } -func (p *ProxyServiceSender) validateMsgSignature(result any, signature lib.HexString, providerPubicKey lib.HexString) bool { - return p.morRPC.VerifySignature(result, signature, providerPubicKey, p.log) +// checkProviderAvailability checks if the provider is alive using portchecker.io API +func checkProviderAvailability(url string) (bool, error) { + host, port, err := net.SplitHostPort(url) + if err != nil { + return false, err + } + + portInt, err := strconv.Atoi(port) + if err != nil { + return false, err + } + + requestBody, err := json.Marshal(map[string]interface{}{ + "host": host, + "ports": []int{portInt}, + }) + if err != nil { + return false, err + } + + req, err := http.NewRequest("POST", "https://portchecker.io/api/v1/query", bytes.NewBuffer(requestBody)) + if err != nil { + return false, err + } + req.Header.Set("Content-Type", "application/json") + + client := &http.Client{} + resp, err := client.Do(req) + if err != nil { + return false, err + } + defer resp.Body.Close() + + body, err := io.ReadAll(resp.Body) + if err != nil { + return false, err + } + + var response struct { + Check []struct { + Status bool `json:"status"` + Port int `json:"port"` + } `json:"check"` + } + err = json.Unmarshal(body, &response) + if err != nil { + return false, err + } + + for _, check := range response.Check { + if check.Port == portInt { + return check.Status, nil + } + } + + return false, fmt.Errorf("port status not found in response") } diff --git a/proxy-router/internal/proxyapi/requests.go b/proxy-router/internal/proxyapi/requests.go index 7664b796..60fcb0af 100644 --- a/proxy-router/internal/proxyapi/requests.go +++ b/proxy-router/internal/proxyapi/requests.go @@ -7,6 +7,15 @@ import ( "github.com/ethereum/go-ethereum/common" ) +type PingReq struct { + ProviderAddr common.Address `json:"providerAddr" validate:"required,eth_addr"` + ProviderURL string `json:"providerUrl" validate:"required,hostname_port"` +} + +type PingRes struct { + PingMs int64 `json:"ping,omitempty"` +} + type InitiateSessionReq struct { User common.Address `json:"user" validate:"required,eth_addr"` Provider common.Address `json:"provider" validate:"required,eth_addr"` @@ -17,13 +26,14 @@ type InitiateSessionReq struct { type PromptReq struct { Signature string `json:"signature" validate:"required,hexadecimal"` - Message json.RawMessage `json:"message" validate:"required"` + Message json.RawMessage `json:"message" validate:"required"` Timestamp string `json:"timestamp" validate:"required,timestamp"` } type PromptHead struct { SessionID lib.Hash `header:"session_id" validate:"hex32"` - ModelID lib.Hash `header:"model_id" validate:"hex32"` + ModelID lib.Hash `header:"model_id" validate:"hex32"` + ChatID lib.Hash `header:"chat_id" validate:"hex32"` } type InferenceRes struct { @@ -31,3 +41,19 @@ type InferenceRes struct { Message json.RawMessage `json:"message" validate:"required"` Timestamp uint64 `json:"timestamp" validate:"required,timestamp"` } + +type UpdateChatTitleReq struct { + Title string `json:"title" validate:"required"` +} + +type ResultResponse struct { + Result bool `json:"result"` +} + +type ChatCompletionRequestSwaggerExample struct { + Stream bool `json:"stream"` + Messages []struct { + Role string `json:"role" example:"user"` + Content string `json:"content" example:"tell me a joke"` + } `json:"messages"` +} diff --git a/proxy-router/internal/proxyctl/proxyctl.go b/proxy-router/internal/proxyctl/proxyctl.go index 43bef0d5..977e7223 100644 --- a/proxy-router/internal/proxyctl/proxyctl.go +++ b/proxy-router/internal/proxyctl/proxyctl.go @@ -2,17 +2,23 @@ package proxyctl import ( "context" + "errors" + "fmt" "math/big" "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/aiengine" "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/blockchainapi" + "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/blockchainapi/structs" "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/config" "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/handlers/tcphandlers" "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/interfaces" "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/lib" "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/proxyapi" + "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/repositories/registries" + sessionrepo "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/repositories/session" "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/repositories/transport" "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/storages" + "github.com/ethereum/go-ethereum/common" "github.com/go-playground/validator/v10" "golang.org/x/sync/errgroup" ) @@ -26,6 +32,16 @@ const ( StateStopping = 3 ) +const ( + MORDecimals = 18 + ETHDecimals = 18 +) + +var ( + MORBalanceThreshold = *lib.Exp10(MORDecimals) // 1 MOR the balance to show a warning + ETHBalanceThreshold = *lib.Exp10(ETHDecimals - 1) // 0.1 ETH the balance to show a warning +) + func (s ProxyState) String() string { switch s { case StateStopped: @@ -40,40 +56,44 @@ func (s ProxyState) String() string { return "unknown" } -type SchedulerLogFactory = func(remoteAddr string) (lib.ILogger, error) - // Proxy is a struct that represents a proxy-router part of the system type Proxy struct { - eventListener *blockchainapi.EventsListener - wallet interfaces.PrKeyProvider - proxyAddr string - chainID *big.Int - sessionStorage *storages.SessionStorage - log *lib.Logger - connLog *lib.Logger - schedulerLogFactory SchedulerLogFactory - aiEngine *aiengine.AiEngine - validator *validator.Validate - modelConfigLoader *config.ModelConfigLoader - - state lib.AtomicValue[ProxyState] - tsk *lib.Task + eventListener *blockchainapi.EventsListener + wallet interfaces.PrKeyProvider + proxyAddr string + chainID *big.Int + sessionStorage *storages.SessionStorage + sessionRepo *sessionrepo.SessionRepositoryCached + log lib.ILogger + tcpLog *lib.Logger + aiEngine *aiengine.AiEngine + validator *validator.Validate + modelConfigLoader *config.ModelConfigLoader + blockchainService *blockchainapi.BlockchainService + sessionExpiryHandler *blockchainapi.SessionExpiryHandler + + state lib.AtomicValue[ProxyState] + tsk *lib.Task + serverStarted <-chan struct{} } // NewProxyCtl creates a new Proxy controller instance -func NewProxyCtl(eventListerer *blockchainapi.EventsListener, wallet interfaces.PrKeyProvider, chainID *big.Int, log *lib.Logger, connLog *lib.Logger, proxyAddr string, scl SchedulerLogFactory, sessionStorage *storages.SessionStorage, modelConfigLoader *config.ModelConfigLoader, valid *validator.Validate, aiEngine *aiengine.AiEngine) *Proxy { +func NewProxyCtl(eventListerer *blockchainapi.EventsListener, wallet interfaces.PrKeyProvider, chainID *big.Int, log lib.ILogger, tcpLog *lib.Logger, proxyAddr string, sessionStorage *storages.SessionStorage, modelConfigLoader *config.ModelConfigLoader, valid *validator.Validate, aiEngine *aiengine.AiEngine, blockchainService *blockchainapi.BlockchainService, sessionRepo *sessionrepo.SessionRepositoryCached, sessionExpiryHandler *blockchainapi.SessionExpiryHandler) *Proxy { return &Proxy{ - eventListener: eventListerer, - chainID: chainID, - wallet: wallet, - log: log, - connLog: connLog, - proxyAddr: proxyAddr, - schedulerLogFactory: scl, - sessionStorage: sessionStorage, - aiEngine: aiEngine, - validator: valid, - modelConfigLoader: modelConfigLoader, + eventListener: eventListerer, + chainID: chainID, + wallet: wallet, + log: log, + tcpLog: tcpLog, + proxyAddr: proxyAddr, + sessionStorage: sessionStorage, + aiEngine: aiEngine, + validator: valid, + modelConfigLoader: modelConfigLoader, + blockchainService: blockchainService, + sessionRepo: sessionRepo, + sessionExpiryHandler: sessionExpiryHandler, + serverStarted: make(chan struct{}), } } @@ -111,7 +131,13 @@ func (p *Proxy) Run(ctx context.Context) error { case <-tsk.Done(): err := tsk.Err() if err != nil { - p.log.Errorf("proxy stopped with error: %s", err) + var logFunc func(string, ...interface{}) + if errors.Is(err, context.Canceled) { + logFunc = p.log.Warnf + } else { + logFunc = p.log.Errorf + } + logFunc("proxy stopped with error: %s", err) return err } } @@ -119,7 +145,7 @@ func (p *Proxy) Run(ctx context.Context) error { } func (p *Proxy) run(ctx context.Context, prKey lib.HexString) error { - tcpServer := transport.NewTCPServer(p.proxyAddr, p.connLog.Named("TCP")) + tcpServer := transport.NewTCPServer(p.proxyAddr, p.tcpLog.Named("TCP")) prKey, err := p.wallet.GetPrivateKey() if err != nil { return err @@ -131,16 +157,39 @@ func (p *Proxy) run(ctx context.Context, prKey lib.HexString) error { } p.log.Infof("Wallet address: %s", walletAddr.String()) - pubKey, err := lib.PubKeyFromPrivate(prKey) + ethBalance, morBalance, err := p.blockchainService.GetBalance(ctx) if err != nil { return err } - proxyReceiver := proxyapi.NewProxyReceiver(prKey, pubKey, p.sessionStorage, p.aiEngine, p.chainID, p.modelConfigLoader) + if ethBalance.Cmp(ÐBalanceThreshold) < 0 { + p.log.Warnf( + "ETH balance is too low: %s (< %s)", + formatETH(ethBalance), + formatETH(ÐBalanceThreshold), + ) + } else { + p.log.Infof("ETH balance: %s", formatETH(ethBalance)) + } + if morBalance.Cmp(&MORBalanceThreshold) < 0 { + p.log.Warnf( + "MOR balance is too low: %s (< %s)", + formatMOR(morBalance), + formatMOR(&MORBalanceThreshold), + ) + } else { + p.log.Infof("MOR balance: %s", formatMOR(morBalance)) + } + + pubKey, err := lib.PubKeyFromPrivate(prKey) + if err != nil { + return err + } - morTcpHandler := proxyapi.NewMORRPCController(proxyReceiver, p.validator, p.sessionStorage) + proxyReceiver := proxyapi.NewProxyReceiver(prKey, pubKey, p.sessionStorage, p.aiEngine, p.chainID, p.modelConfigLoader, p.blockchainService, p.sessionRepo) + morTcpHandler := proxyapi.NewMORRPCController(proxyReceiver, p.validator, p.sessionRepo, p.sessionStorage, prKey) tcpHandler := tcphandlers.NewTCPHandler( - p.log, p.connLog, p.schedulerLogFactory, morTcpHandler, + p.tcpLog, morTcpHandler, ) tcpServer.SetConnectionHandler(tcpHandler) @@ -149,13 +198,85 @@ func (p *Proxy) run(ctx context.Context, prKey lib.HexString) error { return tcpServer.Run(errCtx) }) + g.Go(func() error { + <-tcpServer.Started() + return p.afterStart(errCtx, walletAddr) + }) + g.Go(func() error { return p.eventListener.Run(errCtx) }) + g.Go(func() error { + return p.sessionExpiryHandler.Run(errCtx) + }) + return g.Wait() } +func (p *Proxy) afterStart(ctx context.Context, walletAddr common.Address) error { + log := p.log.Named("PROVIDER_CHECK") + + // check if provider exists + pr, err := p.blockchainService.GetProvider(ctx, walletAddr) + if err != nil { + return fmt.Errorf("cannot get provider %s: %w", walletAddr, err) + } else if pr == nil { + log.Warnf("provider is not registered under this wallet address: %s", walletAddr) + } else { + log.Infof("provider is registered in blockchain, url: %s", pr.Endpoint) + } + + if pr != nil { + // check provider connectivity from localhost + pingDuration, err := p.blockchainService.CheckConnectivity(ctx, pr.Endpoint, pr.Address) + if err != nil { + log.Warnf("provider %s is not reachable from localhost by address %s: %s", pr.Address, pr.Endpoint, err) + } else { + log.Infof("provider is reachable from localhost, ping: %s", pingDuration) + } + + // check connectivity from outer network + ok, err := p.blockchainService.CheckPortOpen(ctx, pr.Endpoint) + if err != nil { + log.Warnf("cannot check if port open for %s %s %s", pr.Address, pr.Endpoint, err) + } else if !ok { + log.Warnf("provider is not reachable from internet by %s", pr.Endpoint) + } else { + log.Infof("provider is reachable from internet") + } + + // check if provider has active bids + bids, err := p.blockchainService.GetActiveBidsByProvider(ctx, walletAddr, big.NewInt(0), 100, registries.OrderDESC) + if err != nil { + log.Warnf("cannot get active bids by provider: %s", walletAddr, err) + } else if len(bids) == 0 { + log.Warnf("provider has no bids available") + } else { + log.Infof("provider has %d bids available", len(bids)) + } + + bidsByModelID := make(map[common.Hash][]*structs.Bid) + for _, bid := range bids { + bidsByModelID[bid.ModelAgentId] = append(bidsByModelID[bid.ModelAgentId], bid) + } + + // check if provider has active bids for each model + modelIDs, _ := p.modelConfigLoader.GetAll() + + for _, modelID := range modelIDs { + count := len(bidsByModelID[modelID]) + if count == 0 { + log.Warnf("model %s, no active bids", lib.Short(modelID)) + } else { + log.Infof("model %s, active bids %d", lib.Short(modelID), count) + } + } + } + + return nil +} + func (p *Proxy) GetState() ProxyState { return p.state.Load() } @@ -164,3 +285,19 @@ func (p *Proxy) setState(s ProxyState) { p.state.Store(s) p.log.Infof("proxy state: %s", s) } + +func (p *Proxy) ServerStarted() <-chan struct{} { + return p.serverStarted +} + +func formatDecimal(n *big.Int, decimals int) string { + return lib.NewRat(n, lib.Exp10(decimals)).FloatString(3) +} + +func formatMOR(n *big.Int) string { + return formatDecimal(n, MORDecimals) + " MOR" +} + +func formatETH(n *big.Int) string { + return formatDecimal(n, ETHDecimals) + " ETH" +} diff --git a/proxy-router/internal/rating/common.go b/proxy-router/internal/rating/common.go new file mode 100644 index 00000000..ca255e04 --- /dev/null +++ b/proxy-router/internal/rating/common.go @@ -0,0 +1,69 @@ +package rating + +import ( + "math" + + s "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/repositories/contracts/bindings/sessionrouter" +) + +// ratioScore calculates the ratio of two numbers +func ratioScore(num, denom uint32) float64 { + if denom == 0 { + return 0 + } + return float64(num) / float64(denom) +} + +// normZIndex normalizes the value using z-index +func normZIndex(pmMean int64, mSD s.LibSDSD, obsNum int64) float64 { + sd := getSD(mSD, obsNum) + if sd == 0 { + return 0 + } + // TODO: consider variance(SD) of provider model stats + return float64(pmMean-mSD.Mean) / sd +} + +// normRange normalizes the incoming data within the range [-normRange, normRange] +// cutting off the values outside the range, and then shifts and scales to the range [0, 1] +func normRange(input float64, normRange float64) float64 { + return cutRange01((input + normRange) / (2.0 * normRange)) +} + +// getSD calculates the standard deviation from the standard deviation struct +func getSD(sd s.LibSDSD, obsNum int64) float64 { + return math.Sqrt(getVariance(sd, obsNum)) +} + +// getVariance calculates the variance from the standard deviation struct +func getVariance(sd s.LibSDSD, obsNum int64) float64 { + if obsNum <= 1 { + return 0 + } + return float64(sd.SqSum) / float64(obsNum-1) +} + +// cutRange01 cuts the value to the range [0, 1] +func cutRange01(val float64) float64 { + if val > 1 { + return 1 + } + if val < 0 { + return 0 + } + return val +} + +// normMinMax normalizes the value within the range [min, max] to the range [0, 1] +func normMinMax(val, min, max int64) float64 { + if max == min { + return 0 + } + if val < min { + return 0 + } + if val > max { + return 1 + } + return float64(val-min) / float64(max-min) +} diff --git a/proxy-router/internal/rating/interface.go b/proxy-router/internal/rating/interface.go new file mode 100644 index 00000000..a0fb119f --- /dev/null +++ b/proxy-router/internal/rating/interface.go @@ -0,0 +1,31 @@ +package rating + +import ( + "math/big" + + s "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/repositories/contracts/bindings/sessionrouter" +) + +type Scorer interface { + // GetScore returns the score of a bid. Returns -Inf if the bid should be skipped + GetScore(args *ScoreInput) float64 +} + +// ScoreInput is a struct that holds the input data for the rating algorithm of a bid +type ScoreInput struct { + ProviderModel *s.IStatsStorageProviderModelStats // stats of the provider specific to the model + Model *s.IStatsStorageModelStats // stats of the model across providers + PricePerSecond *big.Int + ProviderStake *big.Int + MinStake *big.Int +} + +func NewScoreArgs() *ScoreInput { + return &ScoreInput{ + ProviderModel: &s.IStatsStorageProviderModelStats{}, + Model: &s.IStatsStorageModelStats{}, + ProviderStake: big.NewInt(0), + PricePerSecond: big.NewInt(0), + MinStake: big.NewInt(0), + } +} diff --git a/proxy-router/internal/rating/mock.go b/proxy-router/internal/rating/mock.go new file mode 100644 index 00000000..e3c6d418 --- /dev/null +++ b/proxy-router/internal/rating/mock.go @@ -0,0 +1,12 @@ +package rating + +type ScorerMock struct { +} + +func NewScorerMock() *ScorerMock { + return &ScorerMock{} +} + +func (m *ScorerMock) GetScore(args *ScoreInput) float64 { + return 0.5 +} diff --git a/proxy-router/internal/rating/rating-config-schema.json b/proxy-router/internal/rating/rating-config-schema.json new file mode 100644 index 00000000..3db4154c --- /dev/null +++ b/proxy-router/internal/rating/rating-config-schema.json @@ -0,0 +1,41 @@ +{ + "$schema": "https://json-schema.org/draft-07/schema", + "type": "object", + "required": ["algorithm", "params"], + "properties": { + "algorithm": { + "type": "string", + "enum": ["default"], + "title": "Rating algorithm", + "description": "The algorithm used to calculate the rating of a provider" + }, + "providerAllowlist": { + "type": "array", + "items": { + "type": "string", + "pattern": "^0x[0-9a-fA-F]{40}$" + }, + "uniqueItems": true, + "title": "Provider allowlist", + "description": "List of provider addresses that are allowed to open session with" + } + }, + "allOf": [ + { + "if": { + "properties": { + "algorithm": { + "const": "default" + } + } + }, + "then": { + "properties": { + "params": { + "$ref": "./scorer-default-schema.json" + } + } + } + } + ] +} diff --git a/proxy-router/internal/rating/rating.go b/proxy-router/internal/rating/rating.go new file mode 100644 index 00000000..2037ce82 --- /dev/null +++ b/proxy-router/internal/rating/rating.go @@ -0,0 +1,64 @@ +package rating + +import ( + "math" + "sort" + + "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/lib" + "github.com/ethereum/go-ethereum/common" +) + +// Filters bids based on the config, uses the scorer to rate the bids and sorts them +type Rating struct { + scorer Scorer + providerAllowList map[common.Address]struct{} +} + +func (r *Rating) RateBids(scoreInputs []RatingInput, log lib.ILogger) []RatingRes { + scoredBids := make([]RatingRes, 0) + + for _, input := range scoreInputs { + score := r.scorer.GetScore(&input.ScoreInput) + if !r.isAllowed(input.ProviderID) { + log.Warnf("provider %s is not in the allow list, skipping", input.ProviderID.String()) + continue + } + + if math.IsNaN(score) || math.IsInf(score, 0) { + log.Warnf("provider score is not valid %d for %+v), skipping", score, input) + continue + } + + scoredBid := RatingRes{ + BidID: input.BidID, + Score: score, + } + scoredBids = append(scoredBids, scoredBid) + } + + sort.Slice(scoredBids, func(i, j int) bool { + return scoredBids[i].Score > scoredBids[j].Score + }) + + return scoredBids +} + +func (r *Rating) isAllowed(provider common.Address) bool { + if len(r.providerAllowList) == 0 { + return true + } + _, ok := r.providerAllowList[provider] + return ok +} + +type RatingInput struct { + ScoreInput + BidID common.Hash + ModelID common.Hash + ProviderID common.Address +} + +type RatingRes struct { + BidID common.Hash + Score float64 +} diff --git a/proxy-router/internal/rating/rating_factory.go b/proxy-router/internal/rating/rating_factory.go new file mode 100644 index 00000000..58f3081d --- /dev/null +++ b/proxy-router/internal/rating/rating_factory.go @@ -0,0 +1,101 @@ +package rating + +import ( + "encoding/json" + "errors" + "fmt" + "os" + "sort" + "strings" + + "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/lib" + "github.com/ethereum/go-ethereum/common" + "golang.org/x/exp/maps" +) + +type RatingConfig struct { + Algorithm string `json:"algorithm"` + Params json.RawMessage `json:"params"` + ProviderAllowList []common.Address `json:"providerAllowlist"` +} + +func NewRatingFromConfig(config json.RawMessage, log lib.ILogger) (*Rating, error) { + var cfg RatingConfig + err := json.Unmarshal(config, &cfg) + if err != nil { + return nil, fmt.Errorf("failed to unmarshal rating config: %w", err) + } + + log.Infof("rating algorithm: %s", cfg.Algorithm) + + scorer, err := factory(cfg.Algorithm, cfg.Params) + if err != nil { + return nil, err + } + + return NewRating(scorer, cfg.ProviderAllowList, log), nil +} + +func NewRating(scorer Scorer, providerAllowList []common.Address, log lib.ILogger) *Rating { + allowList := map[common.Address]struct{}{} + + if providerAllowList != nil { + for _, addr := range providerAllowList { + allowList[addr] = struct{}{} + } + } + + providerAllowListLegacy := os.Getenv("PROVIDER_ALLOW_LIST") + + if providerAllowListLegacy != "" { + log.Warnf("PROVIDER_ALLOW_LIST is deprecated, please use providerAllowList in rating config") + addresses := strings.Split(providerAllowListLegacy, ",") + for _, address := range addresses { + addr := common.HexToAddress(strings.TrimSpace(address)) + allowList[addr] = struct{}{} + } + log.Warnf("added %d addresses from PROVIDER_ALLOW_LIST", len(addresses)) + } + + if len(allowList) == 0 { + log.Infof("provider filtering is disabled") + } else { + keys := maps.Keys(allowList) + sort.Slice(keys, func(i, j int) bool { + return keys[i].Hex() < keys[j].Hex() + }) + log.Warnf("provider filtering is enabled, allowList: %v", keys) + } + + return &Rating{ + scorer: scorer, + providerAllowList: allowList, + } +} + +var ( + ErrUnknownAlgorithm = errors.New("unknown rating algorithm") + ErrAlgorithmParams = errors.New("invalid algorithm params") +) + +func factory(algo string, params json.RawMessage) (a Scorer, err error) { + switch algo { + case ScorerNameDefault: + a, err = NewScorerDefaultFromJSON(params) + break + // place here the new rating algorithms + // + // case "new_algorithm": + // a, err = NewScorerNewAlgorithmFromJSON(params) + // break + // + } + if err != nil { + return nil, lib.WrapError(ErrAlgorithmParams, fmt.Errorf("algorithm %s, error: %w, config: %s", algo, err, params)) + } + if a == nil { + return nil, lib.WrapError(ErrUnknownAlgorithm, fmt.Errorf("%s", algo)) + } + + return a, nil +} diff --git a/proxy-router/internal/rating/scorer-default-schema.json b/proxy-router/internal/rating/scorer-default-schema.json new file mode 100644 index 00000000..6e051d96 --- /dev/null +++ b/proxy-router/internal/rating/scorer-default-schema.json @@ -0,0 +1,50 @@ +{ + "$schema": "https://json-schema.org/draft-07/schema", + "type": "object", + "properties": { + "weights": { + "title": "Weights", + "description": "Weights for each metric", + "type": "object", + "properties": { + "tps": { + "title": "TPS", + "description": "Tokens per second weight", + "type": "number", + "minimum": 0, + "maximum": 1 + }, + "ttft": { + "title": "TTFT", + "description": "Time to first token weight", + "type": "number", + "minimum": 0, + "maximum": 1 + }, + "duration": { + "title": "Duration", + "description": "Duration weight", + "type": "number", + "minimum": 0, + "maximum": 1 + }, + "success": { + "title": "Success rate", + "description": "Success rate weight", + "type": "number", + "minimum": 0, + "maximum": 1 + }, + "stake": { + "title": "Stake", + "description": "Stake weight", + "type": "number", + "minimum": 0, + "maximum": 1 + } + }, + "required": ["tps", "ttft", "duration", "success", "stake"] + } + }, + "required": ["weights"] +} diff --git a/proxy-router/internal/rating/scorer_default.go b/proxy-router/internal/rating/scorer_default.go new file mode 100644 index 00000000..fd5698b1 --- /dev/null +++ b/proxy-router/internal/rating/scorer_default.go @@ -0,0 +1,84 @@ +package rating + +import ( + "math" + "math/big" +) + +const ( + ScorerNameDefault = "default" +) + +type ScorerDefault struct { + params ScorerDefaultParams +} + +func NewScorerDefault(weights ScorerDefaultParams) *ScorerDefault { + return &ScorerDefault{params: weights} +} + +func (r *ScorerDefault) GetScore(args *ScoreInput) float64 { + tpsScore := r.params.Weights.TPS * tpsScore(args) + ttftScore := r.params.Weights.TTFT * ttftScore(args) + durationScore := r.params.Weights.Duration * durationScore(args) + successScore := r.params.Weights.Success * successScore(args) + stakeScore := r.params.Weights.Stake * stakeScore(args) + + totalScore := tpsScore + ttftScore + durationScore + successScore + stakeScore + + return priceAdjust(totalScore, args.PricePerSecond) +} + +func tpsScore(args *ScoreInput) float64 { + // normalize provider model tps value using stats from the model from other providers + zIndex := normZIndex(args.ProviderModel.TpsScaled1000.Mean, args.Model.TpsScaled1000, int64(args.Model.Count)) + + // cut off the values outside the range [-3, 3] and normalize to [0, 1] + return normRange(zIndex, 3.0) +} + +func ttftScore(args *ScoreInput) float64 { + // normalize provider model ttft value using stats for this model from other providers + zIndex := normZIndex(args.ProviderModel.TtftMs.Mean, args.Model.TtftMs, int64(args.Model.Count)) + + // invert the value, because the higher the ttft, the worse the score + zIndex = -zIndex + + // cut off the values outside the range [-3, 3] and normalize to [0, 1] + return normRange(zIndex, 3.0) +} + +func durationScore(args *ScoreInput) float64 { + // normalize provider model duration value using stats for this model from other providers + zIndex := normZIndex(int64(args.ProviderModel.TotalDuration), args.Model.TotalDuration, int64(args.Model.Count)) + + // cut off the values outside the range [-3, 3] and normalize to [0, 1] + return normRange(zIndex, 3.0) +} + +func successScore(args *ScoreInput) float64 { + // calculate the ratio of successful requests to total requests + ratio := ratioScore(args.ProviderModel.SuccessCount, args.ProviderModel.TotalCount) + + // the higher the ratio, the better the score + return math.Pow(ratio, 2) +} + +func stakeScore(args *ScoreInput) float64 { + // normalize provider stake value to the range [0, 10x min stake] + return normMinMax(args.ProviderStake.Int64(), args.MinStake.Int64(), 10*args.MinStake.Int64()) +} + +func priceAdjust(score float64, pricePerSecond *big.Int) float64 { + priceFloatDecimal, _ := pricePerSecond.Float64() + + // since the price is in decimals, we adjust it to have less of the exponent + // TODO: consider removing it and using the price as is, since the exponent will be + // the same for all providers and can be removed from the equation + priceFloat := priceFloatDecimal / math.Pow10(18) + + // price cannot be 0 according to smart contract, so we can safely divide by it + return score / priceFloat +} + +var _ Scorer = &ScorerDefault{} diff --git a/proxy-router/internal/rating/scorer_default_config.go b/proxy-router/internal/rating/scorer_default_config.go new file mode 100644 index 00000000..7261da9c --- /dev/null +++ b/proxy-router/internal/rating/scorer_default_config.go @@ -0,0 +1,34 @@ +package rating + +import ( + "encoding/json" + "errors" +) + +var ErrInvalidWeights = errors.New("weights must sum to 1") + +type ScorerDefaultParams struct { + Weights struct { + TPS float64 `json:"tps"` + TTFT float64 `json:"ttft"` + Duration float64 `json:"duration"` + Success float64 `json:"success"` + Stake float64 `json:"stake"` + } `json:"weights"` +} + +func (w *ScorerDefaultParams) Validate() bool { + return w.Weights.TPS+w.Weights.TTFT+w.Weights.Duration+w.Weights.Success+w.Weights.Stake == 1 +} + +func NewScorerDefaultFromJSON(data json.RawMessage) (*ScorerDefault, error) { + var params ScorerDefaultParams + err := json.Unmarshal(data, ¶ms) + if err != nil { + return nil, err + } + if !params.Validate() { + return nil, ErrInvalidWeights + } + return &ScorerDefault{params: params}, nil +} diff --git a/proxy-router/internal/rating/scorer_default_mock.go b/proxy-router/internal/rating/scorer_default_mock.go new file mode 100644 index 00000000..19468e24 --- /dev/null +++ b/proxy-router/internal/rating/scorer_default_mock.go @@ -0,0 +1,11 @@ +package rating + +func ScorerDefaultParamsMock() ScorerDefaultParams { + var sc = ScorerDefaultParams{} + sc.Weights.Duration = 0.24 + sc.Weights.Stake = 0.12 + sc.Weights.Success = 0.32 + sc.Weights.TPS = 0.24 + sc.Weights.TTFT = 0.08 + return sc +} diff --git a/proxy-router/internal/rating/scorer_default_test.go b/proxy-router/internal/rating/scorer_default_test.go new file mode 100644 index 00000000..655d78db --- /dev/null +++ b/proxy-router/internal/rating/scorer_default_test.go @@ -0,0 +1,169 @@ +package rating + +import ( + "fmt" + "math" + "testing" + + "github.com/stretchr/testify/require" +) + +func TestParseConfig(t *testing.T) { + cfg := `{"weights":{"tps":0.24,"ttft":0.08,"duration":0.24,"success":0.32,"stake":0.12}}` + k, err := NewScorerDefaultFromJSON([]byte(cfg)) + require.NoError(t, err) + fmt.Printf("%+v", k) +} + +func TestZeroObservations(t *testing.T) { + sc := NewScorerDefault(ScorerDefaultParamsMock()) + args := NewScoreArgs() + args.PricePerSecond.SetUint64(1) + + score := sc.GetScore(args) + + require.NotEqual(t, math.NaN(), score) + require.NotEqual(t, math.Inf(0), score) + require.NotEqual(t, math.Inf(-1), score) +} + +func TestPriceIncrease(t *testing.T) { + sc := NewScorerDefault(ScorerDefaultParamsMock()) + args := NewScoreArgs() + args.PricePerSecond.SetUint64(1) + + score1 := sc.GetScore(args) + + args.PricePerSecond.SetUint64(2) + score2 := sc.GetScore(args) + + require.Greater(t, score1, score2) +} + +func TestFirstTTFTObservation(t *testing.T) { + // when there is only one observation, of in rare case few with same values + // the score should be the same (because standard deviation is 0) + sc := NewScorerDefault(ScorerDefaultParamsMock()) + args := NewScoreArgs() + args.PricePerSecond.SetUint64(10000000000000000) + + args.ProviderModel.TtftMs.Mean = 100 + args.ProviderModel.TotalCount = 1 + args.ProviderModel.SuccessCount = 1 + args.Model.Count = 1 + score1 := sc.GetScore(args) + + args.ProviderModel.TtftMs.Mean = 200 + args.ProviderModel.TotalCount = 1 + args.ProviderModel.SuccessCount = 1 + args.Model.Count = 1 + score2 := sc.GetScore(args) + + require.Equal(t, score1, score2) +} + +func TestTPSImpact(t *testing.T) { + sc := NewScorerDefault(ScorerDefaultParamsMock()) + args := NewScoreArgs() + args.PricePerSecond.SetUint64(10000000000000000) + + args.Model.Count = 2 + args.Model.TpsScaled1000.Mean = 100 + args.Model.TpsScaled1000.SqSum = 1000 + + args.ProviderModel.TpsScaled1000.Mean = 100 + args.ProviderModel.TotalCount = 1 + args.ProviderModel.SuccessCount = 1 + score1 := sc.GetScore(args) + + args.ProviderModel.TpsScaled1000.Mean = 150 + args.ProviderModel.TotalCount = 1 + args.ProviderModel.SuccessCount = 1 + score2 := sc.GetScore(args) + + require.Less(t, score1, score2) +} + +func TestTTFTImpact(t *testing.T) { + // when there is more than one observation, larger ttft should produce lower score + sc := NewScorerDefault(ScorerDefaultParamsMock()) + args := NewScoreArgs() + args.PricePerSecond.SetUint64(10000000000000000) + + args.Model.Count = 2 + args.Model.TtftMs.Mean = 100 + args.Model.TtftMs.SqSum = 1000 + + args.ProviderModel.TtftMs.Mean = 100 + args.ProviderModel.TotalCount = 1 + args.ProviderModel.SuccessCount = 1 + score1 := sc.GetScore(args) + + args.ProviderModel.TtftMs.Mean = 150 + args.ProviderModel.TotalCount = 1 + args.ProviderModel.SuccessCount = 1 + score2 := sc.GetScore(args) + + require.Greater(t, score1, score2) +} + +func TestSuccessScoreImpact(t *testing.T) { + sc := NewScorerDefault(ScorerDefaultParamsMock()) + args := NewScoreArgs() + args.PricePerSecond.SetUint64(10000000000000000) + args.Model.Count = 2 + + args.ProviderModel.TotalCount = 2 + args.ProviderModel.SuccessCount = 1 + score1 := sc.GetScore(args) + + args.ProviderModel.SuccessCount = 2 + score2 := sc.GetScore(args) + + require.Less(t, score1, score2) +} + +func TestStakeScoreImpact(t *testing.T) { + sc := NewScorerDefault(ScorerDefaultParamsMock()) + args := NewScoreArgs() + args.PricePerSecond.SetUint64(10000000000000000) + args.MinStake.SetUint64(1) + + args.ProviderStake.SetUint64(2) + score1 := sc.GetScore(args) + + args.ProviderStake.SetUint64(3) + score2 := sc.GetScore(args) + + require.Less(t, score1, score2) +} + +func TestStakeScoreImpactLimit(t *testing.T) { + // stake score should be capped at 10x min stake + sc := NewScorerDefault(ScorerDefaultParamsMock()) + args := NewScoreArgs() + args.PricePerSecond.SetUint64(10000000000000000) + minStake := uint64(10) + args.MinStake.SetUint64(minStake) + + args.ProviderStake.SetUint64(10 * minStake) + score1 := sc.GetScore(args) + + args.ProviderStake.SetUint64(11 * minStake) + score2 := sc.GetScore(args) + + require.Equal(t, score1, score2) +} + +func TestPriceImpact(t *testing.T) { + sc := NewScorerDefault(ScorerDefaultParamsMock()) + args := NewScoreArgs() + args.PricePerSecond.SetUint64(10000000000000000) + + score1 := sc.GetScore(args) + + args.PricePerSecond.SetUint64(20000000000000000) + score2 := sc.GetScore(args) + + require.Greater(t, score1, score2) +} diff --git a/proxy-router/internal/repositories/contracts/bindings/delegation/Delegation.go b/proxy-router/internal/repositories/contracts/bindings/delegation/Delegation.go new file mode 100644 index 00000000..5ad4ea1e --- /dev/null +++ b/proxy-router/internal/repositories/contracts/bindings/delegation/Delegation.go @@ -0,0 +1,770 @@ +// Code generated - DO NOT EDIT. +// This file is a generated binding and any manual changes will be lost. + +package delegation + +import ( + "errors" + "math/big" + "strings" + + ethereum "github.com/ethereum/go-ethereum" + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/event" +) + +// Reference imports to suppress errors if they are not otherwise used. +var ( + _ = errors.New + _ = big.NewInt + _ = strings.NewReader + _ = ethereum.NotFound + _ = bind.Bind + _ = common.Big1 + _ = types.BloomLookup + _ = event.NewSubscription + _ = abi.ConvertType +) + +// DelegationMetaData contains all meta data concerning the Delegation contract. +var DelegationMetaData = &bind.MetaData{ + ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"delegator\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"delegatee\",\"type\":\"address\"}],\"name\":\"InsufficientRightsForOperation\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account_\",\"type\":\"address\"}],\"name\":\"OwnableUnauthorizedAccount\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"registry\",\"type\":\"address\"}],\"name\":\"DelegationRegistryUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"storageSlot\",\"type\":\"bytes32\"}],\"name\":\"Initialized\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"DELEGATION_RULES_MARKETPLACE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"DELEGATION_RULES_MODEL\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"DELEGATION_RULES_PROVIDER\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"DELEGATION_RULES_SESSION\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"DELEGATION_STORAGE_SLOT\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"DIAMOND_OWNABLE_STORAGE_SLOT\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"registry_\",\"type\":\"address\"}],\"name\":\"__Delegation_init\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getRegistry\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"delegatee_\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"delegator_\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"rights_\",\"type\":\"bytes32\"}],\"name\":\"isRightsDelegated\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"registry_\",\"type\":\"address\"}],\"name\":\"setRegistry\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", +} + +// DelegationABI is the input ABI used to generate the binding from. +// Deprecated: Use DelegationMetaData.ABI instead. +var DelegationABI = DelegationMetaData.ABI + +// Delegation is an auto generated Go binding around an Ethereum contract. +type Delegation struct { + DelegationCaller // Read-only binding to the contract + DelegationTransactor // Write-only binding to the contract + DelegationFilterer // Log filterer for contract events +} + +// DelegationCaller is an auto generated read-only Go binding around an Ethereum contract. +type DelegationCaller struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// DelegationTransactor is an auto generated write-only Go binding around an Ethereum contract. +type DelegationTransactor struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// DelegationFilterer is an auto generated log filtering Go binding around an Ethereum contract events. +type DelegationFilterer struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// DelegationSession is an auto generated Go binding around an Ethereum contract, +// with pre-set call and transact options. +type DelegationSession struct { + Contract *Delegation // Generic contract binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// DelegationCallerSession is an auto generated read-only Go binding around an Ethereum contract, +// with pre-set call options. +type DelegationCallerSession struct { + Contract *DelegationCaller // Generic contract caller binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session +} + +// DelegationTransactorSession is an auto generated write-only Go binding around an Ethereum contract, +// with pre-set transact options. +type DelegationTransactorSession struct { + Contract *DelegationTransactor // Generic contract transactor binding to set the session for + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// DelegationRaw is an auto generated low-level Go binding around an Ethereum contract. +type DelegationRaw struct { + Contract *Delegation // Generic contract binding to access the raw methods on +} + +// DelegationCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. +type DelegationCallerRaw struct { + Contract *DelegationCaller // Generic read-only contract binding to access the raw methods on +} + +// DelegationTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. +type DelegationTransactorRaw struct { + Contract *DelegationTransactor // Generic write-only contract binding to access the raw methods on +} + +// NewDelegation creates a new instance of Delegation, bound to a specific deployed contract. +func NewDelegation(address common.Address, backend bind.ContractBackend) (*Delegation, error) { + contract, err := bindDelegation(address, backend, backend, backend) + if err != nil { + return nil, err + } + return &Delegation{DelegationCaller: DelegationCaller{contract: contract}, DelegationTransactor: DelegationTransactor{contract: contract}, DelegationFilterer: DelegationFilterer{contract: contract}}, nil +} + +// NewDelegationCaller creates a new read-only instance of Delegation, bound to a specific deployed contract. +func NewDelegationCaller(address common.Address, caller bind.ContractCaller) (*DelegationCaller, error) { + contract, err := bindDelegation(address, caller, nil, nil) + if err != nil { + return nil, err + } + return &DelegationCaller{contract: contract}, nil +} + +// NewDelegationTransactor creates a new write-only instance of Delegation, bound to a specific deployed contract. +func NewDelegationTransactor(address common.Address, transactor bind.ContractTransactor) (*DelegationTransactor, error) { + contract, err := bindDelegation(address, nil, transactor, nil) + if err != nil { + return nil, err + } + return &DelegationTransactor{contract: contract}, nil +} + +// NewDelegationFilterer creates a new log filterer instance of Delegation, bound to a specific deployed contract. +func NewDelegationFilterer(address common.Address, filterer bind.ContractFilterer) (*DelegationFilterer, error) { + contract, err := bindDelegation(address, nil, nil, filterer) + if err != nil { + return nil, err + } + return &DelegationFilterer{contract: contract}, nil +} + +// bindDelegation binds a generic wrapper to an already deployed contract. +func bindDelegation(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { + parsed, err := DelegationMetaData.GetAbi() + if err != nil { + return nil, err + } + return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_Delegation *DelegationRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _Delegation.Contract.DelegationCaller.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_Delegation *DelegationRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _Delegation.Contract.DelegationTransactor.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_Delegation *DelegationRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _Delegation.Contract.DelegationTransactor.contract.Transact(opts, method, params...) +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_Delegation *DelegationCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _Delegation.Contract.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_Delegation *DelegationTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _Delegation.Contract.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_Delegation *DelegationTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _Delegation.Contract.contract.Transact(opts, method, params...) +} + +// DELEGATIONRULESMARKETPLACE is a free data retrieval call binding the contract method 0xad34a150. +// +// Solidity: function DELEGATION_RULES_MARKETPLACE() view returns(bytes32) +func (_Delegation *DelegationCaller) DELEGATIONRULESMARKETPLACE(opts *bind.CallOpts) ([32]byte, error) { + var out []interface{} + err := _Delegation.contract.Call(opts, &out, "DELEGATION_RULES_MARKETPLACE") + + if err != nil { + return *new([32]byte), err + } + + out0 := *abi.ConvertType(out[0], new([32]byte)).(*[32]byte) + + return out0, err + +} + +// DELEGATIONRULESMARKETPLACE is a free data retrieval call binding the contract method 0xad34a150. +// +// Solidity: function DELEGATION_RULES_MARKETPLACE() view returns(bytes32) +func (_Delegation *DelegationSession) DELEGATIONRULESMARKETPLACE() ([32]byte, error) { + return _Delegation.Contract.DELEGATIONRULESMARKETPLACE(&_Delegation.CallOpts) +} + +// DELEGATIONRULESMARKETPLACE is a free data retrieval call binding the contract method 0xad34a150. +// +// Solidity: function DELEGATION_RULES_MARKETPLACE() view returns(bytes32) +func (_Delegation *DelegationCallerSession) DELEGATIONRULESMARKETPLACE() ([32]byte, error) { + return _Delegation.Contract.DELEGATIONRULESMARKETPLACE(&_Delegation.CallOpts) +} + +// DELEGATIONRULESMODEL is a free data retrieval call binding the contract method 0x86878047. +// +// Solidity: function DELEGATION_RULES_MODEL() view returns(bytes32) +func (_Delegation *DelegationCaller) DELEGATIONRULESMODEL(opts *bind.CallOpts) ([32]byte, error) { + var out []interface{} + err := _Delegation.contract.Call(opts, &out, "DELEGATION_RULES_MODEL") + + if err != nil { + return *new([32]byte), err + } + + out0 := *abi.ConvertType(out[0], new([32]byte)).(*[32]byte) + + return out0, err + +} + +// DELEGATIONRULESMODEL is a free data retrieval call binding the contract method 0x86878047. +// +// Solidity: function DELEGATION_RULES_MODEL() view returns(bytes32) +func (_Delegation *DelegationSession) DELEGATIONRULESMODEL() ([32]byte, error) { + return _Delegation.Contract.DELEGATIONRULESMODEL(&_Delegation.CallOpts) +} + +// DELEGATIONRULESMODEL is a free data retrieval call binding the contract method 0x86878047. +// +// Solidity: function DELEGATION_RULES_MODEL() view returns(bytes32) +func (_Delegation *DelegationCallerSession) DELEGATIONRULESMODEL() ([32]byte, error) { + return _Delegation.Contract.DELEGATIONRULESMODEL(&_Delegation.CallOpts) +} + +// DELEGATIONRULESPROVIDER is a free data retrieval call binding the contract method 0x58aeef93. +// +// Solidity: function DELEGATION_RULES_PROVIDER() view returns(bytes32) +func (_Delegation *DelegationCaller) DELEGATIONRULESPROVIDER(opts *bind.CallOpts) ([32]byte, error) { + var out []interface{} + err := _Delegation.contract.Call(opts, &out, "DELEGATION_RULES_PROVIDER") + + if err != nil { + return *new([32]byte), err + } + + out0 := *abi.ConvertType(out[0], new([32]byte)).(*[32]byte) + + return out0, err + +} + +// DELEGATIONRULESPROVIDER is a free data retrieval call binding the contract method 0x58aeef93. +// +// Solidity: function DELEGATION_RULES_PROVIDER() view returns(bytes32) +func (_Delegation *DelegationSession) DELEGATIONRULESPROVIDER() ([32]byte, error) { + return _Delegation.Contract.DELEGATIONRULESPROVIDER(&_Delegation.CallOpts) +} + +// DELEGATIONRULESPROVIDER is a free data retrieval call binding the contract method 0x58aeef93. +// +// Solidity: function DELEGATION_RULES_PROVIDER() view returns(bytes32) +func (_Delegation *DelegationCallerSession) DELEGATIONRULESPROVIDER() ([32]byte, error) { + return _Delegation.Contract.DELEGATIONRULESPROVIDER(&_Delegation.CallOpts) +} + +// DELEGATIONRULESSESSION is a free data retrieval call binding the contract method 0xd1b43638. +// +// Solidity: function DELEGATION_RULES_SESSION() view returns(bytes32) +func (_Delegation *DelegationCaller) DELEGATIONRULESSESSION(opts *bind.CallOpts) ([32]byte, error) { + var out []interface{} + err := _Delegation.contract.Call(opts, &out, "DELEGATION_RULES_SESSION") + + if err != nil { + return *new([32]byte), err + } + + out0 := *abi.ConvertType(out[0], new([32]byte)).(*[32]byte) + + return out0, err + +} + +// DELEGATIONRULESSESSION is a free data retrieval call binding the contract method 0xd1b43638. +// +// Solidity: function DELEGATION_RULES_SESSION() view returns(bytes32) +func (_Delegation *DelegationSession) DELEGATIONRULESSESSION() ([32]byte, error) { + return _Delegation.Contract.DELEGATIONRULESSESSION(&_Delegation.CallOpts) +} + +// DELEGATIONRULESSESSION is a free data retrieval call binding the contract method 0xd1b43638. +// +// Solidity: function DELEGATION_RULES_SESSION() view returns(bytes32) +func (_Delegation *DelegationCallerSession) DELEGATIONRULESSESSION() ([32]byte, error) { + return _Delegation.Contract.DELEGATIONRULESSESSION(&_Delegation.CallOpts) +} + +// DELEGATIONSTORAGESLOT is a free data retrieval call binding the contract method 0xdd9b48cb. +// +// Solidity: function DELEGATION_STORAGE_SLOT() view returns(bytes32) +func (_Delegation *DelegationCaller) DELEGATIONSTORAGESLOT(opts *bind.CallOpts) ([32]byte, error) { + var out []interface{} + err := _Delegation.contract.Call(opts, &out, "DELEGATION_STORAGE_SLOT") + + if err != nil { + return *new([32]byte), err + } + + out0 := *abi.ConvertType(out[0], new([32]byte)).(*[32]byte) + + return out0, err + +} + +// DELEGATIONSTORAGESLOT is a free data retrieval call binding the contract method 0xdd9b48cb. +// +// Solidity: function DELEGATION_STORAGE_SLOT() view returns(bytes32) +func (_Delegation *DelegationSession) DELEGATIONSTORAGESLOT() ([32]byte, error) { + return _Delegation.Contract.DELEGATIONSTORAGESLOT(&_Delegation.CallOpts) +} + +// DELEGATIONSTORAGESLOT is a free data retrieval call binding the contract method 0xdd9b48cb. +// +// Solidity: function DELEGATION_STORAGE_SLOT() view returns(bytes32) +func (_Delegation *DelegationCallerSession) DELEGATIONSTORAGESLOT() ([32]byte, error) { + return _Delegation.Contract.DELEGATIONSTORAGESLOT(&_Delegation.CallOpts) +} + +// DIAMONDOWNABLESTORAGESLOT is a free data retrieval call binding the contract method 0x4ac3371e. +// +// Solidity: function DIAMOND_OWNABLE_STORAGE_SLOT() view returns(bytes32) +func (_Delegation *DelegationCaller) DIAMONDOWNABLESTORAGESLOT(opts *bind.CallOpts) ([32]byte, error) { + var out []interface{} + err := _Delegation.contract.Call(opts, &out, "DIAMOND_OWNABLE_STORAGE_SLOT") + + if err != nil { + return *new([32]byte), err + } + + out0 := *abi.ConvertType(out[0], new([32]byte)).(*[32]byte) + + return out0, err + +} + +// DIAMONDOWNABLESTORAGESLOT is a free data retrieval call binding the contract method 0x4ac3371e. +// +// Solidity: function DIAMOND_OWNABLE_STORAGE_SLOT() view returns(bytes32) +func (_Delegation *DelegationSession) DIAMONDOWNABLESTORAGESLOT() ([32]byte, error) { + return _Delegation.Contract.DIAMONDOWNABLESTORAGESLOT(&_Delegation.CallOpts) +} + +// DIAMONDOWNABLESTORAGESLOT is a free data retrieval call binding the contract method 0x4ac3371e. +// +// Solidity: function DIAMOND_OWNABLE_STORAGE_SLOT() view returns(bytes32) +func (_Delegation *DelegationCallerSession) DIAMONDOWNABLESTORAGESLOT() ([32]byte, error) { + return _Delegation.Contract.DIAMONDOWNABLESTORAGESLOT(&_Delegation.CallOpts) +} + +// GetRegistry is a free data retrieval call binding the contract method 0x5ab1bd53. +// +// Solidity: function getRegistry() view returns(address) +func (_Delegation *DelegationCaller) GetRegistry(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _Delegation.contract.Call(opts, &out, "getRegistry") + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +// GetRegistry is a free data retrieval call binding the contract method 0x5ab1bd53. +// +// Solidity: function getRegistry() view returns(address) +func (_Delegation *DelegationSession) GetRegistry() (common.Address, error) { + return _Delegation.Contract.GetRegistry(&_Delegation.CallOpts) +} + +// GetRegistry is a free data retrieval call binding the contract method 0x5ab1bd53. +// +// Solidity: function getRegistry() view returns(address) +func (_Delegation *DelegationCallerSession) GetRegistry() (common.Address, error) { + return _Delegation.Contract.GetRegistry(&_Delegation.CallOpts) +} + +// IsRightsDelegated is a free data retrieval call binding the contract method 0x54126b8f. +// +// Solidity: function isRightsDelegated(address delegatee_, address delegator_, bytes32 rights_) view returns(bool) +func (_Delegation *DelegationCaller) IsRightsDelegated(opts *bind.CallOpts, delegatee_ common.Address, delegator_ common.Address, rights_ [32]byte) (bool, error) { + var out []interface{} + err := _Delegation.contract.Call(opts, &out, "isRightsDelegated", delegatee_, delegator_, rights_) + + if err != nil { + return *new(bool), err + } + + out0 := *abi.ConvertType(out[0], new(bool)).(*bool) + + return out0, err + +} + +// IsRightsDelegated is a free data retrieval call binding the contract method 0x54126b8f. +// +// Solidity: function isRightsDelegated(address delegatee_, address delegator_, bytes32 rights_) view returns(bool) +func (_Delegation *DelegationSession) IsRightsDelegated(delegatee_ common.Address, delegator_ common.Address, rights_ [32]byte) (bool, error) { + return _Delegation.Contract.IsRightsDelegated(&_Delegation.CallOpts, delegatee_, delegator_, rights_) +} + +// IsRightsDelegated is a free data retrieval call binding the contract method 0x54126b8f. +// +// Solidity: function isRightsDelegated(address delegatee_, address delegator_, bytes32 rights_) view returns(bool) +func (_Delegation *DelegationCallerSession) IsRightsDelegated(delegatee_ common.Address, delegator_ common.Address, rights_ [32]byte) (bool, error) { + return _Delegation.Contract.IsRightsDelegated(&_Delegation.CallOpts, delegatee_, delegator_, rights_) +} + +// Owner is a free data retrieval call binding the contract method 0x8da5cb5b. +// +// Solidity: function owner() view returns(address) +func (_Delegation *DelegationCaller) Owner(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _Delegation.contract.Call(opts, &out, "owner") + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +// Owner is a free data retrieval call binding the contract method 0x8da5cb5b. +// +// Solidity: function owner() view returns(address) +func (_Delegation *DelegationSession) Owner() (common.Address, error) { + return _Delegation.Contract.Owner(&_Delegation.CallOpts) +} + +// Owner is a free data retrieval call binding the contract method 0x8da5cb5b. +// +// Solidity: function owner() view returns(address) +func (_Delegation *DelegationCallerSession) Owner() (common.Address, error) { + return _Delegation.Contract.Owner(&_Delegation.CallOpts) +} + +// DelegationInit is a paid mutator transaction binding the contract method 0xe50e4c43. +// +// Solidity: function __Delegation_init(address registry_) returns() +func (_Delegation *DelegationTransactor) DelegationInit(opts *bind.TransactOpts, registry_ common.Address) (*types.Transaction, error) { + return _Delegation.contract.Transact(opts, "__Delegation_init", registry_) +} + +// DelegationInit is a paid mutator transaction binding the contract method 0xe50e4c43. +// +// Solidity: function __Delegation_init(address registry_) returns() +func (_Delegation *DelegationSession) DelegationInit(registry_ common.Address) (*types.Transaction, error) { + return _Delegation.Contract.DelegationInit(&_Delegation.TransactOpts, registry_) +} + +// DelegationInit is a paid mutator transaction binding the contract method 0xe50e4c43. +// +// Solidity: function __Delegation_init(address registry_) returns() +func (_Delegation *DelegationTransactorSession) DelegationInit(registry_ common.Address) (*types.Transaction, error) { + return _Delegation.Contract.DelegationInit(&_Delegation.TransactOpts, registry_) +} + +// SetRegistry is a paid mutator transaction binding the contract method 0xa91ee0dc. +// +// Solidity: function setRegistry(address registry_) returns() +func (_Delegation *DelegationTransactor) SetRegistry(opts *bind.TransactOpts, registry_ common.Address) (*types.Transaction, error) { + return _Delegation.contract.Transact(opts, "setRegistry", registry_) +} + +// SetRegistry is a paid mutator transaction binding the contract method 0xa91ee0dc. +// +// Solidity: function setRegistry(address registry_) returns() +func (_Delegation *DelegationSession) SetRegistry(registry_ common.Address) (*types.Transaction, error) { + return _Delegation.Contract.SetRegistry(&_Delegation.TransactOpts, registry_) +} + +// SetRegistry is a paid mutator transaction binding the contract method 0xa91ee0dc. +// +// Solidity: function setRegistry(address registry_) returns() +func (_Delegation *DelegationTransactorSession) SetRegistry(registry_ common.Address) (*types.Transaction, error) { + return _Delegation.Contract.SetRegistry(&_Delegation.TransactOpts, registry_) +} + +// DelegationDelegationRegistryUpdatedIterator is returned from FilterDelegationRegistryUpdated and is used to iterate over the raw logs and unpacked data for DelegationRegistryUpdated events raised by the Delegation contract. +type DelegationDelegationRegistryUpdatedIterator struct { + Event *DelegationDelegationRegistryUpdated // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *DelegationDelegationRegistryUpdatedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(DelegationDelegationRegistryUpdated) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(DelegationDelegationRegistryUpdated) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *DelegationDelegationRegistryUpdatedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *DelegationDelegationRegistryUpdatedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// DelegationDelegationRegistryUpdated represents a DelegationRegistryUpdated event raised by the Delegation contract. +type DelegationDelegationRegistryUpdated struct { + Registry common.Address + Raw types.Log // Blockchain specific contextual infos +} + +// FilterDelegationRegistryUpdated is a free log retrieval operation binding the contract event 0x836360d1b094a7de3c3eab3d1185f3a5939467c23d4a12709dbdbf8c8d7e2f3b. +// +// Solidity: event DelegationRegistryUpdated(address registry) +func (_Delegation *DelegationFilterer) FilterDelegationRegistryUpdated(opts *bind.FilterOpts) (*DelegationDelegationRegistryUpdatedIterator, error) { + + logs, sub, err := _Delegation.contract.FilterLogs(opts, "DelegationRegistryUpdated") + if err != nil { + return nil, err + } + return &DelegationDelegationRegistryUpdatedIterator{contract: _Delegation.contract, event: "DelegationRegistryUpdated", logs: logs, sub: sub}, nil +} + +// WatchDelegationRegistryUpdated is a free log subscription operation binding the contract event 0x836360d1b094a7de3c3eab3d1185f3a5939467c23d4a12709dbdbf8c8d7e2f3b. +// +// Solidity: event DelegationRegistryUpdated(address registry) +func (_Delegation *DelegationFilterer) WatchDelegationRegistryUpdated(opts *bind.WatchOpts, sink chan<- *DelegationDelegationRegistryUpdated) (event.Subscription, error) { + + logs, sub, err := _Delegation.contract.WatchLogs(opts, "DelegationRegistryUpdated") + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(DelegationDelegationRegistryUpdated) + if err := _Delegation.contract.UnpackLog(event, "DelegationRegistryUpdated", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseDelegationRegistryUpdated is a log parse operation binding the contract event 0x836360d1b094a7de3c3eab3d1185f3a5939467c23d4a12709dbdbf8c8d7e2f3b. +// +// Solidity: event DelegationRegistryUpdated(address registry) +func (_Delegation *DelegationFilterer) ParseDelegationRegistryUpdated(log types.Log) (*DelegationDelegationRegistryUpdated, error) { + event := new(DelegationDelegationRegistryUpdated) + if err := _Delegation.contract.UnpackLog(event, "DelegationRegistryUpdated", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// DelegationInitializedIterator is returned from FilterInitialized and is used to iterate over the raw logs and unpacked data for Initialized events raised by the Delegation contract. +type DelegationInitializedIterator struct { + Event *DelegationInitialized // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *DelegationInitializedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(DelegationInitialized) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(DelegationInitialized) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *DelegationInitializedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *DelegationInitializedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// DelegationInitialized represents a Initialized event raised by the Delegation contract. +type DelegationInitialized struct { + StorageSlot [32]byte + Raw types.Log // Blockchain specific contextual infos +} + +// FilterInitialized is a free log retrieval operation binding the contract event 0xdc73717d728bcfa015e8117438a65319aa06e979ca324afa6e1ea645c28ea15d. +// +// Solidity: event Initialized(bytes32 storageSlot) +func (_Delegation *DelegationFilterer) FilterInitialized(opts *bind.FilterOpts) (*DelegationInitializedIterator, error) { + + logs, sub, err := _Delegation.contract.FilterLogs(opts, "Initialized") + if err != nil { + return nil, err + } + return &DelegationInitializedIterator{contract: _Delegation.contract, event: "Initialized", logs: logs, sub: sub}, nil +} + +// WatchInitialized is a free log subscription operation binding the contract event 0xdc73717d728bcfa015e8117438a65319aa06e979ca324afa6e1ea645c28ea15d. +// +// Solidity: event Initialized(bytes32 storageSlot) +func (_Delegation *DelegationFilterer) WatchInitialized(opts *bind.WatchOpts, sink chan<- *DelegationInitialized) (event.Subscription, error) { + + logs, sub, err := _Delegation.contract.WatchLogs(opts, "Initialized") + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(DelegationInitialized) + if err := _Delegation.contract.UnpackLog(event, "Initialized", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseInitialized is a log parse operation binding the contract event 0xdc73717d728bcfa015e8117438a65319aa06e979ca324afa6e1ea645c28ea15d. +// +// Solidity: event Initialized(bytes32 storageSlot) +func (_Delegation *DelegationFilterer) ParseInitialized(log types.Log) (*DelegationInitialized, error) { + event := new(DelegationInitialized) + if err := _Delegation.contract.UnpackLog(event, "Initialized", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} diff --git a/proxy-router/contracts/lumerintoken/LumerinToken.go b/proxy-router/internal/repositories/contracts/bindings/lumerintoken/LumerinToken.go similarity index 75% rename from proxy-router/contracts/lumerintoken/LumerinToken.go rename to proxy-router/internal/repositories/contracts/bindings/lumerintoken/LumerinToken.go index 25e5b9e5..f498411c 100644 --- a/proxy-router/contracts/lumerintoken/LumerinToken.go +++ b/proxy-router/internal/repositories/contracts/bindings/lumerintoken/LumerinToken.go @@ -31,7 +31,7 @@ var ( // LumerinTokenMetaData contains all meta data concerning the LumerinToken contract. var LumerinTokenMetaData = &bind.MetaData{ - ABI: "[{\"inputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"allowance\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"needed\",\"type\":\"uint256\"}],\"name\":\"ERC20InsufficientAllowance\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"balance\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"needed\",\"type\":\"uint256\"}],\"name\":\"ERC20InsufficientBalance\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"approver\",\"type\":\"address\"}],\"name\":\"ERC20InvalidApprover\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"}],\"name\":\"ERC20InvalidReceiver\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"ERC20InvalidSender\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"}],\"name\":\"ERC20InvalidSpender\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"Approval\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"Transfer\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"}],\"name\":\"allowance\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"approve\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"balanceOf\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"decimals\",\"outputs\":[{\"internalType\":\"uint8\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"name\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"symbol\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"totalSupply\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"transfer\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"transferFrom\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", + ABI: "[{\"inputs\":[{\"internalType\":\"string\",\"name\":\"name_\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"symbol_\",\"type\":\"string\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"Approval\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"Transfer\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"INITIAL_SUPPLUY\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"}],\"name\":\"allowance\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"approve\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"balanceOf\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"decimals\",\"outputs\":[{\"internalType\":\"uint8\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"subtractedValue\",\"type\":\"uint256\"}],\"name\":\"decreaseAllowance\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"addedValue\",\"type\":\"uint256\"}],\"name\":\"increaseAllowance\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"name\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"symbol\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"totalSupply\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"transfer\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"transferFrom\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", } // LumerinTokenABI is the input ABI used to generate the binding from. @@ -180,6 +180,37 @@ func (_LumerinToken *LumerinTokenTransactorRaw) Transact(opts *bind.TransactOpts return _LumerinToken.Contract.contract.Transact(opts, method, params...) } +// INITIALSUPPLUY is a free data retrieval call binding the contract method 0x5ce0b492. +// +// Solidity: function INITIAL_SUPPLUY() view returns(uint256) +func (_LumerinToken *LumerinTokenCaller) INITIALSUPPLUY(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _LumerinToken.contract.Call(opts, &out, "INITIAL_SUPPLUY") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// INITIALSUPPLUY is a free data retrieval call binding the contract method 0x5ce0b492. +// +// Solidity: function INITIAL_SUPPLUY() view returns(uint256) +func (_LumerinToken *LumerinTokenSession) INITIALSUPPLUY() (*big.Int, error) { + return _LumerinToken.Contract.INITIALSUPPLUY(&_LumerinToken.CallOpts) +} + +// INITIALSUPPLUY is a free data retrieval call binding the contract method 0x5ce0b492. +// +// Solidity: function INITIAL_SUPPLUY() view returns(uint256) +func (_LumerinToken *LumerinTokenCallerSession) INITIALSUPPLUY() (*big.Int, error) { + return _LumerinToken.Contract.INITIALSUPPLUY(&_LumerinToken.CallOpts) +} + // Allowance is a free data retrieval call binding the contract method 0xdd62ed3e. // // Solidity: function allowance(address owner, address spender) view returns(uint256) @@ -368,65 +399,107 @@ func (_LumerinToken *LumerinTokenCallerSession) TotalSupply() (*big.Int, error) // Approve is a paid mutator transaction binding the contract method 0x095ea7b3. // -// Solidity: function approve(address spender, uint256 value) returns(bool) -func (_LumerinToken *LumerinTokenTransactor) Approve(opts *bind.TransactOpts, spender common.Address, value *big.Int) (*types.Transaction, error) { - return _LumerinToken.contract.Transact(opts, "approve", spender, value) +// Solidity: function approve(address spender, uint256 amount) returns(bool) +func (_LumerinToken *LumerinTokenTransactor) Approve(opts *bind.TransactOpts, spender common.Address, amount *big.Int) (*types.Transaction, error) { + return _LumerinToken.contract.Transact(opts, "approve", spender, amount) } // Approve is a paid mutator transaction binding the contract method 0x095ea7b3. // -// Solidity: function approve(address spender, uint256 value) returns(bool) -func (_LumerinToken *LumerinTokenSession) Approve(spender common.Address, value *big.Int) (*types.Transaction, error) { - return _LumerinToken.Contract.Approve(&_LumerinToken.TransactOpts, spender, value) +// Solidity: function approve(address spender, uint256 amount) returns(bool) +func (_LumerinToken *LumerinTokenSession) Approve(spender common.Address, amount *big.Int) (*types.Transaction, error) { + return _LumerinToken.Contract.Approve(&_LumerinToken.TransactOpts, spender, amount) } // Approve is a paid mutator transaction binding the contract method 0x095ea7b3. // -// Solidity: function approve(address spender, uint256 value) returns(bool) -func (_LumerinToken *LumerinTokenTransactorSession) Approve(spender common.Address, value *big.Int) (*types.Transaction, error) { - return _LumerinToken.Contract.Approve(&_LumerinToken.TransactOpts, spender, value) +// Solidity: function approve(address spender, uint256 amount) returns(bool) +func (_LumerinToken *LumerinTokenTransactorSession) Approve(spender common.Address, amount *big.Int) (*types.Transaction, error) { + return _LumerinToken.Contract.Approve(&_LumerinToken.TransactOpts, spender, amount) +} + +// DecreaseAllowance is a paid mutator transaction binding the contract method 0xa457c2d7. +// +// Solidity: function decreaseAllowance(address spender, uint256 subtractedValue) returns(bool) +func (_LumerinToken *LumerinTokenTransactor) DecreaseAllowance(opts *bind.TransactOpts, spender common.Address, subtractedValue *big.Int) (*types.Transaction, error) { + return _LumerinToken.contract.Transact(opts, "decreaseAllowance", spender, subtractedValue) +} + +// DecreaseAllowance is a paid mutator transaction binding the contract method 0xa457c2d7. +// +// Solidity: function decreaseAllowance(address spender, uint256 subtractedValue) returns(bool) +func (_LumerinToken *LumerinTokenSession) DecreaseAllowance(spender common.Address, subtractedValue *big.Int) (*types.Transaction, error) { + return _LumerinToken.Contract.DecreaseAllowance(&_LumerinToken.TransactOpts, spender, subtractedValue) +} + +// DecreaseAllowance is a paid mutator transaction binding the contract method 0xa457c2d7. +// +// Solidity: function decreaseAllowance(address spender, uint256 subtractedValue) returns(bool) +func (_LumerinToken *LumerinTokenTransactorSession) DecreaseAllowance(spender common.Address, subtractedValue *big.Int) (*types.Transaction, error) { + return _LumerinToken.Contract.DecreaseAllowance(&_LumerinToken.TransactOpts, spender, subtractedValue) +} + +// IncreaseAllowance is a paid mutator transaction binding the contract method 0x39509351. +// +// Solidity: function increaseAllowance(address spender, uint256 addedValue) returns(bool) +func (_LumerinToken *LumerinTokenTransactor) IncreaseAllowance(opts *bind.TransactOpts, spender common.Address, addedValue *big.Int) (*types.Transaction, error) { + return _LumerinToken.contract.Transact(opts, "increaseAllowance", spender, addedValue) +} + +// IncreaseAllowance is a paid mutator transaction binding the contract method 0x39509351. +// +// Solidity: function increaseAllowance(address spender, uint256 addedValue) returns(bool) +func (_LumerinToken *LumerinTokenSession) IncreaseAllowance(spender common.Address, addedValue *big.Int) (*types.Transaction, error) { + return _LumerinToken.Contract.IncreaseAllowance(&_LumerinToken.TransactOpts, spender, addedValue) +} + +// IncreaseAllowance is a paid mutator transaction binding the contract method 0x39509351. +// +// Solidity: function increaseAllowance(address spender, uint256 addedValue) returns(bool) +func (_LumerinToken *LumerinTokenTransactorSession) IncreaseAllowance(spender common.Address, addedValue *big.Int) (*types.Transaction, error) { + return _LumerinToken.Contract.IncreaseAllowance(&_LumerinToken.TransactOpts, spender, addedValue) } // Transfer is a paid mutator transaction binding the contract method 0xa9059cbb. // -// Solidity: function transfer(address to, uint256 value) returns(bool) -func (_LumerinToken *LumerinTokenTransactor) Transfer(opts *bind.TransactOpts, to common.Address, value *big.Int) (*types.Transaction, error) { - return _LumerinToken.contract.Transact(opts, "transfer", to, value) +// Solidity: function transfer(address to, uint256 amount) returns(bool) +func (_LumerinToken *LumerinTokenTransactor) Transfer(opts *bind.TransactOpts, to common.Address, amount *big.Int) (*types.Transaction, error) { + return _LumerinToken.contract.Transact(opts, "transfer", to, amount) } // Transfer is a paid mutator transaction binding the contract method 0xa9059cbb. // -// Solidity: function transfer(address to, uint256 value) returns(bool) -func (_LumerinToken *LumerinTokenSession) Transfer(to common.Address, value *big.Int) (*types.Transaction, error) { - return _LumerinToken.Contract.Transfer(&_LumerinToken.TransactOpts, to, value) +// Solidity: function transfer(address to, uint256 amount) returns(bool) +func (_LumerinToken *LumerinTokenSession) Transfer(to common.Address, amount *big.Int) (*types.Transaction, error) { + return _LumerinToken.Contract.Transfer(&_LumerinToken.TransactOpts, to, amount) } // Transfer is a paid mutator transaction binding the contract method 0xa9059cbb. // -// Solidity: function transfer(address to, uint256 value) returns(bool) -func (_LumerinToken *LumerinTokenTransactorSession) Transfer(to common.Address, value *big.Int) (*types.Transaction, error) { - return _LumerinToken.Contract.Transfer(&_LumerinToken.TransactOpts, to, value) +// Solidity: function transfer(address to, uint256 amount) returns(bool) +func (_LumerinToken *LumerinTokenTransactorSession) Transfer(to common.Address, amount *big.Int) (*types.Transaction, error) { + return _LumerinToken.Contract.Transfer(&_LumerinToken.TransactOpts, to, amount) } // TransferFrom is a paid mutator transaction binding the contract method 0x23b872dd. // -// Solidity: function transferFrom(address from, address to, uint256 value) returns(bool) -func (_LumerinToken *LumerinTokenTransactor) TransferFrom(opts *bind.TransactOpts, from common.Address, to common.Address, value *big.Int) (*types.Transaction, error) { - return _LumerinToken.contract.Transact(opts, "transferFrom", from, to, value) +// Solidity: function transferFrom(address from, address to, uint256 amount) returns(bool) +func (_LumerinToken *LumerinTokenTransactor) TransferFrom(opts *bind.TransactOpts, from common.Address, to common.Address, amount *big.Int) (*types.Transaction, error) { + return _LumerinToken.contract.Transact(opts, "transferFrom", from, to, amount) } // TransferFrom is a paid mutator transaction binding the contract method 0x23b872dd. // -// Solidity: function transferFrom(address from, address to, uint256 value) returns(bool) -func (_LumerinToken *LumerinTokenSession) TransferFrom(from common.Address, to common.Address, value *big.Int) (*types.Transaction, error) { - return _LumerinToken.Contract.TransferFrom(&_LumerinToken.TransactOpts, from, to, value) +// Solidity: function transferFrom(address from, address to, uint256 amount) returns(bool) +func (_LumerinToken *LumerinTokenSession) TransferFrom(from common.Address, to common.Address, amount *big.Int) (*types.Transaction, error) { + return _LumerinToken.Contract.TransferFrom(&_LumerinToken.TransactOpts, from, to, amount) } // TransferFrom is a paid mutator transaction binding the contract method 0x23b872dd. // -// Solidity: function transferFrom(address from, address to, uint256 value) returns(bool) -func (_LumerinToken *LumerinTokenTransactorSession) TransferFrom(from common.Address, to common.Address, value *big.Int) (*types.Transaction, error) { - return _LumerinToken.Contract.TransferFrom(&_LumerinToken.TransactOpts, from, to, value) +// Solidity: function transferFrom(address from, address to, uint256 amount) returns(bool) +func (_LumerinToken *LumerinTokenTransactorSession) TransferFrom(from common.Address, to common.Address, amount *big.Int) (*types.Transaction, error) { + return _LumerinToken.Contract.TransferFrom(&_LumerinToken.TransactOpts, from, to, amount) } // LumerinTokenApprovalIterator is returned from FilterApproval and is used to iterate over the raw logs and unpacked data for Approval events raised by the LumerinToken contract. diff --git a/proxy-router/internal/repositories/contracts/bindings/marketplace/Marketplace.go b/proxy-router/internal/repositories/contracts/bindings/marketplace/Marketplace.go new file mode 100644 index 00000000..a0bd4394 --- /dev/null +++ b/proxy-router/internal/repositories/contracts/bindings/marketplace/Marketplace.go @@ -0,0 +1,2112 @@ +// Code generated - DO NOT EDIT. +// This file is a generated binding and any manual changes will be lost. + +package marketplace + +import ( + "errors" + "math/big" + "strings" + + ethereum "github.com/ethereum/go-ethereum" + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/event" +) + +// Reference imports to suppress errors if they are not otherwise used. +var ( + _ = errors.New + _ = big.NewInt + _ = strings.NewReader + _ = ethereum.NotFound + _ = bind.Bind + _ = common.Big1 + _ = types.BloomLookup + _ = event.NewSubscription + _ = abi.ConvertType +) + +// IBidStorageBid is an auto generated low-level Go binding around an user-defined struct. +type IBidStorageBid struct { + Provider common.Address + ModelId [32]byte + PricePerSecond *big.Int + Nonce *big.Int + CreatedAt *big.Int + DeletedAt *big.Int +} + +// IModelStorageModel is an auto generated low-level Go binding around an user-defined struct. +type IModelStorageModel struct { + IpfsCID [32]byte + Fee *big.Int + Stake *big.Int + Owner common.Address + Name string + Tags []string + CreatedAt *big.Int + IsDeleted bool +} + +// IProviderStorageProvider is an auto generated low-level Go binding around an user-defined struct. +type IProviderStorageProvider struct { + Endpoint string + Stake *big.Int + CreatedAt *big.Int + LimitPeriodEnd *big.Int + LimitPeriodEarned *big.Int + IsDeleted bool +} + +// MarketplaceMetaData contains all meta data concerning the Marketplace contract. +var MarketplaceMetaData = &bind.MetaData{ + ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"delegator\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"delegatee\",\"type\":\"address\"}],\"name\":\"InsufficientRightsForOperation\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MarketplaceActiveBidNotFound\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MarketplaceBidMinPricePerSecondIsInvalid\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MarketplaceBidMinPricePerSecondIsZero\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MarketplaceBidPricePerSecondInvalid\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MarketplaceFeeAmountIsZero\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MarketplaceModelNotFound\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MarketplaceProviderNotFound\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account_\",\"type\":\"address\"}],\"name\":\"OwnableUnauthorizedAccount\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"storageSlot\",\"type\":\"bytes32\"}],\"name\":\"Initialized\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"bidFee\",\"type\":\"uint256\"}],\"name\":\"MaretplaceFeeUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"provider\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"modelId\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"}],\"name\":\"MarketplaceBidDeleted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"bidMinPricePerSecond\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"bidMaxPricePerSecond\",\"type\":\"uint256\"}],\"name\":\"MarketplaceBidMinMaxPriceUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"provider\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"modelId\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"}],\"name\":\"MarketplaceBidPosted\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"BIDS_STORAGE_SLOT\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"DELEGATION_RULES_MARKETPLACE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"DELEGATION_RULES_MODEL\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"DELEGATION_RULES_PROVIDER\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"DELEGATION_RULES_SESSION\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"DELEGATION_STORAGE_SLOT\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"DIAMOND_OWNABLE_STORAGE_SLOT\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"MARKET_STORAGE_SLOT\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"MODELS_STORAGE_SLOT\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"PROVIDERS_STORAGE_SLOT\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token_\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"bidMinPricePerSecond_\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"bidMaxPricePerSecond_\",\"type\":\"uint256\"}],\"name\":\"__Marketplace_init\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"bidId_\",\"type\":\"bytes32\"}],\"name\":\"deleteModelBid\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"offset_\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"limit_\",\"type\":\"uint256\"}],\"name\":\"getActiveModelIds\",\"outputs\":[{\"internalType\":\"bytes32[]\",\"name\":\"\",\"type\":\"bytes32[]\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"offset_\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"limit_\",\"type\":\"uint256\"}],\"name\":\"getActiveProviders\",\"outputs\":[{\"internalType\":\"address[]\",\"name\":\"\",\"type\":\"address[]\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"bidId_\",\"type\":\"bytes32\"}],\"name\":\"getBid\",\"outputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"provider\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"modelId\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"pricePerSecond\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"internalType\":\"uint128\",\"name\":\"createdAt\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"deletedAt\",\"type\":\"uint128\"}],\"internalType\":\"structIBidStorage.Bid\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getBidFee\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"provider_\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"modelId_\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"nonce_\",\"type\":\"uint256\"}],\"name\":\"getBidId\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getFeeBalance\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"modelId_\",\"type\":\"bytes32\"}],\"name\":\"getIsModelActive\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"provider_\",\"type\":\"address\"}],\"name\":\"getIsProviderActive\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getMinMaxBidPricePerSecond\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"modelId_\",\"type\":\"bytes32\"}],\"name\":\"getModel\",\"outputs\":[{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"ipfsCID\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"fee\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"stake\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"string\",\"name\":\"name\",\"type\":\"string\"},{\"internalType\":\"string[]\",\"name\":\"tags\",\"type\":\"string[]\"},{\"internalType\":\"uint128\",\"name\":\"createdAt\",\"type\":\"uint128\"},{\"internalType\":\"bool\",\"name\":\"isDeleted\",\"type\":\"bool\"}],\"internalType\":\"structIModelStorage.Model\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"modelId_\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"offset_\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"limit_\",\"type\":\"uint256\"}],\"name\":\"getModelActiveBids\",\"outputs\":[{\"internalType\":\"bytes32[]\",\"name\":\"\",\"type\":\"bytes32[]\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"modelId_\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"offset_\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"limit_\",\"type\":\"uint256\"}],\"name\":\"getModelBids\",\"outputs\":[{\"internalType\":\"bytes32[]\",\"name\":\"\",\"type\":\"bytes32[]\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"offset_\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"limit_\",\"type\":\"uint256\"}],\"name\":\"getModelIds\",\"outputs\":[{\"internalType\":\"bytes32[]\",\"name\":\"\",\"type\":\"bytes32[]\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getModelMinimumStake\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"provider_\",\"type\":\"address\"}],\"name\":\"getProvider\",\"outputs\":[{\"components\":[{\"internalType\":\"string\",\"name\":\"endpoint\",\"type\":\"string\"},{\"internalType\":\"uint256\",\"name\":\"stake\",\"type\":\"uint256\"},{\"internalType\":\"uint128\",\"name\":\"createdAt\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"limitPeriodEnd\",\"type\":\"uint128\"},{\"internalType\":\"uint256\",\"name\":\"limitPeriodEarned\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"isDeleted\",\"type\":\"bool\"}],\"internalType\":\"structIProviderStorage.Provider\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"provider_\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"offset_\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"limit_\",\"type\":\"uint256\"}],\"name\":\"getProviderActiveBids\",\"outputs\":[{\"internalType\":\"bytes32[]\",\"name\":\"\",\"type\":\"bytes32[]\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"provider_\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"offset_\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"limit_\",\"type\":\"uint256\"}],\"name\":\"getProviderBids\",\"outputs\":[{\"internalType\":\"bytes32[]\",\"name\":\"\",\"type\":\"bytes32[]\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getProviderMinimumStake\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"provider_\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"modelId_\",\"type\":\"bytes32\"}],\"name\":\"getProviderModelId\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getRegistry\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getToken\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"bidId_\",\"type\":\"bytes32\"}],\"name\":\"isBidActive\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"delegatee_\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"delegator_\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"rights_\",\"type\":\"bytes32\"}],\"name\":\"isRightsDelegated\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"provider_\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"modelId_\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"pricePerSecond_\",\"type\":\"uint256\"}],\"name\":\"postModelBid\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"bidId\",\"type\":\"bytes32\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"bidFee_\",\"type\":\"uint256\"}],\"name\":\"setMarketplaceBidFee\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"bidMinPricePerSecond_\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"bidMaxPricePerSecond_\",\"type\":\"uint256\"}],\"name\":\"setMinMaxBidPricePerSecond\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"recipient_\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount_\",\"type\":\"uint256\"}],\"name\":\"withdrawFee\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", +} + +// MarketplaceABI is the input ABI used to generate the binding from. +// Deprecated: Use MarketplaceMetaData.ABI instead. +var MarketplaceABI = MarketplaceMetaData.ABI + +// Marketplace is an auto generated Go binding around an Ethereum contract. +type Marketplace struct { + MarketplaceCaller // Read-only binding to the contract + MarketplaceTransactor // Write-only binding to the contract + MarketplaceFilterer // Log filterer for contract events +} + +// MarketplaceCaller is an auto generated read-only Go binding around an Ethereum contract. +type MarketplaceCaller struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// MarketplaceTransactor is an auto generated write-only Go binding around an Ethereum contract. +type MarketplaceTransactor struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// MarketplaceFilterer is an auto generated log filtering Go binding around an Ethereum contract events. +type MarketplaceFilterer struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// MarketplaceSession is an auto generated Go binding around an Ethereum contract, +// with pre-set call and transact options. +type MarketplaceSession struct { + Contract *Marketplace // Generic contract binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// MarketplaceCallerSession is an auto generated read-only Go binding around an Ethereum contract, +// with pre-set call options. +type MarketplaceCallerSession struct { + Contract *MarketplaceCaller // Generic contract caller binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session +} + +// MarketplaceTransactorSession is an auto generated write-only Go binding around an Ethereum contract, +// with pre-set transact options. +type MarketplaceTransactorSession struct { + Contract *MarketplaceTransactor // Generic contract transactor binding to set the session for + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// MarketplaceRaw is an auto generated low-level Go binding around an Ethereum contract. +type MarketplaceRaw struct { + Contract *Marketplace // Generic contract binding to access the raw methods on +} + +// MarketplaceCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. +type MarketplaceCallerRaw struct { + Contract *MarketplaceCaller // Generic read-only contract binding to access the raw methods on +} + +// MarketplaceTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. +type MarketplaceTransactorRaw struct { + Contract *MarketplaceTransactor // Generic write-only contract binding to access the raw methods on +} + +// NewMarketplace creates a new instance of Marketplace, bound to a specific deployed contract. +func NewMarketplace(address common.Address, backend bind.ContractBackend) (*Marketplace, error) { + contract, err := bindMarketplace(address, backend, backend, backend) + if err != nil { + return nil, err + } + return &Marketplace{MarketplaceCaller: MarketplaceCaller{contract: contract}, MarketplaceTransactor: MarketplaceTransactor{contract: contract}, MarketplaceFilterer: MarketplaceFilterer{contract: contract}}, nil +} + +// NewMarketplaceCaller creates a new read-only instance of Marketplace, bound to a specific deployed contract. +func NewMarketplaceCaller(address common.Address, caller bind.ContractCaller) (*MarketplaceCaller, error) { + contract, err := bindMarketplace(address, caller, nil, nil) + if err != nil { + return nil, err + } + return &MarketplaceCaller{contract: contract}, nil +} + +// NewMarketplaceTransactor creates a new write-only instance of Marketplace, bound to a specific deployed contract. +func NewMarketplaceTransactor(address common.Address, transactor bind.ContractTransactor) (*MarketplaceTransactor, error) { + contract, err := bindMarketplace(address, nil, transactor, nil) + if err != nil { + return nil, err + } + return &MarketplaceTransactor{contract: contract}, nil +} + +// NewMarketplaceFilterer creates a new log filterer instance of Marketplace, bound to a specific deployed contract. +func NewMarketplaceFilterer(address common.Address, filterer bind.ContractFilterer) (*MarketplaceFilterer, error) { + contract, err := bindMarketplace(address, nil, nil, filterer) + if err != nil { + return nil, err + } + return &MarketplaceFilterer{contract: contract}, nil +} + +// bindMarketplace binds a generic wrapper to an already deployed contract. +func bindMarketplace(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { + parsed, err := MarketplaceMetaData.GetAbi() + if err != nil { + return nil, err + } + return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_Marketplace *MarketplaceRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _Marketplace.Contract.MarketplaceCaller.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_Marketplace *MarketplaceRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _Marketplace.Contract.MarketplaceTransactor.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_Marketplace *MarketplaceRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _Marketplace.Contract.MarketplaceTransactor.contract.Transact(opts, method, params...) +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_Marketplace *MarketplaceCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _Marketplace.Contract.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_Marketplace *MarketplaceTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _Marketplace.Contract.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_Marketplace *MarketplaceTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _Marketplace.Contract.contract.Transact(opts, method, params...) +} + +// BIDSSTORAGESLOT is a free data retrieval call binding the contract method 0x266ccff0. +// +// Solidity: function BIDS_STORAGE_SLOT() view returns(bytes32) +func (_Marketplace *MarketplaceCaller) BIDSSTORAGESLOT(opts *bind.CallOpts) ([32]byte, error) { + var out []interface{} + err := _Marketplace.contract.Call(opts, &out, "BIDS_STORAGE_SLOT") + + if err != nil { + return *new([32]byte), err + } + + out0 := *abi.ConvertType(out[0], new([32]byte)).(*[32]byte) + + return out0, err + +} + +// BIDSSTORAGESLOT is a free data retrieval call binding the contract method 0x266ccff0. +// +// Solidity: function BIDS_STORAGE_SLOT() view returns(bytes32) +func (_Marketplace *MarketplaceSession) BIDSSTORAGESLOT() ([32]byte, error) { + return _Marketplace.Contract.BIDSSTORAGESLOT(&_Marketplace.CallOpts) +} + +// BIDSSTORAGESLOT is a free data retrieval call binding the contract method 0x266ccff0. +// +// Solidity: function BIDS_STORAGE_SLOT() view returns(bytes32) +func (_Marketplace *MarketplaceCallerSession) BIDSSTORAGESLOT() ([32]byte, error) { + return _Marketplace.Contract.BIDSSTORAGESLOT(&_Marketplace.CallOpts) +} + +// DELEGATIONRULESMARKETPLACE is a free data retrieval call binding the contract method 0xad34a150. +// +// Solidity: function DELEGATION_RULES_MARKETPLACE() view returns(bytes32) +func (_Marketplace *MarketplaceCaller) DELEGATIONRULESMARKETPLACE(opts *bind.CallOpts) ([32]byte, error) { + var out []interface{} + err := _Marketplace.contract.Call(opts, &out, "DELEGATION_RULES_MARKETPLACE") + + if err != nil { + return *new([32]byte), err + } + + out0 := *abi.ConvertType(out[0], new([32]byte)).(*[32]byte) + + return out0, err + +} + +// DELEGATIONRULESMARKETPLACE is a free data retrieval call binding the contract method 0xad34a150. +// +// Solidity: function DELEGATION_RULES_MARKETPLACE() view returns(bytes32) +func (_Marketplace *MarketplaceSession) DELEGATIONRULESMARKETPLACE() ([32]byte, error) { + return _Marketplace.Contract.DELEGATIONRULESMARKETPLACE(&_Marketplace.CallOpts) +} + +// DELEGATIONRULESMARKETPLACE is a free data retrieval call binding the contract method 0xad34a150. +// +// Solidity: function DELEGATION_RULES_MARKETPLACE() view returns(bytes32) +func (_Marketplace *MarketplaceCallerSession) DELEGATIONRULESMARKETPLACE() ([32]byte, error) { + return _Marketplace.Contract.DELEGATIONRULESMARKETPLACE(&_Marketplace.CallOpts) +} + +// DELEGATIONRULESMODEL is a free data retrieval call binding the contract method 0x86878047. +// +// Solidity: function DELEGATION_RULES_MODEL() view returns(bytes32) +func (_Marketplace *MarketplaceCaller) DELEGATIONRULESMODEL(opts *bind.CallOpts) ([32]byte, error) { + var out []interface{} + err := _Marketplace.contract.Call(opts, &out, "DELEGATION_RULES_MODEL") + + if err != nil { + return *new([32]byte), err + } + + out0 := *abi.ConvertType(out[0], new([32]byte)).(*[32]byte) + + return out0, err + +} + +// DELEGATIONRULESMODEL is a free data retrieval call binding the contract method 0x86878047. +// +// Solidity: function DELEGATION_RULES_MODEL() view returns(bytes32) +func (_Marketplace *MarketplaceSession) DELEGATIONRULESMODEL() ([32]byte, error) { + return _Marketplace.Contract.DELEGATIONRULESMODEL(&_Marketplace.CallOpts) +} + +// DELEGATIONRULESMODEL is a free data retrieval call binding the contract method 0x86878047. +// +// Solidity: function DELEGATION_RULES_MODEL() view returns(bytes32) +func (_Marketplace *MarketplaceCallerSession) DELEGATIONRULESMODEL() ([32]byte, error) { + return _Marketplace.Contract.DELEGATIONRULESMODEL(&_Marketplace.CallOpts) +} + +// DELEGATIONRULESPROVIDER is a free data retrieval call binding the contract method 0x58aeef93. +// +// Solidity: function DELEGATION_RULES_PROVIDER() view returns(bytes32) +func (_Marketplace *MarketplaceCaller) DELEGATIONRULESPROVIDER(opts *bind.CallOpts) ([32]byte, error) { + var out []interface{} + err := _Marketplace.contract.Call(opts, &out, "DELEGATION_RULES_PROVIDER") + + if err != nil { + return *new([32]byte), err + } + + out0 := *abi.ConvertType(out[0], new([32]byte)).(*[32]byte) + + return out0, err + +} + +// DELEGATIONRULESPROVIDER is a free data retrieval call binding the contract method 0x58aeef93. +// +// Solidity: function DELEGATION_RULES_PROVIDER() view returns(bytes32) +func (_Marketplace *MarketplaceSession) DELEGATIONRULESPROVIDER() ([32]byte, error) { + return _Marketplace.Contract.DELEGATIONRULESPROVIDER(&_Marketplace.CallOpts) +} + +// DELEGATIONRULESPROVIDER is a free data retrieval call binding the contract method 0x58aeef93. +// +// Solidity: function DELEGATION_RULES_PROVIDER() view returns(bytes32) +func (_Marketplace *MarketplaceCallerSession) DELEGATIONRULESPROVIDER() ([32]byte, error) { + return _Marketplace.Contract.DELEGATIONRULESPROVIDER(&_Marketplace.CallOpts) +} + +// DELEGATIONRULESSESSION is a free data retrieval call binding the contract method 0xd1b43638. +// +// Solidity: function DELEGATION_RULES_SESSION() view returns(bytes32) +func (_Marketplace *MarketplaceCaller) DELEGATIONRULESSESSION(opts *bind.CallOpts) ([32]byte, error) { + var out []interface{} + err := _Marketplace.contract.Call(opts, &out, "DELEGATION_RULES_SESSION") + + if err != nil { + return *new([32]byte), err + } + + out0 := *abi.ConvertType(out[0], new([32]byte)).(*[32]byte) + + return out0, err + +} + +// DELEGATIONRULESSESSION is a free data retrieval call binding the contract method 0xd1b43638. +// +// Solidity: function DELEGATION_RULES_SESSION() view returns(bytes32) +func (_Marketplace *MarketplaceSession) DELEGATIONRULESSESSION() ([32]byte, error) { + return _Marketplace.Contract.DELEGATIONRULESSESSION(&_Marketplace.CallOpts) +} + +// DELEGATIONRULESSESSION is a free data retrieval call binding the contract method 0xd1b43638. +// +// Solidity: function DELEGATION_RULES_SESSION() view returns(bytes32) +func (_Marketplace *MarketplaceCallerSession) DELEGATIONRULESSESSION() ([32]byte, error) { + return _Marketplace.Contract.DELEGATIONRULESSESSION(&_Marketplace.CallOpts) +} + +// DELEGATIONSTORAGESLOT is a free data retrieval call binding the contract method 0xdd9b48cb. +// +// Solidity: function DELEGATION_STORAGE_SLOT() view returns(bytes32) +func (_Marketplace *MarketplaceCaller) DELEGATIONSTORAGESLOT(opts *bind.CallOpts) ([32]byte, error) { + var out []interface{} + err := _Marketplace.contract.Call(opts, &out, "DELEGATION_STORAGE_SLOT") + + if err != nil { + return *new([32]byte), err + } + + out0 := *abi.ConvertType(out[0], new([32]byte)).(*[32]byte) + + return out0, err + +} + +// DELEGATIONSTORAGESLOT is a free data retrieval call binding the contract method 0xdd9b48cb. +// +// Solidity: function DELEGATION_STORAGE_SLOT() view returns(bytes32) +func (_Marketplace *MarketplaceSession) DELEGATIONSTORAGESLOT() ([32]byte, error) { + return _Marketplace.Contract.DELEGATIONSTORAGESLOT(&_Marketplace.CallOpts) +} + +// DELEGATIONSTORAGESLOT is a free data retrieval call binding the contract method 0xdd9b48cb. +// +// Solidity: function DELEGATION_STORAGE_SLOT() view returns(bytes32) +func (_Marketplace *MarketplaceCallerSession) DELEGATIONSTORAGESLOT() ([32]byte, error) { + return _Marketplace.Contract.DELEGATIONSTORAGESLOT(&_Marketplace.CallOpts) +} + +// DIAMONDOWNABLESTORAGESLOT is a free data retrieval call binding the contract method 0x4ac3371e. +// +// Solidity: function DIAMOND_OWNABLE_STORAGE_SLOT() view returns(bytes32) +func (_Marketplace *MarketplaceCaller) DIAMONDOWNABLESTORAGESLOT(opts *bind.CallOpts) ([32]byte, error) { + var out []interface{} + err := _Marketplace.contract.Call(opts, &out, "DIAMOND_OWNABLE_STORAGE_SLOT") + + if err != nil { + return *new([32]byte), err + } + + out0 := *abi.ConvertType(out[0], new([32]byte)).(*[32]byte) + + return out0, err + +} + +// DIAMONDOWNABLESTORAGESLOT is a free data retrieval call binding the contract method 0x4ac3371e. +// +// Solidity: function DIAMOND_OWNABLE_STORAGE_SLOT() view returns(bytes32) +func (_Marketplace *MarketplaceSession) DIAMONDOWNABLESTORAGESLOT() ([32]byte, error) { + return _Marketplace.Contract.DIAMONDOWNABLESTORAGESLOT(&_Marketplace.CallOpts) +} + +// DIAMONDOWNABLESTORAGESLOT is a free data retrieval call binding the contract method 0x4ac3371e. +// +// Solidity: function DIAMOND_OWNABLE_STORAGE_SLOT() view returns(bytes32) +func (_Marketplace *MarketplaceCallerSession) DIAMONDOWNABLESTORAGESLOT() ([32]byte, error) { + return _Marketplace.Contract.DIAMONDOWNABLESTORAGESLOT(&_Marketplace.CallOpts) +} + +// MARKETSTORAGESLOT is a free data retrieval call binding the contract method 0x2afa2c86. +// +// Solidity: function MARKET_STORAGE_SLOT() view returns(bytes32) +func (_Marketplace *MarketplaceCaller) MARKETSTORAGESLOT(opts *bind.CallOpts) ([32]byte, error) { + var out []interface{} + err := _Marketplace.contract.Call(opts, &out, "MARKET_STORAGE_SLOT") + + if err != nil { + return *new([32]byte), err + } + + out0 := *abi.ConvertType(out[0], new([32]byte)).(*[32]byte) + + return out0, err + +} + +// MARKETSTORAGESLOT is a free data retrieval call binding the contract method 0x2afa2c86. +// +// Solidity: function MARKET_STORAGE_SLOT() view returns(bytes32) +func (_Marketplace *MarketplaceSession) MARKETSTORAGESLOT() ([32]byte, error) { + return _Marketplace.Contract.MARKETSTORAGESLOT(&_Marketplace.CallOpts) +} + +// MARKETSTORAGESLOT is a free data retrieval call binding the contract method 0x2afa2c86. +// +// Solidity: function MARKET_STORAGE_SLOT() view returns(bytes32) +func (_Marketplace *MarketplaceCallerSession) MARKETSTORAGESLOT() ([32]byte, error) { + return _Marketplace.Contract.MARKETSTORAGESLOT(&_Marketplace.CallOpts) +} + +// MODELSSTORAGESLOT is a free data retrieval call binding the contract method 0x6f276c1e. +// +// Solidity: function MODELS_STORAGE_SLOT() view returns(bytes32) +func (_Marketplace *MarketplaceCaller) MODELSSTORAGESLOT(opts *bind.CallOpts) ([32]byte, error) { + var out []interface{} + err := _Marketplace.contract.Call(opts, &out, "MODELS_STORAGE_SLOT") + + if err != nil { + return *new([32]byte), err + } + + out0 := *abi.ConvertType(out[0], new([32]byte)).(*[32]byte) + + return out0, err + +} + +// MODELSSTORAGESLOT is a free data retrieval call binding the contract method 0x6f276c1e. +// +// Solidity: function MODELS_STORAGE_SLOT() view returns(bytes32) +func (_Marketplace *MarketplaceSession) MODELSSTORAGESLOT() ([32]byte, error) { + return _Marketplace.Contract.MODELSSTORAGESLOT(&_Marketplace.CallOpts) +} + +// MODELSSTORAGESLOT is a free data retrieval call binding the contract method 0x6f276c1e. +// +// Solidity: function MODELS_STORAGE_SLOT() view returns(bytes32) +func (_Marketplace *MarketplaceCallerSession) MODELSSTORAGESLOT() ([32]byte, error) { + return _Marketplace.Contract.MODELSSTORAGESLOT(&_Marketplace.CallOpts) +} + +// PROVIDERSSTORAGESLOT is a free data retrieval call binding the contract method 0xc51830f6. +// +// Solidity: function PROVIDERS_STORAGE_SLOT() view returns(bytes32) +func (_Marketplace *MarketplaceCaller) PROVIDERSSTORAGESLOT(opts *bind.CallOpts) ([32]byte, error) { + var out []interface{} + err := _Marketplace.contract.Call(opts, &out, "PROVIDERS_STORAGE_SLOT") + + if err != nil { + return *new([32]byte), err + } + + out0 := *abi.ConvertType(out[0], new([32]byte)).(*[32]byte) + + return out0, err + +} + +// PROVIDERSSTORAGESLOT is a free data retrieval call binding the contract method 0xc51830f6. +// +// Solidity: function PROVIDERS_STORAGE_SLOT() view returns(bytes32) +func (_Marketplace *MarketplaceSession) PROVIDERSSTORAGESLOT() ([32]byte, error) { + return _Marketplace.Contract.PROVIDERSSTORAGESLOT(&_Marketplace.CallOpts) +} + +// PROVIDERSSTORAGESLOT is a free data retrieval call binding the contract method 0xc51830f6. +// +// Solidity: function PROVIDERS_STORAGE_SLOT() view returns(bytes32) +func (_Marketplace *MarketplaceCallerSession) PROVIDERSSTORAGESLOT() ([32]byte, error) { + return _Marketplace.Contract.PROVIDERSSTORAGESLOT(&_Marketplace.CallOpts) +} + +// GetActiveModelIds is a free data retrieval call binding the contract method 0x3839d3dc. +// +// Solidity: function getActiveModelIds(uint256 offset_, uint256 limit_) view returns(bytes32[], uint256) +func (_Marketplace *MarketplaceCaller) GetActiveModelIds(opts *bind.CallOpts, offset_ *big.Int, limit_ *big.Int) ([][32]byte, *big.Int, error) { + var out []interface{} + err := _Marketplace.contract.Call(opts, &out, "getActiveModelIds", offset_, limit_) + + if err != nil { + return *new([][32]byte), *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new([][32]byte)).(*[][32]byte) + out1 := *abi.ConvertType(out[1], new(*big.Int)).(**big.Int) + + return out0, out1, err + +} + +// GetActiveModelIds is a free data retrieval call binding the contract method 0x3839d3dc. +// +// Solidity: function getActiveModelIds(uint256 offset_, uint256 limit_) view returns(bytes32[], uint256) +func (_Marketplace *MarketplaceSession) GetActiveModelIds(offset_ *big.Int, limit_ *big.Int) ([][32]byte, *big.Int, error) { + return _Marketplace.Contract.GetActiveModelIds(&_Marketplace.CallOpts, offset_, limit_) +} + +// GetActiveModelIds is a free data retrieval call binding the contract method 0x3839d3dc. +// +// Solidity: function getActiveModelIds(uint256 offset_, uint256 limit_) view returns(bytes32[], uint256) +func (_Marketplace *MarketplaceCallerSession) GetActiveModelIds(offset_ *big.Int, limit_ *big.Int) ([][32]byte, *big.Int, error) { + return _Marketplace.Contract.GetActiveModelIds(&_Marketplace.CallOpts, offset_, limit_) +} + +// GetActiveProviders is a free data retrieval call binding the contract method 0xd5472642. +// +// Solidity: function getActiveProviders(uint256 offset_, uint256 limit_) view returns(address[], uint256) +func (_Marketplace *MarketplaceCaller) GetActiveProviders(opts *bind.CallOpts, offset_ *big.Int, limit_ *big.Int) ([]common.Address, *big.Int, error) { + var out []interface{} + err := _Marketplace.contract.Call(opts, &out, "getActiveProviders", offset_, limit_) + + if err != nil { + return *new([]common.Address), *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new([]common.Address)).(*[]common.Address) + out1 := *abi.ConvertType(out[1], new(*big.Int)).(**big.Int) + + return out0, out1, err + +} + +// GetActiveProviders is a free data retrieval call binding the contract method 0xd5472642. +// +// Solidity: function getActiveProviders(uint256 offset_, uint256 limit_) view returns(address[], uint256) +func (_Marketplace *MarketplaceSession) GetActiveProviders(offset_ *big.Int, limit_ *big.Int) ([]common.Address, *big.Int, error) { + return _Marketplace.Contract.GetActiveProviders(&_Marketplace.CallOpts, offset_, limit_) +} + +// GetActiveProviders is a free data retrieval call binding the contract method 0xd5472642. +// +// Solidity: function getActiveProviders(uint256 offset_, uint256 limit_) view returns(address[], uint256) +func (_Marketplace *MarketplaceCallerSession) GetActiveProviders(offset_ *big.Int, limit_ *big.Int) ([]common.Address, *big.Int, error) { + return _Marketplace.Contract.GetActiveProviders(&_Marketplace.CallOpts, offset_, limit_) +} + +// GetBid is a free data retrieval call binding the contract method 0x91704e1e. +// +// Solidity: function getBid(bytes32 bidId_) view returns((address,bytes32,uint256,uint256,uint128,uint128)) +func (_Marketplace *MarketplaceCaller) GetBid(opts *bind.CallOpts, bidId_ [32]byte) (IBidStorageBid, error) { + var out []interface{} + err := _Marketplace.contract.Call(opts, &out, "getBid", bidId_) + + if err != nil { + return *new(IBidStorageBid), err + } + + out0 := *abi.ConvertType(out[0], new(IBidStorageBid)).(*IBidStorageBid) + + return out0, err + +} + +// GetBid is a free data retrieval call binding the contract method 0x91704e1e. +// +// Solidity: function getBid(bytes32 bidId_) view returns((address,bytes32,uint256,uint256,uint128,uint128)) +func (_Marketplace *MarketplaceSession) GetBid(bidId_ [32]byte) (IBidStorageBid, error) { + return _Marketplace.Contract.GetBid(&_Marketplace.CallOpts, bidId_) +} + +// GetBid is a free data retrieval call binding the contract method 0x91704e1e. +// +// Solidity: function getBid(bytes32 bidId_) view returns((address,bytes32,uint256,uint256,uint128,uint128)) +func (_Marketplace *MarketplaceCallerSession) GetBid(bidId_ [32]byte) (IBidStorageBid, error) { + return _Marketplace.Contract.GetBid(&_Marketplace.CallOpts, bidId_) +} + +// GetBidFee is a free data retrieval call binding the contract method 0x8dbb4647. +// +// Solidity: function getBidFee() view returns(uint256) +func (_Marketplace *MarketplaceCaller) GetBidFee(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _Marketplace.contract.Call(opts, &out, "getBidFee") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// GetBidFee is a free data retrieval call binding the contract method 0x8dbb4647. +// +// Solidity: function getBidFee() view returns(uint256) +func (_Marketplace *MarketplaceSession) GetBidFee() (*big.Int, error) { + return _Marketplace.Contract.GetBidFee(&_Marketplace.CallOpts) +} + +// GetBidFee is a free data retrieval call binding the contract method 0x8dbb4647. +// +// Solidity: function getBidFee() view returns(uint256) +func (_Marketplace *MarketplaceCallerSession) GetBidFee() (*big.Int, error) { + return _Marketplace.Contract.GetBidFee(&_Marketplace.CallOpts) +} + +// GetBidId is a free data retrieval call binding the contract method 0x747ddd5b. +// +// Solidity: function getBidId(address provider_, bytes32 modelId_, uint256 nonce_) pure returns(bytes32) +func (_Marketplace *MarketplaceCaller) GetBidId(opts *bind.CallOpts, provider_ common.Address, modelId_ [32]byte, nonce_ *big.Int) ([32]byte, error) { + var out []interface{} + err := _Marketplace.contract.Call(opts, &out, "getBidId", provider_, modelId_, nonce_) + + if err != nil { + return *new([32]byte), err + } + + out0 := *abi.ConvertType(out[0], new([32]byte)).(*[32]byte) + + return out0, err + +} + +// GetBidId is a free data retrieval call binding the contract method 0x747ddd5b. +// +// Solidity: function getBidId(address provider_, bytes32 modelId_, uint256 nonce_) pure returns(bytes32) +func (_Marketplace *MarketplaceSession) GetBidId(provider_ common.Address, modelId_ [32]byte, nonce_ *big.Int) ([32]byte, error) { + return _Marketplace.Contract.GetBidId(&_Marketplace.CallOpts, provider_, modelId_, nonce_) +} + +// GetBidId is a free data retrieval call binding the contract method 0x747ddd5b. +// +// Solidity: function getBidId(address provider_, bytes32 modelId_, uint256 nonce_) pure returns(bytes32) +func (_Marketplace *MarketplaceCallerSession) GetBidId(provider_ common.Address, modelId_ [32]byte, nonce_ *big.Int) ([32]byte, error) { + return _Marketplace.Contract.GetBidId(&_Marketplace.CallOpts, provider_, modelId_, nonce_) +} + +// GetFeeBalance is a free data retrieval call binding the contract method 0xd4c30ceb. +// +// Solidity: function getFeeBalance() view returns(uint256) +func (_Marketplace *MarketplaceCaller) GetFeeBalance(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _Marketplace.contract.Call(opts, &out, "getFeeBalance") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// GetFeeBalance is a free data retrieval call binding the contract method 0xd4c30ceb. +// +// Solidity: function getFeeBalance() view returns(uint256) +func (_Marketplace *MarketplaceSession) GetFeeBalance() (*big.Int, error) { + return _Marketplace.Contract.GetFeeBalance(&_Marketplace.CallOpts) +} + +// GetFeeBalance is a free data retrieval call binding the contract method 0xd4c30ceb. +// +// Solidity: function getFeeBalance() view returns(uint256) +func (_Marketplace *MarketplaceCallerSession) GetFeeBalance() (*big.Int, error) { + return _Marketplace.Contract.GetFeeBalance(&_Marketplace.CallOpts) +} + +// GetIsModelActive is a free data retrieval call binding the contract method 0xca74b5f3. +// +// Solidity: function getIsModelActive(bytes32 modelId_) view returns(bool) +func (_Marketplace *MarketplaceCaller) GetIsModelActive(opts *bind.CallOpts, modelId_ [32]byte) (bool, error) { + var out []interface{} + err := _Marketplace.contract.Call(opts, &out, "getIsModelActive", modelId_) + + if err != nil { + return *new(bool), err + } + + out0 := *abi.ConvertType(out[0], new(bool)).(*bool) + + return out0, err + +} + +// GetIsModelActive is a free data retrieval call binding the contract method 0xca74b5f3. +// +// Solidity: function getIsModelActive(bytes32 modelId_) view returns(bool) +func (_Marketplace *MarketplaceSession) GetIsModelActive(modelId_ [32]byte) (bool, error) { + return _Marketplace.Contract.GetIsModelActive(&_Marketplace.CallOpts, modelId_) +} + +// GetIsModelActive is a free data retrieval call binding the contract method 0xca74b5f3. +// +// Solidity: function getIsModelActive(bytes32 modelId_) view returns(bool) +func (_Marketplace *MarketplaceCallerSession) GetIsModelActive(modelId_ [32]byte) (bool, error) { + return _Marketplace.Contract.GetIsModelActive(&_Marketplace.CallOpts, modelId_) +} + +// GetIsProviderActive is a free data retrieval call binding the contract method 0x63ef175d. +// +// Solidity: function getIsProviderActive(address provider_) view returns(bool) +func (_Marketplace *MarketplaceCaller) GetIsProviderActive(opts *bind.CallOpts, provider_ common.Address) (bool, error) { + var out []interface{} + err := _Marketplace.contract.Call(opts, &out, "getIsProviderActive", provider_) + + if err != nil { + return *new(bool), err + } + + out0 := *abi.ConvertType(out[0], new(bool)).(*bool) + + return out0, err + +} + +// GetIsProviderActive is a free data retrieval call binding the contract method 0x63ef175d. +// +// Solidity: function getIsProviderActive(address provider_) view returns(bool) +func (_Marketplace *MarketplaceSession) GetIsProviderActive(provider_ common.Address) (bool, error) { + return _Marketplace.Contract.GetIsProviderActive(&_Marketplace.CallOpts, provider_) +} + +// GetIsProviderActive is a free data retrieval call binding the contract method 0x63ef175d. +// +// Solidity: function getIsProviderActive(address provider_) view returns(bool) +func (_Marketplace *MarketplaceCallerSession) GetIsProviderActive(provider_ common.Address) (bool, error) { + return _Marketplace.Contract.GetIsProviderActive(&_Marketplace.CallOpts, provider_) +} + +// GetMinMaxBidPricePerSecond is a free data retrieval call binding the contract method 0x38c8ac62. +// +// Solidity: function getMinMaxBidPricePerSecond() view returns(uint256, uint256) +func (_Marketplace *MarketplaceCaller) GetMinMaxBidPricePerSecond(opts *bind.CallOpts) (*big.Int, *big.Int, error) { + var out []interface{} + err := _Marketplace.contract.Call(opts, &out, "getMinMaxBidPricePerSecond") + + if err != nil { + return *new(*big.Int), *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + out1 := *abi.ConvertType(out[1], new(*big.Int)).(**big.Int) + + return out0, out1, err + +} + +// GetMinMaxBidPricePerSecond is a free data retrieval call binding the contract method 0x38c8ac62. +// +// Solidity: function getMinMaxBidPricePerSecond() view returns(uint256, uint256) +func (_Marketplace *MarketplaceSession) GetMinMaxBidPricePerSecond() (*big.Int, *big.Int, error) { + return _Marketplace.Contract.GetMinMaxBidPricePerSecond(&_Marketplace.CallOpts) +} + +// GetMinMaxBidPricePerSecond is a free data retrieval call binding the contract method 0x38c8ac62. +// +// Solidity: function getMinMaxBidPricePerSecond() view returns(uint256, uint256) +func (_Marketplace *MarketplaceCallerSession) GetMinMaxBidPricePerSecond() (*big.Int, *big.Int, error) { + return _Marketplace.Contract.GetMinMaxBidPricePerSecond(&_Marketplace.CallOpts) +} + +// GetModel is a free data retrieval call binding the contract method 0x21e7c498. +// +// Solidity: function getModel(bytes32 modelId_) view returns((bytes32,uint256,uint256,address,string,string[],uint128,bool)) +func (_Marketplace *MarketplaceCaller) GetModel(opts *bind.CallOpts, modelId_ [32]byte) (IModelStorageModel, error) { + var out []interface{} + err := _Marketplace.contract.Call(opts, &out, "getModel", modelId_) + + if err != nil { + return *new(IModelStorageModel), err + } + + out0 := *abi.ConvertType(out[0], new(IModelStorageModel)).(*IModelStorageModel) + + return out0, err + +} + +// GetModel is a free data retrieval call binding the contract method 0x21e7c498. +// +// Solidity: function getModel(bytes32 modelId_) view returns((bytes32,uint256,uint256,address,string,string[],uint128,bool)) +func (_Marketplace *MarketplaceSession) GetModel(modelId_ [32]byte) (IModelStorageModel, error) { + return _Marketplace.Contract.GetModel(&_Marketplace.CallOpts, modelId_) +} + +// GetModel is a free data retrieval call binding the contract method 0x21e7c498. +// +// Solidity: function getModel(bytes32 modelId_) view returns((bytes32,uint256,uint256,address,string,string[],uint128,bool)) +func (_Marketplace *MarketplaceCallerSession) GetModel(modelId_ [32]byte) (IModelStorageModel, error) { + return _Marketplace.Contract.GetModel(&_Marketplace.CallOpts, modelId_) +} + +// GetModelActiveBids is a free data retrieval call binding the contract method 0x8a683b6e. +// +// Solidity: function getModelActiveBids(bytes32 modelId_, uint256 offset_, uint256 limit_) view returns(bytes32[], uint256) +func (_Marketplace *MarketplaceCaller) GetModelActiveBids(opts *bind.CallOpts, modelId_ [32]byte, offset_ *big.Int, limit_ *big.Int) ([][32]byte, *big.Int, error) { + var out []interface{} + err := _Marketplace.contract.Call(opts, &out, "getModelActiveBids", modelId_, offset_, limit_) + + if err != nil { + return *new([][32]byte), *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new([][32]byte)).(*[][32]byte) + out1 := *abi.ConvertType(out[1], new(*big.Int)).(**big.Int) + + return out0, out1, err + +} + +// GetModelActiveBids is a free data retrieval call binding the contract method 0x8a683b6e. +// +// Solidity: function getModelActiveBids(bytes32 modelId_, uint256 offset_, uint256 limit_) view returns(bytes32[], uint256) +func (_Marketplace *MarketplaceSession) GetModelActiveBids(modelId_ [32]byte, offset_ *big.Int, limit_ *big.Int) ([][32]byte, *big.Int, error) { + return _Marketplace.Contract.GetModelActiveBids(&_Marketplace.CallOpts, modelId_, offset_, limit_) +} + +// GetModelActiveBids is a free data retrieval call binding the contract method 0x8a683b6e. +// +// Solidity: function getModelActiveBids(bytes32 modelId_, uint256 offset_, uint256 limit_) view returns(bytes32[], uint256) +func (_Marketplace *MarketplaceCallerSession) GetModelActiveBids(modelId_ [32]byte, offset_ *big.Int, limit_ *big.Int) ([][32]byte, *big.Int, error) { + return _Marketplace.Contract.GetModelActiveBids(&_Marketplace.CallOpts, modelId_, offset_, limit_) +} + +// GetModelBids is a free data retrieval call binding the contract method 0xfade17b1. +// +// Solidity: function getModelBids(bytes32 modelId_, uint256 offset_, uint256 limit_) view returns(bytes32[], uint256) +func (_Marketplace *MarketplaceCaller) GetModelBids(opts *bind.CallOpts, modelId_ [32]byte, offset_ *big.Int, limit_ *big.Int) ([][32]byte, *big.Int, error) { + var out []interface{} + err := _Marketplace.contract.Call(opts, &out, "getModelBids", modelId_, offset_, limit_) + + if err != nil { + return *new([][32]byte), *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new([][32]byte)).(*[][32]byte) + out1 := *abi.ConvertType(out[1], new(*big.Int)).(**big.Int) + + return out0, out1, err + +} + +// GetModelBids is a free data retrieval call binding the contract method 0xfade17b1. +// +// Solidity: function getModelBids(bytes32 modelId_, uint256 offset_, uint256 limit_) view returns(bytes32[], uint256) +func (_Marketplace *MarketplaceSession) GetModelBids(modelId_ [32]byte, offset_ *big.Int, limit_ *big.Int) ([][32]byte, *big.Int, error) { + return _Marketplace.Contract.GetModelBids(&_Marketplace.CallOpts, modelId_, offset_, limit_) +} + +// GetModelBids is a free data retrieval call binding the contract method 0xfade17b1. +// +// Solidity: function getModelBids(bytes32 modelId_, uint256 offset_, uint256 limit_) view returns(bytes32[], uint256) +func (_Marketplace *MarketplaceCallerSession) GetModelBids(modelId_ [32]byte, offset_ *big.Int, limit_ *big.Int) ([][32]byte, *big.Int, error) { + return _Marketplace.Contract.GetModelBids(&_Marketplace.CallOpts, modelId_, offset_, limit_) +} + +// GetModelIds is a free data retrieval call binding the contract method 0x08d0aab4. +// +// Solidity: function getModelIds(uint256 offset_, uint256 limit_) view returns(bytes32[], uint256) +func (_Marketplace *MarketplaceCaller) GetModelIds(opts *bind.CallOpts, offset_ *big.Int, limit_ *big.Int) ([][32]byte, *big.Int, error) { + var out []interface{} + err := _Marketplace.contract.Call(opts, &out, "getModelIds", offset_, limit_) + + if err != nil { + return *new([][32]byte), *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new([][32]byte)).(*[][32]byte) + out1 := *abi.ConvertType(out[1], new(*big.Int)).(**big.Int) + + return out0, out1, err + +} + +// GetModelIds is a free data retrieval call binding the contract method 0x08d0aab4. +// +// Solidity: function getModelIds(uint256 offset_, uint256 limit_) view returns(bytes32[], uint256) +func (_Marketplace *MarketplaceSession) GetModelIds(offset_ *big.Int, limit_ *big.Int) ([][32]byte, *big.Int, error) { + return _Marketplace.Contract.GetModelIds(&_Marketplace.CallOpts, offset_, limit_) +} + +// GetModelIds is a free data retrieval call binding the contract method 0x08d0aab4. +// +// Solidity: function getModelIds(uint256 offset_, uint256 limit_) view returns(bytes32[], uint256) +func (_Marketplace *MarketplaceCallerSession) GetModelIds(offset_ *big.Int, limit_ *big.Int) ([][32]byte, *big.Int, error) { + return _Marketplace.Contract.GetModelIds(&_Marketplace.CallOpts, offset_, limit_) +} + +// GetModelMinimumStake is a free data retrieval call binding the contract method 0xf647ba3d. +// +// Solidity: function getModelMinimumStake() view returns(uint256) +func (_Marketplace *MarketplaceCaller) GetModelMinimumStake(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _Marketplace.contract.Call(opts, &out, "getModelMinimumStake") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// GetModelMinimumStake is a free data retrieval call binding the contract method 0xf647ba3d. +// +// Solidity: function getModelMinimumStake() view returns(uint256) +func (_Marketplace *MarketplaceSession) GetModelMinimumStake() (*big.Int, error) { + return _Marketplace.Contract.GetModelMinimumStake(&_Marketplace.CallOpts) +} + +// GetModelMinimumStake is a free data retrieval call binding the contract method 0xf647ba3d. +// +// Solidity: function getModelMinimumStake() view returns(uint256) +func (_Marketplace *MarketplaceCallerSession) GetModelMinimumStake() (*big.Int, error) { + return _Marketplace.Contract.GetModelMinimumStake(&_Marketplace.CallOpts) +} + +// GetProvider is a free data retrieval call binding the contract method 0x55f21eb7. +// +// Solidity: function getProvider(address provider_) view returns((string,uint256,uint128,uint128,uint256,bool)) +func (_Marketplace *MarketplaceCaller) GetProvider(opts *bind.CallOpts, provider_ common.Address) (IProviderStorageProvider, error) { + var out []interface{} + err := _Marketplace.contract.Call(opts, &out, "getProvider", provider_) + + if err != nil { + return *new(IProviderStorageProvider), err + } + + out0 := *abi.ConvertType(out[0], new(IProviderStorageProvider)).(*IProviderStorageProvider) + + return out0, err + +} + +// GetProvider is a free data retrieval call binding the contract method 0x55f21eb7. +// +// Solidity: function getProvider(address provider_) view returns((string,uint256,uint128,uint128,uint256,bool)) +func (_Marketplace *MarketplaceSession) GetProvider(provider_ common.Address) (IProviderStorageProvider, error) { + return _Marketplace.Contract.GetProvider(&_Marketplace.CallOpts, provider_) +} + +// GetProvider is a free data retrieval call binding the contract method 0x55f21eb7. +// +// Solidity: function getProvider(address provider_) view returns((string,uint256,uint128,uint128,uint256,bool)) +func (_Marketplace *MarketplaceCallerSession) GetProvider(provider_ common.Address) (IProviderStorageProvider, error) { + return _Marketplace.Contract.GetProvider(&_Marketplace.CallOpts, provider_) +} + +// GetProviderActiveBids is a free data retrieval call binding the contract method 0xaf5b77ca. +// +// Solidity: function getProviderActiveBids(address provider_, uint256 offset_, uint256 limit_) view returns(bytes32[], uint256) +func (_Marketplace *MarketplaceCaller) GetProviderActiveBids(opts *bind.CallOpts, provider_ common.Address, offset_ *big.Int, limit_ *big.Int) ([][32]byte, *big.Int, error) { + var out []interface{} + err := _Marketplace.contract.Call(opts, &out, "getProviderActiveBids", provider_, offset_, limit_) + + if err != nil { + return *new([][32]byte), *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new([][32]byte)).(*[][32]byte) + out1 := *abi.ConvertType(out[1], new(*big.Int)).(**big.Int) + + return out0, out1, err + +} + +// GetProviderActiveBids is a free data retrieval call binding the contract method 0xaf5b77ca. +// +// Solidity: function getProviderActiveBids(address provider_, uint256 offset_, uint256 limit_) view returns(bytes32[], uint256) +func (_Marketplace *MarketplaceSession) GetProviderActiveBids(provider_ common.Address, offset_ *big.Int, limit_ *big.Int) ([][32]byte, *big.Int, error) { + return _Marketplace.Contract.GetProviderActiveBids(&_Marketplace.CallOpts, provider_, offset_, limit_) +} + +// GetProviderActiveBids is a free data retrieval call binding the contract method 0xaf5b77ca. +// +// Solidity: function getProviderActiveBids(address provider_, uint256 offset_, uint256 limit_) view returns(bytes32[], uint256) +func (_Marketplace *MarketplaceCallerSession) GetProviderActiveBids(provider_ common.Address, offset_ *big.Int, limit_ *big.Int) ([][32]byte, *big.Int, error) { + return _Marketplace.Contract.GetProviderActiveBids(&_Marketplace.CallOpts, provider_, offset_, limit_) +} + +// GetProviderBids is a free data retrieval call binding the contract method 0x59d435c4. +// +// Solidity: function getProviderBids(address provider_, uint256 offset_, uint256 limit_) view returns(bytes32[], uint256) +func (_Marketplace *MarketplaceCaller) GetProviderBids(opts *bind.CallOpts, provider_ common.Address, offset_ *big.Int, limit_ *big.Int) ([][32]byte, *big.Int, error) { + var out []interface{} + err := _Marketplace.contract.Call(opts, &out, "getProviderBids", provider_, offset_, limit_) + + if err != nil { + return *new([][32]byte), *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new([][32]byte)).(*[][32]byte) + out1 := *abi.ConvertType(out[1], new(*big.Int)).(**big.Int) + + return out0, out1, err + +} + +// GetProviderBids is a free data retrieval call binding the contract method 0x59d435c4. +// +// Solidity: function getProviderBids(address provider_, uint256 offset_, uint256 limit_) view returns(bytes32[], uint256) +func (_Marketplace *MarketplaceSession) GetProviderBids(provider_ common.Address, offset_ *big.Int, limit_ *big.Int) ([][32]byte, *big.Int, error) { + return _Marketplace.Contract.GetProviderBids(&_Marketplace.CallOpts, provider_, offset_, limit_) +} + +// GetProviderBids is a free data retrieval call binding the contract method 0x59d435c4. +// +// Solidity: function getProviderBids(address provider_, uint256 offset_, uint256 limit_) view returns(bytes32[], uint256) +func (_Marketplace *MarketplaceCallerSession) GetProviderBids(provider_ common.Address, offset_ *big.Int, limit_ *big.Int) ([][32]byte, *big.Int, error) { + return _Marketplace.Contract.GetProviderBids(&_Marketplace.CallOpts, provider_, offset_, limit_) +} + +// GetProviderMinimumStake is a free data retrieval call binding the contract method 0x53c029f6. +// +// Solidity: function getProviderMinimumStake() view returns(uint256) +func (_Marketplace *MarketplaceCaller) GetProviderMinimumStake(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _Marketplace.contract.Call(opts, &out, "getProviderMinimumStake") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// GetProviderMinimumStake is a free data retrieval call binding the contract method 0x53c029f6. +// +// Solidity: function getProviderMinimumStake() view returns(uint256) +func (_Marketplace *MarketplaceSession) GetProviderMinimumStake() (*big.Int, error) { + return _Marketplace.Contract.GetProviderMinimumStake(&_Marketplace.CallOpts) +} + +// GetProviderMinimumStake is a free data retrieval call binding the contract method 0x53c029f6. +// +// Solidity: function getProviderMinimumStake() view returns(uint256) +func (_Marketplace *MarketplaceCallerSession) GetProviderMinimumStake() (*big.Int, error) { + return _Marketplace.Contract.GetProviderMinimumStake(&_Marketplace.CallOpts) +} + +// GetProviderModelId is a free data retrieval call binding the contract method 0x1cc9de8c. +// +// Solidity: function getProviderModelId(address provider_, bytes32 modelId_) pure returns(bytes32) +func (_Marketplace *MarketplaceCaller) GetProviderModelId(opts *bind.CallOpts, provider_ common.Address, modelId_ [32]byte) ([32]byte, error) { + var out []interface{} + err := _Marketplace.contract.Call(opts, &out, "getProviderModelId", provider_, modelId_) + + if err != nil { + return *new([32]byte), err + } + + out0 := *abi.ConvertType(out[0], new([32]byte)).(*[32]byte) + + return out0, err + +} + +// GetProviderModelId is a free data retrieval call binding the contract method 0x1cc9de8c. +// +// Solidity: function getProviderModelId(address provider_, bytes32 modelId_) pure returns(bytes32) +func (_Marketplace *MarketplaceSession) GetProviderModelId(provider_ common.Address, modelId_ [32]byte) ([32]byte, error) { + return _Marketplace.Contract.GetProviderModelId(&_Marketplace.CallOpts, provider_, modelId_) +} + +// GetProviderModelId is a free data retrieval call binding the contract method 0x1cc9de8c. +// +// Solidity: function getProviderModelId(address provider_, bytes32 modelId_) pure returns(bytes32) +func (_Marketplace *MarketplaceCallerSession) GetProviderModelId(provider_ common.Address, modelId_ [32]byte) ([32]byte, error) { + return _Marketplace.Contract.GetProviderModelId(&_Marketplace.CallOpts, provider_, modelId_) +} + +// GetRegistry is a free data retrieval call binding the contract method 0x5ab1bd53. +// +// Solidity: function getRegistry() view returns(address) +func (_Marketplace *MarketplaceCaller) GetRegistry(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _Marketplace.contract.Call(opts, &out, "getRegistry") + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +// GetRegistry is a free data retrieval call binding the contract method 0x5ab1bd53. +// +// Solidity: function getRegistry() view returns(address) +func (_Marketplace *MarketplaceSession) GetRegistry() (common.Address, error) { + return _Marketplace.Contract.GetRegistry(&_Marketplace.CallOpts) +} + +// GetRegistry is a free data retrieval call binding the contract method 0x5ab1bd53. +// +// Solidity: function getRegistry() view returns(address) +func (_Marketplace *MarketplaceCallerSession) GetRegistry() (common.Address, error) { + return _Marketplace.Contract.GetRegistry(&_Marketplace.CallOpts) +} + +// GetToken is a free data retrieval call binding the contract method 0x21df0da7. +// +// Solidity: function getToken() view returns(address) +func (_Marketplace *MarketplaceCaller) GetToken(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _Marketplace.contract.Call(opts, &out, "getToken") + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +// GetToken is a free data retrieval call binding the contract method 0x21df0da7. +// +// Solidity: function getToken() view returns(address) +func (_Marketplace *MarketplaceSession) GetToken() (common.Address, error) { + return _Marketplace.Contract.GetToken(&_Marketplace.CallOpts) +} + +// GetToken is a free data retrieval call binding the contract method 0x21df0da7. +// +// Solidity: function getToken() view returns(address) +func (_Marketplace *MarketplaceCallerSession) GetToken() (common.Address, error) { + return _Marketplace.Contract.GetToken(&_Marketplace.CallOpts) +} + +// IsBidActive is a free data retrieval call binding the contract method 0x1345df58. +// +// Solidity: function isBidActive(bytes32 bidId_) view returns(bool) +func (_Marketplace *MarketplaceCaller) IsBidActive(opts *bind.CallOpts, bidId_ [32]byte) (bool, error) { + var out []interface{} + err := _Marketplace.contract.Call(opts, &out, "isBidActive", bidId_) + + if err != nil { + return *new(bool), err + } + + out0 := *abi.ConvertType(out[0], new(bool)).(*bool) + + return out0, err + +} + +// IsBidActive is a free data retrieval call binding the contract method 0x1345df58. +// +// Solidity: function isBidActive(bytes32 bidId_) view returns(bool) +func (_Marketplace *MarketplaceSession) IsBidActive(bidId_ [32]byte) (bool, error) { + return _Marketplace.Contract.IsBidActive(&_Marketplace.CallOpts, bidId_) +} + +// IsBidActive is a free data retrieval call binding the contract method 0x1345df58. +// +// Solidity: function isBidActive(bytes32 bidId_) view returns(bool) +func (_Marketplace *MarketplaceCallerSession) IsBidActive(bidId_ [32]byte) (bool, error) { + return _Marketplace.Contract.IsBidActive(&_Marketplace.CallOpts, bidId_) +} + +// IsRightsDelegated is a free data retrieval call binding the contract method 0x54126b8f. +// +// Solidity: function isRightsDelegated(address delegatee_, address delegator_, bytes32 rights_) view returns(bool) +func (_Marketplace *MarketplaceCaller) IsRightsDelegated(opts *bind.CallOpts, delegatee_ common.Address, delegator_ common.Address, rights_ [32]byte) (bool, error) { + var out []interface{} + err := _Marketplace.contract.Call(opts, &out, "isRightsDelegated", delegatee_, delegator_, rights_) + + if err != nil { + return *new(bool), err + } + + out0 := *abi.ConvertType(out[0], new(bool)).(*bool) + + return out0, err + +} + +// IsRightsDelegated is a free data retrieval call binding the contract method 0x54126b8f. +// +// Solidity: function isRightsDelegated(address delegatee_, address delegator_, bytes32 rights_) view returns(bool) +func (_Marketplace *MarketplaceSession) IsRightsDelegated(delegatee_ common.Address, delegator_ common.Address, rights_ [32]byte) (bool, error) { + return _Marketplace.Contract.IsRightsDelegated(&_Marketplace.CallOpts, delegatee_, delegator_, rights_) +} + +// IsRightsDelegated is a free data retrieval call binding the contract method 0x54126b8f. +// +// Solidity: function isRightsDelegated(address delegatee_, address delegator_, bytes32 rights_) view returns(bool) +func (_Marketplace *MarketplaceCallerSession) IsRightsDelegated(delegatee_ common.Address, delegator_ common.Address, rights_ [32]byte) (bool, error) { + return _Marketplace.Contract.IsRightsDelegated(&_Marketplace.CallOpts, delegatee_, delegator_, rights_) +} + +// Owner is a free data retrieval call binding the contract method 0x8da5cb5b. +// +// Solidity: function owner() view returns(address) +func (_Marketplace *MarketplaceCaller) Owner(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _Marketplace.contract.Call(opts, &out, "owner") + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +// Owner is a free data retrieval call binding the contract method 0x8da5cb5b. +// +// Solidity: function owner() view returns(address) +func (_Marketplace *MarketplaceSession) Owner() (common.Address, error) { + return _Marketplace.Contract.Owner(&_Marketplace.CallOpts) +} + +// Owner is a free data retrieval call binding the contract method 0x8da5cb5b. +// +// Solidity: function owner() view returns(address) +func (_Marketplace *MarketplaceCallerSession) Owner() (common.Address, error) { + return _Marketplace.Contract.Owner(&_Marketplace.CallOpts) +} + +// MarketplaceInit is a paid mutator transaction binding the contract method 0xf9804d0b. +// +// Solidity: function __Marketplace_init(address token_, uint256 bidMinPricePerSecond_, uint256 bidMaxPricePerSecond_) returns() +func (_Marketplace *MarketplaceTransactor) MarketplaceInit(opts *bind.TransactOpts, token_ common.Address, bidMinPricePerSecond_ *big.Int, bidMaxPricePerSecond_ *big.Int) (*types.Transaction, error) { + return _Marketplace.contract.Transact(opts, "__Marketplace_init", token_, bidMinPricePerSecond_, bidMaxPricePerSecond_) +} + +// MarketplaceInit is a paid mutator transaction binding the contract method 0xf9804d0b. +// +// Solidity: function __Marketplace_init(address token_, uint256 bidMinPricePerSecond_, uint256 bidMaxPricePerSecond_) returns() +func (_Marketplace *MarketplaceSession) MarketplaceInit(token_ common.Address, bidMinPricePerSecond_ *big.Int, bidMaxPricePerSecond_ *big.Int) (*types.Transaction, error) { + return _Marketplace.Contract.MarketplaceInit(&_Marketplace.TransactOpts, token_, bidMinPricePerSecond_, bidMaxPricePerSecond_) +} + +// MarketplaceInit is a paid mutator transaction binding the contract method 0xf9804d0b. +// +// Solidity: function __Marketplace_init(address token_, uint256 bidMinPricePerSecond_, uint256 bidMaxPricePerSecond_) returns() +func (_Marketplace *MarketplaceTransactorSession) MarketplaceInit(token_ common.Address, bidMinPricePerSecond_ *big.Int, bidMaxPricePerSecond_ *big.Int) (*types.Transaction, error) { + return _Marketplace.Contract.MarketplaceInit(&_Marketplace.TransactOpts, token_, bidMinPricePerSecond_, bidMaxPricePerSecond_) +} + +// DeleteModelBid is a paid mutator transaction binding the contract method 0x8913dcaa. +// +// Solidity: function deleteModelBid(bytes32 bidId_) returns() +func (_Marketplace *MarketplaceTransactor) DeleteModelBid(opts *bind.TransactOpts, bidId_ [32]byte) (*types.Transaction, error) { + return _Marketplace.contract.Transact(opts, "deleteModelBid", bidId_) +} + +// DeleteModelBid is a paid mutator transaction binding the contract method 0x8913dcaa. +// +// Solidity: function deleteModelBid(bytes32 bidId_) returns() +func (_Marketplace *MarketplaceSession) DeleteModelBid(bidId_ [32]byte) (*types.Transaction, error) { + return _Marketplace.Contract.DeleteModelBid(&_Marketplace.TransactOpts, bidId_) +} + +// DeleteModelBid is a paid mutator transaction binding the contract method 0x8913dcaa. +// +// Solidity: function deleteModelBid(bytes32 bidId_) returns() +func (_Marketplace *MarketplaceTransactorSession) DeleteModelBid(bidId_ [32]byte) (*types.Transaction, error) { + return _Marketplace.Contract.DeleteModelBid(&_Marketplace.TransactOpts, bidId_) +} + +// PostModelBid is a paid mutator transaction binding the contract method 0xede96bb1. +// +// Solidity: function postModelBid(address provider_, bytes32 modelId_, uint256 pricePerSecond_) returns(bytes32 bidId) +func (_Marketplace *MarketplaceTransactor) PostModelBid(opts *bind.TransactOpts, provider_ common.Address, modelId_ [32]byte, pricePerSecond_ *big.Int) (*types.Transaction, error) { + return _Marketplace.contract.Transact(opts, "postModelBid", provider_, modelId_, pricePerSecond_) +} + +// PostModelBid is a paid mutator transaction binding the contract method 0xede96bb1. +// +// Solidity: function postModelBid(address provider_, bytes32 modelId_, uint256 pricePerSecond_) returns(bytes32 bidId) +func (_Marketplace *MarketplaceSession) PostModelBid(provider_ common.Address, modelId_ [32]byte, pricePerSecond_ *big.Int) (*types.Transaction, error) { + return _Marketplace.Contract.PostModelBid(&_Marketplace.TransactOpts, provider_, modelId_, pricePerSecond_) +} + +// PostModelBid is a paid mutator transaction binding the contract method 0xede96bb1. +// +// Solidity: function postModelBid(address provider_, bytes32 modelId_, uint256 pricePerSecond_) returns(bytes32 bidId) +func (_Marketplace *MarketplaceTransactorSession) PostModelBid(provider_ common.Address, modelId_ [32]byte, pricePerSecond_ *big.Int) (*types.Transaction, error) { + return _Marketplace.Contract.PostModelBid(&_Marketplace.TransactOpts, provider_, modelId_, pricePerSecond_) +} + +// SetMarketplaceBidFee is a paid mutator transaction binding the contract method 0x849c239c. +// +// Solidity: function setMarketplaceBidFee(uint256 bidFee_) returns() +func (_Marketplace *MarketplaceTransactor) SetMarketplaceBidFee(opts *bind.TransactOpts, bidFee_ *big.Int) (*types.Transaction, error) { + return _Marketplace.contract.Transact(opts, "setMarketplaceBidFee", bidFee_) +} + +// SetMarketplaceBidFee is a paid mutator transaction binding the contract method 0x849c239c. +// +// Solidity: function setMarketplaceBidFee(uint256 bidFee_) returns() +func (_Marketplace *MarketplaceSession) SetMarketplaceBidFee(bidFee_ *big.Int) (*types.Transaction, error) { + return _Marketplace.Contract.SetMarketplaceBidFee(&_Marketplace.TransactOpts, bidFee_) +} + +// SetMarketplaceBidFee is a paid mutator transaction binding the contract method 0x849c239c. +// +// Solidity: function setMarketplaceBidFee(uint256 bidFee_) returns() +func (_Marketplace *MarketplaceTransactorSession) SetMarketplaceBidFee(bidFee_ *big.Int) (*types.Transaction, error) { + return _Marketplace.Contract.SetMarketplaceBidFee(&_Marketplace.TransactOpts, bidFee_) +} + +// SetMinMaxBidPricePerSecond is a paid mutator transaction binding the contract method 0xf748de1c. +// +// Solidity: function setMinMaxBidPricePerSecond(uint256 bidMinPricePerSecond_, uint256 bidMaxPricePerSecond_) returns() +func (_Marketplace *MarketplaceTransactor) SetMinMaxBidPricePerSecond(opts *bind.TransactOpts, bidMinPricePerSecond_ *big.Int, bidMaxPricePerSecond_ *big.Int) (*types.Transaction, error) { + return _Marketplace.contract.Transact(opts, "setMinMaxBidPricePerSecond", bidMinPricePerSecond_, bidMaxPricePerSecond_) +} + +// SetMinMaxBidPricePerSecond is a paid mutator transaction binding the contract method 0xf748de1c. +// +// Solidity: function setMinMaxBidPricePerSecond(uint256 bidMinPricePerSecond_, uint256 bidMaxPricePerSecond_) returns() +func (_Marketplace *MarketplaceSession) SetMinMaxBidPricePerSecond(bidMinPricePerSecond_ *big.Int, bidMaxPricePerSecond_ *big.Int) (*types.Transaction, error) { + return _Marketplace.Contract.SetMinMaxBidPricePerSecond(&_Marketplace.TransactOpts, bidMinPricePerSecond_, bidMaxPricePerSecond_) +} + +// SetMinMaxBidPricePerSecond is a paid mutator transaction binding the contract method 0xf748de1c. +// +// Solidity: function setMinMaxBidPricePerSecond(uint256 bidMinPricePerSecond_, uint256 bidMaxPricePerSecond_) returns() +func (_Marketplace *MarketplaceTransactorSession) SetMinMaxBidPricePerSecond(bidMinPricePerSecond_ *big.Int, bidMaxPricePerSecond_ *big.Int) (*types.Transaction, error) { + return _Marketplace.Contract.SetMinMaxBidPricePerSecond(&_Marketplace.TransactOpts, bidMinPricePerSecond_, bidMaxPricePerSecond_) +} + +// WithdrawFee is a paid mutator transaction binding the contract method 0xfd9be522. +// +// Solidity: function withdrawFee(address recipient_, uint256 amount_) returns() +func (_Marketplace *MarketplaceTransactor) WithdrawFee(opts *bind.TransactOpts, recipient_ common.Address, amount_ *big.Int) (*types.Transaction, error) { + return _Marketplace.contract.Transact(opts, "withdrawFee", recipient_, amount_) +} + +// WithdrawFee is a paid mutator transaction binding the contract method 0xfd9be522. +// +// Solidity: function withdrawFee(address recipient_, uint256 amount_) returns() +func (_Marketplace *MarketplaceSession) WithdrawFee(recipient_ common.Address, amount_ *big.Int) (*types.Transaction, error) { + return _Marketplace.Contract.WithdrawFee(&_Marketplace.TransactOpts, recipient_, amount_) +} + +// WithdrawFee is a paid mutator transaction binding the contract method 0xfd9be522. +// +// Solidity: function withdrawFee(address recipient_, uint256 amount_) returns() +func (_Marketplace *MarketplaceTransactorSession) WithdrawFee(recipient_ common.Address, amount_ *big.Int) (*types.Transaction, error) { + return _Marketplace.Contract.WithdrawFee(&_Marketplace.TransactOpts, recipient_, amount_) +} + +// MarketplaceInitializedIterator is returned from FilterInitialized and is used to iterate over the raw logs and unpacked data for Initialized events raised by the Marketplace contract. +type MarketplaceInitializedIterator struct { + Event *MarketplaceInitialized // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *MarketplaceInitializedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(MarketplaceInitialized) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(MarketplaceInitialized) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *MarketplaceInitializedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *MarketplaceInitializedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// MarketplaceInitialized represents a Initialized event raised by the Marketplace contract. +type MarketplaceInitialized struct { + StorageSlot [32]byte + Raw types.Log // Blockchain specific contextual infos +} + +// FilterInitialized is a free log retrieval operation binding the contract event 0xdc73717d728bcfa015e8117438a65319aa06e979ca324afa6e1ea645c28ea15d. +// +// Solidity: event Initialized(bytes32 storageSlot) +func (_Marketplace *MarketplaceFilterer) FilterInitialized(opts *bind.FilterOpts) (*MarketplaceInitializedIterator, error) { + + logs, sub, err := _Marketplace.contract.FilterLogs(opts, "Initialized") + if err != nil { + return nil, err + } + return &MarketplaceInitializedIterator{contract: _Marketplace.contract, event: "Initialized", logs: logs, sub: sub}, nil +} + +// WatchInitialized is a free log subscription operation binding the contract event 0xdc73717d728bcfa015e8117438a65319aa06e979ca324afa6e1ea645c28ea15d. +// +// Solidity: event Initialized(bytes32 storageSlot) +func (_Marketplace *MarketplaceFilterer) WatchInitialized(opts *bind.WatchOpts, sink chan<- *MarketplaceInitialized) (event.Subscription, error) { + + logs, sub, err := _Marketplace.contract.WatchLogs(opts, "Initialized") + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(MarketplaceInitialized) + if err := _Marketplace.contract.UnpackLog(event, "Initialized", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseInitialized is a log parse operation binding the contract event 0xdc73717d728bcfa015e8117438a65319aa06e979ca324afa6e1ea645c28ea15d. +// +// Solidity: event Initialized(bytes32 storageSlot) +func (_Marketplace *MarketplaceFilterer) ParseInitialized(log types.Log) (*MarketplaceInitialized, error) { + event := new(MarketplaceInitialized) + if err := _Marketplace.contract.UnpackLog(event, "Initialized", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// MarketplaceMaretplaceFeeUpdatedIterator is returned from FilterMaretplaceFeeUpdated and is used to iterate over the raw logs and unpacked data for MaretplaceFeeUpdated events raised by the Marketplace contract. +type MarketplaceMaretplaceFeeUpdatedIterator struct { + Event *MarketplaceMaretplaceFeeUpdated // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *MarketplaceMaretplaceFeeUpdatedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(MarketplaceMaretplaceFeeUpdated) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(MarketplaceMaretplaceFeeUpdated) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *MarketplaceMaretplaceFeeUpdatedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *MarketplaceMaretplaceFeeUpdatedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// MarketplaceMaretplaceFeeUpdated represents a MaretplaceFeeUpdated event raised by the Marketplace contract. +type MarketplaceMaretplaceFeeUpdated struct { + BidFee *big.Int + Raw types.Log // Blockchain specific contextual infos +} + +// FilterMaretplaceFeeUpdated is a free log retrieval operation binding the contract event 0x9c16b729dd48a231a60f92c4c1a12a5225825dd20699fc221314ea2d73a97cce. +// +// Solidity: event MaretplaceFeeUpdated(uint256 bidFee) +func (_Marketplace *MarketplaceFilterer) FilterMaretplaceFeeUpdated(opts *bind.FilterOpts) (*MarketplaceMaretplaceFeeUpdatedIterator, error) { + + logs, sub, err := _Marketplace.contract.FilterLogs(opts, "MaretplaceFeeUpdated") + if err != nil { + return nil, err + } + return &MarketplaceMaretplaceFeeUpdatedIterator{contract: _Marketplace.contract, event: "MaretplaceFeeUpdated", logs: logs, sub: sub}, nil +} + +// WatchMaretplaceFeeUpdated is a free log subscription operation binding the contract event 0x9c16b729dd48a231a60f92c4c1a12a5225825dd20699fc221314ea2d73a97cce. +// +// Solidity: event MaretplaceFeeUpdated(uint256 bidFee) +func (_Marketplace *MarketplaceFilterer) WatchMaretplaceFeeUpdated(opts *bind.WatchOpts, sink chan<- *MarketplaceMaretplaceFeeUpdated) (event.Subscription, error) { + + logs, sub, err := _Marketplace.contract.WatchLogs(opts, "MaretplaceFeeUpdated") + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(MarketplaceMaretplaceFeeUpdated) + if err := _Marketplace.contract.UnpackLog(event, "MaretplaceFeeUpdated", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseMaretplaceFeeUpdated is a log parse operation binding the contract event 0x9c16b729dd48a231a60f92c4c1a12a5225825dd20699fc221314ea2d73a97cce. +// +// Solidity: event MaretplaceFeeUpdated(uint256 bidFee) +func (_Marketplace *MarketplaceFilterer) ParseMaretplaceFeeUpdated(log types.Log) (*MarketplaceMaretplaceFeeUpdated, error) { + event := new(MarketplaceMaretplaceFeeUpdated) + if err := _Marketplace.contract.UnpackLog(event, "MaretplaceFeeUpdated", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// MarketplaceMarketplaceBidDeletedIterator is returned from FilterMarketplaceBidDeleted and is used to iterate over the raw logs and unpacked data for MarketplaceBidDeleted events raised by the Marketplace contract. +type MarketplaceMarketplaceBidDeletedIterator struct { + Event *MarketplaceMarketplaceBidDeleted // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *MarketplaceMarketplaceBidDeletedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(MarketplaceMarketplaceBidDeleted) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(MarketplaceMarketplaceBidDeleted) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *MarketplaceMarketplaceBidDeletedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *MarketplaceMarketplaceBidDeletedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// MarketplaceMarketplaceBidDeleted represents a MarketplaceBidDeleted event raised by the Marketplace contract. +type MarketplaceMarketplaceBidDeleted struct { + Provider common.Address + ModelId [32]byte + Nonce *big.Int + Raw types.Log // Blockchain specific contextual infos +} + +// FilterMarketplaceBidDeleted is a free log retrieval operation binding the contract event 0x409dfc0f98bf6e062e576fbdc63c9f82392d44deff61e3412f8bd256d2814883. +// +// Solidity: event MarketplaceBidDeleted(address indexed provider, bytes32 indexed modelId, uint256 nonce) +func (_Marketplace *MarketplaceFilterer) FilterMarketplaceBidDeleted(opts *bind.FilterOpts, provider []common.Address, modelId [][32]byte) (*MarketplaceMarketplaceBidDeletedIterator, error) { + + var providerRule []interface{} + for _, providerItem := range provider { + providerRule = append(providerRule, providerItem) + } + var modelIdRule []interface{} + for _, modelIdItem := range modelId { + modelIdRule = append(modelIdRule, modelIdItem) + } + + logs, sub, err := _Marketplace.contract.FilterLogs(opts, "MarketplaceBidDeleted", providerRule, modelIdRule) + if err != nil { + return nil, err + } + return &MarketplaceMarketplaceBidDeletedIterator{contract: _Marketplace.contract, event: "MarketplaceBidDeleted", logs: logs, sub: sub}, nil +} + +// WatchMarketplaceBidDeleted is a free log subscription operation binding the contract event 0x409dfc0f98bf6e062e576fbdc63c9f82392d44deff61e3412f8bd256d2814883. +// +// Solidity: event MarketplaceBidDeleted(address indexed provider, bytes32 indexed modelId, uint256 nonce) +func (_Marketplace *MarketplaceFilterer) WatchMarketplaceBidDeleted(opts *bind.WatchOpts, sink chan<- *MarketplaceMarketplaceBidDeleted, provider []common.Address, modelId [][32]byte) (event.Subscription, error) { + + var providerRule []interface{} + for _, providerItem := range provider { + providerRule = append(providerRule, providerItem) + } + var modelIdRule []interface{} + for _, modelIdItem := range modelId { + modelIdRule = append(modelIdRule, modelIdItem) + } + + logs, sub, err := _Marketplace.contract.WatchLogs(opts, "MarketplaceBidDeleted", providerRule, modelIdRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(MarketplaceMarketplaceBidDeleted) + if err := _Marketplace.contract.UnpackLog(event, "MarketplaceBidDeleted", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseMarketplaceBidDeleted is a log parse operation binding the contract event 0x409dfc0f98bf6e062e576fbdc63c9f82392d44deff61e3412f8bd256d2814883. +// +// Solidity: event MarketplaceBidDeleted(address indexed provider, bytes32 indexed modelId, uint256 nonce) +func (_Marketplace *MarketplaceFilterer) ParseMarketplaceBidDeleted(log types.Log) (*MarketplaceMarketplaceBidDeleted, error) { + event := new(MarketplaceMarketplaceBidDeleted) + if err := _Marketplace.contract.UnpackLog(event, "MarketplaceBidDeleted", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// MarketplaceMarketplaceBidMinMaxPriceUpdatedIterator is returned from FilterMarketplaceBidMinMaxPriceUpdated and is used to iterate over the raw logs and unpacked data for MarketplaceBidMinMaxPriceUpdated events raised by the Marketplace contract. +type MarketplaceMarketplaceBidMinMaxPriceUpdatedIterator struct { + Event *MarketplaceMarketplaceBidMinMaxPriceUpdated // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *MarketplaceMarketplaceBidMinMaxPriceUpdatedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(MarketplaceMarketplaceBidMinMaxPriceUpdated) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(MarketplaceMarketplaceBidMinMaxPriceUpdated) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *MarketplaceMarketplaceBidMinMaxPriceUpdatedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *MarketplaceMarketplaceBidMinMaxPriceUpdatedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// MarketplaceMarketplaceBidMinMaxPriceUpdated represents a MarketplaceBidMinMaxPriceUpdated event raised by the Marketplace contract. +type MarketplaceMarketplaceBidMinMaxPriceUpdated struct { + BidMinPricePerSecond *big.Int + BidMaxPricePerSecond *big.Int + Raw types.Log // Blockchain specific contextual infos +} + +// FilterMarketplaceBidMinMaxPriceUpdated is a free log retrieval operation binding the contract event 0x522f4bcd10bb097a0de10e63abe81fdef5ff505c11cded69df4bb84b1f87a563. +// +// Solidity: event MarketplaceBidMinMaxPriceUpdated(uint256 bidMinPricePerSecond, uint256 bidMaxPricePerSecond) +func (_Marketplace *MarketplaceFilterer) FilterMarketplaceBidMinMaxPriceUpdated(opts *bind.FilterOpts) (*MarketplaceMarketplaceBidMinMaxPriceUpdatedIterator, error) { + + logs, sub, err := _Marketplace.contract.FilterLogs(opts, "MarketplaceBidMinMaxPriceUpdated") + if err != nil { + return nil, err + } + return &MarketplaceMarketplaceBidMinMaxPriceUpdatedIterator{contract: _Marketplace.contract, event: "MarketplaceBidMinMaxPriceUpdated", logs: logs, sub: sub}, nil +} + +// WatchMarketplaceBidMinMaxPriceUpdated is a free log subscription operation binding the contract event 0x522f4bcd10bb097a0de10e63abe81fdef5ff505c11cded69df4bb84b1f87a563. +// +// Solidity: event MarketplaceBidMinMaxPriceUpdated(uint256 bidMinPricePerSecond, uint256 bidMaxPricePerSecond) +func (_Marketplace *MarketplaceFilterer) WatchMarketplaceBidMinMaxPriceUpdated(opts *bind.WatchOpts, sink chan<- *MarketplaceMarketplaceBidMinMaxPriceUpdated) (event.Subscription, error) { + + logs, sub, err := _Marketplace.contract.WatchLogs(opts, "MarketplaceBidMinMaxPriceUpdated") + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(MarketplaceMarketplaceBidMinMaxPriceUpdated) + if err := _Marketplace.contract.UnpackLog(event, "MarketplaceBidMinMaxPriceUpdated", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseMarketplaceBidMinMaxPriceUpdated is a log parse operation binding the contract event 0x522f4bcd10bb097a0de10e63abe81fdef5ff505c11cded69df4bb84b1f87a563. +// +// Solidity: event MarketplaceBidMinMaxPriceUpdated(uint256 bidMinPricePerSecond, uint256 bidMaxPricePerSecond) +func (_Marketplace *MarketplaceFilterer) ParseMarketplaceBidMinMaxPriceUpdated(log types.Log) (*MarketplaceMarketplaceBidMinMaxPriceUpdated, error) { + event := new(MarketplaceMarketplaceBidMinMaxPriceUpdated) + if err := _Marketplace.contract.UnpackLog(event, "MarketplaceBidMinMaxPriceUpdated", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// MarketplaceMarketplaceBidPostedIterator is returned from FilterMarketplaceBidPosted and is used to iterate over the raw logs and unpacked data for MarketplaceBidPosted events raised by the Marketplace contract. +type MarketplaceMarketplaceBidPostedIterator struct { + Event *MarketplaceMarketplaceBidPosted // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *MarketplaceMarketplaceBidPostedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(MarketplaceMarketplaceBidPosted) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(MarketplaceMarketplaceBidPosted) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *MarketplaceMarketplaceBidPostedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *MarketplaceMarketplaceBidPostedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// MarketplaceMarketplaceBidPosted represents a MarketplaceBidPosted event raised by the Marketplace contract. +type MarketplaceMarketplaceBidPosted struct { + Provider common.Address + ModelId [32]byte + Nonce *big.Int + Raw types.Log // Blockchain specific contextual infos +} + +// FilterMarketplaceBidPosted is a free log retrieval operation binding the contract event 0xfc422bb61cd73bc76f27eecf69cce3db0b05d39769ca3ed0fb314a3d04bff6f6. +// +// Solidity: event MarketplaceBidPosted(address indexed provider, bytes32 indexed modelId, uint256 nonce) +func (_Marketplace *MarketplaceFilterer) FilterMarketplaceBidPosted(opts *bind.FilterOpts, provider []common.Address, modelId [][32]byte) (*MarketplaceMarketplaceBidPostedIterator, error) { + + var providerRule []interface{} + for _, providerItem := range provider { + providerRule = append(providerRule, providerItem) + } + var modelIdRule []interface{} + for _, modelIdItem := range modelId { + modelIdRule = append(modelIdRule, modelIdItem) + } + + logs, sub, err := _Marketplace.contract.FilterLogs(opts, "MarketplaceBidPosted", providerRule, modelIdRule) + if err != nil { + return nil, err + } + return &MarketplaceMarketplaceBidPostedIterator{contract: _Marketplace.contract, event: "MarketplaceBidPosted", logs: logs, sub: sub}, nil +} + +// WatchMarketplaceBidPosted is a free log subscription operation binding the contract event 0xfc422bb61cd73bc76f27eecf69cce3db0b05d39769ca3ed0fb314a3d04bff6f6. +// +// Solidity: event MarketplaceBidPosted(address indexed provider, bytes32 indexed modelId, uint256 nonce) +func (_Marketplace *MarketplaceFilterer) WatchMarketplaceBidPosted(opts *bind.WatchOpts, sink chan<- *MarketplaceMarketplaceBidPosted, provider []common.Address, modelId [][32]byte) (event.Subscription, error) { + + var providerRule []interface{} + for _, providerItem := range provider { + providerRule = append(providerRule, providerItem) + } + var modelIdRule []interface{} + for _, modelIdItem := range modelId { + modelIdRule = append(modelIdRule, modelIdItem) + } + + logs, sub, err := _Marketplace.contract.WatchLogs(opts, "MarketplaceBidPosted", providerRule, modelIdRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(MarketplaceMarketplaceBidPosted) + if err := _Marketplace.contract.UnpackLog(event, "MarketplaceBidPosted", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseMarketplaceBidPosted is a log parse operation binding the contract event 0xfc422bb61cd73bc76f27eecf69cce3db0b05d39769ca3ed0fb314a3d04bff6f6. +// +// Solidity: event MarketplaceBidPosted(address indexed provider, bytes32 indexed modelId, uint256 nonce) +func (_Marketplace *MarketplaceFilterer) ParseMarketplaceBidPosted(log types.Log) (*MarketplaceMarketplaceBidPosted, error) { + event := new(MarketplaceMarketplaceBidPosted) + if err := _Marketplace.contract.UnpackLog(event, "MarketplaceBidPosted", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} diff --git a/proxy-router/internal/repositories/contracts/bindings/modelregistry/ModelRegistry.go b/proxy-router/internal/repositories/contracts/bindings/modelregistry/ModelRegistry.go new file mode 100644 index 00000000..ee5a316d --- /dev/null +++ b/proxy-router/internal/repositories/contracts/bindings/modelregistry/ModelRegistry.go @@ -0,0 +1,1611 @@ +// Code generated - DO NOT EDIT. +// This file is a generated binding and any manual changes will be lost. + +package modelregistry + +import ( + "errors" + "math/big" + "strings" + + ethereum "github.com/ethereum/go-ethereum" + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/event" +) + +// Reference imports to suppress errors if they are not otherwise used. +var ( + _ = errors.New + _ = big.NewInt + _ = strings.NewReader + _ = ethereum.NotFound + _ = bind.Bind + _ = common.Big1 + _ = types.BloomLookup + _ = event.NewSubscription + _ = abi.ConvertType +) + +// IBidStorageBid is an auto generated low-level Go binding around an user-defined struct. +type IBidStorageBid struct { + Provider common.Address + ModelId [32]byte + PricePerSecond *big.Int + Nonce *big.Int + CreatedAt *big.Int + DeletedAt *big.Int +} + +// IModelStorageModel is an auto generated low-level Go binding around an user-defined struct. +type IModelStorageModel struct { + IpfsCID [32]byte + Fee *big.Int + Stake *big.Int + Owner common.Address + Name string + Tags []string + CreatedAt *big.Int + IsDeleted bool +} + +// ModelRegistryMetaData contains all meta data concerning the ModelRegistry contract. +var ModelRegistryMetaData = &bind.MetaData{ + ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"delegator\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"delegatee\",\"type\":\"address\"}],\"name\":\"InsufficientRightsForOperation\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ModelHasActiveBids\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ModelHasAlreadyDeregistered\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ModelNotFound\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"minAmount\",\"type\":\"uint256\"}],\"name\":\"ModelStakeTooLow\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account_\",\"type\":\"address\"}],\"name\":\"OwnableUnauthorizedAccount\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"storageSlot\",\"type\":\"bytes32\"}],\"name\":\"Initialized\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"modelId\",\"type\":\"bytes32\"}],\"name\":\"ModelDeregistered\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"modelMinimumStake\",\"type\":\"uint256\"}],\"name\":\"ModelMinimumStakeUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"modelId\",\"type\":\"bytes32\"}],\"name\":\"ModelRegisteredUpdated\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"BIDS_STORAGE_SLOT\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"DELEGATION_RULES_MARKETPLACE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"DELEGATION_RULES_MODEL\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"DELEGATION_RULES_PROVIDER\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"DELEGATION_RULES_SESSION\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"DELEGATION_STORAGE_SLOT\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"DIAMOND_OWNABLE_STORAGE_SLOT\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"MODELS_STORAGE_SLOT\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"__ModelRegistry_init\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"offset_\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"limit_\",\"type\":\"uint256\"}],\"name\":\"getActiveModelIds\",\"outputs\":[{\"internalType\":\"bytes32[]\",\"name\":\"\",\"type\":\"bytes32[]\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"bidId_\",\"type\":\"bytes32\"}],\"name\":\"getBid\",\"outputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"provider\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"modelId\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"pricePerSecond\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"internalType\":\"uint128\",\"name\":\"createdAt\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"deletedAt\",\"type\":\"uint128\"}],\"internalType\":\"structIBidStorage.Bid\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"modelId_\",\"type\":\"bytes32\"}],\"name\":\"getIsModelActive\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"modelId_\",\"type\":\"bytes32\"}],\"name\":\"getModel\",\"outputs\":[{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"ipfsCID\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"fee\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"stake\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"string\",\"name\":\"name\",\"type\":\"string\"},{\"internalType\":\"string[]\",\"name\":\"tags\",\"type\":\"string[]\"},{\"internalType\":\"uint128\",\"name\":\"createdAt\",\"type\":\"uint128\"},{\"internalType\":\"bool\",\"name\":\"isDeleted\",\"type\":\"bool\"}],\"internalType\":\"structIModelStorage.Model\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"modelId_\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"offset_\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"limit_\",\"type\":\"uint256\"}],\"name\":\"getModelActiveBids\",\"outputs\":[{\"internalType\":\"bytes32[]\",\"name\":\"\",\"type\":\"bytes32[]\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"modelId_\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"offset_\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"limit_\",\"type\":\"uint256\"}],\"name\":\"getModelBids\",\"outputs\":[{\"internalType\":\"bytes32[]\",\"name\":\"\",\"type\":\"bytes32[]\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account_\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"baseModelId_\",\"type\":\"bytes32\"}],\"name\":\"getModelId\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"offset_\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"limit_\",\"type\":\"uint256\"}],\"name\":\"getModelIds\",\"outputs\":[{\"internalType\":\"bytes32[]\",\"name\":\"\",\"type\":\"bytes32[]\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getModelMinimumStake\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"provider_\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"offset_\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"limit_\",\"type\":\"uint256\"}],\"name\":\"getProviderActiveBids\",\"outputs\":[{\"internalType\":\"bytes32[]\",\"name\":\"\",\"type\":\"bytes32[]\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"provider_\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"offset_\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"limit_\",\"type\":\"uint256\"}],\"name\":\"getProviderBids\",\"outputs\":[{\"internalType\":\"bytes32[]\",\"name\":\"\",\"type\":\"bytes32[]\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getRegistry\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getToken\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"bidId_\",\"type\":\"bytes32\"}],\"name\":\"isBidActive\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"delegatee_\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"delegator_\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"rights_\",\"type\":\"bytes32\"}],\"name\":\"isRightsDelegated\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"modelId_\",\"type\":\"bytes32\"}],\"name\":\"modelDeregister\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"modelOwner_\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"baseModelId_\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"ipfsCID_\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"fee_\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"amount_\",\"type\":\"uint256\"},{\"internalType\":\"string\",\"name\":\"name_\",\"type\":\"string\"},{\"internalType\":\"string[]\",\"name\":\"tags_\",\"type\":\"string[]\"}],\"name\":\"modelRegister\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"modelMinimumStake_\",\"type\":\"uint256\"}],\"name\":\"modelSetMinStake\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]", +} + +// ModelRegistryABI is the input ABI used to generate the binding from. +// Deprecated: Use ModelRegistryMetaData.ABI instead. +var ModelRegistryABI = ModelRegistryMetaData.ABI + +// ModelRegistry is an auto generated Go binding around an Ethereum contract. +type ModelRegistry struct { + ModelRegistryCaller // Read-only binding to the contract + ModelRegistryTransactor // Write-only binding to the contract + ModelRegistryFilterer // Log filterer for contract events +} + +// ModelRegistryCaller is an auto generated read-only Go binding around an Ethereum contract. +type ModelRegistryCaller struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// ModelRegistryTransactor is an auto generated write-only Go binding around an Ethereum contract. +type ModelRegistryTransactor struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// ModelRegistryFilterer is an auto generated log filtering Go binding around an Ethereum contract events. +type ModelRegistryFilterer struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// ModelRegistrySession is an auto generated Go binding around an Ethereum contract, +// with pre-set call and transact options. +type ModelRegistrySession struct { + Contract *ModelRegistry // Generic contract binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// ModelRegistryCallerSession is an auto generated read-only Go binding around an Ethereum contract, +// with pre-set call options. +type ModelRegistryCallerSession struct { + Contract *ModelRegistryCaller // Generic contract caller binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session +} + +// ModelRegistryTransactorSession is an auto generated write-only Go binding around an Ethereum contract, +// with pre-set transact options. +type ModelRegistryTransactorSession struct { + Contract *ModelRegistryTransactor // Generic contract transactor binding to set the session for + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// ModelRegistryRaw is an auto generated low-level Go binding around an Ethereum contract. +type ModelRegistryRaw struct { + Contract *ModelRegistry // Generic contract binding to access the raw methods on +} + +// ModelRegistryCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. +type ModelRegistryCallerRaw struct { + Contract *ModelRegistryCaller // Generic read-only contract binding to access the raw methods on +} + +// ModelRegistryTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. +type ModelRegistryTransactorRaw struct { + Contract *ModelRegistryTransactor // Generic write-only contract binding to access the raw methods on +} + +// NewModelRegistry creates a new instance of ModelRegistry, bound to a specific deployed contract. +func NewModelRegistry(address common.Address, backend bind.ContractBackend) (*ModelRegistry, error) { + contract, err := bindModelRegistry(address, backend, backend, backend) + if err != nil { + return nil, err + } + return &ModelRegistry{ModelRegistryCaller: ModelRegistryCaller{contract: contract}, ModelRegistryTransactor: ModelRegistryTransactor{contract: contract}, ModelRegistryFilterer: ModelRegistryFilterer{contract: contract}}, nil +} + +// NewModelRegistryCaller creates a new read-only instance of ModelRegistry, bound to a specific deployed contract. +func NewModelRegistryCaller(address common.Address, caller bind.ContractCaller) (*ModelRegistryCaller, error) { + contract, err := bindModelRegistry(address, caller, nil, nil) + if err != nil { + return nil, err + } + return &ModelRegistryCaller{contract: contract}, nil +} + +// NewModelRegistryTransactor creates a new write-only instance of ModelRegistry, bound to a specific deployed contract. +func NewModelRegistryTransactor(address common.Address, transactor bind.ContractTransactor) (*ModelRegistryTransactor, error) { + contract, err := bindModelRegistry(address, nil, transactor, nil) + if err != nil { + return nil, err + } + return &ModelRegistryTransactor{contract: contract}, nil +} + +// NewModelRegistryFilterer creates a new log filterer instance of ModelRegistry, bound to a specific deployed contract. +func NewModelRegistryFilterer(address common.Address, filterer bind.ContractFilterer) (*ModelRegistryFilterer, error) { + contract, err := bindModelRegistry(address, nil, nil, filterer) + if err != nil { + return nil, err + } + return &ModelRegistryFilterer{contract: contract}, nil +} + +// bindModelRegistry binds a generic wrapper to an already deployed contract. +func bindModelRegistry(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { + parsed, err := ModelRegistryMetaData.GetAbi() + if err != nil { + return nil, err + } + return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_ModelRegistry *ModelRegistryRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _ModelRegistry.Contract.ModelRegistryCaller.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_ModelRegistry *ModelRegistryRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _ModelRegistry.Contract.ModelRegistryTransactor.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_ModelRegistry *ModelRegistryRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _ModelRegistry.Contract.ModelRegistryTransactor.contract.Transact(opts, method, params...) +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_ModelRegistry *ModelRegistryCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _ModelRegistry.Contract.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_ModelRegistry *ModelRegistryTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _ModelRegistry.Contract.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_ModelRegistry *ModelRegistryTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _ModelRegistry.Contract.contract.Transact(opts, method, params...) +} + +// BIDSSTORAGESLOT is a free data retrieval call binding the contract method 0x266ccff0. +// +// Solidity: function BIDS_STORAGE_SLOT() view returns(bytes32) +func (_ModelRegistry *ModelRegistryCaller) BIDSSTORAGESLOT(opts *bind.CallOpts) ([32]byte, error) { + var out []interface{} + err := _ModelRegistry.contract.Call(opts, &out, "BIDS_STORAGE_SLOT") + + if err != nil { + return *new([32]byte), err + } + + out0 := *abi.ConvertType(out[0], new([32]byte)).(*[32]byte) + + return out0, err + +} + +// BIDSSTORAGESLOT is a free data retrieval call binding the contract method 0x266ccff0. +// +// Solidity: function BIDS_STORAGE_SLOT() view returns(bytes32) +func (_ModelRegistry *ModelRegistrySession) BIDSSTORAGESLOT() ([32]byte, error) { + return _ModelRegistry.Contract.BIDSSTORAGESLOT(&_ModelRegistry.CallOpts) +} + +// BIDSSTORAGESLOT is a free data retrieval call binding the contract method 0x266ccff0. +// +// Solidity: function BIDS_STORAGE_SLOT() view returns(bytes32) +func (_ModelRegistry *ModelRegistryCallerSession) BIDSSTORAGESLOT() ([32]byte, error) { + return _ModelRegistry.Contract.BIDSSTORAGESLOT(&_ModelRegistry.CallOpts) +} + +// DELEGATIONRULESMARKETPLACE is a free data retrieval call binding the contract method 0xad34a150. +// +// Solidity: function DELEGATION_RULES_MARKETPLACE() view returns(bytes32) +func (_ModelRegistry *ModelRegistryCaller) DELEGATIONRULESMARKETPLACE(opts *bind.CallOpts) ([32]byte, error) { + var out []interface{} + err := _ModelRegistry.contract.Call(opts, &out, "DELEGATION_RULES_MARKETPLACE") + + if err != nil { + return *new([32]byte), err + } + + out0 := *abi.ConvertType(out[0], new([32]byte)).(*[32]byte) + + return out0, err + +} + +// DELEGATIONRULESMARKETPLACE is a free data retrieval call binding the contract method 0xad34a150. +// +// Solidity: function DELEGATION_RULES_MARKETPLACE() view returns(bytes32) +func (_ModelRegistry *ModelRegistrySession) DELEGATIONRULESMARKETPLACE() ([32]byte, error) { + return _ModelRegistry.Contract.DELEGATIONRULESMARKETPLACE(&_ModelRegistry.CallOpts) +} + +// DELEGATIONRULESMARKETPLACE is a free data retrieval call binding the contract method 0xad34a150. +// +// Solidity: function DELEGATION_RULES_MARKETPLACE() view returns(bytes32) +func (_ModelRegistry *ModelRegistryCallerSession) DELEGATIONRULESMARKETPLACE() ([32]byte, error) { + return _ModelRegistry.Contract.DELEGATIONRULESMARKETPLACE(&_ModelRegistry.CallOpts) +} + +// DELEGATIONRULESMODEL is a free data retrieval call binding the contract method 0x86878047. +// +// Solidity: function DELEGATION_RULES_MODEL() view returns(bytes32) +func (_ModelRegistry *ModelRegistryCaller) DELEGATIONRULESMODEL(opts *bind.CallOpts) ([32]byte, error) { + var out []interface{} + err := _ModelRegistry.contract.Call(opts, &out, "DELEGATION_RULES_MODEL") + + if err != nil { + return *new([32]byte), err + } + + out0 := *abi.ConvertType(out[0], new([32]byte)).(*[32]byte) + + return out0, err + +} + +// DELEGATIONRULESMODEL is a free data retrieval call binding the contract method 0x86878047. +// +// Solidity: function DELEGATION_RULES_MODEL() view returns(bytes32) +func (_ModelRegistry *ModelRegistrySession) DELEGATIONRULESMODEL() ([32]byte, error) { + return _ModelRegistry.Contract.DELEGATIONRULESMODEL(&_ModelRegistry.CallOpts) +} + +// DELEGATIONRULESMODEL is a free data retrieval call binding the contract method 0x86878047. +// +// Solidity: function DELEGATION_RULES_MODEL() view returns(bytes32) +func (_ModelRegistry *ModelRegistryCallerSession) DELEGATIONRULESMODEL() ([32]byte, error) { + return _ModelRegistry.Contract.DELEGATIONRULESMODEL(&_ModelRegistry.CallOpts) +} + +// DELEGATIONRULESPROVIDER is a free data retrieval call binding the contract method 0x58aeef93. +// +// Solidity: function DELEGATION_RULES_PROVIDER() view returns(bytes32) +func (_ModelRegistry *ModelRegistryCaller) DELEGATIONRULESPROVIDER(opts *bind.CallOpts) ([32]byte, error) { + var out []interface{} + err := _ModelRegistry.contract.Call(opts, &out, "DELEGATION_RULES_PROVIDER") + + if err != nil { + return *new([32]byte), err + } + + out0 := *abi.ConvertType(out[0], new([32]byte)).(*[32]byte) + + return out0, err + +} + +// DELEGATIONRULESPROVIDER is a free data retrieval call binding the contract method 0x58aeef93. +// +// Solidity: function DELEGATION_RULES_PROVIDER() view returns(bytes32) +func (_ModelRegistry *ModelRegistrySession) DELEGATIONRULESPROVIDER() ([32]byte, error) { + return _ModelRegistry.Contract.DELEGATIONRULESPROVIDER(&_ModelRegistry.CallOpts) +} + +// DELEGATIONRULESPROVIDER is a free data retrieval call binding the contract method 0x58aeef93. +// +// Solidity: function DELEGATION_RULES_PROVIDER() view returns(bytes32) +func (_ModelRegistry *ModelRegistryCallerSession) DELEGATIONRULESPROVIDER() ([32]byte, error) { + return _ModelRegistry.Contract.DELEGATIONRULESPROVIDER(&_ModelRegistry.CallOpts) +} + +// DELEGATIONRULESSESSION is a free data retrieval call binding the contract method 0xd1b43638. +// +// Solidity: function DELEGATION_RULES_SESSION() view returns(bytes32) +func (_ModelRegistry *ModelRegistryCaller) DELEGATIONRULESSESSION(opts *bind.CallOpts) ([32]byte, error) { + var out []interface{} + err := _ModelRegistry.contract.Call(opts, &out, "DELEGATION_RULES_SESSION") + + if err != nil { + return *new([32]byte), err + } + + out0 := *abi.ConvertType(out[0], new([32]byte)).(*[32]byte) + + return out0, err + +} + +// DELEGATIONRULESSESSION is a free data retrieval call binding the contract method 0xd1b43638. +// +// Solidity: function DELEGATION_RULES_SESSION() view returns(bytes32) +func (_ModelRegistry *ModelRegistrySession) DELEGATIONRULESSESSION() ([32]byte, error) { + return _ModelRegistry.Contract.DELEGATIONRULESSESSION(&_ModelRegistry.CallOpts) +} + +// DELEGATIONRULESSESSION is a free data retrieval call binding the contract method 0xd1b43638. +// +// Solidity: function DELEGATION_RULES_SESSION() view returns(bytes32) +func (_ModelRegistry *ModelRegistryCallerSession) DELEGATIONRULESSESSION() ([32]byte, error) { + return _ModelRegistry.Contract.DELEGATIONRULESSESSION(&_ModelRegistry.CallOpts) +} + +// DELEGATIONSTORAGESLOT is a free data retrieval call binding the contract method 0xdd9b48cb. +// +// Solidity: function DELEGATION_STORAGE_SLOT() view returns(bytes32) +func (_ModelRegistry *ModelRegistryCaller) DELEGATIONSTORAGESLOT(opts *bind.CallOpts) ([32]byte, error) { + var out []interface{} + err := _ModelRegistry.contract.Call(opts, &out, "DELEGATION_STORAGE_SLOT") + + if err != nil { + return *new([32]byte), err + } + + out0 := *abi.ConvertType(out[0], new([32]byte)).(*[32]byte) + + return out0, err + +} + +// DELEGATIONSTORAGESLOT is a free data retrieval call binding the contract method 0xdd9b48cb. +// +// Solidity: function DELEGATION_STORAGE_SLOT() view returns(bytes32) +func (_ModelRegistry *ModelRegistrySession) DELEGATIONSTORAGESLOT() ([32]byte, error) { + return _ModelRegistry.Contract.DELEGATIONSTORAGESLOT(&_ModelRegistry.CallOpts) +} + +// DELEGATIONSTORAGESLOT is a free data retrieval call binding the contract method 0xdd9b48cb. +// +// Solidity: function DELEGATION_STORAGE_SLOT() view returns(bytes32) +func (_ModelRegistry *ModelRegistryCallerSession) DELEGATIONSTORAGESLOT() ([32]byte, error) { + return _ModelRegistry.Contract.DELEGATIONSTORAGESLOT(&_ModelRegistry.CallOpts) +} + +// DIAMONDOWNABLESTORAGESLOT is a free data retrieval call binding the contract method 0x4ac3371e. +// +// Solidity: function DIAMOND_OWNABLE_STORAGE_SLOT() view returns(bytes32) +func (_ModelRegistry *ModelRegistryCaller) DIAMONDOWNABLESTORAGESLOT(opts *bind.CallOpts) ([32]byte, error) { + var out []interface{} + err := _ModelRegistry.contract.Call(opts, &out, "DIAMOND_OWNABLE_STORAGE_SLOT") + + if err != nil { + return *new([32]byte), err + } + + out0 := *abi.ConvertType(out[0], new([32]byte)).(*[32]byte) + + return out0, err + +} + +// DIAMONDOWNABLESTORAGESLOT is a free data retrieval call binding the contract method 0x4ac3371e. +// +// Solidity: function DIAMOND_OWNABLE_STORAGE_SLOT() view returns(bytes32) +func (_ModelRegistry *ModelRegistrySession) DIAMONDOWNABLESTORAGESLOT() ([32]byte, error) { + return _ModelRegistry.Contract.DIAMONDOWNABLESTORAGESLOT(&_ModelRegistry.CallOpts) +} + +// DIAMONDOWNABLESTORAGESLOT is a free data retrieval call binding the contract method 0x4ac3371e. +// +// Solidity: function DIAMOND_OWNABLE_STORAGE_SLOT() view returns(bytes32) +func (_ModelRegistry *ModelRegistryCallerSession) DIAMONDOWNABLESTORAGESLOT() ([32]byte, error) { + return _ModelRegistry.Contract.DIAMONDOWNABLESTORAGESLOT(&_ModelRegistry.CallOpts) +} + +// MODELSSTORAGESLOT is a free data retrieval call binding the contract method 0x6f276c1e. +// +// Solidity: function MODELS_STORAGE_SLOT() view returns(bytes32) +func (_ModelRegistry *ModelRegistryCaller) MODELSSTORAGESLOT(opts *bind.CallOpts) ([32]byte, error) { + var out []interface{} + err := _ModelRegistry.contract.Call(opts, &out, "MODELS_STORAGE_SLOT") + + if err != nil { + return *new([32]byte), err + } + + out0 := *abi.ConvertType(out[0], new([32]byte)).(*[32]byte) + + return out0, err + +} + +// MODELSSTORAGESLOT is a free data retrieval call binding the contract method 0x6f276c1e. +// +// Solidity: function MODELS_STORAGE_SLOT() view returns(bytes32) +func (_ModelRegistry *ModelRegistrySession) MODELSSTORAGESLOT() ([32]byte, error) { + return _ModelRegistry.Contract.MODELSSTORAGESLOT(&_ModelRegistry.CallOpts) +} + +// MODELSSTORAGESLOT is a free data retrieval call binding the contract method 0x6f276c1e. +// +// Solidity: function MODELS_STORAGE_SLOT() view returns(bytes32) +func (_ModelRegistry *ModelRegistryCallerSession) MODELSSTORAGESLOT() ([32]byte, error) { + return _ModelRegistry.Contract.MODELSSTORAGESLOT(&_ModelRegistry.CallOpts) +} + +// GetActiveModelIds is a free data retrieval call binding the contract method 0x3839d3dc. +// +// Solidity: function getActiveModelIds(uint256 offset_, uint256 limit_) view returns(bytes32[], uint256) +func (_ModelRegistry *ModelRegistryCaller) GetActiveModelIds(opts *bind.CallOpts, offset_ *big.Int, limit_ *big.Int) ([][32]byte, *big.Int, error) { + var out []interface{} + err := _ModelRegistry.contract.Call(opts, &out, "getActiveModelIds", offset_, limit_) + + if err != nil { + return *new([][32]byte), *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new([][32]byte)).(*[][32]byte) + out1 := *abi.ConvertType(out[1], new(*big.Int)).(**big.Int) + + return out0, out1, err + +} + +// GetActiveModelIds is a free data retrieval call binding the contract method 0x3839d3dc. +// +// Solidity: function getActiveModelIds(uint256 offset_, uint256 limit_) view returns(bytes32[], uint256) +func (_ModelRegistry *ModelRegistrySession) GetActiveModelIds(offset_ *big.Int, limit_ *big.Int) ([][32]byte, *big.Int, error) { + return _ModelRegistry.Contract.GetActiveModelIds(&_ModelRegistry.CallOpts, offset_, limit_) +} + +// GetActiveModelIds is a free data retrieval call binding the contract method 0x3839d3dc. +// +// Solidity: function getActiveModelIds(uint256 offset_, uint256 limit_) view returns(bytes32[], uint256) +func (_ModelRegistry *ModelRegistryCallerSession) GetActiveModelIds(offset_ *big.Int, limit_ *big.Int) ([][32]byte, *big.Int, error) { + return _ModelRegistry.Contract.GetActiveModelIds(&_ModelRegistry.CallOpts, offset_, limit_) +} + +// GetBid is a free data retrieval call binding the contract method 0x91704e1e. +// +// Solidity: function getBid(bytes32 bidId_) view returns((address,bytes32,uint256,uint256,uint128,uint128)) +func (_ModelRegistry *ModelRegistryCaller) GetBid(opts *bind.CallOpts, bidId_ [32]byte) (IBidStorageBid, error) { + var out []interface{} + err := _ModelRegistry.contract.Call(opts, &out, "getBid", bidId_) + + if err != nil { + return *new(IBidStorageBid), err + } + + out0 := *abi.ConvertType(out[0], new(IBidStorageBid)).(*IBidStorageBid) + + return out0, err + +} + +// GetBid is a free data retrieval call binding the contract method 0x91704e1e. +// +// Solidity: function getBid(bytes32 bidId_) view returns((address,bytes32,uint256,uint256,uint128,uint128)) +func (_ModelRegistry *ModelRegistrySession) GetBid(bidId_ [32]byte) (IBidStorageBid, error) { + return _ModelRegistry.Contract.GetBid(&_ModelRegistry.CallOpts, bidId_) +} + +// GetBid is a free data retrieval call binding the contract method 0x91704e1e. +// +// Solidity: function getBid(bytes32 bidId_) view returns((address,bytes32,uint256,uint256,uint128,uint128)) +func (_ModelRegistry *ModelRegistryCallerSession) GetBid(bidId_ [32]byte) (IBidStorageBid, error) { + return _ModelRegistry.Contract.GetBid(&_ModelRegistry.CallOpts, bidId_) +} + +// GetIsModelActive is a free data retrieval call binding the contract method 0xca74b5f3. +// +// Solidity: function getIsModelActive(bytes32 modelId_) view returns(bool) +func (_ModelRegistry *ModelRegistryCaller) GetIsModelActive(opts *bind.CallOpts, modelId_ [32]byte) (bool, error) { + var out []interface{} + err := _ModelRegistry.contract.Call(opts, &out, "getIsModelActive", modelId_) + + if err != nil { + return *new(bool), err + } + + out0 := *abi.ConvertType(out[0], new(bool)).(*bool) + + return out0, err + +} + +// GetIsModelActive is a free data retrieval call binding the contract method 0xca74b5f3. +// +// Solidity: function getIsModelActive(bytes32 modelId_) view returns(bool) +func (_ModelRegistry *ModelRegistrySession) GetIsModelActive(modelId_ [32]byte) (bool, error) { + return _ModelRegistry.Contract.GetIsModelActive(&_ModelRegistry.CallOpts, modelId_) +} + +// GetIsModelActive is a free data retrieval call binding the contract method 0xca74b5f3. +// +// Solidity: function getIsModelActive(bytes32 modelId_) view returns(bool) +func (_ModelRegistry *ModelRegistryCallerSession) GetIsModelActive(modelId_ [32]byte) (bool, error) { + return _ModelRegistry.Contract.GetIsModelActive(&_ModelRegistry.CallOpts, modelId_) +} + +// GetModel is a free data retrieval call binding the contract method 0x21e7c498. +// +// Solidity: function getModel(bytes32 modelId_) view returns((bytes32,uint256,uint256,address,string,string[],uint128,bool)) +func (_ModelRegistry *ModelRegistryCaller) GetModel(opts *bind.CallOpts, modelId_ [32]byte) (IModelStorageModel, error) { + var out []interface{} + err := _ModelRegistry.contract.Call(opts, &out, "getModel", modelId_) + + if err != nil { + return *new(IModelStorageModel), err + } + + out0 := *abi.ConvertType(out[0], new(IModelStorageModel)).(*IModelStorageModel) + + return out0, err + +} + +// GetModel is a free data retrieval call binding the contract method 0x21e7c498. +// +// Solidity: function getModel(bytes32 modelId_) view returns((bytes32,uint256,uint256,address,string,string[],uint128,bool)) +func (_ModelRegistry *ModelRegistrySession) GetModel(modelId_ [32]byte) (IModelStorageModel, error) { + return _ModelRegistry.Contract.GetModel(&_ModelRegistry.CallOpts, modelId_) +} + +// GetModel is a free data retrieval call binding the contract method 0x21e7c498. +// +// Solidity: function getModel(bytes32 modelId_) view returns((bytes32,uint256,uint256,address,string,string[],uint128,bool)) +func (_ModelRegistry *ModelRegistryCallerSession) GetModel(modelId_ [32]byte) (IModelStorageModel, error) { + return _ModelRegistry.Contract.GetModel(&_ModelRegistry.CallOpts, modelId_) +} + +// GetModelActiveBids is a free data retrieval call binding the contract method 0x8a683b6e. +// +// Solidity: function getModelActiveBids(bytes32 modelId_, uint256 offset_, uint256 limit_) view returns(bytes32[], uint256) +func (_ModelRegistry *ModelRegistryCaller) GetModelActiveBids(opts *bind.CallOpts, modelId_ [32]byte, offset_ *big.Int, limit_ *big.Int) ([][32]byte, *big.Int, error) { + var out []interface{} + err := _ModelRegistry.contract.Call(opts, &out, "getModelActiveBids", modelId_, offset_, limit_) + + if err != nil { + return *new([][32]byte), *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new([][32]byte)).(*[][32]byte) + out1 := *abi.ConvertType(out[1], new(*big.Int)).(**big.Int) + + return out0, out1, err + +} + +// GetModelActiveBids is a free data retrieval call binding the contract method 0x8a683b6e. +// +// Solidity: function getModelActiveBids(bytes32 modelId_, uint256 offset_, uint256 limit_) view returns(bytes32[], uint256) +func (_ModelRegistry *ModelRegistrySession) GetModelActiveBids(modelId_ [32]byte, offset_ *big.Int, limit_ *big.Int) ([][32]byte, *big.Int, error) { + return _ModelRegistry.Contract.GetModelActiveBids(&_ModelRegistry.CallOpts, modelId_, offset_, limit_) +} + +// GetModelActiveBids is a free data retrieval call binding the contract method 0x8a683b6e. +// +// Solidity: function getModelActiveBids(bytes32 modelId_, uint256 offset_, uint256 limit_) view returns(bytes32[], uint256) +func (_ModelRegistry *ModelRegistryCallerSession) GetModelActiveBids(modelId_ [32]byte, offset_ *big.Int, limit_ *big.Int) ([][32]byte, *big.Int, error) { + return _ModelRegistry.Contract.GetModelActiveBids(&_ModelRegistry.CallOpts, modelId_, offset_, limit_) +} + +// GetModelBids is a free data retrieval call binding the contract method 0xfade17b1. +// +// Solidity: function getModelBids(bytes32 modelId_, uint256 offset_, uint256 limit_) view returns(bytes32[], uint256) +func (_ModelRegistry *ModelRegistryCaller) GetModelBids(opts *bind.CallOpts, modelId_ [32]byte, offset_ *big.Int, limit_ *big.Int) ([][32]byte, *big.Int, error) { + var out []interface{} + err := _ModelRegistry.contract.Call(opts, &out, "getModelBids", modelId_, offset_, limit_) + + if err != nil { + return *new([][32]byte), *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new([][32]byte)).(*[][32]byte) + out1 := *abi.ConvertType(out[1], new(*big.Int)).(**big.Int) + + return out0, out1, err + +} + +// GetModelBids is a free data retrieval call binding the contract method 0xfade17b1. +// +// Solidity: function getModelBids(bytes32 modelId_, uint256 offset_, uint256 limit_) view returns(bytes32[], uint256) +func (_ModelRegistry *ModelRegistrySession) GetModelBids(modelId_ [32]byte, offset_ *big.Int, limit_ *big.Int) ([][32]byte, *big.Int, error) { + return _ModelRegistry.Contract.GetModelBids(&_ModelRegistry.CallOpts, modelId_, offset_, limit_) +} + +// GetModelBids is a free data retrieval call binding the contract method 0xfade17b1. +// +// Solidity: function getModelBids(bytes32 modelId_, uint256 offset_, uint256 limit_) view returns(bytes32[], uint256) +func (_ModelRegistry *ModelRegistryCallerSession) GetModelBids(modelId_ [32]byte, offset_ *big.Int, limit_ *big.Int) ([][32]byte, *big.Int, error) { + return _ModelRegistry.Contract.GetModelBids(&_ModelRegistry.CallOpts, modelId_, offset_, limit_) +} + +// GetModelId is a free data retrieval call binding the contract method 0xbb93d26a. +// +// Solidity: function getModelId(address account_, bytes32 baseModelId_) pure returns(bytes32) +func (_ModelRegistry *ModelRegistryCaller) GetModelId(opts *bind.CallOpts, account_ common.Address, baseModelId_ [32]byte) ([32]byte, error) { + var out []interface{} + err := _ModelRegistry.contract.Call(opts, &out, "getModelId", account_, baseModelId_) + + if err != nil { + return *new([32]byte), err + } + + out0 := *abi.ConvertType(out[0], new([32]byte)).(*[32]byte) + + return out0, err + +} + +// GetModelId is a free data retrieval call binding the contract method 0xbb93d26a. +// +// Solidity: function getModelId(address account_, bytes32 baseModelId_) pure returns(bytes32) +func (_ModelRegistry *ModelRegistrySession) GetModelId(account_ common.Address, baseModelId_ [32]byte) ([32]byte, error) { + return _ModelRegistry.Contract.GetModelId(&_ModelRegistry.CallOpts, account_, baseModelId_) +} + +// GetModelId is a free data retrieval call binding the contract method 0xbb93d26a. +// +// Solidity: function getModelId(address account_, bytes32 baseModelId_) pure returns(bytes32) +func (_ModelRegistry *ModelRegistryCallerSession) GetModelId(account_ common.Address, baseModelId_ [32]byte) ([32]byte, error) { + return _ModelRegistry.Contract.GetModelId(&_ModelRegistry.CallOpts, account_, baseModelId_) +} + +// GetModelIds is a free data retrieval call binding the contract method 0x08d0aab4. +// +// Solidity: function getModelIds(uint256 offset_, uint256 limit_) view returns(bytes32[], uint256) +func (_ModelRegistry *ModelRegistryCaller) GetModelIds(opts *bind.CallOpts, offset_ *big.Int, limit_ *big.Int) ([][32]byte, *big.Int, error) { + var out []interface{} + err := _ModelRegistry.contract.Call(opts, &out, "getModelIds", offset_, limit_) + + if err != nil { + return *new([][32]byte), *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new([][32]byte)).(*[][32]byte) + out1 := *abi.ConvertType(out[1], new(*big.Int)).(**big.Int) + + return out0, out1, err + +} + +// GetModelIds is a free data retrieval call binding the contract method 0x08d0aab4. +// +// Solidity: function getModelIds(uint256 offset_, uint256 limit_) view returns(bytes32[], uint256) +func (_ModelRegistry *ModelRegistrySession) GetModelIds(offset_ *big.Int, limit_ *big.Int) ([][32]byte, *big.Int, error) { + return _ModelRegistry.Contract.GetModelIds(&_ModelRegistry.CallOpts, offset_, limit_) +} + +// GetModelIds is a free data retrieval call binding the contract method 0x08d0aab4. +// +// Solidity: function getModelIds(uint256 offset_, uint256 limit_) view returns(bytes32[], uint256) +func (_ModelRegistry *ModelRegistryCallerSession) GetModelIds(offset_ *big.Int, limit_ *big.Int) ([][32]byte, *big.Int, error) { + return _ModelRegistry.Contract.GetModelIds(&_ModelRegistry.CallOpts, offset_, limit_) +} + +// GetModelMinimumStake is a free data retrieval call binding the contract method 0xf647ba3d. +// +// Solidity: function getModelMinimumStake() view returns(uint256) +func (_ModelRegistry *ModelRegistryCaller) GetModelMinimumStake(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _ModelRegistry.contract.Call(opts, &out, "getModelMinimumStake") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// GetModelMinimumStake is a free data retrieval call binding the contract method 0xf647ba3d. +// +// Solidity: function getModelMinimumStake() view returns(uint256) +func (_ModelRegistry *ModelRegistrySession) GetModelMinimumStake() (*big.Int, error) { + return _ModelRegistry.Contract.GetModelMinimumStake(&_ModelRegistry.CallOpts) +} + +// GetModelMinimumStake is a free data retrieval call binding the contract method 0xf647ba3d. +// +// Solidity: function getModelMinimumStake() view returns(uint256) +func (_ModelRegistry *ModelRegistryCallerSession) GetModelMinimumStake() (*big.Int, error) { + return _ModelRegistry.Contract.GetModelMinimumStake(&_ModelRegistry.CallOpts) +} + +// GetProviderActiveBids is a free data retrieval call binding the contract method 0xaf5b77ca. +// +// Solidity: function getProviderActiveBids(address provider_, uint256 offset_, uint256 limit_) view returns(bytes32[], uint256) +func (_ModelRegistry *ModelRegistryCaller) GetProviderActiveBids(opts *bind.CallOpts, provider_ common.Address, offset_ *big.Int, limit_ *big.Int) ([][32]byte, *big.Int, error) { + var out []interface{} + err := _ModelRegistry.contract.Call(opts, &out, "getProviderActiveBids", provider_, offset_, limit_) + + if err != nil { + return *new([][32]byte), *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new([][32]byte)).(*[][32]byte) + out1 := *abi.ConvertType(out[1], new(*big.Int)).(**big.Int) + + return out0, out1, err + +} + +// GetProviderActiveBids is a free data retrieval call binding the contract method 0xaf5b77ca. +// +// Solidity: function getProviderActiveBids(address provider_, uint256 offset_, uint256 limit_) view returns(bytes32[], uint256) +func (_ModelRegistry *ModelRegistrySession) GetProviderActiveBids(provider_ common.Address, offset_ *big.Int, limit_ *big.Int) ([][32]byte, *big.Int, error) { + return _ModelRegistry.Contract.GetProviderActiveBids(&_ModelRegistry.CallOpts, provider_, offset_, limit_) +} + +// GetProviderActiveBids is a free data retrieval call binding the contract method 0xaf5b77ca. +// +// Solidity: function getProviderActiveBids(address provider_, uint256 offset_, uint256 limit_) view returns(bytes32[], uint256) +func (_ModelRegistry *ModelRegistryCallerSession) GetProviderActiveBids(provider_ common.Address, offset_ *big.Int, limit_ *big.Int) ([][32]byte, *big.Int, error) { + return _ModelRegistry.Contract.GetProviderActiveBids(&_ModelRegistry.CallOpts, provider_, offset_, limit_) +} + +// GetProviderBids is a free data retrieval call binding the contract method 0x59d435c4. +// +// Solidity: function getProviderBids(address provider_, uint256 offset_, uint256 limit_) view returns(bytes32[], uint256) +func (_ModelRegistry *ModelRegistryCaller) GetProviderBids(opts *bind.CallOpts, provider_ common.Address, offset_ *big.Int, limit_ *big.Int) ([][32]byte, *big.Int, error) { + var out []interface{} + err := _ModelRegistry.contract.Call(opts, &out, "getProviderBids", provider_, offset_, limit_) + + if err != nil { + return *new([][32]byte), *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new([][32]byte)).(*[][32]byte) + out1 := *abi.ConvertType(out[1], new(*big.Int)).(**big.Int) + + return out0, out1, err + +} + +// GetProviderBids is a free data retrieval call binding the contract method 0x59d435c4. +// +// Solidity: function getProviderBids(address provider_, uint256 offset_, uint256 limit_) view returns(bytes32[], uint256) +func (_ModelRegistry *ModelRegistrySession) GetProviderBids(provider_ common.Address, offset_ *big.Int, limit_ *big.Int) ([][32]byte, *big.Int, error) { + return _ModelRegistry.Contract.GetProviderBids(&_ModelRegistry.CallOpts, provider_, offset_, limit_) +} + +// GetProviderBids is a free data retrieval call binding the contract method 0x59d435c4. +// +// Solidity: function getProviderBids(address provider_, uint256 offset_, uint256 limit_) view returns(bytes32[], uint256) +func (_ModelRegistry *ModelRegistryCallerSession) GetProviderBids(provider_ common.Address, offset_ *big.Int, limit_ *big.Int) ([][32]byte, *big.Int, error) { + return _ModelRegistry.Contract.GetProviderBids(&_ModelRegistry.CallOpts, provider_, offset_, limit_) +} + +// GetRegistry is a free data retrieval call binding the contract method 0x5ab1bd53. +// +// Solidity: function getRegistry() view returns(address) +func (_ModelRegistry *ModelRegistryCaller) GetRegistry(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _ModelRegistry.contract.Call(opts, &out, "getRegistry") + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +// GetRegistry is a free data retrieval call binding the contract method 0x5ab1bd53. +// +// Solidity: function getRegistry() view returns(address) +func (_ModelRegistry *ModelRegistrySession) GetRegistry() (common.Address, error) { + return _ModelRegistry.Contract.GetRegistry(&_ModelRegistry.CallOpts) +} + +// GetRegistry is a free data retrieval call binding the contract method 0x5ab1bd53. +// +// Solidity: function getRegistry() view returns(address) +func (_ModelRegistry *ModelRegistryCallerSession) GetRegistry() (common.Address, error) { + return _ModelRegistry.Contract.GetRegistry(&_ModelRegistry.CallOpts) +} + +// GetToken is a free data retrieval call binding the contract method 0x21df0da7. +// +// Solidity: function getToken() view returns(address) +func (_ModelRegistry *ModelRegistryCaller) GetToken(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _ModelRegistry.contract.Call(opts, &out, "getToken") + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +// GetToken is a free data retrieval call binding the contract method 0x21df0da7. +// +// Solidity: function getToken() view returns(address) +func (_ModelRegistry *ModelRegistrySession) GetToken() (common.Address, error) { + return _ModelRegistry.Contract.GetToken(&_ModelRegistry.CallOpts) +} + +// GetToken is a free data retrieval call binding the contract method 0x21df0da7. +// +// Solidity: function getToken() view returns(address) +func (_ModelRegistry *ModelRegistryCallerSession) GetToken() (common.Address, error) { + return _ModelRegistry.Contract.GetToken(&_ModelRegistry.CallOpts) +} + +// IsBidActive is a free data retrieval call binding the contract method 0x1345df58. +// +// Solidity: function isBidActive(bytes32 bidId_) view returns(bool) +func (_ModelRegistry *ModelRegistryCaller) IsBidActive(opts *bind.CallOpts, bidId_ [32]byte) (bool, error) { + var out []interface{} + err := _ModelRegistry.contract.Call(opts, &out, "isBidActive", bidId_) + + if err != nil { + return *new(bool), err + } + + out0 := *abi.ConvertType(out[0], new(bool)).(*bool) + + return out0, err + +} + +// IsBidActive is a free data retrieval call binding the contract method 0x1345df58. +// +// Solidity: function isBidActive(bytes32 bidId_) view returns(bool) +func (_ModelRegistry *ModelRegistrySession) IsBidActive(bidId_ [32]byte) (bool, error) { + return _ModelRegistry.Contract.IsBidActive(&_ModelRegistry.CallOpts, bidId_) +} + +// IsBidActive is a free data retrieval call binding the contract method 0x1345df58. +// +// Solidity: function isBidActive(bytes32 bidId_) view returns(bool) +func (_ModelRegistry *ModelRegistryCallerSession) IsBidActive(bidId_ [32]byte) (bool, error) { + return _ModelRegistry.Contract.IsBidActive(&_ModelRegistry.CallOpts, bidId_) +} + +// IsRightsDelegated is a free data retrieval call binding the contract method 0x54126b8f. +// +// Solidity: function isRightsDelegated(address delegatee_, address delegator_, bytes32 rights_) view returns(bool) +func (_ModelRegistry *ModelRegistryCaller) IsRightsDelegated(opts *bind.CallOpts, delegatee_ common.Address, delegator_ common.Address, rights_ [32]byte) (bool, error) { + var out []interface{} + err := _ModelRegistry.contract.Call(opts, &out, "isRightsDelegated", delegatee_, delegator_, rights_) + + if err != nil { + return *new(bool), err + } + + out0 := *abi.ConvertType(out[0], new(bool)).(*bool) + + return out0, err + +} + +// IsRightsDelegated is a free data retrieval call binding the contract method 0x54126b8f. +// +// Solidity: function isRightsDelegated(address delegatee_, address delegator_, bytes32 rights_) view returns(bool) +func (_ModelRegistry *ModelRegistrySession) IsRightsDelegated(delegatee_ common.Address, delegator_ common.Address, rights_ [32]byte) (bool, error) { + return _ModelRegistry.Contract.IsRightsDelegated(&_ModelRegistry.CallOpts, delegatee_, delegator_, rights_) +} + +// IsRightsDelegated is a free data retrieval call binding the contract method 0x54126b8f. +// +// Solidity: function isRightsDelegated(address delegatee_, address delegator_, bytes32 rights_) view returns(bool) +func (_ModelRegistry *ModelRegistryCallerSession) IsRightsDelegated(delegatee_ common.Address, delegator_ common.Address, rights_ [32]byte) (bool, error) { + return _ModelRegistry.Contract.IsRightsDelegated(&_ModelRegistry.CallOpts, delegatee_, delegator_, rights_) +} + +// Owner is a free data retrieval call binding the contract method 0x8da5cb5b. +// +// Solidity: function owner() view returns(address) +func (_ModelRegistry *ModelRegistryCaller) Owner(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _ModelRegistry.contract.Call(opts, &out, "owner") + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +// Owner is a free data retrieval call binding the contract method 0x8da5cb5b. +// +// Solidity: function owner() view returns(address) +func (_ModelRegistry *ModelRegistrySession) Owner() (common.Address, error) { + return _ModelRegistry.Contract.Owner(&_ModelRegistry.CallOpts) +} + +// Owner is a free data retrieval call binding the contract method 0x8da5cb5b. +// +// Solidity: function owner() view returns(address) +func (_ModelRegistry *ModelRegistryCallerSession) Owner() (common.Address, error) { + return _ModelRegistry.Contract.Owner(&_ModelRegistry.CallOpts) +} + +// ModelRegistryInit is a paid mutator transaction binding the contract method 0xd69bdf30. +// +// Solidity: function __ModelRegistry_init() returns() +func (_ModelRegistry *ModelRegistryTransactor) ModelRegistryInit(opts *bind.TransactOpts) (*types.Transaction, error) { + return _ModelRegistry.contract.Transact(opts, "__ModelRegistry_init") +} + +// ModelRegistryInit is a paid mutator transaction binding the contract method 0xd69bdf30. +// +// Solidity: function __ModelRegistry_init() returns() +func (_ModelRegistry *ModelRegistrySession) ModelRegistryInit() (*types.Transaction, error) { + return _ModelRegistry.Contract.ModelRegistryInit(&_ModelRegistry.TransactOpts) +} + +// ModelRegistryInit is a paid mutator transaction binding the contract method 0xd69bdf30. +// +// Solidity: function __ModelRegistry_init() returns() +func (_ModelRegistry *ModelRegistryTransactorSession) ModelRegistryInit() (*types.Transaction, error) { + return _ModelRegistry.Contract.ModelRegistryInit(&_ModelRegistry.TransactOpts) +} + +// ModelDeregister is a paid mutator transaction binding the contract method 0xd5a245f1. +// +// Solidity: function modelDeregister(bytes32 modelId_) returns() +func (_ModelRegistry *ModelRegistryTransactor) ModelDeregister(opts *bind.TransactOpts, modelId_ [32]byte) (*types.Transaction, error) { + return _ModelRegistry.contract.Transact(opts, "modelDeregister", modelId_) +} + +// ModelDeregister is a paid mutator transaction binding the contract method 0xd5a245f1. +// +// Solidity: function modelDeregister(bytes32 modelId_) returns() +func (_ModelRegistry *ModelRegistrySession) ModelDeregister(modelId_ [32]byte) (*types.Transaction, error) { + return _ModelRegistry.Contract.ModelDeregister(&_ModelRegistry.TransactOpts, modelId_) +} + +// ModelDeregister is a paid mutator transaction binding the contract method 0xd5a245f1. +// +// Solidity: function modelDeregister(bytes32 modelId_) returns() +func (_ModelRegistry *ModelRegistryTransactorSession) ModelDeregister(modelId_ [32]byte) (*types.Transaction, error) { + return _ModelRegistry.Contract.ModelDeregister(&_ModelRegistry.TransactOpts, modelId_) +} + +// ModelRegister is a paid mutator transaction binding the contract method 0x21dea0a0. +// +// Solidity: function modelRegister(address modelOwner_, bytes32 baseModelId_, bytes32 ipfsCID_, uint256 fee_, uint256 amount_, string name_, string[] tags_) returns() +func (_ModelRegistry *ModelRegistryTransactor) ModelRegister(opts *bind.TransactOpts, modelOwner_ common.Address, baseModelId_ [32]byte, ipfsCID_ [32]byte, fee_ *big.Int, amount_ *big.Int, name_ string, tags_ []string) (*types.Transaction, error) { + return _ModelRegistry.contract.Transact(opts, "modelRegister", modelOwner_, baseModelId_, ipfsCID_, fee_, amount_, name_, tags_) +} + +// ModelRegister is a paid mutator transaction binding the contract method 0x21dea0a0. +// +// Solidity: function modelRegister(address modelOwner_, bytes32 baseModelId_, bytes32 ipfsCID_, uint256 fee_, uint256 amount_, string name_, string[] tags_) returns() +func (_ModelRegistry *ModelRegistrySession) ModelRegister(modelOwner_ common.Address, baseModelId_ [32]byte, ipfsCID_ [32]byte, fee_ *big.Int, amount_ *big.Int, name_ string, tags_ []string) (*types.Transaction, error) { + return _ModelRegistry.Contract.ModelRegister(&_ModelRegistry.TransactOpts, modelOwner_, baseModelId_, ipfsCID_, fee_, amount_, name_, tags_) +} + +// ModelRegister is a paid mutator transaction binding the contract method 0x21dea0a0. +// +// Solidity: function modelRegister(address modelOwner_, bytes32 baseModelId_, bytes32 ipfsCID_, uint256 fee_, uint256 amount_, string name_, string[] tags_) returns() +func (_ModelRegistry *ModelRegistryTransactorSession) ModelRegister(modelOwner_ common.Address, baseModelId_ [32]byte, ipfsCID_ [32]byte, fee_ *big.Int, amount_ *big.Int, name_ string, tags_ []string) (*types.Transaction, error) { + return _ModelRegistry.Contract.ModelRegister(&_ModelRegistry.TransactOpts, modelOwner_, baseModelId_, ipfsCID_, fee_, amount_, name_, tags_) +} + +// ModelSetMinStake is a paid mutator transaction binding the contract method 0x78998329. +// +// Solidity: function modelSetMinStake(uint256 modelMinimumStake_) returns() +func (_ModelRegistry *ModelRegistryTransactor) ModelSetMinStake(opts *bind.TransactOpts, modelMinimumStake_ *big.Int) (*types.Transaction, error) { + return _ModelRegistry.contract.Transact(opts, "modelSetMinStake", modelMinimumStake_) +} + +// ModelSetMinStake is a paid mutator transaction binding the contract method 0x78998329. +// +// Solidity: function modelSetMinStake(uint256 modelMinimumStake_) returns() +func (_ModelRegistry *ModelRegistrySession) ModelSetMinStake(modelMinimumStake_ *big.Int) (*types.Transaction, error) { + return _ModelRegistry.Contract.ModelSetMinStake(&_ModelRegistry.TransactOpts, modelMinimumStake_) +} + +// ModelSetMinStake is a paid mutator transaction binding the contract method 0x78998329. +// +// Solidity: function modelSetMinStake(uint256 modelMinimumStake_) returns() +func (_ModelRegistry *ModelRegistryTransactorSession) ModelSetMinStake(modelMinimumStake_ *big.Int) (*types.Transaction, error) { + return _ModelRegistry.Contract.ModelSetMinStake(&_ModelRegistry.TransactOpts, modelMinimumStake_) +} + +// ModelRegistryInitializedIterator is returned from FilterInitialized and is used to iterate over the raw logs and unpacked data for Initialized events raised by the ModelRegistry contract. +type ModelRegistryInitializedIterator struct { + Event *ModelRegistryInitialized // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *ModelRegistryInitializedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(ModelRegistryInitialized) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(ModelRegistryInitialized) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *ModelRegistryInitializedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *ModelRegistryInitializedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// ModelRegistryInitialized represents a Initialized event raised by the ModelRegistry contract. +type ModelRegistryInitialized struct { + StorageSlot [32]byte + Raw types.Log // Blockchain specific contextual infos +} + +// FilterInitialized is a free log retrieval operation binding the contract event 0xdc73717d728bcfa015e8117438a65319aa06e979ca324afa6e1ea645c28ea15d. +// +// Solidity: event Initialized(bytes32 storageSlot) +func (_ModelRegistry *ModelRegistryFilterer) FilterInitialized(opts *bind.FilterOpts) (*ModelRegistryInitializedIterator, error) { + + logs, sub, err := _ModelRegistry.contract.FilterLogs(opts, "Initialized") + if err != nil { + return nil, err + } + return &ModelRegistryInitializedIterator{contract: _ModelRegistry.contract, event: "Initialized", logs: logs, sub: sub}, nil +} + +// WatchInitialized is a free log subscription operation binding the contract event 0xdc73717d728bcfa015e8117438a65319aa06e979ca324afa6e1ea645c28ea15d. +// +// Solidity: event Initialized(bytes32 storageSlot) +func (_ModelRegistry *ModelRegistryFilterer) WatchInitialized(opts *bind.WatchOpts, sink chan<- *ModelRegistryInitialized) (event.Subscription, error) { + + logs, sub, err := _ModelRegistry.contract.WatchLogs(opts, "Initialized") + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(ModelRegistryInitialized) + if err := _ModelRegistry.contract.UnpackLog(event, "Initialized", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseInitialized is a log parse operation binding the contract event 0xdc73717d728bcfa015e8117438a65319aa06e979ca324afa6e1ea645c28ea15d. +// +// Solidity: event Initialized(bytes32 storageSlot) +func (_ModelRegistry *ModelRegistryFilterer) ParseInitialized(log types.Log) (*ModelRegistryInitialized, error) { + event := new(ModelRegistryInitialized) + if err := _ModelRegistry.contract.UnpackLog(event, "Initialized", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// ModelRegistryModelDeregisteredIterator is returned from FilterModelDeregistered and is used to iterate over the raw logs and unpacked data for ModelDeregistered events raised by the ModelRegistry contract. +type ModelRegistryModelDeregisteredIterator struct { + Event *ModelRegistryModelDeregistered // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *ModelRegistryModelDeregisteredIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(ModelRegistryModelDeregistered) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(ModelRegistryModelDeregistered) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *ModelRegistryModelDeregisteredIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *ModelRegistryModelDeregisteredIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// ModelRegistryModelDeregistered represents a ModelDeregistered event raised by the ModelRegistry contract. +type ModelRegistryModelDeregistered struct { + Owner common.Address + ModelId [32]byte + Raw types.Log // Blockchain specific contextual infos +} + +// FilterModelDeregistered is a free log retrieval operation binding the contract event 0x79a9f3017f26694a70f688c1e37f4add042a050660c62fc8351f760b153b888b. +// +// Solidity: event ModelDeregistered(address indexed owner, bytes32 indexed modelId) +func (_ModelRegistry *ModelRegistryFilterer) FilterModelDeregistered(opts *bind.FilterOpts, owner []common.Address, modelId [][32]byte) (*ModelRegistryModelDeregisteredIterator, error) { + + var ownerRule []interface{} + for _, ownerItem := range owner { + ownerRule = append(ownerRule, ownerItem) + } + var modelIdRule []interface{} + for _, modelIdItem := range modelId { + modelIdRule = append(modelIdRule, modelIdItem) + } + + logs, sub, err := _ModelRegistry.contract.FilterLogs(opts, "ModelDeregistered", ownerRule, modelIdRule) + if err != nil { + return nil, err + } + return &ModelRegistryModelDeregisteredIterator{contract: _ModelRegistry.contract, event: "ModelDeregistered", logs: logs, sub: sub}, nil +} + +// WatchModelDeregistered is a free log subscription operation binding the contract event 0x79a9f3017f26694a70f688c1e37f4add042a050660c62fc8351f760b153b888b. +// +// Solidity: event ModelDeregistered(address indexed owner, bytes32 indexed modelId) +func (_ModelRegistry *ModelRegistryFilterer) WatchModelDeregistered(opts *bind.WatchOpts, sink chan<- *ModelRegistryModelDeregistered, owner []common.Address, modelId [][32]byte) (event.Subscription, error) { + + var ownerRule []interface{} + for _, ownerItem := range owner { + ownerRule = append(ownerRule, ownerItem) + } + var modelIdRule []interface{} + for _, modelIdItem := range modelId { + modelIdRule = append(modelIdRule, modelIdItem) + } + + logs, sub, err := _ModelRegistry.contract.WatchLogs(opts, "ModelDeregistered", ownerRule, modelIdRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(ModelRegistryModelDeregistered) + if err := _ModelRegistry.contract.UnpackLog(event, "ModelDeregistered", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseModelDeregistered is a log parse operation binding the contract event 0x79a9f3017f26694a70f688c1e37f4add042a050660c62fc8351f760b153b888b. +// +// Solidity: event ModelDeregistered(address indexed owner, bytes32 indexed modelId) +func (_ModelRegistry *ModelRegistryFilterer) ParseModelDeregistered(log types.Log) (*ModelRegistryModelDeregistered, error) { + event := new(ModelRegistryModelDeregistered) + if err := _ModelRegistry.contract.UnpackLog(event, "ModelDeregistered", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// ModelRegistryModelMinimumStakeUpdatedIterator is returned from FilterModelMinimumStakeUpdated and is used to iterate over the raw logs and unpacked data for ModelMinimumStakeUpdated events raised by the ModelRegistry contract. +type ModelRegistryModelMinimumStakeUpdatedIterator struct { + Event *ModelRegistryModelMinimumStakeUpdated // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *ModelRegistryModelMinimumStakeUpdatedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(ModelRegistryModelMinimumStakeUpdated) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(ModelRegistryModelMinimumStakeUpdated) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *ModelRegistryModelMinimumStakeUpdatedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *ModelRegistryModelMinimumStakeUpdatedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// ModelRegistryModelMinimumStakeUpdated represents a ModelMinimumStakeUpdated event raised by the ModelRegistry contract. +type ModelRegistryModelMinimumStakeUpdated struct { + ModelMinimumStake *big.Int + Raw types.Log // Blockchain specific contextual infos +} + +// FilterModelMinimumStakeUpdated is a free log retrieval operation binding the contract event 0x136e2b2828baa18257e8eef3c26df62481c7b16303ca0ebe4202865df5e97d7e. +// +// Solidity: event ModelMinimumStakeUpdated(uint256 modelMinimumStake) +func (_ModelRegistry *ModelRegistryFilterer) FilterModelMinimumStakeUpdated(opts *bind.FilterOpts) (*ModelRegistryModelMinimumStakeUpdatedIterator, error) { + + logs, sub, err := _ModelRegistry.contract.FilterLogs(opts, "ModelMinimumStakeUpdated") + if err != nil { + return nil, err + } + return &ModelRegistryModelMinimumStakeUpdatedIterator{contract: _ModelRegistry.contract, event: "ModelMinimumStakeUpdated", logs: logs, sub: sub}, nil +} + +// WatchModelMinimumStakeUpdated is a free log subscription operation binding the contract event 0x136e2b2828baa18257e8eef3c26df62481c7b16303ca0ebe4202865df5e97d7e. +// +// Solidity: event ModelMinimumStakeUpdated(uint256 modelMinimumStake) +func (_ModelRegistry *ModelRegistryFilterer) WatchModelMinimumStakeUpdated(opts *bind.WatchOpts, sink chan<- *ModelRegistryModelMinimumStakeUpdated) (event.Subscription, error) { + + logs, sub, err := _ModelRegistry.contract.WatchLogs(opts, "ModelMinimumStakeUpdated") + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(ModelRegistryModelMinimumStakeUpdated) + if err := _ModelRegistry.contract.UnpackLog(event, "ModelMinimumStakeUpdated", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseModelMinimumStakeUpdated is a log parse operation binding the contract event 0x136e2b2828baa18257e8eef3c26df62481c7b16303ca0ebe4202865df5e97d7e. +// +// Solidity: event ModelMinimumStakeUpdated(uint256 modelMinimumStake) +func (_ModelRegistry *ModelRegistryFilterer) ParseModelMinimumStakeUpdated(log types.Log) (*ModelRegistryModelMinimumStakeUpdated, error) { + event := new(ModelRegistryModelMinimumStakeUpdated) + if err := _ModelRegistry.contract.UnpackLog(event, "ModelMinimumStakeUpdated", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// ModelRegistryModelRegisteredUpdatedIterator is returned from FilterModelRegisteredUpdated and is used to iterate over the raw logs and unpacked data for ModelRegisteredUpdated events raised by the ModelRegistry contract. +type ModelRegistryModelRegisteredUpdatedIterator struct { + Event *ModelRegistryModelRegisteredUpdated // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *ModelRegistryModelRegisteredUpdatedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(ModelRegistryModelRegisteredUpdated) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(ModelRegistryModelRegisteredUpdated) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *ModelRegistryModelRegisteredUpdatedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *ModelRegistryModelRegisteredUpdatedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// ModelRegistryModelRegisteredUpdated represents a ModelRegisteredUpdated event raised by the ModelRegistry contract. +type ModelRegistryModelRegisteredUpdated struct { + Owner common.Address + ModelId [32]byte + Raw types.Log // Blockchain specific contextual infos +} + +// FilterModelRegisteredUpdated is a free log retrieval operation binding the contract event 0xda9282a68d90c36d31d780a69a65da6c35191a5d8cdd37bd1a1a5aa9fb168e77. +// +// Solidity: event ModelRegisteredUpdated(address indexed owner, bytes32 indexed modelId) +func (_ModelRegistry *ModelRegistryFilterer) FilterModelRegisteredUpdated(opts *bind.FilterOpts, owner []common.Address, modelId [][32]byte) (*ModelRegistryModelRegisteredUpdatedIterator, error) { + + var ownerRule []interface{} + for _, ownerItem := range owner { + ownerRule = append(ownerRule, ownerItem) + } + var modelIdRule []interface{} + for _, modelIdItem := range modelId { + modelIdRule = append(modelIdRule, modelIdItem) + } + + logs, sub, err := _ModelRegistry.contract.FilterLogs(opts, "ModelRegisteredUpdated", ownerRule, modelIdRule) + if err != nil { + return nil, err + } + return &ModelRegistryModelRegisteredUpdatedIterator{contract: _ModelRegistry.contract, event: "ModelRegisteredUpdated", logs: logs, sub: sub}, nil +} + +// WatchModelRegisteredUpdated is a free log subscription operation binding the contract event 0xda9282a68d90c36d31d780a69a65da6c35191a5d8cdd37bd1a1a5aa9fb168e77. +// +// Solidity: event ModelRegisteredUpdated(address indexed owner, bytes32 indexed modelId) +func (_ModelRegistry *ModelRegistryFilterer) WatchModelRegisteredUpdated(opts *bind.WatchOpts, sink chan<- *ModelRegistryModelRegisteredUpdated, owner []common.Address, modelId [][32]byte) (event.Subscription, error) { + + var ownerRule []interface{} + for _, ownerItem := range owner { + ownerRule = append(ownerRule, ownerItem) + } + var modelIdRule []interface{} + for _, modelIdItem := range modelId { + modelIdRule = append(modelIdRule, modelIdItem) + } + + logs, sub, err := _ModelRegistry.contract.WatchLogs(opts, "ModelRegisteredUpdated", ownerRule, modelIdRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(ModelRegistryModelRegisteredUpdated) + if err := _ModelRegistry.contract.UnpackLog(event, "ModelRegisteredUpdated", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseModelRegisteredUpdated is a log parse operation binding the contract event 0xda9282a68d90c36d31d780a69a65da6c35191a5d8cdd37bd1a1a5aa9fb168e77. +// +// Solidity: event ModelRegisteredUpdated(address indexed owner, bytes32 indexed modelId) +func (_ModelRegistry *ModelRegistryFilterer) ParseModelRegisteredUpdated(log types.Log) (*ModelRegistryModelRegisteredUpdated, error) { + event := new(ModelRegistryModelRegisteredUpdated) + if err := _ModelRegistry.contract.UnpackLog(event, "ModelRegisteredUpdated", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} diff --git a/proxy-router/contracts/morpheustoken/MorpheusToken.go b/proxy-router/internal/repositories/contracts/bindings/morpheustoken/MorpheusToken.go similarity index 75% rename from proxy-router/contracts/morpheustoken/MorpheusToken.go rename to proxy-router/internal/repositories/contracts/bindings/morpheustoken/MorpheusToken.go index f51909ce..ee902aca 100644 --- a/proxy-router/contracts/morpheustoken/MorpheusToken.go +++ b/proxy-router/internal/repositories/contracts/bindings/morpheustoken/MorpheusToken.go @@ -31,7 +31,7 @@ var ( // MorpheusTokenMetaData contains all meta data concerning the MorpheusToken contract. var MorpheusTokenMetaData = &bind.MetaData{ - ABI: "[{\"inputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"allowance\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"needed\",\"type\":\"uint256\"}],\"name\":\"ERC20InsufficientAllowance\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"balance\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"needed\",\"type\":\"uint256\"}],\"name\":\"ERC20InsufficientBalance\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"approver\",\"type\":\"address\"}],\"name\":\"ERC20InvalidApprover\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"}],\"name\":\"ERC20InvalidReceiver\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"ERC20InvalidSender\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"}],\"name\":\"ERC20InvalidSpender\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"Approval\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"Transfer\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"}],\"name\":\"allowance\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"approve\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"balanceOf\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"decimals\",\"outputs\":[{\"internalType\":\"uint8\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"name\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"symbol\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"totalSupply\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"transfer\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"transferFrom\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", + ABI: "[{\"inputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"Approval\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"Transfer\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"INITIAL_SUPPLUY\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"}],\"name\":\"allowance\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"approve\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"balanceOf\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"decimals\",\"outputs\":[{\"internalType\":\"uint8\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"subtractedValue\",\"type\":\"uint256\"}],\"name\":\"decreaseAllowance\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"addedValue\",\"type\":\"uint256\"}],\"name\":\"increaseAllowance\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"name\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"symbol\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"totalSupply\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"transfer\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"transferFrom\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", } // MorpheusTokenABI is the input ABI used to generate the binding from. @@ -180,6 +180,37 @@ func (_MorpheusToken *MorpheusTokenTransactorRaw) Transact(opts *bind.TransactOp return _MorpheusToken.Contract.contract.Transact(opts, method, params...) } +// INITIALSUPPLUY is a free data retrieval call binding the contract method 0x5ce0b492. +// +// Solidity: function INITIAL_SUPPLUY() view returns(uint256) +func (_MorpheusToken *MorpheusTokenCaller) INITIALSUPPLUY(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _MorpheusToken.contract.Call(opts, &out, "INITIAL_SUPPLUY") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// INITIALSUPPLUY is a free data retrieval call binding the contract method 0x5ce0b492. +// +// Solidity: function INITIAL_SUPPLUY() view returns(uint256) +func (_MorpheusToken *MorpheusTokenSession) INITIALSUPPLUY() (*big.Int, error) { + return _MorpheusToken.Contract.INITIALSUPPLUY(&_MorpheusToken.CallOpts) +} + +// INITIALSUPPLUY is a free data retrieval call binding the contract method 0x5ce0b492. +// +// Solidity: function INITIAL_SUPPLUY() view returns(uint256) +func (_MorpheusToken *MorpheusTokenCallerSession) INITIALSUPPLUY() (*big.Int, error) { + return _MorpheusToken.Contract.INITIALSUPPLUY(&_MorpheusToken.CallOpts) +} + // Allowance is a free data retrieval call binding the contract method 0xdd62ed3e. // // Solidity: function allowance(address owner, address spender) view returns(uint256) @@ -368,65 +399,107 @@ func (_MorpheusToken *MorpheusTokenCallerSession) TotalSupply() (*big.Int, error // Approve is a paid mutator transaction binding the contract method 0x095ea7b3. // -// Solidity: function approve(address spender, uint256 value) returns(bool) -func (_MorpheusToken *MorpheusTokenTransactor) Approve(opts *bind.TransactOpts, spender common.Address, value *big.Int) (*types.Transaction, error) { - return _MorpheusToken.contract.Transact(opts, "approve", spender, value) +// Solidity: function approve(address spender, uint256 amount) returns(bool) +func (_MorpheusToken *MorpheusTokenTransactor) Approve(opts *bind.TransactOpts, spender common.Address, amount *big.Int) (*types.Transaction, error) { + return _MorpheusToken.contract.Transact(opts, "approve", spender, amount) } // Approve is a paid mutator transaction binding the contract method 0x095ea7b3. // -// Solidity: function approve(address spender, uint256 value) returns(bool) -func (_MorpheusToken *MorpheusTokenSession) Approve(spender common.Address, value *big.Int) (*types.Transaction, error) { - return _MorpheusToken.Contract.Approve(&_MorpheusToken.TransactOpts, spender, value) +// Solidity: function approve(address spender, uint256 amount) returns(bool) +func (_MorpheusToken *MorpheusTokenSession) Approve(spender common.Address, amount *big.Int) (*types.Transaction, error) { + return _MorpheusToken.Contract.Approve(&_MorpheusToken.TransactOpts, spender, amount) } // Approve is a paid mutator transaction binding the contract method 0x095ea7b3. // -// Solidity: function approve(address spender, uint256 value) returns(bool) -func (_MorpheusToken *MorpheusTokenTransactorSession) Approve(spender common.Address, value *big.Int) (*types.Transaction, error) { - return _MorpheusToken.Contract.Approve(&_MorpheusToken.TransactOpts, spender, value) +// Solidity: function approve(address spender, uint256 amount) returns(bool) +func (_MorpheusToken *MorpheusTokenTransactorSession) Approve(spender common.Address, amount *big.Int) (*types.Transaction, error) { + return _MorpheusToken.Contract.Approve(&_MorpheusToken.TransactOpts, spender, amount) +} + +// DecreaseAllowance is a paid mutator transaction binding the contract method 0xa457c2d7. +// +// Solidity: function decreaseAllowance(address spender, uint256 subtractedValue) returns(bool) +func (_MorpheusToken *MorpheusTokenTransactor) DecreaseAllowance(opts *bind.TransactOpts, spender common.Address, subtractedValue *big.Int) (*types.Transaction, error) { + return _MorpheusToken.contract.Transact(opts, "decreaseAllowance", spender, subtractedValue) +} + +// DecreaseAllowance is a paid mutator transaction binding the contract method 0xa457c2d7. +// +// Solidity: function decreaseAllowance(address spender, uint256 subtractedValue) returns(bool) +func (_MorpheusToken *MorpheusTokenSession) DecreaseAllowance(spender common.Address, subtractedValue *big.Int) (*types.Transaction, error) { + return _MorpheusToken.Contract.DecreaseAllowance(&_MorpheusToken.TransactOpts, spender, subtractedValue) +} + +// DecreaseAllowance is a paid mutator transaction binding the contract method 0xa457c2d7. +// +// Solidity: function decreaseAllowance(address spender, uint256 subtractedValue) returns(bool) +func (_MorpheusToken *MorpheusTokenTransactorSession) DecreaseAllowance(spender common.Address, subtractedValue *big.Int) (*types.Transaction, error) { + return _MorpheusToken.Contract.DecreaseAllowance(&_MorpheusToken.TransactOpts, spender, subtractedValue) +} + +// IncreaseAllowance is a paid mutator transaction binding the contract method 0x39509351. +// +// Solidity: function increaseAllowance(address spender, uint256 addedValue) returns(bool) +func (_MorpheusToken *MorpheusTokenTransactor) IncreaseAllowance(opts *bind.TransactOpts, spender common.Address, addedValue *big.Int) (*types.Transaction, error) { + return _MorpheusToken.contract.Transact(opts, "increaseAllowance", spender, addedValue) +} + +// IncreaseAllowance is a paid mutator transaction binding the contract method 0x39509351. +// +// Solidity: function increaseAllowance(address spender, uint256 addedValue) returns(bool) +func (_MorpheusToken *MorpheusTokenSession) IncreaseAllowance(spender common.Address, addedValue *big.Int) (*types.Transaction, error) { + return _MorpheusToken.Contract.IncreaseAllowance(&_MorpheusToken.TransactOpts, spender, addedValue) +} + +// IncreaseAllowance is a paid mutator transaction binding the contract method 0x39509351. +// +// Solidity: function increaseAllowance(address spender, uint256 addedValue) returns(bool) +func (_MorpheusToken *MorpheusTokenTransactorSession) IncreaseAllowance(spender common.Address, addedValue *big.Int) (*types.Transaction, error) { + return _MorpheusToken.Contract.IncreaseAllowance(&_MorpheusToken.TransactOpts, spender, addedValue) } // Transfer is a paid mutator transaction binding the contract method 0xa9059cbb. // -// Solidity: function transfer(address to, uint256 value) returns(bool) -func (_MorpheusToken *MorpheusTokenTransactor) Transfer(opts *bind.TransactOpts, to common.Address, value *big.Int) (*types.Transaction, error) { - return _MorpheusToken.contract.Transact(opts, "transfer", to, value) +// Solidity: function transfer(address to, uint256 amount) returns(bool) +func (_MorpheusToken *MorpheusTokenTransactor) Transfer(opts *bind.TransactOpts, to common.Address, amount *big.Int) (*types.Transaction, error) { + return _MorpheusToken.contract.Transact(opts, "transfer", to, amount) } // Transfer is a paid mutator transaction binding the contract method 0xa9059cbb. // -// Solidity: function transfer(address to, uint256 value) returns(bool) -func (_MorpheusToken *MorpheusTokenSession) Transfer(to common.Address, value *big.Int) (*types.Transaction, error) { - return _MorpheusToken.Contract.Transfer(&_MorpheusToken.TransactOpts, to, value) +// Solidity: function transfer(address to, uint256 amount) returns(bool) +func (_MorpheusToken *MorpheusTokenSession) Transfer(to common.Address, amount *big.Int) (*types.Transaction, error) { + return _MorpheusToken.Contract.Transfer(&_MorpheusToken.TransactOpts, to, amount) } // Transfer is a paid mutator transaction binding the contract method 0xa9059cbb. // -// Solidity: function transfer(address to, uint256 value) returns(bool) -func (_MorpheusToken *MorpheusTokenTransactorSession) Transfer(to common.Address, value *big.Int) (*types.Transaction, error) { - return _MorpheusToken.Contract.Transfer(&_MorpheusToken.TransactOpts, to, value) +// Solidity: function transfer(address to, uint256 amount) returns(bool) +func (_MorpheusToken *MorpheusTokenTransactorSession) Transfer(to common.Address, amount *big.Int) (*types.Transaction, error) { + return _MorpheusToken.Contract.Transfer(&_MorpheusToken.TransactOpts, to, amount) } // TransferFrom is a paid mutator transaction binding the contract method 0x23b872dd. // -// Solidity: function transferFrom(address from, address to, uint256 value) returns(bool) -func (_MorpheusToken *MorpheusTokenTransactor) TransferFrom(opts *bind.TransactOpts, from common.Address, to common.Address, value *big.Int) (*types.Transaction, error) { - return _MorpheusToken.contract.Transact(opts, "transferFrom", from, to, value) +// Solidity: function transferFrom(address from, address to, uint256 amount) returns(bool) +func (_MorpheusToken *MorpheusTokenTransactor) TransferFrom(opts *bind.TransactOpts, from common.Address, to common.Address, amount *big.Int) (*types.Transaction, error) { + return _MorpheusToken.contract.Transact(opts, "transferFrom", from, to, amount) } // TransferFrom is a paid mutator transaction binding the contract method 0x23b872dd. // -// Solidity: function transferFrom(address from, address to, uint256 value) returns(bool) -func (_MorpheusToken *MorpheusTokenSession) TransferFrom(from common.Address, to common.Address, value *big.Int) (*types.Transaction, error) { - return _MorpheusToken.Contract.TransferFrom(&_MorpheusToken.TransactOpts, from, to, value) +// Solidity: function transferFrom(address from, address to, uint256 amount) returns(bool) +func (_MorpheusToken *MorpheusTokenSession) TransferFrom(from common.Address, to common.Address, amount *big.Int) (*types.Transaction, error) { + return _MorpheusToken.Contract.TransferFrom(&_MorpheusToken.TransactOpts, from, to, amount) } // TransferFrom is a paid mutator transaction binding the contract method 0x23b872dd. // -// Solidity: function transferFrom(address from, address to, uint256 value) returns(bool) -func (_MorpheusToken *MorpheusTokenTransactorSession) TransferFrom(from common.Address, to common.Address, value *big.Int) (*types.Transaction, error) { - return _MorpheusToken.Contract.TransferFrom(&_MorpheusToken.TransactOpts, from, to, value) +// Solidity: function transferFrom(address from, address to, uint256 amount) returns(bool) +func (_MorpheusToken *MorpheusTokenTransactorSession) TransferFrom(from common.Address, to common.Address, amount *big.Int) (*types.Transaction, error) { + return _MorpheusToken.Contract.TransferFrom(&_MorpheusToken.TransactOpts, from, to, amount) } // MorpheusTokenApprovalIterator is returned from FilterApproval and is used to iterate over the raw logs and unpacked data for Approval events raised by the MorpheusToken contract. diff --git a/proxy-router/internal/repositories/contracts/bindings/multicall3/Multicall3.go b/proxy-router/internal/repositories/contracts/bindings/multicall3/Multicall3.go new file mode 100644 index 00000000..17800887 --- /dev/null +++ b/proxy-router/internal/repositories/contracts/bindings/multicall3/Multicall3.go @@ -0,0 +1,644 @@ +// Code generated - DO NOT EDIT. +// This file is a generated binding and any manual changes will be lost. + +package multicall3 + +import ( + "errors" + "math/big" + "strings" + + ethereum "github.com/ethereum/go-ethereum" + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/event" +) + +// Reference imports to suppress errors if they are not otherwise used. +var ( + _ = errors.New + _ = big.NewInt + _ = strings.NewReader + _ = ethereum.NotFound + _ = bind.Bind + _ = common.Big1 + _ = types.BloomLookup + _ = event.NewSubscription + _ = abi.ConvertType +) + +// Multicall3Call is an auto generated low-level Go binding around an user-defined struct. +type Multicall3Call struct { + Target common.Address + CallData []byte +} + +// Multicall3Call3 is an auto generated low-level Go binding around an user-defined struct. +type Multicall3Call3 struct { + Target common.Address + AllowFailure bool + CallData []byte +} + +// Multicall3Call3Value is an auto generated low-level Go binding around an user-defined struct. +type Multicall3Call3Value struct { + Target common.Address + AllowFailure bool + Value *big.Int + CallData []byte +} + +// Multicall3Result is an auto generated low-level Go binding around an user-defined struct. +type Multicall3Result struct { + Success bool + ReturnData []byte +} + +// Multicall3MetaData contains all meta data concerning the Multicall3 contract. +var Multicall3MetaData = &bind.MetaData{ + ABI: "[{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"callData\",\"type\":\"bytes\"}],\"internalType\":\"structMulticall3.Call[]\",\"name\":\"calls\",\"type\":\"tuple[]\"}],\"name\":\"aggregate\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"blockNumber\",\"type\":\"uint256\"},{\"internalType\":\"bytes[]\",\"name\":\"returnData\",\"type\":\"bytes[]\"}],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"allowFailure\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"callData\",\"type\":\"bytes\"}],\"internalType\":\"structMulticall3.Call3[]\",\"name\":\"calls\",\"type\":\"tuple[]\"}],\"name\":\"aggregate3\",\"outputs\":[{\"components\":[{\"internalType\":\"bool\",\"name\":\"success\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"returnData\",\"type\":\"bytes\"}],\"internalType\":\"structMulticall3.Result[]\",\"name\":\"returnData\",\"type\":\"tuple[]\"}],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"allowFailure\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"callData\",\"type\":\"bytes\"}],\"internalType\":\"structMulticall3.Call3Value[]\",\"name\":\"calls\",\"type\":\"tuple[]\"}],\"name\":\"aggregate3Value\",\"outputs\":[{\"components\":[{\"internalType\":\"bool\",\"name\":\"success\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"returnData\",\"type\":\"bytes\"}],\"internalType\":\"structMulticall3.Result[]\",\"name\":\"returnData\",\"type\":\"tuple[]\"}],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"callData\",\"type\":\"bytes\"}],\"internalType\":\"structMulticall3.Call[]\",\"name\":\"calls\",\"type\":\"tuple[]\"}],\"name\":\"blockAndAggregate\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"blockNumber\",\"type\":\"uint256\"},{\"internalType\":\"bytes32\",\"name\":\"blockHash\",\"type\":\"bytes32\"},{\"components\":[{\"internalType\":\"bool\",\"name\":\"success\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"returnData\",\"type\":\"bytes\"}],\"internalType\":\"structMulticall3.Result[]\",\"name\":\"returnData\",\"type\":\"tuple[]\"}],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getBasefee\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"basefee\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"blockNumber\",\"type\":\"uint256\"}],\"name\":\"getBlockHash\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"blockHash\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getBlockNumber\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"blockNumber\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getChainId\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"chainid\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getCurrentBlockCoinbase\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"coinbase\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getCurrentBlockDifficulty\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"difficulty\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getCurrentBlockGasLimit\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"gaslimit\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getCurrentBlockTimestamp\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"timestamp\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"}],\"name\":\"getEthBalance\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"balance\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getLastBlockHash\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"blockHash\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bool\",\"name\":\"requireSuccess\",\"type\":\"bool\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"callData\",\"type\":\"bytes\"}],\"internalType\":\"structMulticall3.Call[]\",\"name\":\"calls\",\"type\":\"tuple[]\"}],\"name\":\"tryAggregate\",\"outputs\":[{\"components\":[{\"internalType\":\"bool\",\"name\":\"success\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"returnData\",\"type\":\"bytes\"}],\"internalType\":\"structMulticall3.Result[]\",\"name\":\"returnData\",\"type\":\"tuple[]\"}],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bool\",\"name\":\"requireSuccess\",\"type\":\"bool\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"callData\",\"type\":\"bytes\"}],\"internalType\":\"structMulticall3.Call[]\",\"name\":\"calls\",\"type\":\"tuple[]\"}],\"name\":\"tryBlockAndAggregate\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"blockNumber\",\"type\":\"uint256\"},{\"internalType\":\"bytes32\",\"name\":\"blockHash\",\"type\":\"bytes32\"},{\"components\":[{\"internalType\":\"bool\",\"name\":\"success\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"returnData\",\"type\":\"bytes\"}],\"internalType\":\"structMulticall3.Result[]\",\"name\":\"returnData\",\"type\":\"tuple[]\"}],\"stateMutability\":\"payable\",\"type\":\"function\"}]", +} + +// Multicall3ABI is the input ABI used to generate the binding from. +// Deprecated: Use Multicall3MetaData.ABI instead. +var Multicall3ABI = Multicall3MetaData.ABI + +// Multicall3 is an auto generated Go binding around an Ethereum contract. +type Multicall3 struct { + Multicall3Caller // Read-only binding to the contract + Multicall3Transactor // Write-only binding to the contract + Multicall3Filterer // Log filterer for contract events +} + +// Multicall3Caller is an auto generated read-only Go binding around an Ethereum contract. +type Multicall3Caller struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// Multicall3Transactor is an auto generated write-only Go binding around an Ethereum contract. +type Multicall3Transactor struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// Multicall3Filterer is an auto generated log filtering Go binding around an Ethereum contract events. +type Multicall3Filterer struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// Multicall3Session is an auto generated Go binding around an Ethereum contract, +// with pre-set call and transact options. +type Multicall3Session struct { + Contract *Multicall3 // Generic contract binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// Multicall3CallerSession is an auto generated read-only Go binding around an Ethereum contract, +// with pre-set call options. +type Multicall3CallerSession struct { + Contract *Multicall3Caller // Generic contract caller binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session +} + +// Multicall3TransactorSession is an auto generated write-only Go binding around an Ethereum contract, +// with pre-set transact options. +type Multicall3TransactorSession struct { + Contract *Multicall3Transactor // Generic contract transactor binding to set the session for + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// Multicall3Raw is an auto generated low-level Go binding around an Ethereum contract. +type Multicall3Raw struct { + Contract *Multicall3 // Generic contract binding to access the raw methods on +} + +// Multicall3CallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. +type Multicall3CallerRaw struct { + Contract *Multicall3Caller // Generic read-only contract binding to access the raw methods on +} + +// Multicall3TransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. +type Multicall3TransactorRaw struct { + Contract *Multicall3Transactor // Generic write-only contract binding to access the raw methods on +} + +// NewMulticall3 creates a new instance of Multicall3, bound to a specific deployed contract. +func NewMulticall3(address common.Address, backend bind.ContractBackend) (*Multicall3, error) { + contract, err := bindMulticall3(address, backend, backend, backend) + if err != nil { + return nil, err + } + return &Multicall3{Multicall3Caller: Multicall3Caller{contract: contract}, Multicall3Transactor: Multicall3Transactor{contract: contract}, Multicall3Filterer: Multicall3Filterer{contract: contract}}, nil +} + +// NewMulticall3Caller creates a new read-only instance of Multicall3, bound to a specific deployed contract. +func NewMulticall3Caller(address common.Address, caller bind.ContractCaller) (*Multicall3Caller, error) { + contract, err := bindMulticall3(address, caller, nil, nil) + if err != nil { + return nil, err + } + return &Multicall3Caller{contract: contract}, nil +} + +// NewMulticall3Transactor creates a new write-only instance of Multicall3, bound to a specific deployed contract. +func NewMulticall3Transactor(address common.Address, transactor bind.ContractTransactor) (*Multicall3Transactor, error) { + contract, err := bindMulticall3(address, nil, transactor, nil) + if err != nil { + return nil, err + } + return &Multicall3Transactor{contract: contract}, nil +} + +// NewMulticall3Filterer creates a new log filterer instance of Multicall3, bound to a specific deployed contract. +func NewMulticall3Filterer(address common.Address, filterer bind.ContractFilterer) (*Multicall3Filterer, error) { + contract, err := bindMulticall3(address, nil, nil, filterer) + if err != nil { + return nil, err + } + return &Multicall3Filterer{contract: contract}, nil +} + +// bindMulticall3 binds a generic wrapper to an already deployed contract. +func bindMulticall3(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { + parsed, err := Multicall3MetaData.GetAbi() + if err != nil { + return nil, err + } + return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_Multicall3 *Multicall3Raw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _Multicall3.Contract.Multicall3Caller.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_Multicall3 *Multicall3Raw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _Multicall3.Contract.Multicall3Transactor.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_Multicall3 *Multicall3Raw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _Multicall3.Contract.Multicall3Transactor.contract.Transact(opts, method, params...) +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_Multicall3 *Multicall3CallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _Multicall3.Contract.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_Multicall3 *Multicall3TransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _Multicall3.Contract.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_Multicall3 *Multicall3TransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _Multicall3.Contract.contract.Transact(opts, method, params...) +} + +// GetBasefee is a free data retrieval call binding the contract method 0x3e64a696. +// +// Solidity: function getBasefee() view returns(uint256 basefee) +func (_Multicall3 *Multicall3Caller) GetBasefee(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _Multicall3.contract.Call(opts, &out, "getBasefee") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// GetBasefee is a free data retrieval call binding the contract method 0x3e64a696. +// +// Solidity: function getBasefee() view returns(uint256 basefee) +func (_Multicall3 *Multicall3Session) GetBasefee() (*big.Int, error) { + return _Multicall3.Contract.GetBasefee(&_Multicall3.CallOpts) +} + +// GetBasefee is a free data retrieval call binding the contract method 0x3e64a696. +// +// Solidity: function getBasefee() view returns(uint256 basefee) +func (_Multicall3 *Multicall3CallerSession) GetBasefee() (*big.Int, error) { + return _Multicall3.Contract.GetBasefee(&_Multicall3.CallOpts) +} + +// GetBlockHash is a free data retrieval call binding the contract method 0xee82ac5e. +// +// Solidity: function getBlockHash(uint256 blockNumber) view returns(bytes32 blockHash) +func (_Multicall3 *Multicall3Caller) GetBlockHash(opts *bind.CallOpts, blockNumber *big.Int) ([32]byte, error) { + var out []interface{} + err := _Multicall3.contract.Call(opts, &out, "getBlockHash", blockNumber) + + if err != nil { + return *new([32]byte), err + } + + out0 := *abi.ConvertType(out[0], new([32]byte)).(*[32]byte) + + return out0, err + +} + +// GetBlockHash is a free data retrieval call binding the contract method 0xee82ac5e. +// +// Solidity: function getBlockHash(uint256 blockNumber) view returns(bytes32 blockHash) +func (_Multicall3 *Multicall3Session) GetBlockHash(blockNumber *big.Int) ([32]byte, error) { + return _Multicall3.Contract.GetBlockHash(&_Multicall3.CallOpts, blockNumber) +} + +// GetBlockHash is a free data retrieval call binding the contract method 0xee82ac5e. +// +// Solidity: function getBlockHash(uint256 blockNumber) view returns(bytes32 blockHash) +func (_Multicall3 *Multicall3CallerSession) GetBlockHash(blockNumber *big.Int) ([32]byte, error) { + return _Multicall3.Contract.GetBlockHash(&_Multicall3.CallOpts, blockNumber) +} + +// GetBlockNumber is a free data retrieval call binding the contract method 0x42cbb15c. +// +// Solidity: function getBlockNumber() view returns(uint256 blockNumber) +func (_Multicall3 *Multicall3Caller) GetBlockNumber(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _Multicall3.contract.Call(opts, &out, "getBlockNumber") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// GetBlockNumber is a free data retrieval call binding the contract method 0x42cbb15c. +// +// Solidity: function getBlockNumber() view returns(uint256 blockNumber) +func (_Multicall3 *Multicall3Session) GetBlockNumber() (*big.Int, error) { + return _Multicall3.Contract.GetBlockNumber(&_Multicall3.CallOpts) +} + +// GetBlockNumber is a free data retrieval call binding the contract method 0x42cbb15c. +// +// Solidity: function getBlockNumber() view returns(uint256 blockNumber) +func (_Multicall3 *Multicall3CallerSession) GetBlockNumber() (*big.Int, error) { + return _Multicall3.Contract.GetBlockNumber(&_Multicall3.CallOpts) +} + +// GetChainId is a free data retrieval call binding the contract method 0x3408e470. +// +// Solidity: function getChainId() view returns(uint256 chainid) +func (_Multicall3 *Multicall3Caller) GetChainId(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _Multicall3.contract.Call(opts, &out, "getChainId") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// GetChainId is a free data retrieval call binding the contract method 0x3408e470. +// +// Solidity: function getChainId() view returns(uint256 chainid) +func (_Multicall3 *Multicall3Session) GetChainId() (*big.Int, error) { + return _Multicall3.Contract.GetChainId(&_Multicall3.CallOpts) +} + +// GetChainId is a free data retrieval call binding the contract method 0x3408e470. +// +// Solidity: function getChainId() view returns(uint256 chainid) +func (_Multicall3 *Multicall3CallerSession) GetChainId() (*big.Int, error) { + return _Multicall3.Contract.GetChainId(&_Multicall3.CallOpts) +} + +// GetCurrentBlockCoinbase is a free data retrieval call binding the contract method 0xa8b0574e. +// +// Solidity: function getCurrentBlockCoinbase() view returns(address coinbase) +func (_Multicall3 *Multicall3Caller) GetCurrentBlockCoinbase(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _Multicall3.contract.Call(opts, &out, "getCurrentBlockCoinbase") + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +// GetCurrentBlockCoinbase is a free data retrieval call binding the contract method 0xa8b0574e. +// +// Solidity: function getCurrentBlockCoinbase() view returns(address coinbase) +func (_Multicall3 *Multicall3Session) GetCurrentBlockCoinbase() (common.Address, error) { + return _Multicall3.Contract.GetCurrentBlockCoinbase(&_Multicall3.CallOpts) +} + +// GetCurrentBlockCoinbase is a free data retrieval call binding the contract method 0xa8b0574e. +// +// Solidity: function getCurrentBlockCoinbase() view returns(address coinbase) +func (_Multicall3 *Multicall3CallerSession) GetCurrentBlockCoinbase() (common.Address, error) { + return _Multicall3.Contract.GetCurrentBlockCoinbase(&_Multicall3.CallOpts) +} + +// GetCurrentBlockDifficulty is a free data retrieval call binding the contract method 0x72425d9d. +// +// Solidity: function getCurrentBlockDifficulty() view returns(uint256 difficulty) +func (_Multicall3 *Multicall3Caller) GetCurrentBlockDifficulty(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _Multicall3.contract.Call(opts, &out, "getCurrentBlockDifficulty") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// GetCurrentBlockDifficulty is a free data retrieval call binding the contract method 0x72425d9d. +// +// Solidity: function getCurrentBlockDifficulty() view returns(uint256 difficulty) +func (_Multicall3 *Multicall3Session) GetCurrentBlockDifficulty() (*big.Int, error) { + return _Multicall3.Contract.GetCurrentBlockDifficulty(&_Multicall3.CallOpts) +} + +// GetCurrentBlockDifficulty is a free data retrieval call binding the contract method 0x72425d9d. +// +// Solidity: function getCurrentBlockDifficulty() view returns(uint256 difficulty) +func (_Multicall3 *Multicall3CallerSession) GetCurrentBlockDifficulty() (*big.Int, error) { + return _Multicall3.Contract.GetCurrentBlockDifficulty(&_Multicall3.CallOpts) +} + +// GetCurrentBlockGasLimit is a free data retrieval call binding the contract method 0x86d516e8. +// +// Solidity: function getCurrentBlockGasLimit() view returns(uint256 gaslimit) +func (_Multicall3 *Multicall3Caller) GetCurrentBlockGasLimit(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _Multicall3.contract.Call(opts, &out, "getCurrentBlockGasLimit") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// GetCurrentBlockGasLimit is a free data retrieval call binding the contract method 0x86d516e8. +// +// Solidity: function getCurrentBlockGasLimit() view returns(uint256 gaslimit) +func (_Multicall3 *Multicall3Session) GetCurrentBlockGasLimit() (*big.Int, error) { + return _Multicall3.Contract.GetCurrentBlockGasLimit(&_Multicall3.CallOpts) +} + +// GetCurrentBlockGasLimit is a free data retrieval call binding the contract method 0x86d516e8. +// +// Solidity: function getCurrentBlockGasLimit() view returns(uint256 gaslimit) +func (_Multicall3 *Multicall3CallerSession) GetCurrentBlockGasLimit() (*big.Int, error) { + return _Multicall3.Contract.GetCurrentBlockGasLimit(&_Multicall3.CallOpts) +} + +// GetCurrentBlockTimestamp is a free data retrieval call binding the contract method 0x0f28c97d. +// +// Solidity: function getCurrentBlockTimestamp() view returns(uint256 timestamp) +func (_Multicall3 *Multicall3Caller) GetCurrentBlockTimestamp(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _Multicall3.contract.Call(opts, &out, "getCurrentBlockTimestamp") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// GetCurrentBlockTimestamp is a free data retrieval call binding the contract method 0x0f28c97d. +// +// Solidity: function getCurrentBlockTimestamp() view returns(uint256 timestamp) +func (_Multicall3 *Multicall3Session) GetCurrentBlockTimestamp() (*big.Int, error) { + return _Multicall3.Contract.GetCurrentBlockTimestamp(&_Multicall3.CallOpts) +} + +// GetCurrentBlockTimestamp is a free data retrieval call binding the contract method 0x0f28c97d. +// +// Solidity: function getCurrentBlockTimestamp() view returns(uint256 timestamp) +func (_Multicall3 *Multicall3CallerSession) GetCurrentBlockTimestamp() (*big.Int, error) { + return _Multicall3.Contract.GetCurrentBlockTimestamp(&_Multicall3.CallOpts) +} + +// GetEthBalance is a free data retrieval call binding the contract method 0x4d2301cc. +// +// Solidity: function getEthBalance(address addr) view returns(uint256 balance) +func (_Multicall3 *Multicall3Caller) GetEthBalance(opts *bind.CallOpts, addr common.Address) (*big.Int, error) { + var out []interface{} + err := _Multicall3.contract.Call(opts, &out, "getEthBalance", addr) + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// GetEthBalance is a free data retrieval call binding the contract method 0x4d2301cc. +// +// Solidity: function getEthBalance(address addr) view returns(uint256 balance) +func (_Multicall3 *Multicall3Session) GetEthBalance(addr common.Address) (*big.Int, error) { + return _Multicall3.Contract.GetEthBalance(&_Multicall3.CallOpts, addr) +} + +// GetEthBalance is a free data retrieval call binding the contract method 0x4d2301cc. +// +// Solidity: function getEthBalance(address addr) view returns(uint256 balance) +func (_Multicall3 *Multicall3CallerSession) GetEthBalance(addr common.Address) (*big.Int, error) { + return _Multicall3.Contract.GetEthBalance(&_Multicall3.CallOpts, addr) +} + +// GetLastBlockHash is a free data retrieval call binding the contract method 0x27e86d6e. +// +// Solidity: function getLastBlockHash() view returns(bytes32 blockHash) +func (_Multicall3 *Multicall3Caller) GetLastBlockHash(opts *bind.CallOpts) ([32]byte, error) { + var out []interface{} + err := _Multicall3.contract.Call(opts, &out, "getLastBlockHash") + + if err != nil { + return *new([32]byte), err + } + + out0 := *abi.ConvertType(out[0], new([32]byte)).(*[32]byte) + + return out0, err + +} + +// GetLastBlockHash is a free data retrieval call binding the contract method 0x27e86d6e. +// +// Solidity: function getLastBlockHash() view returns(bytes32 blockHash) +func (_Multicall3 *Multicall3Session) GetLastBlockHash() ([32]byte, error) { + return _Multicall3.Contract.GetLastBlockHash(&_Multicall3.CallOpts) +} + +// GetLastBlockHash is a free data retrieval call binding the contract method 0x27e86d6e. +// +// Solidity: function getLastBlockHash() view returns(bytes32 blockHash) +func (_Multicall3 *Multicall3CallerSession) GetLastBlockHash() ([32]byte, error) { + return _Multicall3.Contract.GetLastBlockHash(&_Multicall3.CallOpts) +} + +// Aggregate is a paid mutator transaction binding the contract method 0x252dba42. +// +// Solidity: function aggregate((address,bytes)[] calls) payable returns(uint256 blockNumber, bytes[] returnData) +func (_Multicall3 *Multicall3Transactor) Aggregate(opts *bind.TransactOpts, calls []Multicall3Call) (*types.Transaction, error) { + return _Multicall3.contract.Transact(opts, "aggregate", calls) +} + +// Aggregate is a paid mutator transaction binding the contract method 0x252dba42. +// +// Solidity: function aggregate((address,bytes)[] calls) payable returns(uint256 blockNumber, bytes[] returnData) +func (_Multicall3 *Multicall3Session) Aggregate(calls []Multicall3Call) (*types.Transaction, error) { + return _Multicall3.Contract.Aggregate(&_Multicall3.TransactOpts, calls) +} + +// Aggregate is a paid mutator transaction binding the contract method 0x252dba42. +// +// Solidity: function aggregate((address,bytes)[] calls) payable returns(uint256 blockNumber, bytes[] returnData) +func (_Multicall3 *Multicall3TransactorSession) Aggregate(calls []Multicall3Call) (*types.Transaction, error) { + return _Multicall3.Contract.Aggregate(&_Multicall3.TransactOpts, calls) +} + +// Aggregate3 is a paid mutator transaction binding the contract method 0x82ad56cb. +// +// Solidity: function aggregate3((address,bool,bytes)[] calls) payable returns((bool,bytes)[] returnData) +func (_Multicall3 *Multicall3Transactor) Aggregate3(opts *bind.TransactOpts, calls []Multicall3Call3) (*types.Transaction, error) { + return _Multicall3.contract.Transact(opts, "aggregate3", calls) +} + +// Aggregate3 is a paid mutator transaction binding the contract method 0x82ad56cb. +// +// Solidity: function aggregate3((address,bool,bytes)[] calls) payable returns((bool,bytes)[] returnData) +func (_Multicall3 *Multicall3Session) Aggregate3(calls []Multicall3Call3) (*types.Transaction, error) { + return _Multicall3.Contract.Aggregate3(&_Multicall3.TransactOpts, calls) +} + +// Aggregate3 is a paid mutator transaction binding the contract method 0x82ad56cb. +// +// Solidity: function aggregate3((address,bool,bytes)[] calls) payable returns((bool,bytes)[] returnData) +func (_Multicall3 *Multicall3TransactorSession) Aggregate3(calls []Multicall3Call3) (*types.Transaction, error) { + return _Multicall3.Contract.Aggregate3(&_Multicall3.TransactOpts, calls) +} + +// Aggregate3Value is a paid mutator transaction binding the contract method 0x174dea71. +// +// Solidity: function aggregate3Value((address,bool,uint256,bytes)[] calls) payable returns((bool,bytes)[] returnData) +func (_Multicall3 *Multicall3Transactor) Aggregate3Value(opts *bind.TransactOpts, calls []Multicall3Call3Value) (*types.Transaction, error) { + return _Multicall3.contract.Transact(opts, "aggregate3Value", calls) +} + +// Aggregate3Value is a paid mutator transaction binding the contract method 0x174dea71. +// +// Solidity: function aggregate3Value((address,bool,uint256,bytes)[] calls) payable returns((bool,bytes)[] returnData) +func (_Multicall3 *Multicall3Session) Aggregate3Value(calls []Multicall3Call3Value) (*types.Transaction, error) { + return _Multicall3.Contract.Aggregate3Value(&_Multicall3.TransactOpts, calls) +} + +// Aggregate3Value is a paid mutator transaction binding the contract method 0x174dea71. +// +// Solidity: function aggregate3Value((address,bool,uint256,bytes)[] calls) payable returns((bool,bytes)[] returnData) +func (_Multicall3 *Multicall3TransactorSession) Aggregate3Value(calls []Multicall3Call3Value) (*types.Transaction, error) { + return _Multicall3.Contract.Aggregate3Value(&_Multicall3.TransactOpts, calls) +} + +// BlockAndAggregate is a paid mutator transaction binding the contract method 0xc3077fa9. +// +// Solidity: function blockAndAggregate((address,bytes)[] calls) payable returns(uint256 blockNumber, bytes32 blockHash, (bool,bytes)[] returnData) +func (_Multicall3 *Multicall3Transactor) BlockAndAggregate(opts *bind.TransactOpts, calls []Multicall3Call) (*types.Transaction, error) { + return _Multicall3.contract.Transact(opts, "blockAndAggregate", calls) +} + +// BlockAndAggregate is a paid mutator transaction binding the contract method 0xc3077fa9. +// +// Solidity: function blockAndAggregate((address,bytes)[] calls) payable returns(uint256 blockNumber, bytes32 blockHash, (bool,bytes)[] returnData) +func (_Multicall3 *Multicall3Session) BlockAndAggregate(calls []Multicall3Call) (*types.Transaction, error) { + return _Multicall3.Contract.BlockAndAggregate(&_Multicall3.TransactOpts, calls) +} + +// BlockAndAggregate is a paid mutator transaction binding the contract method 0xc3077fa9. +// +// Solidity: function blockAndAggregate((address,bytes)[] calls) payable returns(uint256 blockNumber, bytes32 blockHash, (bool,bytes)[] returnData) +func (_Multicall3 *Multicall3TransactorSession) BlockAndAggregate(calls []Multicall3Call) (*types.Transaction, error) { + return _Multicall3.Contract.BlockAndAggregate(&_Multicall3.TransactOpts, calls) +} + +// TryAggregate is a paid mutator transaction binding the contract method 0xbce38bd7. +// +// Solidity: function tryAggregate(bool requireSuccess, (address,bytes)[] calls) payable returns((bool,bytes)[] returnData) +func (_Multicall3 *Multicall3Transactor) TryAggregate(opts *bind.TransactOpts, requireSuccess bool, calls []Multicall3Call) (*types.Transaction, error) { + return _Multicall3.contract.Transact(opts, "tryAggregate", requireSuccess, calls) +} + +// TryAggregate is a paid mutator transaction binding the contract method 0xbce38bd7. +// +// Solidity: function tryAggregate(bool requireSuccess, (address,bytes)[] calls) payable returns((bool,bytes)[] returnData) +func (_Multicall3 *Multicall3Session) TryAggregate(requireSuccess bool, calls []Multicall3Call) (*types.Transaction, error) { + return _Multicall3.Contract.TryAggregate(&_Multicall3.TransactOpts, requireSuccess, calls) +} + +// TryAggregate is a paid mutator transaction binding the contract method 0xbce38bd7. +// +// Solidity: function tryAggregate(bool requireSuccess, (address,bytes)[] calls) payable returns((bool,bytes)[] returnData) +func (_Multicall3 *Multicall3TransactorSession) TryAggregate(requireSuccess bool, calls []Multicall3Call) (*types.Transaction, error) { + return _Multicall3.Contract.TryAggregate(&_Multicall3.TransactOpts, requireSuccess, calls) +} + +// TryBlockAndAggregate is a paid mutator transaction binding the contract method 0x399542e9. +// +// Solidity: function tryBlockAndAggregate(bool requireSuccess, (address,bytes)[] calls) payable returns(uint256 blockNumber, bytes32 blockHash, (bool,bytes)[] returnData) +func (_Multicall3 *Multicall3Transactor) TryBlockAndAggregate(opts *bind.TransactOpts, requireSuccess bool, calls []Multicall3Call) (*types.Transaction, error) { + return _Multicall3.contract.Transact(opts, "tryBlockAndAggregate", requireSuccess, calls) +} + +// TryBlockAndAggregate is a paid mutator transaction binding the contract method 0x399542e9. +// +// Solidity: function tryBlockAndAggregate(bool requireSuccess, (address,bytes)[] calls) payable returns(uint256 blockNumber, bytes32 blockHash, (bool,bytes)[] returnData) +func (_Multicall3 *Multicall3Session) TryBlockAndAggregate(requireSuccess bool, calls []Multicall3Call) (*types.Transaction, error) { + return _Multicall3.Contract.TryBlockAndAggregate(&_Multicall3.TransactOpts, requireSuccess, calls) +} + +// TryBlockAndAggregate is a paid mutator transaction binding the contract method 0x399542e9. +// +// Solidity: function tryBlockAndAggregate(bool requireSuccess, (address,bytes)[] calls) payable returns(uint256 blockNumber, bytes32 blockHash, (bool,bytes)[] returnData) +func (_Multicall3 *Multicall3TransactorSession) TryBlockAndAggregate(requireSuccess bool, calls []Multicall3Call) (*types.Transaction, error) { + return _Multicall3.Contract.TryBlockAndAggregate(&_Multicall3.TransactOpts, requireSuccess, calls) +} diff --git a/proxy-router/internal/repositories/contracts/bindings/providerregistry/ProviderRegistry.go b/proxy-router/internal/repositories/contracts/bindings/providerregistry/ProviderRegistry.go new file mode 100644 index 00000000..715bc3b1 --- /dev/null +++ b/proxy-router/internal/repositories/contracts/bindings/providerregistry/ProviderRegistry.go @@ -0,0 +1,1673 @@ +// Code generated - DO NOT EDIT. +// This file is a generated binding and any manual changes will be lost. + +package providerregistry + +import ( + "errors" + "math/big" + "strings" + + ethereum "github.com/ethereum/go-ethereum" + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/event" +) + +// Reference imports to suppress errors if they are not otherwise used. +var ( + _ = errors.New + _ = big.NewInt + _ = strings.NewReader + _ = ethereum.NotFound + _ = bind.Bind + _ = common.Big1 + _ = types.BloomLookup + _ = event.NewSubscription + _ = abi.ConvertType +) + +// IBidStorageBid is an auto generated low-level Go binding around an user-defined struct. +type IBidStorageBid struct { + Provider common.Address + ModelId [32]byte + PricePerSecond *big.Int + Nonce *big.Int + CreatedAt *big.Int + DeletedAt *big.Int +} + +// IProviderStorageProvider is an auto generated low-level Go binding around an user-defined struct. +type IProviderStorageProvider struct { + Endpoint string + Stake *big.Int + CreatedAt *big.Int + LimitPeriodEnd *big.Int + LimitPeriodEarned *big.Int + IsDeleted bool +} + +// ProviderRegistryMetaData contains all meta data concerning the ProviderRegistry contract. +var ProviderRegistryMetaData = &bind.MetaData{ + ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"delegator\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"delegatee\",\"type\":\"address\"}],\"name\":\"InsufficientRightsForOperation\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account_\",\"type\":\"address\"}],\"name\":\"OwnableUnauthorizedAccount\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ProviderHasActiveBids\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ProviderHasAlreadyDeregistered\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ProviderNoStake\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ProviderNotDeregistered\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ProviderNotFound\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ProviderNothingToWithdraw\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"minAmount\",\"type\":\"uint256\"}],\"name\":\"ProviderStakeTooLow\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"storageSlot\",\"type\":\"bytes32\"}],\"name\":\"Initialized\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"provider\",\"type\":\"address\"}],\"name\":\"ProviderDeregistered\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"providerMinimumStake\",\"type\":\"uint256\"}],\"name\":\"ProviderMinimumStakeUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"provider\",\"type\":\"address\"}],\"name\":\"ProviderRegistered\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"provider\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"ProviderWithdrawn\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"BIDS_STORAGE_SLOT\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"DELEGATION_RULES_MARKETPLACE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"DELEGATION_RULES_MODEL\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"DELEGATION_RULES_PROVIDER\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"DELEGATION_RULES_SESSION\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"DELEGATION_STORAGE_SLOT\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"DIAMOND_OWNABLE_STORAGE_SLOT\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"PROVIDERS_STORAGE_SLOT\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"__ProviderRegistry_init\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"offset_\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"limit_\",\"type\":\"uint256\"}],\"name\":\"getActiveProviders\",\"outputs\":[{\"internalType\":\"address[]\",\"name\":\"\",\"type\":\"address[]\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"bidId_\",\"type\":\"bytes32\"}],\"name\":\"getBid\",\"outputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"provider\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"modelId\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"pricePerSecond\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"internalType\":\"uint128\",\"name\":\"createdAt\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"deletedAt\",\"type\":\"uint128\"}],\"internalType\":\"structIBidStorage.Bid\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"provider_\",\"type\":\"address\"}],\"name\":\"getIsProviderActive\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"modelId_\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"offset_\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"limit_\",\"type\":\"uint256\"}],\"name\":\"getModelActiveBids\",\"outputs\":[{\"internalType\":\"bytes32[]\",\"name\":\"\",\"type\":\"bytes32[]\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"modelId_\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"offset_\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"limit_\",\"type\":\"uint256\"}],\"name\":\"getModelBids\",\"outputs\":[{\"internalType\":\"bytes32[]\",\"name\":\"\",\"type\":\"bytes32[]\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"provider_\",\"type\":\"address\"}],\"name\":\"getProvider\",\"outputs\":[{\"components\":[{\"internalType\":\"string\",\"name\":\"endpoint\",\"type\":\"string\"},{\"internalType\":\"uint256\",\"name\":\"stake\",\"type\":\"uint256\"},{\"internalType\":\"uint128\",\"name\":\"createdAt\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"limitPeriodEnd\",\"type\":\"uint128\"},{\"internalType\":\"uint256\",\"name\":\"limitPeriodEarned\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"isDeleted\",\"type\":\"bool\"}],\"internalType\":\"structIProviderStorage.Provider\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"provider_\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"offset_\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"limit_\",\"type\":\"uint256\"}],\"name\":\"getProviderActiveBids\",\"outputs\":[{\"internalType\":\"bytes32[]\",\"name\":\"\",\"type\":\"bytes32[]\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"provider_\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"offset_\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"limit_\",\"type\":\"uint256\"}],\"name\":\"getProviderBids\",\"outputs\":[{\"internalType\":\"bytes32[]\",\"name\":\"\",\"type\":\"bytes32[]\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getProviderMinimumStake\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getRegistry\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getToken\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"bidId_\",\"type\":\"bytes32\"}],\"name\":\"isBidActive\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"delegatee_\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"delegator_\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"rights_\",\"type\":\"bytes32\"}],\"name\":\"isRightsDelegated\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"provider_\",\"type\":\"address\"}],\"name\":\"providerDeregister\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"provider_\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount_\",\"type\":\"uint256\"},{\"internalType\":\"string\",\"name\":\"endpoint_\",\"type\":\"string\"}],\"name\":\"providerRegister\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"providerMinimumStake_\",\"type\":\"uint256\"}],\"name\":\"providerSetMinStake\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", +} + +// ProviderRegistryABI is the input ABI used to generate the binding from. +// Deprecated: Use ProviderRegistryMetaData.ABI instead. +var ProviderRegistryABI = ProviderRegistryMetaData.ABI + +// ProviderRegistry is an auto generated Go binding around an Ethereum contract. +type ProviderRegistry struct { + ProviderRegistryCaller // Read-only binding to the contract + ProviderRegistryTransactor // Write-only binding to the contract + ProviderRegistryFilterer // Log filterer for contract events +} + +// ProviderRegistryCaller is an auto generated read-only Go binding around an Ethereum contract. +type ProviderRegistryCaller struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// ProviderRegistryTransactor is an auto generated write-only Go binding around an Ethereum contract. +type ProviderRegistryTransactor struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// ProviderRegistryFilterer is an auto generated log filtering Go binding around an Ethereum contract events. +type ProviderRegistryFilterer struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// ProviderRegistrySession is an auto generated Go binding around an Ethereum contract, +// with pre-set call and transact options. +type ProviderRegistrySession struct { + Contract *ProviderRegistry // Generic contract binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// ProviderRegistryCallerSession is an auto generated read-only Go binding around an Ethereum contract, +// with pre-set call options. +type ProviderRegistryCallerSession struct { + Contract *ProviderRegistryCaller // Generic contract caller binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session +} + +// ProviderRegistryTransactorSession is an auto generated write-only Go binding around an Ethereum contract, +// with pre-set transact options. +type ProviderRegistryTransactorSession struct { + Contract *ProviderRegistryTransactor // Generic contract transactor binding to set the session for + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// ProviderRegistryRaw is an auto generated low-level Go binding around an Ethereum contract. +type ProviderRegistryRaw struct { + Contract *ProviderRegistry // Generic contract binding to access the raw methods on +} + +// ProviderRegistryCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. +type ProviderRegistryCallerRaw struct { + Contract *ProviderRegistryCaller // Generic read-only contract binding to access the raw methods on +} + +// ProviderRegistryTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. +type ProviderRegistryTransactorRaw struct { + Contract *ProviderRegistryTransactor // Generic write-only contract binding to access the raw methods on +} + +// NewProviderRegistry creates a new instance of ProviderRegistry, bound to a specific deployed contract. +func NewProviderRegistry(address common.Address, backend bind.ContractBackend) (*ProviderRegistry, error) { + contract, err := bindProviderRegistry(address, backend, backend, backend) + if err != nil { + return nil, err + } + return &ProviderRegistry{ProviderRegistryCaller: ProviderRegistryCaller{contract: contract}, ProviderRegistryTransactor: ProviderRegistryTransactor{contract: contract}, ProviderRegistryFilterer: ProviderRegistryFilterer{contract: contract}}, nil +} + +// NewProviderRegistryCaller creates a new read-only instance of ProviderRegistry, bound to a specific deployed contract. +func NewProviderRegistryCaller(address common.Address, caller bind.ContractCaller) (*ProviderRegistryCaller, error) { + contract, err := bindProviderRegistry(address, caller, nil, nil) + if err != nil { + return nil, err + } + return &ProviderRegistryCaller{contract: contract}, nil +} + +// NewProviderRegistryTransactor creates a new write-only instance of ProviderRegistry, bound to a specific deployed contract. +func NewProviderRegistryTransactor(address common.Address, transactor bind.ContractTransactor) (*ProviderRegistryTransactor, error) { + contract, err := bindProviderRegistry(address, nil, transactor, nil) + if err != nil { + return nil, err + } + return &ProviderRegistryTransactor{contract: contract}, nil +} + +// NewProviderRegistryFilterer creates a new log filterer instance of ProviderRegistry, bound to a specific deployed contract. +func NewProviderRegistryFilterer(address common.Address, filterer bind.ContractFilterer) (*ProviderRegistryFilterer, error) { + contract, err := bindProviderRegistry(address, nil, nil, filterer) + if err != nil { + return nil, err + } + return &ProviderRegistryFilterer{contract: contract}, nil +} + +// bindProviderRegistry binds a generic wrapper to an already deployed contract. +func bindProviderRegistry(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { + parsed, err := ProviderRegistryMetaData.GetAbi() + if err != nil { + return nil, err + } + return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_ProviderRegistry *ProviderRegistryRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _ProviderRegistry.Contract.ProviderRegistryCaller.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_ProviderRegistry *ProviderRegistryRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _ProviderRegistry.Contract.ProviderRegistryTransactor.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_ProviderRegistry *ProviderRegistryRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _ProviderRegistry.Contract.ProviderRegistryTransactor.contract.Transact(opts, method, params...) +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_ProviderRegistry *ProviderRegistryCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _ProviderRegistry.Contract.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_ProviderRegistry *ProviderRegistryTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _ProviderRegistry.Contract.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_ProviderRegistry *ProviderRegistryTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _ProviderRegistry.Contract.contract.Transact(opts, method, params...) +} + +// BIDSSTORAGESLOT is a free data retrieval call binding the contract method 0x266ccff0. +// +// Solidity: function BIDS_STORAGE_SLOT() view returns(bytes32) +func (_ProviderRegistry *ProviderRegistryCaller) BIDSSTORAGESLOT(opts *bind.CallOpts) ([32]byte, error) { + var out []interface{} + err := _ProviderRegistry.contract.Call(opts, &out, "BIDS_STORAGE_SLOT") + + if err != nil { + return *new([32]byte), err + } + + out0 := *abi.ConvertType(out[0], new([32]byte)).(*[32]byte) + + return out0, err + +} + +// BIDSSTORAGESLOT is a free data retrieval call binding the contract method 0x266ccff0. +// +// Solidity: function BIDS_STORAGE_SLOT() view returns(bytes32) +func (_ProviderRegistry *ProviderRegistrySession) BIDSSTORAGESLOT() ([32]byte, error) { + return _ProviderRegistry.Contract.BIDSSTORAGESLOT(&_ProviderRegistry.CallOpts) +} + +// BIDSSTORAGESLOT is a free data retrieval call binding the contract method 0x266ccff0. +// +// Solidity: function BIDS_STORAGE_SLOT() view returns(bytes32) +func (_ProviderRegistry *ProviderRegistryCallerSession) BIDSSTORAGESLOT() ([32]byte, error) { + return _ProviderRegistry.Contract.BIDSSTORAGESLOT(&_ProviderRegistry.CallOpts) +} + +// DELEGATIONRULESMARKETPLACE is a free data retrieval call binding the contract method 0xad34a150. +// +// Solidity: function DELEGATION_RULES_MARKETPLACE() view returns(bytes32) +func (_ProviderRegistry *ProviderRegistryCaller) DELEGATIONRULESMARKETPLACE(opts *bind.CallOpts) ([32]byte, error) { + var out []interface{} + err := _ProviderRegistry.contract.Call(opts, &out, "DELEGATION_RULES_MARKETPLACE") + + if err != nil { + return *new([32]byte), err + } + + out0 := *abi.ConvertType(out[0], new([32]byte)).(*[32]byte) + + return out0, err + +} + +// DELEGATIONRULESMARKETPLACE is a free data retrieval call binding the contract method 0xad34a150. +// +// Solidity: function DELEGATION_RULES_MARKETPLACE() view returns(bytes32) +func (_ProviderRegistry *ProviderRegistrySession) DELEGATIONRULESMARKETPLACE() ([32]byte, error) { + return _ProviderRegistry.Contract.DELEGATIONRULESMARKETPLACE(&_ProviderRegistry.CallOpts) +} + +// DELEGATIONRULESMARKETPLACE is a free data retrieval call binding the contract method 0xad34a150. +// +// Solidity: function DELEGATION_RULES_MARKETPLACE() view returns(bytes32) +func (_ProviderRegistry *ProviderRegistryCallerSession) DELEGATIONRULESMARKETPLACE() ([32]byte, error) { + return _ProviderRegistry.Contract.DELEGATIONRULESMARKETPLACE(&_ProviderRegistry.CallOpts) +} + +// DELEGATIONRULESMODEL is a free data retrieval call binding the contract method 0x86878047. +// +// Solidity: function DELEGATION_RULES_MODEL() view returns(bytes32) +func (_ProviderRegistry *ProviderRegistryCaller) DELEGATIONRULESMODEL(opts *bind.CallOpts) ([32]byte, error) { + var out []interface{} + err := _ProviderRegistry.contract.Call(opts, &out, "DELEGATION_RULES_MODEL") + + if err != nil { + return *new([32]byte), err + } + + out0 := *abi.ConvertType(out[0], new([32]byte)).(*[32]byte) + + return out0, err + +} + +// DELEGATIONRULESMODEL is a free data retrieval call binding the contract method 0x86878047. +// +// Solidity: function DELEGATION_RULES_MODEL() view returns(bytes32) +func (_ProviderRegistry *ProviderRegistrySession) DELEGATIONRULESMODEL() ([32]byte, error) { + return _ProviderRegistry.Contract.DELEGATIONRULESMODEL(&_ProviderRegistry.CallOpts) +} + +// DELEGATIONRULESMODEL is a free data retrieval call binding the contract method 0x86878047. +// +// Solidity: function DELEGATION_RULES_MODEL() view returns(bytes32) +func (_ProviderRegistry *ProviderRegistryCallerSession) DELEGATIONRULESMODEL() ([32]byte, error) { + return _ProviderRegistry.Contract.DELEGATIONRULESMODEL(&_ProviderRegistry.CallOpts) +} + +// DELEGATIONRULESPROVIDER is a free data retrieval call binding the contract method 0x58aeef93. +// +// Solidity: function DELEGATION_RULES_PROVIDER() view returns(bytes32) +func (_ProviderRegistry *ProviderRegistryCaller) DELEGATIONRULESPROVIDER(opts *bind.CallOpts) ([32]byte, error) { + var out []interface{} + err := _ProviderRegistry.contract.Call(opts, &out, "DELEGATION_RULES_PROVIDER") + + if err != nil { + return *new([32]byte), err + } + + out0 := *abi.ConvertType(out[0], new([32]byte)).(*[32]byte) + + return out0, err + +} + +// DELEGATIONRULESPROVIDER is a free data retrieval call binding the contract method 0x58aeef93. +// +// Solidity: function DELEGATION_RULES_PROVIDER() view returns(bytes32) +func (_ProviderRegistry *ProviderRegistrySession) DELEGATIONRULESPROVIDER() ([32]byte, error) { + return _ProviderRegistry.Contract.DELEGATIONRULESPROVIDER(&_ProviderRegistry.CallOpts) +} + +// DELEGATIONRULESPROVIDER is a free data retrieval call binding the contract method 0x58aeef93. +// +// Solidity: function DELEGATION_RULES_PROVIDER() view returns(bytes32) +func (_ProviderRegistry *ProviderRegistryCallerSession) DELEGATIONRULESPROVIDER() ([32]byte, error) { + return _ProviderRegistry.Contract.DELEGATIONRULESPROVIDER(&_ProviderRegistry.CallOpts) +} + +// DELEGATIONRULESSESSION is a free data retrieval call binding the contract method 0xd1b43638. +// +// Solidity: function DELEGATION_RULES_SESSION() view returns(bytes32) +func (_ProviderRegistry *ProviderRegistryCaller) DELEGATIONRULESSESSION(opts *bind.CallOpts) ([32]byte, error) { + var out []interface{} + err := _ProviderRegistry.contract.Call(opts, &out, "DELEGATION_RULES_SESSION") + + if err != nil { + return *new([32]byte), err + } + + out0 := *abi.ConvertType(out[0], new([32]byte)).(*[32]byte) + + return out0, err + +} + +// DELEGATIONRULESSESSION is a free data retrieval call binding the contract method 0xd1b43638. +// +// Solidity: function DELEGATION_RULES_SESSION() view returns(bytes32) +func (_ProviderRegistry *ProviderRegistrySession) DELEGATIONRULESSESSION() ([32]byte, error) { + return _ProviderRegistry.Contract.DELEGATIONRULESSESSION(&_ProviderRegistry.CallOpts) +} + +// DELEGATIONRULESSESSION is a free data retrieval call binding the contract method 0xd1b43638. +// +// Solidity: function DELEGATION_RULES_SESSION() view returns(bytes32) +func (_ProviderRegistry *ProviderRegistryCallerSession) DELEGATIONRULESSESSION() ([32]byte, error) { + return _ProviderRegistry.Contract.DELEGATIONRULESSESSION(&_ProviderRegistry.CallOpts) +} + +// DELEGATIONSTORAGESLOT is a free data retrieval call binding the contract method 0xdd9b48cb. +// +// Solidity: function DELEGATION_STORAGE_SLOT() view returns(bytes32) +func (_ProviderRegistry *ProviderRegistryCaller) DELEGATIONSTORAGESLOT(opts *bind.CallOpts) ([32]byte, error) { + var out []interface{} + err := _ProviderRegistry.contract.Call(opts, &out, "DELEGATION_STORAGE_SLOT") + + if err != nil { + return *new([32]byte), err + } + + out0 := *abi.ConvertType(out[0], new([32]byte)).(*[32]byte) + + return out0, err + +} + +// DELEGATIONSTORAGESLOT is a free data retrieval call binding the contract method 0xdd9b48cb. +// +// Solidity: function DELEGATION_STORAGE_SLOT() view returns(bytes32) +func (_ProviderRegistry *ProviderRegistrySession) DELEGATIONSTORAGESLOT() ([32]byte, error) { + return _ProviderRegistry.Contract.DELEGATIONSTORAGESLOT(&_ProviderRegistry.CallOpts) +} + +// DELEGATIONSTORAGESLOT is a free data retrieval call binding the contract method 0xdd9b48cb. +// +// Solidity: function DELEGATION_STORAGE_SLOT() view returns(bytes32) +func (_ProviderRegistry *ProviderRegistryCallerSession) DELEGATIONSTORAGESLOT() ([32]byte, error) { + return _ProviderRegistry.Contract.DELEGATIONSTORAGESLOT(&_ProviderRegistry.CallOpts) +} + +// DIAMONDOWNABLESTORAGESLOT is a free data retrieval call binding the contract method 0x4ac3371e. +// +// Solidity: function DIAMOND_OWNABLE_STORAGE_SLOT() view returns(bytes32) +func (_ProviderRegistry *ProviderRegistryCaller) DIAMONDOWNABLESTORAGESLOT(opts *bind.CallOpts) ([32]byte, error) { + var out []interface{} + err := _ProviderRegistry.contract.Call(opts, &out, "DIAMOND_OWNABLE_STORAGE_SLOT") + + if err != nil { + return *new([32]byte), err + } + + out0 := *abi.ConvertType(out[0], new([32]byte)).(*[32]byte) + + return out0, err + +} + +// DIAMONDOWNABLESTORAGESLOT is a free data retrieval call binding the contract method 0x4ac3371e. +// +// Solidity: function DIAMOND_OWNABLE_STORAGE_SLOT() view returns(bytes32) +func (_ProviderRegistry *ProviderRegistrySession) DIAMONDOWNABLESTORAGESLOT() ([32]byte, error) { + return _ProviderRegistry.Contract.DIAMONDOWNABLESTORAGESLOT(&_ProviderRegistry.CallOpts) +} + +// DIAMONDOWNABLESTORAGESLOT is a free data retrieval call binding the contract method 0x4ac3371e. +// +// Solidity: function DIAMOND_OWNABLE_STORAGE_SLOT() view returns(bytes32) +func (_ProviderRegistry *ProviderRegistryCallerSession) DIAMONDOWNABLESTORAGESLOT() ([32]byte, error) { + return _ProviderRegistry.Contract.DIAMONDOWNABLESTORAGESLOT(&_ProviderRegistry.CallOpts) +} + +// PROVIDERSSTORAGESLOT is a free data retrieval call binding the contract method 0xc51830f6. +// +// Solidity: function PROVIDERS_STORAGE_SLOT() view returns(bytes32) +func (_ProviderRegistry *ProviderRegistryCaller) PROVIDERSSTORAGESLOT(opts *bind.CallOpts) ([32]byte, error) { + var out []interface{} + err := _ProviderRegistry.contract.Call(opts, &out, "PROVIDERS_STORAGE_SLOT") + + if err != nil { + return *new([32]byte), err + } + + out0 := *abi.ConvertType(out[0], new([32]byte)).(*[32]byte) + + return out0, err + +} + +// PROVIDERSSTORAGESLOT is a free data retrieval call binding the contract method 0xc51830f6. +// +// Solidity: function PROVIDERS_STORAGE_SLOT() view returns(bytes32) +func (_ProviderRegistry *ProviderRegistrySession) PROVIDERSSTORAGESLOT() ([32]byte, error) { + return _ProviderRegistry.Contract.PROVIDERSSTORAGESLOT(&_ProviderRegistry.CallOpts) +} + +// PROVIDERSSTORAGESLOT is a free data retrieval call binding the contract method 0xc51830f6. +// +// Solidity: function PROVIDERS_STORAGE_SLOT() view returns(bytes32) +func (_ProviderRegistry *ProviderRegistryCallerSession) PROVIDERSSTORAGESLOT() ([32]byte, error) { + return _ProviderRegistry.Contract.PROVIDERSSTORAGESLOT(&_ProviderRegistry.CallOpts) +} + +// GetActiveProviders is a free data retrieval call binding the contract method 0xd5472642. +// +// Solidity: function getActiveProviders(uint256 offset_, uint256 limit_) view returns(address[], uint256) +func (_ProviderRegistry *ProviderRegistryCaller) GetActiveProviders(opts *bind.CallOpts, offset_ *big.Int, limit_ *big.Int) ([]common.Address, *big.Int, error) { + var out []interface{} + err := _ProviderRegistry.contract.Call(opts, &out, "getActiveProviders", offset_, limit_) + + if err != nil { + return *new([]common.Address), *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new([]common.Address)).(*[]common.Address) + out1 := *abi.ConvertType(out[1], new(*big.Int)).(**big.Int) + + return out0, out1, err + +} + +// GetActiveProviders is a free data retrieval call binding the contract method 0xd5472642. +// +// Solidity: function getActiveProviders(uint256 offset_, uint256 limit_) view returns(address[], uint256) +func (_ProviderRegistry *ProviderRegistrySession) GetActiveProviders(offset_ *big.Int, limit_ *big.Int) ([]common.Address, *big.Int, error) { + return _ProviderRegistry.Contract.GetActiveProviders(&_ProviderRegistry.CallOpts, offset_, limit_) +} + +// GetActiveProviders is a free data retrieval call binding the contract method 0xd5472642. +// +// Solidity: function getActiveProviders(uint256 offset_, uint256 limit_) view returns(address[], uint256) +func (_ProviderRegistry *ProviderRegistryCallerSession) GetActiveProviders(offset_ *big.Int, limit_ *big.Int) ([]common.Address, *big.Int, error) { + return _ProviderRegistry.Contract.GetActiveProviders(&_ProviderRegistry.CallOpts, offset_, limit_) +} + +// GetBid is a free data retrieval call binding the contract method 0x91704e1e. +// +// Solidity: function getBid(bytes32 bidId_) view returns((address,bytes32,uint256,uint256,uint128,uint128)) +func (_ProviderRegistry *ProviderRegistryCaller) GetBid(opts *bind.CallOpts, bidId_ [32]byte) (IBidStorageBid, error) { + var out []interface{} + err := _ProviderRegistry.contract.Call(opts, &out, "getBid", bidId_) + + if err != nil { + return *new(IBidStorageBid), err + } + + out0 := *abi.ConvertType(out[0], new(IBidStorageBid)).(*IBidStorageBid) + + return out0, err + +} + +// GetBid is a free data retrieval call binding the contract method 0x91704e1e. +// +// Solidity: function getBid(bytes32 bidId_) view returns((address,bytes32,uint256,uint256,uint128,uint128)) +func (_ProviderRegistry *ProviderRegistrySession) GetBid(bidId_ [32]byte) (IBidStorageBid, error) { + return _ProviderRegistry.Contract.GetBid(&_ProviderRegistry.CallOpts, bidId_) +} + +// GetBid is a free data retrieval call binding the contract method 0x91704e1e. +// +// Solidity: function getBid(bytes32 bidId_) view returns((address,bytes32,uint256,uint256,uint128,uint128)) +func (_ProviderRegistry *ProviderRegistryCallerSession) GetBid(bidId_ [32]byte) (IBidStorageBid, error) { + return _ProviderRegistry.Contract.GetBid(&_ProviderRegistry.CallOpts, bidId_) +} + +// GetIsProviderActive is a free data retrieval call binding the contract method 0x63ef175d. +// +// Solidity: function getIsProviderActive(address provider_) view returns(bool) +func (_ProviderRegistry *ProviderRegistryCaller) GetIsProviderActive(opts *bind.CallOpts, provider_ common.Address) (bool, error) { + var out []interface{} + err := _ProviderRegistry.contract.Call(opts, &out, "getIsProviderActive", provider_) + + if err != nil { + return *new(bool), err + } + + out0 := *abi.ConvertType(out[0], new(bool)).(*bool) + + return out0, err + +} + +// GetIsProviderActive is a free data retrieval call binding the contract method 0x63ef175d. +// +// Solidity: function getIsProviderActive(address provider_) view returns(bool) +func (_ProviderRegistry *ProviderRegistrySession) GetIsProviderActive(provider_ common.Address) (bool, error) { + return _ProviderRegistry.Contract.GetIsProviderActive(&_ProviderRegistry.CallOpts, provider_) +} + +// GetIsProviderActive is a free data retrieval call binding the contract method 0x63ef175d. +// +// Solidity: function getIsProviderActive(address provider_) view returns(bool) +func (_ProviderRegistry *ProviderRegistryCallerSession) GetIsProviderActive(provider_ common.Address) (bool, error) { + return _ProviderRegistry.Contract.GetIsProviderActive(&_ProviderRegistry.CallOpts, provider_) +} + +// GetModelActiveBids is a free data retrieval call binding the contract method 0x8a683b6e. +// +// Solidity: function getModelActiveBids(bytes32 modelId_, uint256 offset_, uint256 limit_) view returns(bytes32[], uint256) +func (_ProviderRegistry *ProviderRegistryCaller) GetModelActiveBids(opts *bind.CallOpts, modelId_ [32]byte, offset_ *big.Int, limit_ *big.Int) ([][32]byte, *big.Int, error) { + var out []interface{} + err := _ProviderRegistry.contract.Call(opts, &out, "getModelActiveBids", modelId_, offset_, limit_) + + if err != nil { + return *new([][32]byte), *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new([][32]byte)).(*[][32]byte) + out1 := *abi.ConvertType(out[1], new(*big.Int)).(**big.Int) + + return out0, out1, err + +} + +// GetModelActiveBids is a free data retrieval call binding the contract method 0x8a683b6e. +// +// Solidity: function getModelActiveBids(bytes32 modelId_, uint256 offset_, uint256 limit_) view returns(bytes32[], uint256) +func (_ProviderRegistry *ProviderRegistrySession) GetModelActiveBids(modelId_ [32]byte, offset_ *big.Int, limit_ *big.Int) ([][32]byte, *big.Int, error) { + return _ProviderRegistry.Contract.GetModelActiveBids(&_ProviderRegistry.CallOpts, modelId_, offset_, limit_) +} + +// GetModelActiveBids is a free data retrieval call binding the contract method 0x8a683b6e. +// +// Solidity: function getModelActiveBids(bytes32 modelId_, uint256 offset_, uint256 limit_) view returns(bytes32[], uint256) +func (_ProviderRegistry *ProviderRegistryCallerSession) GetModelActiveBids(modelId_ [32]byte, offset_ *big.Int, limit_ *big.Int) ([][32]byte, *big.Int, error) { + return _ProviderRegistry.Contract.GetModelActiveBids(&_ProviderRegistry.CallOpts, modelId_, offset_, limit_) +} + +// GetModelBids is a free data retrieval call binding the contract method 0xfade17b1. +// +// Solidity: function getModelBids(bytes32 modelId_, uint256 offset_, uint256 limit_) view returns(bytes32[], uint256) +func (_ProviderRegistry *ProviderRegistryCaller) GetModelBids(opts *bind.CallOpts, modelId_ [32]byte, offset_ *big.Int, limit_ *big.Int) ([][32]byte, *big.Int, error) { + var out []interface{} + err := _ProviderRegistry.contract.Call(opts, &out, "getModelBids", modelId_, offset_, limit_) + + if err != nil { + return *new([][32]byte), *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new([][32]byte)).(*[][32]byte) + out1 := *abi.ConvertType(out[1], new(*big.Int)).(**big.Int) + + return out0, out1, err + +} + +// GetModelBids is a free data retrieval call binding the contract method 0xfade17b1. +// +// Solidity: function getModelBids(bytes32 modelId_, uint256 offset_, uint256 limit_) view returns(bytes32[], uint256) +func (_ProviderRegistry *ProviderRegistrySession) GetModelBids(modelId_ [32]byte, offset_ *big.Int, limit_ *big.Int) ([][32]byte, *big.Int, error) { + return _ProviderRegistry.Contract.GetModelBids(&_ProviderRegistry.CallOpts, modelId_, offset_, limit_) +} + +// GetModelBids is a free data retrieval call binding the contract method 0xfade17b1. +// +// Solidity: function getModelBids(bytes32 modelId_, uint256 offset_, uint256 limit_) view returns(bytes32[], uint256) +func (_ProviderRegistry *ProviderRegistryCallerSession) GetModelBids(modelId_ [32]byte, offset_ *big.Int, limit_ *big.Int) ([][32]byte, *big.Int, error) { + return _ProviderRegistry.Contract.GetModelBids(&_ProviderRegistry.CallOpts, modelId_, offset_, limit_) +} + +// GetProvider is a free data retrieval call binding the contract method 0x55f21eb7. +// +// Solidity: function getProvider(address provider_) view returns((string,uint256,uint128,uint128,uint256,bool)) +func (_ProviderRegistry *ProviderRegistryCaller) GetProvider(opts *bind.CallOpts, provider_ common.Address) (IProviderStorageProvider, error) { + var out []interface{} + err := _ProviderRegistry.contract.Call(opts, &out, "getProvider", provider_) + + if err != nil { + return *new(IProviderStorageProvider), err + } + + out0 := *abi.ConvertType(out[0], new(IProviderStorageProvider)).(*IProviderStorageProvider) + + return out0, err + +} + +// GetProvider is a free data retrieval call binding the contract method 0x55f21eb7. +// +// Solidity: function getProvider(address provider_) view returns((string,uint256,uint128,uint128,uint256,bool)) +func (_ProviderRegistry *ProviderRegistrySession) GetProvider(provider_ common.Address) (IProviderStorageProvider, error) { + return _ProviderRegistry.Contract.GetProvider(&_ProviderRegistry.CallOpts, provider_) +} + +// GetProvider is a free data retrieval call binding the contract method 0x55f21eb7. +// +// Solidity: function getProvider(address provider_) view returns((string,uint256,uint128,uint128,uint256,bool)) +func (_ProviderRegistry *ProviderRegistryCallerSession) GetProvider(provider_ common.Address) (IProviderStorageProvider, error) { + return _ProviderRegistry.Contract.GetProvider(&_ProviderRegistry.CallOpts, provider_) +} + +// GetProviderActiveBids is a free data retrieval call binding the contract method 0xaf5b77ca. +// +// Solidity: function getProviderActiveBids(address provider_, uint256 offset_, uint256 limit_) view returns(bytes32[], uint256) +func (_ProviderRegistry *ProviderRegistryCaller) GetProviderActiveBids(opts *bind.CallOpts, provider_ common.Address, offset_ *big.Int, limit_ *big.Int) ([][32]byte, *big.Int, error) { + var out []interface{} + err := _ProviderRegistry.contract.Call(opts, &out, "getProviderActiveBids", provider_, offset_, limit_) + + if err != nil { + return *new([][32]byte), *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new([][32]byte)).(*[][32]byte) + out1 := *abi.ConvertType(out[1], new(*big.Int)).(**big.Int) + + return out0, out1, err + +} + +// GetProviderActiveBids is a free data retrieval call binding the contract method 0xaf5b77ca. +// +// Solidity: function getProviderActiveBids(address provider_, uint256 offset_, uint256 limit_) view returns(bytes32[], uint256) +func (_ProviderRegistry *ProviderRegistrySession) GetProviderActiveBids(provider_ common.Address, offset_ *big.Int, limit_ *big.Int) ([][32]byte, *big.Int, error) { + return _ProviderRegistry.Contract.GetProviderActiveBids(&_ProviderRegistry.CallOpts, provider_, offset_, limit_) +} + +// GetProviderActiveBids is a free data retrieval call binding the contract method 0xaf5b77ca. +// +// Solidity: function getProviderActiveBids(address provider_, uint256 offset_, uint256 limit_) view returns(bytes32[], uint256) +func (_ProviderRegistry *ProviderRegistryCallerSession) GetProviderActiveBids(provider_ common.Address, offset_ *big.Int, limit_ *big.Int) ([][32]byte, *big.Int, error) { + return _ProviderRegistry.Contract.GetProviderActiveBids(&_ProviderRegistry.CallOpts, provider_, offset_, limit_) +} + +// GetProviderBids is a free data retrieval call binding the contract method 0x59d435c4. +// +// Solidity: function getProviderBids(address provider_, uint256 offset_, uint256 limit_) view returns(bytes32[], uint256) +func (_ProviderRegistry *ProviderRegistryCaller) GetProviderBids(opts *bind.CallOpts, provider_ common.Address, offset_ *big.Int, limit_ *big.Int) ([][32]byte, *big.Int, error) { + var out []interface{} + err := _ProviderRegistry.contract.Call(opts, &out, "getProviderBids", provider_, offset_, limit_) + + if err != nil { + return *new([][32]byte), *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new([][32]byte)).(*[][32]byte) + out1 := *abi.ConvertType(out[1], new(*big.Int)).(**big.Int) + + return out0, out1, err + +} + +// GetProviderBids is a free data retrieval call binding the contract method 0x59d435c4. +// +// Solidity: function getProviderBids(address provider_, uint256 offset_, uint256 limit_) view returns(bytes32[], uint256) +func (_ProviderRegistry *ProviderRegistrySession) GetProviderBids(provider_ common.Address, offset_ *big.Int, limit_ *big.Int) ([][32]byte, *big.Int, error) { + return _ProviderRegistry.Contract.GetProviderBids(&_ProviderRegistry.CallOpts, provider_, offset_, limit_) +} + +// GetProviderBids is a free data retrieval call binding the contract method 0x59d435c4. +// +// Solidity: function getProviderBids(address provider_, uint256 offset_, uint256 limit_) view returns(bytes32[], uint256) +func (_ProviderRegistry *ProviderRegistryCallerSession) GetProviderBids(provider_ common.Address, offset_ *big.Int, limit_ *big.Int) ([][32]byte, *big.Int, error) { + return _ProviderRegistry.Contract.GetProviderBids(&_ProviderRegistry.CallOpts, provider_, offset_, limit_) +} + +// GetProviderMinimumStake is a free data retrieval call binding the contract method 0x53c029f6. +// +// Solidity: function getProviderMinimumStake() view returns(uint256) +func (_ProviderRegistry *ProviderRegistryCaller) GetProviderMinimumStake(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _ProviderRegistry.contract.Call(opts, &out, "getProviderMinimumStake") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// GetProviderMinimumStake is a free data retrieval call binding the contract method 0x53c029f6. +// +// Solidity: function getProviderMinimumStake() view returns(uint256) +func (_ProviderRegistry *ProviderRegistrySession) GetProviderMinimumStake() (*big.Int, error) { + return _ProviderRegistry.Contract.GetProviderMinimumStake(&_ProviderRegistry.CallOpts) +} + +// GetProviderMinimumStake is a free data retrieval call binding the contract method 0x53c029f6. +// +// Solidity: function getProviderMinimumStake() view returns(uint256) +func (_ProviderRegistry *ProviderRegistryCallerSession) GetProviderMinimumStake() (*big.Int, error) { + return _ProviderRegistry.Contract.GetProviderMinimumStake(&_ProviderRegistry.CallOpts) +} + +// GetRegistry is a free data retrieval call binding the contract method 0x5ab1bd53. +// +// Solidity: function getRegistry() view returns(address) +func (_ProviderRegistry *ProviderRegistryCaller) GetRegistry(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _ProviderRegistry.contract.Call(opts, &out, "getRegistry") + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +// GetRegistry is a free data retrieval call binding the contract method 0x5ab1bd53. +// +// Solidity: function getRegistry() view returns(address) +func (_ProviderRegistry *ProviderRegistrySession) GetRegistry() (common.Address, error) { + return _ProviderRegistry.Contract.GetRegistry(&_ProviderRegistry.CallOpts) +} + +// GetRegistry is a free data retrieval call binding the contract method 0x5ab1bd53. +// +// Solidity: function getRegistry() view returns(address) +func (_ProviderRegistry *ProviderRegistryCallerSession) GetRegistry() (common.Address, error) { + return _ProviderRegistry.Contract.GetRegistry(&_ProviderRegistry.CallOpts) +} + +// GetToken is a free data retrieval call binding the contract method 0x21df0da7. +// +// Solidity: function getToken() view returns(address) +func (_ProviderRegistry *ProviderRegistryCaller) GetToken(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _ProviderRegistry.contract.Call(opts, &out, "getToken") + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +// GetToken is a free data retrieval call binding the contract method 0x21df0da7. +// +// Solidity: function getToken() view returns(address) +func (_ProviderRegistry *ProviderRegistrySession) GetToken() (common.Address, error) { + return _ProviderRegistry.Contract.GetToken(&_ProviderRegistry.CallOpts) +} + +// GetToken is a free data retrieval call binding the contract method 0x21df0da7. +// +// Solidity: function getToken() view returns(address) +func (_ProviderRegistry *ProviderRegistryCallerSession) GetToken() (common.Address, error) { + return _ProviderRegistry.Contract.GetToken(&_ProviderRegistry.CallOpts) +} + +// IsBidActive is a free data retrieval call binding the contract method 0x1345df58. +// +// Solidity: function isBidActive(bytes32 bidId_) view returns(bool) +func (_ProviderRegistry *ProviderRegistryCaller) IsBidActive(opts *bind.CallOpts, bidId_ [32]byte) (bool, error) { + var out []interface{} + err := _ProviderRegistry.contract.Call(opts, &out, "isBidActive", bidId_) + + if err != nil { + return *new(bool), err + } + + out0 := *abi.ConvertType(out[0], new(bool)).(*bool) + + return out0, err + +} + +// IsBidActive is a free data retrieval call binding the contract method 0x1345df58. +// +// Solidity: function isBidActive(bytes32 bidId_) view returns(bool) +func (_ProviderRegistry *ProviderRegistrySession) IsBidActive(bidId_ [32]byte) (bool, error) { + return _ProviderRegistry.Contract.IsBidActive(&_ProviderRegistry.CallOpts, bidId_) +} + +// IsBidActive is a free data retrieval call binding the contract method 0x1345df58. +// +// Solidity: function isBidActive(bytes32 bidId_) view returns(bool) +func (_ProviderRegistry *ProviderRegistryCallerSession) IsBidActive(bidId_ [32]byte) (bool, error) { + return _ProviderRegistry.Contract.IsBidActive(&_ProviderRegistry.CallOpts, bidId_) +} + +// IsRightsDelegated is a free data retrieval call binding the contract method 0x54126b8f. +// +// Solidity: function isRightsDelegated(address delegatee_, address delegator_, bytes32 rights_) view returns(bool) +func (_ProviderRegistry *ProviderRegistryCaller) IsRightsDelegated(opts *bind.CallOpts, delegatee_ common.Address, delegator_ common.Address, rights_ [32]byte) (bool, error) { + var out []interface{} + err := _ProviderRegistry.contract.Call(opts, &out, "isRightsDelegated", delegatee_, delegator_, rights_) + + if err != nil { + return *new(bool), err + } + + out0 := *abi.ConvertType(out[0], new(bool)).(*bool) + + return out0, err + +} + +// IsRightsDelegated is a free data retrieval call binding the contract method 0x54126b8f. +// +// Solidity: function isRightsDelegated(address delegatee_, address delegator_, bytes32 rights_) view returns(bool) +func (_ProviderRegistry *ProviderRegistrySession) IsRightsDelegated(delegatee_ common.Address, delegator_ common.Address, rights_ [32]byte) (bool, error) { + return _ProviderRegistry.Contract.IsRightsDelegated(&_ProviderRegistry.CallOpts, delegatee_, delegator_, rights_) +} + +// IsRightsDelegated is a free data retrieval call binding the contract method 0x54126b8f. +// +// Solidity: function isRightsDelegated(address delegatee_, address delegator_, bytes32 rights_) view returns(bool) +func (_ProviderRegistry *ProviderRegistryCallerSession) IsRightsDelegated(delegatee_ common.Address, delegator_ common.Address, rights_ [32]byte) (bool, error) { + return _ProviderRegistry.Contract.IsRightsDelegated(&_ProviderRegistry.CallOpts, delegatee_, delegator_, rights_) +} + +// Owner is a free data retrieval call binding the contract method 0x8da5cb5b. +// +// Solidity: function owner() view returns(address) +func (_ProviderRegistry *ProviderRegistryCaller) Owner(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _ProviderRegistry.contract.Call(opts, &out, "owner") + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +// Owner is a free data retrieval call binding the contract method 0x8da5cb5b. +// +// Solidity: function owner() view returns(address) +func (_ProviderRegistry *ProviderRegistrySession) Owner() (common.Address, error) { + return _ProviderRegistry.Contract.Owner(&_ProviderRegistry.CallOpts) +} + +// Owner is a free data retrieval call binding the contract method 0x8da5cb5b. +// +// Solidity: function owner() view returns(address) +func (_ProviderRegistry *ProviderRegistryCallerSession) Owner() (common.Address, error) { + return _ProviderRegistry.Contract.Owner(&_ProviderRegistry.CallOpts) +} + +// ProviderRegistryInit is a paid mutator transaction binding the contract method 0x5c7ce38b. +// +// Solidity: function __ProviderRegistry_init() returns() +func (_ProviderRegistry *ProviderRegistryTransactor) ProviderRegistryInit(opts *bind.TransactOpts) (*types.Transaction, error) { + return _ProviderRegistry.contract.Transact(opts, "__ProviderRegistry_init") +} + +// ProviderRegistryInit is a paid mutator transaction binding the contract method 0x5c7ce38b. +// +// Solidity: function __ProviderRegistry_init() returns() +func (_ProviderRegistry *ProviderRegistrySession) ProviderRegistryInit() (*types.Transaction, error) { + return _ProviderRegistry.Contract.ProviderRegistryInit(&_ProviderRegistry.TransactOpts) +} + +// ProviderRegistryInit is a paid mutator transaction binding the contract method 0x5c7ce38b. +// +// Solidity: function __ProviderRegistry_init() returns() +func (_ProviderRegistry *ProviderRegistryTransactorSession) ProviderRegistryInit() (*types.Transaction, error) { + return _ProviderRegistry.Contract.ProviderRegistryInit(&_ProviderRegistry.TransactOpts) +} + +// ProviderDeregister is a paid mutator transaction binding the contract method 0x2ca36c49. +// +// Solidity: function providerDeregister(address provider_) returns() +func (_ProviderRegistry *ProviderRegistryTransactor) ProviderDeregister(opts *bind.TransactOpts, provider_ common.Address) (*types.Transaction, error) { + return _ProviderRegistry.contract.Transact(opts, "providerDeregister", provider_) +} + +// ProviderDeregister is a paid mutator transaction binding the contract method 0x2ca36c49. +// +// Solidity: function providerDeregister(address provider_) returns() +func (_ProviderRegistry *ProviderRegistrySession) ProviderDeregister(provider_ common.Address) (*types.Transaction, error) { + return _ProviderRegistry.Contract.ProviderDeregister(&_ProviderRegistry.TransactOpts, provider_) +} + +// ProviderDeregister is a paid mutator transaction binding the contract method 0x2ca36c49. +// +// Solidity: function providerDeregister(address provider_) returns() +func (_ProviderRegistry *ProviderRegistryTransactorSession) ProviderDeregister(provider_ common.Address) (*types.Transaction, error) { + return _ProviderRegistry.Contract.ProviderDeregister(&_ProviderRegistry.TransactOpts, provider_) +} + +// ProviderRegister is a paid mutator transaction binding the contract method 0x365700cb. +// +// Solidity: function providerRegister(address provider_, uint256 amount_, string endpoint_) returns() +func (_ProviderRegistry *ProviderRegistryTransactor) ProviderRegister(opts *bind.TransactOpts, provider_ common.Address, amount_ *big.Int, endpoint_ string) (*types.Transaction, error) { + return _ProviderRegistry.contract.Transact(opts, "providerRegister", provider_, amount_, endpoint_) +} + +// ProviderRegister is a paid mutator transaction binding the contract method 0x365700cb. +// +// Solidity: function providerRegister(address provider_, uint256 amount_, string endpoint_) returns() +func (_ProviderRegistry *ProviderRegistrySession) ProviderRegister(provider_ common.Address, amount_ *big.Int, endpoint_ string) (*types.Transaction, error) { + return _ProviderRegistry.Contract.ProviderRegister(&_ProviderRegistry.TransactOpts, provider_, amount_, endpoint_) +} + +// ProviderRegister is a paid mutator transaction binding the contract method 0x365700cb. +// +// Solidity: function providerRegister(address provider_, uint256 amount_, string endpoint_) returns() +func (_ProviderRegistry *ProviderRegistryTransactorSession) ProviderRegister(provider_ common.Address, amount_ *big.Int, endpoint_ string) (*types.Transaction, error) { + return _ProviderRegistry.Contract.ProviderRegister(&_ProviderRegistry.TransactOpts, provider_, amount_, endpoint_) +} + +// ProviderSetMinStake is a paid mutator transaction binding the contract method 0x0b7f94d6. +// +// Solidity: function providerSetMinStake(uint256 providerMinimumStake_) returns() +func (_ProviderRegistry *ProviderRegistryTransactor) ProviderSetMinStake(opts *bind.TransactOpts, providerMinimumStake_ *big.Int) (*types.Transaction, error) { + return _ProviderRegistry.contract.Transact(opts, "providerSetMinStake", providerMinimumStake_) +} + +// ProviderSetMinStake is a paid mutator transaction binding the contract method 0x0b7f94d6. +// +// Solidity: function providerSetMinStake(uint256 providerMinimumStake_) returns() +func (_ProviderRegistry *ProviderRegistrySession) ProviderSetMinStake(providerMinimumStake_ *big.Int) (*types.Transaction, error) { + return _ProviderRegistry.Contract.ProviderSetMinStake(&_ProviderRegistry.TransactOpts, providerMinimumStake_) +} + +// ProviderSetMinStake is a paid mutator transaction binding the contract method 0x0b7f94d6. +// +// Solidity: function providerSetMinStake(uint256 providerMinimumStake_) returns() +func (_ProviderRegistry *ProviderRegistryTransactorSession) ProviderSetMinStake(providerMinimumStake_ *big.Int) (*types.Transaction, error) { + return _ProviderRegistry.Contract.ProviderSetMinStake(&_ProviderRegistry.TransactOpts, providerMinimumStake_) +} + +// ProviderRegistryInitializedIterator is returned from FilterInitialized and is used to iterate over the raw logs and unpacked data for Initialized events raised by the ProviderRegistry contract. +type ProviderRegistryInitializedIterator struct { + Event *ProviderRegistryInitialized // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *ProviderRegistryInitializedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(ProviderRegistryInitialized) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(ProviderRegistryInitialized) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *ProviderRegistryInitializedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *ProviderRegistryInitializedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// ProviderRegistryInitialized represents a Initialized event raised by the ProviderRegistry contract. +type ProviderRegistryInitialized struct { + StorageSlot [32]byte + Raw types.Log // Blockchain specific contextual infos +} + +// FilterInitialized is a free log retrieval operation binding the contract event 0xdc73717d728bcfa015e8117438a65319aa06e979ca324afa6e1ea645c28ea15d. +// +// Solidity: event Initialized(bytes32 storageSlot) +func (_ProviderRegistry *ProviderRegistryFilterer) FilterInitialized(opts *bind.FilterOpts) (*ProviderRegistryInitializedIterator, error) { + + logs, sub, err := _ProviderRegistry.contract.FilterLogs(opts, "Initialized") + if err != nil { + return nil, err + } + return &ProviderRegistryInitializedIterator{contract: _ProviderRegistry.contract, event: "Initialized", logs: logs, sub: sub}, nil +} + +// WatchInitialized is a free log subscription operation binding the contract event 0xdc73717d728bcfa015e8117438a65319aa06e979ca324afa6e1ea645c28ea15d. +// +// Solidity: event Initialized(bytes32 storageSlot) +func (_ProviderRegistry *ProviderRegistryFilterer) WatchInitialized(opts *bind.WatchOpts, sink chan<- *ProviderRegistryInitialized) (event.Subscription, error) { + + logs, sub, err := _ProviderRegistry.contract.WatchLogs(opts, "Initialized") + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(ProviderRegistryInitialized) + if err := _ProviderRegistry.contract.UnpackLog(event, "Initialized", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseInitialized is a log parse operation binding the contract event 0xdc73717d728bcfa015e8117438a65319aa06e979ca324afa6e1ea645c28ea15d. +// +// Solidity: event Initialized(bytes32 storageSlot) +func (_ProviderRegistry *ProviderRegistryFilterer) ParseInitialized(log types.Log) (*ProviderRegistryInitialized, error) { + event := new(ProviderRegistryInitialized) + if err := _ProviderRegistry.contract.UnpackLog(event, "Initialized", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// ProviderRegistryProviderDeregisteredIterator is returned from FilterProviderDeregistered and is used to iterate over the raw logs and unpacked data for ProviderDeregistered events raised by the ProviderRegistry contract. +type ProviderRegistryProviderDeregisteredIterator struct { + Event *ProviderRegistryProviderDeregistered // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *ProviderRegistryProviderDeregisteredIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(ProviderRegistryProviderDeregistered) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(ProviderRegistryProviderDeregistered) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *ProviderRegistryProviderDeregisteredIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *ProviderRegistryProviderDeregisteredIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// ProviderRegistryProviderDeregistered represents a ProviderDeregistered event raised by the ProviderRegistry contract. +type ProviderRegistryProviderDeregistered struct { + Provider common.Address + Raw types.Log // Blockchain specific contextual infos +} + +// FilterProviderDeregistered is a free log retrieval operation binding the contract event 0xf04091b4a187e321a42001e46961e45b6a75b203fc6fb766b7e05505f6080abb. +// +// Solidity: event ProviderDeregistered(address indexed provider) +func (_ProviderRegistry *ProviderRegistryFilterer) FilterProviderDeregistered(opts *bind.FilterOpts, provider []common.Address) (*ProviderRegistryProviderDeregisteredIterator, error) { + + var providerRule []interface{} + for _, providerItem := range provider { + providerRule = append(providerRule, providerItem) + } + + logs, sub, err := _ProviderRegistry.contract.FilterLogs(opts, "ProviderDeregistered", providerRule) + if err != nil { + return nil, err + } + return &ProviderRegistryProviderDeregisteredIterator{contract: _ProviderRegistry.contract, event: "ProviderDeregistered", logs: logs, sub: sub}, nil +} + +// WatchProviderDeregistered is a free log subscription operation binding the contract event 0xf04091b4a187e321a42001e46961e45b6a75b203fc6fb766b7e05505f6080abb. +// +// Solidity: event ProviderDeregistered(address indexed provider) +func (_ProviderRegistry *ProviderRegistryFilterer) WatchProviderDeregistered(opts *bind.WatchOpts, sink chan<- *ProviderRegistryProviderDeregistered, provider []common.Address) (event.Subscription, error) { + + var providerRule []interface{} + for _, providerItem := range provider { + providerRule = append(providerRule, providerItem) + } + + logs, sub, err := _ProviderRegistry.contract.WatchLogs(opts, "ProviderDeregistered", providerRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(ProviderRegistryProviderDeregistered) + if err := _ProviderRegistry.contract.UnpackLog(event, "ProviderDeregistered", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseProviderDeregistered is a log parse operation binding the contract event 0xf04091b4a187e321a42001e46961e45b6a75b203fc6fb766b7e05505f6080abb. +// +// Solidity: event ProviderDeregistered(address indexed provider) +func (_ProviderRegistry *ProviderRegistryFilterer) ParseProviderDeregistered(log types.Log) (*ProviderRegistryProviderDeregistered, error) { + event := new(ProviderRegistryProviderDeregistered) + if err := _ProviderRegistry.contract.UnpackLog(event, "ProviderDeregistered", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// ProviderRegistryProviderMinimumStakeUpdatedIterator is returned from FilterProviderMinimumStakeUpdated and is used to iterate over the raw logs and unpacked data for ProviderMinimumStakeUpdated events raised by the ProviderRegistry contract. +type ProviderRegistryProviderMinimumStakeUpdatedIterator struct { + Event *ProviderRegistryProviderMinimumStakeUpdated // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *ProviderRegistryProviderMinimumStakeUpdatedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(ProviderRegistryProviderMinimumStakeUpdated) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(ProviderRegistryProviderMinimumStakeUpdated) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *ProviderRegistryProviderMinimumStakeUpdatedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *ProviderRegistryProviderMinimumStakeUpdatedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// ProviderRegistryProviderMinimumStakeUpdated represents a ProviderMinimumStakeUpdated event raised by the ProviderRegistry contract. +type ProviderRegistryProviderMinimumStakeUpdated struct { + ProviderMinimumStake *big.Int + Raw types.Log // Blockchain specific contextual infos +} + +// FilterProviderMinimumStakeUpdated is a free log retrieval operation binding the contract event 0x4d6b08cda70533f8222fea5ffc794d3a1f5dcde2620c6fa74789ef647db19450. +// +// Solidity: event ProviderMinimumStakeUpdated(uint256 providerMinimumStake) +func (_ProviderRegistry *ProviderRegistryFilterer) FilterProviderMinimumStakeUpdated(opts *bind.FilterOpts) (*ProviderRegistryProviderMinimumStakeUpdatedIterator, error) { + + logs, sub, err := _ProviderRegistry.contract.FilterLogs(opts, "ProviderMinimumStakeUpdated") + if err != nil { + return nil, err + } + return &ProviderRegistryProviderMinimumStakeUpdatedIterator{contract: _ProviderRegistry.contract, event: "ProviderMinimumStakeUpdated", logs: logs, sub: sub}, nil +} + +// WatchProviderMinimumStakeUpdated is a free log subscription operation binding the contract event 0x4d6b08cda70533f8222fea5ffc794d3a1f5dcde2620c6fa74789ef647db19450. +// +// Solidity: event ProviderMinimumStakeUpdated(uint256 providerMinimumStake) +func (_ProviderRegistry *ProviderRegistryFilterer) WatchProviderMinimumStakeUpdated(opts *bind.WatchOpts, sink chan<- *ProviderRegistryProviderMinimumStakeUpdated) (event.Subscription, error) { + + logs, sub, err := _ProviderRegistry.contract.WatchLogs(opts, "ProviderMinimumStakeUpdated") + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(ProviderRegistryProviderMinimumStakeUpdated) + if err := _ProviderRegistry.contract.UnpackLog(event, "ProviderMinimumStakeUpdated", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseProviderMinimumStakeUpdated is a log parse operation binding the contract event 0x4d6b08cda70533f8222fea5ffc794d3a1f5dcde2620c6fa74789ef647db19450. +// +// Solidity: event ProviderMinimumStakeUpdated(uint256 providerMinimumStake) +func (_ProviderRegistry *ProviderRegistryFilterer) ParseProviderMinimumStakeUpdated(log types.Log) (*ProviderRegistryProviderMinimumStakeUpdated, error) { + event := new(ProviderRegistryProviderMinimumStakeUpdated) + if err := _ProviderRegistry.contract.UnpackLog(event, "ProviderMinimumStakeUpdated", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// ProviderRegistryProviderRegisteredIterator is returned from FilterProviderRegistered and is used to iterate over the raw logs and unpacked data for ProviderRegistered events raised by the ProviderRegistry contract. +type ProviderRegistryProviderRegisteredIterator struct { + Event *ProviderRegistryProviderRegistered // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *ProviderRegistryProviderRegisteredIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(ProviderRegistryProviderRegistered) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(ProviderRegistryProviderRegistered) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *ProviderRegistryProviderRegisteredIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *ProviderRegistryProviderRegisteredIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// ProviderRegistryProviderRegistered represents a ProviderRegistered event raised by the ProviderRegistry contract. +type ProviderRegistryProviderRegistered struct { + Provider common.Address + Raw types.Log // Blockchain specific contextual infos +} + +// FilterProviderRegistered is a free log retrieval operation binding the contract event 0x70abce74777b3838ae60a33a6b9a87d9d25532668fe4fea548554c55868579c0. +// +// Solidity: event ProviderRegistered(address indexed provider) +func (_ProviderRegistry *ProviderRegistryFilterer) FilterProviderRegistered(opts *bind.FilterOpts, provider []common.Address) (*ProviderRegistryProviderRegisteredIterator, error) { + + var providerRule []interface{} + for _, providerItem := range provider { + providerRule = append(providerRule, providerItem) + } + + logs, sub, err := _ProviderRegistry.contract.FilterLogs(opts, "ProviderRegistered", providerRule) + if err != nil { + return nil, err + } + return &ProviderRegistryProviderRegisteredIterator{contract: _ProviderRegistry.contract, event: "ProviderRegistered", logs: logs, sub: sub}, nil +} + +// WatchProviderRegistered is a free log subscription operation binding the contract event 0x70abce74777b3838ae60a33a6b9a87d9d25532668fe4fea548554c55868579c0. +// +// Solidity: event ProviderRegistered(address indexed provider) +func (_ProviderRegistry *ProviderRegistryFilterer) WatchProviderRegistered(opts *bind.WatchOpts, sink chan<- *ProviderRegistryProviderRegistered, provider []common.Address) (event.Subscription, error) { + + var providerRule []interface{} + for _, providerItem := range provider { + providerRule = append(providerRule, providerItem) + } + + logs, sub, err := _ProviderRegistry.contract.WatchLogs(opts, "ProviderRegistered", providerRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(ProviderRegistryProviderRegistered) + if err := _ProviderRegistry.contract.UnpackLog(event, "ProviderRegistered", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseProviderRegistered is a log parse operation binding the contract event 0x70abce74777b3838ae60a33a6b9a87d9d25532668fe4fea548554c55868579c0. +// +// Solidity: event ProviderRegistered(address indexed provider) +func (_ProviderRegistry *ProviderRegistryFilterer) ParseProviderRegistered(log types.Log) (*ProviderRegistryProviderRegistered, error) { + event := new(ProviderRegistryProviderRegistered) + if err := _ProviderRegistry.contract.UnpackLog(event, "ProviderRegistered", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// ProviderRegistryProviderWithdrawnIterator is returned from FilterProviderWithdrawn and is used to iterate over the raw logs and unpacked data for ProviderWithdrawn events raised by the ProviderRegistry contract. +type ProviderRegistryProviderWithdrawnIterator struct { + Event *ProviderRegistryProviderWithdrawn // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *ProviderRegistryProviderWithdrawnIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(ProviderRegistryProviderWithdrawn) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(ProviderRegistryProviderWithdrawn) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *ProviderRegistryProviderWithdrawnIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *ProviderRegistryProviderWithdrawnIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// ProviderRegistryProviderWithdrawn represents a ProviderWithdrawn event raised by the ProviderRegistry contract. +type ProviderRegistryProviderWithdrawn struct { + Provider common.Address + Amount *big.Int + Raw types.Log // Blockchain specific contextual infos +} + +// FilterProviderWithdrawn is a free log retrieval operation binding the contract event 0x61388fbc2ba003175d3018b8f13b002234cc4e203a332a4a6dadb96bc82c3db2. +// +// Solidity: event ProviderWithdrawn(address indexed provider, uint256 amount) +func (_ProviderRegistry *ProviderRegistryFilterer) FilterProviderWithdrawn(opts *bind.FilterOpts, provider []common.Address) (*ProviderRegistryProviderWithdrawnIterator, error) { + + var providerRule []interface{} + for _, providerItem := range provider { + providerRule = append(providerRule, providerItem) + } + + logs, sub, err := _ProviderRegistry.contract.FilterLogs(opts, "ProviderWithdrawn", providerRule) + if err != nil { + return nil, err + } + return &ProviderRegistryProviderWithdrawnIterator{contract: _ProviderRegistry.contract, event: "ProviderWithdrawn", logs: logs, sub: sub}, nil +} + +// WatchProviderWithdrawn is a free log subscription operation binding the contract event 0x61388fbc2ba003175d3018b8f13b002234cc4e203a332a4a6dadb96bc82c3db2. +// +// Solidity: event ProviderWithdrawn(address indexed provider, uint256 amount) +func (_ProviderRegistry *ProviderRegistryFilterer) WatchProviderWithdrawn(opts *bind.WatchOpts, sink chan<- *ProviderRegistryProviderWithdrawn, provider []common.Address) (event.Subscription, error) { + + var providerRule []interface{} + for _, providerItem := range provider { + providerRule = append(providerRule, providerItem) + } + + logs, sub, err := _ProviderRegistry.contract.WatchLogs(opts, "ProviderWithdrawn", providerRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(ProviderRegistryProviderWithdrawn) + if err := _ProviderRegistry.contract.UnpackLog(event, "ProviderWithdrawn", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseProviderWithdrawn is a log parse operation binding the contract event 0x61388fbc2ba003175d3018b8f13b002234cc4e203a332a4a6dadb96bc82c3db2. +// +// Solidity: event ProviderWithdrawn(address indexed provider, uint256 amount) +func (_ProviderRegistry *ProviderRegistryFilterer) ParseProviderWithdrawn(log types.Log) (*ProviderRegistryProviderWithdrawn, error) { + event := new(ProviderRegistryProviderWithdrawn) + if err := _ProviderRegistry.contract.UnpackLog(event, "ProviderWithdrawn", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} diff --git a/proxy-router/internal/repositories/contracts/bindings/sessionrouter/SessionRouter.go b/proxy-router/internal/repositories/contracts/bindings/sessionrouter/SessionRouter.go new file mode 100644 index 00000000..6cd788ba --- /dev/null +++ b/proxy-router/internal/repositories/contracts/bindings/sessionrouter/SessionRouter.go @@ -0,0 +1,2538 @@ +// Code generated - DO NOT EDIT. +// This file is a generated binding and any manual changes will be lost. + +package sessionrouter + +import ( + "errors" + "math/big" + "strings" + + ethereum "github.com/ethereum/go-ethereum" + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/event" +) + +// Reference imports to suppress errors if they are not otherwise used. +var ( + _ = errors.New + _ = big.NewInt + _ = strings.NewReader + _ = ethereum.NotFound + _ = bind.Bind + _ = common.Big1 + _ = types.BloomLookup + _ = event.NewSubscription + _ = abi.ConvertType +) + +// IBidStorageBid is an auto generated low-level Go binding around an user-defined struct. +type IBidStorageBid struct { + Provider common.Address + ModelId [32]byte + PricePerSecond *big.Int + Nonce *big.Int + CreatedAt *big.Int + DeletedAt *big.Int +} + +// IProviderStorageProvider is an auto generated low-level Go binding around an user-defined struct. +type IProviderStorageProvider struct { + Endpoint string + Stake *big.Int + CreatedAt *big.Int + LimitPeriodEnd *big.Int + LimitPeriodEarned *big.Int + IsDeleted bool +} + +// ISessionStoragePool is an auto generated low-level Go binding around an user-defined struct. +type ISessionStoragePool struct { + InitialReward *big.Int + RewardDecrease *big.Int + PayoutStart *big.Int + DecreaseInterval *big.Int +} + +// ISessionStorageSession is an auto generated low-level Go binding around an user-defined struct. +type ISessionStorageSession struct { + User common.Address + BidId [32]byte + Stake *big.Int + CloseoutReceipt []byte + CloseoutType *big.Int + ProviderWithdrawnAmount *big.Int + OpenedAt *big.Int + EndsAt *big.Int + ClosedAt *big.Int + IsActive bool + IsDirectPaymentFromUser bool +} + +// IStatsStorageModelStats is an auto generated low-level Go binding around an user-defined struct. +type IStatsStorageModelStats struct { + TpsScaled1000 LibSDSD + TtftMs LibSDSD + TotalDuration LibSDSD + Count uint32 +} + +// IStatsStorageProviderModelStats is an auto generated low-level Go binding around an user-defined struct. +type IStatsStorageProviderModelStats struct { + TpsScaled1000 LibSDSD + TtftMs LibSDSD + TotalDuration uint32 + SuccessCount uint32 + TotalCount uint32 +} + +// LibSDSD is an auto generated low-level Go binding around an user-defined struct. +type LibSDSD struct { + Mean int64 + SqSum int64 +} + +// SessionRouterMetaData contains all meta data concerning the SessionRouter contract. +var SessionRouterMetaData = &bind.MetaData{ + ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"delegator\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"delegatee\",\"type\":\"address\"}],\"name\":\"InsufficientRightsForOperation\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account_\",\"type\":\"address\"}],\"name\":\"OwnableUnauthorizedAccount\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"SessionAlreadyClosed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"SessionApprovedForAnotherUser\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"SessionBidNotFound\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"SessionDuplicateApproval\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"SessionMaxDurationTooShort\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"SessionNotEndedOrNotExist\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"SessionPoolIndexOutOfBounds\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"SessionProviderNothingToClaimInThisPeriod\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"SessionProviderSignatureMismatch\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"SessionStakeTooLow\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"SessionTooShort\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"SessionUserAmountToWithdrawIsZero\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"SesssionApproveExpired\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"SesssionApprovedForAnotherChainId\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"SesssionReceiptExpired\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"SesssionReceiptForAnotherChainId\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"storageSlot\",\"type\":\"bytes32\"}],\"name\":\"Initialized\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"user\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"sessionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"providerId\",\"type\":\"address\"}],\"name\":\"SessionClosed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"user\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"sessionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"providerId\",\"type\":\"address\"}],\"name\":\"SessionOpened\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"user\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount_\",\"type\":\"uint256\"}],\"name\":\"UserWithdrawn\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"BIDS_STORAGE_SLOT\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"COMPUTE_POOL_INDEX\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"DELEGATION_RULES_MARKETPLACE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"DELEGATION_RULES_MODEL\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"DELEGATION_RULES_PROVIDER\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"DELEGATION_RULES_SESSION\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"DELEGATION_STORAGE_SLOT\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"DIAMOND_OWNABLE_STORAGE_SLOT\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"MIN_SESSION_DURATION\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"PROVIDERS_STORAGE_SLOT\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"SESSIONS_STORAGE_SLOT\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"SIGNATURE_TTL\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"STATS_STORAGE_SLOT\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"fundingAccount_\",\"type\":\"address\"},{\"internalType\":\"uint128\",\"name\":\"maxSessionDuration_\",\"type\":\"uint128\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"initialReward\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"rewardDecrease\",\"type\":\"uint256\"},{\"internalType\":\"uint128\",\"name\":\"payoutStart\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"decreaseInterval\",\"type\":\"uint128\"}],\"internalType\":\"structISessionStorage.Pool[]\",\"name\":\"pools_\",\"type\":\"tuple[]\"}],\"name\":\"__SessionRouter_init\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"sessionId_\",\"type\":\"bytes32\"}],\"name\":\"claimForProvider\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"receiptEncoded_\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"signature_\",\"type\":\"bytes\"}],\"name\":\"closeSession\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"offset_\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"limit_\",\"type\":\"uint256\"}],\"name\":\"getActiveProviders\",\"outputs\":[{\"internalType\":\"address[]\",\"name\":\"\",\"type\":\"address[]\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"bidId_\",\"type\":\"bytes32\"}],\"name\":\"getBid\",\"outputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"provider\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"modelId\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"pricePerSecond\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"internalType\":\"uint128\",\"name\":\"createdAt\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"deletedAt\",\"type\":\"uint128\"}],\"internalType\":\"structIBidStorage.Bid\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint128\",\"name\":\"timestamp_\",\"type\":\"uint128\"}],\"name\":\"getComputeBalance\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getFundingAccount\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"provider_\",\"type\":\"address\"}],\"name\":\"getIsProviderActive\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"approval_\",\"type\":\"bytes\"}],\"name\":\"getIsProviderApprovalUsed\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getMaxSessionDuration\",\"outputs\":[{\"internalType\":\"uint128\",\"name\":\"\",\"type\":\"uint128\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"modelId_\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"offset_\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"limit_\",\"type\":\"uint256\"}],\"name\":\"getModelActiveBids\",\"outputs\":[{\"internalType\":\"bytes32[]\",\"name\":\"\",\"type\":\"bytes32[]\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"modelId_\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"offset_\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"limit_\",\"type\":\"uint256\"}],\"name\":\"getModelBids\",\"outputs\":[{\"internalType\":\"bytes32[]\",\"name\":\"\",\"type\":\"bytes32[]\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"modelId_\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"offset_\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"limit_\",\"type\":\"uint256\"}],\"name\":\"getModelSessions\",\"outputs\":[{\"internalType\":\"bytes32[]\",\"name\":\"\",\"type\":\"bytes32[]\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"modelId_\",\"type\":\"bytes32\"}],\"name\":\"getModelStats\",\"outputs\":[{\"components\":[{\"components\":[{\"internalType\":\"int64\",\"name\":\"mean\",\"type\":\"int64\"},{\"internalType\":\"int64\",\"name\":\"sqSum\",\"type\":\"int64\"}],\"internalType\":\"structLibSD.SD\",\"name\":\"tpsScaled1000\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"int64\",\"name\":\"mean\",\"type\":\"int64\"},{\"internalType\":\"int64\",\"name\":\"sqSum\",\"type\":\"int64\"}],\"internalType\":\"structLibSD.SD\",\"name\":\"ttftMs\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"int64\",\"name\":\"mean\",\"type\":\"int64\"},{\"internalType\":\"int64\",\"name\":\"sqSum\",\"type\":\"int64\"}],\"internalType\":\"structLibSD.SD\",\"name\":\"totalDuration\",\"type\":\"tuple\"},{\"internalType\":\"uint32\",\"name\":\"count\",\"type\":\"uint32\"}],\"internalType\":\"structIStatsStorage.ModelStats\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"index_\",\"type\":\"uint256\"}],\"name\":\"getPool\",\"outputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"initialReward\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"rewardDecrease\",\"type\":\"uint256\"},{\"internalType\":\"uint128\",\"name\":\"payoutStart\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"decreaseInterval\",\"type\":\"uint128\"}],\"internalType\":\"structISessionStorage.Pool\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getPools\",\"outputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"initialReward\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"rewardDecrease\",\"type\":\"uint256\"},{\"internalType\":\"uint128\",\"name\":\"payoutStart\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"decreaseInterval\",\"type\":\"uint128\"}],\"internalType\":\"structISessionStorage.Pool[]\",\"name\":\"\",\"type\":\"tuple[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"provider_\",\"type\":\"address\"}],\"name\":\"getProvider\",\"outputs\":[{\"components\":[{\"internalType\":\"string\",\"name\":\"endpoint\",\"type\":\"string\"},{\"internalType\":\"uint256\",\"name\":\"stake\",\"type\":\"uint256\"},{\"internalType\":\"uint128\",\"name\":\"createdAt\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"limitPeriodEnd\",\"type\":\"uint128\"},{\"internalType\":\"uint256\",\"name\":\"limitPeriodEarned\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"isDeleted\",\"type\":\"bool\"}],\"internalType\":\"structIProviderStorage.Provider\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"provider_\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"offset_\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"limit_\",\"type\":\"uint256\"}],\"name\":\"getProviderActiveBids\",\"outputs\":[{\"internalType\":\"bytes32[]\",\"name\":\"\",\"type\":\"bytes32[]\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"provider_\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"offset_\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"limit_\",\"type\":\"uint256\"}],\"name\":\"getProviderBids\",\"outputs\":[{\"internalType\":\"bytes32[]\",\"name\":\"\",\"type\":\"bytes32[]\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getProviderMinimumStake\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"modelId_\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"provider_\",\"type\":\"address\"}],\"name\":\"getProviderModelStats\",\"outputs\":[{\"components\":[{\"components\":[{\"internalType\":\"int64\",\"name\":\"mean\",\"type\":\"int64\"},{\"internalType\":\"int64\",\"name\":\"sqSum\",\"type\":\"int64\"}],\"internalType\":\"structLibSD.SD\",\"name\":\"tpsScaled1000\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"int64\",\"name\":\"mean\",\"type\":\"int64\"},{\"internalType\":\"int64\",\"name\":\"sqSum\",\"type\":\"int64\"}],\"internalType\":\"structLibSD.SD\",\"name\":\"ttftMs\",\"type\":\"tuple\"},{\"internalType\":\"uint32\",\"name\":\"totalDuration\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"successCount\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"totalCount\",\"type\":\"uint32\"}],\"internalType\":\"structIStatsStorage.ProviderModelStats\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"provider_\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"offset_\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"limit_\",\"type\":\"uint256\"}],\"name\":\"getProviderSessions\",\"outputs\":[{\"internalType\":\"bytes32[]\",\"name\":\"\",\"type\":\"bytes32[]\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getProvidersTotalClaimed\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getRegistry\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"sessionId_\",\"type\":\"bytes32\"}],\"name\":\"getSession\",\"outputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"user\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"bidId\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"stake\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"closeoutReceipt\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"closeoutType\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"providerWithdrawnAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint128\",\"name\":\"openedAt\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"endsAt\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"closedAt\",\"type\":\"uint128\"},{\"internalType\":\"bool\",\"name\":\"isActive\",\"type\":\"bool\"},{\"internalType\":\"bool\",\"name\":\"isDirectPaymentFromUser\",\"type\":\"bool\"}],\"internalType\":\"structISessionStorage.Session\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"amount_\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"pricePerSecond_\",\"type\":\"uint256\"},{\"internalType\":\"uint128\",\"name\":\"openedAt_\",\"type\":\"uint128\"}],\"name\":\"getSessionEnd\",\"outputs\":[{\"internalType\":\"uint128\",\"name\":\"\",\"type\":\"uint128\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"user_\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"provider_\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"bidId_\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"sessionNonce_\",\"type\":\"uint256\"}],\"name\":\"getSessionId\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint128\",\"name\":\"timestamp_\",\"type\":\"uint128\"}],\"name\":\"getTodaysBudget\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getToken\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"provider_\",\"type\":\"address\"}],\"name\":\"getTotalSessions\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"user_\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"offset_\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"limit_\",\"type\":\"uint256\"}],\"name\":\"getUserSessions\",\"outputs\":[{\"internalType\":\"bytes32[]\",\"name\":\"\",\"type\":\"bytes32[]\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"user_\",\"type\":\"address\"},{\"internalType\":\"uint8\",\"name\":\"iterations_\",\"type\":\"uint8\"}],\"name\":\"getUserStakesOnHold\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"available_\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"hold_\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"bidId_\",\"type\":\"bytes32\"}],\"name\":\"isBidActive\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"delegatee_\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"delegator_\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"rights_\",\"type\":\"bytes32\"}],\"name\":\"isRightsDelegated\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"user_\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount_\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"isDirectPaymentFromUser_\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"approvalEncoded_\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"signature_\",\"type\":\"bytes\"}],\"name\":\"openSession\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint128\",\"name\":\"maxSessionDuration_\",\"type\":\"uint128\"}],\"name\":\"setMaxSessionDuration\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"index_\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"initialReward\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"rewardDecrease\",\"type\":\"uint256\"},{\"internalType\":\"uint128\",\"name\":\"payoutStart\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"decreaseInterval\",\"type\":\"uint128\"}],\"internalType\":\"structISessionStorage.Pool\",\"name\":\"pool_\",\"type\":\"tuple\"}],\"name\":\"setPoolConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"amount_\",\"type\":\"uint256\"},{\"internalType\":\"uint128\",\"name\":\"timestamp_\",\"type\":\"uint128\"}],\"name\":\"stakeToStipend\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint128\",\"name\":\"timestamp_\",\"type\":\"uint128\"}],\"name\":\"startOfTheDay\",\"outputs\":[{\"internalType\":\"uint128\",\"name\":\"\",\"type\":\"uint128\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"stipend_\",\"type\":\"uint256\"},{\"internalType\":\"uint128\",\"name\":\"timestamp_\",\"type\":\"uint128\"}],\"name\":\"stipendToStake\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint128\",\"name\":\"timestamp_\",\"type\":\"uint128\"}],\"name\":\"totalMORSupply\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"user_\",\"type\":\"address\"},{\"internalType\":\"uint8\",\"name\":\"iterations_\",\"type\":\"uint8\"}],\"name\":\"withdrawUserStakes\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", +} + +// SessionRouterABI is the input ABI used to generate the binding from. +// Deprecated: Use SessionRouterMetaData.ABI instead. +var SessionRouterABI = SessionRouterMetaData.ABI + +// SessionRouter is an auto generated Go binding around an Ethereum contract. +type SessionRouter struct { + SessionRouterCaller // Read-only binding to the contract + SessionRouterTransactor // Write-only binding to the contract + SessionRouterFilterer // Log filterer for contract events +} + +// SessionRouterCaller is an auto generated read-only Go binding around an Ethereum contract. +type SessionRouterCaller struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// SessionRouterTransactor is an auto generated write-only Go binding around an Ethereum contract. +type SessionRouterTransactor struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// SessionRouterFilterer is an auto generated log filtering Go binding around an Ethereum contract events. +type SessionRouterFilterer struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// SessionRouterSession is an auto generated Go binding around an Ethereum contract, +// with pre-set call and transact options. +type SessionRouterSession struct { + Contract *SessionRouter // Generic contract binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// SessionRouterCallerSession is an auto generated read-only Go binding around an Ethereum contract, +// with pre-set call options. +type SessionRouterCallerSession struct { + Contract *SessionRouterCaller // Generic contract caller binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session +} + +// SessionRouterTransactorSession is an auto generated write-only Go binding around an Ethereum contract, +// with pre-set transact options. +type SessionRouterTransactorSession struct { + Contract *SessionRouterTransactor // Generic contract transactor binding to set the session for + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// SessionRouterRaw is an auto generated low-level Go binding around an Ethereum contract. +type SessionRouterRaw struct { + Contract *SessionRouter // Generic contract binding to access the raw methods on +} + +// SessionRouterCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. +type SessionRouterCallerRaw struct { + Contract *SessionRouterCaller // Generic read-only contract binding to access the raw methods on +} + +// SessionRouterTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. +type SessionRouterTransactorRaw struct { + Contract *SessionRouterTransactor // Generic write-only contract binding to access the raw methods on +} + +// NewSessionRouter creates a new instance of SessionRouter, bound to a specific deployed contract. +func NewSessionRouter(address common.Address, backend bind.ContractBackend) (*SessionRouter, error) { + contract, err := bindSessionRouter(address, backend, backend, backend) + if err != nil { + return nil, err + } + return &SessionRouter{SessionRouterCaller: SessionRouterCaller{contract: contract}, SessionRouterTransactor: SessionRouterTransactor{contract: contract}, SessionRouterFilterer: SessionRouterFilterer{contract: contract}}, nil +} + +// NewSessionRouterCaller creates a new read-only instance of SessionRouter, bound to a specific deployed contract. +func NewSessionRouterCaller(address common.Address, caller bind.ContractCaller) (*SessionRouterCaller, error) { + contract, err := bindSessionRouter(address, caller, nil, nil) + if err != nil { + return nil, err + } + return &SessionRouterCaller{contract: contract}, nil +} + +// NewSessionRouterTransactor creates a new write-only instance of SessionRouter, bound to a specific deployed contract. +func NewSessionRouterTransactor(address common.Address, transactor bind.ContractTransactor) (*SessionRouterTransactor, error) { + contract, err := bindSessionRouter(address, nil, transactor, nil) + if err != nil { + return nil, err + } + return &SessionRouterTransactor{contract: contract}, nil +} + +// NewSessionRouterFilterer creates a new log filterer instance of SessionRouter, bound to a specific deployed contract. +func NewSessionRouterFilterer(address common.Address, filterer bind.ContractFilterer) (*SessionRouterFilterer, error) { + contract, err := bindSessionRouter(address, nil, nil, filterer) + if err != nil { + return nil, err + } + return &SessionRouterFilterer{contract: contract}, nil +} + +// bindSessionRouter binds a generic wrapper to an already deployed contract. +func bindSessionRouter(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { + parsed, err := SessionRouterMetaData.GetAbi() + if err != nil { + return nil, err + } + return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_SessionRouter *SessionRouterRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _SessionRouter.Contract.SessionRouterCaller.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_SessionRouter *SessionRouterRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _SessionRouter.Contract.SessionRouterTransactor.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_SessionRouter *SessionRouterRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _SessionRouter.Contract.SessionRouterTransactor.contract.Transact(opts, method, params...) +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_SessionRouter *SessionRouterCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _SessionRouter.Contract.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_SessionRouter *SessionRouterTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _SessionRouter.Contract.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_SessionRouter *SessionRouterTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _SessionRouter.Contract.contract.Transact(opts, method, params...) +} + +// BIDSSTORAGESLOT is a free data retrieval call binding the contract method 0x266ccff0. +// +// Solidity: function BIDS_STORAGE_SLOT() view returns(bytes32) +func (_SessionRouter *SessionRouterCaller) BIDSSTORAGESLOT(opts *bind.CallOpts) ([32]byte, error) { + var out []interface{} + err := _SessionRouter.contract.Call(opts, &out, "BIDS_STORAGE_SLOT") + + if err != nil { + return *new([32]byte), err + } + + out0 := *abi.ConvertType(out[0], new([32]byte)).(*[32]byte) + + return out0, err + +} + +// BIDSSTORAGESLOT is a free data retrieval call binding the contract method 0x266ccff0. +// +// Solidity: function BIDS_STORAGE_SLOT() view returns(bytes32) +func (_SessionRouter *SessionRouterSession) BIDSSTORAGESLOT() ([32]byte, error) { + return _SessionRouter.Contract.BIDSSTORAGESLOT(&_SessionRouter.CallOpts) +} + +// BIDSSTORAGESLOT is a free data retrieval call binding the contract method 0x266ccff0. +// +// Solidity: function BIDS_STORAGE_SLOT() view returns(bytes32) +func (_SessionRouter *SessionRouterCallerSession) BIDSSTORAGESLOT() ([32]byte, error) { + return _SessionRouter.Contract.BIDSSTORAGESLOT(&_SessionRouter.CallOpts) +} + +// COMPUTEPOOLINDEX is a free data retrieval call binding the contract method 0xc56d09a0. +// +// Solidity: function COMPUTE_POOL_INDEX() view returns(uint256) +func (_SessionRouter *SessionRouterCaller) COMPUTEPOOLINDEX(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _SessionRouter.contract.Call(opts, &out, "COMPUTE_POOL_INDEX") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// COMPUTEPOOLINDEX is a free data retrieval call binding the contract method 0xc56d09a0. +// +// Solidity: function COMPUTE_POOL_INDEX() view returns(uint256) +func (_SessionRouter *SessionRouterSession) COMPUTEPOOLINDEX() (*big.Int, error) { + return _SessionRouter.Contract.COMPUTEPOOLINDEX(&_SessionRouter.CallOpts) +} + +// COMPUTEPOOLINDEX is a free data retrieval call binding the contract method 0xc56d09a0. +// +// Solidity: function COMPUTE_POOL_INDEX() view returns(uint256) +func (_SessionRouter *SessionRouterCallerSession) COMPUTEPOOLINDEX() (*big.Int, error) { + return _SessionRouter.Contract.COMPUTEPOOLINDEX(&_SessionRouter.CallOpts) +} + +// DELEGATIONRULESMARKETPLACE is a free data retrieval call binding the contract method 0xad34a150. +// +// Solidity: function DELEGATION_RULES_MARKETPLACE() view returns(bytes32) +func (_SessionRouter *SessionRouterCaller) DELEGATIONRULESMARKETPLACE(opts *bind.CallOpts) ([32]byte, error) { + var out []interface{} + err := _SessionRouter.contract.Call(opts, &out, "DELEGATION_RULES_MARKETPLACE") + + if err != nil { + return *new([32]byte), err + } + + out0 := *abi.ConvertType(out[0], new([32]byte)).(*[32]byte) + + return out0, err + +} + +// DELEGATIONRULESMARKETPLACE is a free data retrieval call binding the contract method 0xad34a150. +// +// Solidity: function DELEGATION_RULES_MARKETPLACE() view returns(bytes32) +func (_SessionRouter *SessionRouterSession) DELEGATIONRULESMARKETPLACE() ([32]byte, error) { + return _SessionRouter.Contract.DELEGATIONRULESMARKETPLACE(&_SessionRouter.CallOpts) +} + +// DELEGATIONRULESMARKETPLACE is a free data retrieval call binding the contract method 0xad34a150. +// +// Solidity: function DELEGATION_RULES_MARKETPLACE() view returns(bytes32) +func (_SessionRouter *SessionRouterCallerSession) DELEGATIONRULESMARKETPLACE() ([32]byte, error) { + return _SessionRouter.Contract.DELEGATIONRULESMARKETPLACE(&_SessionRouter.CallOpts) +} + +// DELEGATIONRULESMODEL is a free data retrieval call binding the contract method 0x86878047. +// +// Solidity: function DELEGATION_RULES_MODEL() view returns(bytes32) +func (_SessionRouter *SessionRouterCaller) DELEGATIONRULESMODEL(opts *bind.CallOpts) ([32]byte, error) { + var out []interface{} + err := _SessionRouter.contract.Call(opts, &out, "DELEGATION_RULES_MODEL") + + if err != nil { + return *new([32]byte), err + } + + out0 := *abi.ConvertType(out[0], new([32]byte)).(*[32]byte) + + return out0, err + +} + +// DELEGATIONRULESMODEL is a free data retrieval call binding the contract method 0x86878047. +// +// Solidity: function DELEGATION_RULES_MODEL() view returns(bytes32) +func (_SessionRouter *SessionRouterSession) DELEGATIONRULESMODEL() ([32]byte, error) { + return _SessionRouter.Contract.DELEGATIONRULESMODEL(&_SessionRouter.CallOpts) +} + +// DELEGATIONRULESMODEL is a free data retrieval call binding the contract method 0x86878047. +// +// Solidity: function DELEGATION_RULES_MODEL() view returns(bytes32) +func (_SessionRouter *SessionRouterCallerSession) DELEGATIONRULESMODEL() ([32]byte, error) { + return _SessionRouter.Contract.DELEGATIONRULESMODEL(&_SessionRouter.CallOpts) +} + +// DELEGATIONRULESPROVIDER is a free data retrieval call binding the contract method 0x58aeef93. +// +// Solidity: function DELEGATION_RULES_PROVIDER() view returns(bytes32) +func (_SessionRouter *SessionRouterCaller) DELEGATIONRULESPROVIDER(opts *bind.CallOpts) ([32]byte, error) { + var out []interface{} + err := _SessionRouter.contract.Call(opts, &out, "DELEGATION_RULES_PROVIDER") + + if err != nil { + return *new([32]byte), err + } + + out0 := *abi.ConvertType(out[0], new([32]byte)).(*[32]byte) + + return out0, err + +} + +// DELEGATIONRULESPROVIDER is a free data retrieval call binding the contract method 0x58aeef93. +// +// Solidity: function DELEGATION_RULES_PROVIDER() view returns(bytes32) +func (_SessionRouter *SessionRouterSession) DELEGATIONRULESPROVIDER() ([32]byte, error) { + return _SessionRouter.Contract.DELEGATIONRULESPROVIDER(&_SessionRouter.CallOpts) +} + +// DELEGATIONRULESPROVIDER is a free data retrieval call binding the contract method 0x58aeef93. +// +// Solidity: function DELEGATION_RULES_PROVIDER() view returns(bytes32) +func (_SessionRouter *SessionRouterCallerSession) DELEGATIONRULESPROVIDER() ([32]byte, error) { + return _SessionRouter.Contract.DELEGATIONRULESPROVIDER(&_SessionRouter.CallOpts) +} + +// DELEGATIONRULESSESSION is a free data retrieval call binding the contract method 0xd1b43638. +// +// Solidity: function DELEGATION_RULES_SESSION() view returns(bytes32) +func (_SessionRouter *SessionRouterCaller) DELEGATIONRULESSESSION(opts *bind.CallOpts) ([32]byte, error) { + var out []interface{} + err := _SessionRouter.contract.Call(opts, &out, "DELEGATION_RULES_SESSION") + + if err != nil { + return *new([32]byte), err + } + + out0 := *abi.ConvertType(out[0], new([32]byte)).(*[32]byte) + + return out0, err + +} + +// DELEGATIONRULESSESSION is a free data retrieval call binding the contract method 0xd1b43638. +// +// Solidity: function DELEGATION_RULES_SESSION() view returns(bytes32) +func (_SessionRouter *SessionRouterSession) DELEGATIONRULESSESSION() ([32]byte, error) { + return _SessionRouter.Contract.DELEGATIONRULESSESSION(&_SessionRouter.CallOpts) +} + +// DELEGATIONRULESSESSION is a free data retrieval call binding the contract method 0xd1b43638. +// +// Solidity: function DELEGATION_RULES_SESSION() view returns(bytes32) +func (_SessionRouter *SessionRouterCallerSession) DELEGATIONRULESSESSION() ([32]byte, error) { + return _SessionRouter.Contract.DELEGATIONRULESSESSION(&_SessionRouter.CallOpts) +} + +// DELEGATIONSTORAGESLOT is a free data retrieval call binding the contract method 0xdd9b48cb. +// +// Solidity: function DELEGATION_STORAGE_SLOT() view returns(bytes32) +func (_SessionRouter *SessionRouterCaller) DELEGATIONSTORAGESLOT(opts *bind.CallOpts) ([32]byte, error) { + var out []interface{} + err := _SessionRouter.contract.Call(opts, &out, "DELEGATION_STORAGE_SLOT") + + if err != nil { + return *new([32]byte), err + } + + out0 := *abi.ConvertType(out[0], new([32]byte)).(*[32]byte) + + return out0, err + +} + +// DELEGATIONSTORAGESLOT is a free data retrieval call binding the contract method 0xdd9b48cb. +// +// Solidity: function DELEGATION_STORAGE_SLOT() view returns(bytes32) +func (_SessionRouter *SessionRouterSession) DELEGATIONSTORAGESLOT() ([32]byte, error) { + return _SessionRouter.Contract.DELEGATIONSTORAGESLOT(&_SessionRouter.CallOpts) +} + +// DELEGATIONSTORAGESLOT is a free data retrieval call binding the contract method 0xdd9b48cb. +// +// Solidity: function DELEGATION_STORAGE_SLOT() view returns(bytes32) +func (_SessionRouter *SessionRouterCallerSession) DELEGATIONSTORAGESLOT() ([32]byte, error) { + return _SessionRouter.Contract.DELEGATIONSTORAGESLOT(&_SessionRouter.CallOpts) +} + +// DIAMONDOWNABLESTORAGESLOT is a free data retrieval call binding the contract method 0x4ac3371e. +// +// Solidity: function DIAMOND_OWNABLE_STORAGE_SLOT() view returns(bytes32) +func (_SessionRouter *SessionRouterCaller) DIAMONDOWNABLESTORAGESLOT(opts *bind.CallOpts) ([32]byte, error) { + var out []interface{} + err := _SessionRouter.contract.Call(opts, &out, "DIAMOND_OWNABLE_STORAGE_SLOT") + + if err != nil { + return *new([32]byte), err + } + + out0 := *abi.ConvertType(out[0], new([32]byte)).(*[32]byte) + + return out0, err + +} + +// DIAMONDOWNABLESTORAGESLOT is a free data retrieval call binding the contract method 0x4ac3371e. +// +// Solidity: function DIAMOND_OWNABLE_STORAGE_SLOT() view returns(bytes32) +func (_SessionRouter *SessionRouterSession) DIAMONDOWNABLESTORAGESLOT() ([32]byte, error) { + return _SessionRouter.Contract.DIAMONDOWNABLESTORAGESLOT(&_SessionRouter.CallOpts) +} + +// DIAMONDOWNABLESTORAGESLOT is a free data retrieval call binding the contract method 0x4ac3371e. +// +// Solidity: function DIAMOND_OWNABLE_STORAGE_SLOT() view returns(bytes32) +func (_SessionRouter *SessionRouterCallerSession) DIAMONDOWNABLESTORAGESLOT() ([32]byte, error) { + return _SessionRouter.Contract.DIAMONDOWNABLESTORAGESLOT(&_SessionRouter.CallOpts) +} + +// MINSESSIONDURATION is a free data retrieval call binding the contract method 0x7d980286. +// +// Solidity: function MIN_SESSION_DURATION() view returns(uint32) +func (_SessionRouter *SessionRouterCaller) MINSESSIONDURATION(opts *bind.CallOpts) (uint32, error) { + var out []interface{} + err := _SessionRouter.contract.Call(opts, &out, "MIN_SESSION_DURATION") + + if err != nil { + return *new(uint32), err + } + + out0 := *abi.ConvertType(out[0], new(uint32)).(*uint32) + + return out0, err + +} + +// MINSESSIONDURATION is a free data retrieval call binding the contract method 0x7d980286. +// +// Solidity: function MIN_SESSION_DURATION() view returns(uint32) +func (_SessionRouter *SessionRouterSession) MINSESSIONDURATION() (uint32, error) { + return _SessionRouter.Contract.MINSESSIONDURATION(&_SessionRouter.CallOpts) +} + +// MINSESSIONDURATION is a free data retrieval call binding the contract method 0x7d980286. +// +// Solidity: function MIN_SESSION_DURATION() view returns(uint32) +func (_SessionRouter *SessionRouterCallerSession) MINSESSIONDURATION() (uint32, error) { + return _SessionRouter.Contract.MINSESSIONDURATION(&_SessionRouter.CallOpts) +} + +// PROVIDERSSTORAGESLOT is a free data retrieval call binding the contract method 0xc51830f6. +// +// Solidity: function PROVIDERS_STORAGE_SLOT() view returns(bytes32) +func (_SessionRouter *SessionRouterCaller) PROVIDERSSTORAGESLOT(opts *bind.CallOpts) ([32]byte, error) { + var out []interface{} + err := _SessionRouter.contract.Call(opts, &out, "PROVIDERS_STORAGE_SLOT") + + if err != nil { + return *new([32]byte), err + } + + out0 := *abi.ConvertType(out[0], new([32]byte)).(*[32]byte) + + return out0, err + +} + +// PROVIDERSSTORAGESLOT is a free data retrieval call binding the contract method 0xc51830f6. +// +// Solidity: function PROVIDERS_STORAGE_SLOT() view returns(bytes32) +func (_SessionRouter *SessionRouterSession) PROVIDERSSTORAGESLOT() ([32]byte, error) { + return _SessionRouter.Contract.PROVIDERSSTORAGESLOT(&_SessionRouter.CallOpts) +} + +// PROVIDERSSTORAGESLOT is a free data retrieval call binding the contract method 0xc51830f6. +// +// Solidity: function PROVIDERS_STORAGE_SLOT() view returns(bytes32) +func (_SessionRouter *SessionRouterCallerSession) PROVIDERSSTORAGESLOT() ([32]byte, error) { + return _SessionRouter.Contract.PROVIDERSSTORAGESLOT(&_SessionRouter.CallOpts) +} + +// SESSIONSSTORAGESLOT is a free data retrieval call binding the contract method 0xb392636e. +// +// Solidity: function SESSIONS_STORAGE_SLOT() view returns(bytes32) +func (_SessionRouter *SessionRouterCaller) SESSIONSSTORAGESLOT(opts *bind.CallOpts) ([32]byte, error) { + var out []interface{} + err := _SessionRouter.contract.Call(opts, &out, "SESSIONS_STORAGE_SLOT") + + if err != nil { + return *new([32]byte), err + } + + out0 := *abi.ConvertType(out[0], new([32]byte)).(*[32]byte) + + return out0, err + +} + +// SESSIONSSTORAGESLOT is a free data retrieval call binding the contract method 0xb392636e. +// +// Solidity: function SESSIONS_STORAGE_SLOT() view returns(bytes32) +func (_SessionRouter *SessionRouterSession) SESSIONSSTORAGESLOT() ([32]byte, error) { + return _SessionRouter.Contract.SESSIONSSTORAGESLOT(&_SessionRouter.CallOpts) +} + +// SESSIONSSTORAGESLOT is a free data retrieval call binding the contract method 0xb392636e. +// +// Solidity: function SESSIONS_STORAGE_SLOT() view returns(bytes32) +func (_SessionRouter *SessionRouterCallerSession) SESSIONSSTORAGESLOT() ([32]byte, error) { + return _SessionRouter.Contract.SESSIONSSTORAGESLOT(&_SessionRouter.CallOpts) +} + +// SIGNATURETTL is a free data retrieval call binding the contract method 0xe7d791d0. +// +// Solidity: function SIGNATURE_TTL() view returns(uint32) +func (_SessionRouter *SessionRouterCaller) SIGNATURETTL(opts *bind.CallOpts) (uint32, error) { + var out []interface{} + err := _SessionRouter.contract.Call(opts, &out, "SIGNATURE_TTL") + + if err != nil { + return *new(uint32), err + } + + out0 := *abi.ConvertType(out[0], new(uint32)).(*uint32) + + return out0, err + +} + +// SIGNATURETTL is a free data retrieval call binding the contract method 0xe7d791d0. +// +// Solidity: function SIGNATURE_TTL() view returns(uint32) +func (_SessionRouter *SessionRouterSession) SIGNATURETTL() (uint32, error) { + return _SessionRouter.Contract.SIGNATURETTL(&_SessionRouter.CallOpts) +} + +// SIGNATURETTL is a free data retrieval call binding the contract method 0xe7d791d0. +// +// Solidity: function SIGNATURE_TTL() view returns(uint32) +func (_SessionRouter *SessionRouterCallerSession) SIGNATURETTL() (uint32, error) { + return _SessionRouter.Contract.SIGNATURETTL(&_SessionRouter.CallOpts) +} + +// STATSSTORAGESLOT is a free data retrieval call binding the contract method 0x87040789. +// +// Solidity: function STATS_STORAGE_SLOT() view returns(bytes32) +func (_SessionRouter *SessionRouterCaller) STATSSTORAGESLOT(opts *bind.CallOpts) ([32]byte, error) { + var out []interface{} + err := _SessionRouter.contract.Call(opts, &out, "STATS_STORAGE_SLOT") + + if err != nil { + return *new([32]byte), err + } + + out0 := *abi.ConvertType(out[0], new([32]byte)).(*[32]byte) + + return out0, err + +} + +// STATSSTORAGESLOT is a free data retrieval call binding the contract method 0x87040789. +// +// Solidity: function STATS_STORAGE_SLOT() view returns(bytes32) +func (_SessionRouter *SessionRouterSession) STATSSTORAGESLOT() ([32]byte, error) { + return _SessionRouter.Contract.STATSSTORAGESLOT(&_SessionRouter.CallOpts) +} + +// STATSSTORAGESLOT is a free data retrieval call binding the contract method 0x87040789. +// +// Solidity: function STATS_STORAGE_SLOT() view returns(bytes32) +func (_SessionRouter *SessionRouterCallerSession) STATSSTORAGESLOT() ([32]byte, error) { + return _SessionRouter.Contract.STATSSTORAGESLOT(&_SessionRouter.CallOpts) +} + +// GetActiveProviders is a free data retrieval call binding the contract method 0xd5472642. +// +// Solidity: function getActiveProviders(uint256 offset_, uint256 limit_) view returns(address[], uint256) +func (_SessionRouter *SessionRouterCaller) GetActiveProviders(opts *bind.CallOpts, offset_ *big.Int, limit_ *big.Int) ([]common.Address, *big.Int, error) { + var out []interface{} + err := _SessionRouter.contract.Call(opts, &out, "getActiveProviders", offset_, limit_) + + if err != nil { + return *new([]common.Address), *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new([]common.Address)).(*[]common.Address) + out1 := *abi.ConvertType(out[1], new(*big.Int)).(**big.Int) + + return out0, out1, err + +} + +// GetActiveProviders is a free data retrieval call binding the contract method 0xd5472642. +// +// Solidity: function getActiveProviders(uint256 offset_, uint256 limit_) view returns(address[], uint256) +func (_SessionRouter *SessionRouterSession) GetActiveProviders(offset_ *big.Int, limit_ *big.Int) ([]common.Address, *big.Int, error) { + return _SessionRouter.Contract.GetActiveProviders(&_SessionRouter.CallOpts, offset_, limit_) +} + +// GetActiveProviders is a free data retrieval call binding the contract method 0xd5472642. +// +// Solidity: function getActiveProviders(uint256 offset_, uint256 limit_) view returns(address[], uint256) +func (_SessionRouter *SessionRouterCallerSession) GetActiveProviders(offset_ *big.Int, limit_ *big.Int) ([]common.Address, *big.Int, error) { + return _SessionRouter.Contract.GetActiveProviders(&_SessionRouter.CallOpts, offset_, limit_) +} + +// GetBid is a free data retrieval call binding the contract method 0x91704e1e. +// +// Solidity: function getBid(bytes32 bidId_) view returns((address,bytes32,uint256,uint256,uint128,uint128)) +func (_SessionRouter *SessionRouterCaller) GetBid(opts *bind.CallOpts, bidId_ [32]byte) (IBidStorageBid, error) { + var out []interface{} + err := _SessionRouter.contract.Call(opts, &out, "getBid", bidId_) + + if err != nil { + return *new(IBidStorageBid), err + } + + out0 := *abi.ConvertType(out[0], new(IBidStorageBid)).(*IBidStorageBid) + + return out0, err + +} + +// GetBid is a free data retrieval call binding the contract method 0x91704e1e. +// +// Solidity: function getBid(bytes32 bidId_) view returns((address,bytes32,uint256,uint256,uint128,uint128)) +func (_SessionRouter *SessionRouterSession) GetBid(bidId_ [32]byte) (IBidStorageBid, error) { + return _SessionRouter.Contract.GetBid(&_SessionRouter.CallOpts, bidId_) +} + +// GetBid is a free data retrieval call binding the contract method 0x91704e1e. +// +// Solidity: function getBid(bytes32 bidId_) view returns((address,bytes32,uint256,uint256,uint128,uint128)) +func (_SessionRouter *SessionRouterCallerSession) GetBid(bidId_ [32]byte) (IBidStorageBid, error) { + return _SessionRouter.Contract.GetBid(&_SessionRouter.CallOpts, bidId_) +} + +// GetComputeBalance is a free data retrieval call binding the contract method 0x61ce471a. +// +// Solidity: function getComputeBalance(uint128 timestamp_) view returns(uint256) +func (_SessionRouter *SessionRouterCaller) GetComputeBalance(opts *bind.CallOpts, timestamp_ *big.Int) (*big.Int, error) { + var out []interface{} + err := _SessionRouter.contract.Call(opts, &out, "getComputeBalance", timestamp_) + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// GetComputeBalance is a free data retrieval call binding the contract method 0x61ce471a. +// +// Solidity: function getComputeBalance(uint128 timestamp_) view returns(uint256) +func (_SessionRouter *SessionRouterSession) GetComputeBalance(timestamp_ *big.Int) (*big.Int, error) { + return _SessionRouter.Contract.GetComputeBalance(&_SessionRouter.CallOpts, timestamp_) +} + +// GetComputeBalance is a free data retrieval call binding the contract method 0x61ce471a. +// +// Solidity: function getComputeBalance(uint128 timestamp_) view returns(uint256) +func (_SessionRouter *SessionRouterCallerSession) GetComputeBalance(timestamp_ *big.Int) (*big.Int, error) { + return _SessionRouter.Contract.GetComputeBalance(&_SessionRouter.CallOpts, timestamp_) +} + +// GetFundingAccount is a free data retrieval call binding the contract method 0x775c3727. +// +// Solidity: function getFundingAccount() view returns(address) +func (_SessionRouter *SessionRouterCaller) GetFundingAccount(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _SessionRouter.contract.Call(opts, &out, "getFundingAccount") + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +// GetFundingAccount is a free data retrieval call binding the contract method 0x775c3727. +// +// Solidity: function getFundingAccount() view returns(address) +func (_SessionRouter *SessionRouterSession) GetFundingAccount() (common.Address, error) { + return _SessionRouter.Contract.GetFundingAccount(&_SessionRouter.CallOpts) +} + +// GetFundingAccount is a free data retrieval call binding the contract method 0x775c3727. +// +// Solidity: function getFundingAccount() view returns(address) +func (_SessionRouter *SessionRouterCallerSession) GetFundingAccount() (common.Address, error) { + return _SessionRouter.Contract.GetFundingAccount(&_SessionRouter.CallOpts) +} + +// GetIsProviderActive is a free data retrieval call binding the contract method 0x63ef175d. +// +// Solidity: function getIsProviderActive(address provider_) view returns(bool) +func (_SessionRouter *SessionRouterCaller) GetIsProviderActive(opts *bind.CallOpts, provider_ common.Address) (bool, error) { + var out []interface{} + err := _SessionRouter.contract.Call(opts, &out, "getIsProviderActive", provider_) + + if err != nil { + return *new(bool), err + } + + out0 := *abi.ConvertType(out[0], new(bool)).(*bool) + + return out0, err + +} + +// GetIsProviderActive is a free data retrieval call binding the contract method 0x63ef175d. +// +// Solidity: function getIsProviderActive(address provider_) view returns(bool) +func (_SessionRouter *SessionRouterSession) GetIsProviderActive(provider_ common.Address) (bool, error) { + return _SessionRouter.Contract.GetIsProviderActive(&_SessionRouter.CallOpts, provider_) +} + +// GetIsProviderActive is a free data retrieval call binding the contract method 0x63ef175d. +// +// Solidity: function getIsProviderActive(address provider_) view returns(bool) +func (_SessionRouter *SessionRouterCallerSession) GetIsProviderActive(provider_ common.Address) (bool, error) { + return _SessionRouter.Contract.GetIsProviderActive(&_SessionRouter.CallOpts, provider_) +} + +// GetIsProviderApprovalUsed is a free data retrieval call binding the contract method 0xdb1cf1e2. +// +// Solidity: function getIsProviderApprovalUsed(bytes approval_) view returns(bool) +func (_SessionRouter *SessionRouterCaller) GetIsProviderApprovalUsed(opts *bind.CallOpts, approval_ []byte) (bool, error) { + var out []interface{} + err := _SessionRouter.contract.Call(opts, &out, "getIsProviderApprovalUsed", approval_) + + if err != nil { + return *new(bool), err + } + + out0 := *abi.ConvertType(out[0], new(bool)).(*bool) + + return out0, err + +} + +// GetIsProviderApprovalUsed is a free data retrieval call binding the contract method 0xdb1cf1e2. +// +// Solidity: function getIsProviderApprovalUsed(bytes approval_) view returns(bool) +func (_SessionRouter *SessionRouterSession) GetIsProviderApprovalUsed(approval_ []byte) (bool, error) { + return _SessionRouter.Contract.GetIsProviderApprovalUsed(&_SessionRouter.CallOpts, approval_) +} + +// GetIsProviderApprovalUsed is a free data retrieval call binding the contract method 0xdb1cf1e2. +// +// Solidity: function getIsProviderApprovalUsed(bytes approval_) view returns(bool) +func (_SessionRouter *SessionRouterCallerSession) GetIsProviderApprovalUsed(approval_ []byte) (bool, error) { + return _SessionRouter.Contract.GetIsProviderApprovalUsed(&_SessionRouter.CallOpts, approval_) +} + +// GetMaxSessionDuration is a free data retrieval call binding the contract method 0xa9756858. +// +// Solidity: function getMaxSessionDuration() view returns(uint128) +func (_SessionRouter *SessionRouterCaller) GetMaxSessionDuration(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _SessionRouter.contract.Call(opts, &out, "getMaxSessionDuration") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// GetMaxSessionDuration is a free data retrieval call binding the contract method 0xa9756858. +// +// Solidity: function getMaxSessionDuration() view returns(uint128) +func (_SessionRouter *SessionRouterSession) GetMaxSessionDuration() (*big.Int, error) { + return _SessionRouter.Contract.GetMaxSessionDuration(&_SessionRouter.CallOpts) +} + +// GetMaxSessionDuration is a free data retrieval call binding the contract method 0xa9756858. +// +// Solidity: function getMaxSessionDuration() view returns(uint128) +func (_SessionRouter *SessionRouterCallerSession) GetMaxSessionDuration() (*big.Int, error) { + return _SessionRouter.Contract.GetMaxSessionDuration(&_SessionRouter.CallOpts) +} + +// GetModelActiveBids is a free data retrieval call binding the contract method 0x8a683b6e. +// +// Solidity: function getModelActiveBids(bytes32 modelId_, uint256 offset_, uint256 limit_) view returns(bytes32[], uint256) +func (_SessionRouter *SessionRouterCaller) GetModelActiveBids(opts *bind.CallOpts, modelId_ [32]byte, offset_ *big.Int, limit_ *big.Int) ([][32]byte, *big.Int, error) { + var out []interface{} + err := _SessionRouter.contract.Call(opts, &out, "getModelActiveBids", modelId_, offset_, limit_) + + if err != nil { + return *new([][32]byte), *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new([][32]byte)).(*[][32]byte) + out1 := *abi.ConvertType(out[1], new(*big.Int)).(**big.Int) + + return out0, out1, err + +} + +// GetModelActiveBids is a free data retrieval call binding the contract method 0x8a683b6e. +// +// Solidity: function getModelActiveBids(bytes32 modelId_, uint256 offset_, uint256 limit_) view returns(bytes32[], uint256) +func (_SessionRouter *SessionRouterSession) GetModelActiveBids(modelId_ [32]byte, offset_ *big.Int, limit_ *big.Int) ([][32]byte, *big.Int, error) { + return _SessionRouter.Contract.GetModelActiveBids(&_SessionRouter.CallOpts, modelId_, offset_, limit_) +} + +// GetModelActiveBids is a free data retrieval call binding the contract method 0x8a683b6e. +// +// Solidity: function getModelActiveBids(bytes32 modelId_, uint256 offset_, uint256 limit_) view returns(bytes32[], uint256) +func (_SessionRouter *SessionRouterCallerSession) GetModelActiveBids(modelId_ [32]byte, offset_ *big.Int, limit_ *big.Int) ([][32]byte, *big.Int, error) { + return _SessionRouter.Contract.GetModelActiveBids(&_SessionRouter.CallOpts, modelId_, offset_, limit_) +} + +// GetModelBids is a free data retrieval call binding the contract method 0xfade17b1. +// +// Solidity: function getModelBids(bytes32 modelId_, uint256 offset_, uint256 limit_) view returns(bytes32[], uint256) +func (_SessionRouter *SessionRouterCaller) GetModelBids(opts *bind.CallOpts, modelId_ [32]byte, offset_ *big.Int, limit_ *big.Int) ([][32]byte, *big.Int, error) { + var out []interface{} + err := _SessionRouter.contract.Call(opts, &out, "getModelBids", modelId_, offset_, limit_) + + if err != nil { + return *new([][32]byte), *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new([][32]byte)).(*[][32]byte) + out1 := *abi.ConvertType(out[1], new(*big.Int)).(**big.Int) + + return out0, out1, err + +} + +// GetModelBids is a free data retrieval call binding the contract method 0xfade17b1. +// +// Solidity: function getModelBids(bytes32 modelId_, uint256 offset_, uint256 limit_) view returns(bytes32[], uint256) +func (_SessionRouter *SessionRouterSession) GetModelBids(modelId_ [32]byte, offset_ *big.Int, limit_ *big.Int) ([][32]byte, *big.Int, error) { + return _SessionRouter.Contract.GetModelBids(&_SessionRouter.CallOpts, modelId_, offset_, limit_) +} + +// GetModelBids is a free data retrieval call binding the contract method 0xfade17b1. +// +// Solidity: function getModelBids(bytes32 modelId_, uint256 offset_, uint256 limit_) view returns(bytes32[], uint256) +func (_SessionRouter *SessionRouterCallerSession) GetModelBids(modelId_ [32]byte, offset_ *big.Int, limit_ *big.Int) ([][32]byte, *big.Int, error) { + return _SessionRouter.Contract.GetModelBids(&_SessionRouter.CallOpts, modelId_, offset_, limit_) +} + +// GetModelSessions is a free data retrieval call binding the contract method 0x1d78a872. +// +// Solidity: function getModelSessions(bytes32 modelId_, uint256 offset_, uint256 limit_) view returns(bytes32[], uint256) +func (_SessionRouter *SessionRouterCaller) GetModelSessions(opts *bind.CallOpts, modelId_ [32]byte, offset_ *big.Int, limit_ *big.Int) ([][32]byte, *big.Int, error) { + var out []interface{} + err := _SessionRouter.contract.Call(opts, &out, "getModelSessions", modelId_, offset_, limit_) + + if err != nil { + return *new([][32]byte), *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new([][32]byte)).(*[][32]byte) + out1 := *abi.ConvertType(out[1], new(*big.Int)).(**big.Int) + + return out0, out1, err + +} + +// GetModelSessions is a free data retrieval call binding the contract method 0x1d78a872. +// +// Solidity: function getModelSessions(bytes32 modelId_, uint256 offset_, uint256 limit_) view returns(bytes32[], uint256) +func (_SessionRouter *SessionRouterSession) GetModelSessions(modelId_ [32]byte, offset_ *big.Int, limit_ *big.Int) ([][32]byte, *big.Int, error) { + return _SessionRouter.Contract.GetModelSessions(&_SessionRouter.CallOpts, modelId_, offset_, limit_) +} + +// GetModelSessions is a free data retrieval call binding the contract method 0x1d78a872. +// +// Solidity: function getModelSessions(bytes32 modelId_, uint256 offset_, uint256 limit_) view returns(bytes32[], uint256) +func (_SessionRouter *SessionRouterCallerSession) GetModelSessions(modelId_ [32]byte, offset_ *big.Int, limit_ *big.Int) ([][32]byte, *big.Int, error) { + return _SessionRouter.Contract.GetModelSessions(&_SessionRouter.CallOpts, modelId_, offset_, limit_) +} + +// GetModelStats is a free data retrieval call binding the contract method 0xce535723. +// +// Solidity: function getModelStats(bytes32 modelId_) view returns(((int64,int64),(int64,int64),(int64,int64),uint32)) +func (_SessionRouter *SessionRouterCaller) GetModelStats(opts *bind.CallOpts, modelId_ [32]byte) (IStatsStorageModelStats, error) { + var out []interface{} + err := _SessionRouter.contract.Call(opts, &out, "getModelStats", modelId_) + + if err != nil { + return *new(IStatsStorageModelStats), err + } + + out0 := *abi.ConvertType(out[0], new(IStatsStorageModelStats)).(*IStatsStorageModelStats) + + return out0, err + +} + +// GetModelStats is a free data retrieval call binding the contract method 0xce535723. +// +// Solidity: function getModelStats(bytes32 modelId_) view returns(((int64,int64),(int64,int64),(int64,int64),uint32)) +func (_SessionRouter *SessionRouterSession) GetModelStats(modelId_ [32]byte) (IStatsStorageModelStats, error) { + return _SessionRouter.Contract.GetModelStats(&_SessionRouter.CallOpts, modelId_) +} + +// GetModelStats is a free data retrieval call binding the contract method 0xce535723. +// +// Solidity: function getModelStats(bytes32 modelId_) view returns(((int64,int64),(int64,int64),(int64,int64),uint32)) +func (_SessionRouter *SessionRouterCallerSession) GetModelStats(modelId_ [32]byte) (IStatsStorageModelStats, error) { + return _SessionRouter.Contract.GetModelStats(&_SessionRouter.CallOpts, modelId_) +} + +// GetPool is a free data retrieval call binding the contract method 0x068bcd8d. +// +// Solidity: function getPool(uint256 index_) view returns((uint256,uint256,uint128,uint128)) +func (_SessionRouter *SessionRouterCaller) GetPool(opts *bind.CallOpts, index_ *big.Int) (ISessionStoragePool, error) { + var out []interface{} + err := _SessionRouter.contract.Call(opts, &out, "getPool", index_) + + if err != nil { + return *new(ISessionStoragePool), err + } + + out0 := *abi.ConvertType(out[0], new(ISessionStoragePool)).(*ISessionStoragePool) + + return out0, err + +} + +// GetPool is a free data retrieval call binding the contract method 0x068bcd8d. +// +// Solidity: function getPool(uint256 index_) view returns((uint256,uint256,uint128,uint128)) +func (_SessionRouter *SessionRouterSession) GetPool(index_ *big.Int) (ISessionStoragePool, error) { + return _SessionRouter.Contract.GetPool(&_SessionRouter.CallOpts, index_) +} + +// GetPool is a free data retrieval call binding the contract method 0x068bcd8d. +// +// Solidity: function getPool(uint256 index_) view returns((uint256,uint256,uint128,uint128)) +func (_SessionRouter *SessionRouterCallerSession) GetPool(index_ *big.Int) (ISessionStoragePool, error) { + return _SessionRouter.Contract.GetPool(&_SessionRouter.CallOpts, index_) +} + +// GetPools is a free data retrieval call binding the contract method 0x673a2a1f. +// +// Solidity: function getPools() view returns((uint256,uint256,uint128,uint128)[]) +func (_SessionRouter *SessionRouterCaller) GetPools(opts *bind.CallOpts) ([]ISessionStoragePool, error) { + var out []interface{} + err := _SessionRouter.contract.Call(opts, &out, "getPools") + + if err != nil { + return *new([]ISessionStoragePool), err + } + + out0 := *abi.ConvertType(out[0], new([]ISessionStoragePool)).(*[]ISessionStoragePool) + + return out0, err + +} + +// GetPools is a free data retrieval call binding the contract method 0x673a2a1f. +// +// Solidity: function getPools() view returns((uint256,uint256,uint128,uint128)[]) +func (_SessionRouter *SessionRouterSession) GetPools() ([]ISessionStoragePool, error) { + return _SessionRouter.Contract.GetPools(&_SessionRouter.CallOpts) +} + +// GetPools is a free data retrieval call binding the contract method 0x673a2a1f. +// +// Solidity: function getPools() view returns((uint256,uint256,uint128,uint128)[]) +func (_SessionRouter *SessionRouterCallerSession) GetPools() ([]ISessionStoragePool, error) { + return _SessionRouter.Contract.GetPools(&_SessionRouter.CallOpts) +} + +// GetProvider is a free data retrieval call binding the contract method 0x55f21eb7. +// +// Solidity: function getProvider(address provider_) view returns((string,uint256,uint128,uint128,uint256,bool)) +func (_SessionRouter *SessionRouterCaller) GetProvider(opts *bind.CallOpts, provider_ common.Address) (IProviderStorageProvider, error) { + var out []interface{} + err := _SessionRouter.contract.Call(opts, &out, "getProvider", provider_) + + if err != nil { + return *new(IProviderStorageProvider), err + } + + out0 := *abi.ConvertType(out[0], new(IProviderStorageProvider)).(*IProviderStorageProvider) + + return out0, err + +} + +// GetProvider is a free data retrieval call binding the contract method 0x55f21eb7. +// +// Solidity: function getProvider(address provider_) view returns((string,uint256,uint128,uint128,uint256,bool)) +func (_SessionRouter *SessionRouterSession) GetProvider(provider_ common.Address) (IProviderStorageProvider, error) { + return _SessionRouter.Contract.GetProvider(&_SessionRouter.CallOpts, provider_) +} + +// GetProvider is a free data retrieval call binding the contract method 0x55f21eb7. +// +// Solidity: function getProvider(address provider_) view returns((string,uint256,uint128,uint128,uint256,bool)) +func (_SessionRouter *SessionRouterCallerSession) GetProvider(provider_ common.Address) (IProviderStorageProvider, error) { + return _SessionRouter.Contract.GetProvider(&_SessionRouter.CallOpts, provider_) +} + +// GetProviderActiveBids is a free data retrieval call binding the contract method 0xaf5b77ca. +// +// Solidity: function getProviderActiveBids(address provider_, uint256 offset_, uint256 limit_) view returns(bytes32[], uint256) +func (_SessionRouter *SessionRouterCaller) GetProviderActiveBids(opts *bind.CallOpts, provider_ common.Address, offset_ *big.Int, limit_ *big.Int) ([][32]byte, *big.Int, error) { + var out []interface{} + err := _SessionRouter.contract.Call(opts, &out, "getProviderActiveBids", provider_, offset_, limit_) + + if err != nil { + return *new([][32]byte), *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new([][32]byte)).(*[][32]byte) + out1 := *abi.ConvertType(out[1], new(*big.Int)).(**big.Int) + + return out0, out1, err + +} + +// GetProviderActiveBids is a free data retrieval call binding the contract method 0xaf5b77ca. +// +// Solidity: function getProviderActiveBids(address provider_, uint256 offset_, uint256 limit_) view returns(bytes32[], uint256) +func (_SessionRouter *SessionRouterSession) GetProviderActiveBids(provider_ common.Address, offset_ *big.Int, limit_ *big.Int) ([][32]byte, *big.Int, error) { + return _SessionRouter.Contract.GetProviderActiveBids(&_SessionRouter.CallOpts, provider_, offset_, limit_) +} + +// GetProviderActiveBids is a free data retrieval call binding the contract method 0xaf5b77ca. +// +// Solidity: function getProviderActiveBids(address provider_, uint256 offset_, uint256 limit_) view returns(bytes32[], uint256) +func (_SessionRouter *SessionRouterCallerSession) GetProviderActiveBids(provider_ common.Address, offset_ *big.Int, limit_ *big.Int) ([][32]byte, *big.Int, error) { + return _SessionRouter.Contract.GetProviderActiveBids(&_SessionRouter.CallOpts, provider_, offset_, limit_) +} + +// GetProviderBids is a free data retrieval call binding the contract method 0x59d435c4. +// +// Solidity: function getProviderBids(address provider_, uint256 offset_, uint256 limit_) view returns(bytes32[], uint256) +func (_SessionRouter *SessionRouterCaller) GetProviderBids(opts *bind.CallOpts, provider_ common.Address, offset_ *big.Int, limit_ *big.Int) ([][32]byte, *big.Int, error) { + var out []interface{} + err := _SessionRouter.contract.Call(opts, &out, "getProviderBids", provider_, offset_, limit_) + + if err != nil { + return *new([][32]byte), *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new([][32]byte)).(*[][32]byte) + out1 := *abi.ConvertType(out[1], new(*big.Int)).(**big.Int) + + return out0, out1, err + +} + +// GetProviderBids is a free data retrieval call binding the contract method 0x59d435c4. +// +// Solidity: function getProviderBids(address provider_, uint256 offset_, uint256 limit_) view returns(bytes32[], uint256) +func (_SessionRouter *SessionRouterSession) GetProviderBids(provider_ common.Address, offset_ *big.Int, limit_ *big.Int) ([][32]byte, *big.Int, error) { + return _SessionRouter.Contract.GetProviderBids(&_SessionRouter.CallOpts, provider_, offset_, limit_) +} + +// GetProviderBids is a free data retrieval call binding the contract method 0x59d435c4. +// +// Solidity: function getProviderBids(address provider_, uint256 offset_, uint256 limit_) view returns(bytes32[], uint256) +func (_SessionRouter *SessionRouterCallerSession) GetProviderBids(provider_ common.Address, offset_ *big.Int, limit_ *big.Int) ([][32]byte, *big.Int, error) { + return _SessionRouter.Contract.GetProviderBids(&_SessionRouter.CallOpts, provider_, offset_, limit_) +} + +// GetProviderMinimumStake is a free data retrieval call binding the contract method 0x53c029f6. +// +// Solidity: function getProviderMinimumStake() view returns(uint256) +func (_SessionRouter *SessionRouterCaller) GetProviderMinimumStake(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _SessionRouter.contract.Call(opts, &out, "getProviderMinimumStake") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// GetProviderMinimumStake is a free data retrieval call binding the contract method 0x53c029f6. +// +// Solidity: function getProviderMinimumStake() view returns(uint256) +func (_SessionRouter *SessionRouterSession) GetProviderMinimumStake() (*big.Int, error) { + return _SessionRouter.Contract.GetProviderMinimumStake(&_SessionRouter.CallOpts) +} + +// GetProviderMinimumStake is a free data retrieval call binding the contract method 0x53c029f6. +// +// Solidity: function getProviderMinimumStake() view returns(uint256) +func (_SessionRouter *SessionRouterCallerSession) GetProviderMinimumStake() (*big.Int, error) { + return _SessionRouter.Contract.GetProviderMinimumStake(&_SessionRouter.CallOpts) +} + +// GetProviderModelStats is a free data retrieval call binding the contract method 0x1b26c116. +// +// Solidity: function getProviderModelStats(bytes32 modelId_, address provider_) view returns(((int64,int64),(int64,int64),uint32,uint32,uint32)) +func (_SessionRouter *SessionRouterCaller) GetProviderModelStats(opts *bind.CallOpts, modelId_ [32]byte, provider_ common.Address) (IStatsStorageProviderModelStats, error) { + var out []interface{} + err := _SessionRouter.contract.Call(opts, &out, "getProviderModelStats", modelId_, provider_) + + if err != nil { + return *new(IStatsStorageProviderModelStats), err + } + + out0 := *abi.ConvertType(out[0], new(IStatsStorageProviderModelStats)).(*IStatsStorageProviderModelStats) + + return out0, err + +} + +// GetProviderModelStats is a free data retrieval call binding the contract method 0x1b26c116. +// +// Solidity: function getProviderModelStats(bytes32 modelId_, address provider_) view returns(((int64,int64),(int64,int64),uint32,uint32,uint32)) +func (_SessionRouter *SessionRouterSession) GetProviderModelStats(modelId_ [32]byte, provider_ common.Address) (IStatsStorageProviderModelStats, error) { + return _SessionRouter.Contract.GetProviderModelStats(&_SessionRouter.CallOpts, modelId_, provider_) +} + +// GetProviderModelStats is a free data retrieval call binding the contract method 0x1b26c116. +// +// Solidity: function getProviderModelStats(bytes32 modelId_, address provider_) view returns(((int64,int64),(int64,int64),uint32,uint32,uint32)) +func (_SessionRouter *SessionRouterCallerSession) GetProviderModelStats(modelId_ [32]byte, provider_ common.Address) (IStatsStorageProviderModelStats, error) { + return _SessionRouter.Contract.GetProviderModelStats(&_SessionRouter.CallOpts, modelId_, provider_) +} + +// GetProviderSessions is a free data retrieval call binding the contract method 0x87bced7d. +// +// Solidity: function getProviderSessions(address provider_, uint256 offset_, uint256 limit_) view returns(bytes32[], uint256) +func (_SessionRouter *SessionRouterCaller) GetProviderSessions(opts *bind.CallOpts, provider_ common.Address, offset_ *big.Int, limit_ *big.Int) ([][32]byte, *big.Int, error) { + var out []interface{} + err := _SessionRouter.contract.Call(opts, &out, "getProviderSessions", provider_, offset_, limit_) + + if err != nil { + return *new([][32]byte), *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new([][32]byte)).(*[][32]byte) + out1 := *abi.ConvertType(out[1], new(*big.Int)).(**big.Int) + + return out0, out1, err + +} + +// GetProviderSessions is a free data retrieval call binding the contract method 0x87bced7d. +// +// Solidity: function getProviderSessions(address provider_, uint256 offset_, uint256 limit_) view returns(bytes32[], uint256) +func (_SessionRouter *SessionRouterSession) GetProviderSessions(provider_ common.Address, offset_ *big.Int, limit_ *big.Int) ([][32]byte, *big.Int, error) { + return _SessionRouter.Contract.GetProviderSessions(&_SessionRouter.CallOpts, provider_, offset_, limit_) +} + +// GetProviderSessions is a free data retrieval call binding the contract method 0x87bced7d. +// +// Solidity: function getProviderSessions(address provider_, uint256 offset_, uint256 limit_) view returns(bytes32[], uint256) +func (_SessionRouter *SessionRouterCallerSession) GetProviderSessions(provider_ common.Address, offset_ *big.Int, limit_ *big.Int) ([][32]byte, *big.Int, error) { + return _SessionRouter.Contract.GetProviderSessions(&_SessionRouter.CallOpts, provider_, offset_, limit_) +} + +// GetProvidersTotalClaimed is a free data retrieval call binding the contract method 0xbdfbbada. +// +// Solidity: function getProvidersTotalClaimed() view returns(uint256) +func (_SessionRouter *SessionRouterCaller) GetProvidersTotalClaimed(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _SessionRouter.contract.Call(opts, &out, "getProvidersTotalClaimed") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// GetProvidersTotalClaimed is a free data retrieval call binding the contract method 0xbdfbbada. +// +// Solidity: function getProvidersTotalClaimed() view returns(uint256) +func (_SessionRouter *SessionRouterSession) GetProvidersTotalClaimed() (*big.Int, error) { + return _SessionRouter.Contract.GetProvidersTotalClaimed(&_SessionRouter.CallOpts) +} + +// GetProvidersTotalClaimed is a free data retrieval call binding the contract method 0xbdfbbada. +// +// Solidity: function getProvidersTotalClaimed() view returns(uint256) +func (_SessionRouter *SessionRouterCallerSession) GetProvidersTotalClaimed() (*big.Int, error) { + return _SessionRouter.Contract.GetProvidersTotalClaimed(&_SessionRouter.CallOpts) +} + +// GetRegistry is a free data retrieval call binding the contract method 0x5ab1bd53. +// +// Solidity: function getRegistry() view returns(address) +func (_SessionRouter *SessionRouterCaller) GetRegistry(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _SessionRouter.contract.Call(opts, &out, "getRegistry") + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +// GetRegistry is a free data retrieval call binding the contract method 0x5ab1bd53. +// +// Solidity: function getRegistry() view returns(address) +func (_SessionRouter *SessionRouterSession) GetRegistry() (common.Address, error) { + return _SessionRouter.Contract.GetRegistry(&_SessionRouter.CallOpts) +} + +// GetRegistry is a free data retrieval call binding the contract method 0x5ab1bd53. +// +// Solidity: function getRegistry() view returns(address) +func (_SessionRouter *SessionRouterCallerSession) GetRegistry() (common.Address, error) { + return _SessionRouter.Contract.GetRegistry(&_SessionRouter.CallOpts) +} + +// GetSession is a free data retrieval call binding the contract method 0x39b240bd. +// +// Solidity: function getSession(bytes32 sessionId_) view returns((address,bytes32,uint256,bytes,uint256,uint256,uint128,uint128,uint128,bool,bool)) +func (_SessionRouter *SessionRouterCaller) GetSession(opts *bind.CallOpts, sessionId_ [32]byte) (ISessionStorageSession, error) { + var out []interface{} + err := _SessionRouter.contract.Call(opts, &out, "getSession", sessionId_) + + if err != nil { + return *new(ISessionStorageSession), err + } + + out0 := *abi.ConvertType(out[0], new(ISessionStorageSession)).(*ISessionStorageSession) + + return out0, err + +} + +// GetSession is a free data retrieval call binding the contract method 0x39b240bd. +// +// Solidity: function getSession(bytes32 sessionId_) view returns((address,bytes32,uint256,bytes,uint256,uint256,uint128,uint128,uint128,bool,bool)) +func (_SessionRouter *SessionRouterSession) GetSession(sessionId_ [32]byte) (ISessionStorageSession, error) { + return _SessionRouter.Contract.GetSession(&_SessionRouter.CallOpts, sessionId_) +} + +// GetSession is a free data retrieval call binding the contract method 0x39b240bd. +// +// Solidity: function getSession(bytes32 sessionId_) view returns((address,bytes32,uint256,bytes,uint256,uint256,uint128,uint128,uint128,bool,bool)) +func (_SessionRouter *SessionRouterCallerSession) GetSession(sessionId_ [32]byte) (ISessionStorageSession, error) { + return _SessionRouter.Contract.GetSession(&_SessionRouter.CallOpts, sessionId_) +} + +// GetSessionEnd is a free data retrieval call binding the contract method 0xb823dc8f. +// +// Solidity: function getSessionEnd(uint256 amount_, uint256 pricePerSecond_, uint128 openedAt_) view returns(uint128) +func (_SessionRouter *SessionRouterCaller) GetSessionEnd(opts *bind.CallOpts, amount_ *big.Int, pricePerSecond_ *big.Int, openedAt_ *big.Int) (*big.Int, error) { + var out []interface{} + err := _SessionRouter.contract.Call(opts, &out, "getSessionEnd", amount_, pricePerSecond_, openedAt_) + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// GetSessionEnd is a free data retrieval call binding the contract method 0xb823dc8f. +// +// Solidity: function getSessionEnd(uint256 amount_, uint256 pricePerSecond_, uint128 openedAt_) view returns(uint128) +func (_SessionRouter *SessionRouterSession) GetSessionEnd(amount_ *big.Int, pricePerSecond_ *big.Int, openedAt_ *big.Int) (*big.Int, error) { + return _SessionRouter.Contract.GetSessionEnd(&_SessionRouter.CallOpts, amount_, pricePerSecond_, openedAt_) +} + +// GetSessionEnd is a free data retrieval call binding the contract method 0xb823dc8f. +// +// Solidity: function getSessionEnd(uint256 amount_, uint256 pricePerSecond_, uint128 openedAt_) view returns(uint128) +func (_SessionRouter *SessionRouterCallerSession) GetSessionEnd(amount_ *big.Int, pricePerSecond_ *big.Int, openedAt_ *big.Int) (*big.Int, error) { + return _SessionRouter.Contract.GetSessionEnd(&_SessionRouter.CallOpts, amount_, pricePerSecond_, openedAt_) +} + +// GetSessionId is a free data retrieval call binding the contract method 0x4d689ffd. +// +// Solidity: function getSessionId(address user_, address provider_, bytes32 bidId_, uint256 sessionNonce_) pure returns(bytes32) +func (_SessionRouter *SessionRouterCaller) GetSessionId(opts *bind.CallOpts, user_ common.Address, provider_ common.Address, bidId_ [32]byte, sessionNonce_ *big.Int) ([32]byte, error) { + var out []interface{} + err := _SessionRouter.contract.Call(opts, &out, "getSessionId", user_, provider_, bidId_, sessionNonce_) + + if err != nil { + return *new([32]byte), err + } + + out0 := *abi.ConvertType(out[0], new([32]byte)).(*[32]byte) + + return out0, err + +} + +// GetSessionId is a free data retrieval call binding the contract method 0x4d689ffd. +// +// Solidity: function getSessionId(address user_, address provider_, bytes32 bidId_, uint256 sessionNonce_) pure returns(bytes32) +func (_SessionRouter *SessionRouterSession) GetSessionId(user_ common.Address, provider_ common.Address, bidId_ [32]byte, sessionNonce_ *big.Int) ([32]byte, error) { + return _SessionRouter.Contract.GetSessionId(&_SessionRouter.CallOpts, user_, provider_, bidId_, sessionNonce_) +} + +// GetSessionId is a free data retrieval call binding the contract method 0x4d689ffd. +// +// Solidity: function getSessionId(address user_, address provider_, bytes32 bidId_, uint256 sessionNonce_) pure returns(bytes32) +func (_SessionRouter *SessionRouterCallerSession) GetSessionId(user_ common.Address, provider_ common.Address, bidId_ [32]byte, sessionNonce_ *big.Int) ([32]byte, error) { + return _SessionRouter.Contract.GetSessionId(&_SessionRouter.CallOpts, user_, provider_, bidId_, sessionNonce_) +} + +// GetTodaysBudget is a free data retrieval call binding the contract method 0x40005965. +// +// Solidity: function getTodaysBudget(uint128 timestamp_) view returns(uint256) +func (_SessionRouter *SessionRouterCaller) GetTodaysBudget(opts *bind.CallOpts, timestamp_ *big.Int) (*big.Int, error) { + var out []interface{} + err := _SessionRouter.contract.Call(opts, &out, "getTodaysBudget", timestamp_) + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// GetTodaysBudget is a free data retrieval call binding the contract method 0x40005965. +// +// Solidity: function getTodaysBudget(uint128 timestamp_) view returns(uint256) +func (_SessionRouter *SessionRouterSession) GetTodaysBudget(timestamp_ *big.Int) (*big.Int, error) { + return _SessionRouter.Contract.GetTodaysBudget(&_SessionRouter.CallOpts, timestamp_) +} + +// GetTodaysBudget is a free data retrieval call binding the contract method 0x40005965. +// +// Solidity: function getTodaysBudget(uint128 timestamp_) view returns(uint256) +func (_SessionRouter *SessionRouterCallerSession) GetTodaysBudget(timestamp_ *big.Int) (*big.Int, error) { + return _SessionRouter.Contract.GetTodaysBudget(&_SessionRouter.CallOpts, timestamp_) +} + +// GetToken is a free data retrieval call binding the contract method 0x21df0da7. +// +// Solidity: function getToken() view returns(address) +func (_SessionRouter *SessionRouterCaller) GetToken(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _SessionRouter.contract.Call(opts, &out, "getToken") + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +// GetToken is a free data retrieval call binding the contract method 0x21df0da7. +// +// Solidity: function getToken() view returns(address) +func (_SessionRouter *SessionRouterSession) GetToken() (common.Address, error) { + return _SessionRouter.Contract.GetToken(&_SessionRouter.CallOpts) +} + +// GetToken is a free data retrieval call binding the contract method 0x21df0da7. +// +// Solidity: function getToken() view returns(address) +func (_SessionRouter *SessionRouterCallerSession) GetToken() (common.Address, error) { + return _SessionRouter.Contract.GetToken(&_SessionRouter.CallOpts) +} + +// GetTotalSessions is a free data retrieval call binding the contract method 0x76400935. +// +// Solidity: function getTotalSessions(address provider_) view returns(uint256) +func (_SessionRouter *SessionRouterCaller) GetTotalSessions(opts *bind.CallOpts, provider_ common.Address) (*big.Int, error) { + var out []interface{} + err := _SessionRouter.contract.Call(opts, &out, "getTotalSessions", provider_) + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// GetTotalSessions is a free data retrieval call binding the contract method 0x76400935. +// +// Solidity: function getTotalSessions(address provider_) view returns(uint256) +func (_SessionRouter *SessionRouterSession) GetTotalSessions(provider_ common.Address) (*big.Int, error) { + return _SessionRouter.Contract.GetTotalSessions(&_SessionRouter.CallOpts, provider_) +} + +// GetTotalSessions is a free data retrieval call binding the contract method 0x76400935. +// +// Solidity: function getTotalSessions(address provider_) view returns(uint256) +func (_SessionRouter *SessionRouterCallerSession) GetTotalSessions(provider_ common.Address) (*big.Int, error) { + return _SessionRouter.Contract.GetTotalSessions(&_SessionRouter.CallOpts, provider_) +} + +// GetUserSessions is a free data retrieval call binding the contract method 0xeb7764bb. +// +// Solidity: function getUserSessions(address user_, uint256 offset_, uint256 limit_) view returns(bytes32[], uint256) +func (_SessionRouter *SessionRouterCaller) GetUserSessions(opts *bind.CallOpts, user_ common.Address, offset_ *big.Int, limit_ *big.Int) ([][32]byte, *big.Int, error) { + var out []interface{} + err := _SessionRouter.contract.Call(opts, &out, "getUserSessions", user_, offset_, limit_) + + if err != nil { + return *new([][32]byte), *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new([][32]byte)).(*[][32]byte) + out1 := *abi.ConvertType(out[1], new(*big.Int)).(**big.Int) + + return out0, out1, err + +} + +// GetUserSessions is a free data retrieval call binding the contract method 0xeb7764bb. +// +// Solidity: function getUserSessions(address user_, uint256 offset_, uint256 limit_) view returns(bytes32[], uint256) +func (_SessionRouter *SessionRouterSession) GetUserSessions(user_ common.Address, offset_ *big.Int, limit_ *big.Int) ([][32]byte, *big.Int, error) { + return _SessionRouter.Contract.GetUserSessions(&_SessionRouter.CallOpts, user_, offset_, limit_) +} + +// GetUserSessions is a free data retrieval call binding the contract method 0xeb7764bb. +// +// Solidity: function getUserSessions(address user_, uint256 offset_, uint256 limit_) view returns(bytes32[], uint256) +func (_SessionRouter *SessionRouterCallerSession) GetUserSessions(user_ common.Address, offset_ *big.Int, limit_ *big.Int) ([][32]byte, *big.Int, error) { + return _SessionRouter.Contract.GetUserSessions(&_SessionRouter.CallOpts, user_, offset_, limit_) +} + +// GetUserStakesOnHold is a free data retrieval call binding the contract method 0x967885df. +// +// Solidity: function getUserStakesOnHold(address user_, uint8 iterations_) view returns(uint256 available_, uint256 hold_) +func (_SessionRouter *SessionRouterCaller) GetUserStakesOnHold(opts *bind.CallOpts, user_ common.Address, iterations_ uint8) (struct { + Available *big.Int + Hold *big.Int +}, error) { + var out []interface{} + err := _SessionRouter.contract.Call(opts, &out, "getUserStakesOnHold", user_, iterations_) + + outstruct := new(struct { + Available *big.Int + Hold *big.Int + }) + if err != nil { + return *outstruct, err + } + + outstruct.Available = *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + outstruct.Hold = *abi.ConvertType(out[1], new(*big.Int)).(**big.Int) + + return *outstruct, err + +} + +// GetUserStakesOnHold is a free data retrieval call binding the contract method 0x967885df. +// +// Solidity: function getUserStakesOnHold(address user_, uint8 iterations_) view returns(uint256 available_, uint256 hold_) +func (_SessionRouter *SessionRouterSession) GetUserStakesOnHold(user_ common.Address, iterations_ uint8) (struct { + Available *big.Int + Hold *big.Int +}, error) { + return _SessionRouter.Contract.GetUserStakesOnHold(&_SessionRouter.CallOpts, user_, iterations_) +} + +// GetUserStakesOnHold is a free data retrieval call binding the contract method 0x967885df. +// +// Solidity: function getUserStakesOnHold(address user_, uint8 iterations_) view returns(uint256 available_, uint256 hold_) +func (_SessionRouter *SessionRouterCallerSession) GetUserStakesOnHold(user_ common.Address, iterations_ uint8) (struct { + Available *big.Int + Hold *big.Int +}, error) { + return _SessionRouter.Contract.GetUserStakesOnHold(&_SessionRouter.CallOpts, user_, iterations_) +} + +// IsBidActive is a free data retrieval call binding the contract method 0x1345df58. +// +// Solidity: function isBidActive(bytes32 bidId_) view returns(bool) +func (_SessionRouter *SessionRouterCaller) IsBidActive(opts *bind.CallOpts, bidId_ [32]byte) (bool, error) { + var out []interface{} + err := _SessionRouter.contract.Call(opts, &out, "isBidActive", bidId_) + + if err != nil { + return *new(bool), err + } + + out0 := *abi.ConvertType(out[0], new(bool)).(*bool) + + return out0, err + +} + +// IsBidActive is a free data retrieval call binding the contract method 0x1345df58. +// +// Solidity: function isBidActive(bytes32 bidId_) view returns(bool) +func (_SessionRouter *SessionRouterSession) IsBidActive(bidId_ [32]byte) (bool, error) { + return _SessionRouter.Contract.IsBidActive(&_SessionRouter.CallOpts, bidId_) +} + +// IsBidActive is a free data retrieval call binding the contract method 0x1345df58. +// +// Solidity: function isBidActive(bytes32 bidId_) view returns(bool) +func (_SessionRouter *SessionRouterCallerSession) IsBidActive(bidId_ [32]byte) (bool, error) { + return _SessionRouter.Contract.IsBidActive(&_SessionRouter.CallOpts, bidId_) +} + +// IsRightsDelegated is a free data retrieval call binding the contract method 0x54126b8f. +// +// Solidity: function isRightsDelegated(address delegatee_, address delegator_, bytes32 rights_) view returns(bool) +func (_SessionRouter *SessionRouterCaller) IsRightsDelegated(opts *bind.CallOpts, delegatee_ common.Address, delegator_ common.Address, rights_ [32]byte) (bool, error) { + var out []interface{} + err := _SessionRouter.contract.Call(opts, &out, "isRightsDelegated", delegatee_, delegator_, rights_) + + if err != nil { + return *new(bool), err + } + + out0 := *abi.ConvertType(out[0], new(bool)).(*bool) + + return out0, err + +} + +// IsRightsDelegated is a free data retrieval call binding the contract method 0x54126b8f. +// +// Solidity: function isRightsDelegated(address delegatee_, address delegator_, bytes32 rights_) view returns(bool) +func (_SessionRouter *SessionRouterSession) IsRightsDelegated(delegatee_ common.Address, delegator_ common.Address, rights_ [32]byte) (bool, error) { + return _SessionRouter.Contract.IsRightsDelegated(&_SessionRouter.CallOpts, delegatee_, delegator_, rights_) +} + +// IsRightsDelegated is a free data retrieval call binding the contract method 0x54126b8f. +// +// Solidity: function isRightsDelegated(address delegatee_, address delegator_, bytes32 rights_) view returns(bool) +func (_SessionRouter *SessionRouterCallerSession) IsRightsDelegated(delegatee_ common.Address, delegator_ common.Address, rights_ [32]byte) (bool, error) { + return _SessionRouter.Contract.IsRightsDelegated(&_SessionRouter.CallOpts, delegatee_, delegator_, rights_) +} + +// Owner is a free data retrieval call binding the contract method 0x8da5cb5b. +// +// Solidity: function owner() view returns(address) +func (_SessionRouter *SessionRouterCaller) Owner(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _SessionRouter.contract.Call(opts, &out, "owner") + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +// Owner is a free data retrieval call binding the contract method 0x8da5cb5b. +// +// Solidity: function owner() view returns(address) +func (_SessionRouter *SessionRouterSession) Owner() (common.Address, error) { + return _SessionRouter.Contract.Owner(&_SessionRouter.CallOpts) +} + +// Owner is a free data retrieval call binding the contract method 0x8da5cb5b. +// +// Solidity: function owner() view returns(address) +func (_SessionRouter *SessionRouterCallerSession) Owner() (common.Address, error) { + return _SessionRouter.Contract.Owner(&_SessionRouter.CallOpts) +} + +// StakeToStipend is a free data retrieval call binding the contract method 0xb3cb0d0f. +// +// Solidity: function stakeToStipend(uint256 amount_, uint128 timestamp_) view returns(uint256) +func (_SessionRouter *SessionRouterCaller) StakeToStipend(opts *bind.CallOpts, amount_ *big.Int, timestamp_ *big.Int) (*big.Int, error) { + var out []interface{} + err := _SessionRouter.contract.Call(opts, &out, "stakeToStipend", amount_, timestamp_) + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// StakeToStipend is a free data retrieval call binding the contract method 0xb3cb0d0f. +// +// Solidity: function stakeToStipend(uint256 amount_, uint128 timestamp_) view returns(uint256) +func (_SessionRouter *SessionRouterSession) StakeToStipend(amount_ *big.Int, timestamp_ *big.Int) (*big.Int, error) { + return _SessionRouter.Contract.StakeToStipend(&_SessionRouter.CallOpts, amount_, timestamp_) +} + +// StakeToStipend is a free data retrieval call binding the contract method 0xb3cb0d0f. +// +// Solidity: function stakeToStipend(uint256 amount_, uint128 timestamp_) view returns(uint256) +func (_SessionRouter *SessionRouterCallerSession) StakeToStipend(amount_ *big.Int, timestamp_ *big.Int) (*big.Int, error) { + return _SessionRouter.Contract.StakeToStipend(&_SessionRouter.CallOpts, amount_, timestamp_) +} + +// StartOfTheDay is a free data retrieval call binding the contract method 0xba26588c. +// +// Solidity: function startOfTheDay(uint128 timestamp_) pure returns(uint128) +func (_SessionRouter *SessionRouterCaller) StartOfTheDay(opts *bind.CallOpts, timestamp_ *big.Int) (*big.Int, error) { + var out []interface{} + err := _SessionRouter.contract.Call(opts, &out, "startOfTheDay", timestamp_) + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// StartOfTheDay is a free data retrieval call binding the contract method 0xba26588c. +// +// Solidity: function startOfTheDay(uint128 timestamp_) pure returns(uint128) +func (_SessionRouter *SessionRouterSession) StartOfTheDay(timestamp_ *big.Int) (*big.Int, error) { + return _SessionRouter.Contract.StartOfTheDay(&_SessionRouter.CallOpts, timestamp_) +} + +// StartOfTheDay is a free data retrieval call binding the contract method 0xba26588c. +// +// Solidity: function startOfTheDay(uint128 timestamp_) pure returns(uint128) +func (_SessionRouter *SessionRouterCallerSession) StartOfTheDay(timestamp_ *big.Int) (*big.Int, error) { + return _SessionRouter.Contract.StartOfTheDay(&_SessionRouter.CallOpts, timestamp_) +} + +// StipendToStake is a free data retrieval call binding the contract method 0xca40d45f. +// +// Solidity: function stipendToStake(uint256 stipend_, uint128 timestamp_) view returns(uint256) +func (_SessionRouter *SessionRouterCaller) StipendToStake(opts *bind.CallOpts, stipend_ *big.Int, timestamp_ *big.Int) (*big.Int, error) { + var out []interface{} + err := _SessionRouter.contract.Call(opts, &out, "stipendToStake", stipend_, timestamp_) + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// StipendToStake is a free data retrieval call binding the contract method 0xca40d45f. +// +// Solidity: function stipendToStake(uint256 stipend_, uint128 timestamp_) view returns(uint256) +func (_SessionRouter *SessionRouterSession) StipendToStake(stipend_ *big.Int, timestamp_ *big.Int) (*big.Int, error) { + return _SessionRouter.Contract.StipendToStake(&_SessionRouter.CallOpts, stipend_, timestamp_) +} + +// StipendToStake is a free data retrieval call binding the contract method 0xca40d45f. +// +// Solidity: function stipendToStake(uint256 stipend_, uint128 timestamp_) view returns(uint256) +func (_SessionRouter *SessionRouterCallerSession) StipendToStake(stipend_ *big.Int, timestamp_ *big.Int) (*big.Int, error) { + return _SessionRouter.Contract.StipendToStake(&_SessionRouter.CallOpts, stipend_, timestamp_) +} + +// TotalMORSupply is a free data retrieval call binding the contract method 0x6d0cfe5a. +// +// Solidity: function totalMORSupply(uint128 timestamp_) view returns(uint256) +func (_SessionRouter *SessionRouterCaller) TotalMORSupply(opts *bind.CallOpts, timestamp_ *big.Int) (*big.Int, error) { + var out []interface{} + err := _SessionRouter.contract.Call(opts, &out, "totalMORSupply", timestamp_) + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// TotalMORSupply is a free data retrieval call binding the contract method 0x6d0cfe5a. +// +// Solidity: function totalMORSupply(uint128 timestamp_) view returns(uint256) +func (_SessionRouter *SessionRouterSession) TotalMORSupply(timestamp_ *big.Int) (*big.Int, error) { + return _SessionRouter.Contract.TotalMORSupply(&_SessionRouter.CallOpts, timestamp_) +} + +// TotalMORSupply is a free data retrieval call binding the contract method 0x6d0cfe5a. +// +// Solidity: function totalMORSupply(uint128 timestamp_) view returns(uint256) +func (_SessionRouter *SessionRouterCallerSession) TotalMORSupply(timestamp_ *big.Int) (*big.Int, error) { + return _SessionRouter.Contract.TotalMORSupply(&_SessionRouter.CallOpts, timestamp_) +} + +// SessionRouterInit is a paid mutator transaction binding the contract method 0xf8ba944b. +// +// Solidity: function __SessionRouter_init(address fundingAccount_, uint128 maxSessionDuration_, (uint256,uint256,uint128,uint128)[] pools_) returns() +func (_SessionRouter *SessionRouterTransactor) SessionRouterInit(opts *bind.TransactOpts, fundingAccount_ common.Address, maxSessionDuration_ *big.Int, pools_ []ISessionStoragePool) (*types.Transaction, error) { + return _SessionRouter.contract.Transact(opts, "__SessionRouter_init", fundingAccount_, maxSessionDuration_, pools_) +} + +// SessionRouterInit is a paid mutator transaction binding the contract method 0xf8ba944b. +// +// Solidity: function __SessionRouter_init(address fundingAccount_, uint128 maxSessionDuration_, (uint256,uint256,uint128,uint128)[] pools_) returns() +func (_SessionRouter *SessionRouterSession) SessionRouterInit(fundingAccount_ common.Address, maxSessionDuration_ *big.Int, pools_ []ISessionStoragePool) (*types.Transaction, error) { + return _SessionRouter.Contract.SessionRouterInit(&_SessionRouter.TransactOpts, fundingAccount_, maxSessionDuration_, pools_) +} + +// SessionRouterInit is a paid mutator transaction binding the contract method 0xf8ba944b. +// +// Solidity: function __SessionRouter_init(address fundingAccount_, uint128 maxSessionDuration_, (uint256,uint256,uint128,uint128)[] pools_) returns() +func (_SessionRouter *SessionRouterTransactorSession) SessionRouterInit(fundingAccount_ common.Address, maxSessionDuration_ *big.Int, pools_ []ISessionStoragePool) (*types.Transaction, error) { + return _SessionRouter.Contract.SessionRouterInit(&_SessionRouter.TransactOpts, fundingAccount_, maxSessionDuration_, pools_) +} + +// ClaimForProvider is a paid mutator transaction binding the contract method 0xf2e96e8e. +// +// Solidity: function claimForProvider(bytes32 sessionId_) returns() +func (_SessionRouter *SessionRouterTransactor) ClaimForProvider(opts *bind.TransactOpts, sessionId_ [32]byte) (*types.Transaction, error) { + return _SessionRouter.contract.Transact(opts, "claimForProvider", sessionId_) +} + +// ClaimForProvider is a paid mutator transaction binding the contract method 0xf2e96e8e. +// +// Solidity: function claimForProvider(bytes32 sessionId_) returns() +func (_SessionRouter *SessionRouterSession) ClaimForProvider(sessionId_ [32]byte) (*types.Transaction, error) { + return _SessionRouter.Contract.ClaimForProvider(&_SessionRouter.TransactOpts, sessionId_) +} + +// ClaimForProvider is a paid mutator transaction binding the contract method 0xf2e96e8e. +// +// Solidity: function claimForProvider(bytes32 sessionId_) returns() +func (_SessionRouter *SessionRouterTransactorSession) ClaimForProvider(sessionId_ [32]byte) (*types.Transaction, error) { + return _SessionRouter.Contract.ClaimForProvider(&_SessionRouter.TransactOpts, sessionId_) +} + +// CloseSession is a paid mutator transaction binding the contract method 0x42f77a31. +// +// Solidity: function closeSession(bytes receiptEncoded_, bytes signature_) returns() +func (_SessionRouter *SessionRouterTransactor) CloseSession(opts *bind.TransactOpts, receiptEncoded_ []byte, signature_ []byte) (*types.Transaction, error) { + return _SessionRouter.contract.Transact(opts, "closeSession", receiptEncoded_, signature_) +} + +// CloseSession is a paid mutator transaction binding the contract method 0x42f77a31. +// +// Solidity: function closeSession(bytes receiptEncoded_, bytes signature_) returns() +func (_SessionRouter *SessionRouterSession) CloseSession(receiptEncoded_ []byte, signature_ []byte) (*types.Transaction, error) { + return _SessionRouter.Contract.CloseSession(&_SessionRouter.TransactOpts, receiptEncoded_, signature_) +} + +// CloseSession is a paid mutator transaction binding the contract method 0x42f77a31. +// +// Solidity: function closeSession(bytes receiptEncoded_, bytes signature_) returns() +func (_SessionRouter *SessionRouterTransactorSession) CloseSession(receiptEncoded_ []byte, signature_ []byte) (*types.Transaction, error) { + return _SessionRouter.Contract.CloseSession(&_SessionRouter.TransactOpts, receiptEncoded_, signature_) +} + +// OpenSession is a paid mutator transaction binding the contract method 0xa85a1782. +// +// Solidity: function openSession(address user_, uint256 amount_, bool isDirectPaymentFromUser_, bytes approvalEncoded_, bytes signature_) returns(bytes32) +func (_SessionRouter *SessionRouterTransactor) OpenSession(opts *bind.TransactOpts, user_ common.Address, amount_ *big.Int, isDirectPaymentFromUser_ bool, approvalEncoded_ []byte, signature_ []byte) (*types.Transaction, error) { + return _SessionRouter.contract.Transact(opts, "openSession", user_, amount_, isDirectPaymentFromUser_, approvalEncoded_, signature_) +} + +// OpenSession is a paid mutator transaction binding the contract method 0xa85a1782. +// +// Solidity: function openSession(address user_, uint256 amount_, bool isDirectPaymentFromUser_, bytes approvalEncoded_, bytes signature_) returns(bytes32) +func (_SessionRouter *SessionRouterSession) OpenSession(user_ common.Address, amount_ *big.Int, isDirectPaymentFromUser_ bool, approvalEncoded_ []byte, signature_ []byte) (*types.Transaction, error) { + return _SessionRouter.Contract.OpenSession(&_SessionRouter.TransactOpts, user_, amount_, isDirectPaymentFromUser_, approvalEncoded_, signature_) +} + +// OpenSession is a paid mutator transaction binding the contract method 0xa85a1782. +// +// Solidity: function openSession(address user_, uint256 amount_, bool isDirectPaymentFromUser_, bytes approvalEncoded_, bytes signature_) returns(bytes32) +func (_SessionRouter *SessionRouterTransactorSession) OpenSession(user_ common.Address, amount_ *big.Int, isDirectPaymentFromUser_ bool, approvalEncoded_ []byte, signature_ []byte) (*types.Transaction, error) { + return _SessionRouter.Contract.OpenSession(&_SessionRouter.TransactOpts, user_, amount_, isDirectPaymentFromUser_, approvalEncoded_, signature_) +} + +// SetMaxSessionDuration is a paid mutator transaction binding the contract method 0xe8664577. +// +// Solidity: function setMaxSessionDuration(uint128 maxSessionDuration_) returns() +func (_SessionRouter *SessionRouterTransactor) SetMaxSessionDuration(opts *bind.TransactOpts, maxSessionDuration_ *big.Int) (*types.Transaction, error) { + return _SessionRouter.contract.Transact(opts, "setMaxSessionDuration", maxSessionDuration_) +} + +// SetMaxSessionDuration is a paid mutator transaction binding the contract method 0xe8664577. +// +// Solidity: function setMaxSessionDuration(uint128 maxSessionDuration_) returns() +func (_SessionRouter *SessionRouterSession) SetMaxSessionDuration(maxSessionDuration_ *big.Int) (*types.Transaction, error) { + return _SessionRouter.Contract.SetMaxSessionDuration(&_SessionRouter.TransactOpts, maxSessionDuration_) +} + +// SetMaxSessionDuration is a paid mutator transaction binding the contract method 0xe8664577. +// +// Solidity: function setMaxSessionDuration(uint128 maxSessionDuration_) returns() +func (_SessionRouter *SessionRouterTransactorSession) SetMaxSessionDuration(maxSessionDuration_ *big.Int) (*types.Transaction, error) { + return _SessionRouter.Contract.SetMaxSessionDuration(&_SessionRouter.TransactOpts, maxSessionDuration_) +} + +// SetPoolConfig is a paid mutator transaction binding the contract method 0xd7178753. +// +// Solidity: function setPoolConfig(uint256 index_, (uint256,uint256,uint128,uint128) pool_) returns() +func (_SessionRouter *SessionRouterTransactor) SetPoolConfig(opts *bind.TransactOpts, index_ *big.Int, pool_ ISessionStoragePool) (*types.Transaction, error) { + return _SessionRouter.contract.Transact(opts, "setPoolConfig", index_, pool_) +} + +// SetPoolConfig is a paid mutator transaction binding the contract method 0xd7178753. +// +// Solidity: function setPoolConfig(uint256 index_, (uint256,uint256,uint128,uint128) pool_) returns() +func (_SessionRouter *SessionRouterSession) SetPoolConfig(index_ *big.Int, pool_ ISessionStoragePool) (*types.Transaction, error) { + return _SessionRouter.Contract.SetPoolConfig(&_SessionRouter.TransactOpts, index_, pool_) +} + +// SetPoolConfig is a paid mutator transaction binding the contract method 0xd7178753. +// +// Solidity: function setPoolConfig(uint256 index_, (uint256,uint256,uint128,uint128) pool_) returns() +func (_SessionRouter *SessionRouterTransactorSession) SetPoolConfig(index_ *big.Int, pool_ ISessionStoragePool) (*types.Transaction, error) { + return _SessionRouter.Contract.SetPoolConfig(&_SessionRouter.TransactOpts, index_, pool_) +} + +// WithdrawUserStakes is a paid mutator transaction binding the contract method 0xa98a7c6b. +// +// Solidity: function withdrawUserStakes(address user_, uint8 iterations_) returns() +func (_SessionRouter *SessionRouterTransactor) WithdrawUserStakes(opts *bind.TransactOpts, user_ common.Address, iterations_ uint8) (*types.Transaction, error) { + return _SessionRouter.contract.Transact(opts, "withdrawUserStakes", user_, iterations_) +} + +// WithdrawUserStakes is a paid mutator transaction binding the contract method 0xa98a7c6b. +// +// Solidity: function withdrawUserStakes(address user_, uint8 iterations_) returns() +func (_SessionRouter *SessionRouterSession) WithdrawUserStakes(user_ common.Address, iterations_ uint8) (*types.Transaction, error) { + return _SessionRouter.Contract.WithdrawUserStakes(&_SessionRouter.TransactOpts, user_, iterations_) +} + +// WithdrawUserStakes is a paid mutator transaction binding the contract method 0xa98a7c6b. +// +// Solidity: function withdrawUserStakes(address user_, uint8 iterations_) returns() +func (_SessionRouter *SessionRouterTransactorSession) WithdrawUserStakes(user_ common.Address, iterations_ uint8) (*types.Transaction, error) { + return _SessionRouter.Contract.WithdrawUserStakes(&_SessionRouter.TransactOpts, user_, iterations_) +} + +// SessionRouterInitializedIterator is returned from FilterInitialized and is used to iterate over the raw logs and unpacked data for Initialized events raised by the SessionRouter contract. +type SessionRouterInitializedIterator struct { + Event *SessionRouterInitialized // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *SessionRouterInitializedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(SessionRouterInitialized) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(SessionRouterInitialized) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *SessionRouterInitializedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *SessionRouterInitializedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// SessionRouterInitialized represents a Initialized event raised by the SessionRouter contract. +type SessionRouterInitialized struct { + StorageSlot [32]byte + Raw types.Log // Blockchain specific contextual infos +} + +// FilterInitialized is a free log retrieval operation binding the contract event 0xdc73717d728bcfa015e8117438a65319aa06e979ca324afa6e1ea645c28ea15d. +// +// Solidity: event Initialized(bytes32 storageSlot) +func (_SessionRouter *SessionRouterFilterer) FilterInitialized(opts *bind.FilterOpts) (*SessionRouterInitializedIterator, error) { + + logs, sub, err := _SessionRouter.contract.FilterLogs(opts, "Initialized") + if err != nil { + return nil, err + } + return &SessionRouterInitializedIterator{contract: _SessionRouter.contract, event: "Initialized", logs: logs, sub: sub}, nil +} + +// WatchInitialized is a free log subscription operation binding the contract event 0xdc73717d728bcfa015e8117438a65319aa06e979ca324afa6e1ea645c28ea15d. +// +// Solidity: event Initialized(bytes32 storageSlot) +func (_SessionRouter *SessionRouterFilterer) WatchInitialized(opts *bind.WatchOpts, sink chan<- *SessionRouterInitialized) (event.Subscription, error) { + + logs, sub, err := _SessionRouter.contract.WatchLogs(opts, "Initialized") + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(SessionRouterInitialized) + if err := _SessionRouter.contract.UnpackLog(event, "Initialized", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseInitialized is a log parse operation binding the contract event 0xdc73717d728bcfa015e8117438a65319aa06e979ca324afa6e1ea645c28ea15d. +// +// Solidity: event Initialized(bytes32 storageSlot) +func (_SessionRouter *SessionRouterFilterer) ParseInitialized(log types.Log) (*SessionRouterInitialized, error) { + event := new(SessionRouterInitialized) + if err := _SessionRouter.contract.UnpackLog(event, "Initialized", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// SessionRouterSessionClosedIterator is returned from FilterSessionClosed and is used to iterate over the raw logs and unpacked data for SessionClosed events raised by the SessionRouter contract. +type SessionRouterSessionClosedIterator struct { + Event *SessionRouterSessionClosed // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *SessionRouterSessionClosedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(SessionRouterSessionClosed) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(SessionRouterSessionClosed) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *SessionRouterSessionClosedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *SessionRouterSessionClosedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// SessionRouterSessionClosed represents a SessionClosed event raised by the SessionRouter contract. +type SessionRouterSessionClosed struct { + User common.Address + SessionId [32]byte + ProviderId common.Address + Raw types.Log // Blockchain specific contextual infos +} + +// FilterSessionClosed is a free log retrieval operation binding the contract event 0x337fbb0a41a596db800dc836595a57815f967185e3596615c646f2455ac3914a. +// +// Solidity: event SessionClosed(address indexed user, bytes32 indexed sessionId, address indexed providerId) +func (_SessionRouter *SessionRouterFilterer) FilterSessionClosed(opts *bind.FilterOpts, user []common.Address, sessionId [][32]byte, providerId []common.Address) (*SessionRouterSessionClosedIterator, error) { + + var userRule []interface{} + for _, userItem := range user { + userRule = append(userRule, userItem) + } + var sessionIdRule []interface{} + for _, sessionIdItem := range sessionId { + sessionIdRule = append(sessionIdRule, sessionIdItem) + } + var providerIdRule []interface{} + for _, providerIdItem := range providerId { + providerIdRule = append(providerIdRule, providerIdItem) + } + + logs, sub, err := _SessionRouter.contract.FilterLogs(opts, "SessionClosed", userRule, sessionIdRule, providerIdRule) + if err != nil { + return nil, err + } + return &SessionRouterSessionClosedIterator{contract: _SessionRouter.contract, event: "SessionClosed", logs: logs, sub: sub}, nil +} + +// WatchSessionClosed is a free log subscription operation binding the contract event 0x337fbb0a41a596db800dc836595a57815f967185e3596615c646f2455ac3914a. +// +// Solidity: event SessionClosed(address indexed user, bytes32 indexed sessionId, address indexed providerId) +func (_SessionRouter *SessionRouterFilterer) WatchSessionClosed(opts *bind.WatchOpts, sink chan<- *SessionRouterSessionClosed, user []common.Address, sessionId [][32]byte, providerId []common.Address) (event.Subscription, error) { + + var userRule []interface{} + for _, userItem := range user { + userRule = append(userRule, userItem) + } + var sessionIdRule []interface{} + for _, sessionIdItem := range sessionId { + sessionIdRule = append(sessionIdRule, sessionIdItem) + } + var providerIdRule []interface{} + for _, providerIdItem := range providerId { + providerIdRule = append(providerIdRule, providerIdItem) + } + + logs, sub, err := _SessionRouter.contract.WatchLogs(opts, "SessionClosed", userRule, sessionIdRule, providerIdRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(SessionRouterSessionClosed) + if err := _SessionRouter.contract.UnpackLog(event, "SessionClosed", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseSessionClosed is a log parse operation binding the contract event 0x337fbb0a41a596db800dc836595a57815f967185e3596615c646f2455ac3914a. +// +// Solidity: event SessionClosed(address indexed user, bytes32 indexed sessionId, address indexed providerId) +func (_SessionRouter *SessionRouterFilterer) ParseSessionClosed(log types.Log) (*SessionRouterSessionClosed, error) { + event := new(SessionRouterSessionClosed) + if err := _SessionRouter.contract.UnpackLog(event, "SessionClosed", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// SessionRouterSessionOpenedIterator is returned from FilterSessionOpened and is used to iterate over the raw logs and unpacked data for SessionOpened events raised by the SessionRouter contract. +type SessionRouterSessionOpenedIterator struct { + Event *SessionRouterSessionOpened // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *SessionRouterSessionOpenedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(SessionRouterSessionOpened) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(SessionRouterSessionOpened) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *SessionRouterSessionOpenedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *SessionRouterSessionOpenedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// SessionRouterSessionOpened represents a SessionOpened event raised by the SessionRouter contract. +type SessionRouterSessionOpened struct { + User common.Address + SessionId [32]byte + ProviderId common.Address + Raw types.Log // Blockchain specific contextual infos +} + +// FilterSessionOpened is a free log retrieval operation binding the contract event 0x2bd7c890baf595977d256a6e784512c873ac58ba612b4895dbb7f784bfbf4839. +// +// Solidity: event SessionOpened(address indexed user, bytes32 indexed sessionId, address indexed providerId) +func (_SessionRouter *SessionRouterFilterer) FilterSessionOpened(opts *bind.FilterOpts, user []common.Address, sessionId [][32]byte, providerId []common.Address) (*SessionRouterSessionOpenedIterator, error) { + + var userRule []interface{} + for _, userItem := range user { + userRule = append(userRule, userItem) + } + var sessionIdRule []interface{} + for _, sessionIdItem := range sessionId { + sessionIdRule = append(sessionIdRule, sessionIdItem) + } + var providerIdRule []interface{} + for _, providerIdItem := range providerId { + providerIdRule = append(providerIdRule, providerIdItem) + } + + logs, sub, err := _SessionRouter.contract.FilterLogs(opts, "SessionOpened", userRule, sessionIdRule, providerIdRule) + if err != nil { + return nil, err + } + return &SessionRouterSessionOpenedIterator{contract: _SessionRouter.contract, event: "SessionOpened", logs: logs, sub: sub}, nil +} + +// WatchSessionOpened is a free log subscription operation binding the contract event 0x2bd7c890baf595977d256a6e784512c873ac58ba612b4895dbb7f784bfbf4839. +// +// Solidity: event SessionOpened(address indexed user, bytes32 indexed sessionId, address indexed providerId) +func (_SessionRouter *SessionRouterFilterer) WatchSessionOpened(opts *bind.WatchOpts, sink chan<- *SessionRouterSessionOpened, user []common.Address, sessionId [][32]byte, providerId []common.Address) (event.Subscription, error) { + + var userRule []interface{} + for _, userItem := range user { + userRule = append(userRule, userItem) + } + var sessionIdRule []interface{} + for _, sessionIdItem := range sessionId { + sessionIdRule = append(sessionIdRule, sessionIdItem) + } + var providerIdRule []interface{} + for _, providerIdItem := range providerId { + providerIdRule = append(providerIdRule, providerIdItem) + } + + logs, sub, err := _SessionRouter.contract.WatchLogs(opts, "SessionOpened", userRule, sessionIdRule, providerIdRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(SessionRouterSessionOpened) + if err := _SessionRouter.contract.UnpackLog(event, "SessionOpened", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseSessionOpened is a log parse operation binding the contract event 0x2bd7c890baf595977d256a6e784512c873ac58ba612b4895dbb7f784bfbf4839. +// +// Solidity: event SessionOpened(address indexed user, bytes32 indexed sessionId, address indexed providerId) +func (_SessionRouter *SessionRouterFilterer) ParseSessionOpened(log types.Log) (*SessionRouterSessionOpened, error) { + event := new(SessionRouterSessionOpened) + if err := _SessionRouter.contract.UnpackLog(event, "SessionOpened", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// SessionRouterUserWithdrawnIterator is returned from FilterUserWithdrawn and is used to iterate over the raw logs and unpacked data for UserWithdrawn events raised by the SessionRouter contract. +type SessionRouterUserWithdrawnIterator struct { + Event *SessionRouterUserWithdrawn // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *SessionRouterUserWithdrawnIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(SessionRouterUserWithdrawn) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(SessionRouterUserWithdrawn) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *SessionRouterUserWithdrawnIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *SessionRouterUserWithdrawnIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// SessionRouterUserWithdrawn represents a UserWithdrawn event raised by the SessionRouter contract. +type SessionRouterUserWithdrawn struct { + User common.Address + Amount *big.Int + Raw types.Log // Blockchain specific contextual infos +} + +// FilterUserWithdrawn is a free log retrieval operation binding the contract event 0xe6b386172074b393dc04ed6cb1a352475ffad5dd8cebc76231a3b683141ea6fb. +// +// Solidity: event UserWithdrawn(address indexed user, uint256 amount_) +func (_SessionRouter *SessionRouterFilterer) FilterUserWithdrawn(opts *bind.FilterOpts, user []common.Address) (*SessionRouterUserWithdrawnIterator, error) { + + var userRule []interface{} + for _, userItem := range user { + userRule = append(userRule, userItem) + } + + logs, sub, err := _SessionRouter.contract.FilterLogs(opts, "UserWithdrawn", userRule) + if err != nil { + return nil, err + } + return &SessionRouterUserWithdrawnIterator{contract: _SessionRouter.contract, event: "UserWithdrawn", logs: logs, sub: sub}, nil +} + +// WatchUserWithdrawn is a free log subscription operation binding the contract event 0xe6b386172074b393dc04ed6cb1a352475ffad5dd8cebc76231a3b683141ea6fb. +// +// Solidity: event UserWithdrawn(address indexed user, uint256 amount_) +func (_SessionRouter *SessionRouterFilterer) WatchUserWithdrawn(opts *bind.WatchOpts, sink chan<- *SessionRouterUserWithdrawn, user []common.Address) (event.Subscription, error) { + + var userRule []interface{} + for _, userItem := range user { + userRule = append(userRule, userItem) + } + + logs, sub, err := _SessionRouter.contract.WatchLogs(opts, "UserWithdrawn", userRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(SessionRouterUserWithdrawn) + if err := _SessionRouter.contract.UnpackLog(event, "UserWithdrawn", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseUserWithdrawn is a log parse operation binding the contract event 0xe6b386172074b393dc04ed6cb1a352475ffad5dd8cebc76231a3b683141ea6fb. +// +// Solidity: event UserWithdrawn(address indexed user, uint256 amount_) +func (_SessionRouter *SessionRouterFilterer) ParseUserWithdrawn(log types.Log) (*SessionRouterUserWithdrawn, error) { + event := new(SessionRouterUserWithdrawn) + if err := _SessionRouter.contract.UnpackLog(event, "UserWithdrawn", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} diff --git a/proxy-router/internal/repositories/contracts/interface.go b/proxy-router/internal/repositories/contracts/interface.go deleted file mode 100644 index 379bd730..00000000 --- a/proxy-router/internal/repositories/contracts/interface.go +++ /dev/null @@ -1,30 +0,0 @@ -package contracts - -import ( - "context" - "math/big" - - "github.com/ethereum/go-ethereum/accounts/abi/bind" - "github.com/ethereum/go-ethereum/common" -) - -type DataAccess interface { - // string used as address cause different blockchains may return different type of addresses - GetContractsIDs() ([]string, error) - GetContract(contractID string) (interface{}, error) - CloseContract(contractID string, meta interface{}) error - - OnNewContract(func(contractID string)) CloseListererFunc - OnContractUpdated(contractID string, cb func()) CloseListererFunc - OnContractClosed(contractID string, cb func()) CloseListererFunc -} - -type EthereumClient interface { - bind.ContractBackend - bind.DeployBackend - ChainID(ctx context.Context) (*big.Int, error) - BalanceAt(ctx context.Context, addr common.Address, blockNumber *big.Int) (*big.Int, error) - StorageAt(ctx context.Context, account common.Address, key common.Hash, blockNumber *big.Int) ([]byte, error) -} - -type CloseListererFunc = func() diff --git a/proxy-router/internal/repositories/contracts/log_watcher.go b/proxy-router/internal/repositories/contracts/log_watcher.go new file mode 100644 index 00000000..93a509e1 --- /dev/null +++ b/proxy-router/internal/repositories/contracts/log_watcher.go @@ -0,0 +1,13 @@ +package contracts + +import ( + "context" + "math/big" + + "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/lib" + "github.com/ethereum/go-ethereum/common" +) + +type LogWatcher interface { + Watch(ctx context.Context, contractAddr common.Address, mapper EventMapper, fromBlock *big.Int) (*lib.Subscription, error) +} diff --git a/proxy-router/internal/repositories/contracts/log_watcher_polling.go b/proxy-router/internal/repositories/contracts/log_watcher_polling.go new file mode 100644 index 00000000..427bea89 --- /dev/null +++ b/proxy-router/internal/repositories/contracts/log_watcher_polling.go @@ -0,0 +1,162 @@ +package contracts + +import ( + "context" + "errors" + "fmt" + "math/big" + "time" + + i "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/interfaces" + "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/lib" + "github.com/ethereum/go-ethereum" + "github.com/ethereum/go-ethereum/common" +) + +var ( + SubClosedError = errors.New("subscription closed") +) + +type LogWatcherPolling struct { + // config + maxReconnects int + pollInterval time.Duration + + // deps + client i.EthClient + log lib.ILogger +} + +func NewLogWatcherPolling(client i.EthClient, pollInterval time.Duration, maxReconnects int, log lib.ILogger) *LogWatcherPolling { + return &LogWatcherPolling{ + client: client, + pollInterval: pollInterval, + maxReconnects: maxReconnects, + log: log.Named("POLLING"), + } +} + +func (w *LogWatcherPolling) Watch(ctx context.Context, contractAddr common.Address, mapper EventMapper, fromBlock *big.Int) (*lib.Subscription, error) { + var nextFromBlock *big.Int + + if fromBlock != nil { + nextFromBlock = new(big.Int).Set(fromBlock) + } + + sink := make(chan interface{}) + return lib.NewSubscription(func(quit <-chan struct{}) error { + defer close(sink) + + for { // infinite polling loop + nextFrom, err := w.pollReconnect(ctx, quit, nextFromBlock, contractAddr, mapper, sink) + if err != nil { + return err + } + nextFromBlock = nextFrom + } + }, sink), nil +} + +func (w *LogWatcherPolling) pollReconnect(ctx context.Context, quit <-chan struct{}, nextFromBlock *big.Int, contractAddr common.Address, mapper EventMapper, sink chan interface{}) (*big.Int, error) { + var lastErr error + for i := 0; i < w.maxReconnects || w.maxReconnects == 0; i++ { + // for any of those cases, we should stop retrying + select { + case <-quit: + return nextFromBlock, SubClosedError + case <-ctx.Done(): + return nextFromBlock, ctx.Err() + default: + } + newNextFromBlock, err := w.pollChanges(ctx, nextFromBlock, quit, contractAddr, mapper, sink) + if err == nil { + return newNextFromBlock, nil + } + maxReconnects := fmt.Sprintf("%d", w.maxReconnects) + if w.maxReconnects == 0 { + maxReconnects = "∞" + } + w.log.Warnf("request error, retrying (%d/%s): %s", i, maxReconnects, err) + lastErr = err + + // retry delay + select { + case <-quit: + return nextFromBlock, SubClosedError + case <-ctx.Done(): + return nextFromBlock, ctx.Err() + case <-time.After(w.pollInterval): + } + } + + err := fmt.Errorf("request error, retries exhausted (%d), stopping: %s", w.maxReconnects, lastErr) + w.log.Warnf(err.Error()) + return nextFromBlock, err +} + +func (w *LogWatcherPolling) pollChanges(ctx context.Context, nextFromBlock *big.Int, quit <-chan struct{}, contractAddr common.Address, mapper EventMapper, sink chan interface{}) (*big.Int, error) { + currentBlock, err := w.client.HeaderByNumber(ctx, nil) + if err != nil { + return nil, err + } + + if nextFromBlock == nil { + nextFromBlock = new(big.Int).Set(currentBlock.Number) + } + + // if we poll too often, we might be behind the chain, so we wait for the next block + // mapper error, retry won't help, but we can continue + if currentBlock.Number.Cmp(nextFromBlock) < 0 { + select { + case <-quit: + return nextFromBlock, SubClosedError + case <-ctx.Done(): + return nextFromBlock, ctx.Err() + case <-time.After(w.pollInterval): + } + return nextFromBlock, nil + } + + query := ethereum.FilterQuery{ + Addresses: []common.Address{contractAddr}, + FromBlock: nextFromBlock, + ToBlock: currentBlock.Number, + } + + w.log.Debugf("requesting changes from %s to %s block", query.FromBlock.String(), query.ToBlock.String()) + sub, err := w.client.FilterLogs(ctx, query) + if err != nil { + return nextFromBlock, err + } + + for _, log := range sub { + if log.Removed { + continue + } + event, err := mapper(log) + if err != nil { + w.log.Debugf("error mapping event, skipping: %s", err) + continue + } + + select { + case <-quit: + return nextFromBlock, SubClosedError + case <-ctx.Done(): + return nextFromBlock, ctx.Err() + case sink <- event: + } + } + + nextFromBlock.Add(currentBlock.Number, big.NewInt(1)) + + select { + case <-quit: + return nextFromBlock, SubClosedError + case <-ctx.Done(): + return nextFromBlock, ctx.Err() + case <-time.After(w.pollInterval): + } + + return nextFromBlock, nil +} diff --git a/proxy-router/internal/repositories/contracts/log_watcher_polling_test.go b/proxy-router/internal/repositories/contracts/log_watcher_polling_test.go new file mode 100644 index 00000000..50f93b6b --- /dev/null +++ b/proxy-router/internal/repositories/contracts/log_watcher_polling_test.go @@ -0,0 +1,159 @@ +package contracts + +import ( + "context" + "errors" + "fmt" + "math/big" + "testing" + + "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/interfaces/mocks" + "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/lib" + "github.com/ethereum/go-ethereum" + common "github.com/ethereum/go-ethereum/common" + types "github.com/ethereum/go-ethereum/core/types" + "github.com/stretchr/testify/mock" + "github.com/stretchr/testify/require" +) + +var TEST_ERR = errors.New("test error") + +func TestLogWatcherPolling(t *testing.T) { + failTimes := 5 + + ethClientMock := mocks.NewEthClientMock(t) + call1 := ethClientMock.EXPECT().FilterLogs(mock.Anything, mock.Anything).Return(nil, TEST_ERR).Times(failTimes) + _ = ethClientMock.EXPECT().FilterLogs(mock.Anything, mock.Anything).Return([]types.Log{}, nil).Times(1).NotBefore(call1) + logWatcherPolling := NewLogWatcherPolling(ethClientMock, 0, 10, lib.NewTestLogger()) + + _, err := logWatcherPolling.filterLogsRetry(context.Background(), ethereum.FilterQuery{}, make(<-chan struct{})) + require.NoError(t, err) + ethClientMock.AssertNumberOfCalls(t, "FilterLogs", failTimes+1) +} + +func TestWatchDoesntReturnEventsTwice(t *testing.T) { + ethClientMock := mocks.NewEthClientMock(t) + event1 := types.Log{ + BlockNumber: 2, + Index: 1, + Data: []byte{2}, + } + event2 := types.Log{ + BlockNumber: 3, + Index: 1, + Data: []byte{3}, + } + + _ = ethClientMock.EXPECT().FilterLogs(mock.Anything, matchBlockNumber(1)).Return([]types.Log{event1}, nil) + _ = ethClientMock.EXPECT().FilterLogs(mock.Anything, matchBlockNumber(2)).Return([]types.Log{event2}, nil) + _ = ethClientMock.EXPECT().FilterLogs(mock.Anything, mock.Anything).Return([]types.Log{}, nil) + + logWatcherPolling := NewLogWatcherPolling(ethClientMock, 0, 10, lib.NewTestLogger()) + sub, err := logWatcherPolling.Watch(context.Background(), common.Address{}, eventMapper, big.NewInt(1)) + require.NoError(t, err) + defer sub.Unsubscribe() + + totalEvents := 0 + uniqueEvents := make(map[string]types.Log) + +OUTER: + for { + select { + case e := <-sub.Events(): + event := e.(types.Log) + totalEvents++ + uniqueEvents[fmt.Sprintf("%d-%d", event.BlockNumber, event.Index)] = event + if len(uniqueEvents) == 2 { + break OUTER + } + case <-sub.Err(): + require.NoError(t, err) + } + } + + require.Equal(t, totalEvents, len(uniqueEvents)) +} + +func TestWatchShouldErrorAfterMaxReconnects(t *testing.T) { + ethClientMock := mocks.NewEthClientMock(t) + maxRetries := 10 + + _ = ethClientMock.EXPECT().FilterLogs(mock.Anything, mock.Anything).Return([]types.Log{}, TEST_ERR) + + logWatcherPolling := NewLogWatcherPolling(ethClientMock, 0, maxRetries, lib.NewTestLogger()) + sub, err := logWatcherPolling.Watch(context.Background(), common.Address{}, eventMapper, big.NewInt(1)) + require.NoError(t, err) + defer sub.Unsubscribe() + + for { + select { + case e := <-sub.Events(): + if e != nil { + require.Fail(t, "should not receive events") + } + case err := <-sub.Err(): + require.ErrorIs(t, err, TEST_ERR) + ethClientMock.AssertNumberOfCalls(t, "FilterLogs", maxRetries) + return + } + } +} + +func TestShouldHandleContextCancellation(t *testing.T) { + ethClientMock := mocks.NewEthClientMock(t) + ctx, cancel := context.WithCancel(context.Background()) + + _ = ethClientMock.EXPECT().FilterLogs(mock.Anything, mock.Anything).Return([]types.Log{}, nil) + + logWatcherPolling := NewLogWatcherPolling(ethClientMock, 0, 10, lib.NewTestLogger()) + sub, err := logWatcherPolling.Watch(ctx, common.Address{}, eventMapper, big.NewInt(1)) + require.NoError(t, err) + defer sub.Unsubscribe() + + cancel() + + for { + select { + case e := <-sub.Events(): + if e != nil { + require.Fail(t, "should not receive events") + } + case err := <-sub.Err(): + require.ErrorIs(t, err, context.Canceled) + return + } + } +} + +func TestShouldUnsubscribe(t *testing.T) { + ethClientMock := mocks.NewEthClientMock(t) + _ = ethClientMock.EXPECT().FilterLogs(mock.Anything, mock.Anything).Return([]types.Log{}, nil) + + logWatcherPolling := NewLogWatcherPolling(ethClientMock, 0, 10, lib.NewTestLogger()) + sub, err := logWatcherPolling.Watch(context.Background(), common.Address{}, eventMapper, big.NewInt(1)) + require.NoError(t, err) + + sub.Unsubscribe() + + for { + select { + case e := <-sub.Events(): + if e != nil { + require.Fail(t, "should not receive events") + } + case err := <-sub.Err(): + require.Nil(t, err) + return + } + } +} + +func matchBlockNumber(blockNumber int) any { + return mock.MatchedBy(func(query ethereum.FilterQuery) bool { + return int(query.FromBlock.Int64()) == blockNumber + }) +} + +func eventMapper(log types.Log) (interface{}, error) { + return log, nil +} diff --git a/proxy-router/internal/repositories/contracts/log_watcher_subscription.go b/proxy-router/internal/repositories/contracts/log_watcher_subscription.go new file mode 100644 index 00000000..c5629a60 --- /dev/null +++ b/proxy-router/internal/repositories/contracts/log_watcher_subscription.go @@ -0,0 +1,116 @@ +package contracts + +import ( + "context" + "fmt" + "math/big" + + i "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/interfaces" + "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/lib" + "github.com/ethereum/go-ethereum" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" +) + +type LogWatcherSubscription struct { + // config + maxReconnects int + + // deps + client i.EthClient + log lib.ILogger +} + +// NewLogWatcherSubscription creates a new log subscription using websocket +// TODO: if it is going to be primary implementation we should rewrite it so it doesn't skip events in case of temporary downtime +func NewLogWatcherSubscription(client i.EthClient, maxReconnects int, log lib.ILogger) *LogWatcherSubscription { + return &LogWatcherSubscription{ + maxReconnects: maxReconnects, + client: client, + log: log, + } +} + +func (w *LogWatcherSubscription) Watch(ctx context.Context, contractAddr common.Address, mapper EventMapper, fromBlock *big.Int) (*lib.Subscription, error) { + sink := make(chan interface{}) + + return lib.NewSubscription(func(quit <-chan struct{}) error { + defer close(sink) + + query := ethereum.FilterQuery{ + Addresses: []common.Address{contractAddr}, + } + in := make(chan types.Log) + defer close(in) + + for { + + sub, err := w.subscribeFilterLogsRetry(ctx, query, in) + if err != nil { + w.log.Errorf("failed to subscribe to logs: %s", err) + return err + } + + defer sub.Unsubscribe() + + EVENTS_LOOP: + for { + select { + case log := <-in: + event, err := mapper(log) + if err != nil { + w.log.Debugf("failed to map event: %s", err) + // mapper error, retry won't help, continue to next event + continue + } + + select { + case sink <- event: + case err := <-sub.Err(): + w.log.Debugf("subscription error: %s", err) + break EVENTS_LOOP + case <-quit: + return nil + case <-ctx.Done(): + return ctx.Err() + } + case err := <-sub.Err(): + w.log.Debugf("subscription error: %s", err) + break EVENTS_LOOP + case <-quit: + return nil + case <-ctx.Done(): + return ctx.Err() + } + } + } + }, sink), nil +} + +func (w *LogWatcherSubscription) subscribeFilterLogsRetry(ctx context.Context, query ethereum.FilterQuery, ch chan<- types.Log) (ethereum.Subscription, error) { + var lastErr error + + for attempts := 0; attempts < w.maxReconnects || w.maxReconnects == 0; attempts++ { + sub, err := w.client.SubscribeFilterLogs(ctx, query, ch) + if err != nil { + maxReconnects := fmt.Sprintf("%d", w.maxReconnects) + if w.maxReconnects == 0 { + maxReconnects = "∞" + } + w.log.Warnf("subscription error, retrying (%d/%s): %s", attempts, maxReconnects, err) + + lastErr = err + continue + } + if attempts > 0 { + w.log.Warnf("subscription successfully reconnected after error: %s", lastErr) + } + + return sub, nil + } + + err := fmt.Errorf("subscription error, retries exhausted (%d), stopping: %s", w.maxReconnects, lastErr) + w.log.Warnf(err.Error()) + + return nil, err +} diff --git a/proxy-router/internal/repositories/contracts/mapper.go b/proxy-router/internal/repositories/contracts/mapper.go index 645cd27b..5f021765 100644 --- a/proxy-router/internal/repositories/contracts/mapper.go +++ b/proxy-router/internal/repositories/contracts/mapper.go @@ -17,8 +17,6 @@ type EventFactory func(name string) interface{} func CreateEventMapper(eventFactory EventFactory, abi *abi.ABI) func(log types.Log) (interface{}, error) { return func(log types.Log) (interface{}, error) { - fmt.Println("log.Topics[0]:", log.Topics[0]) - fmt.Println("abi", abi.Events) namedEvent, err := abi.EventByID(log.Topics[0]) if err != nil { return nil, err diff --git a/proxy-router/internal/repositories/contracts/subscription.go b/proxy-router/internal/repositories/contracts/subscription.go index 5876e30c..7fa5282a 100644 --- a/proxy-router/internal/repositories/contracts/subscription.go +++ b/proxy-router/internal/repositories/contracts/subscription.go @@ -1,14 +1,9 @@ package contracts import ( - "context" - "errors" "time" - "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/contracts/sessionrouter" - "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/lib" - "github.com/ethereum/go-ethereum" - "github.com/ethereum/go-ethereum/common" + "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/repositories/contracts/bindings/sessionrouter" "github.com/ethereum/go-ethereum/core/types" ) @@ -16,7 +11,7 @@ const RECONNECT_TIMEOUT = 2 * time.Second type EventMapper func(types.Log) (interface{}, error) -func BlockchainEventFactory(name string) interface{} { +func SessionRouterEventFactory(name string) interface{} { switch name { case "SessionOpened": return new(sessionrouter.SessionRouterSessionOpened) @@ -26,93 +21,3 @@ func BlockchainEventFactory(name string) interface{} { return nil } } - -// WatchContractEvents watches for all events from the contract and converts them to the concrete type, using mapper -func WatchContractEvents(ctx context.Context, client EthereumClient, contractAddr common.Address, mapper EventMapper, log lib.ILogger) (*lib.Subscription, error) { - sink := make(chan interface{}) - - return lib.NewSubscription(func(quit <-chan struct{}) error { - defer close(sink) - - query := ethereum.FilterQuery{ - Addresses: []common.Address{contractAddr}, - } - in := make(chan types.Log) - defer close(in) - - var lastErr error - - for attempts := 0; true; attempts++ { - sub, err := client.SubscribeFilterLogs(ctx, query, in) - if err != nil { - lastErr = err - - log.Warnf("subscription error, reconnect in %s: %s", RECONNECT_TIMEOUT, lastErr) - - select { - case <-quit: - return nil - case <-ctx.Done(): - return ctx.Err() - case <-time.After(RECONNECT_TIMEOUT): - } - - continue - } - if attempts > 0 { - log.Warnf("subscription reconnected due to error: %s", lastErr) - } - attempts = 0 - - defer sub.Unsubscribe() - - EVENTS_LOOP: - for { - select { - case logEntry := <-in: - event, err := mapper(logEntry) - if err != nil { - - if errors.Is(err, ErrUnknownEvent) { - log.Warnf("unknown event: %s", err) - continue - } - // mapper error, retry won't help - // return err - continue - } - - select { - case sink <- event: - case err := <-sub.Err(): - lastErr = err - break EVENTS_LOOP - case <-quit: - return nil - case <-ctx.Done(): - return ctx.Err() - } - case err := <-sub.Err(): - lastErr = err - break EVENTS_LOOP - case <-quit: - return nil - case <-ctx.Done(): - return ctx.Err() - } - } - - log.Warnf("subscription error, reconnect in %s: %s", RECONNECT_TIMEOUT, lastErr) - - select { - case <-quit: - return nil - case <-ctx.Done(): - return ctx.Err() - case <-time.After(RECONNECT_TIMEOUT): - } - } - - return lastErr - }, sink), nil -} diff --git a/proxy-router/internal/repositories/ethclient/ethclient.go b/proxy-router/internal/repositories/ethclient/ethclient.go new file mode 100644 index 00000000..cfd44d6f --- /dev/null +++ b/proxy-router/internal/repositories/ethclient/ethclient.go @@ -0,0 +1,278 @@ +package ethclient + +import ( + "context" + "errors" + "fmt" + "math/big" + + "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/interfaces" + "github.com/ethereum/go-ethereum" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/rpc" +) + +// Client defines typed wrappers for the Ethereum RPC API. +type Client struct { + c RPCClient + chainID *big.Int +} + +// NewClient creates a client that uses the given RPC client. +func NewClient(c RPCClient) *Client { + return &Client{c, nil} +} + +// Close closes the underlying RPC connection. +func (ec *Client) Close() { + ec.c.Close() +} + +// Client gets the underlying RPC client. +func (ec *Client) Client() RPCClient { + return ec.c +} + +// Blockchain Access + +// ChainID retrieves the current chain ID for transaction replay protection. +func (ec *Client) ChainID(ctx context.Context) (*big.Int, error) { + if ec.chainID == nil { + var result hexutil.Big + err := ec.c.CallContext(ctx, &result, "eth_chainId") + if err != nil { + return nil, err + } + ec.chainID = (*big.Int)(&result) + } + + return new(big.Int).Set(ec.chainID), nil +} + +// BlockNumber returns the most recent block number +func (ec *Client) BlockNumber(ctx context.Context) (uint64, error) { + var result hexutil.Uint64 + err := ec.c.CallContext(ctx, &result, "eth_blockNumber") + return uint64(result), err +} + +// HeaderByNumber returns a block header from the current canonical chain. If number is +// nil, the latest known header is returned. +func (ec *Client) HeaderByNumber(ctx context.Context, number *big.Int) (*types.Header, error) { + var head *types.Header + err := ec.c.CallContext(ctx, &head, "eth_getBlockByNumber", toBlockNumArg(number), false) + if err == nil && head == nil { + err = ethereum.NotFound + } + return head, err +} + +// TransactionReceipt returns the receipt of a transaction by transaction hash. +// Note that the receipt is not available for pending transactions. +func (ec *Client) TransactionReceipt(ctx context.Context, txHash common.Hash) (*types.Receipt, error) { + var r *types.Receipt + err := ec.c.CallContext(ctx, &r, "eth_getTransactionReceipt", txHash) + if err == nil && r == nil { + return nil, ethereum.NotFound + } + return r, err +} + +// State Access + +// BalanceAt returns the wei balance of the given account. +// The block number can be nil, in which case the balance is taken from the latest known block. +func (ec *Client) BalanceAt(ctx context.Context, account common.Address, blockNumber *big.Int) (*big.Int, error) { + var result hexutil.Big + err := ec.c.CallContext(ctx, &result, "eth_getBalance", account, toBlockNumArg(blockNumber)) + return (*big.Int)(&result), err +} + +// CodeAt returns the contract code of the given account. +// The block number can be nil, in which case the code is taken from the latest known block. +func (ec *Client) CodeAt(ctx context.Context, account common.Address, blockNumber *big.Int) ([]byte, error) { + var result hexutil.Bytes + err := ec.c.CallContext(ctx, &result, "eth_getCode", account, toBlockNumArg(blockNumber)) + return result, err +} + +// Filters + +// FilterLogs executes a filter query. +func (ec *Client) FilterLogs(ctx context.Context, q ethereum.FilterQuery) ([]types.Log, error) { + var result []types.Log + arg, err := toFilterArg(q) + if err != nil { + return nil, err + } + err = ec.c.CallContext(ctx, &result, "eth_getLogs", arg) + return result, err +} + +// SubscribeFilterLogs subscribes to the results of a streaming filter query. +func (ec *Client) SubscribeFilterLogs(ctx context.Context, q ethereum.FilterQuery, ch chan<- types.Log) (ethereum.Subscription, error) { + arg, err := toFilterArg(q) + if err != nil { + return nil, err + } + sub, err := ec.c.EthSubscribe(ctx, ch, "logs", arg) + if err != nil { + // Defensively prefer returning nil interface explicitly on error-path, instead + // of letting default golang behavior wrap it with non-nil interface that stores + // nil concrete type value. + return nil, err + } + return sub, nil +} + +func toFilterArg(q ethereum.FilterQuery) (interface{}, error) { + arg := map[string]interface{}{ + "address": q.Addresses, + "topics": q.Topics, + } + if q.BlockHash != nil { + arg["blockHash"] = *q.BlockHash + if q.FromBlock != nil || q.ToBlock != nil { + return nil, errors.New("cannot specify both BlockHash and FromBlock/ToBlock") + } + } else { + if q.FromBlock == nil { + arg["fromBlock"] = "0x0" + } else { + arg["fromBlock"] = toBlockNumArg(q.FromBlock) + } + arg["toBlock"] = toBlockNumArg(q.ToBlock) + } + return arg, nil +} + +// PendingCodeAt returns the contract code of the given account in the pending state. +func (ec *Client) PendingCodeAt(ctx context.Context, account common.Address) ([]byte, error) { + var result hexutil.Bytes + err := ec.c.CallContext(ctx, &result, "eth_getCode", account, "pending") + return result, err +} + +// PendingNonceAt returns the account nonce of the given account in the pending state. +// This is the nonce that should be used for the next transaction. +func (ec *Client) PendingNonceAt(ctx context.Context, account common.Address) (uint64, error) { + var result hexutil.Uint64 + err := ec.c.CallContext(ctx, &result, "eth_getTransactionCount", account, "pending") + return uint64(result), err +} + +// Contract Calling + +// CallContract executes a message call transaction, which is directly executed in the VM +// of the node, but never mined into the blockchain. +// +// blockNumber selects the block height at which the call runs. It can be nil, in which +// case the code is taken from the latest known block. Note that state from very old +// blocks might not be available. +func (ec *Client) CallContract(ctx context.Context, msg ethereum.CallMsg, blockNumber *big.Int) ([]byte, error) { + var hex hexutil.Bytes + err := ec.c.CallContext(ctx, &hex, "eth_call", toCallArg(msg), toBlockNumArg(blockNumber)) + if err != nil { + return nil, err + } + return hex, nil +} + +// SuggestGasPrice retrieves the currently suggested gas price to allow a timely +// execution of a transaction. +func (ec *Client) SuggestGasPrice(ctx context.Context) (*big.Int, error) { + var hex hexutil.Big + if err := ec.c.CallContext(ctx, &hex, "eth_gasPrice"); err != nil { + return nil, err + } + return (*big.Int)(&hex), nil +} + +// SuggestGasTipCap retrieves the currently suggested gas tip cap after 1559 to +// allow a timely execution of a transaction. +func (ec *Client) SuggestGasTipCap(ctx context.Context) (*big.Int, error) { + var hex hexutil.Big + if err := ec.c.CallContext(ctx, &hex, "eth_maxPriorityFeePerGas"); err != nil { + return nil, err + } + return (*big.Int)(&hex), nil +} + +// EstimateGas tries to estimate the gas needed to execute a specific transaction based on +// the current pending state of the backend blockchain. There is no guarantee that this is +// the true gas limit requirement as other transactions may be added or removed by miners, +// but it should provide a basis for setting a reasonable default. +func (ec *Client) EstimateGas(ctx context.Context, msg ethereum.CallMsg) (uint64, error) { + var hex hexutil.Uint64 + err := ec.c.CallContext(ctx, &hex, "eth_estimateGas", toCallArg(msg)) + if err != nil { + return 0, err + } + return uint64(hex), nil +} + +// SendTransaction injects a signed transaction into the pending pool for execution. +// +// If the transaction was a contract creation use the TransactionReceipt method to get the +// contract address after the transaction has been mined. +func (ec *Client) SendTransaction(ctx context.Context, tx *types.Transaction) error { + data, err := tx.MarshalBinary() + if err != nil { + return err + } + return ec.c.CallContext(ctx, nil, "eth_sendRawTransaction", hexutil.Encode(data)) +} + +func toBlockNumArg(number *big.Int) string { + if number == nil { + return "latest" + } + if number.Sign() >= 0 { + return hexutil.EncodeBig(number) + } + // It's negative. + if number.IsInt64() { + return rpc.BlockNumber(number.Int64()).String() + } + // It's negative and large, which is invalid. + return fmt.Sprintf("", number) +} + +func toCallArg(msg ethereum.CallMsg) interface{} { + arg := map[string]interface{}{ + "from": msg.From, + "to": msg.To, + } + if len(msg.Data) > 0 { + arg["input"] = hexutil.Bytes(msg.Data) + } + if msg.Value != nil { + arg["value"] = (*hexutil.Big)(msg.Value) + } + if msg.Gas != 0 { + arg["gas"] = hexutil.Uint64(msg.Gas) + } + if msg.GasPrice != nil { + arg["gasPrice"] = (*hexutil.Big)(msg.GasPrice) + } + if msg.GasFeeCap != nil { + arg["maxFeePerGas"] = (*hexutil.Big)(msg.GasFeeCap) + } + if msg.GasTipCap != nil { + arg["maxPriorityFeePerGas"] = (*hexutil.Big)(msg.GasTipCap) + } + if msg.AccessList != nil { + arg["accessList"] = msg.AccessList + } + if msg.BlobGasFeeCap != nil { + arg["maxFeePerBlobGas"] = (*hexutil.Big)(msg.BlobGasFeeCap) + } + if msg.BlobHashes != nil { + arg["blobVersionedHashes"] = msg.BlobHashes + } + return arg +} + +var _ interfaces.EthClient = (*Client)(nil) diff --git a/proxy-router/internal/repositories/ethclient/ethclient_test.go b/proxy-router/internal/repositories/ethclient/ethclient_test.go new file mode 100644 index 00000000..227df747 --- /dev/null +++ b/proxy-router/internal/repositories/ethclient/ethclient_test.go @@ -0,0 +1,41 @@ +package ethclient + +import ( + "fmt" + "sync" + "testing" + + "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/lib" + "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/repositories/contracts/bindings/modelregistry" + "github.com/ethereum/go-ethereum/common" + "github.com/stretchr/testify/require" +) + +func TestEthClient(t *testing.T) { + t.SkipNow() + rpcClient, err := NewRPCClientMultiple([]string{ + "https://arbitrum.blockpi.network/v1/rpc/public", + }, &lib.LoggerMock{}) + require.NoError(t, err) + client := NewClient(rpcClient) + + wg := sync.WaitGroup{} + + mr, err := modelregistry.NewModelRegistry(common.HexToAddress("0x0FC0c323Cf76E188654D63D62e668caBeC7a525b"), client) + require.NoError(t, err) + + for i := 0; i < 500; i++ { + wg.Add(1) + go func() { + ids, _, err := mr.ModelGetAll(nil) + defer wg.Done() + if err != nil { + fmt.Printf("Error: %s\n", err) + return + } + fmt.Printf("Models number: %d\n", len(ids)) + }() + + } + wg.Wait() +} diff --git a/proxy-router/internal/repositories/ethclient/public.go b/proxy-router/internal/repositories/ethclient/public.go new file mode 100644 index 00000000..212e3389 --- /dev/null +++ b/proxy-router/internal/repositories/ethclient/public.go @@ -0,0 +1,51 @@ +package ethclient + +import ( + "fmt" + + "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/lib" +) + +var publicRPCURLs = map[int][]string{ + 421614: { + "https://arbitrum-sepolia.blockpi.network/v1/rpc/public", + "https://sepolia-rollup.arbitrum.io/rpc", + "https://arbitrum-sepolia.gateway.tenderly.co", + "https://endpoints.omniatech.io/v1/arbitrum/sepolia/public", + "https://public.stackup.sh/api/v1/node/arbitrum-sepolia", + "https://arbitrum-sepolia-rpc.publicnode.com", + "https://rpc.ankr.com/arbitrum_sepolia", + "https://arbitrum-sepolia.public.blastapi.io", + }, + 42161: { + "https://arbitrum.llamarpc.com", + "https://api.zan.top/node/v1/arb/one/public", + "https://1rpc.io/arb", + "https://arbitrum.blockpi.network/v1/rpc/public", + "https://arb-pokt.nodies.app", + "https://arbitrum.drpc.org", + "https://arbitrum.meowrpc.com", + "https://rpc.ankr.com/arbitrum", + "https://arbitrum-one.public.blastapi.io", + "https://arbitrum.gateway.tenderly.co", + "https://arbitrum-one-rpc.publicnode.com", + "https://arbitrum-one.publicnode.com", + "https://arb1.arbitrum.io/rpc", + "https://arbitrum.rpc.subquery.network/public", + "https://api.stateless.solutions/arbitrum-one/v1/demo", + "https://public.stackup.sh/api/v1/node/arbitrum-one", + "https://rpc.arb1.arbitrum.gateway.fm", + "https://arb-mainnet-public.unifra.io", + "https://arb-mainnet.g.alchemy.com/v2/demo", + }, +} + +var ErrNotSupportedChain = fmt.Errorf("chain is not supported") + +func GetPublicRPCURLs(chainID int) ([]string, error) { + urls, ok := publicRPCURLs[chainID] + if !ok { + return nil, lib.WrapError(ErrNotSupportedChain, fmt.Errorf("chainID: %d", chainID)) + } + return urls, nil +} diff --git a/proxy-router/internal/repositories/ethclient/rpcclient.go b/proxy-router/internal/repositories/ethclient/rpcclient.go new file mode 100644 index 00000000..2fac363c --- /dev/null +++ b/proxy-router/internal/repositories/ethclient/rpcclient.go @@ -0,0 +1,20 @@ +package ethclient + +import ( + "context" + + "github.com/ethereum/go-ethereum/rpc" +) + +type RPCClient interface { + Close() + BatchCallContext(context.Context, []rpc.BatchElem) error + CallContext(ctx context.Context, result interface{}, method string, args ...interface{}) error + EthSubscribe(ctx context.Context, channel interface{}, args ...interface{}) (*rpc.ClientSubscription, error) +} + +type RPCClientModifiable interface { + RPCClient + GetURLs() []string + SetURLs(urls []string) error +} diff --git a/proxy-router/internal/repositories/ethclient/rpcclient_store_env.go b/proxy-router/internal/repositories/ethclient/rpcclient_store_env.go new file mode 100644 index 00000000..58c7daba --- /dev/null +++ b/proxy-router/internal/repositories/ethclient/rpcclient_store_env.go @@ -0,0 +1,31 @@ +package ethclient + +import ( + "errors" +) + +var ErrEnvRPCSet = errors.New("cannot set rpc url when using env store, switch to keychain store by removing ETH_NODE_URL env var") + +type RPCClientStoreEnv struct { + rpcClient RPCClientModifiable +} + +func (p *RPCClientStoreEnv) GetURLs() []string { + return p.rpcClient.GetURLs() +} + +func (p *RPCClientStoreEnv) SetURLs(urls []string) error { + return ErrEnvRPCSet +} + +func (p *RPCClientStoreEnv) SetURLsNoPersist(urls []string) error { + return ErrEnvRPCSet +} + +func (p *RPCClientStoreEnv) RemoveURLs() error { + return ErrEnvRPCSet +} + +func (p *RPCClientStoreEnv) GetClient() RPCClient { + return p.rpcClient +} diff --git a/proxy-router/internal/repositories/ethclient/rpcclient_store_factory.go b/proxy-router/internal/repositories/ethclient/rpcclient_store_factory.go new file mode 100644 index 00000000..2faf2ebe --- /dev/null +++ b/proxy-router/internal/repositories/ethclient/rpcclient_store_factory.go @@ -0,0 +1,84 @@ +package ethclient + +import ( + "errors" + + "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/interfaces" + "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/lib" + "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/repositories/keychain" +) + +type RPCEndpointsPersister interface { + GetURLs() []string + SetURLs(urls []string) error + SetURLsNoPersist(urls []string) error + RemoveURLs() error + GetClient() RPCClient +} + +func ConfigureRPCClientStore(storage interfaces.KeyValueStorage, envURLs []string, chainID int, log lib.ILogger) (RPCEndpointsPersister, error) { + // if env set, use env store + if len(envURLs) > 0 { + rpcClient, err := NewRPCClientMultiple(envURLs, log) + if err != nil { + return nil, err + } + + log.Info("using eth node address configured in env") + + p := &RPCClientStoreEnv{ + rpcClient: rpcClient, + } + return p, nil + } + + // if no env set, try use keychain store + rpcClient := &RPCClientMultiple{ + log: log, + } + p := &RPCClientStoreKeychain{ + storage: storage, + log: log, + rpcClient: rpcClient, + } + + urls, err := p.loadURLsFromStorage() + if err == nil { + log.Info("using eth node address configured in keychain") + + err = rpcClient.SetURLs(urls) + if err != nil { + return nil, err + } + + return p, nil + } + + // if error during loading keychain, use fallback URLs + if !errors.Is(err, keychain.ErrKeyNotFound) { + p.log.Warn("Error during loading keychain eth client URLs, using fallback URLs", err) + } + + if chainID == 0 { + return nil, errors.New("Missing chain ID. You need to configure chain ID to use public eth node addresses") + } + + publicURLs, err := GetPublicRPCURLs(chainID) + if err != nil { + return nil, err + } + + log.Info("using public eth node addresses") + + rpcClient, err = NewRPCClientMultiple(publicURLs, log) + if err != nil { + return nil, err + } + + rpc := &RPCClientStoreKeychain{ + rpcClient: rpcClient, + storage: storage, + } + + return rpc, nil +} diff --git a/proxy-router/internal/repositories/ethclient/rpcclient_store_keychain.go b/proxy-router/internal/repositories/ethclient/rpcclient_store_keychain.go new file mode 100644 index 00000000..79e20823 --- /dev/null +++ b/proxy-router/internal/repositories/ethclient/rpcclient_store_keychain.go @@ -0,0 +1,84 @@ +package ethclient + +import ( + "encoding/json" + + "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/interfaces" + "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/lib" +) + +const ( + ETH_NODE_URL_KEY = "eth-node-url" +) + +type RPCClientStoreKeychain struct { + storage interfaces.KeyValueStorage + rpcClient RPCClientModifiable + log lib.ILogger +} + +func NewRPCClientStoreKeychain(storage interfaces.KeyValueStorage, rpcClient RPCClientModifiable, log lib.ILogger) *RPCClientStoreKeychain { + return &RPCClientStoreKeychain{ + storage: storage, + rpcClient: rpcClient, + log: log, + } +} + +func (p *RPCClientStoreKeychain) GetURLs() []string { + return p.rpcClient.GetURLs() +} + +func (p *RPCClientStoreKeychain) SetURLs(urls []string) error { + err := p.storeURLsInStorage(urls) + if err != nil { + return err + } + + return p.rpcClient.SetURLs(urls) +} + +func (p *RPCClientStoreKeychain) SetURLsNoPersist(urls []string) error { + return p.rpcClient.SetURLs(urls) +} + +func (p *RPCClientStoreKeychain) RemoveURLs() error { + return p.deleteURLsInStorage() +} + +func (p *RPCClientStoreKeychain) GetClient() RPCClient { + return p.rpcClient +} + +func (p *RPCClientStoreKeychain) loadURLsFromStorage() ([]string, error) { + str, err := p.storage.Get(ETH_NODE_URL_KEY) + if err != nil { + return nil, err + } + + var urls []string + err = json.Unmarshal([]byte(str), &urls) + if err != nil { + return nil, err + } + + return urls, nil +} + +func (p *RPCClientStoreKeychain) storeURLsInStorage(urls []string) error { + str, err := json.Marshal(urls) + if err != nil { + return err + } + + err = p.storage.Upsert(ETH_NODE_URL_KEY, string(str)) + if err != nil { + return err + } + + return nil +} + +func (p *RPCClientStoreKeychain) deleteURLsInStorage() error { + return p.storage.DeleteIfExists(ETH_NODE_URL_KEY) +} diff --git a/proxy-router/internal/repositories/ethclient/rpcclientmultiple.go b/proxy-router/internal/repositories/ethclient/rpcclientmultiple.go new file mode 100644 index 00000000..2a58c247 --- /dev/null +++ b/proxy-router/internal/repositories/ethclient/rpcclientmultiple.go @@ -0,0 +1,148 @@ +package ethclient + +import ( + "context" + "sync" + + "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/lib" + "github.com/ethereum/go-ethereum/rpc" +) + +// Wrapper around multiple RPC clients, used to retry calls on multiple endpoints +type RPCClientMultiple struct { + lock sync.RWMutex + clients []*rpcClient + log lib.ILogger +} + +func NewRPCClientMultiple(urls []string, log lib.ILogger) (*RPCClientMultiple, error) { + clients := make([]*rpcClient, len(urls)) + + for i, url := range urls { + client, err := rpc.DialOptions(context.Background(), url) + if err != nil { + return nil, err + } + clients[i] = &rpcClient{ + url: url, + client: client, + } + } + + return &RPCClientMultiple{clients: clients, log: log}, nil +} + +func (c *RPCClientMultiple) CallContext(ctx context.Context, result interface{}, method string, args ...interface{}) error { + return c.retriableCall(ctx, func(client *rpcClient) error { + c.log.Debugf("calling %s", method) + return client.client.CallContext(ctx, result, method, args...) + }) +} + +func (c *RPCClientMultiple) BatchCallContext(ctx context.Context, b []rpc.BatchElem) error { + return c.retriableCall(ctx, func(client *rpcClient) error { + return client.client.BatchCallContext(ctx, b) + }) +} + +func (c *RPCClientMultiple) Close() { + for _, rpcClient := range c.getClients() { + rpcClient.client.Close() + } +} + +func (c *RPCClientMultiple) EthSubscribe(ctx context.Context, channel interface{}, args ...interface{}) (*rpc.ClientSubscription, error) { + client := c.getClients()[0] + return client.client.EthSubscribe(ctx, channel, args...) +} + +func (c *RPCClientMultiple) GetURLs() []string { + clients := c.getClients() + urls := make([]string, len(clients)) + for i, rpcClient := range clients { + urls[i] = rpcClient.url + } + return urls +} + +func (c *RPCClientMultiple) SetURLs(urls []string) error { + clients := make([]*rpcClient, len(urls)) + + for i, url := range urls { + client, err := rpc.DialOptions(context.Background(), url) + if err != nil { + return err + } + clients[i] = &rpcClient{ + url: url, + client: client, + } + } + + c.lock.Lock() + defer c.lock.Unlock() + for _, rpcClient := range c.clients { + rpcClient.client.Close() + } + + c.clients = clients + + return nil +} + +func (c *RPCClientMultiple) getClients() []*rpcClient { + c.lock.RLock() + defer c.lock.RUnlock() + return c.clients +} + +// retriableCall is a helper function that retries the call on different endpoints +func (c *RPCClientMultiple) retriableCall(ctx context.Context, fn func(client *rpcClient) error) error { + var lastErr error + + for _, rpcClient := range c.getClients() { + if ctx.Err() != nil { + return ctx.Err() + } + + err := fn(rpcClient) + if err == nil { + return nil + } + + retryable := c.shouldBeRetried(err) + c.log.Debugf("error (retryable: %t) calling eth endpoint %s: %s", retryable, rpcClient.url, err) + if !retryable { + return err + } + + lastErr = err + } + + c.log.Debugf("all endpoints failed") + return lastErr +} + +func (c *RPCClientMultiple) shouldBeRetried(err error) bool { + switch err.(type) { + case rpc.HTTPError: + // if err.(rpc.HTTPError).StatusCode == 429 { + // return true + // } + return true + case JSONError: + return false + } + return false +} + +type JSONError interface { + Error() string + ErrorCode() int + ErrorData() interface{} +} + +type rpcClient struct { + url string + client *rpc.Client +} diff --git a/proxy-router/internal/repositories/multicall/batch.go b/proxy-router/internal/repositories/multicall/batch.go new file mode 100644 index 00000000..834654f9 --- /dev/null +++ b/proxy-router/internal/repositories/multicall/batch.go @@ -0,0 +1,44 @@ +package multicall + +import ( + "context" + + "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/repositories/contracts/bindings/multicall3" + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/common" +) + +// Batch executes multiple calls to the same method on the same contract in a single multicall and converts the results to the specified type +// TODO: configure max batch size, enabling multicall level and json-rpc level batching +func Batch[T any](ctx context.Context, mc MulticallBackend, contractABI *abi.ABI, addr common.Address, method string, callsArgs [][]interface{}) ([]T, error) { + var calls []multicall3.Multicall3Call + + for _, args := range callsArgs { + calldata, err := contractABI.Pack(method, args...) + if err != nil { + return nil, err + } + calls = append(calls, multicall3.Multicall3Call{ + Target: addr, + CallData: calldata, + }) + } + + _, res, err := mc.Aggregate(ctx, calls) + if err != nil { + return nil, err + } + + sessions := make([]T, len(res)) + for i, result := range res { + var data interface{} + err := contractABI.UnpackIntoInterface(&data, method, result) + if err != nil { + return nil, err + } + + sessions[i] = *abi.ConvertType(data, new(T)).(*T) + } + + return sessions, nil +} diff --git a/proxy-router/internal/repositories/multicall/interface.go b/proxy-router/internal/repositories/multicall/interface.go new file mode 100644 index 00000000..87cd623a --- /dev/null +++ b/proxy-router/internal/repositories/multicall/interface.go @@ -0,0 +1,12 @@ +package multicall + +import ( + "context" + "math/big" + + "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/repositories/contracts/bindings/multicall3" +) + +type MulticallBackend interface { + Aggregate(ctx context.Context, calls []multicall3.Multicall3Call) (blockNumer *big.Int, returnData [][]byte, err error) +} diff --git a/proxy-router/internal/repositories/multicall/multicall.go b/proxy-router/internal/repositories/multicall/multicall.go new file mode 100644 index 00000000..ea8aca2e --- /dev/null +++ b/proxy-router/internal/repositories/multicall/multicall.go @@ -0,0 +1,104 @@ +package multicall + +import ( + "context" + "fmt" + "math/big" + + mc3 "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/repositories/contracts/bindings/multicall3" + ethereum "github.com/ethereum/go-ethereum" + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/common" +) + +type Multicall3Custom struct { + mutlicall3Addr common.Address + multicall3Abi *abi.ABI + client bind.ContractCaller +} + +var MULTICALL3_ADDR = common.HexToAddress("0xcA11bde05977b3631167028862bE2a173976CA11") + +func NewMulticall3(client bind.ContractCaller) *Multicall3Custom { + return NewMulticall3Custom(client, MULTICALL3_ADDR) +} + +func NewMulticall3Custom(client bind.ContractCaller, multicall3Addr common.Address) *Multicall3Custom { + multicall3Abi, err := mc3.Multicall3MetaData.GetAbi() + if err != nil { + panic("invalid multicall3 ABI: " + err.Error()) + } + return &Multicall3Custom{ + mutlicall3Addr: multicall3Addr, + multicall3Abi: multicall3Abi, + client: client, + } +} + +func (m *Multicall3Custom) Aggregate(ctx context.Context, calls []mc3.Multicall3Call) (blockNumer *big.Int, returnData [][]byte, err error) { + res, err := m.aggregate(ctx, calls, "aggregate") + if err != nil { + return nil, nil, err + } + + blockNumer, ok := res[0].(*big.Int) + if !ok { + return nil, nil, fmt.Errorf("Failed to parse block number") + } + returnData, ok = res[1].([][]byte) + if !ok { + return nil, nil, fmt.Errorf("Failed to parse return data") + } + + return blockNumer, returnData, nil +} + +func (m *Multicall3Custom) Aggregate3(ctx context.Context, calls []mc3.Multicall3Call3) ([]mc3.Multicall3Result, error) { + res, err := m.aggregate(ctx, calls, "aggregate3") + if err != nil { + return nil, err + } + + parsed, ok := res[0].([]struct { + Success bool "json:\"success\"" + ReturnData []uint8 "json:\"returnData\"" + }) + if !ok { + return nil, fmt.Errorf("Failed to parse result") + } + + var results []mc3.Multicall3Result + for _, vv := range parsed { + results = append(results, mc3.Multicall3Result{ + Success: vv.Success, + ReturnData: vv.ReturnData, + }) + } + + return results, nil +} + +func (m *Multicall3Custom) aggregate(ctx context.Context, calls interface{}, method string) ([]interface{}, error) { + calldata, err := m.multicall3Abi.Pack(method, calls) + if err != nil { + return nil, fmt.Errorf("Failed to pack data: %w", err) + } + + result, err := m.client.CallContract(ctx, ethereum.CallMsg{ + To: &m.mutlicall3Addr, + Data: calldata, + }, nil) + if err != nil { + return nil, fmt.Errorf("Failed to call contract: %w", err) + } + + parsedResult, err := m.multicall3Abi.Unpack(method, result) + if err != nil { + return nil, fmt.Errorf("Failed to unpack result: %w", err) + } + + return parsedResult, nil +} + +var _ MulticallBackend = &Multicall3Custom{} diff --git a/proxy-router/internal/repositories/registries/marketplace.go b/proxy-router/internal/repositories/registries/marketplace.go index af4c08d4..8bfdbdbc 100644 --- a/proxy-router/internal/repositories/registries/marketplace.go +++ b/proxy-router/internal/repositories/registries/marketplace.go @@ -2,14 +2,17 @@ package registries import ( "context" + "errors" "fmt" "math/big" - "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/contracts/marketplace" + i "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/interfaces" "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/lib" + "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/repositories/contracts/bindings/marketplace" + mc "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/repositories/multicall" + "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/ethclient" ) type Marketplace struct { @@ -17,167 +20,225 @@ type Marketplace struct { marketplaceAddr common.Address // deps - marketplace *marketplace.Marketplace - client *ethclient.Client - log lib.ILogger + marketplace *marketplace.Marketplace + multicall mc.MulticallBackend + marketplaceABI *abi.ABI + client i.ContractBackend + log lib.ILogger } -func NewMarketplace(marketplaceAddr common.Address, client *ethclient.Client, log lib.ILogger) *Marketplace { +var ( + ErrBidPricePerSecondInvalid = errors.New("Invalid bid price per second") +) + +func NewMarketplace(marketplaceAddr common.Address, client i.ContractBackend, multicall mc.MulticallBackend, log lib.ILogger) *Marketplace { mp, err := marketplace.NewMarketplace(marketplaceAddr, client) if err != nil { panic("invalid marketplace ABI") } + marketplaceABI, err := marketplace.MarketplaceMetaData.GetAbi() + if err != nil { + panic("invalid marketplace ABI: " + err.Error()) + } + return &Marketplace{ marketplace: mp, marketplaceAddr: marketplaceAddr, + marketplaceABI: marketplaceABI, + multicall: multicall, client: client, log: log, } } -func (g *Marketplace) PostModelBid(opts *bind.TransactOpts, provider common.Address, model common.Hash, pricePerSecond *big.Int) error { - tx, err := g.marketplace.PostModelBid(opts, provider, model, pricePerSecond) +func (g *Marketplace) PostModelBid(opts *bind.TransactOpts, model common.Hash, pricePerSecond *big.Int) (common.Hash, error) { + tx, err := g.marketplace.PostModelBid(opts, opts.From, model, pricePerSecond) if err != nil { - return lib.TryConvertGethError(err) + err = lib.TryConvertGethError(err) + + evmErr := lib.EVMError{} + if errors.As(err, &evmErr) { + if evmErr.Abi.Name == "MarketplaceBidPricePerSecondInvalid" { + min, max, err := g.GetMinMaxBidPricePerSecond(opts.Context) + if err != nil { + return common.Hash{}, lib.WrapError(ErrBidPricePerSecondInvalid, err) + } + + return common.Hash{}, lib.WrapError(ErrBidPricePerSecondInvalid, fmt.Errorf("must be between %s and %s, %w", min.String(), max.String(), evmErr)) + } + } + + return common.Hash{}, lib.TryConvertGethError(err) } // Wait for the transaction receipt receipt, err := bind.WaitMined(opts.Context, g.client, tx) - if err != nil { - return lib.TryConvertGethError(err) + return common.Hash{}, lib.TryConvertGethError(err) } - // Find the event log for _, log := range receipt.Logs { - // Check if the log belongs to the OpenSession event - _, err := g.marketplace.ParseBidPosted(*log) - - if err != nil { - continue // not our event, skip it + event, err := g.marketplace.ParseMarketplaceBidPosted(*log) + if err == nil { + bidId, errBid := g.marketplace.GetBidId(&bind.CallOpts{Context: opts.Context}, event.Provider, event.ModelId, event.Nonce) + if errBid == nil { + return bidId, nil + } } - - return nil } - return fmt.Errorf("PostModelBid event not found in transaction logs") + return common.Hash{}, nil } -func (g *Marketplace) DeleteBid(opts *bind.TransactOpts, bidId common.Hash) (common.Hash, error) { - tx, err := g.marketplace.DeleteModelAgentBid(opts, bidId) +func (g *Marketplace) DeleteBid(opts *bind.TransactOpts, bidID common.Hash) (common.Hash, error) { + tx, err := g.marketplace.DeleteModelBid(opts, bidID) if err != nil { return common.Hash{}, lib.TryConvertGethError(err) } // Wait for the transaction receipt receipt, err := bind.WaitMined(opts.Context, g.client, tx) - if err != nil { return common.Hash{}, lib.TryConvertGethError(err) } - // Find the event log - for _, log := range receipt.Logs { - // Check if the log belongs to the OpenSession event - _, err := g.marketplace.ParseBidDeleted(*log) - - if err != nil { - continue // not our event, skip it - } - - return tx.Hash(), nil + if receipt.Status != 1 { + return receipt.TxHash, fmt.Errorf("Transaction failed") } - return common.Hash{}, fmt.Errorf("BidDeleted event not found in transaction logs") + return receipt.TxHash, nil } -func (g *Marketplace) GetBidById(ctx context.Context, bidId [32]byte) (*marketplace.Bid, error) { - bid, err := g.marketplace.BidMap(&bind.CallOpts{Context: ctx}, bidId) +func (g *Marketplace) GetBidById(ctx context.Context, bidID common.Hash) (*marketplace.IBidStorageBid, error) { + bid, err := g.marketplace.GetBid(&bind.CallOpts{Context: ctx}, bidID) if err != nil { return nil, err } return &bid, nil } -func (g *Marketplace) GetBestBidByModelId(ctx context.Context, modelId common.Hash) (common.Hash, *marketplace.Bid, error) { - limit := uint8(100) +func (g *Marketplace) GetBestBidByModelId(ctx context.Context, modelID common.Hash) (common.Hash, *marketplace.IBidStorageBid, error) { + limit := big.NewInt(100) offset := big.NewInt(0) - ids, bids, err := g.marketplace.GetBidsByModelAgent(&bind.CallOpts{Context: ctx}, modelId, offset, limit) + bidIDs, _, err := g.marketplace.GetModelActiveBids(&bind.CallOpts{Context: ctx}, modelID, offset, limit) if err != nil { return common.Hash{}, nil, err } - // TODO: replace with a rating system - cheapestBid := bids[0] - idIndex := 0 - for i, bid := range bids { - if bid.PricePerSecond.Cmp(cheapestBid.PricePerSecond) < 0 { - cheapestBid = bid - idIndex = i - } - } + var cheapestBidID common.Hash + var cheapestBid *marketplace.IBidStorageBid - return ids[idIndex], &cheapestBid, nil -} + for _, bidID := range bidIDs { + bid, err := g.marketplace.GetBid(&bind.CallOpts{Context: ctx}, bidID) + if err != nil { + return common.Hash{}, nil, err + } + if cheapestBid == nil { + cheapestBid = &bid + cheapestBidID = bidID -func (g *Marketplace) GetAllBidsWithRating(ctx context.Context, modelAgentID [32]byte) ([][32]byte, []marketplace.Bid, []marketplace.ProviderModelStats, error) { - batchSize := uint8(255) - return collectBids(ctx, modelAgentID, g.GetBidsWithRating, batchSize) -} + } else if bid.PricePerSecond.Cmp(cheapestBid.PricePerSecond) < 0 { + cheapestBid = &bid + cheapestBidID = bidID + } + } -func (g *Marketplace) GetBidsWithRating(ctx context.Context, modelAgentID [32]byte, offset *big.Int, limit uint8) ([][32]byte, []marketplace.Bid, []marketplace.ProviderModelStats, error) { - return g.marketplace.GetActiveBidsRatingByModelAgent(&bind.CallOpts{Context: ctx}, modelAgentID, offset, limit) + return cheapestBidID, cheapestBid, nil } -func (g *Marketplace) GetModelStats(ctx context.Context, modelID [32]byte) (marketplace.ModelStats, error) { - return g.marketplace.GetModelStats(&bind.CallOpts{Context: ctx}, modelID) -} +func (g *Marketplace) GetBidsByProvider(ctx context.Context, provider common.Address, offset *big.Int, limit uint8, order Order) ([][32]byte, []marketplace.IBidStorageBid, error) { + _, len, err := g.marketplace.GetProviderBids(&bind.CallOpts{Context: ctx}, provider, big.NewInt(0), big.NewInt(0)) + if err != nil { + return nil, nil, err + } -func (g *Marketplace) GetBidsByProvider(ctx context.Context, provider common.Address, offset *big.Int, limit uint8) ([][32]byte, []marketplace.Bid, error) { - return g.marketplace.GetBidsByProvider(&bind.CallOpts{Context: ctx}, provider, offset, limit) -} + _offset, _limit := adjustPagination(order, len, offset, limit) + bidIDs, _, err := g.marketplace.GetProviderBids(&bind.CallOpts{Context: ctx}, provider, _offset, _limit) + if err != nil { + return nil, nil, err + } -func (g *Marketplace) GetBidsByModelAgent(ctx context.Context, modelAgentId common.Hash, offset *big.Int, limit uint8) ([][32]byte, []marketplace.Bid, error) { - return g.marketplace.GetBidsByModelAgent(&bind.CallOpts{Context: ctx}, modelAgentId, offset, limit) + adjustOrder(order, bidIDs) + return g.GetMultipleBids(ctx, bidIDs) } -func (g *Marketplace) GetActiveBidsByProvider(ctx context.Context, provider common.Address) ([][32]byte, []marketplace.Bid, error) { - return g.marketplace.GetActiveBidsByProvider(&bind.CallOpts{Context: ctx}, provider) +func (g *Marketplace) GetBidsByModelAgent(ctx context.Context, modelAgentId common.Hash, offset *big.Int, limit uint8, order Order) ([][32]byte, []marketplace.IBidStorageBid, error) { + _, len, err := g.marketplace.GetModelBids(&bind.CallOpts{Context: ctx}, modelAgentId, big.NewInt(0), big.NewInt(0)) + if err != nil { + return nil, nil, err + } + _offset, _limit := adjustPagination(order, len, offset, limit) + bidIDs, _, err := g.marketplace.GetModelBids(&bind.CallOpts{Context: ctx}, modelAgentId, _offset, _limit) + if err != nil { + return nil, nil, err + } + adjustOrder(order, bidIDs) + return g.GetMultipleBids(ctx, bidIDs) } -func (g *Marketplace) GetActiveBidsByModel(ctx context.Context, modelAgentId common.Hash) ([][32]byte, []marketplace.Bid, error) { - return g.marketplace.GetActiveBidsByModelAgent(&bind.CallOpts{Context: ctx}, modelAgentId) +func (g *Marketplace) GetActiveBidsByProviderCount(ctx context.Context, provider common.Address) (*big.Int, error) { + _, len, err := g.marketplace.GetProviderActiveBids(&bind.CallOpts{Context: ctx}, provider, big.NewInt(0), big.NewInt(0)) + if err != nil { + return nil, err + } + return len, nil } -type BidsGetter = func(ctx context.Context, modelAgentID [32]byte, offset *big.Int, limit uint8) ([][32]byte, []marketplace.Bid, []marketplace.ProviderModelStats, error) - -func collectBids(ctx context.Context, modelAgentID [32]byte, bidsGetter BidsGetter, batchSize uint8) ([][32]byte, []marketplace.Bid, []marketplace.ProviderModelStats, error) { - offset := big.NewInt(0) - bids := make([]marketplace.Bid, 0) - ids := make([][32]byte, 0) - providerModelStats := make([]marketplace.ProviderModelStats, 0) +func (g *Marketplace) GetActiveBidsByProvider(ctx context.Context, provider common.Address, offset *big.Int, limit uint8, order Order) ([][32]byte, []marketplace.IBidStorageBid, error) { + len, err := g.GetActiveBidsByProviderCount(ctx, provider) + if err != nil { + return nil, nil, err + } - for { - if ctx.Err() != nil { - return nil, nil, nil, ctx.Err() - } + _offset, _limit := adjustPagination(order, len, offset, limit) + bidIDs, _, err := g.marketplace.GetProviderActiveBids(&bind.CallOpts{Context: ctx}, provider, _offset, _limit) + if err != nil { + return nil, nil, err + } - idsBatch, bidsBatch, providerModelStatsBatch, err := bidsGetter(ctx, modelAgentID, offset, batchSize) - if err != nil { - return nil, nil, nil, err - } + adjustOrder(order, bidIDs) + return g.GetMultipleBids(ctx, bidIDs) +} - ids = append(ids, idsBatch...) - bids = append(bids, bidsBatch...) - providerModelStats = append(providerModelStats, providerModelStatsBatch...) +func (g *Marketplace) GetActiveBidsByModel(ctx context.Context, modelAgentId common.Hash, offset *big.Int, limit uint8, order Order) ([][32]byte, []marketplace.IBidStorageBid, error) { + _, len, err := g.marketplace.GetModelActiveBids(&bind.CallOpts{Context: ctx}, modelAgentId, big.NewInt(0), big.NewInt(0)) + if err != nil { + return nil, nil, err + } + _offset, _limit := adjustPagination(order, len, offset, limit) + bidIDs, _, err := g.marketplace.GetModelActiveBids(&bind.CallOpts{Context: ctx}, modelAgentId, _offset, _limit) + if err != nil { + return nil, nil, err + } + adjustOrder(order, bidIDs) + return g.GetMultipleBids(ctx, bidIDs) +} - if len(bidsBatch) < int(batchSize) { - break - } +func (g *Marketplace) GetMultipleBids(ctx context.Context, IDs [][32]byte) ([][32]byte, []marketplace.IBidStorageBid, error) { + args := make([][]interface{}, len(IDs)) + for i, id := range IDs { + args[i] = []interface{}{id} + } + bids, err := mc.Batch[marketplace.IBidStorageBid](ctx, g.multicall, g.marketplaceABI, g.marketplaceAddr, "getBid", args) + if err != nil { + return nil, nil, err + } + return IDs, bids, nil +} - offset.Add(offset, big.NewInt(int64(batchSize))) +func (g *Marketplace) GetBidFee(ctx context.Context) (*big.Int, error) { + fee, err := g.marketplace.GetBidFee(&bind.CallOpts{Context: ctx}) + if err != nil { + return nil, lib.TryConvertGethError(err) } + return fee, nil +} - return ids, bids, providerModelStats, nil +func (g *Marketplace) GetMinMaxBidPricePerSecond(ctx context.Context) (*big.Int, *big.Int, error) { + min, max, err := g.marketplace.GetMinMaxBidPricePerSecond(&bind.CallOpts{Context: ctx}) + if err != nil { + return nil, nil, lib.TryConvertGethError(err) + } + return min, max, nil } diff --git a/proxy-router/internal/repositories/registries/marketplace_test.go b/proxy-router/internal/repositories/registries/marketplace_test.go index ed54689c..2c674eeb 100644 --- a/proxy-router/internal/repositories/registries/marketplace_test.go +++ b/proxy-router/internal/repositories/registries/marketplace_test.go @@ -5,40 +5,39 @@ import ( "math/big" "testing" - "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/contracts/marketplace" - "github.com/stretchr/testify/require" + "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/repositories/contracts/bindings/sessionrouter" ) func TestCollectBids(t *testing.T) { - bidIDs, bids, stats, err := collectBids(context.TODO(), [32]byte{0x01}, bidsGetter1000, 100) - require.NoError(t, err) - require.Len(t, bidIDs, 1000) - require.Len(t, bids, 1000) - require.Len(t, stats, 1000) + // bidIDs, bids, stats, err := collectBids(context.TODO(), [32]byte{0x01}, bidsGetter1000, 100) + // require.NoError(t, err) + // require.Len(t, bidIDs, 1000) + // require.Len(t, bids, 1000) + // require.Len(t, stats, 1000) } // bidsGetter1000 simulates a paginated query to get all bids for a model -func bidsGetter1000(ctx context.Context, modelId [32]byte, offset *big.Int, limit uint8) ([][32]byte, []marketplace.Bid, []marketplace.ProviderModelStats, error) { +func bidsGetter1000(ctx context.Context, modelId [32]byte, offset *big.Int, limit uint8) ([][32]byte, []sessionrouter.IBidStorageBid, []sessionrouter.IStatsStorageProviderModelStats, error) { maxItems := 1000 ids := [][32]byte{} - bids := []marketplace.Bid{} - stats := []marketplace.ProviderModelStats{} + bids := []sessionrouter.IBidStorageBid{} + stats := []sessionrouter.IStatsStorageProviderModelStats{} for i := offset.Int64(); i < offset.Int64()+int64(limit); i++ { if i >= int64(maxItems) { break } ids = append(ids, [32]byte{byte(i)}) - bids = append(bids, marketplace.Bid{ + bids = append(bids, sessionrouter.IBidStorageBid{ PricePerSecond: big.NewInt(i), Provider: [20]byte{byte(i)}, - ModelAgentId: modelId, + ModelId: modelId, Nonce: big.NewInt(i), CreatedAt: big.NewInt(i), DeletedAt: big.NewInt(i), }) - stats = append(stats, marketplace.ProviderModelStats{ - TpsScaled1000: marketplace.LibSDSD{}, - TtftMs: marketplace.LibSDSD{}, + stats = append(stats, sessionrouter.IStatsStorageProviderModelStats{ + TpsScaled1000: sessionrouter.LibSDSD{}, + TtftMs: sessionrouter.LibSDSD{}, TotalDuration: uint32(i), SuccessCount: uint32(i), TotalCount: uint32(i), diff --git a/proxy-router/internal/repositories/registries/model_registry.go b/proxy-router/internal/repositories/registries/model_registry.go index 05b9b58d..e3947457 100644 --- a/proxy-router/internal/repositories/registries/model_registry.go +++ b/proxy-router/internal/repositories/registries/model_registry.go @@ -3,12 +3,15 @@ package registries import ( "context" "fmt" + "math/big" - "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/contracts/modelregistry" + i "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/interfaces" "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/lib" + "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/repositories/contracts/bindings/modelregistry" + mc "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/repositories/multicall" + "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/ethclient" ) type ModelRegistry struct { @@ -19,35 +22,71 @@ type ModelRegistry struct { nonce uint64 // deps - modelRegistry *modelregistry.ModelRegistry - client *ethclient.Client - log lib.ILogger + modelRegistry *modelregistry.ModelRegistry + modelRegistryAbi *abi.ABI + multicall mc.MulticallBackend + client i.ContractBackend + log lib.ILogger } -func NewModelRegistry(modelRegistryAddr common.Address, client *ethclient.Client, log lib.ILogger) *ModelRegistry { +func NewModelRegistry(modelRegistryAddr common.Address, client i.ContractBackend, multicall mc.MulticallBackend, log lib.ILogger) *ModelRegistry { mr, err := modelregistry.NewModelRegistry(modelRegistryAddr, client) if err != nil { panic("invalid model registry ABI") } + mrAbi, err := modelregistry.ModelRegistryMetaData.GetAbi() + if err != nil { + panic("invalid model registry ABI") + } return &ModelRegistry{ modelRegistry: mr, modelRegistryAddr: modelRegistryAddr, + modelRegistryAbi: mrAbi, + multicall: multicall, client: client, log: log, } } -func (g *ModelRegistry) GetAllModels(ctx context.Context) ([][32]byte, []modelregistry.Model, error) { - adresses, models, err := g.modelRegistry.ModelGetAll(&bind.CallOpts{Context: ctx}) +func (g *ModelRegistry) GetAllModels(ctx context.Context) ([][32]byte, []modelregistry.IModelStorageModel, error) { + batchSize := 100 + offset := big.NewInt(0) + var allIDs [][32]byte + var allModels []modelregistry.IModelStorageModel + for { + ids, providers, err := g.GetModels(ctx, offset, uint8(batchSize), OrderASC) + if err != nil { + return nil, nil, err + } + if len(ids) == 0 { + break + } + allModels = append(allModels, providers...) + allIDs = append(allIDs, ids...) + if len(ids) < batchSize { + break + } + offset.Add(offset, big.NewInt(int64(batchSize))) + } + return allIDs, allModels, nil +} + +func (g *ModelRegistry) GetModels(ctx context.Context, offset *big.Int, limit uint8, order Order) ([][32]byte, []modelregistry.IModelStorageModel, error) { + _, len, err := g.modelRegistry.GetActiveModelIds(&bind.CallOpts{Context: ctx}, big.NewInt(0), big.NewInt(0)) if err != nil { return nil, nil, err } - - return adresses, models, nil + _offset, _limit := adjustPagination(order, len, offset, limit) + ids, _, err := g.modelRegistry.GetActiveModelIds(&bind.CallOpts{Context: ctx}, _offset, _limit) + if err != nil { + return nil, nil, err + } + adjustOrder(order, ids) + return g.getMultipleModels(ctx, ids) } -func (g *ModelRegistry) CreateNewModel(opts *bind.TransactOpts, modelId common.Hash, ipfsID common.Hash, fee *lib.BigInt, stake *lib.BigInt, owner common.Address, name string, tags []string) error { - tx, err := g.modelRegistry.ModelRegister(opts, modelId, ipfsID, &fee.Int, &stake.Int, owner, name, tags) +func (g *ModelRegistry) CreateNewModel(opts *bind.TransactOpts, modelId common.Hash, ipfsID common.Hash, fee *lib.BigInt, stake *lib.BigInt, name string, tags []string) error { + tx, err := g.modelRegistry.ModelRegister(opts, opts.From, modelId, ipfsID, &fee.Int, &stake.Int, name, tags) if err != nil { return lib.TryConvertGethError(err) } @@ -99,10 +138,30 @@ func (g *ModelRegistry) DeregisterModel(opts *bind.TransactOpts, modelId common. return common.Hash{}, fmt.Errorf("ModelDeregistered event not found in transaction logs") } -func (g *ModelRegistry) GetModelById(ctx context.Context, modelId common.Hash) (*modelregistry.Model, error) { - model, err := g.modelRegistry.ModelMap(&bind.CallOpts{Context: ctx}, modelId) +func (g *ModelRegistry) GetModelById(ctx context.Context, modelId common.Hash) (*modelregistry.IModelStorageModel, error) { + model, err := g.modelRegistry.GetModel(&bind.CallOpts{Context: ctx}, modelId) if err != nil { return nil, err } return &model, nil } + +func (g *ModelRegistry) GetModelId(ctx context.Context, accountAddr common.Address, baseModelId common.Hash) (common.Hash, error) { + id, err := g.modelRegistry.GetModelId(&bind.CallOpts{Context: ctx}, accountAddr, baseModelId) + if err != nil { + return common.Hash{}, err + } + return id, nil +} + +func (g *ModelRegistry) getMultipleModels(ctx context.Context, IDs [][32]byte) ([][32]byte, []modelregistry.IModelStorageModel, error) { + args := make([][]interface{}, len(IDs)) + for i, id := range IDs { + args[i] = []interface{}{id} + } + models, err := mc.Batch[modelregistry.IModelStorageModel](ctx, g.multicall, g.modelRegistryAbi, g.modelRegistryAddr, "getModel", args) + if err != nil { + return nil, nil, err + } + return IDs, models, nil +} diff --git a/proxy-router/internal/repositories/registries/mor_token.go b/proxy-router/internal/repositories/registries/mor_token.go index b5986301..9ecd9398 100644 --- a/proxy-router/internal/repositories/registries/mor_token.go +++ b/proxy-router/internal/repositories/registries/mor_token.go @@ -4,13 +4,13 @@ import ( "context" "math/big" - "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/contracts/morpheustoken" + i "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/interfaces" "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/lib" + "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/repositories/contracts/bindings/morpheustoken" "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/ethclient" ) type MorToken struct { @@ -23,11 +23,11 @@ type MorToken struct { // deps mor *morpheustoken.MorpheusToken - client *ethclient.Client + client i.ContractBackend log lib.ILogger } -func NewMorToken(morTokenAddr common.Address, client *ethclient.Client, log lib.ILogger) *MorToken { +func NewMorToken(morTokenAddr common.Address, client i.ContractBackend, log lib.ILogger) *MorToken { mor, err := morpheustoken.NewMorpheusToken(morTokenAddr, client) if err != nil { panic("invalid mor ABI") diff --git a/proxy-router/internal/repositories/registries/pagination.go b/proxy-router/internal/repositories/registries/pagination.go new file mode 100644 index 00000000..023b1156 --- /dev/null +++ b/proxy-router/internal/repositories/registries/pagination.go @@ -0,0 +1,59 @@ +package registries + +import ( + "math/big" + "slices" +) + +type Order = bool + +const ( + OrderASC Order = false + OrderDESC Order = true +) + +// function to "reverse" pagination based on the desired ordering +func adjustPagination(order Order, length *big.Int, offset *big.Int, limit uint8) (newOffset *big.Int, newLimit *big.Int) { + newOffset, newLimit = new(big.Int), new(big.Int) + + // if offset is larger than the length of the array, + // just return empty array + if offset.Cmp(length) >= 0 { + return newOffset, newLimit + } + + newOffset.Set(offset) + newLimit.SetUint64(uint64(limit)) + + // calculate the remaining elements at the end of the array + remainingAtEnd := new(big.Int).Add(offset, newLimit) + remainingAtEnd.Sub(length, remainingAtEnd) + + if remainingAtEnd.Sign() < 0 { + // means that offset+limit is out of bounds, + // so limit has to be reduced by the amount of overflow + newLimit.Add(newLimit, remainingAtEnd) + } + + // if the order is DESC, the offset has to be adjusted + if order == OrderDESC { + newOffset.Set(max(remainingAtEnd, big.NewInt(0))) + } + + return newOffset, newLimit +} + +// adjustOrder in-plase reverses the order of the array if the order is DESC +func adjustOrder[T any](order Order, arr []T) { + if order == OrderASC { + return + } + slices.Reverse(arr) +} + +func max(a, b *big.Int) *big.Int { + if a.Cmp(b) > 0 { + return a + } + return b +} diff --git a/proxy-router/internal/repositories/registries/pagination_test.go b/proxy-router/internal/repositories/registries/pagination_test.go new file mode 100644 index 00000000..76c487ad --- /dev/null +++ b/proxy-router/internal/repositories/registries/pagination_test.go @@ -0,0 +1,76 @@ +package registries + +import ( + "math/big" + "testing" + + "github.com/stretchr/testify/require" +) + +func TestOffsetLimit(t *testing.T) { + type args struct { + order Order + length *big.Int + offset *big.Int + limit uint8 + } + + type want struct { + offset *big.Int + limit *big.Int + } + + tests := []struct { + name string + args args + want want + }{ + { + name: "ASC within bounds", + args: args{order: OrderASC, length: big.NewInt(10), offset: big.NewInt(0), limit: 5}, + want: want{offset: big.NewInt(0), limit: big.NewInt(5)}, + }, + { + name: "ASC offset out of bounds", + args: args{order: OrderASC, length: big.NewInt(10), offset: big.NewInt(15), limit: 5}, + want: want{offset: big.NewInt(0), limit: big.NewInt(0)}, + }, + { + name: "ASC limit out of bounds", + args: args{order: OrderASC, length: big.NewInt(10), offset: big.NewInt(5), limit: 10}, + want: want{offset: big.NewInt(5), limit: big.NewInt(5)}, + }, + { + name: "ASC offset and limit out of bounds", + args: args{order: OrderASC, length: big.NewInt(10), offset: big.NewInt(15), limit: 15}, + want: want{offset: big.NewInt(0), limit: big.NewInt(0)}, + }, + { + name: "DESC within bounds", + args: args{order: OrderDESC, length: big.NewInt(10), offset: big.NewInt(0), limit: 5}, + want: want{offset: big.NewInt(5), limit: big.NewInt(5)}, + }, + { + name: "DESC offset out of bounds", + args: args{order: OrderDESC, length: big.NewInt(10), offset: big.NewInt(15), limit: 5}, + want: want{offset: big.NewInt(0), limit: big.NewInt(0)}, + }, + { + name: "DESC limit out of bounds", + args: args{order: OrderDESC, length: big.NewInt(10), offset: big.NewInt(5), limit: 10}, + want: want{offset: big.NewInt(0), limit: big.NewInt(5)}, + }, + { + name: "DESC offset and limit out of bounds", + args: args{order: OrderDESC, length: big.NewInt(10), offset: big.NewInt(15), limit: 15}, + want: want{offset: big.NewInt(0), limit: big.NewInt(0)}, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + newOffset, newLimit := adjustPagination(tt.args.order, tt.args.length, tt.args.offset, tt.args.limit) + require.Equalf(t, tt.want.offset.Cmp(newOffset), 0, "expected offset %v, got %v", tt.want.offset, newOffset) + require.Equalf(t, tt.want.limit.Cmp(newLimit), 0, "expected limit %v, got %v", tt.want.limit, newLimit) + }) + } +} diff --git a/proxy-router/internal/repositories/registries/provider_registry.go b/proxy-router/internal/repositories/registries/provider_registry.go index 66afb10a..dfc90d08 100644 --- a/proxy-router/internal/repositories/registries/provider_registry.go +++ b/proxy-router/internal/repositories/registries/provider_registry.go @@ -3,12 +3,15 @@ package registries import ( "context" "fmt" + "math/big" - "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/contracts/providerregistry" + i "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/interfaces" "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/lib" + "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/repositories/contracts/bindings/providerregistry" + mc "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/repositories/multicall" + "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/ethclient" ) type ProviderRegistry struct { @@ -19,40 +22,73 @@ type ProviderRegistry struct { nonce uint64 // deps - providerRegistry *providerregistry.ProviderRegistry - client *ethclient.Client - log lib.ILogger + providerRegistry *providerregistry.ProviderRegistry + providerRegistryAbi *abi.ABI + client i.ContractBackend + multicall mc.MulticallBackend + log lib.ILogger } -func NewProviderRegistry(providerRegistryAddr common.Address, client *ethclient.Client, log lib.ILogger) *ProviderRegistry { +func NewProviderRegistry(providerRegistryAddr common.Address, client i.ContractBackend, multicall mc.MulticallBackend, log lib.ILogger) *ProviderRegistry { pr, err := providerregistry.NewProviderRegistry(providerRegistryAddr, client) if err != nil { panic("invalid provider registry ABI") } + providerRegistryAbi, err := providerregistry.ProviderRegistryMetaData.GetAbi() + if err != nil { + panic("invalid provider registry ABI") + } return &ProviderRegistry{ providerRegistry: pr, providerRegistryAddr: providerRegistryAddr, + providerRegistryAbi: providerRegistryAbi, + multicall: multicall, client: client, log: log, } } -func (g *ProviderRegistry) GetAllProviders(ctx context.Context) ([]common.Address, []providerregistry.Provider, error) { - providerAddrs, providers, err := g.providerRegistry.ProviderGetAll(&bind.CallOpts{Context: ctx}) +func (g *ProviderRegistry) GetAllProviders(ctx context.Context) ([]common.Address, []providerregistry.IProviderStorageProvider, error) { + batchSize := 100 + offset := big.NewInt(0) + var allIDs []common.Address + var allProviders []providerregistry.IProviderStorageProvider + for { + ids, providers, err := g.GetProviders(ctx, offset, uint8(batchSize), OrderASC) + if err != nil { + return nil, nil, err + } + if len(ids) == 0 { + break + } + allProviders = append(allProviders, providers...) + allIDs = append(allIDs, ids...) + if len(ids) < batchSize { + break + } + offset.Add(offset, big.NewInt(int64(batchSize))) + } + return allIDs, allProviders, nil +} + +func (g *ProviderRegistry) GetProviders(ctx context.Context, offset *big.Int, limit uint8, order Order) ([]common.Address, []providerregistry.IProviderStorageProvider, error) { + _, len, err := g.providerRegistry.GetActiveProviders(&bind.CallOpts{Context: ctx}, big.NewInt(0), big.NewInt(0)) if err != nil { return nil, nil, err } - addresses := make([]common.Address, len(providerAddrs)) - for i, address := range providerAddrs { - addresses[i] = address + _offset, _limit := adjustPagination(order, len, offset, limit) + ids, _, err := g.providerRegistry.GetActiveProviders(&bind.CallOpts{Context: ctx}, _offset, _limit) + if err != nil { + return nil, nil, err } - return addresses, providers, nil + adjustOrder(order, ids) + return g.getMultipleProviders(ctx, ids) } -func (g *ProviderRegistry) CreateNewProvider(opts *bind.TransactOpts, address common.Address, addStake *lib.BigInt, endpoint string) error { - providerTx, err := g.providerRegistry.ProviderRegister(opts, address, &addStake.Int, endpoint) +func (g *ProviderRegistry) CreateNewProvider(opts *bind.TransactOpts, addStake *lib.BigInt, endpoint string) error { + providerTx, err := g.providerRegistry.ProviderRegister(opts, opts.From, &addStake.Int, endpoint) if err != nil { return lib.TryConvertGethError(err) @@ -64,23 +100,15 @@ func (g *ProviderRegistry) CreateNewProvider(opts *bind.TransactOpts, address co return lib.TryConvertGethError(err) } - // Find the event log - for _, log := range receipt.Logs { - // Check if the log belongs to the OpenSession event - _, err := g.providerRegistry.ParseProviderRegisteredUpdated(*log) - - if err != nil { - continue // not our event, skip it - } - - return nil + if receipt.Status != 1 { + return fmt.Errorf("Transaction failed with status %d", receipt.Status) } - return fmt.Errorf("OpenSession event not found in transaction logs") + return nil } -func (g *ProviderRegistry) DeregisterProvider(opts *bind.TransactOpts, address common.Address) (common.Hash, error) { - providerTx, err := g.providerRegistry.ProviderDeregister(opts, address) +func (g *ProviderRegistry) DeregisterProvider(opts *bind.TransactOpts) (common.Hash, error) { + providerTx, err := g.providerRegistry.ProviderDeregister(opts, opts.From) if err != nil { return common.Hash{}, lib.TryConvertGethError(err) @@ -92,25 +120,39 @@ func (g *ProviderRegistry) DeregisterProvider(opts *bind.TransactOpts, address c return common.Hash{}, lib.TryConvertGethError(err) } - // Find the event log - for _, log := range receipt.Logs { - _, err := g.providerRegistry.ParseProviderDeregistered(*log) + if receipt.Status != 1 { + return receipt.TxHash, fmt.Errorf("Transaction failed with status %d", receipt.Status) + } - if err != nil { - continue // not our event, skip it - } + return receipt.TxHash, nil +} - return providerTx.Hash(), nil +func (g *ProviderRegistry) GetProviderById(ctx context.Context, id common.Address) (*providerregistry.IProviderStorageProvider, error) { + provider, err := g.providerRegistry.GetProvider(&bind.CallOpts{Context: ctx}, id) + if err != nil { + return nil, err } - return common.Hash{}, fmt.Errorf("ProviderDeregistered event not found in transaction logs") + return &provider, nil } -func (g *ProviderRegistry) GetProviderById(ctx context.Context, id common.Address) (*providerregistry.Provider, error) { - provider, err := g.providerRegistry.ProviderMap(&bind.CallOpts{Context: ctx}, id) +func (g *ProviderRegistry) GetMinStake(ctx context.Context) (*big.Int, error) { + minStake, err := g.providerRegistry.GetProviderMinimumStake(&bind.CallOpts{Context: ctx}) if err != nil { return nil, err } - return &provider, nil + return minStake, nil +} + +func (g *ProviderRegistry) getMultipleProviders(ctx context.Context, IDs []common.Address) ([]common.Address, []providerregistry.IProviderStorageProvider, error) { + args := make([][]interface{}, len(IDs)) + for i, id := range IDs { + args[i] = []interface{}{id} + } + providers, err := mc.Batch[providerregistry.IProviderStorageProvider](ctx, g.multicall, g.providerRegistryAbi, g.providerRegistryAddr, "getProvider", args) + if err != nil { + return nil, nil, err + } + return IDs, providers, nil } diff --git a/proxy-router/internal/repositories/registries/session_router.go b/proxy-router/internal/repositories/registries/session_router.go index 8a6e2551..366a79e1 100644 --- a/proxy-router/internal/repositories/registries/session_router.go +++ b/proxy-router/internal/repositories/registries/session_router.go @@ -6,12 +6,13 @@ import ( "math/big" "time" - "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/contracts/sessionrouter" + i "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/interfaces" "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/lib" + src "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/repositories/contracts/bindings/sessionrouter" + mc "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/repositories/multicall" "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/ethclient" ) type SessionRouter struct { @@ -20,11 +21,12 @@ type SessionRouter struct { // state nonce uint64 - srABI *abi.ABI // deps - sessionRouter *sessionrouter.SessionRouter - client *ethclient.Client + client i.ContractBackend + sessionRouter *src.SessionRouter + multicall mc.MulticallBackend + srABI *abi.ABI log lib.ILogger } @@ -34,26 +36,28 @@ var closeReportAbi = []lib.AbiParameter{ {Type: "uint32"}, } -func NewSessionRouter(sessionRouterAddr common.Address, client *ethclient.Client, log lib.ILogger) *SessionRouter { - sr, err := sessionrouter.NewSessionRouter(sessionRouterAddr, client) +func NewSessionRouter(sessionRouterAddr common.Address, client i.ContractBackend, multicall mc.MulticallBackend, log lib.ILogger) *SessionRouter { + sr, err := src.NewSessionRouter(sessionRouterAddr, client) if err != nil { panic("invalid marketplace ABI") } - srABI, err := sessionrouter.SessionRouterMetaData.GetAbi() + srABI, err := src.SessionRouterMetaData.GetAbi() if err != nil { panic("invalid marketplace ABI: " + err.Error()) } + return &SessionRouter{ sessionRouter: sr, sessionRouterAddr: sessionRouterAddr, client: client, srABI: srABI, + multicall: multicall, log: log, } } -func (g *SessionRouter) OpenSession(opts *bind.TransactOpts, approval []byte, approvalSig []byte, stake *big.Int, privateKeyHex lib.HexString) (sessionID common.Hash, providerID common.Address, userID common.Address, err error) { - sessionTx, err := g.sessionRouter.OpenSession(opts, stake, approval, approvalSig) +func (g *SessionRouter) OpenSession(opts *bind.TransactOpts, approval []byte, approvalSig []byte, stake *big.Int, directPayment bool, privateKeyHex lib.HexString) (sessionID common.Hash, providerID common.Address, userID common.Address, err error) { + sessionTx, err := g.sessionRouter.OpenSession(opts, opts.From, stake, directPayment, approval, approvalSig) if err != nil { return common.Hash{}, common.Address{}, common.Address{}, lib.TryConvertGethError(err) } @@ -64,19 +68,23 @@ func (g *SessionRouter) OpenSession(opts *bind.TransactOpts, approval []byte, ap return common.Hash{}, common.Address{}, common.Address{}, lib.TryConvertGethError(err) } + if receipt.Status != 1 { + return receipt.TxHash, common.Address{}, common.Address{}, fmt.Errorf("Transaction failed with status %d", receipt.Status) + } + // Find the event log for _, log := range receipt.Logs { // Check if the log belongs to the OpenSession event event, err := g.sessionRouter.ParseSessionOpened(*log) if err == nil { - return event.SessionId, event.ProviderId, event.UserAddress, nil + return event.SessionId, event.ProviderId, event.User, nil } } return common.Hash{}, common.Address{}, common.Address{}, fmt.Errorf("OpenSession event not found in transaction logs") } -func (g *SessionRouter) GetSession(ctx context.Context, sessionID common.Hash) (*sessionrouter.Session, error) { +func (g *SessionRouter) GetSession(ctx context.Context, sessionID common.Hash) (*src.ISessionStorageSession, error) { session, err := g.sessionRouter.GetSession(&bind.CallOpts{Context: ctx}, sessionID) if err != nil { return nil, err @@ -85,20 +93,61 @@ func (g *SessionRouter) GetSession(ctx context.Context, sessionID common.Hash) ( return &session, nil } -func (g *SessionRouter) GetSessionsByProvider(ctx context.Context, providerAddr common.Address, offset *big.Int, limit uint8) ([]sessionrouter.Session, error) { - sessions, err := g.sessionRouter.GetSessionsByProvider(&bind.CallOpts{Context: ctx}, providerAddr, offset, limit) +func (g *SessionRouter) GetSessionsByProvider(ctx context.Context, providerAddr common.Address, offset *big.Int, limit uint8, order Order) ([][32]byte, []src.ISessionStorageSession, error) { + _, length, err := g.sessionRouter.GetProviderSessions(&bind.CallOpts{Context: ctx}, providerAddr, big.NewInt(0), big.NewInt(0)) + if err != nil { + return nil, nil, lib.TryConvertGethError(err) + } + _offset, _limit := adjustPagination(order, length, offset, limit) + ids, _, err := g.sessionRouter.GetProviderSessions(&bind.CallOpts{Context: ctx}, providerAddr, _offset, _limit) + if err != nil { + return nil, nil, lib.TryConvertGethError(err) + } + adjustOrder(order, ids) + return g.getMultipleSessions(ctx, ids) +} + +func (g *SessionRouter) GetSessionsByUser(ctx context.Context, userAddr common.Address, offset *big.Int, limit uint8, order Order) ([][32]byte, []src.ISessionStorageSession, error) { + _, length, err := g.sessionRouter.GetUserSessions(&bind.CallOpts{Context: ctx}, userAddr, big.NewInt(0), big.NewInt(0)) + if err != nil { + return nil, nil, lib.TryConvertGethError(err) + } + + _offset, _limit := adjustPagination(order, length, offset, limit) + ids, _, err := g.sessionRouter.GetUserSessions(&bind.CallOpts{Context: ctx}, userAddr, _offset, _limit) + if err != nil { + return nil, nil, lib.TryConvertGethError(err) + } + adjustOrder(order, ids) + return g.getMultipleSessions(ctx, ids) +} + +func (g *SessionRouter) GetSessionsIdsByUser(ctx context.Context, userAddr common.Address, offset *big.Int, limit uint8, order Order) ([][32]byte, error) { + _, length, err := g.sessionRouter.GetUserSessions(&bind.CallOpts{Context: ctx}, userAddr, big.NewInt(0), big.NewInt(0)) if err != nil { return nil, lib.TryConvertGethError(err) } - return sessions, nil + _offset, _limit := adjustPagination(order, length, offset, limit) + IDs, _, err := g.sessionRouter.GetUserSessions(&bind.CallOpts{Context: ctx}, userAddr, _offset, _limit) + if err != nil { + return nil, lib.TryConvertGethError(err) + } + adjustOrder(order, IDs) + return IDs, nil } -func (g *SessionRouter) GetSessionsByUser(ctx context.Context, userAddr common.Address, offset *big.Int, limit uint8) ([]sessionrouter.Session, error) { - sessions, err := g.sessionRouter.GetSessionsByUser(&bind.CallOpts{Context: ctx}, userAddr, offset, limit) +func (g *SessionRouter) GetSessionsIDsByProvider(ctx context.Context, userAddr common.Address, offset *big.Int, limit uint8, order Order) ([][32]byte, error) { + _, length, err := g.sessionRouter.GetProviderSessions(&bind.CallOpts{Context: ctx}, userAddr, big.NewInt(0), big.NewInt(0)) if err != nil { return nil, lib.TryConvertGethError(err) } - return sessions, nil + _offset, _limit := adjustPagination(order, length, offset, limit) + IDs, _, err := g.sessionRouter.GetProviderSessions(&bind.CallOpts{Context: ctx}, userAddr, _offset, _limit) + if err != nil { + return nil, lib.TryConvertGethError(err) + } + adjustOrder(order, IDs) + return IDs, nil } func (g *SessionRouter) CloseSession(opts *bind.TransactOpts, sessionID common.Hash, report []byte, signedReport []byte, privateKeyHex lib.HexString) (common.Hash, error) { @@ -108,24 +157,49 @@ func (g *SessionRouter) CloseSession(opts *bind.TransactOpts, sessionID common.H } // Wait for the transaction receipt - _, err = bind.WaitMined(opts.Context, g.client, sessionTx) + receipt, err := bind.WaitMined(opts.Context, g.client, sessionTx) if err != nil { return common.Hash{}, err } + if receipt.Status != 1 { + return receipt.TxHash, fmt.Errorf("Transaction failed with status %d", receipt.Status) + } + return sessionTx.Hash(), nil } func (g *SessionRouter) GetProviderClaimableBalance(ctx context.Context, sessionId [32]byte) (*big.Int, error) { - balance, err := g.sessionRouter.GetProviderClaimableBalance(&bind.CallOpts{Context: ctx}, sessionId) + session, err := g.sessionRouter.GetSession(&bind.CallOpts{Context: ctx}, sessionId) + if err != nil { + return nil, lib.TryConvertGethError(err) + } + + bid, err := g.sessionRouter.GetBid(&bind.CallOpts{Context: ctx}, session.BidId) if err != nil { return nil, lib.TryConvertGethError(err) } - return balance, nil + + var sessionEnd *big.Int + if session.ClosedAt.Cmp(big.NewInt(0)) == 0 { + sessionEnd = session.EndsAt + } else { + sessionEnd = session.ClosedAt + } + + if sessionEnd.Cmp(big.NewInt(time.Now().Unix())) > 0 { + return nil, fmt.Errorf("session not ended or does not exist") + } + + duration := new(big.Int).Sub(sessionEnd, session.OpenedAt) + amount := new(big.Int).Mul(duration, bid.PricePerSecond) + amount.Sub(amount, session.ProviderWithdrawnAmount) + + return amount, nil } -func (g *SessionRouter) ClaimProviderBalance(opts *bind.TransactOpts, sessionId [32]byte, amount *big.Int) (common.Hash, error) { - tx, err := g.sessionRouter.ClaimProviderBalance(opts, sessionId, amount) +func (g *SessionRouter) ClaimProviderBalance(opts *bind.TransactOpts, sessionId [32]byte) (common.Hash, error) { + tx, err := g.sessionRouter.ClaimForProvider(opts, sessionId) if err != nil { return common.Hash{}, lib.TryConvertGethError(err) } @@ -139,8 +213,7 @@ func (g *SessionRouter) ClaimProviderBalance(opts *bind.TransactOpts, sessionId return tx.Hash(), nil } -func (g *SessionRouter) GetTodaysBudget(ctx context.Context) (*big.Int, error) { - timestamp := big.NewInt(time.Now().Unix()) +func (g *SessionRouter) GetTodaysBudget(ctx context.Context, timestamp *big.Int) (*big.Int, error) { budget, err := g.sessionRouter.GetTodaysBudget(&bind.CallOpts{Context: ctx}, timestamp) if err != nil { return nil, lib.TryConvertGethError(err) @@ -148,6 +221,22 @@ func (g *SessionRouter) GetTodaysBudget(ctx context.Context) (*big.Int, error) { return budget, nil } +func (g *SessionRouter) GetModelStats(ctx context.Context, modelID [32]byte) (*src.IStatsStorageModelStats, error) { + res, err := g.sessionRouter.GetModelStats(&bind.CallOpts{Context: ctx}, modelID) + if err != nil { + return nil, lib.TryConvertGethError(err) + } + return &res, nil +} + +func (g *SessionRouter) GetProviderModelStats(ctx context.Context, modelID [32]byte, provider common.Address) (*src.IStatsStorageProviderModelStats, error) { + res, err := g.sessionRouter.GetProviderModelStats(&bind.CallOpts{Context: ctx}, modelID, provider) + if err != nil { + return nil, lib.TryConvertGethError(err) + } + return &res, nil +} + func (g *SessionRouter) GetContractAddress() common.Address { return g.sessionRouterAddr } @@ -155,3 +244,19 @@ func (g *SessionRouter) GetContractAddress() common.Address { func (g *SessionRouter) GetABI() *abi.ABI { return g.srABI } + +func (g *SessionRouter) GetTotalMORSupply(ctx context.Context, timestamp *big.Int) (*big.Int, error) { + return g.sessionRouter.TotalMORSupply(&bind.CallOpts{Context: ctx}, timestamp) +} + +func (g *SessionRouter) getMultipleSessions(ctx context.Context, IDs [][32]byte) ([][32]byte, []src.ISessionStorageSession, error) { + args := make([][]interface{}, len(IDs)) + for i, id := range IDs { + args[i] = []interface{}{id} + } + sessions, err := mc.Batch[src.ISessionStorageSession](ctx, g.multicall, g.srABI, g.sessionRouterAddr, "getSession", args) + if err != nil { + return nil, nil, err + } + return IDs, sessions, nil +} diff --git a/proxy-router/internal/repositories/registries/session_router_test.go b/proxy-router/internal/repositories/registries/session_router_test.go new file mode 100644 index 00000000..4c1ffdcf --- /dev/null +++ b/proxy-router/internal/repositories/registries/session_router_test.go @@ -0,0 +1,36 @@ +package registries + +import ( + "context" + "fmt" + "math/big" + "testing" + + "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/lib" + "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/repositories/multicall" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/ethclient" + "github.com/stretchr/testify/require" +) + +func TestGetSessions(t *testing.T) { + t.Skip() + ethNodeAddr := "" + ethClient, err := ethclient.Dial(ethNodeAddr) + require.NoError(t, err) + + mc := multicall.NewMulticall3(ethClient) + + diamondAddr := common.HexToAddress("0xb8C55cD613af947E73E262F0d3C54b7211Af16CF") + sr := NewSessionRouter(diamondAddr, ethClient, mc, lib.NewTestLogger()) + sessionIDs, err := sr.GetSessionsIDsByProvider(context.Background(), common.HexToAddress("0x1441Bc52156Cf18c12cde6A92aE6BDE8B7f775D4"), big.NewInt(0), 2, OrderASC) + require.NoError(t, err) + for _, sessionID := range sessionIDs { + fmt.Printf("sessionID: %v\n", common.Hash(sessionID).Hex()) + } + + _, sessions, err := sr.getMultipleSessions(context.Background(), sessionIDs) + require.NoError(t, err) + + fmt.Printf("sessions: %v\n", sessions[0].Stake) +} diff --git a/proxy-router/internal/repositories/session/session_model.go b/proxy-router/internal/repositories/session/session_model.go new file mode 100644 index 00000000..8136b685 --- /dev/null +++ b/proxy-router/internal/repositories/session/session_model.go @@ -0,0 +1,62 @@ +package sessionrepo + +import ( + "math/big" + + "github.com/ethereum/go-ethereum/common" +) + +type sessionModel struct { + id common.Hash + userAddr common.Address + providerAddr common.Address + endsAt *big.Int + modelID common.Hash + + tpsScaled1000Arr []int + ttftMsArr []int + failoverEnabled bool + directPayment bool +} + +func (s *sessionModel) ID() common.Hash { + return s.id +} + +func (s *sessionModel) UserAddr() common.Address { + return s.userAddr +} + +func (s *sessionModel) ProviderAddr() common.Address { + return s.providerAddr +} + +func (s *sessionModel) EndsAt() *big.Int { + // copy big.Int so that the original value is not modified + return new(big.Int).Set(s.endsAt) +} + +func (s *sessionModel) GetStats() (tpsScaled1000Arr []int, ttftMsArr []int) { + return s.tpsScaled1000Arr, s.ttftMsArr +} + +func (s *sessionModel) ModelID() common.Hash { + return s.modelID +} + +func (s *sessionModel) FailoverEnabled() bool { + return s.failoverEnabled +} + +func (s *sessionModel) DirectPayment() bool { + return s.directPayment +} + +func (s *sessionModel) AddStats(tpsScaled1000 int, ttftMs int) { + s.tpsScaled1000Arr = append(s.tpsScaled1000Arr, tpsScaled1000) + s.ttftMsArr = append(s.ttftMsArr, ttftMs) +} + +func (s *sessionModel) SetFailoverEnabled(enabled bool) { + s.failoverEnabled = enabled +} diff --git a/proxy-router/internal/repositories/session/session_repo.go b/proxy-router/internal/repositories/session/session_repo.go new file mode 100644 index 00000000..312fefe6 --- /dev/null +++ b/proxy-router/internal/repositories/session/session_repo.go @@ -0,0 +1,116 @@ +package sessionrepo + +import ( + "context" + + "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/repositories/registries" + "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/storages" + "github.com/ethereum/go-ethereum/common" +) + +type SessionRepositoryCached struct { + storage *storages.SessionStorage + reg *registries.SessionRouter + mkt *registries.Marketplace +} + +func NewSessionRepositoryCached(storage *storages.SessionStorage, reg *registries.SessionRouter, mkt *registries.Marketplace) *SessionRepositoryCached { + return &SessionRepositoryCached{ + storage: storage, + reg: reg, + mkt: mkt, + } +} + +// GetSession returns a session by its ID from the read-through cache +func (r *SessionRepositoryCached) GetSession(ctx context.Context, id common.Hash) (*sessionModel, error) { + ses, ok := r.getSessionFromCache(id) + if ok { + return ses, nil + } + + session, err := r.getSessionFromBlockchain(ctx, id) + if err != nil { + return nil, err + } + + err = r.saveSessionToCache(session) + if err != nil { + return nil, err + } + + return session, nil +} + +// SaveSession saves a session to the cache. Before saving it to cache you have to call GetSession +func (r *SessionRepositoryCached) SaveSession(ctx context.Context, ses *sessionModel) error { + return r.saveSessionToCache(ses) +} + +// RemoveSession removes a session from the cache +func (r *SessionRepositoryCached) RemoveSession(ctx context.Context, id common.Hash) error { + return r.storage.RemoveSession(id.Hex()) +} + +// RefreshSession refreshes the session cache by fetching the session from the blockchain +func (r *SessionRepositoryCached) RefreshSession(ctx context.Context, id common.Hash) error { + // since the session record in blockchain is immutable if we have it in cache it is noop + // if we don't have it in cache we need to fetch it and save it to cache + _, err := r.GetSession(ctx, id) + return err +} + +func (r *SessionRepositoryCached) getSessionFromBlockchain(ctx context.Context, id common.Hash) (*sessionModel, error) { + session, err := r.reg.GetSession(ctx, id) + if err != nil { + return nil, err + } + + bid, err := r.mkt.GetBidById(ctx, session.BidId) + if err != nil { + return nil, err + } + + return &sessionModel{ + id: id, + userAddr: session.User, + providerAddr: bid.Provider, + endsAt: session.EndsAt, + modelID: bid.ModelId, + tpsScaled1000Arr: []int{}, + ttftMsArr: []int{}, + failoverEnabled: false, + directPayment: session.IsDirectPaymentFromUser, + }, nil +} + +func (r *SessionRepositoryCached) getSessionFromCache(id common.Hash) (*sessionModel, bool) { + ses, ok := r.storage.GetSession(id.Hex()) + if !ok { + return nil, false + } + return &sessionModel{ + id: common.HexToHash(ses.Id), + userAddr: common.HexToAddress(ses.UserAddr), + providerAddr: common.HexToAddress(ses.ProviderAddr), + modelID: common.HexToHash(ses.ModelID), + endsAt: ses.EndsAt, + tpsScaled1000Arr: ses.TPSScaled1000Arr, + ttftMsArr: ses.TTFTMsArr, + failoverEnabled: ses.FailoverEnabled, + }, true +} + +func (r *SessionRepositoryCached) saveSessionToCache(ses *sessionModel) error { + return r.storage.AddSession(&storages.Session{ + Id: ses.id.Hex(), + UserAddr: ses.userAddr.Hex(), + ProviderAddr: ses.providerAddr.Hex(), + EndsAt: ses.endsAt, + ModelID: ses.modelID.Hex(), + TPSScaled1000Arr: ses.tpsScaled1000Arr, + TTFTMsArr: ses.ttftMsArr, + FailoverEnabled: ses.failoverEnabled, + DirectPayment: ses.directPayment, + }) +} diff --git a/proxy-router/internal/repositories/transport/tcp_server.go b/proxy-router/internal/repositories/transport/tcp_server.go index ba92ea20..5a19d0f4 100644 --- a/proxy-router/internal/repositories/transport/tcp_server.go +++ b/proxy-router/internal/repositories/transport/tcp_server.go @@ -14,12 +14,14 @@ import ( type TCPServer struct { serverAddr string handler Handler + started chan struct{} log lib.ILogger } func NewTCPServer(serverAddr string, log lib.ILogger) *TCPServer { return &TCPServer{ serverAddr: serverAddr, + started: make(chan struct{}), log: log, } } @@ -35,10 +37,10 @@ func (p *TCPServer) Run(ctx context.Context) error { } listener, err := net.Listen("tcp", add.String()) - if err != nil { return fmt.Errorf("listener error %s %w", p.serverAddr, err) } + close(p.started) p.log.Infof("tcp server is listening: %s", p.serverAddr) @@ -64,6 +66,10 @@ func (p *TCPServer) Run(ctx context.Context) error { return err } +func (p *TCPServer) Started() <-chan struct{} { + return p.started +} + func (p *TCPServer) startAccepting(ctx context.Context, listener net.Listener) error { wg := sync.WaitGroup{} // waits for all handlers to finish to ensure proper cleanup defer wg.Wait() diff --git a/proxy-router/internal/repositories/wallet/hdwallet.go b/proxy-router/internal/repositories/wallet/hdwallet.go new file mode 100644 index 00000000..0ff5ae43 --- /dev/null +++ b/proxy-router/internal/repositories/wallet/hdwallet.go @@ -0,0 +1,84 @@ +package wallet + +import ( + "crypto/ecdsa" + "errors" + + "github.com/btcsuite/btcd/chaincfg" + "github.com/btcsuite/btcutil/hdkeychain" + "github.com/ethereum/go-ethereum/accounts" + "github.com/ethereum/go-ethereum/common" + "github.com/tyler-smith/go-bip39" +) + +type Wallet struct { + mnemonic string + masterKey *hdkeychain.ExtendedKey + seed []byte + accounts []accounts.Account + paths map[common.Address]accounts.DerivationPath +} + +// NewFromMnemonic returns a new wallet from a BIP-39 mnemonic. +func NewFromMnemonic(mnemonic string, passOpt ...string) (*Wallet, error) { + seed, err := NewSeedFromMnemonic(mnemonic, passOpt...) + if err != nil { + return nil, err + } + + wallet, err := newWallet(seed) + if err != nil { + return nil, err + } + wallet.mnemonic = mnemonic + + return wallet, nil +} + +func newWallet(seed []byte) (*Wallet, error) { + masterKey, err := hdkeychain.NewMaster(seed, &chaincfg.MainNetParams) + if err != nil { + return nil, err + } + + return &Wallet{ + masterKey: masterKey, + seed: seed, + accounts: []accounts.Account{}, + paths: map[common.Address]accounts.DerivationPath{}, + }, nil +} + +// NewSeedFromMnemonic returns a BIP-39 seed based on a BIP-39 mnemonic. +func NewSeedFromMnemonic(mnemonic string, passOpt ...string) ([]byte, error) { + if mnemonic == "" { + return nil, errors.New("mnemonic is required") + } + + password := "" + if len(passOpt) > 0 { + password = passOpt[0] + } + + return bip39.NewSeedWithErrorChecking(mnemonic, password) +} + +// DerivePrivateKey derives the private key of the derivation path. +func (w *Wallet) DerivePrivateKey(path accounts.DerivationPath) (*ecdsa.PrivateKey, error) { + var err error + key := w.masterKey + for _, n := range path { + key, err = key.Derive(n) + if err != nil { + return nil, err + } + } + + privateKey, err := key.ECPrivKey() + privateKeyECDSA := privateKey.ToECDSA() + if err != nil { + return nil, err + } + + return privateKeyECDSA, nil +} diff --git a/proxy-router/internal/repositories/wallet/hdwallet_test.go b/proxy-router/internal/repositories/wallet/hdwallet_test.go new file mode 100644 index 00000000..e20a5d36 --- /dev/null +++ b/proxy-router/internal/repositories/wallet/hdwallet_test.go @@ -0,0 +1,30 @@ +package wallet + +import ( + "testing" + + "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/lib" + "github.com/ethereum/go-ethereum/accounts" + "github.com/ethereum/go-ethereum/common" + "github.com/stretchr/testify/require" +) + +func TestIssue172(t *testing.T) { + // https://github.com/btcsuite/btcutil/pull/182 + // makes sure that the private key is derived correctly + seed := common.FromHex("00000000000000500000000000000000") + path, err := accounts.ParseDerivationPath("m/44'/60'/0'/0/0") + require.NoError(t, err) + expectedAddr := common.HexToAddress("0xe39Be4d7E9D91D14e837589F3027798f3911A83c") + + wallet, err := newWallet(seed) + require.NoError(t, err) + + prkey, err := wallet.DerivePrivateKey(path) + require.NoError(t, err) + + addr, err := lib.PrivKeyToAddr(prkey) + require.NoError(t, err) + + require.Equal(t, expectedAddr, addr) +} diff --git a/proxy-router/internal/repositories/wallet/keychainwallet.go b/proxy-router/internal/repositories/wallet/keychainwallet.go index 6b6d2624..1530c367 100644 --- a/proxy-router/internal/repositories/wallet/keychainwallet.go +++ b/proxy-router/internal/repositories/wallet/keychainwallet.go @@ -4,9 +4,11 @@ import ( "errors" "sync" + i "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/interfaces" "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/lib" "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/repositories/keychain" - hdwallet "github.com/miguelmota/go-ethereum-hdwallet" + "github.com/ethereum/go-ethereum/accounts" + "github.com/ethereum/go-ethereum/crypto" ) const ( @@ -21,14 +23,14 @@ var ( ) type KeychainWallet struct { - storage *keychain.Keychain + storage i.KeyValueStorage updatedCh chan struct{} mutex sync.Mutex } -func NewKeychainWallet() *KeychainWallet { +func NewKeychainWallet(keychain i.KeyValueStorage) *KeychainWallet { return &KeychainWallet{ - storage: keychain.NewKeychain(), + storage: keychain, updatedCh: make(chan struct{}), } } @@ -76,7 +78,7 @@ func (w *KeychainWallet) SetPrivateKey(privateKey lib.HexString) error { } // either mnemonic or private key can be stored at a time err = w.storage.DeleteIfExists(MNEMONIC_KEY) - if err == nil { + if err != nil { return err } @@ -104,7 +106,7 @@ func (w *KeychainWallet) SetMnemonic(mnemonic string, derivationPath string) err // either mnemonic or private key can be stored at a time err = w.storage.DeleteIfExists(PRIVATE_KEY_KEY) - if err == nil { + if err != nil { return err } @@ -159,19 +161,19 @@ func (w *KeychainWallet) getStoredMnemonic() (string, string, error) { } func (w *KeychainWallet) mnemonicToPrivateKey(mnemonic, derivationPath string) (lib.HexString, error) { - wallet, err := hdwallet.NewFromMnemonic(mnemonic) + wallet, err := NewFromMnemonic(mnemonic) if err != nil { return nil, err } - path, err := hdwallet.ParseDerivationPath(derivationPath) + path, err := accounts.ParseDerivationPath(derivationPath) if err != nil { return nil, err } - account, err := wallet.Derive(path, true) + prKey, err := wallet.DerivePrivateKey(path) if err != nil { return nil, err } - return wallet.PrivateKeyBytes(account) + return crypto.FromECDSA(prKey), nil } func (w *KeychainWallet) PrivateKeyUpdated() <-chan struct{} { diff --git a/proxy-router/internal/storages/logger.go b/proxy-router/internal/storages/logger.go index e4b82590..902668d6 100644 --- a/proxy-router/internal/storages/logger.go +++ b/proxy-router/internal/storages/logger.go @@ -6,26 +6,26 @@ import ( "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/lib" ) -type BadgerLogger struct { +type StorageLogger struct { log lib.ILogger } -func NewBadgerLogger(log lib.ILogger) *BadgerLogger { - return &BadgerLogger{ - log: log.Named("BADGER"), +func NewStorageLogger(log lib.ILogger) *StorageLogger { + return &StorageLogger{ + log: log.Named("Storage"), } } -func (l *BadgerLogger) Errorf(s string, p ...interface{}) { +func (l *StorageLogger) Errorf(s string, p ...interface{}) { l.log.Errorf(normalize(s), p...) } -func (l *BadgerLogger) Warningf(s string, p ...interface{}) { +func (l *StorageLogger) Warningf(s string, p ...interface{}) { l.log.Warnf(normalize(s), p...) } -func (l *BadgerLogger) Infof(s string, p ...interface{}) { +func (l *StorageLogger) Infof(s string, p ...interface{}) { l.log.Infof(normalize(s), p...) } -func (l *BadgerLogger) Debugf(s string, p ...interface{}) { +func (l *StorageLogger) Debugf(s string, p ...interface{}) { l.log.Debugf(normalize(s), p...) } diff --git a/proxy-router/internal/storages/session_storage.go b/proxy-router/internal/storages/session_storage.go index c5c05a1d..b6426bcd 100644 --- a/proxy-router/internal/storages/session_storage.go +++ b/proxy-router/internal/storages/session_storage.go @@ -3,29 +3,9 @@ package storages import ( "encoding/json" "fmt" - "math/big" "strings" ) -type Session struct { - Id string - UserAddr string - ProviderAddr string - EndsAt *big.Int - TPSScaled1000Arr []int - TTFTMsArr []int - - ModelID string - ModelName string - ModelApiType string -} - -type User struct { - Addr string - PubKey string - Url string -} - type SessionStorage struct { db *Storage } @@ -36,77 +16,234 @@ func NewSessionStorage(storage *Storage) *SessionStorage { } } -func (s *SessionStorage) GetSession(id string) (*Session, bool) { - id = strings.ToLower(id) - key := fmt.Sprintf("session:%s", id) - - sessionJson, err := s.db.Get([]byte(key)) +func (s *SessionStorage) GetUser(addr string) (*User, bool) { + addr = strings.ToLower(addr) + key := fmt.Sprintf("user:%s", addr) + userJson, err := s.db.Get([]byte(key)) if err != nil { return nil, false } - session := &Session{} - err = json.Unmarshal(sessionJson, session) + user := &User{} + err = json.Unmarshal(userJson, user) if err != nil { return nil, false } - return session, true + return user, true } -func (s *SessionStorage) GetUser(addr string) (*User, bool) { - addr = strings.ToLower(addr) +func (s *SessionStorage) AddUser(user *User) error { + addr := strings.ToLower(user.Addr) key := fmt.Sprintf("user:%s", addr) - userJson, err := s.db.Get([]byte(key)) + userJson, err := json.Marshal(user) + if err != nil { + return err + } + + err = s.db.Set([]byte(key), userJson) + if err != nil { + return err + } + return nil +} + +func (s *SessionStorage) GetSession(id string) (*Session, bool) { + sessionJson, err := s.db.Get(formatSessionKey(id)) if err != nil { return nil, false } - user := &User{} - err = json.Unmarshal(userJson, user) + session := &Session{} + err = json.Unmarshal(sessionJson, session) if err != nil { return nil, false } - return user, true + return session, true } func (s *SessionStorage) AddSession(session *Session) error { - sessionId := strings.ToLower(session.Id) - key := fmt.Sprintf("session:%s", sessionId) sessionJson, err := json.Marshal(session) if err != nil { return err } - err = s.db.Set([]byte(key), sessionJson) + // TODO: do in a single transaction + err = s.db.Set(formatSessionKey(session.Id), sessionJson) + if err != nil { + return err + } + err = s.addSessionToModel(session.ModelID, session.Id) if err != nil { return err } return nil } -func (s *SessionStorage) AddUser(user *User) error { - addr := strings.ToLower(user.Addr) - key := fmt.Sprintf("user:%s", addr) - userJson, err := json.Marshal(user) +func (s *SessionStorage) RemoveSession(id string) error { + ses, ok := s.GetSession(id) + if !ok { + return nil + } + sessionId := strings.ToLower(id) + key := fmt.Sprintf("session:%s", sessionId) + + err := s.db.Delete([]byte(key)) if err != nil { return err } - err = s.db.Set([]byte(key), userJson) + return s.removeSessionFromModel(ses.ModelID, sessionId) +} + +func (s *SessionStorage) addSessionToModel(modelID string, sessionID string) error { + err := s.db.Set(formatModelSessionKey(modelID, sessionID), []byte{}) + if err != nil { + return fmt.Errorf("error adding session to model: %s", err) + } + return nil +} + +func (s *SessionStorage) removeSessionFromModel(modelID string, sessionID string) error { + err := s.db.Delete(formatModelSessionKey(modelID, sessionID)) + if err != nil { + return fmt.Errorf("error removing session from model: %s", err) + } + return nil +} + +func (s *SessionStorage) GetSessions() ([]Session, error) { + keys, err := s.db.GetPrefix(formatSessionKey("")) + if err != nil { + return []Session{}, err + } + + sessions := make([]Session, len(keys)) + for i, key := range keys { + _, sessionID := parseSessionKey(key) + session, ok := s.GetSession(sessionID) + if !ok { + return nil, fmt.Errorf("error getting session: %s", sessionID) + } + sessions[i] = *session + } + + return sessions, nil +} + +func (s *SessionStorage) GetSessionsForModel(modelID string) ([]string, error) { + keys, err := s.db.GetPrefix(formatModelSessionKey(modelID, "")) + if err != nil { + return []string{}, err + } + + sessionIDs := make([]string, len(keys)) + for i, key := range keys { + _, sessionID := parseModelSessionKey(key) + sessionIDs[i] = sessionID + } + + return sessionIDs, nil +} + +func (s *SessionStorage) AddActivity(modelID string, activity *PromptActivity) error { + modelID = strings.ToLower(modelID) + key := fmt.Sprintf("activity:%s", modelID) + + var activities []*PromptActivity + activitiesJson, err := s.db.Get([]byte(key)) + if err == nil { + err = json.Unmarshal(activitiesJson, &activities) + if err != nil { + return err + } + } else { + activities = []*PromptActivity{} + } + + activities = append(activities, activity) + activitiesJson, err = json.Marshal(activities) + if err != nil { + return err + } + + err = s.db.Set([]byte(key), activitiesJson) if err != nil { return err } return nil } -func (s *SessionStorage) RemoveSession(id string) error { - sessionId := strings.ToLower(id) - key := fmt.Sprintf("session:%s", sessionId) - err := s.db.Delete([]byte(key)) +func (s *SessionStorage) GetActivities(modelID string) ([]*PromptActivity, error) { + modelID = strings.ToLower(modelID) + key := fmt.Sprintf("activity:%s", modelID) + + activitiesJson, err := s.db.Get([]byte(key)) + if err != nil { + return []*PromptActivity{}, nil + } + + var activities []*PromptActivity + err = json.Unmarshal(activitiesJson, &activities) + if err != nil { + return nil, err + } + + return activities, nil +} + +// // New method to remove activities older than a certain time +func (s *SessionStorage) RemoveOldActivities(modelID string, beforeTime int64) error { + modelID = strings.ToLower(modelID) + key := fmt.Sprintf("activity:%s", modelID) + + activitiesJson, err := s.db.Get([]byte(key)) + if err != nil { + return nil + } + + var activities []*PromptActivity + err = json.Unmarshal(activitiesJson, &activities) if err != nil { return err } + + // Filter activities, keep only those after beforeTime + var updatedActivities []*PromptActivity + for _, activity := range activities { + if activity.EndTime > beforeTime { + updatedActivities = append(updatedActivities, activity) + } + } + + activitiesJson, err = json.Marshal(updatedActivities) + if err != nil { + return err + } + + err = s.db.Set([]byte(key), activitiesJson) + if err != nil { + return err + } + return nil } + +func formatModelSessionKey(modelID string, sessionID string) []byte { + return []byte(fmt.Sprintf("model:%s:session:%s", strings.ToLower(modelID), strings.ToLower(sessionID))) +} + +func formatSessionKey(sessionID string) []byte { + return []byte(fmt.Sprintf("session:%s", strings.ToLower(sessionID))) +} + +func parseModelSessionKey(key []byte) (string, string) { + parts := strings.Split(string(key), ":") + return parts[1], parts[3] +} + +func parseSessionKey(key []byte) (string, string) { + parts := strings.Split(string(key), ":") + return parts[0], parts[1] +} diff --git a/proxy-router/internal/storages/session_storage_test.go b/proxy-router/internal/storages/session_storage_test.go new file mode 100644 index 00000000..5da5131a --- /dev/null +++ b/proxy-router/internal/storages/session_storage_test.go @@ -0,0 +1,64 @@ +package storages + +import ( + "math/big" + "testing" + + "github.com/stretchr/testify/require" +) + +func TestAddSession(t *testing.T) { + storage := NewTestStorage() + sessionStorage := NewSessionStorage(storage) + + session := &Session{ + Id: "0x0", + UserAddr: "0x1", + ProviderAddr: "0x2", + EndsAt: big.NewInt(100), + ModelID: "0x3", + TPSScaled1000Arr: []int{1, 2, 3}, + TTFTMsArr: []int{4, 5, 6}, + FailoverEnabled: true, + } + + err := sessionStorage.AddSession(session) + require.NoError(t, err) + + s, ok := sessionStorage.GetSession(session.Id) + require.True(t, ok) + require.Equal(t, session, s) + + sessionIds, err := sessionStorage.GetSessionsForModel(session.ModelID) + require.NoError(t, err) + require.Equal(t, []string{session.Id}, sessionIds) +} + +func TestRemoveSession(t *testing.T) { + storage := NewTestStorage() + sessionStorage := NewSessionStorage(storage) + + session := &Session{ + Id: "0x0", + UserAddr: "0x1", + ProviderAddr: "0x2", + EndsAt: big.NewInt(100), + ModelID: "0x3", + TPSScaled1000Arr: []int{1, 2, 3}, + TTFTMsArr: []int{4, 5, 6}, + FailoverEnabled: true, + } + + err := sessionStorage.AddSession(session) + require.NoError(t, err) + + err = sessionStorage.RemoveSession(session.Id) + require.NoError(t, err) + + _, ok := sessionStorage.GetSession(session.Id) + require.False(t, ok) + + sessionIds, err := sessionStorage.GetSessionsForModel(session.ModelID) + require.NoError(t, err) + require.Empty(t, sessionIds) +} diff --git a/proxy-router/internal/storages/storage.go b/proxy-router/internal/storages/storage.go index a0a03649..8b0e4271 100644 --- a/proxy-router/internal/storages/storage.go +++ b/proxy-router/internal/storages/storage.go @@ -12,17 +12,28 @@ type Storage struct { } func NewStorage(log lib.ILogger, path string) *Storage { + storageLogger := NewStorageLogger(log) if err := os.Mkdir(path, os.ModePerm); err != nil { - log.Warn(err) + storageLogger.Debugf("%s", err) } opts := badger.DefaultOptions(path) - opts.Logger = NewBadgerLogger(log) + opts.Logger = storageLogger db, err := badger.Open(opts) - if err != nil { log.Fatal(err) } + + return &Storage{db} +} + +func NewTestStorage() *Storage { + opts := badger.DefaultOptions("") + opts.InMemory = true + db, err := badger.Open(opts) + if err != nil { + panic(err) + } return &Storage{db} } @@ -50,6 +61,22 @@ func (s *Storage) Get(key []byte) ([]byte, error) { return valCopy, err } +func (s *Storage) GetPrefix(prefix []byte) ([][]byte, error) { + keys := make([][]byte, 0) + err := s.db.View(func(txn *badger.Txn) error { + it := txn.NewIterator(badger.IteratorOptions{PrefetchValues: false, Prefix: prefix}) + defer it.Close() + + for it.Seek(prefix); it.ValidForPrefix(prefix); it.Next() { + item := it.Item() + k := item.KeyCopy(nil) + keys = append(keys, k) + } + return nil + }) + return keys, err +} + func (s *Storage) Set(key, val []byte) error { return s.db.Update(func(txn *badger.Txn) error { return txn.Set(key, val) diff --git a/proxy-router/internal/storages/structs.go b/proxy-router/internal/storages/structs.go new file mode 100644 index 00000000..e693c675 --- /dev/null +++ b/proxy-router/internal/storages/structs.go @@ -0,0 +1,28 @@ +package storages + +import "math/big" + +type Session struct { + Id string + UserAddr string + ProviderAddr string + EndsAt *big.Int + ModelID string + + TPSScaled1000Arr []int + TTFTMsArr []int + FailoverEnabled bool + DirectPayment bool +} + +type User struct { + Addr string + PubKey string + Url string +} + +type PromptActivity struct { + SessionID string + StartTime int64 + EndTime int64 +} diff --git a/proxy-router/internal/system/controller.go b/proxy-router/internal/system/controller.go index 700d157c..9d39d3db 100644 --- a/proxy-router/internal/system/controller.go +++ b/proxy-router/internal/system/controller.go @@ -10,57 +10,52 @@ import ( "time" "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/config" - "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/interfaces" + i "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/interfaces" "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/lib" + "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/repositories/ethclient" "github.com/gin-gonic/gin" ) -type HealthCheckResponse struct { - Status string - Version string - Uptime string -} - type SystemController struct { - config *config.Config - wallet interfaces.Wallet - sysConfig *SystemConfigurator - appStartTime time.Time - chainID *big.Int - log lib.ILogger + config *config.Config + wallet i.Wallet + ethRPC i.RPCEndpoints + sysConfig *SystemConfigurator + appStartTime time.Time + chainID *big.Int + log lib.ILogger + ethConnectionValidator IEthConnectionValidator } -type ConfigResponse struct { - Version string - Commit string - DerivedConfig interface{} - Config interface{} -} - -func NewSystemController(config *config.Config, wallet interfaces.Wallet, sysConfig *SystemConfigurator, appStartTime time.Time, chainID *big.Int, log lib.ILogger) *SystemController { +func NewSystemController(config *config.Config, wallet i.Wallet, ethRPC i.RPCEndpoints, sysConfig *SystemConfigurator, appStartTime time.Time, chainID *big.Int, log lib.ILogger, ethConnectionValidator IEthConnectionValidator) *SystemController { c := &SystemController{ - config: config, - wallet: wallet, - sysConfig: sysConfig, - appStartTime: appStartTime, - chainID: chainID, - log: log, + config: config, + wallet: wallet, + ethRPC: ethRPC, + sysConfig: sysConfig, + appStartTime: appStartTime, + chainID: chainID, + log: log, + ethConnectionValidator: ethConnectionValidator, } return c } -func (s *SystemController) RegisterRoutes(r interfaces.Router) { +func (s *SystemController) RegisterRoutes(r i.Router) { r.GET("/healthcheck", s.HealthCheck) r.GET("/config", s.GetConfig) r.GET("/files", s.GetFiles) + + r.POST("/config/ethNode", s.SetEthNode) + r.DELETE("/config/ethNode", s.RemoveEthNode) } // HealthCheck godoc // // @Summary Healthcheck example // @Description do ping -// @Tags healthcheck +// @Tags system // @Produce json // @Success 200 {object} HealthCheckResponse // @Router /healthcheck [get] @@ -76,7 +71,7 @@ func (s *SystemController) HealthCheck(ctx *gin.Context) { // // @Summary Get Config // @Description Return the current config of proxy router -// @Tags healthcheck +// @Tags system // @Produce json // @Success 200 {object} ConfigResponse // @Router /config [get] @@ -98,6 +93,7 @@ func (s *SystemController) GetConfig(ctx *gin.Context) { DerivedConfig: config.DerivedConfig{ WalletAddress: addr, ChainID: s.chainID, + EthNodeURLs: s.ethRPC.GetURLs(), }, }) } @@ -106,7 +102,7 @@ func (s *SystemController) GetConfig(ctx *gin.Context) { // // @Summary Get files // @Description Returns opened files -// @Tags healthcheck +// @Tags system // @Produce json // @Success 200 {object} []FD // @Router /files [get] @@ -140,6 +136,70 @@ func (s *SystemController) GetFiles(ctx *gin.Context) { return } +// SetEthNode godoc +// +// @Summary Set Eth Node URLs +// @Description Set the Eth Node URLs +// @Tags system +// @Accept json +// @Produce json +// @Param urls body SetEthNodeURLReq true "URLs" +// @Success 200 {object} StatusRes +// @Router /config/ethNode [post] +func (s *SystemController) SetEthNode(ctx *gin.Context) { + var req SetEthNodeURLReq + if err := ctx.BindJSON(&req); err != nil { + ctx.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) + return + } + + for _, url := range req.URLs { + validationErr := s.ethConnectionValidator.ValidateEthResourse(ctx, url, time.Second*2) + if validationErr != nil { + ctx.JSON(http.StatusInternalServerError, gin.H{"error": fmt.Sprintf("Resource %s is not available", url)}) + return + } + } + + err := s.ethRPC.SetURLs(req.URLs) + if err != nil { + ctx.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + return + } + + ctx.JSON(http.StatusOK, OkRes()) +} + +// DeleteEthNode godoc +// +// @Summary Delete Eth Node URLs +// @Description Delete the Eth Node URLs +// @Tags system +// @Produce json +// @Success 200 {object} StatusRes +// @Router /config/ethNode [delete] +func (c *SystemController) RemoveEthNode(ctx *gin.Context) { + err := c.ethRPC.RemoveURLs() + if err != nil { + ctx.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + return + } + + urls, err := ethclient.GetPublicRPCURLs(int(c.chainID.Int64())) + if err != nil { + ctx.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + return + } + + err = c.ethRPC.SetURLsNoPersist(urls) + if err != nil { + ctx.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + return + } + + ctx.JSON(http.StatusOK, OkRes()) +} + func writeFiles(writer io.Writer, files []FD) error { text := fmt.Sprintf("Total: %d\n", len(files)) text += "\n" diff --git a/proxy-router/internal/system/interface.go b/proxy-router/internal/system/interface.go index 5c7067a3..78486778 100644 --- a/proxy-router/internal/system/interface.go +++ b/proxy-router/internal/system/interface.go @@ -1,9 +1,16 @@ package system -import "context" +import ( + "context" + "time" +) type osConfigurator interface { GetConfig() (*Config, error) ApplyConfig(cfg *Config) error GetFileDescriptors(ctx context.Context, pid int) ([]FD, error) } + +type IEthConnectionValidator interface { + ValidateEthResourse(ctx context.Context, url string, timeout time.Duration) error +} diff --git a/proxy-router/internal/system/structs.go b/proxy-router/internal/system/structs.go index 3c8e440e..c8972b7c 100644 --- a/proxy-router/internal/system/structs.go +++ b/proxy-router/internal/system/structs.go @@ -4,3 +4,28 @@ type FD struct { ID string Path string } + +type SetEthNodeURLReq struct { + URLs []string `json:"urls" binding:"required" validate:"required,url"` +} + +type ConfigResponse struct { + Version string + Commit string + DerivedConfig interface{} + Config interface{} +} + +type HealthCheckResponse struct { + Status string + Version string + Uptime string +} + +type StatusRes struct { + Status string `json:"status"` +} + +func OkRes() StatusRes { + return StatusRes{Status: "ok"} +} diff --git a/proxy-router/internal/system/validation.go b/proxy-router/internal/system/validation.go new file mode 100644 index 00000000..91874957 --- /dev/null +++ b/proxy-router/internal/system/validation.go @@ -0,0 +1,41 @@ +package system + +import ( + "context" + "fmt" + "math/big" + "time" + + "github.com/ethereum/go-ethereum/ethclient" +) + +type EthConnectionValidator struct { + chainId big.Int +} + +func NewEthConnectionValidator(chainId big.Int) *EthConnectionValidator { + return &EthConnectionValidator{ + chainId: chainId, + } +} + +func (v *EthConnectionValidator) ValidateEthResourse(ctx context.Context, url string, timeout time.Duration) error { + timeoutCtx, cancel := context.WithTimeout(ctx, timeout) + defer cancel() + + ethClient, err := ethclient.DialContext(timeoutCtx, url) + if err != nil { + return err + } + + urlChainId, chainIdError := ethClient.ChainID(timeoutCtx) + if chainIdError != nil { + return chainIdError + } + + if v.chainId.Cmp(urlChainId) != 0 { + return fmt.Errorf("invalid chain id %s, expected: %s", urlChainId, &v.chainId) + } + + return nil +} diff --git a/proxy-router/models-config.json.example b/proxy-router/models-config.json.example index d327a10d..2e71310e 100644 --- a/proxy-router/models-config.json.example +++ b/proxy-router/models-config.json.example @@ -1,12 +1,25 @@ { - "0x2d4b79107cc0b262f29628d97e6a4905a37e7fc9cd820dbdaf359e9ff5f5d9cf": { - "modelName": "v1-5-pruned-emaonly.safetensors [d7049739]", - "apiType": "prodia", - "apiUrl": "https://api.prodia.com/v1/sd/generate", - "apiKey": "API_KEY_HERE" + "$schema": "./internal/config/models-config-schema.json", + "models": [ + { + "modelId": "0x0000000000000000000000000000000000000000000000000000000000000000", + "modelName": "llama2", + "apiType": "openai", + "apiUrl": "http://localhost:8080/v1" }, - "0x6a4813e866a48da528c533e706344ea853a1d3f21e37b4c8e7ffd5ff25779018": { - "modelName": "llama2", - "apiType": "openai" + { + "modelId": "0x0000000000000000000000000000000000000000000000000000000000000001", + "modelName": "v1-5-pruned-emaonly.safetensors [d7049739]", + "apiType": "prodia-sd", + "apiUrl": "https://api.prodia.com/v1", + "apiKey": "FILL_ME_IN" + }, + { + "modelId": "0x0000000000000000000000000000000000000000000000000000000000000002", + "modelName": "SDXL1.0-base", + "apiType": "hyperbolic-sd", + "apiUrl": "https://api.hyperbolic.xyz/v1", + "apiKey": "Authentication Token" } -} \ No newline at end of file + ] +} diff --git a/proxy-router/rating-config.json.example b/proxy-router/rating-config.json.example new file mode 100644 index 00000000..c27f6082 --- /dev/null +++ b/proxy-router/rating-config.json.example @@ -0,0 +1,14 @@ +{ + "$schema": "./internal/rating/rating-config-schema.json", + "algorithm": "default", + "providerAllowlist": [], + "params": { + "weights": { + "tps": 0.24, + "ttft": 0.08, + "duration": 0.24, + "success": 0.32, + "stake": 0.12 + } + } +} \ No newline at end of file diff --git a/proxy-router/readme.md b/proxy-router/readme.md new file mode 100644 index 00000000..0b6a4b3a --- /dev/null +++ b/proxy-router/readme.md @@ -0,0 +1,58 @@ +## Environment Variables: + +`PROXY_STORE_CHAT_CONTEXT` + +- **Type:** Boolean +- **Purpose:** Controls whether the proxy-router stores chat contexts locally. + +#### When `PROXY_STORE_CHAT_CONTEXT` is set to `TRUE` + +- **Local Storage of Chats:** + - The proxy saves chat sessions to local files. + - Chat histories are maintained, allowing for persistent conversations. + +- **API Operations:** (check swagger - `/v1/chats`) + - **Retrieve Chats:** Access stored chats via API endpoints. + - **Update Titles:** Modify chat titles using API calls. + - **Delete Chats:** Remove chat sessions through the API. + +- **Using `chat_id`:** + - Include a `chat_id` in the request header. + - The proxy-router automatically injects the corresponding chat context. + - **Request Simplification:** Only the latest message needs to be sent in the request body. + +#### When `PROXY_STORE_CHAT_CONTEXT` is set to `FALSE` + +- **No Chat Storage:** + - The proxy-router does not save any chat sessions locally. + +- **Client-Side Context Management:** + - Clients must include the entire conversation history in each request. + - The proxy-router forwards the request to the AI model without adding any context. + +--- + +Ensure the proxy-router is restarted after changing the environment variable to apply the new configuration. + +## CapacityPolicy strategies (models-config.json): + +#### `simple` + +Assign a slot to each session upon initiation, blocking new sessions when all slots are occupied, regardless of activity level. + +- Each new session consumes one slot from the total available slots N (`concurrentSlots`). + +- Do not allow new sessions when slots_in_use >= N. + +- Slots remain occupied until the user explicitly closes the session or times out. + + +#### `idle_timeout` + +Free up slots occupied by inactive sessions by setting an idle timeout period. + +Timeout is 15 minutes. + +- If no prompt is received within the idle timeout period, mark the session as idle. + +- Release the slot associated with the idle session, making it available for new users. diff --git a/proxy-router/test/httphandlers_test.go b/proxy-router/test/httphandlers_test.go index 03e773d2..380c15f9 100644 --- a/proxy-router/test/httphandlers_test.go +++ b/proxy-router/test/httphandlers_test.go @@ -31,7 +31,7 @@ import ( var WALLET_PRIVATE_KEY = lib.MustStringToHexString("") // Set this to a valid private key to run the test. var DIAMOND_CONTRACT_ADDR = lib.MustStringToAddress("0x70768f0ff919e194e11abfc3a2edf43213359dc1") -var MOR_CONTRACT_ADDR = lib.MustStringToAddress("0xc1664f994fd3991f98ae944bc16b9aed673ef5fd") +var MOR_CONTRACT_ADDR = lib.MustStringToAddress("0x34a285a1b1c166420df5b6630132542923b5b27e") var EXPLORER_API_URL = "https://api-sepolia.arbiscan.io/api" var ETH_LEGACY_TX = false var ETH_NODE_ADDRESS = "wss://arb-sepolia.g.alchemy.com/v2/Ken3T8xkvWUxtpKvb3yDedzF-sNsQDlZ" diff --git a/readme.md b/readme.md index a90fdf06..f8263e11 100644 --- a/readme.md +++ b/readme.md @@ -10,26 +10,33 @@ The purpose of this software is to enable interaction with distributed, decentra 5. Consumers purchase the bid and stake MOR for their session time 6. Once the bid has been purchased, prompt and inference (ChatGPT-like) can start -# **NOTE: ARBITRUM SEPOLIA TESTNET ONLY at this time** **Components that are included in this repository are:** * Local `Llama.cpp` and tinyllama model to run locally for demonstration purposes only * Lumerin `proxy-router` is a background process that monitors sepcific blockchain contract events, manages secure sessions between consumers and providers and routes prompts and responses between them -* Lumerin `ui-desktop` is the front end UI to interact with LLMs and the Morpheus network via the proxy-router as a consumer +* Lumerin `MorpheusUI` is the front end UI to interact with LLMs and the Morpheus network via the proxy-router as a consumer * Lumerin `cli` is the cli client to interact with LLMs and the Morpheus network via the proxy-router as a consumer -## Tokens and Contract Information -* Morpheus saMOR Token: `0xc1664f994fd3991f98ae944bc16b9aed673ef5fd` -* Lumerin Morpheus Smart Contract : `0x8e19288d908b2d9F8D7C539c74C899808AC3dE45` - * Interact with the Morpheus Contract: https://louper.dev/diamond/0x8e19288d908b2d9F8D7C539c74C899808AC3dE45?network=arbitrumSepolia#write +## Tokens and Contract Information (update 11/15/2024) +### MainNet: (MAIN Branch and MAIN-* Releases) +* Blockchain: Arbitrum One (ChainID: `42161`) +* Morpheus MOR Token: `0x092bAaDB7DEf4C3981454dD9c0A0D7FF07bCFc86` +* Diamond MarketPlace Contract: `0xDE819AaEE474626E3f34Ef0263373357e5a6C71b` +* Blockchain Explorer: `https://arbiscan.io/` +* GitHub Source: https://github.com/Lumerin-protocol/Morpheus-Lumerin-Node/tree/main + +### TestNet (TEST Branch and TEST-* Releases) +* Blockchain: Sepolia Arbitrum (ChainID: `421614`) +* Morpheus MOR Token: `0x34a285a1b1c166420df5b6630132542923b5b27e` +* Diamond MarketPlace Contract: `0xb8C55cD613af947E73E262F0d3C54b7211Af16CF` * Blockchain Explorer: `https://sepolia.arbiscan.io/` -* Swagger API: `http://localhost:8082/swagger/index.html` +* GitHub Source: https://github.com/Lumerin-protocol/Morpheus-Lumerin-Node/tree/test ## Funds -* **WALLET:** For testing as a provider or consumer, you will need both `saMOR` and `saETH` tokens in your wallet. You should be able to get either of these from the usual Sepolia Arbitrum testnet faucets. - * `saMOR` is the token used to pay for the model provider staking and consumer usage - * `saETH` is the token used to pay for the gas fees on the network +* **WALLET:** For testing as a provider or consumer, you will need both `MOR` and `ETH` tokens in your wallet. + * `MOR` is the token used to pay for the model provider staking and consumer usage + * `ETH` is the token used to pay for the gas fees on the network ## Installation & Operation * [00-Overview](docs/00-overview.md) - This provides a comprehensive picture of the Provider, Blockchain and Consumer environments and how they interact. This will also link to other documents for more advanced setup and configuration. diff --git a/smart-contracts/contracts/diamond/facets/Delegation.sol b/smart-contracts/contracts/diamond/facets/Delegation.sol new file mode 100644 index 00000000..9009b38b --- /dev/null +++ b/smart-contracts/contracts/diamond/facets/Delegation.sol @@ -0,0 +1,21 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.24; + +import {OwnableDiamondStorage} from "../presets/OwnableDiamondStorage.sol"; + +import {DelegationStorage} from "../storages/DelegationStorage.sol"; + +import {IDelegation} from "../../interfaces/facets/IDelegation.sol"; + +contract Delegation is IDelegation, OwnableDiamondStorage, DelegationStorage { + function __Delegation_init(address registry_) external initializer(DELEGATION_STORAGE_SLOT) { + setRegistry(registry_); + } + + function setRegistry(address registry_) public onlyOwner { + DLGTNStorage storage delegationStorage = _getDelegationStorage(); + delegationStorage.registry = registry_; + + emit DelegationRegistryUpdated(registry_); + } +} diff --git a/smart-contracts/contracts/diamond/facets/Marketplace.sol b/smart-contracts/contracts/diamond/facets/Marketplace.sol index e5d47c0a..dff7ec7c 100644 --- a/smart-contracts/contracts/diamond/facets/Marketplace.sol +++ b/smart-contracts/contracts/diamond/facets/Marketplace.sol @@ -10,6 +10,7 @@ import {BidStorage} from "../storages/BidStorage.sol"; import {ModelStorage} from "../storages/ModelStorage.sol"; import {ProviderStorage} from "../storages/ProviderStorage.sol"; import {MarketplaceStorage} from "../storages/MarketplaceStorage.sol"; +import {DelegationStorage} from "../storages/DelegationStorage.sol"; import {IMarketplace} from "../../interfaces/facets/IMarketplace.sol"; @@ -19,7 +20,8 @@ contract Marketplace is MarketplaceStorage, ProviderStorage, ModelStorage, - BidStorage + BidStorage, + DelegationStorage { using SafeERC20 for IERC20; using EnumerableSet for EnumerableSet.Bytes32Set; @@ -42,14 +44,11 @@ contract Marketplace is emit MaretplaceFeeUpdated(bidFee_); } - function setMinMaxBidPricePerSecond( - uint256 bidMinPricePerSecond_, - uint256 bidMaxPricePerSecond_ - ) public onlyOwner { + function setMinMaxBidPricePerSecond(uint256 bidMinPricePerSecond_, uint256 bidMaxPricePerSecond_) public onlyOwner { if (bidMinPricePerSecond_ == 0) { revert MarketplaceBidMinPricePerSecondIsZero(); } - + if (bidMinPricePerSecond_ > bidMaxPricePerSecond_) { revert MarketplaceBidMinPricePerSecondIsInvalid(); } @@ -61,8 +60,12 @@ contract Marketplace is emit MarketplaceBidMinMaxPriceUpdated(bidMinPricePerSecond_, bidMaxPricePerSecond_); } - function postModelBid(bytes32 modelId_, uint256 pricePerSecond_) external returns (bytes32 bidId) { - address provider_ = _msgSender(); + function postModelBid( + address provider_, + bytes32 modelId_, + uint256 pricePerSecond_ + ) external returns (bytes32 bidId) { + _validateDelegatee(_msgSender(), provider_, DELEGATION_RULES_MARKETPLACE); if (!getIsProviderActive(provider_)) { revert MarketplaceProviderNotFound(); @@ -74,7 +77,9 @@ contract Marketplace is BidsStorage storage bidsStorage = _getBidsStorage(); MarketStorage storage marketStorage = _getMarketStorage(); - if (pricePerSecond_ < marketStorage.bidMinPricePerSecond || pricePerSecond_ > marketStorage.bidMaxPricePerSecond) { + if ( + pricePerSecond_ < marketStorage.bidMinPricePerSecond || pricePerSecond_ > marketStorage.bidMaxPricePerSecond + ) { revert MarketplaceBidPricePerSecondInvalid(); } @@ -111,7 +116,7 @@ contract Marketplace is function deleteModelBid(bytes32 bidId_) external { BidsStorage storage bidsStorage = _getBidsStorage(); - _onlyAccount(bidsStorage.bids[bidId_].provider); + _validateDelegatee(_msgSender(), bidsStorage.bids[bidId_].provider, DELEGATION_RULES_MARKETPLACE); if (!isBidActive(bidId_)) { revert MarketplaceActiveBidNotFound(); diff --git a/smart-contracts/contracts/diamond/facets/ModelRegistry.sol b/smart-contracts/contracts/diamond/facets/ModelRegistry.sol index 5c4571d8..2b46af4d 100644 --- a/smart-contracts/contracts/diamond/facets/ModelRegistry.sol +++ b/smart-contracts/contracts/diamond/facets/ModelRegistry.sol @@ -8,10 +8,11 @@ import {OwnableDiamondStorage} from "../presets/OwnableDiamondStorage.sol"; import {BidStorage} from "../storages/BidStorage.sol"; import {ModelStorage} from "../storages/ModelStorage.sol"; +import {DelegationStorage} from "../storages/DelegationStorage.sol"; import {IModelRegistry} from "../../interfaces/facets/IModelRegistry.sol"; -contract ModelRegistry is IModelRegistry, OwnableDiamondStorage, ModelStorage, BidStorage { +contract ModelRegistry is IModelRegistry, OwnableDiamondStorage, ModelStorage, BidStorage, DelegationStorage { using EnumerableSet for EnumerableSet.Bytes32Set; using SafeERC20 for IERC20; @@ -25,14 +26,19 @@ contract ModelRegistry is IModelRegistry, OwnableDiamondStorage, ModelStorage, B } function modelRegister( - bytes32 modelId_, + address modelOwner_, + bytes32 baseModelId_, bytes32 ipfsCID_, uint256 fee_, uint256 amount_, string calldata name_, string[] memory tags_ ) external { + _validateDelegatee(_msgSender(), modelOwner_, DELEGATION_RULES_MODEL); + ModelsStorage storage modelsStorage = _getModelsStorage(); + + bytes32 modelId_ = getModelId(modelOwner_, baseModelId_); Model storage model = modelsStorage.models[modelId_]; uint256 newStake_ = model.stake + amount_; @@ -43,16 +49,14 @@ contract ModelRegistry is IModelRegistry, OwnableDiamondStorage, ModelStorage, B if (amount_ > 0) { BidsStorage storage bidsStorage = _getBidsStorage(); - IERC20(bidsStorage.token).safeTransferFrom(_msgSender(), address(this), amount_); + IERC20(bidsStorage.token).safeTransferFrom(modelOwner_, address(this), amount_); } if (model.createdAt == 0) { modelsStorage.modelIds.add(modelId_); model.createdAt = uint128(block.timestamp); - model.owner = _msgSender(); - } else { - _onlyAccount(model.owner); + model.owner = modelOwner_; } model.stake = newStake_; @@ -64,14 +68,15 @@ contract ModelRegistry is IModelRegistry, OwnableDiamondStorage, ModelStorage, B modelsStorage.activeModels.add(modelId_); - emit ModelRegisteredUpdated(_msgSender(), modelId_); + emit ModelRegisteredUpdated(modelOwner_, modelId_); } function modelDeregister(bytes32 modelId_) external { ModelsStorage storage modelsStorage = _getModelsStorage(); Model storage model = modelsStorage.models[modelId_]; - _onlyAccount(model.owner); + _validateDelegatee(_msgSender(), model.owner, DELEGATION_RULES_MODEL); + if (!_isModelActiveBidsEmpty(modelId_)) { revert ModelHasActiveBids(); } @@ -91,4 +96,8 @@ contract ModelRegistry is IModelRegistry, OwnableDiamondStorage, ModelStorage, B emit ModelDeregistered(model.owner, modelId_); } + + function getModelId(address account_, bytes32 baseModelId_) public pure returns (bytes32) { + return keccak256(abi.encodePacked(account_, baseModelId_)); + } } diff --git a/smart-contracts/contracts/diamond/facets/ProviderRegistry.sol b/smart-contracts/contracts/diamond/facets/ProviderRegistry.sol index 13dcbca6..c410ad7a 100644 --- a/smart-contracts/contracts/diamond/facets/ProviderRegistry.sol +++ b/smart-contracts/contracts/diamond/facets/ProviderRegistry.sol @@ -8,10 +8,12 @@ import {OwnableDiamondStorage} from "../presets/OwnableDiamondStorage.sol"; import {BidStorage} from "../storages/BidStorage.sol"; import {ProviderStorage} from "../storages/ProviderStorage.sol"; +import {DelegationStorage} from "../storages/DelegationStorage.sol"; import {IProviderRegistry} from "../../interfaces/facets/IProviderRegistry.sol"; +import {IDelegateRegistry} from "../../interfaces/deps/IDelegateRegistry.sol"; -contract ProviderRegistry is IProviderRegistry, OwnableDiamondStorage, ProviderStorage, BidStorage { +contract ProviderRegistry is IProviderRegistry, OwnableDiamondStorage, ProviderStorage, BidStorage, DelegationStorage { using EnumerableSet for EnumerableSet.AddressSet; using SafeERC20 for IERC20; @@ -24,15 +26,16 @@ contract ProviderRegistry is IProviderRegistry, OwnableDiamondStorage, ProviderS emit ProviderMinimumStakeUpdated(providerMinimumStake_); } - function providerRegister(uint256 amount_, string calldata endpoint_) external { - BidsStorage storage bidsStorage = _getBidsStorage(); + function providerRegister(address provider_, uint256 amount_, string calldata endpoint_) external { + _validateDelegatee(_msgSender(), provider_, DELEGATION_RULES_PROVIDER); + BidsStorage storage bidsStorage = _getBidsStorage(); if (amount_ > 0) { - IERC20(bidsStorage.token).safeTransferFrom(_msgSender(), address(this), amount_); + IERC20(bidsStorage.token).safeTransferFrom(provider_, address(this), amount_); } PovidersStorage storage providersStorage = _getProvidersStorage(); - Provider storage provider = providersStorage.providers[_msgSender()]; + Provider storage provider = providersStorage.providers[provider_]; uint256 newStake_ = provider.stake + amount_; uint256 minStake_ = providersStorage.providerMinimumStake; @@ -50,13 +53,13 @@ contract ProviderRegistry is IProviderRegistry, OwnableDiamondStorage, ProviderS provider.endpoint = endpoint_; provider.stake = newStake_; - providersStorage.activeProviders.add(_msgSender()); + providersStorage.activeProviders.add(provider_); - emit ProviderRegistered(_msgSender()); + emit ProviderRegistered(provider_); } - function providerDeregister() external { - address provider_ = _msgSender(); + function providerDeregister(address provider_) external { + _validateDelegatee(_msgSender(), provider_, DELEGATION_RULES_PROVIDER); PovidersStorage storage providersStorage = _getProvidersStorage(); Provider storage provider = providersStorage.providers[provider_]; @@ -86,32 +89,6 @@ contract ProviderRegistry is IProviderRegistry, OwnableDiamondStorage, ProviderS emit ProviderDeregistered(provider_); } - // /** - // * - // * @notice Withdraws stake from a provider after it has been deregistered - // * Allows to withdraw the stake after provider reward period has ended - // */ - // function providerWithdrawStake() external { - // Provider storage provider = providers(_msgSender()); - - // if (!provider.isDeleted) { - // revert ProviderNotDeregistered(); - // } - // if (provider.stake == 0) { - // revert ProviderNoStake(); - // } - - // uint256 withdrawAmount_ = _getWithdrawAmount(provider); - // if (withdrawAmount_ == 0) { - // revert ProviderNothingToWithdraw(); - // } - - // provider.stake -= withdrawAmount_; - // getToken().safeTransfer(_msgSender(), withdrawAmount_); - - // emit ProviderWithdrawn(_msgSender(), withdrawAmount_); - // } - /** * @notice Returns the withdrawable stake for a provider * @dev If the provider already earned this period then withdrawable stake diff --git a/smart-contracts/contracts/diamond/facets/SessionRouter.sol b/smart-contracts/contracts/diamond/facets/SessionRouter.sol index e7edf4a3..5b330636 100644 --- a/smart-contracts/contracts/diamond/facets/SessionRouter.sol +++ b/smart-contracts/contracts/diamond/facets/SessionRouter.sol @@ -13,20 +13,20 @@ import {BidStorage, EnumerableSet} from "../storages/BidStorage.sol"; import {StatsStorage} from "../storages/StatsStorage.sol"; import {SessionStorage} from "../storages/SessionStorage.sol"; import {ProviderStorage} from "../storages/ProviderStorage.sol"; +import {DelegationStorage} from "../storages/DelegationStorage.sol"; import {LibSD} from "../../libs/LibSD.sol"; import {ISessionRouter} from "../../interfaces/facets/ISessionRouter.sol"; -import "hardhat/console.sol"; - contract SessionRouter is ISessionRouter, OwnableDiamondStorage, SessionStorage, ProviderStorage, BidStorage, - StatsStorage + StatsStorage, + DelegationStorage { using Math for *; using LibSD for LibSD.SD; @@ -78,38 +78,43 @@ contract SessionRouter is /// OPEN SESSION /// //////////////////////// function openSession( + address user_, uint256 amount_, bool isDirectPaymentFromUser_, bytes calldata approvalEncoded_, bytes calldata signature_ ) external returns (bytes32) { + _validateDelegatee(_msgSender(), user_, DELEGATION_RULES_SESSION); + SessionsStorage storage sessionsStorage = _getSessionsStorage(); bytes32 bidId_ = _extractProviderApproval(approvalEncoded_); - Bid storage bid = _getBidsStorage().bids[bidId_]; - bytes32 sessionId_ = getSessionId(_msgSender(), bid.provider, bidId_, sessionsStorage.sessionNonce++); + bytes32 sessionId_ = getSessionId( + user_, + _getBidsStorage().bids[bidId_].provider, + bidId_, + sessionsStorage.sessionNonce++ + ); Session storage session = sessionsStorage.sessions[sessionId_]; - uint128 endsAt_ = _validateSession(bidId_, amount_, isDirectPaymentFromUser_, approvalEncoded_, signature_); - - IERC20(_getBidsStorage().token).safeTransferFrom(_msgSender(), address(this), amount_); + IERC20(_getBidsStorage().token).safeTransferFrom(user_, address(this), amount_); - session.user = _msgSender(); + session.user = user_; session.stake = amount_; session.bidId = bidId_; session.openedAt = uint128(block.timestamp); - session.endsAt = endsAt_; + session.endsAt = _validateSession(bidId_, amount_, isDirectPaymentFromUser_, approvalEncoded_, signature_); session.isActive = true; session.isDirectPaymentFromUser = isDirectPaymentFromUser_; - sessionsStorage.userSessions[_msgSender()].add(sessionId_); - sessionsStorage.providerSessions[bid.provider].add(sessionId_); - sessionsStorage.modelSessions[bid.modelId].add(sessionId_); + sessionsStorage.userSessions[user_].add(sessionId_); + sessionsStorage.providerSessions[_getBidsStorage().bids[bidId_].provider].add(sessionId_); + sessionsStorage.modelSessions[_getBidsStorage().bids[bidId_].modelId].add(sessionId_); sessionsStorage.isProviderApprovalUsed[approvalEncoded_] = true; - emit SessionOpened(_msgSender(), sessionId_, bid.provider); + emit SessionOpened(user_, sessionId_, _getBidsStorage().bids[bidId_].provider); return sessionId_; } @@ -209,7 +214,8 @@ contract SessionRouter is Session storage session = _getSessionsStorage().sessions[sessionId_]; Bid storage bid = _getBidsStorage().bids[session.bidId]; - _onlyAccount(session.user); + _validateDelegatee(_msgSender(), session.user, DELEGATION_RULES_SESSION); + if (session.closedAt != 0) { revert SessionAlreadyClosed(); } @@ -258,16 +264,26 @@ contract SessionRouter is return (sessionEnd_ - session.openedAt) * bid.pricePerSecond - withdrawnAmount; } + function _getProviderOnHoldAmount(Session storage session, Bid storage bid) private view returns (uint256) { + uint128 startOfClosedAt = startOfTheDay(session.closedAt); + if (block.timestamp >= startOfClosedAt + 1 days) { + return 0; + } + + // `closedAt` - latest timestamp, cause `endsAt` bigger then `closedAt` + // Lock the provider's tokens for the current day. + // Withdrawal is allowed after a day after `startOfTheDay(session.closedAt)`. + return (session.closedAt - startOfClosedAt.max(session.openedAt)) * bid.pricePerSecond; + } + function _rewardProviderAfterClose(bool noDispute_, Session storage session, Bid storage bid) internal { - uint128 startOfToday_ = startOfTheDay(uint128(block.timestamp)); - bool isClosingLate_ = uint128(block.timestamp) > session.endsAt; + bool isClosingLate_ = session.closedAt >= session.endsAt; uint256 providerAmountToWithdraw_ = _getProviderRewards(session, bid, true); uint256 providerOnHoldAmount = 0; + // Enter when the user has a dispute AND closing early if (!noDispute_ && !isClosingLate_) { - providerOnHoldAmount = - (session.endsAt.min(session.closedAt) - startOfToday_.max(session.openedAt)) * - bid.pricePerSecond; + providerOnHoldAmount = _getProviderOnHoldAmount(session, bid); } providerAmountToWithdraw_ -= providerOnHoldAmount; @@ -275,19 +291,19 @@ contract SessionRouter is } function _rewardUserAfterClose(Session storage session, Bid storage bid) private { - uint128 startOfToday_ = startOfTheDay(uint128(block.timestamp)); - bool isClosingLate_ = uint128(block.timestamp) > session.endsAt; + uint128 startOfClosedAt_ = startOfTheDay(session.closedAt); + bool isClosingLate_ = session.closedAt >= session.endsAt; uint256 userStakeToProvider = session.isDirectPaymentFromUser ? _getProviderRewards(session, bid, false) : 0; uint256 userStake = session.stake - userStakeToProvider; uint256 userStakeToLock_ = 0; if (!isClosingLate_) { - uint256 userDuration_ = session.endsAt.min(session.closedAt) - session.openedAt.max(startOfToday_); + uint256 userDuration_ = session.endsAt.min(session.closedAt) - session.openedAt.max(startOfClosedAt_); uint256 userInitialLock_ = userDuration_ * bid.pricePerSecond; - userStakeToLock_ = userStake.min(stipendToStake(userInitialLock_, startOfToday_)); + userStakeToLock_ = userStake.min(stipendToStake(userInitialLock_, startOfClosedAt_)); _getSessionsStorage().userStakesOnHold[session.user].push( - OnHold(userStakeToLock_, uint128(startOfToday_ + 1 days)) + OnHold(userStakeToLock_, uint128(startOfClosedAt_ + 1 days)) ); } uint256 userAmountToWithdraw_ = userStake - userStakeToLock_; @@ -338,8 +354,11 @@ contract SessionRouter is Session storage session = _getSessionsStorage().sessions[sessionId_]; Bid storage bid = _getBidsStorage().bids[session.bidId]; - _onlyAccount(bid.provider); - _claimForProvider(session, _getProviderRewards(session, bid, true)); + _validateDelegatee(_msgSender(), bid.provider, DELEGATION_RULES_SESSION); + + uint256 amount_ = _getProviderRewards(session, bid, true) - _getProviderOnHoldAmount(session, bid); + + _claimForProvider(session, amount_); } /** @@ -370,7 +389,11 @@ contract SessionRouter is if (session.isDirectPaymentFromUser) { IERC20(_getBidsStorage().token).safeTransfer(bid.provider, amount_); } else { - IERC20(_getBidsStorage().token).safeTransferFrom(_getSessionsStorage().fundingAccount, bid.provider, amount_); + IERC20(_getBidsStorage().token).safeTransferFrom( + _getSessionsStorage().fundingAccount, + bid.provider, + amount_ + ); } } @@ -404,8 +427,10 @@ contract SessionRouter is } } - function withdrawUserStakes(uint8 iterations_) external { - OnHold[] storage onHoldEntries = _getSessionsStorage().userStakesOnHold[_msgSender()]; + function withdrawUserStakes(address user_, uint8 iterations_) external { + _validateDelegatee(_msgSender(), user_, DELEGATION_RULES_SESSION); + + OnHold[] storage onHoldEntries = _getSessionsStorage().userStakesOnHold[user_]; uint8 count_ = iterations_ >= onHoldEntries.length ? uint8(onHoldEntries.length) : iterations_; uint256 length_ = onHoldEntries.length; uint256 amount_ = 0; @@ -432,9 +457,9 @@ contract SessionRouter is revert SessionUserAmountToWithdrawIsZero(); } - IERC20(_getBidsStorage().token).safeTransfer(_msgSender(), amount_); + IERC20(_getBidsStorage().token).safeTransfer(user_, amount_); - emit UserWithdrawn(_msgSender(), amount_); + emit UserWithdrawn(user_, amount_); } //////////////////////// diff --git a/smart-contracts/contracts/diamond/presets/OwnableDiamondStorage.sol b/smart-contracts/contracts/diamond/presets/OwnableDiamondStorage.sol index d671a880..c484d6c8 100644 --- a/smart-contracts/contracts/diamond/presets/OwnableDiamondStorage.sol +++ b/smart-contracts/contracts/diamond/presets/OwnableDiamondStorage.sol @@ -16,10 +16,4 @@ abstract contract OwnableDiamondStorage is DiamondOwnableStorage, Context { revert OwnableUnauthorizedAccount(_msgSender()); } } - - function _onlyAccount(address sender_) internal view { - if (_msgSender() != sender_) { - revert OwnableUnauthorizedAccount(_msgSender()); - } - } } diff --git a/smart-contracts/contracts/diamond/storages/BidStorage.sol b/smart-contracts/contracts/diamond/storages/BidStorage.sol index 7a2db7ee..7a842aea 100644 --- a/smart-contracts/contracts/diamond/storages/BidStorage.sol +++ b/smart-contracts/contracts/diamond/storages/BidStorage.sol @@ -32,28 +32,40 @@ contract BidStorage is IBidStorage { address provider_, uint256 offset_, uint256 limit_ - ) external view returns (bytes32[] memory) { - return _getBidsStorage().providerActiveBids[provider_].part(offset_, limit_); + ) external view returns (bytes32[] memory, uint256) { + EnumerableSet.Bytes32Set storage providerActiveBids = _getBidsStorage().providerActiveBids[provider_]; + + return (providerActiveBids.part(offset_, limit_), providerActiveBids.length()); } function getModelActiveBids( bytes32 modelId_, uint256 offset_, uint256 limit_ - ) external view returns (bytes32[] memory) { - return _getBidsStorage().modelActiveBids[modelId_].part(offset_, limit_); + ) external view returns (bytes32[] memory, uint256) { + EnumerableSet.Bytes32Set storage modelActiveBids = _getBidsStorage().modelActiveBids[modelId_]; + + return (modelActiveBids.part(offset_, limit_), modelActiveBids.length()); } function getProviderBids( address provider_, uint256 offset_, uint256 limit_ - ) external view returns (bytes32[] memory) { - return _getBidsStorage().providerBids[provider_].part(offset_, limit_); + ) external view returns (bytes32[] memory, uint256) { + EnumerableSet.Bytes32Set storage providerBids = _getBidsStorage().providerBids[provider_]; + + return (providerBids.part(offset_, limit_), providerBids.length()); } - function getModelBids(bytes32 modelId_, uint256 offset_, uint256 limit_) external view returns (bytes32[] memory) { - return _getBidsStorage().modelBids[modelId_].part(offset_, limit_); + function getModelBids( + bytes32 modelId_, + uint256 offset_, + uint256 limit_ + ) external view returns (bytes32[] memory, uint256) { + EnumerableSet.Bytes32Set storage modelBids = _getBidsStorage().modelBids[modelId_]; + + return (modelBids.part(offset_, limit_), modelBids.length()); } function getToken() external view returns (address) { diff --git a/smart-contracts/contracts/diamond/storages/DelegationStorage.sol b/smart-contracts/contracts/diamond/storages/DelegationStorage.sol new file mode 100644 index 00000000..a5418894 --- /dev/null +++ b/smart-contracts/contracts/diamond/storages/DelegationStorage.sol @@ -0,0 +1,53 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.24; + +import {EnumerableSet} from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol"; +import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import {Paginator} from "@solarity/solidity-lib/libs/arrays/Paginator.sol"; + +import {IDelegationStorage} from "../../interfaces/storage/IDelegationStorage.sol"; +import {IDelegateRegistry} from "../../interfaces/deps/IDelegateRegistry.sol"; + +contract DelegationStorage is IDelegationStorage { + struct DLGTNStorage { + address registry; + } + + bytes32 public constant DELEGATION_STORAGE_SLOT = keccak256("diamond.standard.delegation.storage"); + bytes32 public constant DELEGATION_RULES_PROVIDER = keccak256("delegation.rules.provider"); + bytes32 public constant DELEGATION_RULES_MODEL = keccak256("delegation.rules.model"); + bytes32 public constant DELEGATION_RULES_MARKETPLACE = keccak256("delegation.rules.marketplace"); + bytes32 public constant DELEGATION_RULES_SESSION = keccak256("delegation.rules.session"); + + /** PUBLIC, GETTERS */ + function getRegistry() external view returns (address) { + return _getDelegationStorage().registry; + } + + function isRightsDelegated(address delegatee_, address delegator_, bytes32 rights_) public view returns (bool) { + DLGTNStorage storage delegationStorage = _getDelegationStorage(); + + return + IDelegateRegistry(delegationStorage.registry).checkDelegateForContract( + delegatee_, + delegator_, + address(this), + rights_ + ); + } + + /** INTERNAL */ + function _validateDelegatee(address delegatee_, address delegator_, bytes32 rights_) internal view { + if (delegatee_ != delegator_ && !isRightsDelegated(delegatee_, delegator_, rights_)) { + revert InsufficientRightsForOperation(delegator_, delegatee_); + } + } + + function _getDelegationStorage() internal pure returns (DLGTNStorage storage ds) { + bytes32 slot_ = DELEGATION_STORAGE_SLOT; + + assembly { + ds.slot := slot_ + } + } +} diff --git a/smart-contracts/contracts/diamond/storages/ModelStorage.sol b/smart-contracts/contracts/diamond/storages/ModelStorage.sol index 90df70cb..0b8425df 100644 --- a/smart-contracts/contracts/diamond/storages/ModelStorage.sol +++ b/smart-contracts/contracts/diamond/storages/ModelStorage.sol @@ -25,20 +25,24 @@ contract ModelStorage is IModelStorage { return _getModelsStorage().models[modelId_]; } - function getModelIds(uint256 offset_, uint256 limit_) external view returns (bytes32[] memory) { - return _getModelsStorage().modelIds.part(offset_, limit_); + function getModelIds(uint256 offset_, uint256 limit_) external view returns (bytes32[] memory, uint256) { + EnumerableSet.Bytes32Set storage modelIds = _getModelsStorage().modelIds; + + return (modelIds.part(offset_, limit_), modelIds.length()); } function getModelMinimumStake() external view returns (uint256) { return _getModelsStorage().modelMinimumStake; } - function getActiveModelIds(uint256 offset_, uint256 limit_) external view returns (bytes32[] memory) { - return _getModelsStorage().activeModels.part(offset_, limit_); + function getActiveModelIds(uint256 offset_, uint256 limit_) external view returns (bytes32[] memory, uint256) { + EnumerableSet.Bytes32Set storage activeModels = _getModelsStorage().activeModels; + + return (activeModels.part(offset_, limit_), activeModels.length()); } function getIsModelActive(bytes32 modelId_) public view returns (bool) { - return !_getModelsStorage().models[modelId_].isDeleted; + return (!_getModelsStorage().models[modelId_].isDeleted && _getModelsStorage().models[modelId_].createdAt != 0); } /** INTERNAL */ diff --git a/smart-contracts/contracts/diamond/storages/ProviderStorage.sol b/smart-contracts/contracts/diamond/storages/ProviderStorage.sol index ae87e2ce..5dad575c 100644 --- a/smart-contracts/contracts/diamond/storages/ProviderStorage.sol +++ b/smart-contracts/contracts/diamond/storages/ProviderStorage.sol @@ -31,12 +31,15 @@ contract ProviderStorage is IProviderStorage { return _getProvidersStorage().providerMinimumStake; } - function getActiveProviders(uint256 offset_, uint256 limit_) external view returns (address[] memory) { - return _getProvidersStorage().activeProviders.part(offset_, limit_); + function getActiveProviders(uint256 offset_, uint256 limit_) external view returns (address[] memory, uint256) { + EnumerableSet.AddressSet storage activeProviders = _getProvidersStorage().activeProviders; + + return (activeProviders.part(offset_, limit_), activeProviders.length()); } function getIsProviderActive(address provider_) public view returns (bool) { - return !_getProvidersStorage().providers[provider_].isDeleted; + return (!_getProvidersStorage().providers[provider_].isDeleted && + _getProvidersStorage().providers[provider_].createdAt != 0); } /** INTERNAL */ diff --git a/smart-contracts/contracts/diamond/storages/SessionStorage.sol b/smart-contracts/contracts/diamond/storages/SessionStorage.sol index eb33f9ae..3a34f4ef 100644 --- a/smart-contracts/contracts/diamond/storages/SessionStorage.sol +++ b/smart-contracts/contracts/diamond/storages/SessionStorage.sol @@ -40,24 +40,34 @@ contract SessionStorage is ISessionStorage { return _getSessionsStorage().sessions[sessionId_]; } - function getUserSessions(address user_, uint256 offset_, uint256 limit_) external view returns (bytes32[] memory) { - return _getSessionsStorage().userSessions[user_].part(offset_, limit_); + function getUserSessions( + address user_, + uint256 offset_, + uint256 limit_ + ) external view returns (bytes32[] memory, uint256) { + EnumerableSet.Bytes32Set storage userSessions = _getSessionsStorage().userSessions[user_]; + + return (userSessions.part(offset_, limit_), userSessions.length()); } function getProviderSessions( address provider_, uint256 offset_, uint256 limit_ - ) external view returns (bytes32[] memory) { - return _getSessionsStorage().providerSessions[provider_].part(offset_, limit_); + ) external view returns (bytes32[] memory, uint256) { + EnumerableSet.Bytes32Set storage providerSessions = _getSessionsStorage().providerSessions[provider_]; + + return (providerSessions.part(offset_, limit_), providerSessions.length()); } function getModelSessions( bytes32 modelId_, uint256 offset_, uint256 limit_ - ) external view returns (bytes32[] memory) { - return _getSessionsStorage().modelSessions[modelId_].part(offset_, limit_); + ) external view returns (bytes32[] memory, uint256) { + EnumerableSet.Bytes32Set storage modelSessions = _getSessionsStorage().modelSessions[modelId_]; + + return (modelSessions.part(offset_, limit_), modelSessions.length()); } function getPools() external view returns (Pool[] memory) { diff --git a/smart-contracts/contracts/diamond/storages/StatsStorage.sol b/smart-contracts/contracts/diamond/storages/StatsStorage.sol index 96fafeff..9a47c8fb 100644 --- a/smart-contracts/contracts/diamond/storages/StatsStorage.sol +++ b/smart-contracts/contracts/diamond/storages/StatsStorage.sol @@ -9,7 +9,7 @@ contract StatsStorage is IStatsStorage { mapping(bytes32 => ModelStats) modelStats; } - bytes32 public constant STATS_STORAGE_SLOT = keccak256("diamond.stats.storage"); + bytes32 public constant STATS_STORAGE_SLOT = keccak256("diamond.standard.stats.storage"); /** PUBLIC, GETTERS */ function getProviderModelStats( diff --git a/smart-contracts/contracts/interfaces/deps/IDelegateRegistry.sol b/smart-contracts/contracts/interfaces/deps/IDelegateRegistry.sol new file mode 100644 index 00000000..c3aa59b4 --- /dev/null +++ b/smart-contracts/contracts/interfaces/deps/IDelegateRegistry.sol @@ -0,0 +1,293 @@ +// SPDX-License-Identifier: CC0-1.0 +pragma solidity ^0.8.24; // Changed from `pragma solidity >=0.8.13;` + +/** + * @title IDelegateRegistry + * @custom:version 2.0 + * @custom:author foobar (0xfoobar) + * @notice A standalone immutable registry storing delegated permissions from one address to another + */ +interface IDelegateRegistry { + /// @notice Delegation type, NONE is used when a delegation does not exist or is revoked + enum DelegationType { + NONE, + ALL, + CONTRACT, + ERC721, + ERC20, + ERC1155 + } + + /// @notice Struct for returning delegations + struct Delegation { + DelegationType type_; + address to; + address from; + bytes32 rights; + address contract_; + uint256 tokenId; + uint256 amount; + } + + /// @notice Emitted when an address delegates or revokes rights for their entire wallet + event DelegateAll(address indexed from, address indexed to, bytes32 rights, bool enable); + + /// @notice Emitted when an address delegates or revokes rights for a contract address + event DelegateContract( + address indexed from, + address indexed to, + address indexed contract_, + bytes32 rights, + bool enable + ); + + /// @notice Emitted when an address delegates or revokes rights for an ERC721 tokenId + event DelegateERC721( + address indexed from, + address indexed to, + address indexed contract_, + uint256 tokenId, + bytes32 rights, + bool enable + ); + + /// @notice Emitted when an address delegates or revokes rights for an amount of ERC20 tokens + event DelegateERC20( + address indexed from, + address indexed to, + address indexed contract_, + bytes32 rights, + uint256 amount + ); + + /// @notice Emitted when an address delegates or revokes rights for an amount of an ERC1155 tokenId + event DelegateERC1155( + address indexed from, + address indexed to, + address indexed contract_, + uint256 tokenId, + bytes32 rights, + uint256 amount + ); + + /// @notice Thrown if multicall calldata is malformed + error MulticallFailed(); + + /** + * ----------- WRITE ----------- + */ + + /** + * @notice Call multiple functions in the current contract and return the data from all of them if they all succeed + * @param data The encoded function data for each of the calls to make to this contract + * @return results The results from each of the calls passed in via data + */ + function multicall(bytes[] calldata data) external payable returns (bytes[] memory results); + + /** + * @notice Allow the delegate to act on behalf of `msg.sender` for all contracts + * @param to The address to act as delegate + * @param rights Specific subdelegation rights granted to the delegate, pass an empty bytestring to encompass all rights + * @param enable Whether to enable or disable this delegation, true delegates and false revokes + * @return delegationHash The unique identifier of the delegation + */ + function delegateAll(address to, bytes32 rights, bool enable) external payable returns (bytes32 delegationHash); + + /** + * @notice Allow the delegate to act on behalf of `msg.sender` for a specific contract + * @param to The address to act as delegate + * @param contract_ The contract whose rights are being delegated + * @param rights Specific subdelegation rights granted to the delegate, pass an empty bytestring to encompass all rights + * @param enable Whether to enable or disable this delegation, true delegates and false revokes + * @return delegationHash The unique identifier of the delegation + */ + function delegateContract( + address to, + address contract_, + bytes32 rights, + bool enable + ) external payable returns (bytes32 delegationHash); + + /** + * @notice Allow the delegate to act on behalf of `msg.sender` for a specific ERC721 token + * @param to The address to act as delegate + * @param contract_ The contract whose rights are being delegated + * @param tokenId The token id to delegate + * @param rights Specific subdelegation rights granted to the delegate, pass an empty bytestring to encompass all rights + * @param enable Whether to enable or disable this delegation, true delegates and false revokes + * @return delegationHash The unique identifier of the delegation + */ + function delegateERC721( + address to, + address contract_, + uint256 tokenId, + bytes32 rights, + bool enable + ) external payable returns (bytes32 delegationHash); + + /** + * @notice Allow the delegate to act on behalf of `msg.sender` for a specific amount of ERC20 tokens + * @dev The actual amount is not encoded in the hash, just the existence of a amount (since it is an upper bound) + * @param to The address to act as delegate + * @param contract_ The address for the fungible token contract + * @param rights Specific subdelegation rights granted to the delegate, pass an empty bytestring to encompass all rights + * @param amount The amount to delegate, > 0 delegates and 0 revokes + * @return delegationHash The unique identifier of the delegation + */ + function delegateERC20( + address to, + address contract_, + bytes32 rights, + uint256 amount + ) external payable returns (bytes32 delegationHash); + + /** + * @notice Allow the delegate to act on behalf of `msg.sender` for a specific amount of ERC1155 tokens + * @dev The actual amount is not encoded in the hash, just the existence of a amount (since it is an upper bound) + * @param to The address to act as delegate + * @param contract_ The address of the contract that holds the token + * @param tokenId The token id to delegate + * @param rights Specific subdelegation rights granted to the delegate, pass an empty bytestring to encompass all rights + * @param amount The amount of that token id to delegate, > 0 delegates and 0 revokes + * @return delegationHash The unique identifier of the delegation + */ + function delegateERC1155( + address to, + address contract_, + uint256 tokenId, + bytes32 rights, + uint256 amount + ) external payable returns (bytes32 delegationHash); + + /** + * ----------- CHECKS ----------- + */ + + /** + * @notice Check if `to` is a delegate of `from` for the entire wallet + * @param to The potential delegate address + * @param from The potential address who delegated rights + * @param rights Specific rights to check for, pass the zero value to ignore subdelegations and check full delegations only + * @return valid Whether delegate is granted to act on the from's behalf + */ + function checkDelegateForAll(address to, address from, bytes32 rights) external view returns (bool); + + /** + * @notice Check if `to` is a delegate of `from` for the specified `contract_` or the entire wallet + * @param to The delegated address to check + * @param contract_ The specific contract address being checked + * @param from The cold wallet who issued the delegation + * @param rights Specific rights to check for, pass the zero value to ignore subdelegations and check full delegations only + * @return valid Whether delegate is granted to act on from's behalf for entire wallet or that specific contract + */ + function checkDelegateForContract( + address to, + address from, + address contract_, + bytes32 rights + ) external view returns (bool); + + /** + * @notice Check if `to` is a delegate of `from` for the specific `contract` and `tokenId`, the entire `contract_`, or the entire wallet + * @param to The delegated address to check + * @param contract_ The specific contract address being checked + * @param tokenId The token id for the token to delegating + * @param from The wallet that issued the delegation + * @param rights Specific rights to check for, pass the zero value to ignore subdelegations and check full delegations only + * @return valid Whether delegate is granted to act on from's behalf for entire wallet, that contract, or that specific tokenId + */ + function checkDelegateForERC721( + address to, + address from, + address contract_, + uint256 tokenId, + bytes32 rights + ) external view returns (bool); + + /** + * @notice Returns the amount of ERC20 tokens the delegate is granted rights to act on the behalf of + * @param to The delegated address to check + * @param contract_ The address of the token contract + * @param from The cold wallet who issued the delegation + * @param rights Specific rights to check for, pass the zero value to ignore subdelegations and check full delegations only + * @return balance The delegated balance, which will be 0 if the delegation does not exist + */ + function checkDelegateForERC20( + address to, + address from, + address contract_, + bytes32 rights + ) external view returns (uint256); + + /** + * @notice Returns the amount of a ERC1155 tokens the delegate is granted rights to act on the behalf of + * @param to The delegated address to check + * @param contract_ The address of the token contract + * @param tokenId The token id to check the delegated amount of + * @param from The cold wallet who issued the delegation + * @param rights Specific rights to check for, pass the zero value to ignore subdelegations and check full delegations only + * @return balance The delegated balance, which will be 0 if the delegation does not exist + */ + function checkDelegateForERC1155( + address to, + address from, + address contract_, + uint256 tokenId, + bytes32 rights + ) external view returns (uint256); + + /** + * ----------- ENUMERATIONS ----------- + */ + + /** + * @notice Returns all enabled delegations a given delegate has received + * @param to The address to retrieve delegations for + * @return delegations Array of Delegation structs + */ + function getIncomingDelegations(address to) external view returns (Delegation[] memory delegations); + + /** + * @notice Returns all enabled delegations an address has given out + * @param from The address to retrieve delegations for + * @return delegations Array of Delegation structs + */ + function getOutgoingDelegations(address from) external view returns (Delegation[] memory delegations); + + /** + * @notice Returns all hashes associated with enabled delegations an address has received + * @param to The address to retrieve incoming delegation hashes for + * @return delegationHashes Array of delegation hashes + */ + function getIncomingDelegationHashes(address to) external view returns (bytes32[] memory delegationHashes); + + /** + * @notice Returns all hashes associated with enabled delegations an address has given out + * @param from The address to retrieve outgoing delegation hashes for + * @return delegationHashes Array of delegation hashes + */ + function getOutgoingDelegationHashes(address from) external view returns (bytes32[] memory delegationHashes); + + /** + * @notice Returns the delegations for a given array of delegation hashes + * @param delegationHashes is an array of hashes that correspond to delegations + * @return delegations Array of Delegation structs, return empty structs for nonexistent or revoked delegations + */ + function getDelegationsFromHashes( + bytes32[] calldata delegationHashes + ) external view returns (Delegation[] memory delegations); + + /** + * ----------- STORAGE ACCESS ----------- + */ + + /** + * @notice Allows external contracts to read arbitrary storage slots + */ + function readSlot(bytes32 location) external view returns (bytes32); + + /** + * @notice Allows external contracts to read an arbitrary array of storage slots + */ + function readSlots(bytes32[] calldata locations) external view returns (bytes32[] memory); +} diff --git a/smart-contracts/contracts/interfaces/facets/IDelegation.sol b/smart-contracts/contracts/interfaces/facets/IDelegation.sol new file mode 100644 index 00000000..3adb2619 --- /dev/null +++ b/smart-contracts/contracts/interfaces/facets/IDelegation.sol @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.24; + +import {IDelegationStorage} from "../storage/IDelegationStorage.sol"; + +interface IDelegation is IDelegationStorage { + event DelegationRegistryUpdated(address registry); + + /** + * The function to initialize the facet. + * @param registry_ https://docs.delegate.xyz/technical-documentation/delegate-registry/contract-addresses + */ + function __Delegation_init(address registry_) external; + + /** + * The function to set the registry. + * @param registry_ https://docs.delegate.xyz/technical-documentation/delegate-registry/contract-addresses + */ + function setRegistry(address registry_) external; +} diff --git a/smart-contracts/contracts/interfaces/facets/IMarketplace.sol b/smart-contracts/contracts/interfaces/facets/IMarketplace.sol index 8a61e14c..f2ddb297 100644 --- a/smart-contracts/contracts/interfaces/facets/IMarketplace.sol +++ b/smart-contracts/contracts/interfaces/facets/IMarketplace.sol @@ -19,38 +19,36 @@ interface IMarketplace is IMarketplaceStorage { /** * The function to initialize the facet. - * @param token_ Stake token (MOR) - * @param bidMinPricePerSecond_ Min price per second for bid - * @param bidMaxPricePerSecond_ Max price per second for bid + * @param token_ Stake token (MOR). + * @param bidMinPricePerSecond_ Min price per second for bid. + * @param bidMaxPricePerSecond_ Max price per second for bid. */ function __Marketplace_init(address token_, uint256 bidMinPricePerSecond_, uint256 bidMaxPricePerSecond_) external; /** * The function to set the bidFee. - * @param bidFee_ Amount of tokens + * @param bidFee_ Amount of tokens. */ function setMarketplaceBidFee(uint256 bidFee_) external; /** * The function to set the min and max price per second for bid. - * @param bidMinPricePerSecond_ Min price per second for bid - * @param bidMaxPricePerSecond_ Max price per second for bid + * @param bidMinPricePerSecond_ Min price per second for bid. + * @param bidMaxPricePerSecond_ Max price per second for bid. */ - function setMinMaxBidPricePerSecond( - uint256 bidMinPricePerSecond_, - uint256 bidMaxPricePerSecond_ - ) external; + function setMinMaxBidPricePerSecond(uint256 bidMinPricePerSecond_, uint256 bidMaxPricePerSecond_) external; /** * The function to create the bid. - * @param modelId_ The mode ID - * @param pricePerSecond_ The price per second + * @param provider_ The provider address. + * @param modelId_ The mode ID. + * @param pricePerSecond_ The price per second. */ - function postModelBid(bytes32 modelId_, uint256 pricePerSecond_) external returns (bytes32); + function postModelBid(address provider_, bytes32 modelId_, uint256 pricePerSecond_) external returns (bytes32); /** * The function to delete the bid. - * @param bidId_ The bid ID + * @param bidId_ The bid ID. */ function deleteModelBid(bytes32 bidId_) external; @@ -70,7 +68,7 @@ interface IMarketplace is IMarketplaceStorage { function getBidId(address provider_, bytes32 modelId_, uint256 nonce_) external view returns (bytes32); /** - * The function to returns provider model ID + * The function to returns provider model ID. * @param provider_ The provider address. * @param modelId_ The model ID. */ diff --git a/smart-contracts/contracts/interfaces/facets/IModelRegistry.sol b/smart-contracts/contracts/interfaces/facets/IModelRegistry.sol index c842a04d..0bea4210 100644 --- a/smart-contracts/contracts/interfaces/facets/IModelRegistry.sol +++ b/smart-contracts/contracts/interfaces/facets/IModelRegistry.sol @@ -25,6 +25,7 @@ interface IModelRegistry is IModelStorage { /** * The function to register the model. + * @param modelOwner_ The model owner address. * @param modelId_ The model ID. * @param ipfsCID_ The model IPFS CID. * @param fee_ The model fee. @@ -33,6 +34,7 @@ interface IModelRegistry is IModelStorage { * @param tags_ The model tags. */ function modelRegister( + address modelOwner_, bytes32 modelId_, bytes32 ipfsCID_, uint256 fee_, @@ -46,4 +48,11 @@ interface IModelRegistry is IModelStorage { * @param modelId_ The model ID. */ function modelDeregister(bytes32 modelId_) external; + + /** + * Form model ID for the user models. + * @param account_ The address. + * @param baseModelId_ The base model ID. + */ + function getModelId(address account_, bytes32 baseModelId_) external pure returns (bytes32); } diff --git a/smart-contracts/contracts/interfaces/facets/IProviderRegistry.sol b/smart-contracts/contracts/interfaces/facets/IProviderRegistry.sol index 3c05429d..8386e5e3 100644 --- a/smart-contracts/contracts/interfaces/facets/IProviderRegistry.sol +++ b/smart-contracts/contracts/interfaces/facets/IProviderRegistry.sol @@ -28,14 +28,16 @@ interface IProviderRegistry is IProviderStorage { function providerSetMinStake(uint256 providerMinimumStake_) external; /** - * @notice The function to register the provider - * @param amount_ The amount of stake to add - * @param endpoint_ The provider endpoint (host.com:1234) + * @notice The function to register the provider. + * @param provider_ The provider address. + * @param amount_ The amount of stake to add. + * @param endpoint_ The provider endpoint (host.com:1234). */ - function providerRegister(uint256 amount_, string calldata endpoint_) external; + function providerRegister(address provider_, uint256 amount_, string calldata endpoint_) external; /** - * @notice The function to deregister the provider + * @notice The function to deregister the provider. + * @param provider_ The provider address. */ - function providerDeregister() external; + function providerDeregister(address provider_) external; } diff --git a/smart-contracts/contracts/interfaces/facets/ISessionRouter.sol b/smart-contracts/contracts/interfaces/facets/ISessionRouter.sol index f58439bd..ff759435 100644 --- a/smart-contracts/contracts/interfaces/facets/ISessionRouter.sol +++ b/smart-contracts/contracts/interfaces/facets/ISessionRouter.sol @@ -56,12 +56,14 @@ interface ISessionRouter is ISessionStorage { /** * The function to open the session. + * @param user_ The user address. * @param amount_ The stake amount. * @param isDirectPaymentFromUser_ If active, provider rewarded from the user stake. * @param approvalEncoded_ Provider approval. * @param signature_ Provider signature. */ function openSession( + address user_, uint256 amount_, bool isDirectPaymentFromUser_, bytes calldata approvalEncoded_, @@ -132,9 +134,10 @@ interface ISessionRouter is ISessionStorage { /** * The function to withdraw user stakes. + * @param user_ The user address. * @param iterations_ The loop interaction amount. */ - function withdrawUserStakes(uint8 iterations_) external; + function withdrawUserStakes(address user_, uint8 iterations_) external; /** * Returns today's budget in MOR. 1%. diff --git a/smart-contracts/contracts/interfaces/storage/IBidStorage.sol b/smart-contracts/contracts/interfaces/storage/IBidStorage.sol index 708bf7e8..05f2ad25 100644 --- a/smart-contracts/contracts/interfaces/storage/IBidStorage.sol +++ b/smart-contracts/contracts/interfaces/storage/IBidStorage.sol @@ -36,7 +36,7 @@ interface IBidStorage { address provider_, uint256 offset_, uint256 limit_ - ) external view returns (bytes32[] memory); + ) external view returns (bytes32[] memory, uint256); /** * The function returns active model bids. @@ -48,7 +48,7 @@ interface IBidStorage { bytes32 modelId_, uint256 offset_, uint256 limit_ - ) external view returns (bytes32[] memory); + ) external view returns (bytes32[] memory, uint256); /** * The function returns provider bids. @@ -60,7 +60,7 @@ interface IBidStorage { address provider_, uint256 offset_, uint256 limit_ - ) external view returns (bytes32[] memory); + ) external view returns (bytes32[] memory, uint256); /** * The function returns model bids. @@ -68,7 +68,11 @@ interface IBidStorage { * @param offset_ Offset for the pagination. * @param limit_ Number of entities to return. */ - function getModelBids(bytes32 modelId_, uint256 offset_, uint256 limit_) external view returns (bytes32[] memory); + function getModelBids( + bytes32 modelId_, + uint256 offset_, + uint256 limit_ + ) external view returns (bytes32[] memory, uint256); /** * The function returns stake token (MOR). diff --git a/smart-contracts/contracts/interfaces/storage/IDelegationStorage.sol b/smart-contracts/contracts/interfaces/storage/IDelegationStorage.sol new file mode 100644 index 00000000..487f56cd --- /dev/null +++ b/smart-contracts/contracts/interfaces/storage/IDelegationStorage.sol @@ -0,0 +1,37 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.24; + +interface IDelegationStorage { + error InsufficientRightsForOperation(address delegator, address delegatee); + + /** + * @return `keccak256("delegation.rules.provider")` + */ + function DELEGATION_RULES_PROVIDER() external view returns (bytes32); + + /** + * @return `keccak256("delegation.rules.model")` + */ + function DELEGATION_RULES_MODEL() external view returns (bytes32); + + /** + * @return `keccak256("delegation.rules.marketplace")` + */ + function DELEGATION_RULES_MARKETPLACE() external view returns (bytes32); + + /** + * @return `keccak256("delegation.rules.session")` + */ + function DELEGATION_RULES_SESSION() external view returns (bytes32); + + /** + * @return The registry address. + */ + function getRegistry() external view returns (address); + + /** + * The function to check is `delegator_` add permissions for `delegatee_`. + * @return `true` when delegated. + */ + function isRightsDelegated(address delegatee_, address delegator_, bytes32 rights_) external view returns (bool); +} diff --git a/smart-contracts/contracts/interfaces/storage/IModelStorage.sol b/smart-contracts/contracts/interfaces/storage/IModelStorage.sol index 64529112..9387ad5f 100644 --- a/smart-contracts/contracts/interfaces/storage/IModelStorage.sol +++ b/smart-contracts/contracts/interfaces/storage/IModelStorage.sol @@ -35,7 +35,7 @@ interface IModelStorage { * @param offset_ Offset for the pagination. * @param limit_ Number of entities to return. */ - function getModelIds(uint256 offset_, uint256 limit_) external view returns (bytes32[] memory); + function getModelIds(uint256 offset_, uint256 limit_) external view returns (bytes32[] memory, uint256); /** * The function returns the model minimal stake. @@ -47,7 +47,7 @@ interface IModelStorage { * @param offset_ Offset for the pagination. * @param limit_ Number of entities to return. */ - function getActiveModelIds(uint256 offset_, uint256 limit_) external view returns (bytes32[] memory); + function getActiveModelIds(uint256 offset_, uint256 limit_) external view returns (bytes32[] memory, uint256); /** * The function returns the model status, active or not. diff --git a/smart-contracts/contracts/interfaces/storage/IProviderStorage.sol b/smart-contracts/contracts/interfaces/storage/IProviderStorage.sol index 74fc8e1d..308a711d 100644 --- a/smart-contracts/contracts/interfaces/storage/IProviderStorage.sol +++ b/smart-contracts/contracts/interfaces/storage/IProviderStorage.sol @@ -36,7 +36,7 @@ interface IProviderStorage { * @param offset_ Offset for the pagination. * @param limit_ Number of entities to return. */ - function getActiveProviders(uint256 offset_, uint256 limit_) external view returns (address[] memory); + function getActiveProviders(uint256 offset_, uint256 limit_) external view returns (address[] memory, uint256); /** * The function returns provider status, active or not. diff --git a/smart-contracts/contracts/interfaces/storage/ISessionStorage.sol b/smart-contracts/contracts/interfaces/storage/ISessionStorage.sol index b2eb97ed..50abd11d 100644 --- a/smart-contracts/contracts/interfaces/storage/ISessionStorage.sol +++ b/smart-contracts/contracts/interfaces/storage/ISessionStorage.sol @@ -63,7 +63,11 @@ interface ISessionStorage { * @param offset_ Offset for the pagination. * @param limit_ Number of entities to return. */ - function getUserSessions(address user_, uint256 offset_, uint256 limit_) external view returns (bytes32[] memory); + function getUserSessions( + address user_, + uint256 offset_, + uint256 limit_ + ) external view returns (bytes32[] memory, uint256); /** * The function returns the provider session IDs. @@ -75,7 +79,7 @@ interface ISessionStorage { address provider_, uint256 offset_, uint256 limit_ - ) external view returns (bytes32[] memory); + ) external view returns (bytes32[] memory, uint256); /** * The function returns the model session IDs. @@ -87,7 +91,7 @@ interface ISessionStorage { bytes32 modelId_, uint256 offset_, uint256 limit_ - ) external view returns (bytes32[] memory); + ) external view returns (bytes32[] memory, uint256); /** * The function returns the pools info. diff --git a/smart-contracts/contracts/mock/delegate-registry/DelegateRegistry.sol b/smart-contracts/contracts/mock/delegate-registry/DelegateRegistry.sol new file mode 100644 index 00000000..766413d4 --- /dev/null +++ b/smart-contracts/contracts/mock/delegate-registry/DelegateRegistry.sol @@ -0,0 +1,549 @@ +// SPDX-License-Identifier: CC0-1.0 +pragma solidity ^0.8.21; + +import {IDelegateRegistry as IDelegateRegistry} from "./IDelegateRegistry.sol"; +import {RegistryHashes as Hashes} from "./libraries/RegistryHashes.sol"; +import {RegistryStorage as Storage} from "./libraries/RegistryStorage.sol"; +import {RegistryOps as Ops} from "./libraries/RegistryOps.sol"; + +/** + * @title DelegateRegistry + * @custom:version 2.0 + * @custom:coauthor foobar (0xfoobar) + * @custom:coauthor mireynolds + * @notice A standalone immutable registry storing delegated permissions from one address to another + */ +contract DelegateRegistry is IDelegateRegistry { + /// @dev Only this mapping should be used to verify delegations; the other mapping arrays are for enumerations + mapping(bytes32 delegationHash => bytes32[5] delegationStorage) internal delegations; + + /// @dev Vault delegation enumeration outbox, for pushing new hashes only + mapping(address from => bytes32[] delegationHashes) internal outgoingDelegationHashes; + + /// @dev Delegate enumeration inbox, for pushing new hashes only + mapping(address to => bytes32[] delegationHashes) internal incomingDelegationHashes; + + /** + * ----------- WRITE ----------- + */ + + /// @inheritdoc IDelegateRegistry + function multicall(bytes[] calldata data) external payable override returns (bytes[] memory results) { + results = new bytes[](data.length); + bool success; + unchecked { + for (uint256 i = 0; i < data.length; ++i) { + //slither-disable-next-line calls-loop,delegatecall-loop + (success, results[i]) = address(this).delegatecall(data[i]); + if (!success) revert MulticallFailed(); + } + } + } + + /// @inheritdoc IDelegateRegistry + function delegateAll(address to, bytes32 rights, bool enable) external payable override returns (bytes32 hash) { + hash = Hashes.allHash(msg.sender, rights, to); + bytes32 location = Hashes.location(hash); + address loadedFrom = _loadFrom(location); + if (enable) { + if (loadedFrom == Storage.DELEGATION_EMPTY) { + _pushDelegationHashes(msg.sender, to, hash); + _writeDelegationAddresses(location, msg.sender, to, address(0)); + if (rights != "") _writeDelegation(location, Storage.POSITIONS_RIGHTS, rights); + } else if (loadedFrom == Storage.DELEGATION_REVOKED) { + _updateFrom(location, msg.sender); + } + } else if (loadedFrom == msg.sender) { + _updateFrom(location, Storage.DELEGATION_REVOKED); + } + emit DelegateAll(msg.sender, to, rights, enable); + } + + /// @inheritdoc IDelegateRegistry + function delegateContract( + address to, + address contract_, + bytes32 rights, + bool enable + ) external payable override returns (bytes32 hash) { + hash = Hashes.contractHash(msg.sender, rights, to, contract_); + bytes32 location = Hashes.location(hash); + address loadedFrom = _loadFrom(location); + if (enable) { + if (loadedFrom == Storage.DELEGATION_EMPTY) { + _pushDelegationHashes(msg.sender, to, hash); + _writeDelegationAddresses(location, msg.sender, to, contract_); + if (rights != "") _writeDelegation(location, Storage.POSITIONS_RIGHTS, rights); + } else if (loadedFrom == Storage.DELEGATION_REVOKED) { + _updateFrom(location, msg.sender); + } + } else if (loadedFrom == msg.sender) { + _updateFrom(location, Storage.DELEGATION_REVOKED); + } + emit DelegateContract(msg.sender, to, contract_, rights, enable); + } + + /// @inheritdoc IDelegateRegistry + function delegateERC721( + address to, + address contract_, + uint256 tokenId, + bytes32 rights, + bool enable + ) external payable override returns (bytes32 hash) { + hash = Hashes.erc721Hash(msg.sender, rights, to, tokenId, contract_); + bytes32 location = Hashes.location(hash); + address loadedFrom = _loadFrom(location); + if (enable) { + if (loadedFrom == Storage.DELEGATION_EMPTY) { + _pushDelegationHashes(msg.sender, to, hash); + _writeDelegationAddresses(location, msg.sender, to, contract_); + _writeDelegation(location, Storage.POSITIONS_TOKEN_ID, tokenId); + if (rights != "") _writeDelegation(location, Storage.POSITIONS_RIGHTS, rights); + } else if (loadedFrom == Storage.DELEGATION_REVOKED) { + _updateFrom(location, msg.sender); + } + } else if (loadedFrom == msg.sender) { + _updateFrom(location, Storage.DELEGATION_REVOKED); + } + emit DelegateERC721(msg.sender, to, contract_, tokenId, rights, enable); + } + + // @inheritdoc IDelegateRegistry + function delegateERC20( + address to, + address contract_, + bytes32 rights, + uint256 amount + ) external payable override returns (bytes32 hash) { + hash = Hashes.erc20Hash(msg.sender, rights, to, contract_); + bytes32 location = Hashes.location(hash); + address loadedFrom = _loadFrom(location); + if (amount != 0) { + if (loadedFrom == Storage.DELEGATION_EMPTY) { + _pushDelegationHashes(msg.sender, to, hash); + _writeDelegationAddresses(location, msg.sender, to, contract_); + _writeDelegation(location, Storage.POSITIONS_AMOUNT, amount); + if (rights != "") _writeDelegation(location, Storage.POSITIONS_RIGHTS, rights); + } else if (loadedFrom == Storage.DELEGATION_REVOKED) { + _updateFrom(location, msg.sender); + _writeDelegation(location, Storage.POSITIONS_AMOUNT, amount); + } else if (loadedFrom == msg.sender) { + _writeDelegation(location, Storage.POSITIONS_AMOUNT, amount); + } + } else if (loadedFrom == msg.sender) { + _updateFrom(location, Storage.DELEGATION_REVOKED); + _writeDelegation(location, Storage.POSITIONS_AMOUNT, uint256(0)); + } + emit DelegateERC20(msg.sender, to, contract_, rights, amount); + } + + /// @inheritdoc IDelegateRegistry + function delegateERC1155( + address to, + address contract_, + uint256 tokenId, + bytes32 rights, + uint256 amount + ) external payable override returns (bytes32 hash) { + hash = Hashes.erc1155Hash(msg.sender, rights, to, tokenId, contract_); + bytes32 location = Hashes.location(hash); + address loadedFrom = _loadFrom(location); + if (amount != 0) { + if (loadedFrom == Storage.DELEGATION_EMPTY) { + _pushDelegationHashes(msg.sender, to, hash); + _writeDelegationAddresses(location, msg.sender, to, contract_); + _writeDelegation(location, Storage.POSITIONS_TOKEN_ID, tokenId); + _writeDelegation(location, Storage.POSITIONS_AMOUNT, amount); + if (rights != "") _writeDelegation(location, Storage.POSITIONS_RIGHTS, rights); + } else if (loadedFrom == Storage.DELEGATION_REVOKED) { + _updateFrom(location, msg.sender); + _writeDelegation(location, Storage.POSITIONS_AMOUNT, amount); + } else if (loadedFrom == msg.sender) { + _writeDelegation(location, Storage.POSITIONS_AMOUNT, amount); + } + } else if (loadedFrom == msg.sender) { + _updateFrom(location, Storage.DELEGATION_REVOKED); + _writeDelegation(location, Storage.POSITIONS_AMOUNT, uint256(0)); + } + emit DelegateERC1155(msg.sender, to, contract_, tokenId, rights, amount); + } + + /// @dev Transfer native token out + function sweep() external { + assembly ("memory-safe") { + // This hardcoded address is a CREATE2 factory counterfactual smart contract wallet that will always accept native token transfers + let result := call(gas(), 0x000000dE1E80ea5a234FB5488fee2584251BC7e8, selfbalance(), 0, 0, 0, 0) + } + } + + /** + * ----------- CHECKS ----------- + */ + + /// @inheritdoc IDelegateRegistry + function checkDelegateForAll(address to, address from, bytes32 rights) external view override returns (bool valid) { + if (!_invalidFrom(from)) { + valid = _validateFrom(Hashes.allLocation(from, "", to), from); + if (!Ops.or(rights == "", valid)) valid = _validateFrom(Hashes.allLocation(from, rights, to), from); + } + assembly ("memory-safe") { + // Only first 32 bytes of scratch space is accessed + mstore(0, iszero(iszero(valid))) // Compiler cleans dirty booleans on the stack to 1, so do the same here + return(0, 32) // Direct return, skips Solidity's redundant copying to save gas + } + } + + /// @inheritdoc IDelegateRegistry + function checkDelegateForContract( + address to, + address from, + address contract_, + bytes32 rights + ) external view override returns (bool valid) { + if (!_invalidFrom(from)) { + valid = + _validateFrom(Hashes.allLocation(from, "", to), from) || + _validateFrom(Hashes.contractLocation(from, "", to, contract_), from); + if (!Ops.or(rights == "", valid)) { + valid = + _validateFrom(Hashes.allLocation(from, rights, to), from) || + _validateFrom(Hashes.contractLocation(from, rights, to, contract_), from); + } + } + assembly ("memory-safe") { + // Only first 32 bytes of scratch space is accessed + mstore(0, iszero(iszero(valid))) // Compiler cleans dirty booleans on the stack to 1, so do the same here + return(0, 32) // Direct return, skips Solidity's redundant copying to save gas + } + } + + /// @inheritdoc IDelegateRegistry + function checkDelegateForERC721( + address to, + address from, + address contract_, + uint256 tokenId, + bytes32 rights + ) external view override returns (bool valid) { + if (!_invalidFrom(from)) { + valid = + _validateFrom(Hashes.allLocation(from, "", to), from) || + _validateFrom(Hashes.contractLocation(from, "", to, contract_), from) || + _validateFrom(Hashes.erc721Location(from, "", to, tokenId, contract_), from); + if (!Ops.or(rights == "", valid)) { + valid = + _validateFrom(Hashes.allLocation(from, rights, to), from) || + _validateFrom(Hashes.contractLocation(from, rights, to, contract_), from) || + _validateFrom(Hashes.erc721Location(from, rights, to, tokenId, contract_), from); + } + } + assembly ("memory-safe") { + // Only first 32 bytes of scratch space is accessed + mstore(0, iszero(iszero(valid))) // Compiler cleans dirty booleans on the stack to 1, so do the same here + return(0, 32) // Direct return, skips Solidity's redundant copying to save gas + } + } + + /// @inheritdoc IDelegateRegistry + function checkDelegateForERC20( + address to, + address from, + address contract_, + bytes32 rights + ) external view override returns (uint256 amount) { + if (!_invalidFrom(from)) { + amount = (_validateFrom(Hashes.allLocation(from, "", to), from) || + _validateFrom(Hashes.contractLocation(from, "", to, contract_), from)) + ? type(uint256).max + : _loadDelegationUint(Hashes.erc20Location(from, "", to, contract_), Storage.POSITIONS_AMOUNT); + if (!Ops.or(rights == "", amount == type(uint256).max)) { + uint256 rightsBalance = (_validateFrom(Hashes.allLocation(from, rights, to), from) || + _validateFrom(Hashes.contractLocation(from, rights, to, contract_), from)) + ? type(uint256).max + : _loadDelegationUint(Hashes.erc20Location(from, rights, to, contract_), Storage.POSITIONS_AMOUNT); + amount = Ops.max(rightsBalance, amount); + } + } + assembly ("memory-safe") { + mstore(0, amount) // Only first 32 bytes of scratch space being accessed + return(0, 32) // Direct return, skips Solidity's redundant copying to save gas + } + } + + /// @inheritdoc IDelegateRegistry + function checkDelegateForERC1155( + address to, + address from, + address contract_, + uint256 tokenId, + bytes32 rights + ) external view override returns (uint256 amount) { + if (!_invalidFrom(from)) { + amount = (_validateFrom(Hashes.allLocation(from, "", to), from) || + _validateFrom(Hashes.contractLocation(from, "", to, contract_), from)) + ? type(uint256).max + : _loadDelegationUint( + Hashes.erc1155Location(from, "", to, tokenId, contract_), + Storage.POSITIONS_AMOUNT + ); + if (!Ops.or(rights == "", amount == type(uint256).max)) { + uint256 rightsBalance = (_validateFrom(Hashes.allLocation(from, rights, to), from) || + _validateFrom(Hashes.contractLocation(from, rights, to, contract_), from)) + ? type(uint256).max + : _loadDelegationUint( + Hashes.erc1155Location(from, rights, to, tokenId, contract_), + Storage.POSITIONS_AMOUNT + ); + amount = Ops.max(rightsBalance, amount); + } + } + assembly ("memory-safe") { + mstore(0, amount) // Only first 32 bytes of scratch space is accessed + return(0, 32) // Direct return, skips Solidity's redundant copying to save gas + } + } + + /** + * ----------- ENUMERATIONS ----------- + */ + + /// @inheritdoc IDelegateRegistry + function getIncomingDelegations(address to) external view override returns (Delegation[] memory delegations_) { + delegations_ = _getValidDelegationsFromHashes(incomingDelegationHashes[to]); + } + + /// @inheritdoc IDelegateRegistry + function getOutgoingDelegations(address from) external view returns (Delegation[] memory delegations_) { + delegations_ = _getValidDelegationsFromHashes(outgoingDelegationHashes[from]); + } + + /// @inheritdoc IDelegateRegistry + function getIncomingDelegationHashes(address to) external view returns (bytes32[] memory delegationHashes) { + delegationHashes = _getValidDelegationHashesFromHashes(incomingDelegationHashes[to]); + } + + /// @inheritdoc IDelegateRegistry + function getOutgoingDelegationHashes(address from) external view returns (bytes32[] memory delegationHashes) { + delegationHashes = _getValidDelegationHashesFromHashes(outgoingDelegationHashes[from]); + } + + /// @inheritdoc IDelegateRegistry + function getDelegationsFromHashes( + bytes32[] calldata hashes + ) external view returns (Delegation[] memory delegations_) { + delegations_ = new Delegation[](hashes.length); + unchecked { + for (uint256 i = 0; i < hashes.length; ++i) { + bytes32 location = Hashes.location(hashes[i]); + address from = _loadFrom(location); + if (_invalidFrom(from)) { + delegations_[i] = Delegation({ + type_: DelegationType.NONE, + to: address(0), + from: address(0), + rights: "", + amount: 0, + contract_: address(0), + tokenId: 0 + }); + } else { + (, address to, address contract_) = _loadDelegationAddresses(location); + delegations_[i] = Delegation({ + type_: Hashes.decodeType(hashes[i]), + to: to, + from: from, + rights: _loadDelegationBytes32(location, Storage.POSITIONS_RIGHTS), + amount: _loadDelegationUint(location, Storage.POSITIONS_AMOUNT), + contract_: contract_, + tokenId: _loadDelegationUint(location, Storage.POSITIONS_TOKEN_ID) + }); + } + } + } + } + + /** + * ----------- EXTERNAL STORAGE ACCESS ----------- + */ + function readSlot(bytes32 location) external view returns (bytes32 contents) { + assembly { + contents := sload(location) + } + } + + function readSlots(bytes32[] calldata locations) external view returns (bytes32[] memory contents) { + uint256 length = locations.length; + contents = new bytes32[](length); + bytes32 tempLocation; + bytes32 tempValue; + unchecked { + for (uint256 i = 0; i < length; ++i) { + tempLocation = locations[i]; + assembly { + tempValue := sload(tempLocation) + } + contents[i] = tempValue; + } + } + } + + /** + * ----------- ERC165 ----------- + */ + + /// @notice Query if a contract implements an ERC-165 interface + /// @param interfaceId The interface identifier + /// @return valid Whether the queried interface is supported + function supportsInterface(bytes4 interfaceId) external pure returns (bool) { + return Ops.or(interfaceId == type(IDelegateRegistry).interfaceId, interfaceId == 0x01ffc9a7); + } + + /** + * ----------- INTERNAL ----------- + */ + + /// @dev Helper function to push new delegation hashes to the incoming and outgoing hashes mappings + function _pushDelegationHashes(address from, address to, bytes32 delegationHash) internal { + outgoingDelegationHashes[from].push(delegationHash); + incomingDelegationHashes[to].push(delegationHash); + } + + /// @dev Helper function that writes bytes32 data to delegation data location at array position + function _writeDelegation(bytes32 location, uint256 position, bytes32 data) internal { + assembly { + sstore(add(location, position), data) + } + } + + /// @dev Helper function that writes uint256 data to delegation data location at array position + function _writeDelegation(bytes32 location, uint256 position, uint256 data) internal { + assembly { + sstore(add(location, position), data) + } + } + + /// @dev Helper function that writes addresses according to the packing rule for delegation storage + function _writeDelegationAddresses(bytes32 location, address from, address to, address contract_) internal { + (bytes32 firstSlot, bytes32 secondSlot) = Storage.packAddresses(from, to, contract_); + uint256 firstPacked = Storage.POSITIONS_FIRST_PACKED; + uint256 secondPacked = Storage.POSITIONS_SECOND_PACKED; + assembly { + sstore(add(location, firstPacked), firstSlot) + sstore(add(location, secondPacked), secondSlot) + } + } + + /// @dev Helper function that writes `from` while preserving the rest of the storage slot + function _updateFrom(bytes32 location, address from) internal { + uint256 firstPacked = Storage.POSITIONS_FIRST_PACKED; + uint256 cleanAddress = Storage.CLEAN_ADDRESS; + uint256 cleanUpper12Bytes = type(uint256).max << 160; + assembly { + let slot := and(sload(add(location, firstPacked)), cleanUpper12Bytes) + sstore(add(location, firstPacked), or(slot, and(from, cleanAddress))) + } + } + + /// @dev Helper function that takes an array of delegation hashes and returns an array of Delegation structs with their onchain information + function _getValidDelegationsFromHashes( + bytes32[] storage hashes + ) internal view returns (Delegation[] memory delegations_) { + uint256 count = 0; + uint256 hashesLength = hashes.length; + bytes32 hash; + bytes32[] memory filteredHashes = new bytes32[](hashesLength); + unchecked { + for (uint256 i = 0; i < hashesLength; ++i) { + hash = hashes[i]; + if (_invalidFrom(_loadFrom(Hashes.location(hash)))) continue; + filteredHashes[count++] = hash; + } + delegations_ = new Delegation[](count); + bytes32 location; + for (uint256 i = 0; i < count; ++i) { + hash = filteredHashes[i]; + location = Hashes.location(hash); + (address from, address to, address contract_) = _loadDelegationAddresses(location); + delegations_[i] = Delegation({ + type_: Hashes.decodeType(hash), + to: to, + from: from, + rights: _loadDelegationBytes32(location, Storage.POSITIONS_RIGHTS), + amount: _loadDelegationUint(location, Storage.POSITIONS_AMOUNT), + contract_: contract_, + tokenId: _loadDelegationUint(location, Storage.POSITIONS_TOKEN_ID) + }); + } + } + } + + /// @dev Helper function that takes an array of delegation hashes and returns an array of valid delegation hashes + function _getValidDelegationHashesFromHashes( + bytes32[] storage hashes + ) internal view returns (bytes32[] memory validHashes) { + uint256 count = 0; + uint256 hashesLength = hashes.length; + bytes32 hash; + bytes32[] memory filteredHashes = new bytes32[](hashesLength); + unchecked { + for (uint256 i = 0; i < hashesLength; ++i) { + hash = hashes[i]; + if (_invalidFrom(_loadFrom(Hashes.location(hash)))) continue; + filteredHashes[count++] = hash; + } + validHashes = new bytes32[](count); + for (uint256 i = 0; i < count; ++i) { + validHashes[i] = filteredHashes[i]; + } + } + } + + /// @dev Helper function that loads delegation data from a particular array position and returns as bytes32 + function _loadDelegationBytes32(bytes32 location, uint256 position) internal view returns (bytes32 data) { + assembly { + data := sload(add(location, position)) + } + } + + /// @dev Helper function that loads delegation data from a particular array position and returns as uint256 + function _loadDelegationUint(bytes32 location, uint256 position) internal view returns (uint256 data) { + assembly { + data := sload(add(location, position)) + } + } + + // @dev Helper function that loads the from address from storage according to the packing rule for delegation storage + function _loadFrom(bytes32 location) internal view returns (address) { + bytes32 data; + uint256 firstPacked = Storage.POSITIONS_FIRST_PACKED; + assembly { + data := sload(add(location, firstPacked)) + } + return Storage.unpackAddress(data); + } + + /// @dev Helper function to establish whether a delegation is enabled + function _validateFrom(bytes32 location, address from) internal view returns (bool) { + return (from == _loadFrom(location)); + } + + /// @dev Helper function that loads the address for the delegation according to the packing rule for delegation storage + function _loadDelegationAddresses( + bytes32 location + ) internal view returns (address from, address to, address contract_) { + bytes32 firstSlot; + bytes32 secondSlot; + uint256 firstPacked = Storage.POSITIONS_FIRST_PACKED; + uint256 secondPacked = Storage.POSITIONS_SECOND_PACKED; + assembly { + firstSlot := sload(add(location, firstPacked)) + secondSlot := sload(add(location, secondPacked)) + } + (from, to, contract_) = Storage.unpackAddresses(firstSlot, secondSlot); + } + + function _invalidFrom(address from) internal pure returns (bool) { + return Ops.or(from == Storage.DELEGATION_EMPTY, from == Storage.DELEGATION_REVOKED); + } +} diff --git a/smart-contracts/contracts/mock/delegate-registry/IDelegateRegistry.sol b/smart-contracts/contracts/mock/delegate-registry/IDelegateRegistry.sol new file mode 100644 index 00000000..5ff67ad2 --- /dev/null +++ b/smart-contracts/contracts/mock/delegate-registry/IDelegateRegistry.sol @@ -0,0 +1,293 @@ +// SPDX-License-Identifier: CC0-1.0 +pragma solidity >=0.8.13; + +/** + * @title IDelegateRegistry + * @custom:version 2.0 + * @custom:author foobar (0xfoobar) + * @notice A standalone immutable registry storing delegated permissions from one address to another + */ +interface IDelegateRegistry { + /// @notice Delegation type, NONE is used when a delegation does not exist or is revoked + enum DelegationType { + NONE, + ALL, + CONTRACT, + ERC721, + ERC20, + ERC1155 + } + + /// @notice Struct for returning delegations + struct Delegation { + DelegationType type_; + address to; + address from; + bytes32 rights; + address contract_; + uint256 tokenId; + uint256 amount; + } + + /// @notice Emitted when an address delegates or revokes rights for their entire wallet + event DelegateAll(address indexed from, address indexed to, bytes32 rights, bool enable); + + /// @notice Emitted when an address delegates or revokes rights for a contract address + event DelegateContract( + address indexed from, + address indexed to, + address indexed contract_, + bytes32 rights, + bool enable + ); + + /// @notice Emitted when an address delegates or revokes rights for an ERC721 tokenId + event DelegateERC721( + address indexed from, + address indexed to, + address indexed contract_, + uint256 tokenId, + bytes32 rights, + bool enable + ); + + /// @notice Emitted when an address delegates or revokes rights for an amount of ERC20 tokens + event DelegateERC20( + address indexed from, + address indexed to, + address indexed contract_, + bytes32 rights, + uint256 amount + ); + + /// @notice Emitted when an address delegates or revokes rights for an amount of an ERC1155 tokenId + event DelegateERC1155( + address indexed from, + address indexed to, + address indexed contract_, + uint256 tokenId, + bytes32 rights, + uint256 amount + ); + + /// @notice Thrown if multicall calldata is malformed + error MulticallFailed(); + + /** + * ----------- WRITE ----------- + */ + + /** + * @notice Call multiple functions in the current contract and return the data from all of them if they all succeed + * @param data The encoded function data for each of the calls to make to this contract + * @return results The results from each of the calls passed in via data + */ + function multicall(bytes[] calldata data) external payable returns (bytes[] memory results); + + /** + * @notice Allow the delegate to act on behalf of `msg.sender` for all contracts + * @param to The address to act as delegate + * @param rights Specific subdelegation rights granted to the delegate, pass an empty bytestring to encompass all rights + * @param enable Whether to enable or disable this delegation, true delegates and false revokes + * @return delegationHash The unique identifier of the delegation + */ + function delegateAll(address to, bytes32 rights, bool enable) external payable returns (bytes32 delegationHash); + + /** + * @notice Allow the delegate to act on behalf of `msg.sender` for a specific contract + * @param to The address to act as delegate + * @param contract_ The contract whose rights are being delegated + * @param rights Specific subdelegation rights granted to the delegate, pass an empty bytestring to encompass all rights + * @param enable Whether to enable or disable this delegation, true delegates and false revokes + * @return delegationHash The unique identifier of the delegation + */ + function delegateContract( + address to, + address contract_, + bytes32 rights, + bool enable + ) external payable returns (bytes32 delegationHash); + + /** + * @notice Allow the delegate to act on behalf of `msg.sender` for a specific ERC721 token + * @param to The address to act as delegate + * @param contract_ The contract whose rights are being delegated + * @param tokenId The token id to delegate + * @param rights Specific subdelegation rights granted to the delegate, pass an empty bytestring to encompass all rights + * @param enable Whether to enable or disable this delegation, true delegates and false revokes + * @return delegationHash The unique identifier of the delegation + */ + function delegateERC721( + address to, + address contract_, + uint256 tokenId, + bytes32 rights, + bool enable + ) external payable returns (bytes32 delegationHash); + + /** + * @notice Allow the delegate to act on behalf of `msg.sender` for a specific amount of ERC20 tokens + * @dev The actual amount is not encoded in the hash, just the existence of a amount (since it is an upper bound) + * @param to The address to act as delegate + * @param contract_ The address for the fungible token contract + * @param rights Specific subdelegation rights granted to the delegate, pass an empty bytestring to encompass all rights + * @param amount The amount to delegate, > 0 delegates and 0 revokes + * @return delegationHash The unique identifier of the delegation + */ + function delegateERC20( + address to, + address contract_, + bytes32 rights, + uint256 amount + ) external payable returns (bytes32 delegationHash); + + /** + * @notice Allow the delegate to act on behalf of `msg.sender` for a specific amount of ERC1155 tokens + * @dev The actual amount is not encoded in the hash, just the existence of a amount (since it is an upper bound) + * @param to The address to act as delegate + * @param contract_ The address of the contract that holds the token + * @param tokenId The token id to delegate + * @param rights Specific subdelegation rights granted to the delegate, pass an empty bytestring to encompass all rights + * @param amount The amount of that token id to delegate, > 0 delegates and 0 revokes + * @return delegationHash The unique identifier of the delegation + */ + function delegateERC1155( + address to, + address contract_, + uint256 tokenId, + bytes32 rights, + uint256 amount + ) external payable returns (bytes32 delegationHash); + + /** + * ----------- CHECKS ----------- + */ + + /** + * @notice Check if `to` is a delegate of `from` for the entire wallet + * @param to The potential delegate address + * @param from The potential address who delegated rights + * @param rights Specific rights to check for, pass the zero value to ignore subdelegations and check full delegations only + * @return valid Whether delegate is granted to act on the from's behalf + */ + function checkDelegateForAll(address to, address from, bytes32 rights) external view returns (bool); + + /** + * @notice Check if `to` is a delegate of `from` for the specified `contract_` or the entire wallet + * @param to The delegated address to check + * @param contract_ The specific contract address being checked + * @param from The cold wallet who issued the delegation + * @param rights Specific rights to check for, pass the zero value to ignore subdelegations and check full delegations only + * @return valid Whether delegate is granted to act on from's behalf for entire wallet or that specific contract + */ + function checkDelegateForContract( + address to, + address from, + address contract_, + bytes32 rights + ) external view returns (bool); + + /** + * @notice Check if `to` is a delegate of `from` for the specific `contract` and `tokenId`, the entire `contract_`, or the entire wallet + * @param to The delegated address to check + * @param contract_ The specific contract address being checked + * @param tokenId The token id for the token to delegating + * @param from The wallet that issued the delegation + * @param rights Specific rights to check for, pass the zero value to ignore subdelegations and check full delegations only + * @return valid Whether delegate is granted to act on from's behalf for entire wallet, that contract, or that specific tokenId + */ + function checkDelegateForERC721( + address to, + address from, + address contract_, + uint256 tokenId, + bytes32 rights + ) external view returns (bool); + + /** + * @notice Returns the amount of ERC20 tokens the delegate is granted rights to act on the behalf of + * @param to The delegated address to check + * @param contract_ The address of the token contract + * @param from The cold wallet who issued the delegation + * @param rights Specific rights to check for, pass the zero value to ignore subdelegations and check full delegations only + * @return balance The delegated balance, which will be 0 if the delegation does not exist + */ + function checkDelegateForERC20( + address to, + address from, + address contract_, + bytes32 rights + ) external view returns (uint256); + + /** + * @notice Returns the amount of a ERC1155 tokens the delegate is granted rights to act on the behalf of + * @param to The delegated address to check + * @param contract_ The address of the token contract + * @param tokenId The token id to check the delegated amount of + * @param from The cold wallet who issued the delegation + * @param rights Specific rights to check for, pass the zero value to ignore subdelegations and check full delegations only + * @return balance The delegated balance, which will be 0 if the delegation does not exist + */ + function checkDelegateForERC1155( + address to, + address from, + address contract_, + uint256 tokenId, + bytes32 rights + ) external view returns (uint256); + + /** + * ----------- ENUMERATIONS ----------- + */ + + /** + * @notice Returns all enabled delegations a given delegate has received + * @param to The address to retrieve delegations for + * @return delegations Array of Delegation structs + */ + function getIncomingDelegations(address to) external view returns (Delegation[] memory delegations); + + /** + * @notice Returns all enabled delegations an address has given out + * @param from The address to retrieve delegations for + * @return delegations Array of Delegation structs + */ + function getOutgoingDelegations(address from) external view returns (Delegation[] memory delegations); + + /** + * @notice Returns all hashes associated with enabled delegations an address has received + * @param to The address to retrieve incoming delegation hashes for + * @return delegationHashes Array of delegation hashes + */ + function getIncomingDelegationHashes(address to) external view returns (bytes32[] memory delegationHashes); + + /** + * @notice Returns all hashes associated with enabled delegations an address has given out + * @param from The address to retrieve outgoing delegation hashes for + * @return delegationHashes Array of delegation hashes + */ + function getOutgoingDelegationHashes(address from) external view returns (bytes32[] memory delegationHashes); + + /** + * @notice Returns the delegations for a given array of delegation hashes + * @param delegationHashes is an array of hashes that correspond to delegations + * @return delegations Array of Delegation structs, return empty structs for nonexistent or revoked delegations + */ + function getDelegationsFromHashes( + bytes32[] calldata delegationHashes + ) external view returns (Delegation[] memory delegations); + + /** + * ----------- STORAGE ACCESS ----------- + */ + + /** + * @notice Allows external contracts to read arbitrary storage slots + */ + function readSlot(bytes32 location) external view returns (bytes32); + + /** + * @notice Allows external contracts to read an arbitrary array of storage slots + */ + function readSlots(bytes32[] calldata locations) external view returns (bytes32[] memory); +} diff --git a/smart-contracts/contracts/mock/delegate-registry/libraries/RegistryHashes.sol b/smart-contracts/contracts/mock/delegate-registry/libraries/RegistryHashes.sol new file mode 100644 index 00000000..c8a51006 --- /dev/null +++ b/smart-contracts/contracts/mock/delegate-registry/libraries/RegistryHashes.sol @@ -0,0 +1,347 @@ +// SPDX-License-Identifier: CC0-1.0 +pragma solidity ^0.8.21; + +import {IDelegateRegistry} from "../IDelegateRegistry.sol"; + +/** + * @title Library for calculating the hashes and storage locations used in the delegate registry + * + * The encoding for the 5 types of delegate registry hashes should be as follows: + * + * ALL: keccak256(abi.encodePacked(rights, from, to)) + * CONTRACT: keccak256(abi.encodePacked(rights, from, to, contract_)) + * ERC721: keccak256(abi.encodePacked(rights, from, to, contract_, tokenId)) + * ERC20: keccak256(abi.encodePacked(rights, from, to, contract_)) + * ERC1155: keccak256(abi.encodePacked(rights, from, to, contract_, tokenId)) + * + * To avoid collisions between the hashes with respect to type, the hash is shifted left by one byte + * and the last byte is then encoded with a unique number for the delegation type + * + */ +library RegistryHashes { + /// @dev Used to delete everything but the last byte of a 32 byte word with and(word, EXTRACT_LAST_BYTE) + uint256 internal constant EXTRACT_LAST_BYTE = 0xff; + /// @dev Constants for the delegate registry delegation type enumeration + uint256 internal constant ALL_TYPE = 1; + uint256 internal constant CONTRACT_TYPE = 2; + uint256 internal constant ERC721_TYPE = 3; + uint256 internal constant ERC20_TYPE = 4; + uint256 internal constant ERC1155_TYPE = 5; + /// @dev Constant for the location of the delegations array in the delegate registry, defined to be zero + uint256 internal constant DELEGATION_SLOT = 0; + + /** + * @notice Helper function to decode last byte of a delegation hash into its delegation type enum + * @param inputHash The bytehash to decode the type from + * @return decodedType The delegation type + */ + function decodeType(bytes32 inputHash) internal pure returns (IDelegateRegistry.DelegationType decodedType) { + assembly { + decodedType := and(inputHash, EXTRACT_LAST_BYTE) + } + } + + /** + * @notice Helper function that computes the storage location of a particular delegation array + * @dev Storage keys further down the array can be obtained by adding computedLocation with the element position + * @dev Follows the solidity storage location encoding for a mapping(bytes32 => fixedArray) at the position of the delegationSlot + * @param inputHash The bytehash to decode the type from + * @return computedLocation is the storage key of the delegation array at position 0 + */ + function location(bytes32 inputHash) internal pure returns (bytes32 computedLocation) { + assembly ("memory-safe") { + // This block only allocates memory in the scratch space + mstore(0, inputHash) + mstore(32, DELEGATION_SLOT) + computedLocation := keccak256(0, 64) // Run keccak256 over bytes in scratch space to obtain the storage key + } + } + + /** + * @notice Helper function to compute delegation hash for `DelegationType.ALL` + * @dev Equivalent to `keccak256(abi.encodePacked(rights, from, to))` then left-shift by 1 byte and write the delegation type to the cleaned last byte + * @dev Will not revert if `from` or `to` are > uint160, any input larger than uint160 for `from` and `to` will be cleaned to its lower 20 bytes + * @param from The address making the delegation + * @param rights The rights specified by the delegation + * @param to The address receiving the delegation + * @return hash The delegation parameters encoded with ALL_TYPE + */ + function allHash(address from, bytes32 rights, address to) internal pure returns (bytes32 hash) { + assembly ("memory-safe") { + // This block only allocates memory after the free memory pointer + let ptr := mload(64) // Load the free memory pointer + // Lay out the variables from last to first, agnostic to upper 96 bits of address words. + mstore(add(ptr, 40), to) + mstore(add(ptr, 20), from) + mstore(ptr, rights) + hash := or(shl(8, keccak256(ptr, 72)), ALL_TYPE) // Keccak-hashes the packed encoding, left-shifts by one byte, then writes type to the lowest-order byte + } + } + + /** + * @notice Helper function to compute delegation location for `DelegationType.ALL` + * @dev Equivalent to `location(allHash(rights, from, to))` + * @dev Will not revert if `from` or `to` are > uint160, any input larger than uint160 for `from` and `to` will be cleaned to its lower 20 bytes + * @param from The address making the delegation + * @param rights The rights specified by the delegation + * @param to The address receiving the delegation + * @return computedLocation The storage location of the all delegation with those parameters in the delegations mapping + */ + function allLocation(address from, bytes32 rights, address to) internal pure returns (bytes32 computedLocation) { + assembly ("memory-safe") { + // This block only allocates memory after the free memory pointer and in the scratch space + let ptr := mload(64) // Load the free memory pointer + // Lay out the variables from last to first, agnostic to upper 96 bits of address words. + mstore(add(ptr, 40), to) + mstore(add(ptr, 20), from) + mstore(ptr, rights) + mstore(0, or(shl(8, keccak256(ptr, 72)), ALL_TYPE)) // Computes `allHash`, then stores the result in scratch space + mstore(32, DELEGATION_SLOT) + computedLocation := keccak256(0, 64) // Runs keccak over the scratch space to obtain the storage key + } + } + + /** + * @notice Helper function to compute delegation hash for `DelegationType.CONTRACT` + * @dev Equivalent to keccak256(abi.encodePacked(rights, from, to, contract_)) left-shifted by 1 then last byte overwritten with CONTRACT_TYPE + * @dev Will not revert if `from`, `to` or `contract_` are > uint160, these inputs will be cleaned to their lower 20 bytes + * @param from The address making the delegation + * @param rights The rights specified by the delegation + * @param to The address receiving the delegation + * @param contract_ The address of the contract specified by the delegation + * @return hash The delegation parameters encoded with CONTRACT_TYPE + */ + function contractHash( + address from, + bytes32 rights, + address to, + address contract_ + ) internal pure returns (bytes32 hash) { + assembly ("memory-safe") { + // This block only allocates memory after the free memory pointer + let ptr := mload(64) // Load the free memory pointer + // Lay out the variables from last to first, agnostic to upper 96 bits of address words. + mstore(add(ptr, 60), contract_) + mstore(add(ptr, 40), to) + mstore(add(ptr, 20), from) + mstore(ptr, rights) + hash := or(shl(8, keccak256(ptr, 92)), CONTRACT_TYPE) // Keccak-hashes the packed encoding, left-shifts by one byte, then writes type to the lowest-order byte + } + } + + /** + * @notice Helper function to compute delegation location for `DelegationType.CONTRACT` + * @dev Equivalent to `location(contractHash(rights, from, to, contract_))` + * @dev Will not revert if `from`, `to` or `contract_` are > uint160, these inputs will be cleaned to their lower 20 bytes + * @param from The address making the delegation + * @param rights The rights specified by the delegation + * @param to The address receiving the delegation + * @param contract_ The address of the contract specified by the delegation + * @return computedLocation The storage location of the contract delegation with those parameters in the delegations mapping + */ + function contractLocation( + address from, + bytes32 rights, + address to, + address contract_ + ) internal pure returns (bytes32 computedLocation) { + assembly ("memory-safe") { + // This block only allocates memory after the free memory pointer and in the scratch space + let ptr := mload(64) // Load free memory pointer + // Lay out the variables from last to first, agnostic to upper 96 bits of address words. + mstore(add(ptr, 60), contract_) + mstore(add(ptr, 40), to) + mstore(add(ptr, 20), from) + mstore(ptr, rights) + mstore(0, or(shl(8, keccak256(ptr, 92)), CONTRACT_TYPE)) // Computes `contractHash`, then stores the result in scratch space + mstore(32, DELEGATION_SLOT) + computedLocation := keccak256(0, 64) // Runs keccak over the scratch space to obtain the storage key + } + } + + /** + * @notice Helper function to compute delegation hash for `DelegationType.ERC721` + * @dev Equivalent to `keccak256(abi.encodePacked(rights, from, to, contract_, tokenId)) left-shifted by 1 then last byte overwritten with ERC721_TYPE + * @dev Will not revert if `from`, `to` or `contract_` are > uint160, these inputs will be cleaned to their lower 20 bytes + * @param from The address making the delegation + * @param rights The rights specified by the delegation + * @param to The address receiving the delegation + * @param tokenId The id of the token specified by the delegation + * @param contract_ The address of the contract specified by the delegation + * @return hash The delegation parameters encoded with ERC721_TYPE + */ + function erc721Hash( + address from, + bytes32 rights, + address to, + uint256 tokenId, + address contract_ + ) internal pure returns (bytes32 hash) { + assembly ("memory-safe") { + // This block only allocates memory after the free memory pointer + let ptr := mload(64) // Cache the free memory pointer. + // Lay out the variables from last to first, agnostic to upper 96 bits of address words. + mstore(add(ptr, 92), tokenId) + mstore(add(ptr, 60), contract_) + mstore(add(ptr, 40), to) + mstore(add(ptr, 20), from) + mstore(ptr, rights) + hash := or(shl(8, keccak256(ptr, 124)), ERC721_TYPE) // Keccak-hashes the packed encoding, left-shifts by one byte, then writes type to the lowest-order byte + } + } + + /** + * @notice Helper function to compute delegation location for `DelegationType.ERC721` + * @dev Equivalent to `location(ERC721Hash(rights, from, to, contract_, tokenId))` + * @dev Will not revert if `from`, `to` or `contract_` are > uint160, these inputs will be cleaned to their lower 20 bytes + * @param from The address making the delegation + * @param rights The rights specified by the delegation + * @param to The address receiving the delegation + * @param tokenId The id of the ERC721 token + * @param contract_ The address of the ERC721 token contract + * @return computedLocation The storage location of the ERC721 delegation with those parameters in the delegations mapping + */ + function erc721Location( + address from, + bytes32 rights, + address to, + uint256 tokenId, + address contract_ + ) internal pure returns (bytes32 computedLocation) { + assembly ("memory-safe") { + // This block only allocates memory after the free memory pointer and in the scratch space + let ptr := mload(64) // Cache the free memory pointer. + // Lay out the variables from last to first, agnostic to upper 96 bits of address words. + mstore(add(ptr, 92), tokenId) + mstore(add(ptr, 60), contract_) + mstore(add(ptr, 40), to) + mstore(add(ptr, 20), from) + mstore(ptr, rights) + mstore(0, or(shl(8, keccak256(ptr, 124)), ERC721_TYPE)) // Computes erc721Hash, then stores the result in scratch space + mstore(32, DELEGATION_SLOT) + computedLocation := keccak256(0, 64) // Runs keccak256 over the scratch space to obtain the storage key + } + } + + /** + * @notice Helper function to compute delegation hash for `DelegationType.ERC20` + * @dev Equivalent to `keccak256(abi.encodePacked(rights, from, to, contract_))` with the last byte overwritten with ERC20_TYPE + * @dev Will not revert if `from`, `to` or `contract_` are > uint160, these inputs will be cleaned to their lower 20 bytes + * @param from The address making the delegation + * @param rights The rights specified by the delegation + * @param to The address receiving the delegation + * @param contract_ The address of the ERC20 token contract + * @return hash The parameters encoded with ERC20_TYPE + */ + function erc20Hash( + address from, + bytes32 rights, + address to, + address contract_ + ) internal pure returns (bytes32 hash) { + assembly ("memory-safe") { + // This block only allocates memory after the free memory pointer + let ptr := mload(64) // Load free memory pointer + // Lay out the variables from last to first, agnostic to upper 96 bits of address words. + mstore(add(ptr, 60), contract_) + mstore(add(ptr, 40), to) + mstore(add(ptr, 20), from) + mstore(ptr, rights) + hash := or(shl(8, keccak256(ptr, 92)), ERC20_TYPE) // Keccak-hashes the packed encoding, left-shifts by one byte, then writes type to the lowest-order byte + } + } + + /** + * @notice Helper function to compute delegation location for `DelegationType.ERC20` + * @dev Equivalent to `location(ERC20Hash(rights, from, to, contract_))` + * @dev Will not revert if `from`, `to` or `contract_` are > uint160, these inputs will be cleaned to their lower 20 bytes + * @param from The address making the delegation + * @param rights The rights specified by the delegation + * @param to The address receiving the delegation + * @param contract_ The address of the ERC20 token contract + * @return computedLocation The storage location of the ERC20 delegation with those parameters in the delegations mapping + */ + function erc20Location( + address from, + bytes32 rights, + address to, + address contract_ + ) internal pure returns (bytes32 computedLocation) { + assembly ("memory-safe") { + // This block only allocates memory after the free memory pointer and in the scratch space + let ptr := mload(64) // Loads the free memory pointer + // Lay out the variables from last to first, agnostic to upper 96 bits of address words. + mstore(add(ptr, 60), contract_) + mstore(add(ptr, 40), to) + mstore(add(ptr, 20), from) + mstore(ptr, rights) + mstore(0, or(shl(8, keccak256(ptr, 92)), ERC20_TYPE)) // Computes erc20Hash, then stores the result in scratch space + mstore(32, DELEGATION_SLOT) + computedLocation := keccak256(0, 64) // Runs keccak over the scratch space to obtain the storage key + } + } + + /** + * @notice Helper function to compute delegation hash for `DelegationType.ERC1155` + * @dev Equivalent to keccak256(abi.encodePacked(rights, from, to, contract_, tokenId)) left-shifted with the last byte overwritten with ERC1155_TYPE + * @dev Will not revert if `from`, `to` or `contract_` are > uint160, these inputs will be cleaned to their lower 20 bytes + * @param from The address making the delegation + * @param rights The rights specified by the delegation + * @param to The address receiving the delegation + * @param tokenId The id of the ERC1155 token + * @param contract_ The address of the ERC1155 token contract + * @return hash The parameters encoded with ERC1155_TYPE + */ + function erc1155Hash( + address from, + bytes32 rights, + address to, + uint256 tokenId, + address contract_ + ) internal pure returns (bytes32 hash) { + assembly ("memory-safe") { + // This block only allocates memory after the free memory pointer + let ptr := mload(64) // Load the free memory pointer. + // Lay out the variables from last to first, agnostic to upper 96 bits of address words. + mstore(add(ptr, 92), tokenId) + mstore(add(ptr, 60), contract_) + mstore(add(ptr, 40), to) + mstore(add(ptr, 20), from) + mstore(ptr, rights) + hash := or(shl(8, keccak256(ptr, 124)), ERC1155_TYPE) // Keccak-hashes the packed encoding, left-shifts by one byte, then writes type to the lowest-order byte + } + } + + /** + * @notice Helper function to compute delegation location for `DelegationType.ERC1155` + * @dev Equivalent to `location(ERC1155Hash(rights, from, to, contract_, tokenId))` + * @dev Will not revert if `from`, `to` or `contract_` are > uint160, these inputs will be cleaned to their lower 20 bytes + * @param from The address making the delegation + * @param rights The rights specified by the delegation + * @param to The address receiving the delegation + * @param tokenId The id of the ERC1155 token + * @param contract_ The address of the ERC1155 token contract + * @return computedLocation The storage location of the ERC1155 delegation with those parameters in the delegations mapping + */ + function erc1155Location( + address from, + bytes32 rights, + address to, + uint256 tokenId, + address contract_ + ) internal pure returns (bytes32 computedLocation) { + assembly ("memory-safe") { + // This block only allocates memory after the free memory pointer and in the scratch space + let ptr := mload(64) // Cache the free memory pointer. + // Lay out the variables from last to first, agnostic to upper 96 bits of address words. + mstore(add(ptr, 92), tokenId) + mstore(add(ptr, 60), contract_) + mstore(add(ptr, 40), to) + mstore(add(ptr, 20), from) + mstore(ptr, rights) + mstore(0, or(shl(8, keccak256(ptr, 124)), ERC1155_TYPE)) // Computes erc1155Hash, then stores the result in scratch space + mstore(32, DELEGATION_SLOT) + computedLocation := keccak256(0, 64) // Runs keccak over the scratch space to obtain the storage key + } + } +} diff --git a/smart-contracts/contracts/mock/delegate-registry/libraries/RegistryOps.sol b/smart-contracts/contracts/mock/delegate-registry/libraries/RegistryOps.sol new file mode 100644 index 00000000..b59ade16 --- /dev/null +++ b/smart-contracts/contracts/mock/delegate-registry/libraries/RegistryOps.sol @@ -0,0 +1,31 @@ +// SPDX-License-Identifier: CC0-1.0 +pragma solidity ^0.8.21; + +library RegistryOps { + /// @dev `x > y ? x : y`. + function max(uint256 x, uint256 y) internal pure returns (uint256 z) { + assembly { + // `gt(y, x)` will evaluate to 1 if `y > x`, else 0. + // + // If `y > x`: + // `x ^ ((x ^ y) * 1) = x ^ (x ^ y) = (x ^ x) ^ y = 0 ^ y = y`. + // otherwise: + // `x ^ ((x ^ y) * 0) = x ^ 0 = x`. + z := xor(x, mul(xor(x, y), gt(y, x))) + } + } + + /// @dev `x & y`. + function and(bool x, bool y) internal pure returns (bool z) { + assembly { + z := and(iszero(iszero(x)), iszero(iszero(y))) // Compiler cleans dirty booleans on the stack to 1, so do the same here + } + } + + /// @dev `x | y`. + function or(bool x, bool y) internal pure returns (bool z) { + assembly { + z := or(iszero(iszero(x)), iszero(iszero(y))) // Compiler cleans dirty booleans on the stack to 1, so do the same here + } + } +} diff --git a/smart-contracts/contracts/mock/delegate-registry/libraries/RegistryStorage.sol b/smart-contracts/contracts/mock/delegate-registry/libraries/RegistryStorage.sol new file mode 100644 index 00000000..92c4fcb0 --- /dev/null +++ b/smart-contracts/contracts/mock/delegate-registry/libraries/RegistryStorage.sol @@ -0,0 +1,76 @@ +// SPDX-License-Identifier: CC0-1.0 +pragma solidity ^0.8.21; + +library RegistryStorage { + /// @dev Standardizes `from` storage flags to prevent double-writes in the delegation in/outbox if the same delegation is revoked and rewritten + address internal constant DELEGATION_EMPTY = address(0); + address internal constant DELEGATION_REVOKED = address(1); + + /// @dev Standardizes storage positions of delegation data + uint256 internal constant POSITIONS_FIRST_PACKED = 0; // | 4 bytes empty | first 8 bytes of contract address | 20 bytes of from address | + uint256 internal constant POSITIONS_SECOND_PACKED = 1; // | last 12 bytes of contract address | 20 bytes of to address | + uint256 internal constant POSITIONS_RIGHTS = 2; + uint256 internal constant POSITIONS_TOKEN_ID = 3; + uint256 internal constant POSITIONS_AMOUNT = 4; + + /// @dev Used to clean address types of dirty bits with `and(address, CLEAN_ADDRESS)` + uint256 internal constant CLEAN_ADDRESS = 0x00ffffffffffffffffffffffffffffffffffffffff; + + /// @dev Used to clean everything but the first 8 bytes of an address + uint256 internal constant CLEAN_FIRST8_BYTES_ADDRESS = 0xffffffffffffffff << 96; + + /// @dev Used to clean everything but the first 8 bytes of an address in the packed position + uint256 internal constant CLEAN_PACKED8_BYTES_ADDRESS = 0xffffffffffffffff << 160; + + /** + * @notice Helper function that packs from, to, and contract_ address to into the two slot configuration + * @param from The address making the delegation + * @param to The address receiving the delegation + * @param contract_ The contract address associated with the delegation (optional) + * @return firstPacked The firstPacked storage configured with the parameters + * @return secondPacked The secondPacked storage configured with the parameters + * @dev Will not revert if `from`, `to`, and `contract_` are > uint160, any inputs with dirty bits outside the last 20 bytes will be cleaned + */ + function packAddresses( + address from, + address to, + address contract_ + ) internal pure returns (bytes32 firstPacked, bytes32 secondPacked) { + assembly { + firstPacked := or(shl(64, and(contract_, CLEAN_FIRST8_BYTES_ADDRESS)), and(from, CLEAN_ADDRESS)) + secondPacked := or(shl(160, contract_), and(to, CLEAN_ADDRESS)) + } + } + + /** + * @notice Helper function that unpacks from, to, and contract_ address inside the firstPacked secondPacked storage configuration + * @param firstPacked The firstPacked storage to be decoded + * @param secondPacked The secondPacked storage to be decoded + * @return from The address making the delegation + * @return to The address receiving the delegation + * @return contract_ The contract address associated with the delegation + * @dev Will not revert if `from`, `to`, and `contract_` are > uint160, any inputs with dirty bits outside the last 20 bytes will be cleaned + */ + function unpackAddresses( + bytes32 firstPacked, + bytes32 secondPacked + ) internal pure returns (address from, address to, address contract_) { + assembly { + from := and(firstPacked, CLEAN_ADDRESS) + to := and(secondPacked, CLEAN_ADDRESS) + contract_ := or(shr(64, and(firstPacked, CLEAN_PACKED8_BYTES_ADDRESS)), shr(160, secondPacked)) + } + } + + /** + * @notice Helper function that can unpack the from or to address from their respective packed slots in the registry + * @param packedSlot The slot containing the from or to address + * @return unpacked The `from` or `to` address + * @dev Will not work if you want to obtain the contract address, use unpackAddresses + */ + function unpackAddress(bytes32 packedSlot) internal pure returns (address unpacked) { + assembly { + unpacked := and(packedSlot, CLEAN_ADDRESS) + } + } +} diff --git a/smart-contracts/deploy/1_full_protocol.migration.ts b/smart-contracts/deploy/1_full_protocol.migration.ts index ac3b6c87..f7abe4ad 100644 --- a/smart-contracts/deploy/1_full_protocol.migration.ts +++ b/smart-contracts/deploy/1_full_protocol.migration.ts @@ -4,7 +4,10 @@ import { Fragment } from 'ethers'; import { parseConfig } from './helpers/config-parser'; import { + Delegation, + Delegation__factory, IBidStorage__factory, + IDelegation__factory, IMarketplace__factory, IModelRegistry__factory, IProviderRegistry__factory, @@ -40,6 +43,7 @@ module.exports = async function (deployer: Deployer) { LinearDistributionIntervalDecrease: ldid, }, }); + let delegationFacet = await deployer.deploy(Delegation__factory); await lumerinDiamond['diamondCut((address,uint8,bytes4[])[])']([ { @@ -84,6 +88,13 @@ module.exports = async function (deployer: Deployer) { .fragments.filter(Fragment.isFunction) .map((f) => f.selector), }, + { + facetAddress: delegationFacet, + action: FacetAction.Add, + functionSelectors: IDelegation__factory.createInterface() + .fragments.filter(Fragment.isFunction) + .map((f) => f.selector), + }, ]); providerRegistryFacet = providerRegistryFacet.attach(lumerinDiamond.target) as ProviderRegistry; @@ -98,6 +109,8 @@ module.exports = async function (deployer: Deployer) { ); sessionRouterFacet = sessionRouterFacet.attach(lumerinDiamond.target) as SessionRouter; await sessionRouterFacet.__SessionRouter_init(config.fundingAccount, 7 * DAY, config.pools); + delegationFacet = delegationFacet.attach(lumerinDiamond.target) as Delegation; + await delegationFacet.__Delegation_init(config.delegateRegistry); await providerRegistryFacet.providerSetMinStake(config.providerMinStake); await modelRegistryFacet.modelSetMinStake(config.modelMinStake); diff --git a/smart-contracts/deploy/data/config_arbitrum_sepolia.json b/smart-contracts/deploy/data/config_arbitrum_sepolia.json index 2436772e..42edaa04 100644 --- a/smart-contracts/deploy/data/config_arbitrum_sepolia.json +++ b/smart-contracts/deploy/data/config_arbitrum_sepolia.json @@ -6,6 +6,7 @@ "marketplaceBidFee": "300000000000000000", "marketplaceMinBidPricePerSecond": "5000000000000000", "marketplaceMaxBidPricePerSecond": "20000000000000000000", + "delegateRegistry": "0x00000000000000447e69651d841bD8D104Bed493", "pools": [ { diff --git a/smart-contracts/deploy/helpers/config-parser.ts b/smart-contracts/deploy/helpers/config-parser.ts index a17a6f71..10a3773f 100644 --- a/smart-contracts/deploy/helpers/config-parser.ts +++ b/smart-contracts/deploy/helpers/config-parser.ts @@ -11,6 +11,7 @@ export type Config = { marketplaceBidFee: string; marketplaceMinBidPricePerSecond: string; marketplaceMaxBidPricePerSecond: string; + delegateRegistry: string; }; export function parseConfig(): Config { diff --git a/smart-contracts/test/diamond/facets/Delegation.test.ts b/smart-contracts/test/diamond/facets/Delegation.test.ts new file mode 100644 index 00000000..1cb56151 --- /dev/null +++ b/smart-contracts/test/diamond/facets/Delegation.test.ts @@ -0,0 +1,109 @@ +import { Delegation, LumerinDiamond, MorpheusToken } from '@ethers-v6'; +import { SignerWithAddress } from '@nomicfoundation/hardhat-ethers/signers'; +import { expect } from 'chai'; +import { ethers } from 'hardhat'; + +import { DelegateRegistry } from '@/generated-types/ethers/contracts/mock/delegate-registry/src'; +import { getHex, wei } from '@/scripts/utils/utils'; +import { + deployDelegateRegistry, + deployFacetDelegation, + deployFacetMarketplace, + deployFacetModelRegistry, + deployFacetProviderRegistry, + deployFacetSessionRouter, + deployLumerinDiamond, + deployMORToken, +} from '@/test/helpers/deployers'; +import { Reverter } from '@/test/helpers/reverter'; + +describe('Delegation', () => { + const reverter = new Reverter(); + + let OWNER: SignerWithAddress; + let PROVIDER: SignerWithAddress; + + let diamond: LumerinDiamond; + let delegation: Delegation; + + let token: MorpheusToken; + let delegateRegistry: DelegateRegistry; + + before(async () => { + [OWNER, PROVIDER] = await ethers.getSigners(); + + [diamond, token, delegateRegistry] = await Promise.all([ + deployLumerinDiamond(), + deployMORToken(), + deployDelegateRegistry(), + ]); + + [, , , , delegation] = await Promise.all([ + deployFacetProviderRegistry(diamond), + deployFacetModelRegistry(diamond), + deployFacetSessionRouter(diamond, OWNER), + deployFacetMarketplace(diamond, token, wei(0.0001), wei(900)), + deployFacetDelegation(diamond, delegateRegistry), + ]); + + await reverter.snapshot(); + }); + + afterEach(reverter.revert); + + describe('#__Delegation_init', () => { + it('should revert if try to call init function twice', async () => { + await expect(delegation.__Delegation_init(OWNER)).to.be.rejectedWith( + 'Initializable: contract is already initialized', + ); + }); + }); + + describe('#setRegistry', async () => { + it('should set new registry', async () => { + await expect(delegation.setRegistry(PROVIDER)) + .to.emit(delegation, 'DelegationRegistryUpdated') + .withArgs(PROVIDER); + + expect(await delegation.getRegistry()).eq(PROVIDER); + }); + + it('should throw error when caller is not an owner', async () => { + await expect(delegation.connect(PROVIDER).setRegistry(PROVIDER)).to.be.revertedWithCustomError( + diamond, + 'OwnableUnauthorizedAccount', + ); + }); + }); + + describe('#isRightsDelegated', async () => { + it('should return `false` when rights not delegated', async () => { + const rights = await delegation.DELEGATION_RULES_PROVIDER(); + + expect(await delegation.isRightsDelegated(OWNER, PROVIDER, rights)).eq(false); + }); + it('should return `false` when correct rights not delegated', async () => { + const rights = await delegation.DELEGATION_RULES_PROVIDER(); + await delegateRegistry.connect(PROVIDER).delegateContract(OWNER, delegation, rights, true); + + expect(await delegation.isRightsDelegated(OWNER, PROVIDER, await delegation.DELEGATION_RULES_SESSION())).eq( + false, + ); + }); + it('should return `true` when rights delegated for the specific rule', async () => { + const rights = await delegation.DELEGATION_RULES_PROVIDER(); + await delegateRegistry.connect(PROVIDER).delegateContract(OWNER, delegation, rights, true); + + expect(await delegation.isRightsDelegated(OWNER, PROVIDER, rights)).eq(true); + }); + it('should return `true` when rights delegated for the all rules', async () => { + const rights = await delegation.DELEGATION_RULES_PROVIDER(); + await delegateRegistry.connect(PROVIDER).delegateContract(OWNER, delegation, getHex(Buffer.from('')), true); + + expect(await delegation.isRightsDelegated(OWNER, PROVIDER, rights)).eq(true); + }); + }); +}); + +// npm run generate-types && npx hardhat test "test/diamond/facets/Delegation.test.ts" +// npx hardhat coverage --solcoverjs ./.solcover.ts --testfiles "test/diamond/facets/Delegation.test.ts" diff --git a/smart-contracts/test/diamond/facets/Marketplace.test.ts b/smart-contracts/test/diamond/facets/Marketplace.test.ts index aa28ee6e..50837814 100644 --- a/smart-contracts/test/diamond/facets/Marketplace.test.ts +++ b/smart-contracts/test/diamond/facets/Marketplace.test.ts @@ -1,10 +1,19 @@ -import { LumerinDiamond, Marketplace, ModelRegistry, MorpheusToken, ProviderRegistry } from '@ethers-v6'; +import { + DelegateRegistry, + LumerinDiamond, + Marketplace, + ModelRegistry, + MorpheusToken, + ProviderRegistry, +} from '@ethers-v6'; import { SignerWithAddress } from '@nomicfoundation/hardhat-ethers/signers'; import { expect } from 'chai'; import { ethers } from 'hardhat'; import { getHex, wei } from '@/scripts/utils/utils'; import { + deployDelegateRegistry, + deployFacetDelegation, deployFacetMarketplace, deployFacetModelRegistry, deployFacetProviderRegistry, @@ -28,20 +37,27 @@ describe('Marketplace', () => { let providerRegistry: ProviderRegistry; let token: MorpheusToken; + let delegateRegistry: DelegateRegistry; - const modelId1 = getHex(Buffer.from('1')); - const modelId2 = getHex(Buffer.from('2')); + const baseModelId1 = getHex(Buffer.from('1')); + const baseModelId2 = getHex(Buffer.from('2')); + let modelId1 = getHex(Buffer.from('')); + let modelId2 = getHex(Buffer.from('')); before(async () => { [OWNER, SECOND, PROVIDER] = await ethers.getSigners(); - [diamond, token] = await Promise.all([deployLumerinDiamond(), deployMORToken()]); - + [diamond, token, delegateRegistry] = await Promise.all([ + deployLumerinDiamond(), + deployMORToken(), + deployDelegateRegistry(), + ]); [providerRegistry, modelRegistry, , marketplace] = await Promise.all([ deployFacetProviderRegistry(diamond), deployFacetModelRegistry(diamond), deployFacetSessionRouter(diamond, OWNER), deployFacetMarketplace(diamond, token, wei(0.0001), wei(900)), + deployFacetDelegation(diamond, delegateRegistry), ]); await token.transfer(SECOND, wei(1000)); @@ -53,9 +69,12 @@ describe('Marketplace', () => { await token.approve(marketplace, wei(1000)); const ipfsCID = getHex(Buffer.from('ipfs://ipfsaddress')); - await providerRegistry.connect(SECOND).providerRegister(wei(100), 'test'); - await modelRegistry.connect(SECOND).modelRegister(modelId1, ipfsCID, 0, wei(100), 'name', ['tag_1']); - await modelRegistry.connect(SECOND).modelRegister(modelId2, ipfsCID, 0, wei(100), 'name', ['tag_1']); + await providerRegistry.connect(SECOND).providerRegister(SECOND, wei(100), 'test'); + await modelRegistry.connect(SECOND).modelRegister(SECOND, baseModelId1, ipfsCID, 0, wei(100), 'name', ['tag_1']); + await modelRegistry.connect(SECOND).modelRegister(SECOND, baseModelId2, ipfsCID, 0, wei(100), 'name', ['tag_1']); + + modelId1 = await modelRegistry.getModelId(SECOND, baseModelId1); + modelId2 = await modelRegistry.getModelId(SECOND, baseModelId2); await reverter.snapshot(); }); @@ -123,7 +142,7 @@ describe('Marketplace', () => { it('should post a model bid', async () => { await setNextTime(300); - await marketplace.connect(SECOND).postModelBid(modelId1, wei(10)); + await marketplace.connect(SECOND).postModelBid(SECOND, modelId1, wei(10)); const bidId = await marketplace.getBidId(SECOND, modelId1, 0); const data = await marketplace.getBid(bidId); @@ -137,15 +156,40 @@ describe('Marketplace', () => { expect(await token.balanceOf(marketplace)).to.eq(wei(301)); expect(await token.balanceOf(SECOND)).to.eq(wei(699)); - expect(await marketplace.getProviderBids(SECOND, 0, 10)).deep.eq([bidId]); - expect(await marketplace.getModelBids(modelId1, 0, 10)).deep.eq([bidId]); - expect(await marketplace.getProviderActiveBids(SECOND, 0, 10)).deep.eq([bidId]); - expect(await marketplace.getModelActiveBids(modelId1, 0, 10)).deep.eq([bidId]); + expect(await marketplace.getProviderBids(SECOND, 0, 10)).deep.eq([[bidId], 1n]); + expect(await marketplace.getModelBids(modelId1, 0, 10)).deep.eq([[bidId], 1n]); + expect(await marketplace.getProviderActiveBids(SECOND, 0, 10)).deep.eq([[bidId], 1n]); + expect(await marketplace.getModelActiveBids(modelId1, 0, 10)).deep.eq([[bidId], 1n]); + }); + it('should post a model bid from the delegatee address', async () => { + await delegateRegistry + .connect(SECOND) + .delegateContract(OWNER, providerRegistry, await providerRegistry.DELEGATION_RULES_MARKETPLACE(), true); + + await setNextTime(300); + await marketplace.connect(OWNER).postModelBid(SECOND, modelId1, wei(10)); + + const bidId = await marketplace.getBidId(SECOND, modelId1, 0); + const data = await marketplace.getBid(bidId); + expect(data.provider).to.eq(SECOND); + expect(data.modelId).to.eq(modelId1); + expect(data.pricePerSecond).to.eq(wei(10)); + expect(data.nonce).to.eq(0); + expect(data.createdAt).to.eq(300); + expect(data.deletedAt).to.eq(0); + + expect(await token.balanceOf(marketplace)).to.eq(wei(301)); + expect(await token.balanceOf(SECOND)).to.eq(wei(699)); + + expect(await marketplace.getProviderBids(SECOND, 0, 10)).deep.eq([[bidId], 1n]); + expect(await marketplace.getModelBids(modelId1, 0, 10)).deep.eq([[bidId], 1n]); + expect(await marketplace.getProviderActiveBids(SECOND, 0, 10)).deep.eq([[bidId], 1n]); + expect(await marketplace.getModelActiveBids(modelId1, 0, 10)).deep.eq([[bidId], 1n]); }); it('should post few model bids', async () => { await setNextTime(300); - await marketplace.connect(SECOND).postModelBid(modelId1, wei(10)); - await marketplace.connect(SECOND).postModelBid(modelId2, wei(20)); + await marketplace.connect(SECOND).postModelBid(SECOND, modelId1, wei(10)); + await marketplace.connect(SECOND).postModelBid(SECOND, modelId2, wei(20)); const bidId1 = await marketplace.getBidId(SECOND, modelId1, 0); let data = await marketplace.getBid(bidId1); @@ -168,17 +212,17 @@ describe('Marketplace', () => { expect(await token.balanceOf(marketplace)).to.eq(wei(302)); expect(await token.balanceOf(SECOND)).to.eq(wei(698)); - expect(await marketplace.getProviderBids(SECOND, 0, 10)).deep.eq([bidId1, bidId2]); - expect(await marketplace.getModelBids(modelId1, 0, 10)).deep.eq([bidId1]); - expect(await marketplace.getModelBids(modelId2, 0, 10)).deep.eq([bidId2]); - expect(await marketplace.getProviderActiveBids(SECOND, 0, 10)).deep.eq([bidId1, bidId2]); - expect(await marketplace.getModelActiveBids(modelId1, 0, 10)).deep.eq([bidId1]); - expect(await marketplace.getModelActiveBids(modelId2, 0, 10)).deep.eq([bidId2]); + expect(await marketplace.getProviderBids(SECOND, 0, 10)).deep.eq([[bidId1, bidId2], 2n]); + expect(await marketplace.getModelBids(modelId1, 0, 10)).deep.eq([[bidId1], 1n]); + expect(await marketplace.getModelBids(modelId2, 0, 10)).deep.eq([[bidId2], 1n]); + expect(await marketplace.getProviderActiveBids(SECOND, 0, 10)).deep.eq([[bidId1, bidId2], 2n]); + expect(await marketplace.getModelActiveBids(modelId1, 0, 10)).deep.eq([[bidId1], 1n]); + expect(await marketplace.getModelActiveBids(modelId2, 0, 10)).deep.eq([[bidId2], 1n]); }); it('should post a new model bid and delete an old bid when an old bid is active', async () => { await setNextTime(300); - await marketplace.connect(SECOND).postModelBid(modelId1, wei(10)); - await marketplace.connect(SECOND).postModelBid(modelId1, wei(20)); + await marketplace.connect(SECOND).postModelBid(SECOND, modelId1, wei(10)); + await marketplace.connect(SECOND).postModelBid(SECOND, modelId1, wei(20)); const bidId1 = await marketplace.getBidId(SECOND, modelId1, 0); let data = await marketplace.getBid(bidId1); @@ -196,45 +240,74 @@ describe('Marketplace', () => { expect(await token.balanceOf(marketplace)).to.eq(wei(302)); expect(await token.balanceOf(SECOND)).to.eq(wei(698)); - expect(await marketplace.getProviderBids(SECOND, 0, 10)).deep.eq([bidId1, bidId2]); - expect(await marketplace.getModelBids(modelId1, 0, 10)).deep.eq([bidId1, bidId2]); - expect(await marketplace.getProviderActiveBids(SECOND, 0, 10)).deep.eq([bidId2]); - expect(await marketplace.getModelActiveBids(modelId1, 0, 10)).deep.eq([bidId2]); + expect(await marketplace.getProviderBids(SECOND, 0, 10)).deep.eq([[bidId1, bidId2], 2]); + expect(await marketplace.getModelBids(modelId1, 0, 10)).deep.eq([[bidId1, bidId2], 2]); + expect(await marketplace.getProviderActiveBids(SECOND, 0, 10)).deep.eq([[bidId2], 1]); + expect(await marketplace.getModelActiveBids(modelId1, 0, 10)).deep.eq([[bidId2], 1]); }); it('should post a new model bid and skip the old bid delete', async () => { await setNextTime(300); - await marketplace.connect(SECOND).postModelBid(modelId1, wei(10)); + await marketplace.connect(SECOND).postModelBid(SECOND, modelId1, wei(10)); const bidId1 = await marketplace.getBidId(SECOND, modelId1, 0); await marketplace.connect(SECOND).deleteModelBid(bidId1); - await marketplace.connect(SECOND).postModelBid(modelId1, wei(20)); + await marketplace.connect(SECOND).postModelBid(SECOND, modelId1, wei(20)); }); it('should throw error when the provider is deregistered', async () => { - await providerRegistry.connect(SECOND).providerDeregister(); - await expect(marketplace.connect(SECOND).postModelBid(modelId1, wei(10))).to.be.revertedWithCustomError( + await providerRegistry.connect(SECOND).providerDeregister(SECOND); + await expect(marketplace.connect(SECOND).postModelBid(SECOND, modelId1, wei(10))).to.be.revertedWithCustomError( marketplace, 'MarketplaceProviderNotFound', ); }); it('should throw error when the model is deregistered', async () => { await modelRegistry.connect(SECOND).modelDeregister(modelId1); - await expect(marketplace.connect(SECOND).postModelBid(modelId1, wei(10))).to.be.revertedWithCustomError( + await expect(marketplace.connect(SECOND).postModelBid(SECOND, modelId1, wei(10))).to.be.revertedWithCustomError( marketplace, 'MarketplaceModelNotFound', ); }); - it('should throw error when the bid price is invalid', async () => { - await expect(marketplace.connect(SECOND).postModelBid(modelId1, wei(99999))).to.be.revertedWithCustomError( + it('should throw error when the bid price is invalid #1', async () => { + await expect( + marketplace.connect(SECOND).postModelBid(SECOND, modelId1, wei(99999)), + ).to.be.revertedWithCustomError(marketplace, 'MarketplaceBidPricePerSecondInvalid'); + }); + it('should throw error when the bid price is invalid #2', async () => { + await expect(marketplace.connect(SECOND).postModelBid(SECOND, modelId1, wei(0))).to.be.revertedWithCustomError( marketplace, 'MarketplaceBidPricePerSecondInvalid', ); }); + it('should throw error when model not found', async () => { + await expect( + marketplace.connect(SECOND).postModelBid(SECOND, getHex(Buffer.from('123')), wei(1)), + ).to.be.revertedWithCustomError(marketplace, 'MarketplaceModelNotFound'); + }); + it('should throw error when provider not found', async () => { + await expect( + marketplace.connect(OWNER).postModelBid(OWNER, getHex(Buffer.from('123')), wei(1)), + ).to.be.revertedWithCustomError(marketplace, 'MarketplaceProviderNotFound'); + }); + it('should throw error when post a bid without delegation or with incorrect rules', async () => { + await expect(marketplace.connect(OWNER).postModelBid(SECOND, modelId1, wei(10))).to.be.revertedWithCustomError( + providerRegistry, + 'InsufficientRightsForOperation', + ); + + await delegateRegistry + .connect(SECOND) + .delegateContract(OWNER, providerRegistry, getHex(Buffer.from('123')), true); + await expect(marketplace.connect(OWNER).postModelBid(SECOND, modelId1, wei(10))).to.be.revertedWithCustomError( + providerRegistry, + 'InsufficientRightsForOperation', + ); + }); }); describe('#deleteModelBid', async () => { it('should delete a bid', async () => { await setNextTime(300); - await marketplace.connect(SECOND).postModelBid(modelId1, wei(10)); + await marketplace.connect(SECOND).postModelBid(SECOND, modelId1, wei(10)); const bidId1 = await marketplace.getBidId(SECOND, modelId1, 0); await marketplace.connect(SECOND).deleteModelBid(bidId1); @@ -243,17 +316,32 @@ describe('Marketplace', () => { expect(data.deletedAt).to.eq(301); expect(await marketplace.isBidActive(bidId1)).to.eq(false); }); + it('should delete a bid from the delegatee address', async () => { + await setNextTime(300); + await marketplace.connect(SECOND).postModelBid(SECOND, modelId1, wei(10)); + + await delegateRegistry + .connect(SECOND) + .delegateContract(OWNER, providerRegistry, await providerRegistry.DELEGATION_RULES_MARKETPLACE(), true); + + const bidId1 = await marketplace.getBidId(SECOND, modelId1, 0); + await marketplace.connect(OWNER).deleteModelBid(bidId1); + + const data = await marketplace.getBid(bidId1); + expect(data.deletedAt).to.eq(302); + expect(await marketplace.isBidActive(bidId1)).to.eq(false); + }); it('should throw error when caller is not an owner', async () => { - await marketplace.connect(SECOND).postModelBid(modelId1, wei(10)); + await marketplace.connect(SECOND).postModelBid(SECOND, modelId1, wei(10)); const bidId1 = await marketplace.getBidId(SECOND, modelId1, 0); await expect(marketplace.connect(PROVIDER).deleteModelBid(bidId1)).to.be.revertedWithCustomError( - diamond, - 'OwnableUnauthorizedAccount', + marketplace, + 'InsufficientRightsForOperation', ); }); it('should throw error when bid already deleted', async () => { - await marketplace.connect(SECOND).postModelBid(modelId1, wei(10)); + await marketplace.connect(SECOND).postModelBid(SECOND, modelId1, wei(10)); const bidId1 = await marketplace.getBidId(SECOND, modelId1, 0); await marketplace.connect(SECOND).deleteModelBid(bidId1); @@ -270,7 +358,7 @@ describe('Marketplace', () => { }); it('should withdraw fee, all fee balance', async () => { - await marketplace.connect(SECOND).postModelBid(modelId1, wei(10)); + await marketplace.connect(SECOND).postModelBid(SECOND, modelId1, wei(10)); expect(await marketplace.getFeeBalance()).to.eq(wei(1)); await marketplace.withdrawFee(PROVIDER, wei(999)); @@ -280,7 +368,7 @@ describe('Marketplace', () => { expect(await token.balanceOf(PROVIDER)).to.eq(wei(1)); }); it('should withdraw fee, part of fee balance', async () => { - await marketplace.connect(SECOND).postModelBid(modelId1, wei(10)); + await marketplace.connect(SECOND).postModelBid(SECOND, modelId1, wei(10)); expect(await marketplace.getFeeBalance()).to.eq(wei(1)); await marketplace.withdrawFee(PROVIDER, wei(0.1)); diff --git a/smart-contracts/test/diamond/facets/ModelRegistry.test.ts b/smart-contracts/test/diamond/facets/ModelRegistry.test.ts index 04bddbc0..9d2005c6 100644 --- a/smart-contracts/test/diamond/facets/ModelRegistry.test.ts +++ b/smart-contracts/test/diamond/facets/ModelRegistry.test.ts @@ -1,10 +1,19 @@ -import { LumerinDiamond, Marketplace, ModelRegistry, MorpheusToken, ProviderRegistry } from '@ethers-v6'; +import { + DelegateRegistry, + LumerinDiamond, + Marketplace, + ModelRegistry, + MorpheusToken, + ProviderRegistry, +} from '@ethers-v6'; import { SignerWithAddress } from '@nomicfoundation/hardhat-ethers/signers'; import { expect } from 'chai'; import { ethers } from 'hardhat'; import { getHex, wei } from '@/scripts/utils/utils'; import { + deployDelegateRegistry, + deployFacetDelegation, deployFacetMarketplace, deployFacetModelRegistry, deployFacetProviderRegistry, @@ -27,20 +36,27 @@ describe('ModelRegistry', () => { let marketplace: Marketplace; let token: MorpheusToken; + let delegateRegistry: DelegateRegistry; - const modelId = getHex(Buffer.from('1')); + const baseModelId = getHex(Buffer.from('1')); + let modelId = getHex(Buffer.from('')); const ipfsCID = getHex(Buffer.from('ipfs://ipfsaddress')); before(async () => { [OWNER, SECOND] = await ethers.getSigners(); - [diamond, token] = await Promise.all([deployLumerinDiamond(), deployMORToken()]); + [diamond, token, delegateRegistry] = await Promise.all([ + deployLumerinDiamond(), + deployMORToken(), + deployDelegateRegistry(), + ]); [providerRegistry, modelRegistry, , marketplace] = await Promise.all([ deployFacetProviderRegistry(diamond), deployFacetModelRegistry(diamond), deployFacetSessionRouter(diamond, OWNER), deployFacetMarketplace(diamond, token, wei(0.0001), wei(900)), + deployFacetDelegation(diamond, delegateRegistry), ]); await token.transfer(SECOND, wei(1000)); @@ -51,6 +67,8 @@ describe('ModelRegistry', () => { await token.connect(SECOND).approve(marketplace, wei(1000)); await token.approve(marketplace, wei(1000)); + modelId = await modelRegistry.getModelId(SECOND, baseModelId); + await reverter.snapshot(); }); @@ -88,10 +106,10 @@ describe('ModelRegistry', () => { await setNextTime(300); await modelRegistry .connect(SECOND) - .modelRegister(getHex(Buffer.from('1')), ipfsCID, 0, wei(100), 'name1', ['tag_1']); + .modelRegister(SECOND, getHex(Buffer.from('1')), ipfsCID, 0, wei(100), 'name1', ['tag_1']); await modelRegistry .connect(SECOND) - .modelRegister(getHex(Buffer.from('2')), ipfsCID, 0, wei(100), 'name2', ['tag_1']); + .modelRegister(SECOND, getHex(Buffer.from('2')), ipfsCID, 0, wei(100), 'name2', ['tag_1']); const modelIds = await modelRegistry.getModelIds(0, 10); expect(modelIds.length).to.eq(2); @@ -108,7 +126,7 @@ describe('ModelRegistry', () => { describe('#modelRegister', async () => { it('should register a new model', async () => { await setNextTime(300); - await modelRegistry.connect(SECOND).modelRegister(modelId, ipfsCID, 0, wei(100), 'name', ['tag_1']); + await modelRegistry.connect(SECOND).modelRegister(SECOND, baseModelId, ipfsCID, 0, wei(100), 'name', ['tag_1']); const data = await modelRegistry.getModel(modelId); expect(data.ipfsCID).to.eq(ipfsCID); @@ -124,16 +142,44 @@ describe('ModelRegistry', () => { expect(await token.balanceOf(modelRegistry)).to.eq(wei(100)); expect(await token.balanceOf(SECOND)).to.eq(wei(900)); - expect(await modelRegistry.getActiveModelIds(0, 10)).to.deep.eq([modelId]); + expect(await modelRegistry.getActiveModelIds(0, 10)).to.deep.eq([[modelId], 1n]); - await modelRegistry.connect(SECOND).modelRegister(modelId, ipfsCID, 0, wei(0), 'name', ['tag_1']); + await modelRegistry.connect(SECOND).modelRegister(SECOND, baseModelId, ipfsCID, 0, wei(0), 'name', ['tag_1']); + }); + it('should register a new model from the delegatee address', async () => { + await delegateRegistry + .connect(SECOND) + .delegateContract(OWNER, providerRegistry, await providerRegistry.DELEGATION_RULES_MODEL(), true); + + await setNextTime(300); + await modelRegistry.connect(OWNER).modelRegister(SECOND, baseModelId, ipfsCID, 0, wei(100), 'name', ['tag_1']); + + const data = await modelRegistry.getModel(modelId); + expect(data.ipfsCID).to.eq(ipfsCID); + expect(data.fee).to.eq(0); + expect(data.stake).to.eq(wei(100)); + expect(data.owner).to.eq(SECOND); + expect(data.name).to.eq('name'); + expect(data.tags).deep.eq(['tag_1']); + expect(data.createdAt).to.eq(300); + expect(data.isDeleted).to.eq(false); + expect(await modelRegistry.getIsModelActive(modelId)).to.eq(true); + + expect(await token.balanceOf(modelRegistry)).to.eq(wei(100)); + expect(await token.balanceOf(SECOND)).to.eq(wei(900)); + + expect(await modelRegistry.getActiveModelIds(0, 10)).to.deep.eq([[modelId], 1n]); + + await modelRegistry.connect(SECOND).modelRegister(SECOND, baseModelId, ipfsCID, 0, wei(0), 'name', ['tag_1']); }); it('should add stake to existed model', async () => { const ipfsCID2 = getHex(Buffer.from('ipfs://ipfsaddress/2')); await setNextTime(300); - await modelRegistry.connect(SECOND).modelRegister(modelId, ipfsCID, 0, wei(100), 'name', ['tag_1']); - await modelRegistry.connect(SECOND).modelRegister(modelId, ipfsCID2, 1, wei(300), 'name2', ['tag_1', 'tag_2']); + await modelRegistry.connect(SECOND).modelRegister(SECOND, baseModelId, ipfsCID, 0, wei(100), 'name', ['tag_1']); + await modelRegistry + .connect(SECOND) + .modelRegister(SECOND, baseModelId, ipfsCID2, 1, wei(300), 'name2', ['tag_1', 'tag_2']); const data = await modelRegistry.getModel(modelId); expect(data.ipfsCID).to.eq(ipfsCID2); @@ -151,14 +197,14 @@ describe('ModelRegistry', () => { }); it('should activate deregistered model', async () => { await setNextTime(300); - await modelRegistry.connect(SECOND).modelRegister(modelId, ipfsCID, 0, wei(100), 'name', ['tag_1']); + await modelRegistry.connect(SECOND).modelRegister(SECOND, baseModelId, ipfsCID, 0, wei(100), 'name', ['tag_1']); await modelRegistry.connect(SECOND).modelDeregister(modelId); let data = await modelRegistry.getModel(modelId); expect(data.isDeleted).to.eq(true); expect(await modelRegistry.getIsModelActive(modelId)).to.eq(false); - await modelRegistry.connect(SECOND).modelRegister(modelId, ipfsCID, 4, wei(200), 'name3', ['tag_3']); + await modelRegistry.connect(SECOND).modelRegister(SECOND, baseModelId, ipfsCID, 4, wei(200), 'name3', ['tag_3']); data = await modelRegistry.getModel(modelId); expect(data.ipfsCID).to.eq(ipfsCID); @@ -171,24 +217,30 @@ describe('ModelRegistry', () => { expect(data.isDeleted).to.eq(false); expect(await modelRegistry.getIsModelActive(modelId)).to.eq(true); }); - it('should throw error when the caller is not a model owner', async () => { - await modelRegistry.connect(SECOND).modelRegister(modelId, ipfsCID, 0, wei(100), 'name', ['tag_1']); - await expect( - modelRegistry.connect(OWNER).modelRegister(modelId, ipfsCID, 0, wei(100), 'name', ['tag_1']), - ).to.be.revertedWithCustomError(modelRegistry, 'OwnableUnauthorizedAccount'); - }); it('should throw error when the stake is too low', async () => { await modelRegistry.modelSetMinStake(wei(2)); await expect( - modelRegistry.connect(SECOND).modelRegister(modelId, ipfsCID, 0, wei(1), 'name', ['tag_1']), + modelRegistry.connect(SECOND).modelRegister(SECOND, baseModelId, ipfsCID, 0, wei(1), 'name', ['tag_1']), ).to.be.revertedWithCustomError(modelRegistry, 'ModelStakeTooLow'); }); + it('should throw error when register the model without delegation or with incorrect rules', async () => { + await expect( + modelRegistry.connect(OWNER).modelRegister(SECOND, baseModelId, ipfsCID, 0, wei(100), 'name', ['tag_1']), + ).to.be.revertedWithCustomError(providerRegistry, 'InsufficientRightsForOperation'); + + await delegateRegistry + .connect(SECOND) + .delegateContract(OWNER, providerRegistry, getHex(Buffer.from('123')), true); + await expect( + modelRegistry.connect(OWNER).modelRegister(SECOND, baseModelId, ipfsCID, 0, wei(100), 'name', ['tag_1']), + ).to.be.revertedWithCustomError(providerRegistry, 'InsufficientRightsForOperation'); + }); }); describe('#modelDeregister', async () => { it('should deregister the model', async () => { await setNextTime(300); - await modelRegistry.connect(SECOND).modelRegister(modelId, ipfsCID, 0, wei(100), 'name', ['tag_1']); + await modelRegistry.connect(SECOND).modelRegister(SECOND, baseModelId, ipfsCID, 0, wei(100), 'name', ['tag_1']); await modelRegistry.connect(SECOND).modelDeregister(modelId); expect((await modelRegistry.getModel(modelId)).isDeleted).to.equal(true); @@ -196,25 +248,41 @@ describe('ModelRegistry', () => { expect(await token.balanceOf(modelRegistry)).to.eq(0); expect(await token.balanceOf(SECOND)).to.eq(wei(1000)); - expect(await modelRegistry.getActiveModelIds(0, 10)).to.deep.eq([]); + expect(await modelRegistry.getActiveModelIds(0, 10)).to.deep.eq([[], 0n]); + }); + it('should deregister the model from the delegatee address', async () => { + await setNextTime(300); + await modelRegistry.connect(SECOND).modelRegister(SECOND, baseModelId, ipfsCID, 0, wei(100), 'name', ['tag_1']); + + await delegateRegistry + .connect(SECOND) + .delegateContract(OWNER, providerRegistry, await providerRegistry.DELEGATION_RULES_MODEL(), true); + await modelRegistry.connect(OWNER).modelDeregister(modelId); + + expect((await modelRegistry.getModel(modelId)).isDeleted).to.equal(true); + expect(await modelRegistry.getIsModelActive(modelId)).to.eq(false); + expect(await token.balanceOf(modelRegistry)).to.eq(0); + expect(await token.balanceOf(SECOND)).to.eq(wei(1000)); + + expect(await modelRegistry.getActiveModelIds(0, 10)).to.deep.eq([[], 0n]); }); it('should throw error when the caller is not an owner or specified address', async () => { await expect(modelRegistry.connect(SECOND).modelDeregister(modelId)).to.be.revertedWithCustomError( modelRegistry, - 'OwnableUnauthorizedAccount', + 'InsufficientRightsForOperation', ); }); it('should throw error when model has active bids', async () => { - await providerRegistry.connect(SECOND).providerRegister(wei(100), 'test'); - await modelRegistry.connect(SECOND).modelRegister(modelId, ipfsCID, 0, wei(100), 'name', ['tag_1']); - await marketplace.connect(SECOND).postModelBid(modelId, wei(10)); + await providerRegistry.connect(SECOND).providerRegister(SECOND, wei(100), 'test'); + await modelRegistry.connect(SECOND).modelRegister(SECOND, baseModelId, ipfsCID, 0, wei(100), 'name', ['tag_1']); + await marketplace.connect(SECOND).postModelBid(SECOND, modelId, wei(10)); await expect(modelRegistry.connect(SECOND).modelDeregister(modelId)).to.be.revertedWithCustomError( modelRegistry, 'ModelHasActiveBids', ); }); it('should throw error when delete model few times', async () => { - await modelRegistry.connect(SECOND).modelRegister(modelId, ipfsCID, 0, wei(100), 'name', ['tag_1']); + await modelRegistry.connect(SECOND).modelRegister(SECOND, baseModelId, ipfsCID, 0, wei(100), 'name', ['tag_1']); await modelRegistry.connect(SECOND).modelDeregister(modelId); await expect(modelRegistry.connect(SECOND).modelDeregister(modelId)).to.be.revertedWithCustomError( modelRegistry, diff --git a/smart-contracts/test/diamond/facets/ProviderRegistry.test.ts b/smart-contracts/test/diamond/facets/ProviderRegistry.test.ts index 9a392db2..9d9b8af0 100644 --- a/smart-contracts/test/diamond/facets/ProviderRegistry.test.ts +++ b/smart-contracts/test/diamond/facets/ProviderRegistry.test.ts @@ -3,8 +3,11 @@ import { SignerWithAddress } from '@nomicfoundation/hardhat-ethers/signers'; import { expect } from 'chai'; import { ethers } from 'hardhat'; +import { DelegateRegistry } from '@/generated-types/ethers/contracts/mock/delegate-registry/src'; import { getHex, wei } from '@/scripts/utils/utils'; import { + deployDelegateRegistry, + deployFacetDelegation, deployFacetMarketplace, deployFacetModelRegistry, deployFacetProviderRegistry, @@ -28,26 +31,35 @@ describe('ProviderRegistry', () => { let marketplace: Marketplace; let token: MorpheusToken; + let delegateRegistry: DelegateRegistry; - const modelId = getHex(Buffer.from('1')); + const baseModelId = getHex(Buffer.from('1')); + let modelId = getHex(Buffer.from('')); const ipfsCID = getHex(Buffer.from('ipfs://ipfsaddress')); before(async () => { [OWNER, PROVIDER] = await ethers.getSigners(); - [diamond, token] = await Promise.all([deployLumerinDiamond(), deployMORToken()]); + [diamond, token, delegateRegistry] = await Promise.all([ + deployLumerinDiamond(), + deployMORToken(), + deployDelegateRegistry(), + ]); [providerRegistry, modelRegistry, , marketplace] = await Promise.all([ deployFacetProviderRegistry(diamond), deployFacetModelRegistry(diamond), deployFacetSessionRouter(diamond, OWNER), deployFacetMarketplace(diamond, token, wei(0.0001), wei(900)), + deployFacetDelegation(diamond, delegateRegistry), ]); await token.transfer(PROVIDER, wei(1000)); await token.connect(PROVIDER).approve(providerRegistry, wei(1000)); await token.approve(providerRegistry, wei(1000)); + modelId = await modelRegistry.getModelId(PROVIDER, baseModelId); + await reverter.snapshot(); }); @@ -83,7 +95,7 @@ describe('ProviderRegistry', () => { describe('#providerRegister', async () => { it('should register a new provider', async () => { await setNextTime(300); - await providerRegistry.connect(PROVIDER).providerRegister(wei(100), 'test'); + await providerRegistry.connect(PROVIDER).providerRegister(PROVIDER, wei(100), 'test'); const data = await providerRegistry.getProvider(PROVIDER); @@ -98,14 +110,14 @@ describe('ProviderRegistry', () => { expect(await token.balanceOf(providerRegistry)).to.eq(wei(100)); expect(await token.balanceOf(PROVIDER)).to.eq(wei(900)); - expect(await providerRegistry.getActiveProviders(0, 10)).to.deep.eq([PROVIDER.address]); + expect(await providerRegistry.getActiveProviders(0, 10)).to.deep.eq([[PROVIDER.address], 1n]); - await providerRegistry.connect(PROVIDER).providerRegister(wei(0), 'test'); + await providerRegistry.connect(PROVIDER).providerRegister(PROVIDER, wei(0), 'test'); }); it('should add stake to existed provider', async () => { await setNextTime(300); - await providerRegistry.connect(PROVIDER).providerRegister(wei(100), 'test'); - await providerRegistry.connect(PROVIDER).providerRegister(wei(300), 'test2'); + await providerRegistry.connect(PROVIDER).providerRegister(PROVIDER, wei(100), 'test'); + await providerRegistry.connect(PROVIDER).providerRegister(PROVIDER, wei(300), 'test2'); const data = await providerRegistry.getProvider(PROVIDER); @@ -122,15 +134,15 @@ describe('ProviderRegistry', () => { }); it('should activate deregistered provider', async () => { await setNextTime(300); - await providerRegistry.connect(PROVIDER).providerRegister(wei(100), 'test'); + await providerRegistry.connect(PROVIDER).providerRegister(PROVIDER, wei(100), 'test'); await setNextTime(301 + YEAR); - await providerRegistry.connect(PROVIDER).providerDeregister(); + await providerRegistry.connect(PROVIDER).providerDeregister(PROVIDER); let data = await providerRegistry.getProvider(PROVIDER); expect(data.isDeleted).to.eq(true); expect(await providerRegistry.getIsProviderActive(PROVIDER)).to.eq(false); - await providerRegistry.connect(PROVIDER).providerRegister(wei(1), 'test2'); + await providerRegistry.connect(PROVIDER).providerRegister(PROVIDER, wei(1), 'test2'); data = await providerRegistry.getProvider(PROVIDER); expect(data.endpoint).to.eq('test2'); @@ -141,35 +153,88 @@ describe('ProviderRegistry', () => { expect(data.isDeleted).to.eq(false); expect(await providerRegistry.getIsProviderActive(PROVIDER)).to.eq(true); }); + it('should register a new provider from the delegatee address', async () => { + await delegateRegistry + .connect(PROVIDER) + .delegateContract(OWNER, providerRegistry, await providerRegistry.DELEGATION_RULES_PROVIDER(), true); + + await setNextTime(300); + await providerRegistry.connect(OWNER).providerRegister(PROVIDER, wei(100), 'test'); + + const data = await providerRegistry.getProvider(PROVIDER); + + expect(data.endpoint).to.eq('test'); + expect(data.stake).to.eq(wei(100)); + expect(data.createdAt).to.eq(300); + expect(data.limitPeriodEnd).to.eq(YEAR + 300); + expect(data.limitPeriodEarned).to.eq(0); + expect(data.isDeleted).to.eq(false); + expect(await providerRegistry.getIsProviderActive(PROVIDER)).to.eq(true); + + expect(await token.balanceOf(providerRegistry)).to.eq(wei(100)); + expect(await token.balanceOf(PROVIDER)).to.eq(wei(900)); + + expect(await providerRegistry.getActiveProviders(0, 10)).to.deep.eq([[PROVIDER.address], 1n]); + + await providerRegistry.connect(PROVIDER).providerRegister(PROVIDER, wei(0), 'test'); + }); it('should throw error when the stake is too low', async () => { await providerRegistry.providerSetMinStake(wei(2)); - await expect(providerRegistry.connect(PROVIDER).providerRegister(wei(0), '')).to.be.revertedWithCustomError( - providerRegistry, - 'ProviderStakeTooLow', - ); + await expect( + providerRegistry.connect(PROVIDER).providerRegister(PROVIDER, wei(0), ''), + ).to.be.revertedWithCustomError(providerRegistry, 'ProviderStakeTooLow'); + }); + it('should throw error when create provider without delegation or with incorrect rules', async () => { + await expect( + providerRegistry.connect(OWNER).providerRegister(PROVIDER, wei(0), ''), + ).to.be.revertedWithCustomError(providerRegistry, 'InsufficientRightsForOperation'); + + await delegateRegistry + .connect(PROVIDER) + .delegateContract(OWNER, providerRegistry, getHex(Buffer.from('123')), true); + await expect( + providerRegistry.connect(OWNER).providerRegister(PROVIDER, wei(0), ''), + ).to.be.revertedWithCustomError(providerRegistry, 'InsufficientRightsForOperation'); }); }); describe('#providerDeregister', async () => { it('should deregister the provider', async () => { await setNextTime(300); - await providerRegistry.connect(PROVIDER).providerRegister(wei(100), 'test'); + await providerRegistry.connect(PROVIDER).providerRegister(PROVIDER, wei(100), 'test'); + await setNextTime(301 + YEAR); + await providerRegistry.connect(PROVIDER).providerDeregister(PROVIDER); + + expect((await providerRegistry.getProvider(PROVIDER)).isDeleted).to.equal(true); + expect(await providerRegistry.getIsProviderActive(PROVIDER)).to.eq(false); + expect(await token.balanceOf(providerRegistry)).to.eq(0); + expect(await token.balanceOf(PROVIDER)).to.eq(wei(1000)); + + expect(await providerRegistry.getActiveProviders(0, 10)).to.deep.eq([[], 0n]); + }); + it('should deregister the provider from the delegatee address', async () => { + await setNextTime(300); + await providerRegistry.connect(PROVIDER).providerRegister(PROVIDER, wei(100), 'test'); + + await delegateRegistry + .connect(PROVIDER) + .delegateContract(OWNER, providerRegistry, await providerRegistry.DELEGATION_RULES_PROVIDER(), true); await setNextTime(301 + YEAR); - await providerRegistry.connect(PROVIDER).providerDeregister(); + await providerRegistry.connect(OWNER).providerDeregister(PROVIDER); expect((await providerRegistry.getProvider(PROVIDER)).isDeleted).to.equal(true); expect(await providerRegistry.getIsProviderActive(PROVIDER)).to.eq(false); expect(await token.balanceOf(providerRegistry)).to.eq(0); expect(await token.balanceOf(PROVIDER)).to.eq(wei(1000)); - expect(await providerRegistry.getActiveProviders(0, 10)).to.deep.eq([]); + expect(await providerRegistry.getActiveProviders(0, 10)).to.deep.eq([[], 0n]); }); it('should deregister the provider without transfer', async () => { await providerRegistry.providerSetMinStake(0); await setNextTime(300); - await providerRegistry.connect(PROVIDER).providerRegister(wei(0), 'test'); + await providerRegistry.connect(PROVIDER).providerRegister(PROVIDER, wei(0), 'test'); await setNextTime(301 + YEAR); - await providerRegistry.connect(PROVIDER).providerDeregister(); + await providerRegistry.connect(PROVIDER).providerDeregister(PROVIDER); expect((await providerRegistry.getProvider(PROVIDER)).isDeleted).to.equal(true); expect(await providerRegistry.getIsProviderActive(PROVIDER)).to.eq(false); @@ -177,24 +242,26 @@ describe('ProviderRegistry', () => { expect(await token.balanceOf(PROVIDER)).to.eq(wei(1000)); }); it('should throw error when provider is not found', async () => { - await expect(providerRegistry.connect(OWNER).providerDeregister()).to.be.revertedWithCustomError( + await expect(providerRegistry.connect(OWNER).providerDeregister(OWNER)).to.be.revertedWithCustomError( providerRegistry, 'ProviderNotFound', ); }); it('should throw error when provider has active bids', async () => { - await providerRegistry.connect(PROVIDER).providerRegister(wei(100), 'test'); - await modelRegistry.connect(PROVIDER).modelRegister(modelId, ipfsCID, 0, wei(100), 'name', ['tag_1']); - await marketplace.connect(PROVIDER).postModelBid(modelId, wei(10)); - await expect(providerRegistry.connect(PROVIDER).providerDeregister()).to.be.revertedWithCustomError( + await providerRegistry.connect(PROVIDER).providerRegister(PROVIDER, wei(100), 'test'); + await modelRegistry + .connect(PROVIDER) + .modelRegister(PROVIDER, baseModelId, ipfsCID, 0, wei(100), 'name', ['tag_1']); + await marketplace.connect(PROVIDER).postModelBid(PROVIDER, modelId, wei(10)); + await expect(providerRegistry.connect(PROVIDER).providerDeregister(PROVIDER)).to.be.revertedWithCustomError( providerRegistry, 'ProviderHasActiveBids', ); }); it('should throw error when delete provider few times', async () => { - await providerRegistry.connect(OWNER).providerRegister(wei(100), 'test'); - await providerRegistry.connect(OWNER).providerDeregister(); - await expect(providerRegistry.connect(OWNER).providerDeregister()).to.be.revertedWithCustomError( + await providerRegistry.connect(PROVIDER).providerRegister(PROVIDER, wei(100), 'test'); + await providerRegistry.connect(PROVIDER).providerDeregister(PROVIDER); + await expect(providerRegistry.connect(PROVIDER).providerDeregister(PROVIDER)).to.be.revertedWithCustomError( providerRegistry, 'ProviderHasAlreadyDeregistered', ); diff --git a/smart-contracts/test/diamond/facets/SessionRouter.test.ts b/smart-contracts/test/diamond/facets/SessionRouter.test.ts index 2ceba527..8279f3e1 100644 --- a/smart-contracts/test/diamond/facets/SessionRouter.test.ts +++ b/smart-contracts/test/diamond/facets/SessionRouter.test.ts @@ -1,10 +1,20 @@ -import { LumerinDiamond, Marketplace, ModelRegistry, MorpheusToken, ProviderRegistry, SessionRouter } from '@ethers-v6'; +import { + DelegateRegistry, + LumerinDiamond, + Marketplace, + ModelRegistry, + MorpheusToken, + ProviderRegistry, + SessionRouter, +} from '@ethers-v6'; import { SignerWithAddress } from '@nomicfoundation/hardhat-ethers/signers'; import { expect } from 'chai'; import { ethers } from 'hardhat'; import { getHex, wei } from '@/scripts/utils/utils'; import { + deployDelegateRegistry, + deployFacetDelegation, deployFacetMarketplace, deployFacetModelRegistry, deployFacetProviderRegistry, @@ -33,21 +43,28 @@ describe('SessionRouter', () => { let sessionRouter: SessionRouter; let token: MorpheusToken; + let delegateRegistry: DelegateRegistry; let bidId = ''; - const modelId = getHex(Buffer.from('1')); + const baseModelId = getHex(Buffer.from('1')); + let modelId = getHex(Buffer.from('')); const bidPricePerSecond = wei(0.0001); before(async () => { [OWNER, SECOND, FUNDING, PROVIDER] = await ethers.getSigners(); - [diamond, token] = await Promise.all([deployLumerinDiamond(), deployMORToken()]); + [diamond, token, delegateRegistry] = await Promise.all([ + deployLumerinDiamond(), + deployMORToken(), + deployDelegateRegistry(), + ]); [providerRegistry, modelRegistry, sessionRouter, marketplace] = await Promise.all([ deployFacetProviderRegistry(diamond), deployFacetModelRegistry(diamond), deployFacetSessionRouter(diamond, FUNDING), deployFacetMarketplace(diamond, token, wei(0.0001), wei(900)), + deployFacetDelegation(diamond, delegateRegistry), ]); await token.transfer(SECOND, wei(10000)); @@ -60,10 +77,12 @@ describe('SessionRouter', () => { await token.connect(FUNDING).approve(sessionRouter, wei(10000)); const ipfsCID = getHex(Buffer.from('ipfs://ipfsaddress')); - await providerRegistry.connect(PROVIDER).providerRegister(wei(0.2), 'test'); - await modelRegistry.connect(PROVIDER).modelRegister(modelId, ipfsCID, 0, wei(100), 'name', ['tag_1']); + await providerRegistry.connect(PROVIDER).providerRegister(PROVIDER, wei(0.2), 'test'); + await modelRegistry.connect(PROVIDER).modelRegister(PROVIDER, baseModelId, ipfsCID, 0, wei(100), 'name', ['tag_1']); + + modelId = await modelRegistry.getModelId(PROVIDER, baseModelId); - await marketplace.connect(PROVIDER).postModelBid(modelId, bidPricePerSecond); + await marketplace.connect(PROVIDER).postModelBid(PROVIDER, modelId, bidPricePerSecond); bidId = await marketplace.getBidId(PROVIDER, modelId, 0); await reverter.snapshot(); @@ -157,10 +176,10 @@ describe('SessionRouter', () => { tokenBalBefore = await token.balanceOf(sessionRouter); secondBalBefore = await token.balanceOf(SECOND); }); - it('should open session', async () => { + it('should open a session', async () => { await setTime(payoutStart + 10 * DAY); const { msg, signature } = await getProviderApproval(PROVIDER, SECOND, bidId); - await sessionRouter.connect(SECOND).openSession(wei(50), false, msg, signature); + await sessionRouter.connect(SECOND).openSession(SECOND, wei(50), false, msg, signature); const sessionId = await sessionRouter.getSessionId(SECOND, PROVIDER, bidId, 0); const data = await sessionRouter.getSession(sessionId); @@ -182,17 +201,50 @@ describe('SessionRouter', () => { expect(secondBalBefore - secondBalAfter).to.eq(wei(50)); expect(await sessionRouter.getIsProviderApprovalUsed(msg)).to.eq(true); - expect(await sessionRouter.getUserSessions(SECOND, 0, 10)).to.deep.eq([sessionId]); - expect(await sessionRouter.getProviderSessions(PROVIDER, 0, 10)).to.deep.eq([sessionId]); - expect(await sessionRouter.getModelSessions(modelId, 0, 10)).to.deep.eq([sessionId]); + expect(await sessionRouter.getUserSessions(SECOND, 0, 10)).to.deep.eq([[sessionId], 1n]); + expect(await sessionRouter.getProviderSessions(PROVIDER, 0, 10)).to.deep.eq([[sessionId], 1n]); + expect(await sessionRouter.getModelSessions(modelId, 0, 10)).to.deep.eq([[sessionId], 1n]); }); - it('should open two different session wit the same input params', async () => { + it('should open a session from the delegatee address', async () => { + await delegateRegistry + .connect(SECOND) + .delegateContract(OWNER, providerRegistry, await providerRegistry.DELEGATION_RULES_SESSION(), true); + + await setTime(payoutStart + 10 * DAY); + const { msg, signature } = await getProviderApproval(PROVIDER, OWNER, bidId); + await sessionRouter.connect(OWNER).openSession(SECOND, wei(50), false, msg, signature); + + const sessionId = await sessionRouter.getSessionId(SECOND, PROVIDER, bidId, 0); + const data = await sessionRouter.getSession(sessionId); + expect(data.user).to.eq(SECOND); + expect(data.bidId).to.eq(bidId); + expect(data.stake).to.eq(wei(50)); + expect(data.closeoutReceipt).to.eq('0x'); + expect(data.closeoutType).to.eq(0); + expect(data.providerWithdrawnAmount).to.eq(0); + expect(data.openedAt).to.eq(payoutStart + 10 * DAY + 1); + expect(data.endsAt).to.greaterThan(data.openedAt); + expect(data.closedAt).to.eq(0); + expect(data.isActive).to.eq(true); + expect(data.isDirectPaymentFromUser).to.eq(false); + + const tokenBalAfter = await token.balanceOf(sessionRouter); + expect(tokenBalAfter - tokenBalBefore).to.eq(wei(50)); + const secondBalAfter = await token.balanceOf(SECOND); + expect(secondBalBefore - secondBalAfter).to.eq(wei(50)); + + expect(await sessionRouter.getIsProviderApprovalUsed(msg)).to.eq(true); + expect(await sessionRouter.getUserSessions(SECOND, 0, 10)).to.deep.eq([[sessionId], 1n]); + expect(await sessionRouter.getProviderSessions(PROVIDER, 0, 10)).to.deep.eq([[sessionId], 1n]); + expect(await sessionRouter.getModelSessions(modelId, 0, 10)).to.deep.eq([[sessionId], 1n]); + }); + it('should open two different sessions wit the same input params', async () => { await setTime(payoutStart + 10 * DAY); const { msg: msg1, signature: signature1 } = await getProviderApproval(PROVIDER, SECOND, bidId); await setTime(payoutStart + 10 * DAY + 1); const { msg: msg2, signature: signature2 } = await getProviderApproval(PROVIDER, SECOND, bidId); - await sessionRouter.connect(SECOND).openSession(wei(50), false, msg1, signature1); - await sessionRouter.connect(SECOND).openSession(wei(50), false, msg2, signature2); + await sessionRouter.connect(SECOND).openSession(SECOND, wei(50), false, msg1, signature1); + await sessionRouter.connect(SECOND).openSession(SECOND, wei(50), false, msg2, signature2); const sessionId1 = await sessionRouter.getSessionId(SECOND, PROVIDER, bidId, 0); const sessionId2 = await sessionRouter.getSessionId(SECOND, PROVIDER, bidId, 1); @@ -204,25 +256,25 @@ describe('SessionRouter', () => { expect(await sessionRouter.getIsProviderApprovalUsed(msg1)).to.eq(true); expect(await sessionRouter.getIsProviderApprovalUsed(msg2)).to.eq(true); - expect(await sessionRouter.getUserSessions(SECOND, 0, 10)).to.deep.eq([sessionId1, sessionId2]); - expect(await sessionRouter.getProviderSessions(PROVIDER, 0, 10)).to.deep.eq([sessionId1, sessionId2]); - expect(await sessionRouter.getModelSessions(modelId, 0, 10)).to.deep.eq([sessionId1, sessionId2]); + expect(await sessionRouter.getUserSessions(SECOND, 0, 10)).to.deep.eq([[sessionId1, sessionId2], 2n]); + expect(await sessionRouter.getProviderSessions(PROVIDER, 0, 10)).to.deep.eq([[sessionId1, sessionId2], 2n]); + expect(await sessionRouter.getModelSessions(modelId, 0, 10)).to.deep.eq([[sessionId1, sessionId2], 2n]); expect(await sessionRouter.getTotalSessions(PROVIDER)).to.eq(2); }); - it('should open session with max duration', async () => { + it('should open a session with max duration', async () => { await setTime(payoutStart + 10 * DAY); const { msg, signature } = await getProviderApproval(PROVIDER, SECOND, bidId); - await sessionRouter.connect(SECOND).openSession(wei(10000), false, msg, signature); + await sessionRouter.connect(SECOND).openSession(SECOND, wei(10000), false, msg, signature); const sessionId = await sessionRouter.getSessionId(SECOND, PROVIDER, bidId, 0); const data = await sessionRouter.getSession(sessionId); expect(data.endsAt).to.eq(Number(data.openedAt.toString()) + DAY); }); - it('should open session with valid amount for direct user payment', async () => { + it('should open a session with valid amount for direct user payment', async () => { await setTime(payoutStart + 10 * DAY); const { msg, signature } = await getProviderApproval(PROVIDER, SECOND, bidId); - await sessionRouter.connect(SECOND).openSession(wei(50), true, msg, signature); + await sessionRouter.connect(SECOND).openSession(SECOND, wei(50), true, msg, signature); const sessionId = await sessionRouter.getSessionId(SECOND, PROVIDER, bidId, 0); const data = await sessionRouter.getSession(sessionId); @@ -244,20 +296,20 @@ describe('SessionRouter', () => { expect(secondBalBefore - secondBalAfter).to.eq(wei(50)); expect(await sessionRouter.getIsProviderApprovalUsed(msg)).to.eq(true); - expect(await sessionRouter.getUserSessions(SECOND, 0, 10)).to.deep.eq([sessionId]); - expect(await sessionRouter.getProviderSessions(PROVIDER, 0, 10)).to.deep.eq([sessionId]); - expect(await sessionRouter.getModelSessions(modelId, 0, 10)).to.deep.eq([sessionId]); + expect(await sessionRouter.getUserSessions(SECOND, 0, 10)).to.deep.eq([[sessionId], 1n]); + expect(await sessionRouter.getProviderSessions(PROVIDER, 0, 10)).to.deep.eq([[sessionId], 1n]); + expect(await sessionRouter.getModelSessions(modelId, 0, 10)).to.deep.eq([[sessionId], 1n]); }); it('should throw error when the approval is for an another user', async () => { const { msg, signature } = await getProviderApproval(PROVIDER, OWNER, bidId); await expect( - sessionRouter.connect(SECOND).openSession(wei(50), false, msg, signature), + sessionRouter.connect(SECOND).openSession(SECOND, wei(50), false, msg, signature), ).to.be.revertedWithCustomError(sessionRouter, 'SessionApprovedForAnotherUser'); }); it('should throw error when the approval is for an another chain', async () => { const { msg, signature } = await getProviderApproval(PROVIDER, SECOND, bidId, 1n); await expect( - sessionRouter.connect(SECOND).openSession(wei(50), false, msg, signature), + sessionRouter.connect(SECOND).openSession(SECOND, wei(50), false, msg, signature), ).to.be.revertedWithCustomError(sessionRouter, 'SesssionApprovedForAnotherChainId'); }); it('should throw error when an aprrove expired', async () => { @@ -265,35 +317,50 @@ describe('SessionRouter', () => { const { msg, signature } = await getProviderApproval(PROVIDER, SECOND, bidId); await setTime(payoutStart + 600); await expect( - sessionRouter.connect(SECOND).openSession(wei(50), false, msg, signature), + sessionRouter.connect(SECOND).openSession(SECOND, wei(50), false, msg, signature), ).to.be.revertedWithCustomError(sessionRouter, 'SesssionApproveExpired'); }); it('should throw error when the bid is not found', async () => { const { msg, signature } = await getProviderApproval(PROVIDER, SECOND, getHex(Buffer.from('1'))); await expect( - sessionRouter.connect(SECOND).openSession(wei(50), false, msg, signature), + sessionRouter.connect(SECOND).openSession(SECOND, wei(50), false, msg, signature), ).to.be.revertedWithCustomError(sessionRouter, 'SessionBidNotFound'); }); it('should throw error when the signature mismatch', async () => { const { msg, signature } = await getProviderApproval(OWNER, SECOND, bidId); await expect( - sessionRouter.connect(SECOND).openSession(wei(50), false, msg, signature), + sessionRouter.connect(SECOND).openSession(SECOND, wei(50), false, msg, signature), ).to.be.revertedWithCustomError(sessionRouter, 'SessionProviderSignatureMismatch'); }); it('should throw error when an approval duplicated', async () => { await setTime(payoutStart + 10 * DAY); const { msg, signature } = await getProviderApproval(PROVIDER, SECOND, bidId); - await sessionRouter.connect(SECOND).openSession(wei(50), false, msg, signature); + await sessionRouter.connect(SECOND).openSession(SECOND, wei(50), false, msg, signature); await expect( - sessionRouter.connect(SECOND).openSession(wei(50), false, msg, signature), + sessionRouter.connect(SECOND).openSession(SECOND, wei(50), false, msg, signature), ).to.be.revertedWithCustomError(sessionRouter, 'SessionDuplicateApproval'); }); it('should throw error when session duration too short', async () => { const { msg, signature } = await getProviderApproval(PROVIDER, SECOND, bidId); await expect( - sessionRouter.connect(SECOND).openSession(wei(50), false, msg, signature), + sessionRouter.connect(SECOND).openSession(SECOND, wei(50), false, msg, signature), ).to.be.revertedWithCustomError(sessionRouter, 'SessionTooShort'); }); + it('should throw error when open a session without delegation or with incorrect rules', async () => { + await setTime(payoutStart + 10 * DAY); + const { msg, signature } = await getProviderApproval(PROVIDER, OWNER, bidId); + + await expect( + sessionRouter.connect(OWNER).openSession(SECOND, wei(50), false, msg, signature), + ).to.be.revertedWithCustomError(providerRegistry, 'InsufficientRightsForOperation'); + + await delegateRegistry + .connect(SECOND) + .delegateContract(OWNER, providerRegistry, getHex(Buffer.from('123')), true); + await expect( + sessionRouter.connect(OWNER).openSession(SECOND, wei(50), false, msg, signature), + ).to.be.revertedWithCustomError(providerRegistry, 'InsufficientRightsForOperation'); + }); }); describe('#closeSession', () => { @@ -323,6 +390,36 @@ describe('SessionRouter', () => { const fundingBalAfter = await token.balanceOf(FUNDING); expect(fundingBalBefore - fundingBalAfter).to.eq(bidPricePerSecond * duration); }); + it('should close session and send rewards for the provider from the delegatee address, late closure', async () => { + const { sessionId, openedAt } = await _createSession(); + + const providerBalBefore = await token.balanceOf(PROVIDER); + const fundingBalBefore = await token.balanceOf(FUNDING); + + await delegateRegistry + .connect(SECOND) + .delegateContract(OWNER, providerRegistry, await providerRegistry.DELEGATION_RULES_SESSION(), true); + + await setTime(openedAt + 5 * DAY); + const { msg: receiptMsg } = await getReceipt(PROVIDER, sessionId, 0, 0); + const { signature: receiptSig } = await getReceipt(OWNER, sessionId, 0, 0); + await sessionRouter.connect(OWNER).closeSession(receiptMsg, receiptSig); + + const session = await sessionRouter.getSession(sessionId); + const duration = session.endsAt - session.openedAt; + + expect(session.closedAt).to.eq(openedAt + 5 * DAY + 1); + expect(session.isActive).to.eq(false); + expect(session.closeoutReceipt).to.eq(receiptMsg); + expect(session.providerWithdrawnAmount).to.eq(bidPricePerSecond * duration); + + expect((await sessionRouter.getProvider(PROVIDER)).limitPeriodEarned).to.eq(bidPricePerSecond * duration); + + const providerBalAfter = await token.balanceOf(PROVIDER); + expect(providerBalAfter - providerBalBefore).to.eq(bidPricePerSecond * duration); + const fundingBalAfter = await token.balanceOf(FUNDING); + expect(fundingBalBefore - fundingBalAfter).to.eq(bidPricePerSecond * duration); + }); it('should close session and send rewards for the provider, no dispute, early closure', async () => { const { sessionId, openedAt } = await _createSession(); const providerBalBefore = await token.balanceOf(PROVIDER); @@ -347,7 +444,7 @@ describe('SessionRouter', () => { const fundingBalAfter = await token.balanceOf(FUNDING); expect(fundingBalBefore - fundingBalAfter).to.eq(bidPricePerSecond * duration); }); - it('should close session and send rewards for the provider, late closure before end', async () => { + it('should close session and send rewards for the provider, with dispute, early closure on the next day', async () => { const { sessionId, secondsToDayEnd, openedAt } = await _createSession(); const providerBalBefore = await token.balanceOf(PROVIDER); @@ -373,7 +470,37 @@ describe('SessionRouter', () => { const fundingBalAfter = await token.balanceOf(FUNDING); expect(fundingBalBefore - fundingBalAfter).to.eq(bidPricePerSecond * duration); }); - it('should close session and do not send rewards for the provider, with dispute, same day closure', async () => { + it('should close session and send rewards for the provider from the delegatee address, with dispute, early closure on the next day', async () => { + const { sessionId, secondsToDayEnd, openedAt } = await _createSession(); + + const providerBalBefore = await token.balanceOf(PROVIDER); + const fundingBalBefore = await token.balanceOf(FUNDING); + + await delegateRegistry + .connect(SECOND) + .delegateContract(OWNER, providerRegistry, await providerRegistry.DELEGATION_RULES_SESSION(), true); + + await setTime(openedAt + secondsToDayEnd + 1); + const { msg: receiptMsg } = await getReceipt(PROVIDER, sessionId, 0, 0); + const { signature: receiptSig } = await getReceipt(OWNER, sessionId, 0, 0); + await sessionRouter.connect(OWNER).closeSession(receiptMsg, receiptSig); + + const session = await sessionRouter.getSession(sessionId); + const duration = BigInt(secondsToDayEnd); + + expect(session.closedAt).to.eq(openedAt + secondsToDayEnd + 2); + expect(session.isActive).to.eq(false); + expect(session.closeoutReceipt).to.eq(receiptMsg); + expect(session.providerWithdrawnAmount).to.eq(bidPricePerSecond * duration); + + expect((await sessionRouter.getProvider(PROVIDER)).limitPeriodEarned).to.eq(bidPricePerSecond * duration); + + const providerBalAfter = await token.balanceOf(PROVIDER); + expect(providerBalAfter - providerBalBefore).to.eq(bidPricePerSecond * duration); + const fundingBalAfter = await token.balanceOf(FUNDING); + expect(fundingBalBefore - fundingBalAfter).to.eq(bidPricePerSecond * duration); + }); + it('should close session and do not send rewards for the provider, with dispute, early closure on the same day', async () => { const { sessionId, secondsToDayEnd, openedAt } = await _createSession(); const providerBalBefore = await token.balanceOf(PROVIDER); @@ -524,7 +651,7 @@ describe('SessionRouter', () => { const { msg: receiptMsg, signature: receiptSig } = await getReceipt(PROVIDER, getHex(Buffer.from('1')), 0, 0); await expect(sessionRouter.connect(SECOND).closeSession(receiptMsg, receiptSig)).to.be.revertedWithCustomError( sessionRouter, - 'OwnableUnauthorizedAccount', + 'InsufficientRightsForOperation', ); }); it('should throw error when the session already closed', async () => { @@ -563,7 +690,7 @@ describe('SessionRouter', () => { }); describe('#claimForProvider', () => { - it('should claim provider rewards, remainder, session closed with dispute', async () => { + it('should claim provider rewards, remainder, with dispute, early closure on the next day', async () => { const { sessionId, secondsToDayEnd, openedAt } = await _createSession(); await setTime(openedAt + secondsToDayEnd + 1); @@ -578,6 +705,7 @@ describe('SessionRouter', () => { const providerBalBefore = await token.balanceOf(PROVIDER); const fundingBalBefore = await token.balanceOf(FUNDING); + await setTime(openedAt + secondsToDayEnd + 1 + 1 * DAY); await sessionRouter.connect(PROVIDER).claimForProvider(sessionId); session = await sessionRouter.getSession(sessionId); @@ -590,6 +718,65 @@ describe('SessionRouter', () => { const fundingBalAfter = await token.balanceOf(FUNDING); expect(fundingBalBefore - fundingBalAfter).to.eq(bidPricePerSecond * duration); }); + it('should claim provider rewards from the delegatee address, remainder, with dispute, early closure on the next day', async () => { + const { sessionId, secondsToDayEnd, openedAt } = await _createSession(); + + await setTime(openedAt + secondsToDayEnd + 1); + const { msg: receiptMsg } = await getReceipt(PROVIDER, sessionId, 0, 0); + const { signature: receiptSig } = await getReceipt(OWNER, sessionId, 0, 0); + await sessionRouter.connect(SECOND).closeSession(receiptMsg, receiptSig); + + let session = await sessionRouter.getSession(sessionId); + const fullDuration = BigInt(secondsToDayEnd + 1); + const duration = 1n; + + const providerBalBefore = await token.balanceOf(PROVIDER); + const fundingBalBefore = await token.balanceOf(FUNDING); + + await delegateRegistry + .connect(PROVIDER) + .delegateContract(OWNER, providerRegistry, await providerRegistry.DELEGATION_RULES_SESSION(), true); + + await setTime(openedAt + secondsToDayEnd + 1 + 1 * DAY); + await sessionRouter.connect(OWNER).claimForProvider(sessionId); + session = await sessionRouter.getSession(sessionId); + + expect(session.providerWithdrawnAmount).to.eq(bidPricePerSecond * fullDuration); + expect(await sessionRouter.getProvidersTotalClaimed()).to.eq(bidPricePerSecond * fullDuration); + expect((await sessionRouter.getProvider(PROVIDER)).limitPeriodEarned).to.eq(bidPricePerSecond * fullDuration); + + const providerBalAfter = await token.balanceOf(PROVIDER); + expect(providerBalAfter - providerBalBefore).to.eq(bidPricePerSecond * duration); + const fundingBalAfter = await token.balanceOf(FUNDING); + expect(fundingBalBefore - fundingBalAfter).to.eq(bidPricePerSecond * duration); + }); + it('should not claim provider rewards, when provider funds on lock', async () => { + const { sessionId, secondsToDayEnd, openedAt } = await _createSession(); + + await setTime(openedAt + secondsToDayEnd + 1); + const { msg: receiptMsg } = await getReceipt(PROVIDER, sessionId, 0, 0); + const { signature: receiptSig } = await getReceipt(OWNER, sessionId, 0, 0); + await sessionRouter.connect(SECOND).closeSession(receiptMsg, receiptSig); + + let session = await sessionRouter.getSession(sessionId); + const duration = BigInt(secondsToDayEnd); + + const providerBalBefore = await token.balanceOf(PROVIDER); + const fundingBalBefore = await token.balanceOf(FUNDING); + + await setTime(openedAt + secondsToDayEnd + 100); + await sessionRouter.connect(PROVIDER).claimForProvider(sessionId); + session = await sessionRouter.getSession(sessionId); + + expect(session.providerWithdrawnAmount).to.eq(bidPricePerSecond * duration); + expect(await sessionRouter.getProvidersTotalClaimed()).to.eq(bidPricePerSecond * duration); + expect((await sessionRouter.getProvider(PROVIDER)).limitPeriodEarned).to.eq(bidPricePerSecond * duration); + + const providerBalAfter = await token.balanceOf(PROVIDER); + expect(providerBalAfter - providerBalBefore).to.eq(0); + const fundingBalAfter = await token.balanceOf(FUNDING); + expect(fundingBalBefore - fundingBalAfter).to.eq(0); + }); it('should claim provider rewards, full', async () => { const { sessionId, openedAt } = await _createSession(); @@ -618,7 +805,7 @@ describe('SessionRouter', () => { await setTime(payoutStart + 10 * DAY); const { msg: msg1, signature: sig1 } = await getProviderApproval(PROVIDER, SECOND, bidId); - await sessionRouter.connect(SECOND).openSession(wei(50), false, msg1, sig1); + await sessionRouter.connect(SECOND).openSession(SECOND, wei(50), false, msg1, sig1); const sessionId1 = await sessionRouter.getSessionId(SECOND, PROVIDER, bidId, 0); await setTime(payoutStart + 20 * DAY); @@ -626,7 +813,7 @@ describe('SessionRouter', () => { await setTime(payoutStart + 30 * DAY); const { msg: msg2, signature: sig2 } = await getProviderApproval(PROVIDER, SECOND, bidId); - await sessionRouter.connect(SECOND).openSession(wei(50), false, msg2, sig2); + await sessionRouter.connect(SECOND).openSession(SECOND, wei(50), false, msg2, sig2); const sessionId2 = await sessionRouter.getSessionId(SECOND, PROVIDER, bidId, 1); await setTime(payoutStart + 40 * DAY); @@ -659,7 +846,7 @@ describe('SessionRouter', () => { await expect(sessionRouter.connect(SECOND).claimForProvider(sessionId)).to.be.revertedWithCustomError( sessionRouter, - 'OwnableUnauthorizedAccount', + 'InsufficientRightsForOperation', ); }); }); @@ -670,7 +857,7 @@ describe('SessionRouter', () => { await setTime(openedAt + 1 * DAY); const { msg, signature } = await getProviderApproval(PROVIDER, SECOND, bidId); - await sessionRouter.connect(SECOND).openSession(wei(50), false, msg, signature); + await sessionRouter.connect(SECOND).openSession(SECOND, wei(50), false, msg, signature); const sessionId1 = await sessionRouter.getSessionId(SECOND, PROVIDER, bidId, 0); await setTime(openedAt + 1 * DAY + 100); @@ -681,7 +868,38 @@ describe('SessionRouter', () => { const contractBalBefore = await token.balanceOf(sessionRouter); await setTime(openedAt + 3 * DAY + 2); - await sessionRouter.connect(SECOND).withdrawUserStakes(1); + await sessionRouter.connect(SECOND).withdrawUserStakes(SECOND, 1); + + const stakesOnHold = await sessionRouter.getUserStakesOnHold(SECOND, 1); + expect(stakesOnHold[0]).to.eq(0); + expect(stakesOnHold[1]).to.eq(0); + + const userBalAfter = await token.balanceOf(SECOND); + expect(userBalAfter - userBalBefore).to.greaterThan(0); + const contractBalAfter = await token.balanceOf(sessionRouter); + expect(contractBalBefore - contractBalAfter).to.greaterThan(0); + }); + it('should withdraw the user stake on hold from the delegatee address, one entity', async () => { + const openedAt = payoutStart + (payoutStart % DAY) + 10 * DAY - 201; + + await setTime(openedAt + 1 * DAY); + const { msg, signature } = await getProviderApproval(PROVIDER, SECOND, bidId); + await sessionRouter.connect(SECOND).openSession(SECOND, wei(50), false, msg, signature); + const sessionId1 = await sessionRouter.getSessionId(SECOND, PROVIDER, bidId, 0); + + await setTime(openedAt + 1 * DAY + 100); + const { msg: receiptMsg, signature: receiptSig } = await getReceipt(PROVIDER, sessionId1, 0, 0); + await sessionRouter.connect(SECOND).closeSession(receiptMsg, receiptSig); + + const userBalBefore = await token.balanceOf(SECOND); + const contractBalBefore = await token.balanceOf(sessionRouter); + + await delegateRegistry + .connect(SECOND) + .delegateContract(OWNER, providerRegistry, await providerRegistry.DELEGATION_RULES_SESSION(), true); + + await setTime(openedAt + 3 * DAY + 2); + await sessionRouter.connect(OWNER).withdrawUserStakes(SECOND, 1); const stakesOnHold = await sessionRouter.getUserStakesOnHold(SECOND, 1); expect(stakesOnHold[0]).to.eq(0); @@ -697,7 +915,7 @@ describe('SessionRouter', () => { await setTime(openedAt + 1 * DAY); const { msg: msg1, signature: sig1 } = await getProviderApproval(PROVIDER, SECOND, bidId); - await sessionRouter.connect(SECOND).openSession(wei(50), false, msg1, sig1); + await sessionRouter.connect(SECOND).openSession(SECOND, wei(50), false, msg1, sig1); const sessionId1 = await sessionRouter.getSessionId(SECOND, PROVIDER, bidId, 0); await setTime(openedAt + 1 * DAY + 500); @@ -706,7 +924,7 @@ describe('SessionRouter', () => { await setTime(openedAt + 3 * DAY); const { msg: msg2, signature: sig2 } = await getProviderApproval(PROVIDER, SECOND, bidId); - await sessionRouter.connect(SECOND).openSession(wei(50), false, msg2, sig2); + await sessionRouter.connect(SECOND).openSession(SECOND, wei(50), false, msg2, sig2); const sessionId2 = await sessionRouter.getSessionId(SECOND, PROVIDER, bidId, 1); await setTime(openedAt + 3 * DAY + 500); @@ -721,7 +939,7 @@ describe('SessionRouter', () => { const contractBalBefore = await token.balanceOf(sessionRouter); await setTime(openedAt + 4 * DAY); - await sessionRouter.connect(SECOND).withdrawUserStakes(20); + await sessionRouter.connect(SECOND).withdrawUserStakes(SECOND, 20); const userBalAfter = await token.balanceOf(SECOND); expect(userBalAfter - userBalBefore).to.eq(stakesOnHold[0]); @@ -734,7 +952,7 @@ describe('SessionRouter', () => { // Open and close session #1 await setTime(openedAt + 1 * DAY); const { msg: msg1, signature: sig1 } = await getProviderApproval(PROVIDER, SECOND, bidId); - await sessionRouter.connect(SECOND).openSession(wei(50), false, msg1, sig1); + await sessionRouter.connect(SECOND).openSession(SECOND, wei(50), false, msg1, sig1); const sessionId1 = await sessionRouter.getSessionId(SECOND, PROVIDER, bidId, 0); await setTime(openedAt + 1 * DAY + 500); @@ -747,7 +965,7 @@ describe('SessionRouter', () => { // Open and close session #2 await setTime(openedAt + 3 * DAY); const { msg: msg2, signature: sig2 } = await getProviderApproval(PROVIDER, SECOND, bidId); - await sessionRouter.connect(SECOND).openSession(wei(50), false, msg2, sig2); + await sessionRouter.connect(SECOND).openSession(SECOND, wei(50), false, msg2, sig2); const sessionId2 = await sessionRouter.getSessionId(SECOND, PROVIDER, bidId, 1); await setTime(openedAt + 3 * DAY + 500); @@ -760,7 +978,7 @@ describe('SessionRouter', () => { // Open and close session #3 await setTime(openedAt + 5 * DAY); const { msg: msg3, signature: sig3 } = await getProviderApproval(PROVIDER, SECOND, bidId); - await sessionRouter.connect(SECOND).openSession(wei(50), false, msg3, sig3); + await sessionRouter.connect(SECOND).openSession(SECOND, wei(50), false, msg3, sig3); const sessionId3 = await sessionRouter.getSessionId(SECOND, PROVIDER, bidId, 2); await setTime(openedAt + 5 * DAY + 500); @@ -779,7 +997,7 @@ describe('SessionRouter', () => { let userBalBefore = await token.balanceOf(SECOND); let contractBalBefore = await token.balanceOf(sessionRouter); - await sessionRouter.connect(SECOND).withdrawUserStakes(1); + await sessionRouter.connect(SECOND).withdrawUserStakes(SECOND, 1); let userBalAfter = await token.balanceOf(SECOND); expect(userBalAfter - userBalBefore).to.eq(onHoldAfterSession3); @@ -794,7 +1012,7 @@ describe('SessionRouter', () => { userBalBefore = await token.balanceOf(SECOND); contractBalBefore = await token.balanceOf(sessionRouter); - await sessionRouter.connect(SECOND).withdrawUserStakes(1); + await sessionRouter.connect(SECOND).withdrawUserStakes(SECOND, 1); userBalAfter = await token.balanceOf(SECOND); expect(userBalAfter - userBalBefore).to.eq(onHoldAfterSession2); @@ -809,7 +1027,7 @@ describe('SessionRouter', () => { userBalBefore = await token.balanceOf(SECOND); contractBalBefore = await token.balanceOf(sessionRouter); - await sessionRouter.connect(SECOND).withdrawUserStakes(1); + await sessionRouter.connect(SECOND).withdrawUserStakes(SECOND, 1); userBalAfter = await token.balanceOf(SECOND); expect(userBalAfter - userBalBefore).to.eq(onHoldAfterSession1); @@ -821,7 +1039,7 @@ describe('SessionRouter', () => { await setTime(openedAt + 1 * DAY); const { msg: msg1, signature: sig1 } = await getProviderApproval(PROVIDER, SECOND, bidId); - await sessionRouter.connect(SECOND).openSession(wei(50), false, msg1, sig1); + await sessionRouter.connect(SECOND).openSession(SECOND, wei(50), false, msg1, sig1); const sessionId1 = await sessionRouter.getSessionId(SECOND, PROVIDER, bidId, 0); await setTime(openedAt + 1 * DAY + 500); @@ -830,7 +1048,7 @@ describe('SessionRouter', () => { await setTime(openedAt + 3 * DAY); const { msg: msg2, signature: sig2 } = await getProviderApproval(PROVIDER, SECOND, bidId); - await sessionRouter.connect(SECOND).openSession(wei(50), false, msg2, sig2); + await sessionRouter.connect(SECOND).openSession(SECOND, wei(50), false, msg2, sig2); const sessionId2 = await sessionRouter.getSessionId(SECOND, PROVIDER, bidId, 1); await setTime(openedAt + 3 * DAY + 500); @@ -845,7 +1063,7 @@ describe('SessionRouter', () => { const userBalBefore = await token.balanceOf(SECOND); const contractBalBefore = await token.balanceOf(sessionRouter); - await sessionRouter.connect(SECOND).withdrawUserStakes(20); + await sessionRouter.connect(SECOND).withdrawUserStakes(SECOND, 20); const userBalAfter = await token.balanceOf(SECOND); expect(userBalAfter - userBalBefore).to.eq(stakesOnHold[0]); @@ -857,11 +1075,11 @@ describe('SessionRouter', () => { await setTime(openedAt + 1 * DAY); const { msg: msg1, signature: sig1 } = await getProviderApproval(PROVIDER, SECOND, bidId); - await sessionRouter.connect(SECOND).openSession(wei(50), false, msg1, sig1); + await sessionRouter.connect(SECOND).openSession(SECOND, wei(50), false, msg1, sig1); const sessionId1 = await sessionRouter.getSessionId(SECOND, PROVIDER, bidId, 0); const { msg: msg2, signature: sig2 } = await getProviderApproval(PROVIDER, SECOND, bidId); - await sessionRouter.connect(SECOND).openSession(wei(50), false, msg2, sig2); + await sessionRouter.connect(SECOND).openSession(SECOND, wei(50), false, msg2, sig2); const sessionId2 = await sessionRouter.getSessionId(SECOND, PROVIDER, bidId, 1); await setTime(openedAt + 1 * DAY + 500); @@ -872,13 +1090,13 @@ describe('SessionRouter', () => { const { msg: receiptMsg2, signature: receiptSig2 } = await getReceipt(PROVIDER, sessionId2, 0, 0); await sessionRouter.connect(SECOND).closeSession(receiptMsg2, receiptSig2); - await expect(sessionRouter.connect(SECOND).withdrawUserStakes(20)).to.be.revertedWithCustomError( + await expect(sessionRouter.connect(SECOND).withdrawUserStakes(SECOND, 20)).to.be.revertedWithCustomError( sessionRouter, 'SessionUserAmountToWithdrawIsZero', ); }); it('should throw error when amount of itterations are zero', async () => { - await expect(sessionRouter.connect(SECOND).withdrawUserStakes(0)).to.be.revertedWithCustomError( + await expect(sessionRouter.connect(SECOND).withdrawUserStakes(SECOND, 0)).to.be.revertedWithCustomError( sessionRouter, 'SessionUserAmountToWithdrawIsZero', ); @@ -897,7 +1115,7 @@ describe('SessionRouter', () => { await setTime(openedAt); const { msg, signature } = await getProviderApproval(PROVIDER, SECOND, bidId); - await sessionRouter.connect(SECOND).openSession(wei(50), isDirectPaymentFromUser, msg, signature); + await sessionRouter.connect(SECOND).openSession(SECOND, wei(50), isDirectPaymentFromUser, msg, signature); return { sessionId: await sessionRouter.getSessionId(SECOND, PROVIDER, bidId, 0), diff --git a/smart-contracts/test/helpers/deployers/diamond/facets/delegation.ts b/smart-contracts/test/helpers/deployers/diamond/facets/delegation.ts new file mode 100644 index 00000000..f54cb91d --- /dev/null +++ b/smart-contracts/test/helpers/deployers/diamond/facets/delegation.ts @@ -0,0 +1,31 @@ +import { Fragment } from 'ethers'; +import { ethers } from 'hardhat'; + +import { Delegation, IDelegation__factory, LumerinDiamond } from '@/generated-types/ethers'; +import { DelegateRegistry } from '@/generated-types/ethers/contracts/mock/delegate-registry/src'; +import { FacetAction } from '@/test/helpers/deployers/diamond/lumerin-diamond'; + +export const deployFacetDelegation = async ( + diamond: LumerinDiamond, + delegateRegistry: DelegateRegistry, +): Promise => { + let facet: Delegation; + + const factory = await ethers.getContractFactory('Delegation'); + facet = await factory.deploy(); + + await diamond['diamondCut((address,uint8,bytes4[])[])']([ + { + facetAddress: facet, + action: FacetAction.Add, + functionSelectors: IDelegation__factory.createInterface() + .fragments.filter(Fragment.isFunction) + .map((f) => f.selector), + }, + ]); + + facet = facet.attach(diamond.target) as Delegation; + await facet.__Delegation_init(delegateRegistry); + + return facet; +}; diff --git a/smart-contracts/test/helpers/deployers/diamond/index.ts b/smart-contracts/test/helpers/deployers/diamond/index.ts index 36c74670..53aedb86 100644 --- a/smart-contracts/test/helpers/deployers/diamond/index.ts +++ b/smart-contracts/test/helpers/deployers/diamond/index.ts @@ -1,3 +1,4 @@ +export * from './facets/delegation'; export * from './facets/model-registry'; export * from './facets/marketplace'; export * from './facets/provider-registry'; diff --git a/smart-contracts/test/helpers/deployers/mock/delegate-registry/delegate-registry.ts b/smart-contracts/test/helpers/deployers/mock/delegate-registry/delegate-registry.ts new file mode 100644 index 00000000..9fee3f6a --- /dev/null +++ b/smart-contracts/test/helpers/deployers/mock/delegate-registry/delegate-registry.ts @@ -0,0 +1,10 @@ +import { ethers } from 'hardhat'; + +import { DelegateRegistry } from '@/generated-types/ethers'; + +export const deployDelegateRegistry = async (): Promise => { + const factory = await ethers.getContractFactory('DelegateRegistry'); + const contract = await factory.deploy(); + + return contract; +}; diff --git a/smart-contracts/test/helpers/deployers/mock/index.ts b/smart-contracts/test/helpers/deployers/mock/index.ts index cfcb186e..e63b68ea 100644 --- a/smart-contracts/test/helpers/deployers/mock/index.ts +++ b/smart-contracts/test/helpers/deployers/mock/index.ts @@ -1 +1,2 @@ +export * from './delegate-registry/delegate-registry'; export * from './tokens/morpheus-token'; diff --git a/ui-core/package.json b/ui-core/package.json index f6f33a9c..53f2bd93 100644 --- a/ui-core/package.json +++ b/ui-core/package.json @@ -3,8 +3,8 @@ "version": "1.0.90", "author": { "name": "Lumerin", - "email": "developer@lumerin.io", - "url": "https://lumerin.io" + "email": "developer@mor.org", + "url": "https://mor.org" }, "description": "Core logic to develop a Lumerin wallet", "keywords": [ diff --git a/ui-desktop/.env.example b/ui-desktop/.env.example index fecc58ca..8f68da8d 100644 --- a/ui-desktop/.env.example +++ b/ui-desktop/.env.example @@ -1,15 +1,32 @@ +# This file is used to set the environment variables for the cicd workflow +# Contract and Token current as of 11/5/2024 + +# MAINNET VALUES +CHAIN_ID=42161 +DIAMOND_ADDRESS=0xDE819AaEE474626E3f34Ef0263373357e5a6C71b +DISPLAY_NAME=Arbitrum +EXPLORER_URL=https://arbiscan.io/tx/{{hash}} +TOKEN_ADDRESS=0x092bAaDB7DEf4C3981454dD9c0A0D7FF07bCFc86 +DEV_TOOLS=false +SYMBOL_ETH=ETH +SYMBOL_COIN=MOR + +# TESTNET VALUES +#CHAIN_ID=421614 +#DIAMOND_ADDRESS=0xb8C55cD613af947E73E262F0d3C54b7211Af16CF +#DISPLAY_NAME=Sepolia Arbitrum +#EXPLORER_URL=https://sepolia.arbiscan.io/tx/{{hash}} +#TOKEN_ADDRESS=0x34a285a1b1c166420df5b6630132542923b5b27e +#DEV_TOOLS=true +#SYMBOL_ETH=ETH +#SYMBOL_COIN=MOR + +# COMMON BYPASS_AUTH=false -CHAIN_ID=421614 DEBUG=false DEFAULT_SELLER_CURRENCY=BTC -DEV_TOOLS=true -DIAMOND_ADDRESS=0x8e19288d908b2d9f8d7c539c74c899808ac3de45 -DISPLAY_NAME=Sepolia Arbitrum -EXPLORER_URL=https://sepolia.arbiscan.io/tx/{{hash}} IGNORE_DEBUG_LOGS=false PROXY_WEB_DEFAULT_PORT=8082 SENTRY_DSN= -SYMBOL_ETH=saETH -SYMBOL_LMR=saMOR -TOKEN_ADDRESS=0xc1664f994fd3991f98ae944bc16b9aed673ef5fd TRACKING_ID= +FAILOVER_ENABLED= diff --git a/ui-desktop/README.md b/ui-desktop/README.md index b9469b53..5db56562 100644 --- a/ui-desktop/README.md +++ b/ui-desktop/README.md @@ -1,4 +1,4 @@ -# ui-desktop +# MorpheusUI An Electron application with React and TypeScript diff --git a/ui-desktop/buildResources/icon.icns b/ui-desktop/buildResources/icon.icns new file mode 100644 index 00000000..7061b439 Binary files /dev/null and b/ui-desktop/buildResources/icon.icns differ diff --git a/ui-desktop/buildResources/icon.png b/ui-desktop/buildResources/icon.png new file mode 100644 index 00000000..93dee361 Binary files /dev/null and b/ui-desktop/buildResources/icon.png differ diff --git a/ui-desktop/electron-builder.yml b/ui-desktop/electron-builder.yml index fc105a19..1e158443 100644 --- a/ui-desktop/electron-builder.yml +++ b/ui-desktop/electron-builder.yml @@ -1,7 +1,7 @@ -appId: com.electron.app -productName: ui-desktop +appId: com.electron.morpheus-ui +productName: MorpheusUI directories: - buildResources: build + buildResources: buildResources files: - '!**/.vscode/*' - '!src/*' @@ -12,34 +12,33 @@ files: asarUnpack: - resources/** win: - executableName: ui-desktop -nsis: - artifactName: ${name}-${version}-setup.${ext} - shortcutName: ${productName} - uninstallDisplayName: ${productName} - createDesktopShortcut: always + executableName: morpheus-ui + target: + - portable +portable: + artifactName: ${name}-${version}-${arch}-${os}.${ext} mac: - entitlementsInherit: build/entitlements.mac.plist + executableName: MorpheusUI + entitlementsInherit: buildResources/entitlements.mac.plist extendInfo: - NSCameraUsageDescription: Application requests access to the device's camera. - NSMicrophoneUsageDescription: Application requests access to the device's microphone. - NSDocumentsFolderUsageDescription: Application requests access to the user's Documents folder. - NSDownloadsFolderUsageDescription: Application requests access to the user's Downloads folder. notarize: false -dmg: - artifactName: ${name}-${version}.${ext} + artifactName: ${name}-${version}-${arch}-${os}.${ext} linux: target: - AppImage - - snap - deb - maintainer: electronjs.org + maintainer: mor.org category: Utility -appImage: - artifactName: ${name}-${version}.${ext} + artifactName: ${name}-${version}-${arch}-${os}.${ext} +# appImage: +# artifactName: ${name}-${version}-${arch}-${os}.${ext} npmRebuild: false publish: provider: generic url: https://example.com/auto-updates electronDownload: - mirror: https://npmmirror.com/mirrors/electron/ \ No newline at end of file + mirror: https://npmmirror.com/mirrors/electron/ diff --git a/ui-desktop/electron.vite.config.ts b/ui-desktop/electron.vite.config.ts index ae2ccca6..17971b3e 100644 --- a/ui-desktop/electron.vite.config.ts +++ b/ui-desktop/electron.vite.config.ts @@ -17,9 +17,10 @@ const envsToInject = [ 'PROXY_WEB_DEFAULT_PORT', 'SENTRY_DSN', 'SYMBOL_ETH', - 'SYMBOL_LMR', + 'SYMBOL_COIN', 'TOKEN_ADDRESS', - 'TRACKING_ID' + 'TRACKING_ID', + 'FAILOVER_ENABLED' ] as const export default defineConfig(({ /*command,*/ mode }) => { diff --git a/ui-desktop/package.json b/ui-desktop/package.json index 85503825..c2a98e01 100644 --- a/ui-desktop/package.json +++ b/ui-desktop/package.json @@ -1,10 +1,10 @@ { - "name": "ui-desktop", + "name": "morpheus-ui", "version": "1.0.0", - "description": "An Electron application with React and TypeScript", + "description": "The Morpheus Decentralized AI Desktop App", "main": "./out/main/index.mjs", - "author": "example.com", - "homepage": "https://electron-vite.org", + "author": "mor.org", + "homepage": "https://mor.org", "scripts": { "format": "prettier --write .", "lint": "eslint . --ext .js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --fix", @@ -58,7 +58,7 @@ "react-modern-drawer": "^1.2.2", "react-motion": "^0.5.2", "react-redux": "^9.1.0", - "react-router-dom": "4.3.1", + "react-router-dom": "^7.0.2", "react-select": "^5.8.0", "react-simple-image-viewer": "^1.2.2", "react-syntax-highlighter": "^15.5.0", @@ -81,8 +81,8 @@ "@types/react-dom": "^18.2.18", "@vitejs/plugin-react": "^4.2.1", "electron": "^28.2.0", - "electron-builder": "^24.9.1", - "electron-vite": "^2.0.0", + "electron-builder": "^25.1.8", + "electron-vite": "^2.3.0", "eslint": "^8.56.0", "eslint-plugin-react": "^7.33.2", "patch-package": "^8.0.0", diff --git a/ui-desktop/public/.eslintrc.json.bak b/ui-desktop/public/.eslintrc.json.bak deleted file mode 100644 index 79e94c7d..00000000 --- a/ui-desktop/public/.eslintrc.json.bak +++ /dev/null @@ -1,20 +0,0 @@ -{ - "env": { - "node": true - }, - "extends": [ - "bloq", - "prettier" - ], - "parserOptions": { - "ecmaFeatures": { - "experimentalObjectRestSpread": false, - "jsx": false - }, - "ecmaVersion": 2017 - }, - "root": true, - "rules": { - "promise/catch-or-return": "error" - } -} diff --git a/ui-desktop/public/favicon.ico b/ui-desktop/public/favicon.ico deleted file mode 100644 index a11777cc..00000000 Binary files a/ui-desktop/public/favicon.ico and /dev/null differ diff --git a/ui-desktop/public/fonts/montserrat-v25-latin/montserrat-v25-latin-100.woff2 b/ui-desktop/public/fonts/montserrat-v25-latin/montserrat-v25-latin-100.woff2 deleted file mode 100644 index 94871cdf..00000000 Binary files a/ui-desktop/public/fonts/montserrat-v25-latin/montserrat-v25-latin-100.woff2 and /dev/null differ diff --git a/ui-desktop/public/fonts/montserrat-v25-latin/montserrat-v25-latin-200.woff2 b/ui-desktop/public/fonts/montserrat-v25-latin/montserrat-v25-latin-200.woff2 deleted file mode 100644 index 1e310eb0..00000000 Binary files a/ui-desktop/public/fonts/montserrat-v25-latin/montserrat-v25-latin-200.woff2 and /dev/null differ diff --git a/ui-desktop/public/fonts/montserrat-v25-latin/montserrat-v25-latin-300.woff2 b/ui-desktop/public/fonts/montserrat-v25-latin/montserrat-v25-latin-300.woff2 deleted file mode 100644 index a0d3d1fd..00000000 Binary files a/ui-desktop/public/fonts/montserrat-v25-latin/montserrat-v25-latin-300.woff2 and /dev/null differ diff --git a/ui-desktop/public/fonts/montserrat-v25-latin/montserrat-v25-latin-500.woff2 b/ui-desktop/public/fonts/montserrat-v25-latin/montserrat-v25-latin-500.woff2 deleted file mode 100644 index 1dfcab6a..00000000 Binary files a/ui-desktop/public/fonts/montserrat-v25-latin/montserrat-v25-latin-500.woff2 and /dev/null differ diff --git a/ui-desktop/public/fonts/montserrat-v25-latin/montserrat-v25-latin-600.woff2 b/ui-desktop/public/fonts/montserrat-v25-latin/montserrat-v25-latin-600.woff2 deleted file mode 100644 index 7d9b42d6..00000000 Binary files a/ui-desktop/public/fonts/montserrat-v25-latin/montserrat-v25-latin-600.woff2 and /dev/null differ diff --git a/ui-desktop/public/fonts/montserrat-v25-latin/montserrat-v25-latin-700.woff2 b/ui-desktop/public/fonts/montserrat-v25-latin/montserrat-v25-latin-700.woff2 deleted file mode 100644 index a7e1118f..00000000 Binary files a/ui-desktop/public/fonts/montserrat-v25-latin/montserrat-v25-latin-700.woff2 and /dev/null differ diff --git a/ui-desktop/public/fonts/montserrat-v25-latin/montserrat-v25-latin-800.woff2 b/ui-desktop/public/fonts/montserrat-v25-latin/montserrat-v25-latin-800.woff2 deleted file mode 100644 index 1ce621e8..00000000 Binary files a/ui-desktop/public/fonts/montserrat-v25-latin/montserrat-v25-latin-800.woff2 and /dev/null differ diff --git a/ui-desktop/public/fonts/montserrat-v25-latin/montserrat-v25-latin-900.woff2 b/ui-desktop/public/fonts/montserrat-v25-latin/montserrat-v25-latin-900.woff2 deleted file mode 100644 index e73b95af..00000000 Binary files a/ui-desktop/public/fonts/montserrat-v25-latin/montserrat-v25-latin-900.woff2 and /dev/null differ diff --git a/ui-desktop/public/fonts/montserrat-v25-latin/montserrat-v25-latin-italic.woff2 b/ui-desktop/public/fonts/montserrat-v25-latin/montserrat-v25-latin-italic.woff2 deleted file mode 100644 index 9ce7f917..00000000 Binary files a/ui-desktop/public/fonts/montserrat-v25-latin/montserrat-v25-latin-italic.woff2 and /dev/null differ diff --git a/ui-desktop/public/fonts/montserrat-v25-latin/montserrat-v25-latin-regular.woff2 b/ui-desktop/public/fonts/montserrat-v25-latin/montserrat-v25-latin-regular.woff2 deleted file mode 100644 index e04ffc26..00000000 Binary files a/ui-desktop/public/fonts/montserrat-v25-latin/montserrat-v25-latin-regular.woff2 and /dev/null differ diff --git a/ui-desktop/public/images/MainBackground.png b/ui-desktop/public/images/MainBackground.png deleted file mode 100644 index 7e4617d0..00000000 Binary files a/ui-desktop/public/images/MainBackground.png and /dev/null differ diff --git a/ui-desktop/public/images/ant-miner.jpg b/ui-desktop/public/images/ant-miner.jpg deleted file mode 100644 index 1d8722cb..00000000 Binary files a/ui-desktop/public/images/ant-miner.jpg and /dev/null differ diff --git a/ui-desktop/public/images/banner.png b/ui-desktop/public/images/banner.png deleted file mode 100644 index 08556f68..00000000 Binary files a/ui-desktop/public/images/banner.png and /dev/null differ diff --git a/ui-desktop/public/images/banner.svg b/ui-desktop/public/images/banner.svg deleted file mode 100644 index 724e4f13..00000000 --- a/ui-desktop/public/images/banner.svg +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - - - - - - - - - - - - diff --git a/ui-desktop/public/images/pattern-light.png b/ui-desktop/public/images/pattern-light.png deleted file mode 100644 index b3f25d6b..00000000 Binary files a/ui-desktop/public/images/pattern-light.png and /dev/null differ diff --git a/ui-desktop/public/images/pattern.png b/ui-desktop/public/images/pattern.png deleted file mode 100644 index c34c59e4..00000000 Binary files a/ui-desktop/public/images/pattern.png and /dev/null differ diff --git a/ui-desktop/public/index.html b/ui-desktop/public/index.html deleted file mode 100644 index 2be0b0e9..00000000 --- a/ui-desktop/public/index.html +++ /dev/null @@ -1,137 +0,0 @@ - - - - - - - - Lumerin Wallet - - - - -
- - - \ No newline at end of file diff --git a/ui-desktop/public/logger.js b/ui-desktop/public/logger.js deleted file mode 100644 index ef00e446..00000000 --- a/ui-desktop/public/logger.js +++ /dev/null @@ -1,42 +0,0 @@ -'use strict' - -const chalk = require('chalk') -const logger = require('electron-log') -const stringify = require('json-stringify-safe') -const config = require('./config') - -logger.transports.file.appName = 'lumerin-wallet-desktop' - -function getColorLevel(level = '') { - const colors = { - error: 'red', - verbose: 'cyan', - warn: 'yellow', - debug: 'magenta', - silly: 'blue' - } - return colors[level.toString()] || 'green' -} - -logger.transports.console = function ({ date, level, data }) { - const color = getColorLevel(level) - - let meta = '' - if (data.length) { - meta += ' => ' - meta += data.map((d) => (typeof d === 'object' ? stringify(d) : d)).join(', ') - } - - // eslint-disable-next-line no-console - console.log(`${date.toISOString()} - ${chalk[color](level)}:\t${meta}`) -} - -if (config.debug) { - logger.transports.console.level = 'debug' - logger.transports.file.level = 'debug' -} else { - logger.transports.console.level = 'warn' - logger.transports.file.level = 'warn' -} - -export default logger diff --git a/ui-desktop/public/main.jpg b/ui-desktop/public/main.jpg deleted file mode 100644 index ea440789..00000000 Binary files a/ui-desktop/public/main.jpg and /dev/null differ diff --git a/ui-desktop/public/manifest.json b/ui-desktop/public/manifest.json deleted file mode 100644 index ef19ec24..00000000 --- a/ui-desktop/public/manifest.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "short_name": "React App", - "name": "Create React App Sample", - "icons": [ - { - "src": "favicon.ico", - "sizes": "64x64 32x32 24x24 16x16", - "type": "image/x-icon" - } - ], - "start_url": "./index.html", - "display": "standalone", - "theme_color": "#000000", - "background_color": "#ffffff" -} diff --git a/ui-desktop/resources/icon.png b/ui-desktop/resources/icon.png deleted file mode 100644 index cf9e8b2c..00000000 Binary files a/ui-desktop/resources/icon.png and /dev/null differ diff --git a/ui-desktop/src/main/config/index.ts b/ui-desktop/src/main/config/index.ts index 4c56559c..abdaced7 100644 --- a/ui-desktop/src/main/config/index.ts +++ b/ui-desktop/src/main/config/index.ts @@ -10,7 +10,7 @@ const config = { explorerUrl: process.env.EXPLORER_URL, localProxyRouterUrl: `http://localhost:${process.env.PROXY_WEB_DEFAULT_PORT || 8082}`, mainTokenAddress: process.env.TOKEN_ADDRESS, - symbol: process.env.SYMBOL_LMR || 'MOR', + symbol: process.env.SYMBOL_COIN || 'MOR', symbolEth: process.env.SYMBOL_ETH || 'ETH' }, dbAutocompactionInterval: 30000, @@ -18,7 +18,8 @@ const config = { devTools: process.env.DEV_TOOLS === 'true', sentryDsn: process.env.SENTRY_DSN, statePersistanceDebounce: 2000, - trackingId: process.env.TRACKING_ID + trackingId: process.env.TRACKING_ID, + isFailoverEnabled: process.env.FAILOVER_ENABLED ? process.env.FAILOVER_ENABLED === 'true' : true } export default config diff --git a/ui-desktop/src/main/index.ts b/ui-desktop/src/main/index.ts index 2f41069f..e544e360 100644 --- a/ui-desktop/src/main/index.ts +++ b/ui-desktop/src/main/index.ts @@ -53,6 +53,7 @@ errorHandler({ logger: logger.error }) // initialization and is ready to create browser windows. // Some APIs can only be used after this event occurs. app.whenReady().then(() => { + app.setName("morpheus"); // Set app user model id for windows electronApp.setAppUserModelId('com.electron') diff --git a/ui-desktop/src/main/menu.js b/ui-desktop/src/main/menu.js index a3ef642e..e2ad8cc9 100644 --- a/ui-desktop/src/main/menu.js +++ b/ui-desktop/src/main/menu.js @@ -1,7 +1,7 @@ 'use strict'; const { app, shell, Menu } = require('electron'); -const APP_NAME = 'Lumerin Wallet'; +const APP_NAME = 'Morpheus Wallet'; const template = [ { @@ -56,7 +56,7 @@ const template = [ { label: 'Learn More', click () { - return shell.openExternal('https://lumerin.io') + return shell.openExternal('https://mor.org') } } ] diff --git a/ui-desktop/src/main/src/client/apiGateway.js b/ui-desktop/src/main/src/client/apiGateway.js index e438e766..dda44599 100644 --- a/ui-desktop/src/main/src/client/apiGateway.js +++ b/ui-desktop/src/main/src/client/apiGateway.js @@ -62,9 +62,9 @@ const sendMor = async (to, amount) => { } } -const getTransactions = async (page = 1, size = 15) => { +const getTransactions = async (payload) => { try { - const path = `${config.chain.localProxyRouterUrl}/blockchain/transactions?page=${page}&limit=${size}` + const path = `${config.chain.localProxyRouterUrl}/blockchain/transactions?page=${payload.page}&limit=${payload.pageSize}` const response = await fetch(path); const data = await response.json(); return data.transactions; @@ -114,6 +114,137 @@ const getTokenSupply = async () => { } } +/** + * + * @returns {{ + * title: string, + * chatId: string[] + * }} + */ +const getChatHistoryTitles = async () => { + try { + const path = `${config.chain.localProxyRouterUrl}/v1/chats`; + const response = await fetch(path); + const body = await response.json(); + return body; + } + catch (e) { + console.log("Error", e) + return null; + } +} + +/** + * @typedef ChatHistory + * @property {string} title + * @property {string} modelId + * @property {string} sessionId + * @property {ChatMessage[]} messages + */ + +/** + * @typedef ChatMessage + * @property {string} response + * @property {string} prompt + * @property {number} promptAt + * @property {number} responseAt + */ + +/** + * @typedef ChatPrompt + * @property {string} model + * @property {{ + * role: string, + * content: string + * }[]} messages + */ + +/** + * @param {string} chatId + * @returns {Promise} +*/ +const getChatHistory = async (chatId) => { + try { + const path = `${config.chain.localProxyRouterUrl}/v1/chats/${chatId}`; + const response = await fetch(path); + const body = await response.json(); + return body; + } + catch (e) { + console.log("Error", e) + return null; + } +} + +/** + * @param {string} chatId + * @returns {Promise} +*/ +const deleteChatHistory = async (chatId) => { + try { + const path = `${config.chain.localProxyRouterUrl}/v1/chats/${chatId}`; + const response = await fetch(path, { + method: "DELETE", + }); + const body = await response.json(); + return body.result; + } + catch (e) { + console.log("Error", e) + return false; + } + } + + /** + * @param {string} chatId + * @param {string} title + * @returns {Promise} +*/ +const updateChatHistoryTitle = async ({ id, title}) => { + try { + const path = `${config.chain.localProxyRouterUrl}/v1/chats/${id}`; + const response = await fetch(path, { + method: "POST", + body: JSON.stringify({ title }), + }); + const body = await response.json(); + return body.result; + } + catch (e) { + console.log("Error", e) + return false; + } + } + + /** + * @param {string} address + * @param {string} endpoint + * @returns {Promise} +*/ +const checkProviderConnectivity = async ({ address, endpoint}) => { + try { + const path = `${config.chain.localProxyRouterUrl}/proxy/provider/ping`; + const response = await fetch(path, { + method: "POST", + body: JSON.stringify({ + providerAddr: address, + providerUrl: endpoint + }), + }); + + if(!response.ok) { + return false; + } + + const body = await response.json(); + return !!body.ping; + } + catch (e) { + console.log("checkProviderConnectivity: Error", e) + return false; + } + } + export default { getAllModels, getBalances, @@ -122,5 +253,10 @@ export default { getTransactions, getMorRate, getTodaysBudget, - getTokenSupply + getTokenSupply, + getChatHistoryTitles, + getChatHistory, + updateChatHistoryTitle, + deleteChatHistory, + checkProviderConnectivity } \ No newline at end of file diff --git a/ui-desktop/src/main/src/client/handlers/no-core.js b/ui-desktop/src/main/src/client/handlers/no-core.js index a2cbcfdf..03d4bf44 100644 --- a/ui-desktop/src/main/src/client/handlers/no-core.js +++ b/ui-desktop/src/main/src/client/handlers/no-core.js @@ -12,10 +12,12 @@ import { getDefaultCurrencySetting, setDefaultCurrencySetting, getKey, - setKey + setKey, + getFailoverSetting, + setFailoverSetting } from '../settings' import apiGateway from '../apiGateway'; -import chatHistory from '../history/chat-history'; +import config from '../../../config'; const validatePassword = (data) => auth.isValidPassword(data) @@ -95,6 +97,14 @@ const getContractHashrate = async ({ contractId, fromDate }) => { .sort((a, b) => a.timestamp - b.timestamp) } +const isFailoverEnabled = async () => { + const settings = await getFailoverSetting(); + if(!settings) { + return ({ isEnabled: config.isFailoverEnabled }) + } + return settings; +} + const restartWallet = () => restart(1) export default { @@ -115,6 +125,7 @@ export default { setProfitSettings, getAutoAdjustPriceData, setAutoAdjustPriceData, + isFailoverEnabled, + setFailoverSetting, ...apiGateway, - ...chatHistory } diff --git a/ui-desktop/src/main/src/client/handlers/single-core.js b/ui-desktop/src/main/src/client/handlers/single-core.js index 6cc17555..934cae6e 100644 --- a/ui-desktop/src/main/src/client/handlers/single-core.js +++ b/ui-desktop/src/main/src/client/handlers/single-core.js @@ -10,21 +10,21 @@ import { setProxyRouterConfig, cleanupDb, getProxyRouterConfig } from '../settin export const withAuth = (fn) => - (data, { api }) => { - if (typeof data.walletId !== 'string') { - throw new WalletError('walletId is not defined') - } + (data, { api }) => { + if (typeof data.walletId !== 'string') { + throw new WalletError('walletId is not defined') + } - return auth - .isValidPassword(data.password) - .then(() => { - return wallet.getSeed(data.password) - }) - .then((seed, index) => { - return wallet.createPrivateKey(seed, index) - }) - .then((privateKey) => fn(privateKey, data)) - } + return auth + .isValidPassword(data.password) + .then(() => { + return wallet.getSeed(data.password) + }) + .then((seed, index) => { + return wallet.createPrivateKey(seed, index) + }) + .then((privateKey) => fn(privateKey, data)) + } export const createContract = async function (data, { api }) { data.walletId = wallet.getAddress().address @@ -134,74 +134,78 @@ export const setContractDeleteStatus = async function (data, { api }) { )(data, { api }) } -export function createWallet(data, core, isOpen = true) { - const seed = keys.mnemonicToSeedHex(data.mnemonic) - const entropy = keys.mnemonicToEntropy(data.mnemonic) - const walletAddress = wallet.createAddress(seed) - - return Promise.all([ - wallet.setSeed(seed, data.password), - wallet.setEntropy(entropy, data.password), - wallet.setAddress(walletAddress) - ]) - .then(() => core.emitter.emit('create-wallet', { address: walletAddress })) - .then(() => isOpen && openWallet(core, data.password)) -} - export async function openWallet({ emitter }, password) { - const { address } = wallet.getAddress() + const storedAddress = wallet.getAddress() + if(!storedAddress) { + return; + } + + const { address } = storedAddress; emitter.emit('open-wallet', { address, isActive: true }) emitter.emit('open-proxy-router', { password }) } -export const onboardingCompleted = (data, core) => { - setProxyRouterConfig(data.proxyRouterConfig) - return auth - .setPassword(data.password) - .then(() => - createWallet( - { - mnemonic: data.mnemonic, - password: data.password - }, - core, - true - ) - ) - .then(() => { - return wallet.createPrivateKey(wallet.getSeed(data.password)) - }) - .then((privateKey) => { - const { proxyUrl } = data - return fetch(`${proxyUrl}/wallet`, { +export const suggestAddresses = async (mnemonic) => { + const seed = keys.mnemonicToSeedHex(mnemonic); + let results = []; + for (let i = 0; i < 10; i++) { + const walletAddress = wallet.createAddress(seed, i); + results.push(walletAddress); + } + return results; +} + +export const onboardingCompleted = async (data, core) => { + try { + const { proxyUrl } = data; + + if (data.ethNode) { + const ethNodeResult = await fetch(`${proxyUrl}/config/ethNode`, { + method: 'POST', + body: JSON.stringify({ urls: [data.ethNode] }) + }) + + const dataResponse = await ethNodeResult.json(); + if (dataResponse.error) { + return (dataResponse.error) + } + } + + await auth.setPassword(data.password); + + if (data.mnemonic) { + const mnemonicRes = await fetch(`${proxyUrl}/wallet/mnemonic`, { method: 'POST', body: JSON.stringify({ - privateKey + mnemonic: data.mnemonic, + derivationPath: String(data.derivationPath || 0) }) }) - }) - .then(() => true) - .catch((err) => ({ error: new WalletError('Onboarding unable to be completed: ', err) })) -} -export const recoverFromMnemonic = function (data, core) { - if (!auth.isValidPassword(data.password)) { - return null - } + console.log("Set Mnemonic To Wallet", await mnemonicRes.json()); + } + else { + const pKeyResp = await fetch(`${proxyUrl}/wallet/privateKey`, { + method: 'POST', + body: JSON.stringify({ "PrivateKey": String(data.privateKey) }) + }) + console.log("Set Private Key To Wallet", await pKeyResp.json()); + } - wallet.clearWallet() + const walletResp = await fetch(`${proxyUrl}/wallet`); + const walletAddress = (await walletResp.json()).address; - return createWallet( - { - mnemonic: data.mnemonic, - password: data.password - }, - core, - false - ) - .then(noCore.clearCache) - .then((_) => auth.setSessionPassword(data.password)) + console.log("Address Wallet Is", walletAddress); + + await wallet.setSeed(walletAddress, data.password), + await wallet.setAddress(walletAddress) + await core.emitter.emit('create-wallet', { address: walletAddress }) + openWallet(core, data.password) + } + catch (err) { + return ({ error: new WalletError('Onboarding unable to be completed: ', err) }); + } } function onLoginSubmit({ password }, core) { @@ -264,7 +268,7 @@ export const getMarketplaceFee = async function (data, { api }) { return api.contracts.getMarketplaceFee(data) } -export function refreshAllContracts({}, { api }) { +export function refreshAllContracts({ }, { api }) { const walletId = wallet.getAddress().address return api.contracts.refreshContracts(null, walletId) } @@ -310,7 +314,7 @@ export const getAddressAndPrivateKey = async (data, { api }) => { export const refreshProxyRouterConnection = async (data, { api }) => api['proxy-router'].refreshConnectionsStream(data) -export const getLocalIp = async ({}, { api }) => api['proxy-router'].getLocalIp() +export const getLocalIp = async ({ }, { api }) => api['proxy-router'].getLocalIp() export const logout = async (data) => { return cleanupDb() @@ -321,21 +325,6 @@ export const getPoolAddress = async (data) => { return config.buyerDefaultPool || config.defaultPool } -export const hasStoredSecretPhrase = async (data) => { - return wallet.hasEntropy() -} - -export const revealSecretPhrase = async (password) => { - const isValid = await auth.isValidPassword(password) - if (!isValid) { - return { error: new WalletError('Invalid password') } - } - - const entropy = wallet.getEntropy(password) - const mnemonic = keys.entropyToMnemonic(entropy) - return mnemonic -} - export function getPastTransactions({ address, page, pageSize }, { api }) { return api.explorer.getPastCoinTransactions(0, undefined, address, page, pageSize) } @@ -346,10 +335,9 @@ export default { createContract, cancelContract, onboardingCompleted, - recoverFromMnemonic, + suggestAddresses, onLoginSubmit, refreshAllTransactions, - createWallet, openWallet, sendLmr, sendEth, @@ -363,8 +351,6 @@ export default { getLocalIp, getPoolAddress, claimFaucet, - revealSecretPhrase, - hasStoredSecretPhrase, getPastTransactions, setContractDeleteStatus, editContract, diff --git a/ui-desktop/src/main/src/client/history/chat-history.js b/ui-desktop/src/main/src/client/history/chat-history.js deleted file mode 100644 index 87f5e2c0..00000000 --- a/ui-desktop/src/main/src/client/history/chat-history.js +++ /dev/null @@ -1,45 +0,0 @@ -import dbManager from '../database'; - -const getChatHitory = async (sessionId) => { - return await dbManager.getDb().collection('chat').findAsync({ sessionId }); -} - -const saveChatHistory = async ({ sessionId, messages }) => { - const db = dbManager.getDb(); - const collection = db.collection('chat'); - - const items = await getChatHitory(sessionId); - - if (!items.length) { - await collection.insert({ sessionId, messages }); - return; - } - - await collection.update({ sessionId }, { messages, sessionId }, { upsert: true }); -} - -const getTitles = async () => { - return await dbManager.getDb().collection('chat-title').findAsync({}); -} - -const saveTitle = async (data) => { - const db = dbManager.getDb(); - const collection = db.collection('chat-title'); - await collection.insert({ _id: data.sessionId, ...data }); -} - -const deleteTitle = async (id) => { - const db = dbManager.getDb(); - await db.collection('chat-title').remove({ _id: id }) - await db.collection('chat').remove({ sessionId: id }) -} - -const updateChatTitle = async ({ id, title }) => { - const db = dbManager.getDb(); - const collection = db.collection('chat-title'); - const { _id, ...stored } = await collection.findAsync({ _id: id }) - const data = { ...stored[0], title }; - await collection.update({ _id: id }, data); -} - -export default { getChatHitory, saveChatHistory, getTitles, saveTitle, deleteTitle, updateChatTitle }; \ No newline at end of file diff --git a/ui-desktop/src/main/src/client/settings/index.js b/ui-desktop/src/main/src/client/settings/index.js index a8e2a95c..8a2e2b27 100644 --- a/ui-desktop/src/main/src/client/settings/index.js +++ b/ui-desktop/src/main/src/client/settings/index.js @@ -8,6 +8,9 @@ import logger from '../../../logger' import restart from '../electron-restart' import { getDb } from '../database' import defaultSettings from './defaultSettings' + +const FAILOVER_KEY = "user.failover"; + //TODO: make sure default settings works as a static import. it was getting imported every time // it was accessed. if that's necessary, we have to use the async method // import() instead of require() with the new version of node @@ -100,6 +103,10 @@ export const getAppVersion = () => getKey('app.version') export const setAppVersion = (value) => setKey('app.version', value) +export const getFailoverSetting = async() => getKey(FAILOVER_KEY) + +export const setFailoverSetting = async (isEnabled) => setKey(FAILOVER_KEY, { isEnabled }) + export default { getPasswordHash, setPasswordHash, @@ -112,5 +119,7 @@ export default { getKey, setKey, getAppVersion, - setAppVersion + setAppVersion, + getFailoverSetting, + setFailoverSetting } diff --git a/ui-desktop/src/main/src/client/subscriptions/no-core.js b/ui-desktop/src/main/src/client/subscriptions/no-core.js index 54efabb0..f12bf403 100644 --- a/ui-desktop/src/main/src/client/subscriptions/no-core.js +++ b/ui-desktop/src/main/src/client/subscriptions/no-core.js @@ -10,8 +10,6 @@ const listeners = { 'clear-cache': handlers.clearCache, 'handle-client-error': handlers.handleClientSideError, 'get-pool-address': handlers.getPoolAddress, - 'reveal-secret-phrase': handlers.revealSecretPhrase, - 'has-stored-secret-phrase': handlers.hasStoredSecretPhrase, logout: handlers.logout, 'save-proxy-router-settings': handlers.saveProxyRouterSettings, 'get-proxy-router-settings': handlers.getProxyRouterSettings, @@ -32,12 +30,14 @@ const listeners = { "get-todays-budget": handlers.getTodaysBudget, "get-supply": handlers.getTokenSupply, // Chat history - "get-chat-history": handlers.getChatHitory, - "save-chat-history": handlers.saveChatHistory, - "get-chat-titles": handlers.getTitles, - "save-chat-title": handlers.saveTitle, - "update-chat-title": handlers.updateChatTitle, - "delete-chat-title": handlers.deleteTitle + "get-chat-history-titles": handlers.getChatHistoryTitles, + "get-chat-history": handlers.getChatHistory, + "delete-chat-history": handlers.deleteChatHistory, + "update-chat-history-title": handlers.updateChatHistoryTitle, + // Failover + "get-failover-setting": handlers.isFailoverEnabled, + "set-failover-setting": handlers.setFailoverSetting, + "check-provider-connectivity": handlers.checkProviderConnectivity } // Subscribe to messages where no core has to react diff --git a/ui-desktop/src/main/src/client/subscriptions/single-core.js b/ui-desktop/src/main/src/client/subscriptions/single-core.js index fb3ee47c..958df8fb 100644 --- a/ui-desktop/src/main/src/client/subscriptions/single-core.js +++ b/ui-desktop/src/main/src/client/subscriptions/single-core.js @@ -4,8 +4,8 @@ import utils from './utils' export const withCore = (core) => (fn) => (data) => fn(data, core) export const listeners = { - 'recover-from-mnemonic': handlers.recoverFromMnemonic, 'onboarding-completed': handlers.onboardingCompleted, + 'suggest-addresses': handlers.suggestAddresses, 'login-submit': handlers.onLoginSubmit, // 'refresh-all-sockets': handlers.refreshAllSockets, 'refresh-all-contracts': handlers.refreshAllContracts, diff --git a/ui-desktop/src/main/src/client/wallet.js b/ui-desktop/src/main/src/client/wallet.js index 60a89ad5..bac673e1 100644 --- a/ui-desktop/src/main/src/client/wallet.js +++ b/ui-desktop/src/main/src/client/wallet.js @@ -1,6 +1,3 @@ -//@ts-check -'use strict' - const settings = require('electron-settings') const { hdkey } = require('ethereumjs-wallet') @@ -16,22 +13,11 @@ export function getSeed(password) { const encryptedSeed = settings.getSync(`user.wallet.encryptedSeed`) return aes256cbcIv.decrypt(password, encryptedSeed) } - -export const hasEntropy = () => !!settings.getSync(`user.wallet.encryptedEntropy`) - -export function getEntropy(password) { - const encryptedEntropy = settings.getSync(`user.wallet.encryptedEntropy`) - return aes256cbcIv.decrypt(password, encryptedEntropy) -} - export const setAddress = (address) => settings.setSync(`user.wallet.address`, { address }) export const setSeed = (seed, password) => settings.setSync(`user.wallet.encryptedSeed`, aes256cbcIv.encrypt(password, seed)) -export const setEntropy = (entropy, password) => - settings.setSync(`user.wallet.encryptedEntropy`, aes256cbcIv.encrypt(password, entropy)) - export const clearWallet = () => settings.setSync('user.wallet', {}) const getWalletFromSeed = (seed, index = 0) => @@ -41,8 +27,6 @@ const getAddress2 = (seed, index) => getWalletFromSeed(seed, index).getChecksumA const getPrivateKey = (seed, index) => getWalletFromSeed(seed, index).getPrivateKey() -const createPrivateKey = (seed, index) => getWalletFromSeed(seed, index).getPrivateKeyString() - const getAddressAndPrivateKey = (seed, index) => ({ address: getAddress2(seed, index), privateKey: getPrivateKey(seed, index).toString('hex') @@ -54,14 +38,10 @@ export default { getActiveWallet: getWallet, setActiveWallet: setAddress, createAddress: getAddress2, - createPrivateKey, getAddressAndPrivateKey, clearWallet, getWallet, getToken, getSeed, setSeed, - getEntropy, - setEntropy, - hasEntropy } diff --git a/ui-desktop/src/renderer/index.html b/ui-desktop/src/renderer/index.html index 70d4fab7..529ec6d3 100644 --- a/ui-desktop/src/renderer/index.html +++ b/ui-desktop/src/renderer/index.html @@ -27,7 +27,22 @@ html { font-size: 10px; } - + + ::-webkit-scrollbar { + background-color: #03160d; + width: 16px /* 20px / 16px */; + } + + ::-webkit-scrollbar-thumb { + background-color: #20dc8e80; + border: 0.25em /* 4px / 16px */ solid #03160d; + border-radius: 16px /* 20px / 16px #2c2c2c */; + } + + ::-webkit-scrollbar-corner { + background-color: #03160d; + } + body { margin: 0; padding: 0; diff --git a/ui-desktop/src/renderer/src/assets/logo.svg b/ui-desktop/src/renderer/src/assets/logo.svg index 71f3ca24..4180a9e0 100644 --- a/ui-desktop/src/renderer/src/assets/logo.svg +++ b/ui-desktop/src/renderer/src/assets/logo.svg @@ -1,5 +1,5 @@
Staked MOR funds will be reserved to start session
-
Session may last from 5 mins to 24 hours depending on staked funds (min: {(Number(requiredStake.min) / 10 ** 18).toFixed(2)}, max: {(Number(requiredStake.max) / 10 ** 18).toFixed(2)} MOR)
+
Staked funds will be reserved to start session
+
Session may last from 5 mins to 24 hours depending on available balance (min: {(Number(requiredStake.min) / 10 ** 18).toFixed(2)}, max: {(Number(requiredStake.max) / 10 ** 18).toFixed(2)} {props.symbol})
: -
To start session required balance should be at least {(Number(requiredStake.min) / 10 ** 18).toFixed(2)} MOR
+
To start session required balance should be at least {(Number(requiredStake.min) / 10 ** 18).toFixed(2)} {props.symbol}
}
{ handleSubmit(); } }} - value={value} - onChange={ev => setValue(ev.target.value)} + value={promptInput} + onChange={ev => setPromptInput(ev.target.value)} placeholder={isReadonly ? "Session is closed. Chat in ReadOnly Mode" : "Ask me anything..."} minRows={1} maxRows={6} /> { - isReadonly - ? ( - {isSpinning ? : Reopen} - ) - : ( - { - isSpinning ? : - } - ) + isReadonly + ? ( + {isSpinning ? : Reopen} + ) + : ( + { + isSpinning ? : + } + ) } @@ -633,6 +797,8 @@ const Chat = (props) => { { onCreateNewChat(eventData); }} @@ -641,6 +807,42 @@ const Chat = (props) => { ) } +const renderMessage = (message, onOpenImage) => { + if (message.isImageContent) { + return ({ onOpenImage(message.text)} />}) + } + + if (message.isVideoRawContent) { + return () + } + + return ( + + + ) : ( + + {children} + + ) + } + }} + /> + ) +}; + const Message = ({ message, onOpenImage }) => { return (
@@ -650,36 +852,10 @@ const Message = ({ message, onOpenImage }) => {
{message.user} { - message.isImageContent - ? ({ onOpenImage(message.text)} />}) - : ( - - - ) : ( - - {children} - - ) - } - }} - /> - ) + renderMessage(message, onOpenImage) }
) } -export default withRouter(withChatState(Chat)); +export default withChatState(Chat); diff --git a/ui-desktop/src/renderer/src/components/chat/ChatHistory.styles.tsx b/ui-desktop/src/renderer/src/components/chat/ChatHistory.styles.tsx index 138722c3..52440ef1 100644 --- a/ui-desktop/src/renderer/src/components/chat/ChatHistory.styles.tsx +++ b/ui-desktop/src/renderer/src/components/chat/ChatHistory.styles.tsx @@ -6,7 +6,7 @@ export const Container = styled.div` display: none !important; } .history-block { - height: calc(100vh - 100px); + height: calc(100vh - 140px); } .history-scroll-block { overflow-y: auto; @@ -20,6 +20,11 @@ export const Container = styled.div` border-color: ${p => p.theme.colors.morMain} background-color: rgba(0,0,0,0.4); } + + .list-container { + overflow-y: auto; + max-height: calc(100vh - 90px); + } } ` @@ -81,7 +86,7 @@ export const HistoryEntryTitle = styled(FlexSpaceBetween)` export const ModelName = styled.div` text-overflow: ellipsis; - width: 250px; + width: 220px; height: 24px; overflow: hidden; text-wrap: nowrap; @@ -97,6 +102,10 @@ export const Duration = styled.div` ` export const IconsContainer = styled.div` + display: flex; + align-items: center; + justify-content: space-evenly; + width: 100px; svg:hover { opacity: 0.8 } diff --git a/ui-desktop/src/renderer/src/components/chat/ChatHistory.tsx b/ui-desktop/src/renderer/src/components/chat/ChatHistory.tsx index a2f41f3e..81a24bb9 100644 --- a/ui-desktop/src/renderer/src/components/chat/ChatHistory.tsx +++ b/ui-desktop/src/renderer/src/components/chat/ChatHistory.tsx @@ -9,21 +9,22 @@ import Badge from 'react-bootstrap/Badge'; import { SearchContainer } from '../contracts/modals/CreateContractModal.styles'; import * as components from './ChatHistory.styles'; import { useEffect, useState } from "react"; +import { ChatData } from "./interfaces"; interface ChatHistoryProps { open: boolean, - onCloseSession: (string) => void; - onSelectSession: (session) => void; - refreshSessions: () => void; - deleteHistory: (string) => void - onChangeTitle: (data: { id, title }) => Promise; + onCloseSession: (id: string) => void; + onSelectChat: (chat: ChatData) => void; + refreshSessions: () => Promise; + deleteHistory: (chatId: string) => void + onChangeTitle: (data: { id: string, title: string }) => Promise; sessions: any[]; models: any[]; activeChat: any, - sessionTitles: { sessionId: string, title: string, createdAt: any }[] + chatData: ChatData[] } -const HisotryEntry = ({ entry, deleteHistory, onSelectSession, isActive, onChangeTitle }) => { +const HisotryEntry = ({ entry, deleteHistory, onSelectChat, isActive, onChangeTitle }) => { const [isEdit, setIsEdit] = useState(false); const [title, setTitle] = useState(entry?.title || ""); @@ -32,19 +33,19 @@ const HisotryEntry = ({ entry, deleteHistory, onSelectSession, isActive, onChang deleteHistory(id); } - const changetTitle = (e, id) => { + const changetTitle = (e, chatId) => { setIsEdit(!isEdit); e.stopPropagation(); - onChangeTitle({ id, title }); + onChangeTitle({ id: chatId, title }); } return ( - onSelectSession(entry)}> + onSelectChat(entry)}> { !isEdit ? ( <> - {title} + {title} { isActive && ( @@ -52,7 +53,7 @@ const HisotryEntry = ({ entry, deleteHistory, onSelectSession, isActive, onChang e.stopPropagation(); setIsEdit(!isEdit); }} style={{ marginRight: '1.5rem' }} size={22} /> - wrapDelete(e, entry.sessionId)} /> + wrapDelete(e, entry.id)} /> ) } @@ -70,7 +71,7 @@ const HisotryEntry = ({ entry, deleteHistory, onSelectSession, isActive, onChang { - changetTitle(e, entry.sessionId) + changetTitle(e, entry.id) }} style={{ margin: '0 1.5rem' }} size={22} /> { e.stopPropagation(); @@ -86,32 +87,37 @@ const HisotryEntry = ({ entry, deleteHistory, onSelectSession, isActive, onChang export const ChatHistory = (props: ChatHistoryProps) => { const sessions = props.sessions; - const [search, setSearch] = useState(); + const [search, setSearch] = useState(''); useEffect(() => { - setSearch(""); + setSearch(''); }, [props.open]) - const renderTitlesGroup = (items) => { + const renderTitlesGroup = (items: ChatData[]) => { return items.map(t => { return () + onSelectChat={props.onSelectChat} />) }) } - const getGroupHistory = (items) => { + const getGroupHistory = (items: T[]) => { const getPreviousDate = (shift) => { const d = new Date(); d.setDate(d.getDate() - shift); return d; } - const source = (items || []).filter(i => i.createdAt).sort((a, b) => b.createdAt - a.createdAt); - const result: any = { + const source = (items || []).filter(i => i.createdAt).sort((a, b) => b.createdAt.getTime() - a.createdAt.getTime()); + const result: { + today: T[], + last7: T[], + last30: T[], + older: T[], + } = { today: [], last7: [], last30: [], @@ -137,16 +143,23 @@ export const ChatHistory = (props: ChatHistoryProps) => { return result; } - const filterdModels = props.sessionTitles && search ? props.sessionTitles.filter(m => m.title.includes(search)) : (props.sessionTitles || []); - const groupedItems = getGroupHistory(filterdModels); + const handleTabSwitch = async (tabName) => { + if(tabName == 'sessions') { + await props.refreshSessions(); + } + } + + const filterdModels = props.chatData && search ? props.chatData.filter(m => m.title?.includes(search)) : (props.chatData || []); + const groupedItems = getGroupHistory(filterdModels); return (
@@ -199,23 +212,22 @@ export const ChatHistory = (props: ChatHistoryProps) => {
+
{ sessions?.length ? ( - sessions.map(a => { - const model = props.models.find(x => x.Id == a.ModelAgentId); - + sessions.map(s => { return ( - +
- {!isClosed(a) ? + {!isClosed(s) ? Active - props.onCloseSession(a.Id)}>Close + props.onCloseSession(s.Id)}>Close : null}
- {model?.Name} - {((a.EndsAt - a.OpenedAt) / 60).toFixed(0)} min + {s.ModelName} + {((s.EndsAt - s.OpenedAt) / 60).toFixed(0)} min
) @@ -223,6 +235,7 @@ export const ChatHistory = (props: ChatHistoryProps) => { )) :
You have not any sessions
} +
diff --git a/ui-desktop/src/renderer/src/components/chat/interfaces.tsx b/ui-desktop/src/renderer/src/components/chat/interfaces.tsx new file mode 100644 index 00000000..df40c786 --- /dev/null +++ b/ui-desktop/src/renderer/src/components/chat/interfaces.tsx @@ -0,0 +1,50 @@ +export interface ChatTitle { + chatId: string; + title: string; + createdAt: number; // timestamp in seconds + modelId: string; + isLocal?: boolean; +} + +export interface ChatData { + id: string; + title?: string; + createdAt: Date; + modelId: string; + isLocal?: boolean; +} + +export interface HistoryMessage { + id: string; + text: string; + user: string; + role: string; + icon: string; + color: string; + isImageContent?: boolean; + isVideoRawContent?: boolean; +} + +export interface ChatHistoryInterface { + title: string; + modelId: string; + messages: ChatMessage[]; +} + +export interface ChatMessage { + response: string; + prompt: ChatPrompt; + promptAt: number; + responseAt: number; + isImageContent?: boolean; + isVideoRawContent?: boolean; +} + +export interface ChatPrompt { + model: string; + messages: { + role: string; + content: string; + }[]; +} + diff --git a/ui-desktop/src/renderer/src/components/chat/modals/ModelRow.tsx b/ui-desktop/src/renderer/src/components/chat/modals/ModelRow.tsx index 670280e5..ea0e0bb3 100644 --- a/ui-desktop/src/renderer/src/components/chat/modals/ModelRow.tsx +++ b/ui-desktop/src/renderer/src/components/chat/modals/ModelRow.tsx @@ -6,7 +6,7 @@ import { } from '../../contracts/modals/CreateContractModal.styles'; import { abbreviateAddress } from '../../../utils'; import { formatSmallNumber } from '../utils'; -import { IconX } from '@tabler/icons-react'; +import { IconX, IconPlugConnectedX } from '@tabler/icons-react'; const RowContainer = styled.div` padding: 0 1.2rem; @@ -46,7 +46,7 @@ const Buttons = styled.div` const PriceContainer = styled.div` display: flex; - justify-content: ${p => p.hasLocal ? "space-evenly" : 'center'}; + justify-content: center; align-items: center; white-space: nowrap; ` @@ -58,6 +58,12 @@ const ModelNameContainer = styled(FlexCenter)` text-overflow: ellipsis; ` +const DisconnectedIcon = styled(IconPlugConnectedX)` + width: 16px; + color: white; + margin-left: 10px; +` + const selectorStyles = { control: (base) => ({ ...base, borderColor: '#20dc8e', width: '100%', background: 'transparent' }), option: (base, state) => ({ @@ -92,15 +98,15 @@ const selectorStyles = { function ModelRow(props) { const bids = props?.model?.bids || []; const modelId = props?.model?.Id || ''; - const hasLocal = props?.model?.hasLocal; - const hasBids = Boolean(bids.length); + const isLocal = props?.model?.isLocal; + const lastAvailabilityCheck: Date = new Date(props?.model?.lastCheck ?? new Date()); const [selected, changeSelected] = useState(); const [useSelect, setUseSelect] = useState(); const [targetBid, setTargetBid] = useState(); const options = bids.map(x => { - return ({ value: x.Id, label: `${abbreviateAddress(x.Provider || "", 3)} ${formatSmallNumber(x.PricePerSecond / (10 ** 18))} MOR` }) + return ({ value: x.Id, label: `${abbreviateAddress(x.Provider || "", 3)} ${formatSmallNumber(x.PricePerSecond / (10 ** 18))} ${props.symbol}` }) }); const handleChangeModel = () => { @@ -118,26 +124,30 @@ function ModelRow(props) { const formatPrice = () => { if (targetBid) { - return `${formatSmallNumber(targetBid?.PricePerSecond / (10 ** 18))} MOR`; + return `${formatSmallNumber(targetBid?.PricePerSecond / (10 ** 18))} ${props.symbol}`; } - const prices = bids.filter(x => x.Id).map(x => x.PricePerSecond); + const prices = bids.filter(x => x.Id).map(x => Number(x.PricePerSecond)); if (prices.length == 1) { - return `${formatSmallNumber(prices[0] / (10 ** 18))} MOR`; + return `${formatSmallNumber(prices[0] / (10 ** 18))} ${props.symbol}`; } - const minPrice = Math.min(prices); - const maxPrice = Math.max(prices); + const minPrice = Math.min(...prices); + const maxPrice = Math.max(...prices); - return `${formatSmallNumber(minPrice / (10 ** 18))} - ${formatSmallNumber(maxPrice / (10 ** 18))} MOR` + return `${formatSmallNumber(minPrice / (10 ** 18))} - ${formatSmallNumber(maxPrice / (10 ** 18))} ${props.symbol}` } return ( - {props?.model?.Name} + { props?.model?.Name } + { + !props?.model?.isOnline && + + } - + { useSelect ?
@@ -158,32 +168,24 @@ function ModelRow(props) {
:
{ - hasBids ? - - {formatPrice()} - - - {/* setUseSelect(!useSelect)}> */} - - : - - + !isLocal ? ( + + + {formatPrice()} + + {/* setUseSelect(!useSelect)}> */} + + ) : + (local) } -
}
- { - hasLocal && - Local - } - { - hasBids && - Select - } + isLocal ? selectLocal() : handleChangeModel()}>Select
); diff --git a/ui-desktop/src/renderer/src/components/chat/modals/ModelSelectionModal.tsx b/ui-desktop/src/renderer/src/components/chat/modals/ModelSelectionModal.tsx index a2f97713..56b0593e 100644 --- a/ui-desktop/src/renderer/src/components/chat/modals/ModelSelectionModal.tsx +++ b/ui-desktop/src/renderer/src/components/chat/modals/ModelSelectionModal.tsx @@ -14,9 +14,10 @@ import { IconSearch } from '@tabler/icons-react'; import ModelRow from './ModelRow'; import { useState } from 'react'; -const rowRenderer = (models, onChangeModel) => ({ index, style }) => ( +const rowRenderer = (models, onChangeModel, symbol) => ({ index, style }) => (
{ +const ModelSelectionModal = ({ isActive, handleClose, models, onChangeModel, symbol, providersAvailability }) => { const [search, setSearch] = useState(); if (!isActive) { @@ -47,7 +48,34 @@ const ModelSelectionModal = ({ isActive, handleClose, models, onChangeModel }) = handleClose(); } - const filterdModels = search ? models.filter(m => m.Name.includes(search)) : models; + const sortedModels = models + .map(m => { + if(m.isLocal || !providersAvailability){ + return ({...m, isOnline: true }) + } + + const info = m.bids.reduce((acc, next) => { + const entry = providersAvailability.find(pa => pa.id == next.Provider); + if(!entry) { + return acc; + } + + if(entry.isOnline) { + return acc; + } + + const isOnline = entry.status != "disconnected"; + + return { + isOnline, + lastCheck: !isOnline ? entry.time : undefined + } + }, {}); + return ({ ...m, ...info }) + } ) + .sort((a, b) => b.isOnline - a.isOnline); + + const filterdModels = search ? sortedModels.filter(m => m.Name.toLowerCase().includes(search.toLowerCase())) : sortedModels; return ( - Select Model + Select Model To Create Chat @@ -75,9 +103,9 @@ const ModelSelectionModal = ({ isActive, handleClose, models, onChangeModel }) = { filterdModels.length == 0 &&
No models found
} - {({ width, height }) => ( + {({ width }) => ( { return result; } +export const generateHashId = (length = 64) => { + const hex = [...Array(length)].map(() => Math.floor(Math.random() * 16).toString(16)).join(''); + return `0x${hex}`; +} + export const getHashCode = (string) => { var hash = 0; for (var i = 0; i < string.length; i++) { diff --git a/ui-desktop/src/renderer/src/components/common/ChainHeader.jsx b/ui-desktop/src/renderer/src/components/common/ChainHeader.jsx new file mode 100644 index 00000000..d533bcef --- /dev/null +++ b/ui-desktop/src/renderer/src/components/common/ChainHeader.jsx @@ -0,0 +1,85 @@ + +import styled from 'styled-components'; + +import ArbLogo from '../icons/ArbLogo'; + +const Container = styled.div` + display: flex; + flex-direction: row; + justify-content: space-between; + align-items: center; + position: sticky; + width: 100%; + padding: 0 0 1.5rem 0; + z-index: 2; + right: 0; + left: 0; + top: 0; +`; + +const TitleRow = styled.div` + width: 100%; + display: flex; + flex-direction: row; + align-items: center; + justify-content: space-between; +`; + +const Title = styled.div` + width: 100%; + display: flex; + justify-content: space-between; + align-items: center; + font-size: 2.4rem; + line-height: 3rem; + white-space: nowrap; + margin: 0; + font-weight: 600; + color: ${p => p.theme.colors.morMain}; + margin-right: 2.4rem; + cursor: default; + /* width: 100%; */ + + @media (min-width: 1140px) { + } + + @media (min-width: 1200px) { + } +`; + +const ChainContainer = styled.div` + display: flex; + align-items: center; + gap: 10px; + color: white; + font-size: 1.2rem; + padding: 0.6rem 1.2rem; + background: rgba(255,255,255,0.04); + border-width: 1px; + border: 1px solid rgba(255,255,255,0.04); +` + +const getChainLogo = (chainId) => { + const arbLogo = (); + if(chainId === 42161 || chainId === 421614) { + return arbLogo; + } + // Handle other icons (ETH, Base, etc.) + + return arbLogo; +} + +export const ChainHeader = ({ title, children, chain }) => ( + + + + <div>{title}</div> + <ChainContainer> + {getChainLogo(Number(chain?.chainId || 42161))} + <div>{chain?.displayName || "Arbitrum"}</div> + </ChainContainer> + + {children} + + +); diff --git a/ui-desktop/src/renderer/src/components/common/Root.jsx b/ui-desktop/src/renderer/src/components/common/Root.jsx index e75efbc5..19dbd96b 100644 --- a/ui-desktop/src/renderer/src/components/common/Root.jsx +++ b/ui-desktop/src/renderer/src/components/common/Root.jsx @@ -64,11 +64,15 @@ class Root extends React.Component { }) } - onOnboardingCompleted = ({ password, mnemonic, proxyRouterConfig }) => { + onOnboardingCompleted = (data) => { return ( this.props.client - .onOnboardingCompleted({ password, mnemonic, proxyRouterConfig, proxyUrl: this.props.config.chain.localProxyRouterUrl }) - .then(() => { + .onOnboardingCompleted({ proxyUrl: this.props.config.chain.localProxyRouterUrl, ...data }) + .then((error) => { + if(error) { + this.context.toast('error', error); + return; + } this.setState({ onboardingComplete: true }) this.props.dispatch({ type: 'session-started' }) }) diff --git a/ui-desktop/src/renderer/src/components/common/TextInput.styles.jsx b/ui-desktop/src/renderer/src/components/common/TextInput.styles.jsx index 6ecdefbc..1bd0a678 100644 --- a/ui-desktop/src/renderer/src/components/common/TextInput.styles.jsx +++ b/ui-desktop/src/renderer/src/components/common/TextInput.styles.jsx @@ -9,15 +9,15 @@ export const Label = styled.label` `; export const Input = styled.input` - border: none; + border: 1px solid gray; display: block; border-radius: 2px; padding: 0.8rem 1.6rem; - background-color: ${p => p.theme.colors.lightBlue}; + background-color: transparent; margin-top: 0.8rem; width: 100%; line-height: 2.5rem; - color: ${p => (p.disabled ? p.theme.colors.copy : p.theme.colors.primary)}; + color: ${p => (p.disabled ? p.theme.colors.copy : "white")}; font-size: 1.3rem; font-weight: 600; letter-spacing: 0.5px; @@ -28,11 +28,11 @@ export const Input = styled.input` &:focus { outline: none; - box-shadow: 0 2px 0 0px ${p => p.theme.colors.primary}; + box-shadow: 0 2px 0 0px ${p => p.theme.colors.morMain}; box-shadow: ${p => p.noFocus && p.value.length > 0 ? 'none' - : `0 2px 0 0px ${p.theme.colors.primary}`}; + : `0 2px 0 0px ${p.theme.colors.morMains}`}; } `; diff --git a/ui-desktop/src/renderer/src/components/dashboard/Dashboard.jsx b/ui-desktop/src/renderer/src/components/dashboard/Dashboard.jsx index 1e84d332..e74d9606 100644 --- a/ui-desktop/src/renderer/src/components/dashboard/Dashboard.jsx +++ b/ui-desktop/src/renderer/src/components/dashboard/Dashboard.jsx @@ -3,19 +3,45 @@ import styled from 'styled-components' import withDashboardState from '../../store/hocs/withDashboardState' -import { LayoutHeader } from '../common/LayoutHeader' +import { ChainHeader } from '../common/ChainHeader' import BalanceBlock from './BalanceBlock' import TransactionModal from './tx-modal' import TxList from './tx-list/TxList' import { View } from '../common/View' import { toUSD } from '../../store/utils/syncAmounts'; +import { + BtnAccent, +} from './BalanceBlock.styles'; -const Container = styled.div` - background-color: ${(p) => p.theme.colors.light}; - height: 100vh; - max-width: 100vw; - position: relative; - padding: 0 2.4rem; +const CustomBtn = styled(BtnAccent)` + margin-left: 0; + padding: 1.5rem 1rem; +` +const WidjetsContainer = styled.div` + display: flex; + align-items: center; + justify-content: left; + gap: 1.6rem; +` + +const WidjetItem = styled.div` + margin: 1.6rem 0 1.6rem; + padding: 1.6rem 3.2rem; + border-radius: 0.375rem; + color: white; + max-width: 720px; + + color: white; +` + +const StakingWidjet = styled(WidjetItem)` + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + background: rgba(255,255,255,0.04); + border-width: 1px; + border: 1px solid rgba(255,255,255,0.04); ` const Dashboard = ({ @@ -29,6 +55,8 @@ const Dashboard = ({ getBalances, ethCoinPrice, loadTransactions, + getStakedFunds, + explorerUrl, ...props }) => { const [activeModal, setActiveModal] = useState(null) @@ -45,7 +73,8 @@ const Dashboard = ({ } }); const [transactions, setTransactions] = useState([]); - const [pagging, setPagging] = useState({ page: 1, pageSize: 15, hasNextPage: true }) + const [pagging, setPagging] = useState({ page: 1, pageSize: 50, hasNextPage: true }) + const [staked, setStaked] = useState(0); const loadBalances = async () => { const data = await getBalances(); @@ -109,6 +138,9 @@ const Dashboard = ({ useEffect(() => { loadBalances(); getTransactions(); + getStakedFunds(address).then((data) => { + setStaked(data); + }) const interval = setInterval(() => { console.log("Update balances...") @@ -125,7 +157,7 @@ const Dashboard = ({ return ( - + + + +
+ Staked Balance +
+
{staked} {props.symbol}
+
+ + window.openLink(explorerUrl)} + block + > + Transaction Explorer + + + + window.openLink("https://staking.mor.lumerin.io")} + block + > + Staking Dashboard + + +
+ {}} hasTransactions={!!transactions.length} syncStatus={syncStatus} transactions={transactions} diff --git a/ui-desktop/src/renderer/src/components/dashboard/tx-list/TxList.jsx b/ui-desktop/src/renderer/src/components/dashboard/tx-list/TxList.jsx index b803fedd..2ba62f9f 100644 --- a/ui-desktop/src/renderer/src/components/dashboard/tx-list/TxList.jsx +++ b/ui-desktop/src/renderer/src/components/dashboard/tx-list/TxList.jsx @@ -32,7 +32,7 @@ const Transactions = styled.div` `; const ListContainer = styled.div` - height: calc(100vh - 370px); + height: calc(100vh - 490px); border-radius: 0.375rem; background: rgba(255,255,255, 0.04); @@ -86,7 +86,7 @@ export const TxList = ({ return ( - Transactions + Last Transactions txType)} > {({ filteredItems, onFilterChange, activeFilter }) => { - const rowCount = hasNextPage - ? filteredItems.length + 1 - : filteredItems.length; + // const rowCount = hasNextPage + // ? filteredItems.length + 1 + // : filteredItems.length; + const rowCount = filteredItems.length; // Only load 1 page of items at a time. // Pass an empty callback to InfiniteLoader in case it asks us to load more than once. const loadMoreRows = nextPageLoading ? () => {} : () => { - load(); + // load(); }; // Every row is loaded except for our loading indicator row. @@ -124,9 +125,10 @@ export const TxList = ({ /> ) : ( - - Loading... - + null + // + // Loading... + // ); return ( @@ -147,18 +149,9 @@ export const TxList = ({ ))} {+transactions.length > 0 && ( - - {({ onRowsRendered, registerChild }) => ( - + {({ width, height }) => ( )} - )} - + // + // {({ onRowsRendered, registerChild }) => ( + // + // {({ width, height }) => ( + // + // )} + // + // )} + // )} diff --git a/ui-desktop/src/renderer/src/components/dashboard/tx-list/row/ReceivedDetails.jsx b/ui-desktop/src/renderer/src/components/dashboard/tx-list/row/ReceivedDetails.jsx index 6b8d0d60..e03fe57f 100644 --- a/ui-desktop/src/renderer/src/components/dashboard/tx-list/row/ReceivedDetails.jsx +++ b/ui-desktop/src/renderer/src/components/dashboard/tx-list/row/ReceivedDetails.jsx @@ -18,7 +18,6 @@ const Address = styled.span` export default class ReceivedDetails extends React.Component { static propTypes = { - isPending: PropTypes.bool.isRequired, from: PropTypes.string.isRequired }; diff --git a/ui-desktop/src/renderer/src/components/dashboard/tx-list/row/SentDetails.jsx b/ui-desktop/src/renderer/src/components/dashboard/tx-list/row/SentDetails.jsx index f78177f6..e00652e5 100644 --- a/ui-desktop/src/renderer/src/components/dashboard/tx-list/row/SentDetails.jsx +++ b/ui-desktop/src/renderer/src/components/dashboard/tx-list/row/SentDetails.jsx @@ -20,7 +20,6 @@ export default class SentDetails extends React.Component { static propTypes = { isCancelApproval: PropTypes.bool, isApproval: PropTypes.bool, - isPending: PropTypes.bool.isRequired, to: PropTypes.string.isRequired }; diff --git a/ui-desktop/src/renderer/src/components/icons/ArbLogo.jsx b/ui-desktop/src/renderer/src/components/icons/ArbLogo.jsx new file mode 100644 index 00000000..b2653373 --- /dev/null +++ b/ui-desktop/src/renderer/src/components/icons/ArbLogo.jsx @@ -0,0 +1,73 @@ +import * as React from "react"; +const ArbLogo = (props) => ( + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +); +export default ArbLogo; diff --git a/ui-desktop/src/renderer/src/components/icons/LumerinLogoFull.jsx b/ui-desktop/src/renderer/src/components/icons/LumerinLogoFull.jsx index 81734b09..45d4be23 100644 --- a/ui-desktop/src/renderer/src/components/icons/LumerinLogoFull.jsx +++ b/ui-desktop/src/renderer/src/components/icons/LumerinLogoFull.jsx @@ -1,7 +1,7 @@ export const LumerinLogoFull = (props) => (
Name: {f.name}
+
Path: {f.path}
+
Size: {(f.size / 1024).toFixed(0)}
+ + }) + ) + } + + + Pin Model Files + + +
+ ); +} + +export default FileSelectionModal; \ No newline at end of file diff --git a/ui-desktop/src/renderer/src/components/models/Models.tsx b/ui-desktop/src/renderer/src/components/models/Models.tsx index c1b9d85e..bc2a9ae0 100644 --- a/ui-desktop/src/renderer/src/components/models/Models.tsx +++ b/ui-desktop/src/renderer/src/components/models/Models.tsx @@ -1,11 +1,57 @@ +import { useState } from 'react'; import { LayoutHeader } from '../common/LayoutHeader' import { View } from '../common/View' +import { BtnAccent } from '../dashboard/BalanceBlock.styles'; import ModelsTable from './ModelsTable'; +import Tab from 'react-bootstrap/Tab'; +import Tabs from 'react-bootstrap/Tabs'; +import styled from 'styled-components' +import FileSelectionModal from './FileSelectionModal'; -export const Models = () => { - return ( - - - - ) -} \ No newline at end of file + +const Container = styled.div` + overflow-y: auto; + + .nav-link { + color: ${p => p.theme.colors.morMain} + } + + .nav-link.active { + color: ${p => p.theme.colors.morMain} + border-color: ${p => p.theme.colors.morMain} + background-color: rgba(0,0,0,0.4); + } +` + +const Models = () => { + + const [openChangeModal, setOpenChangeModal] = useState(false); + + return ( + + + setOpenChangeModal(true)}>Pin Model + + + + + + + + + + + + + setOpenChangeModal(false)} /> + ) + +} + +export default Models; \ No newline at end of file diff --git a/ui-desktop/src/renderer/src/components/models/ModelsTable.tsx b/ui-desktop/src/renderer/src/components/models/ModelsTable.tsx index 1e399648..7e70a4a7 100644 --- a/ui-desktop/src/renderer/src/components/models/ModelsTable.tsx +++ b/ui-desktop/src/renderer/src/components/models/ModelsTable.tsx @@ -1,5 +1,5 @@ import { useState } from 'react'; -import { withRouter } from 'react-router-dom'; + import withModelsState from "../../store/hocs/withModelsState"; import styled from 'styled-components'; @@ -80,7 +80,6 @@ function ModelsTable({ const onSelect = (id) => { console.log("selected", id); setSelectedModel(models.find(x => x.Id == id)); - history.push("/bids"); } return ( @@ -90,4 +89,4 @@ function ModelsTable({ ) } -export default withRouter(withModelsState(ModelsTable)); +export default withModelsState(ModelsTable); diff --git a/ui-desktop/src/renderer/src/components/onboarding/CopyMnemonicStep.jsx b/ui-desktop/src/renderer/src/components/onboarding/CopyMnemonicStep.jsx index 230b7087..923d018e 100644 --- a/ui-desktop/src/renderer/src/components/onboarding/CopyMnemonicStep.jsx +++ b/ui-desktop/src/renderer/src/components/onboarding/CopyMnemonicStep.jsx @@ -49,15 +49,15 @@ export default class CopyMnemonicStep extends React.Component { I’ve copied it - + {/* - Or recover a wallet from a saved mnemonic + DELETE - + */} ); diff --git a/ui-desktop/src/renderer/src/components/onboarding/ImportFlow.jsx b/ui-desktop/src/renderer/src/components/onboarding/ImportFlow.jsx new file mode 100644 index 00000000..19d7abba --- /dev/null +++ b/ui-desktop/src/renderer/src/components/onboarding/ImportFlow.jsx @@ -0,0 +1,236 @@ +import TermsAndConditions from '../common/TermsAndConditions'; +import PropTypes from 'prop-types'; +import styled from 'styled-components'; +import React, { useState } from 'react'; +import { TextInput, AltLayout, AltLayoutNarrow, Btn, Sp } from '../common'; +import { abbreviateAddress } from '../../utils'; + +import Message from './Message'; + +const DisclaimerWarning = styled.div` + text-align: left; + color: ${p => p.theme.colors.dark}; + font-size: 16px; + margin-top: 16px; + text-align: justify; +`; + +const DisclaimerMessage = styled.div` + width: 100%; + height: 130px; + border-radius: 2px; + background-color: rgba(0, 0, 0, 0.5); + color: ${p => p.theme.colors.dark}; + overflow: auto; + font-size: 12px; + padding: 10px 16px 0 16px; + margin: 16px 0; +`; + +const P = styled.p` + color: ${p => p.theme.colors.dark}; +`; + +const Subtext = styled.span` + color: ${p => p.theme.colors.dark}; +`; + +const Mnemonic = styled.div` + font-size: 1.8rem; + font-weight: 600; + line-height: 2; + text-align: center; + color: ${p => p.theme.colors.morMain}; + word-spacing: 1.6rem; +`; + +const Select = styled.select` + outline: 0; + border: 1px solid grey; + padding: 1.2rem 2.4rem; + letter-spacing: 1.4px; + line-height: 1.2rem; + font-size: 1.2rem; + background: transparent; + border-radius: 5px; + font-weight: bold; + font: inherit; + color: white; +`; + +export const ImportFlow = props => { + const onCheckboxToggle = e => { + props.onInputChange({ id: e.target.id, value: e.target.checked }); + }; + + const [mode, setMode] = useState("mnemonic") + const [isSelectingAddress, setIsSelectingAddress] = useState(false); + const [addresses, setAddresses] = useState([]); + const [derivationIndex, setDerivationIndex] = useState(0); + + const handleSetMnemonic = async (e) => { + setIsSelectingAddress(true); + e.stopPropagation(); + const addresses = await props.onSuggestAddress(); + setAddresses(addresses); + } + + return ( + + + + { + isSelectingAddress ? + ( + <> + + + {props.userMnemonic} + + + + + + Select one of 10 accounts derivied from mnemonic + + + + + + + ) + : + ( + + <> + + Import your wallet using a private key or mnemonic + + + + + + { + mode == "mnemonic" ? + ( + <> + + + Enter a valid 12 word mnemonic to import a previously created + wallet and select address + + + + { + e.preventDefault(); + const value = e.clipboardData.getData('Text').trim(); + console.log(value); + props.onInputChange({ value, id: "userMnemonic" }); + }} + label="Import Mnemonic" + error={props.errors.userMnemonic} + value={props.userMnemonic || ''} + rows={2} + id={'userMnemonic'} + /> + + + ) + : + ( + <> + + + Enter private key to import wallet + + + + { + e.preventDefault(); + const value = e.clipboardData.getData('Text').trim(); + console.log(value); + props.onInputChange({ value, id: "userPrivateKey" }); + }} + label="Import Private Key" + error={props.errors.userPrivateKey} + value={props.userPrivateKey || ''} + rows={2} + id={'userPrivateKey'} + /> + + + ) + } + + ) + + } + + {/* Select address - generate addresses - use */} + { + mode == "mnemonic" ? ( + + !isSelectingAddress ? handleSetMnemonic(e) : props.onMnemonicSet(e, derivationIndex)} + block + > + { !isSelectingAddress ? "Select Address" : "Confirm"} + + + ) + : ( + + props.onPrivateKeyAccepted(e)} + block + > + Confirm + + + ) + } + + + + ); +}; + +// RecoverFromPrivateKey.propTypes = { +// onTermsLinkClick: PropTypes.func.isRequired, +// onTermsAccepted: PropTypes.func.isRequired, +// licenseCheckbox: PropTypes.bool.isRequired, +// termsCheckbox: PropTypes.bool.isRequired, +// onInputChange: PropTypes.func.isRequired +// }; \ No newline at end of file diff --git a/ui-desktop/src/renderer/src/components/onboarding/Message.jsx b/ui-desktop/src/renderer/src/components/onboarding/Message.jsx index dc87f206..82d46a78 100644 --- a/ui-desktop/src/renderer/src/components/onboarding/Message.jsx +++ b/ui-desktop/src/renderer/src/components/onboarding/Message.jsx @@ -5,6 +5,7 @@ const Message = styled.div` font-weight: 500; line-height: 1.5; color: ${p => p.theme.colors.dark}; + text-align: justify; & span { font-size: 13px; diff --git a/ui-desktop/src/renderer/src/components/onboarding/Onboarding.tsx b/ui-desktop/src/renderer/src/components/onboarding/Onboarding.tsx index 1814a418..12e6adce 100644 --- a/ui-desktop/src/renderer/src/components/onboarding/Onboarding.tsx +++ b/ui-desktop/src/renderer/src/components/onboarding/Onboarding.tsx @@ -6,6 +6,8 @@ import CopyMnemonicStep from './CopyMnemonicStep' import UserMnemonicStep from './UserMnemonicStep' import PasswordStep from './PasswordStep' import TermsStep from './TermsStep' +import { ImportFlow } from './ImportFlow' +import { SetCustomEthStep } from './SetCustomEthStep' const Onboarding = (props) => { const page = () => { @@ -20,6 +22,10 @@ const Onboarding = (props) => { return case 'recover-from-mnemonic': return + case 'import-flow': + return + case 'set-custom-eth': + return default: return null } diff --git a/ui-desktop/src/renderer/src/components/onboarding/PasswordStep.jsx b/ui-desktop/src/renderer/src/components/onboarding/PasswordStep.jsx index b5dc8556..c1418944 100644 --- a/ui-desktop/src/renderer/src/components/onboarding/PasswordStep.jsx +++ b/ui-desktop/src/renderer/src/components/onboarding/PasswordStep.jsx @@ -17,6 +17,7 @@ import Message from './Message'; const PasswordMessage = styled(Message)` text-align: left; color: ${p => p.theme.colors.dark}; + text-align: justify; `; const Green = styled.div` @@ -28,19 +29,25 @@ const PasswordInputWrap = styled.div` position: relative; `; +const SecondaryBtn = styled(Btn)` + border: 1px solid #20dc8e; + color: #20dc8e; + background: transparent; +` + const PasswordStep = props => { const [typed, setTyped] = useState(false); const [suggestion, setSuggestion] = useState(''); - const onPasswordSubmit = e => { + const onPasswordSubmit = (e, useImportFlow) => { e.preventDefault(); - props.onPasswordSubmit({ clearOnError: false }); + props.onPasswordSubmit({ clearOnError: false, useImportFlow }); }; let tooltipTimeout; return ( - + -
+ Enter a strong password until the meter turns green. @@ -90,10 +97,15 @@ const PasswordStep = props => { /> - - Continue + onPasswordSubmit(e, false)}> + Create a new wallet + + onPasswordSubmit(e, true)}> + Import an existing wallet + +
diff --git a/ui-desktop/src/renderer/src/components/onboarding/SetCustomEthStep.jsx b/ui-desktop/src/renderer/src/components/onboarding/SetCustomEthStep.jsx new file mode 100644 index 00000000..b0b65dfc --- /dev/null +++ b/ui-desktop/src/renderer/src/components/onboarding/SetCustomEthStep.jsx @@ -0,0 +1,92 @@ +import TermsAndConditions from '../../components/common/TermsAndConditions'; +import PropTypes from 'prop-types'; +import styled from 'styled-components'; +import React from 'react'; +import SecondaryBtn from './SecondaryBtn'; +import { AltLayout, AltLayoutNarrow, Btn, Sp, TextInput } from '../common'; +import Message from './Message'; + +const DisclaimerWarning = styled.div` + text-align: left; + color: ${p => p.theme.colors.dark}; + font-size: 16px; + margin-top: 16px; + text-align: justify; +`; + +const DisclaimerMessage = styled.div` + width: 100%; + height: 130px; + border-radius: 2px; + background-color: rgba(0, 0, 0, 0.1); + color: ${p => p.theme.colors.dark}; + overflow: auto; + font-size: 12px; + padding: 10px 16px 0 16px; + margin: 16px 0; +`; + +const P = styled.p` + color: ${p => p.theme.colors.dark}; +`; + +const Subtext = styled.span` + color: ${p => p.theme.colors.dark}; +`; + +export const SetCustomEthStep = props => { + + return ( + + + + Set Custom ETH node url that will be used for blockchain interactions instead of default. This can be set later in Settings + + + + { + e.preventDefault(); + const value = e.clipboardData.getData('Text').trim(); + console.log(value); + props.onInputChange({ value, id: 'customEthNode' }); + }} + label="Custom ETH Node Url" + error={props.errors.customEthNode} + value={props.customEthNode || ''} + id={'customEthNode'} + /> + + + + + Accept + + + + { + e.preventDefault(); + props.onInputChange({ value: "", id: 'customEthNode' }); + props.onEthNodeSet(e) + }} + block + > + Skip + + + + + ); +}; diff --git a/ui-desktop/src/renderer/src/components/onboarding/TermsStep.jsx b/ui-desktop/src/renderer/src/components/onboarding/TermsStep.jsx index 1303e063..863d97dc 100644 --- a/ui-desktop/src/renderer/src/components/onboarding/TermsStep.jsx +++ b/ui-desktop/src/renderer/src/components/onboarding/TermsStep.jsx @@ -11,13 +11,14 @@ const DisclaimerWarning = styled.div` color: ${p => p.theme.colors.dark}; font-size: 16px; margin-top: 16px; + text-align: justify; `; const DisclaimerMessage = styled.div` width: 100%; height: 130px; border-radius: 2px; - background-color: rgba(0, 0, 0, 0.1); + background-color: rgba(0, 0, 0, 0.5); color: ${p => p.theme.colors.dark}; overflow: auto; font-size: 12px; @@ -31,6 +32,7 @@ const P = styled.p` const Subtext = styled.span` color: ${p => p.theme.colors.dark}; + margin-left: 5px; `; const TermsStep = props => { @@ -72,7 +74,6 @@ const TermsStep = props => { software license - .
diff --git a/ui-desktop/src/renderer/src/components/providers/Providers.tsx b/ui-desktop/src/renderer/src/components/providers/Providers.tsx index 1e445d4f..920adb3e 100644 --- a/ui-desktop/src/renderer/src/components/providers/Providers.tsx +++ b/ui-desktop/src/renderer/src/components/providers/Providers.tsx @@ -2,7 +2,7 @@ import { useEffect, useState } from 'react' import { LayoutHeader } from '../common/LayoutHeader' import { View } from '../common/View' import ProvidersList from './ProvidersList' -import { withRouter } from 'react-router-dom'; + import { BtnAccent } from '../dashboard/BalanceBlock.styles'; import withProvidersState from "../../store/hocs/withProvidersState"; @@ -27,4 +27,4 @@ const Providers = ({ fetchData, providerId }) => { ) } -export default withRouter(withProvidersState(Providers)); \ No newline at end of file +export default withProvidersState(Providers); \ No newline at end of file diff --git a/ui-desktop/src/renderer/src/components/providers/ProvidersList.tsx b/ui-desktop/src/renderer/src/components/providers/ProvidersList.tsx index 851c9458..652f7a2e 100644 --- a/ui-desktop/src/renderer/src/components/providers/ProvidersList.tsx +++ b/ui-desktop/src/renderer/src/components/providers/ProvidersList.tsx @@ -1,4 +1,4 @@ -import { withRouter } from 'react-router-dom'; + import withProvidersState from "../../store/hocs/withProvidersState"; import styled from 'styled-components'; import Accordion from 'react-bootstrap/Accordion'; @@ -86,4 +86,4 @@ function ProvidersList({ data, claimFunds }) { ) } -export default withRouter(withProvidersState(ProvidersList)); +export default withProvidersState(ProvidersList); diff --git a/ui-desktop/src/renderer/src/components/settings/Settings.tsx b/ui-desktop/src/renderer/src/components/settings/Settings.tsx index 15e27c7e..47377e29 100644 --- a/ui-desktop/src/renderer/src/components/settings/Settings.tsx +++ b/ui-desktop/src/renderer/src/components/settings/Settings.tsx @@ -2,13 +2,27 @@ import { LayoutHeader } from '../common/LayoutHeader' import { View } from '../common/View' import { Sp } from '../common'; import withSettingsState from '../../store/hocs/withSettingsState'; -import { StyledBtn, Subtitle, StyledParagraph } from '../tools/common'; +import { StyledBtn, Subtitle, StyledParagraph, Input } from '../tools/common'; +import { useEffect, useState } from 'react'; const Settings = (props) => { + const [ethNodeUrl, setEthUrl] = useState(""); + const [useFailover, setUseFailover] = useState(false); + + useEffect(() => { + (async () => { + const cfg = await props.getConfig(); + const customUrl = cfg?.DerivedConfig?.EthNodeURLs[0] || ""; + setEthUrl(customUrl); + const failoverSettings = await props.client.getFailoverSetting(); + setUseFailover(Boolean(failoverSettings.isEnabled)); + })() + }, []) + return ( - + Reset Set up your wallet from scratch. @@ -17,6 +31,43 @@ const Settings = (props) => { Reset + + Set Custom ETH Node + + setEthUrl(e.value)} /> + + + props.updateEthNodeUrl(ethNodeUrl)}> + Set + + + + Failover Mechanism + + A failover policy is applied when a provider is unable to service an open session. This policy ensures continuity by automatically rerouting or reassigning sessions to an alternate provider, minimizing service disruptions and maintaining a seamless user experience + + +
+ { + setUseFailover(Boolean(e.target.checked)) + } } + style={{ marginRight: '5px' }} + + /> +
Use Default Policy (set by proxy-router)
+
+
+ props.updateFailoverSetting(useFailover)}> + Apply + +
) } diff --git a/ui-desktop/src/renderer/src/components/sidebar/PrimaryNav.jsx b/ui-desktop/src/renderer/src/components/sidebar/PrimaryNav.jsx index 6025a40e..aff2d4d3 100644 --- a/ui-desktop/src/renderer/src/components/sidebar/PrimaryNav.jsx +++ b/ui-desktop/src/renderer/src/components/sidebar/PrimaryNav.jsx @@ -81,7 +81,7 @@ export default function PrimaryNav({ parent, activeIndex, setActiveIndex }) { - - - diff --git a/ui-desktop/src/renderer/src/components/sidebar/SecondaryNav.jsx b/ui-desktop/src/renderer/src/components/sidebar/SecondaryNav.jsx index 40fb31fa..1cb37f42 100644 --- a/ui-desktop/src/renderer/src/components/sidebar/SecondaryNav.jsx +++ b/ui-desktop/src/renderer/src/components/sidebar/SecondaryNav.jsx @@ -119,7 +119,6 @@ function SecondaryNav({ {/* Tools