diff --git a/.github/actions/copy_env_files/action.yml b/.github/actions/copy_env_files/action.yml new file mode 100644 index 00000000..b52ab7ea --- /dev/null +++ b/.github/actions/copy_env_files/action.yml @@ -0,0 +1,23 @@ +name: Copy Environment Files +description: "Copies environment files based on branch" +runs: + using: "composite" + steps: + - name: Copy Environment Files + shell: bash + run: | + cp ./proxy-router/models-config.json.example ./proxy-router/models-config.json + cp ./proxy-router/models-config.json.example models-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/stg" ]]; 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 ./proxy-router/.env.example ./proxy-router/.env + cp ./proxy-router/.env.example .env + cp ./ui-desktop/.env.example ./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..50a11dbc --- /dev/null +++ b/.github/actions/gen_tag_name/action.yml @@ -0,0 +1,21 @@ +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: | + SHORT_HASH="$(git rev-parse --short=7 HEAD)" + echo $SHORT_HASH + if [[ "${GITHUB_REF}" == "refs/heads/main" ]]; then + PREFIX="main-" + elif [[ "${GITHUB_REF}" == "refs/heads/stg" ]]; then + PREFIX="test-" + else + PREFIX="dev-" + fi + TAG_NAME="${PREFIX}${SHORT_HASH}" + echo $TAG_NAME + echo "TAG_NAME=${TAG_NAME}" >> $GITHUB_ENV \ No newline at end of file diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 5011c6c1..acba89c4 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -10,6 +10,7 @@ on: push: branches: - main + - stg paths: ['.github/workflows/**', '**/Makefile', '**/*.go', '**/*.json', '**/*.yml', '**/*.ts', '**/*.js'] pull_request: types: [opened, reopened, synchronize] @@ -22,7 +23,7 @@ concurrency: defaults: run: shell: bash - + jobs: Ubuntu-22-x64: runs-on: ubuntu-22.04 @@ -34,7 +35,7 @@ jobs: - 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,49 +56,45 @@ 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 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 + ARTIFACT="mor-launch-$TAG_NAME-ubuntu-x64.zip" 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 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 - 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: + runs-on: macos-13 steps: - name: Clone uses: actions/checkout@v4 @@ -106,7 +103,7 @@ jobs: - 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 @@ -127,38 +124,34 @@ 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 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" 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 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 @@ -167,7 +160,7 @@ jobs: - 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: @@ -180,7 +173,7 @@ jobs: - 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 @@ -201,38 +194,34 @@ 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 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" 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 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 @@ -241,7 +230,7 @@ jobs: - 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: @@ -254,7 +243,7 @@ jobs: - 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 +255,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,38 +269,36 @@ 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 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 + ARTIFACT="mor-launch-$TAG_NAME-win-x64.zip" 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 + 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 @@ -320,15 +308,15 @@ jobs: - 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.event_name == 'push' && (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/stg')) || 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: @@ -336,11 +324,8 @@ jobs: id: checkout uses: actions/checkout@v4 - - 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 +345,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/proxy-router.main.env b/.github/workflows/proxy-router.main.env new file mode 100644 index 00000000..92855207 --- /dev/null +++ b/.github/workflows/proxy-router.main.env @@ -0,0 +1,14 @@ +# This file is used to set the environment variables for the cicd workflow +# To Generate the STG or TestNet release +# Contract and Token current as of 11/5/2024 (and are using the same values as the testnet) +# ...when mainnet release is imminent, update the values + +DIAMOND_CONTRACT_ADDRESS=0x10777866547c53cbd69b02c5c76369d7e24e7b10 +MOR_TOKEN_ADDRESS=0x34a285a1b1c166420df5b6630132542923b5b27e +EXPLORER_API_URL="https://api-sepolia.arbiscan.io/api" +ETH_NODE_CHAIN_ID=421614 +OPENAI_BASE_URL=http://localhost:8080/v1 +PROXY_STORE_CHAT_CONTEXT=true +# PROXY_STORAGE_PATH=.\data\ (for windows) +PROXY_STORAGE_PATH=./data/ +LOG_COLOR=true \ 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..c8e1c587 --- /dev/null +++ b/.github/workflows/proxy-router.test.env @@ -0,0 +1,13 @@ +# This file is used to set the environment variables for the cicd workflow +# To Generate the STG or TestNet release +# Contract and Token current as of 11/5/2024 + +DIAMOND_CONTRACT_ADDRESS=0x10777866547c53cbd69b02c5c76369d7e24e7b10 +MOR_TOKEN_ADDRESS=0x34a285a1b1c166420df5b6630132542923b5b27e +EXPLORER_API_URL="https://api-sepolia.arbiscan.io/api" +ETH_NODE_CHAIN_ID=421614 +OPENAI_BASE_URL=http://localhost:8080/v1 +PROXY_STORE_CHAT_CONTEXT=true +# PROXY_STORAGE_PATH=.\data\ (for windows) +PROXY_STORAGE_PATH=./data/ +LOG_COLOR=true \ No newline at end of file diff --git a/.github/workflows/ui-desktop.main.env b/.github/workflows/ui-desktop.main.env new file mode 100644 index 00000000..d8294a90 --- /dev/null +++ b/.github/workflows/ui-desktop.main.env @@ -0,0 +1,19 @@ +# This file is used to set the environment variables for the cicd workflow +# To Generate the MAIN or MAINNET release +# Contract and Token current as of 11/5/2024 (and are using the same values as the testnet) +# ...when mainnet release is imminent, update the values +BYPASS_AUTH=false +CHAIN_ID=421614 +DEBUG=false +DEFAULT_SELLER_CURRENCY=BTC +DEV_TOOLS=true +DIAMOND_ADDRESS=0x10777866547c53cbd69b02c5c76369d7e24e7b10 +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=0x34a285a1b1c166420df5b6630132542923b5b27e +TRACKING_ID= diff --git a/.github/workflows/ui-desktop.test.env b/.github/workflows/ui-desktop.test.env new file mode 100644 index 00000000..827e23c0 --- /dev/null +++ b/.github/workflows/ui-desktop.test.env @@ -0,0 +1,18 @@ +# This file is used to set the environment variables for the cicd workflow +# To Generate the STG or TestNet release +# Contract and Token current as of 11/5/2024 +BYPASS_AUTH=false +CHAIN_ID=421614 +DEBUG=false +DEFAULT_SELLER_CURRENCY=BTC +DEV_TOOLS=true +DIAMOND_ADDRESS=0x10777866547c53cbd69b02c5c76369d7e24e7b10 +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=0x34a285a1b1c166420df5b6630132542923b5b27e +TRACKING_ID= 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/02-provider-setup.md b/docs/02-provider-setup.md index d2d1a9b5..936ce805 100644 --- a/docs/02-provider-setup.md +++ b/docs/02-provider-setup.md @@ -69,11 +69,11 @@ Key Values in the .env file are (there are others, but these are primarly respon - 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` +- `DIAMOND_CONTRACT_ADDRESS=0x10777866547c53cbd69b02c5c76369d7e24e7b10` - 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` +- `MOR_TOKEN_ADDRESS=0x34a285a1b1c166420df5b6630132542923b5b27e` - 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` diff --git a/docs/03-provider-offer.md b/docs/03-provider-offer.md index ee301d2b..36dfa58b 100644 --- a/docs/03-provider-offer.md +++ b/docs/03-provider-offer.md @@ -1,6 +1,6 @@ # Creating Provider, Model and Bid on the Blockchain: -**Diamond contract:** `0x8e19288d908b2d9F8D7C539c74C899808AC3dE45` +**Diamond contract:** `0x10777866547c53cbd69b02c5c76369d7e24e7b10` **Needed information:** * Provider/Owner: `0x9E26Fea97F7d644BAf62d0e20e4d4b8F836C166c` # Your ERC-20 Wallet with saMOR & saETH @@ -12,7 +12,7 @@ ## Steps 1. WEB3/Arbiscan/Metamask: Authorize Diamond Contract to spend on the Provider's behalf - 1. https://sepolia.arbiscan.io/address/0xc1664f994fd3991f98ae944bc16b9aed673ef5fd#writeContract + 1. https://sepolia.arbiscan.io/address/0x34a285a1b1c166420df5b6630132542923b5b27e#writeContract 1. Connect to Web3 (connect Provider wallet) 1. Click Approve 1. Spender Address = Diamond Contract diff --git a/docs/04a-consumer-setup-source.md b/docs/04a-consumer-setup-source.md index 3840a6fb..08b2bc13 100644 --- a/docs/04a-consumer-setup-source.md +++ b/docs/04a-consumer-setup-source.md @@ -45,7 +45,7 @@ After the iniial setup, you can execute `git pull` to get the latest updates and 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:0x10777866547c53cbd69b02c5c76369d7e24e7b10 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 0x10777866547c53cbd69b02c5c76369d7e24e7b10 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=0x10777866547c53cbd69b02c5c76369d7e24e7b10&amount=3' -H 'accept: application/json' -d ''` # Approve the contract to spend 3 saMOR 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,7 +144,7 @@ curl -X 'POST' \ ### Quick and Dirty Sample: -`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=0x10777866547c53cbd69b02c5c76369d7e24e7b10&amount=3' -H 'accept: application/json' -d ''` # approves the smart contract `0x8e19...dE45` to spend 3 saMOR tokens on your behalf `curl -s -X 'GET' 'http://localhost:8082/wallet' -H 'accept: application/json' | jq .address` diff --git a/docs/images/overview.svg b/docs/images/overview.svg index 924e965d..20ee8529 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 +
Existing / Foundational Elements

Arbitrum BlockChain, Token Contract & Smart Contract
MOR_TOKEN_ADDRESS=0x34a285a1b1c166420df5b6630132542923b5b27e
DIAMOND_CONTRACT_ADDRESS=0x10777866547c53cbd69b02c5c76369d7e24e7b10
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..73b83311 100644 --- a/docs/mac-boot-strap.md +++ b/docs/mac-boot-strap.md @@ -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 0x10777866547c53cbd69b02c5c76369d7e24e7b10 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 ``` diff --git a/docs/models-config.json.md b/docs/models-config.json.md new file mode 100644 index 00000000..dee8d26b --- /dev/null +++ b/docs/models-config.json.md @@ -0,0 +1,42 @@ +# Example models config file. Local model configurations are stored in this file +* `rooot_key` (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" and "openai" +* `apiUrl` (required) is the url of the LLM server or model API +* `apiKey` (optional) is the api key for the model +* `cononcurrentSlots` (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 +* The first key (`0x6a...9018`) 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 + +```bash +{ + "0x6a4813e866a48da528c533e706344ea853a1d3f21e37b4c8e7ffd5ff25779018": { + "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" + } +} +``` \ No newline at end of file diff --git a/docs/proxy-router-api-direct.md b/docs/proxy-router-api-direct.md index 94c163d6..70960fac 100644 --- a/docs/proxy-router-api-direct.md +++ b/docs/proxy-router-api-direct.md @@ -21,7 +21,7 @@ Either via the swagger interface http://localhost:8082/swagger/index.html#/walle Approve the contract to spend 3 saMOR 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=0x10777866547c53cbd69b02c5c76369d7e24e7b10&amount=3' -H 'accept: application/json' -d '' ``` ### C. Query the blockchain for various models / providers (Get ModelID) @@ -110,7 +110,7 @@ curl -X 'POST' \ ### Quick and Dirty Sample: -`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=0x10777866547c53cbd69b02c5c76369d7e24e7b10&amount=3' -H 'accept: application/json' -d ''` # approves the smart contract `0x8e19...dE45` to spend 3 saMOR tokens on your behalf `curl -s -X 'GET' 'http://localhost:8082/wallet' -H 'accept: application/json' | jq .address` diff --git a/docs/proxy-router.all.env b/docs/proxy-router.all.env new file mode 100644 index 00000000..9b42faeb --- /dev/null +++ b/docs/proxy-router.all.env @@ -0,0 +1,98 @@ +# 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 keychain on start +APP_RESET_KEYCHAIN=false + +# AI Engine Configurations +# Base URL for OpenAI API (required, must be a valid URL) +OPENAI_BASE_URL= +# API key for OpenAI +OPENAI_API_KEY= + +# 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 +# Set to true to enable subscriptions for blockchain events, otherwise, polling will be used +ETH_NODE_USE_SUBSCRIPTIONS=false +# Interval for polling eth node for new events (defaults to 1s) +ETH_NODE_POLLING_INTERVAL=1s +# Maximum number of reconnect attempts to Ethereum node (defaults to 30) +ETH_NODE_MAX_RECONNECTS=30 + +# Environment Configuration +# Environment for the application (default is "development") +ENVIRONMENT=development + +# Marketplace Configurations +# Diamond contract address (optional, must be a valid Ethereum address) +# TESTNET: 0x10777866547c53cbd69b02c5c76369d7e24e7b10, MAINNET: TBD +DIAMOND_CONTRACT_ADDRESS=0x10777866547c53cbd69b02c5c76369d7e24e7b10 +# MOR token address (optional, must be a valid Ethereum address) +# TESTNET: 0x34a285a1b1c166420df5b6630132542923b5b27e, MAINNET: TBD +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 +# Folder path for log files (optional, 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_CONNECTION=info +LOG_LEVEL_PROXY=info +LOG_LEVEL_SCHEDULER=info +LOG_LEVEL_CONTRACT=debug +LOG_LEVEL_RPC=info +LOG_LEVEL_BADGER=info + +# Proxy Configurations +# Address for the proxy (default is "0.0.0.0:3333") +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 +# Path to models configuration file +MODELS_CONFIG_PATH= +# Comma-separated list of provider addresses allowed to open a session +PROVIDER_ALLOW_LIST= + +# 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") +WEB_ADDRESS=0.0.0.0:8082 +# Public URL of the proxyrouter (falls back to WEB_ADDRESS if empty) +WEB_PUBLIC_URL=http://localhost:8082 \ No newline at end of file diff --git a/docs/source/overview.drawio b/docs/source/overview.drawio index 0b9111c9..f7badae8 100644 --- a/docs/source/overview.drawio +++ b/docs/source/overview.drawio @@ -218,7 +218,7 @@ - + diff --git a/docs/ui-desktop.all.env b/docs/ui-desktop.all.env new file mode 100644 index 00000000..9f3a4027 --- /dev/null +++ b/docs/ui-desktop.all.env @@ -0,0 +1,54 @@ +# Full set of ui-desktop variables based on the ui-desktop/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: 1 +CHAIN_ID= + +# Default currency symbol for sellers (default is "BTC") +DEFAULT_SELLER_CURRENCY=BTC + +# Diamond contract address for the chain (required) +# TESTNET: 0x10777866547c53cbd69b02c5c76369d7e24e7b10, MAINNET: TBD +DIAMOND_ADDRESS=0x10777866547c53cbd69b02c5c76369d7e24e7b10 + +# Display name for the application (optional) +DISPLAY_NAME= + +# 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: TBD +TOKEN_ADDRESS=0x34a285a1b1c166420df5b6630132542923b5b27e + +# Symbol for the primary token (default is "MOR") +SYMBOL_LMR=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= \ 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..31cf6892 100644 --- a/proxy-router/.env.example +++ b/proxy-router/.env.example @@ -1,29 +1,19 @@ -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 +# Contract and Token current as of 11/5/2024 and are TESTNET values +# ...when mainnet release is imminent, update the values to mainnet alignment +# Full ENV details can be found in /docs/proxy-router.full.env -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 - -# MODELS_CONFIG_PATH= +WALLET_PRIVATE_KEY= +DIAMOND_CONTRACT_ADDRESS=0x10777866547c53cbd69b02c5c76369d7e24e7b10 +MOR_TOKEN_ADDRESS=0x34a285a1b1c166420df5b6630132542923b5b27e +EXPLORER_API_URL="https://api-sepolia.arbiscan.io/api" +ETH_NODE_CHAIN_ID=421614 +ETH_NODE_USE_SUBSCRIPTIONS=false +ETH_NODE_ADDRESS= 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 -PROXY_ADDRESS=0.0.0.0:3333 +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 +WEB_ADDRESS=0.0.0.0:8082 +WEB_PUBLIC_URL=http://localhost:8082 \ No newline at end of file diff --git a/proxy-router/.env.example.win b/proxy-router/.env.example.win index f0657406..2758c76c 100644 --- a/proxy-router/.env.example.win +++ b/proxy-router/.env.example.win @@ -1,29 +1,19 @@ -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 +# Contract and Token current as of 11/5/2024 and are TESTNET values +# ...when mainnet release is imminent, update the values to mainnet alignment +# Full ENV details can be found in /docs/proxy-router.full.env -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 - -# MODELS_CONFIG_PATH= +WALLET_PRIVATE_KEY= +DIAMOND_CONTRACT_ADDRESS=0x10777866547c53cbd69b02c5c76369d7e24e7b10 +MOR_TOKEN_ADDRESS=0x34a285a1b1c166420df5b6630132542923b5b27e +EXPLORER_API_URL="https://api-sepolia.arbiscan.io/api" +ETH_NODE_CHAIN_ID=421614 +ETH_NODE_USE_SUBSCRIPTIONS=false +ETH_NODE_ADDRESS= 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 -PROXY_ADDRESS=0.0.0.0:3333 +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 +WEB_ADDRESS=0.0.0.0:8082 +WEB_PUBLIC_URL=http://localhost:8082 \ No newline at end of file diff --git a/proxy-router/.gitignore b/proxy-router/.gitignore index 708c6949..e77303d8 100644 --- a/proxy-router/.gitignore +++ b/proxy-router/.gitignore @@ -8,6 +8,6 @@ logs dist bin -data +data* models-config.json \ 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 index 3effbab8..413f4908 100644 --- a/proxy-router/.version +++ b/proxy-router/.version @@ -1 +1 @@ -VERSION=0.0.3 +VERSION=0.1.0 diff --git a/proxy-router/Dockerfile b/proxy-router/Dockerfile index 1eda590d..6a25774a 100644 --- a/proxy-router/Dockerfile +++ b/proxy-router/Dockerfile @@ -1,24 +1,23 @@ -FROM golang:1.22.3 as base -RUN apt-get update && apt-get install -y procps curl gnupg2 dbus-x11 +FROM golang:1.22.3-alpine as builder -FROM base as builder ARG COMMIT ENV COMMIT=$COMMIT WORKDIR /app COPY . . -RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 ./build.sh +RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 ./build.sh&& \ +cp /bin/sh /app/sh && chmod +x /app/sh FROM scratch WORKDIR /app 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 -COPY --from=busybox /bin /bin -COPY --from=busybox /lib /lib +# COPY --from=builder /usr/bin/dbus-launch /usr/bin/ +# COPY --from=builder /app/.env /app/.env +# 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/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..ea7c4235 100755 --- a/proxy-router/build.sh +++ b/proxy-router/build.sh @@ -8,7 +8,7 @@ if [ -z "$COMMIT" ]; then COMMIT=$(git rev-parse HEAD) fi echo COMMIT=$COMMIT - +go mod tidy go build \ -tags docker \ -ldflags="-s -w \ diff --git a/proxy-router/cmd/main.go b/proxy-router/cmd/main.go index 9e90f0b9..c9ca9d3c 100644 --- a/proxy-router/cmd/main.go +++ b/proxy-router/cmd/main.go @@ -3,38 +3,41 @@ package main import ( "context" "fmt" + "math/big" "net/url" "os" "os/signal" "path/filepath" + "strings" "syscall" "time" "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" + "github.com/ethereum/go-ethereum/common" 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") ) @@ -116,20 +119,22 @@ func start() error { 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) - // } + rpcLog, err := lib.NewLogger(cfg.Log.LevelRPC, cfg.Log.Color, cfg.Log.IsProd, cfg.Log.JSON, mainLogFilePath) + if err != nil { + return err + } + + badgerLog, err := lib.NewLogger(cfg.Log.LevelBadger, cfg.Log.Color, cfg.Log.IsProd, cfg.Log.JSON, mainLogFilePath) + if err != nil { + return err + } defer func() { _ = connLog.Close() _ = proxyLog.Close() _ = log.Close() + _ = rpcLog.Close() + _ = badgerLog.Close() }() appLog.Infof("proxy-router %s", config.BuildVersion) @@ -182,14 +187,45 @@ 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, log) + 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) } + 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) publicUrl, err := url.Parse(cfg.Web.PublicUrl) @@ -197,7 +233,7 @@ func start() error { return err } - storage := storages.NewStorage(log, cfg.Proxy.StoragePath) + storage := storages.NewStorage(badgerLog, cfg.Proxy.StoragePath) sessionStorage := storages.NewSessionStorage(storage) var wallet interfaces.Wallet @@ -205,31 +241,55 @@ func start() error { wallet = wlt.NewEnvWallet(*cfg.Marketplace.WalletPrivateKey) log.Warnf("Using env wallet. Private key persistance unavailable") } else { - wallet = wlt.NewKeychainWallet() + wallet = wlt.NewKeychainWallet(keychainStorage) log.Infof("Using keychain wallet") } + var logWatcher contracts.LogWatcher + if cfg.Blockchain.UseSubscriptions { + logWatcher = contracts.NewLogWatcherSubscription(ethClient, cfg.Blockchain.MaxReconnects, log) + appLog.Infof("using websocket log subscription for blockchain events") + } else { + logWatcher = contracts.NewLogWatcherPolling(ethClient, cfg.Blockchain.PollingInterval, cfg.Blockchain.MaxReconnects, log) + appLog.Infof("using polling for blockchain events") + } + modelConfigLoader := config.NewModelConfigLoader(cfg.Proxy.ModelsConfigPath, log) err = modelConfigLoader.Init() if err != nil { log.Warnf("failed to load model config: %s, run with empty", 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) + providerAllowList := []common.Address{} + if cfg.Proxy.ProviderAllowList != "" { + addresses := strings.Split(cfg.Proxy.ProviderAllowList, ",") + for _, address := range addresses { + addr := strings.TrimSpace(address) + providerAllowList = append(providerAllowList, common.HexToAddress(addr)) + } + } + + 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, log) + marketplace := registries.NewMarketplace(*cfg.Marketplace.DiamondContractAddress, ethClient, multicallBackend, log) + sessionRepo := sessionrepo.NewSessionRepositoryCached(sessionStorage, sessionRouter, marketplace) + proxyRouterApi := proxyapi.NewProxySender(chainID, publicUrl, wallet, contractLogStorage, sessionStorage, sessionRepo, log) + blockchainApi := blockchainapi.NewBlockchainService(ethClient, multicallBackend, *cfg.Marketplace.DiamondContractAddress, *cfg.Marketplace.MorTokenAddress, cfg.Blockchain.ExplorerApiUrl, wallet, proxyRouterApi, sessionRepo, providerAllowList, proxyLog, cfg.Blockchain.EthLegacyTx) + proxyRouterApi.SetSessionService(blockchainApi) + aiEngine := aiengine.NewAiEngine(proxyRouterApi, chatStorage, modelConfigLoader, log) - eventListener := blockchainapi.NewEventsListener(ethClient, sessionStorage, sessionRouter, wallet, modelConfigLoader, log) + eventListener := blockchainapi.NewEventsListener(sessionRepo, sessionRouter, wallet, logWatcher, log) + sessionExpiryHandler := blockchainapi.NewSessionExpiryHandler(blockchainApi, sessionStorage, log) blockchainController := blockchainapi.NewBlockchainController(blockchainApi, log) - chatStoragePath := filepath.Join(cfg.Proxy.StoragePath, "chat") - chatStorage := proxyapi.NewChatStorage(chatStoragePath) - proxyController := proxyapi.NewProxyController(proxyRouterApi, aiEngine, chatStorage) + ethConnectionValidator := system.NewEthConnectionValidator(*big.NewInt(int64(cfg.Blockchain.ChainID))) + proxyController := proxyapi.NewProxyController(proxyRouterApi, aiEngine, chatStorage, *cfg.Proxy.StoreChatContext.Bool, *cfg.Proxy.ForwardChatContext.Bool, log) walletController := walletapi.NewWalletController(wallet) - systemController := system.NewSystemController(&cfg, wallet, sysConfig, appStartTime, chainID, log) + systemController := system.NewSystemController(&cfg, wallet, rpcClientStore, sysConfig, appStartTime, chainID, log, ethConnectionValidator) apiBus := apibus.NewApiBus(blockchainController, proxyController, walletController, systemController) httpHandler := httphandlers.CreateHTTPServer(log, apiBus) @@ -243,7 +303,7 @@ func start() error { cancel() }() - proxy := proxyctl.NewProxyCtl(eventListener, wallet, chainID, log, connLog, cfg.Proxy.Address, schedulerLogFactory, sessionStorage, modelConfigLoader, valid, aiEngine) + proxy := proxyctl.NewProxyCtl(eventListener, wallet, chainID, log, connLog, cfg.Proxy.Address, schedulerLogFactory, 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..e4beebfa 100644 --- a/proxy-router/docker-compose.yml +++ b/proxy-router/docker-compose.yml @@ -4,5 +4,5 @@ services: env_file: - .env ports: - - 8080:8080 + - 8082:8082 - 3333:3333 \ No newline at end of file diff --git a/proxy-router/docs/docs.go b/proxy-router/docs/docs.go index bede38e7..ce9b7715 100644 --- a/proxy-router/docs/docs.go +++ b/proxy-router/docs/docs.go @@ -260,6 +260,20 @@ const docTemplate = `{ "models" ], "summary": "Get models list", + "parameters": [ + { + "type": "string", + "description": "Offset", + "name": "offset", + "in": "query" + }, + { + "type": "string", + "description": "Limit", + "name": "limit", + "in": "query" + } + ], "responses": { "200": { "description": "OK", @@ -407,7 +421,7 @@ const docTemplate = `{ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/structs.OpenSessionWithDurationRequest" + "$ref": "#/definitions/structs.OpenSessionWithFailover" } }, { @@ -438,6 +452,20 @@ const docTemplate = `{ "providers" ], "summary": "Get providers list", + "parameters": [ + { + "type": "string", + "description": "Offset", + "name": "offset", + "in": "query" + }, + { + "type": "string", + "description": "Limit", + "name": "limit", + "in": "query" + } + ], "responses": { "200": { "description": "OK", @@ -488,15 +516,6 @@ const docTemplate = `{ "providers" ], "summary": "Deregister Provider", - "parameters": [ - { - "type": "string", - "description": "Provider Address", - "name": "id", - "in": "path", - "required": true - } - ], "responses": { "200": { "description": "OK", @@ -640,98 +659,136 @@ const docTemplate = `{ } }, "/blockchain/sessions": { - "get": { - "description": "Get sessions from blockchain by user or provider", + "post": { + "description": "Sends transaction in blockchain to open a session", + "consumes": [ + "application/json" + ], "produces": [ "application/json" ], "tags": [ "sessions" ], - "summary": "Get Sessions", + "summary": "Open Session with Provider in blockchain", "parameters": [ { - "type": "string", - "description": "Offset", - "name": "offset", - "in": "query" - }, - { - "type": "string", - "description": "Limit", - "name": "limit", - "in": "query" - }, - { - "type": "string", - "description": "Provider address", - "name": "provider", - "in": "query" - }, - { - "type": "string", - "description": "User address", - "name": "user", - "in": "query" + "description": "Open session", + "name": "opensession", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/structs.OpenSessionRequest" + } } ], "responses": { "200": { "description": "OK", "schema": { - "$ref": "#/definitions/structs.SessionsRes" + "$ref": "#/definitions/structs.OpenSessionRes" } } } - }, - "post": { - "description": "Sends transaction in blockchain to open a session", - "consumes": [ + } + }, + "/blockchain/sessions/budget": { + "get": { + "description": "Get todays budget from blockchain", + "produces": [ "application/json" ], + "tags": [ + "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": "Open Session with Provider in blockchain", + "summary": "Get Sessions for Provider", "parameters": [ { - "description": "Open session", - "name": "opensession", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/structs.OpenSessionRequest" - } + "type": "string", + "description": "Offset", + "name": "offset", + "in": "query" + }, + { + "type": "string", + "description": "Limit", + "name": "limit", + "in": "query" + }, + { + "type": "string", + "description": "Provider address", + "name": "provider", + "in": "query", + "required": true } ], "responses": { "200": { "description": "OK", "schema": { - "$ref": "#/definitions/structs.OpenSessionRes" + "$ref": "#/definitions/structs.SessionsRes" } } } } }, - "/blockchain/sessions/budget": { + "/blockchain/sessions/user": { "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": "Offset", + "name": "offset", + "in": "query" + }, + { + "type": "string", + "description": "Limit", + "name": "limit", + "in": "query" + }, + { + "type": "string", + "description": "User address", + "name": "user", + "in": "query", + "required": true + } + ], "responses": { "200": { "description": "OK", "schema": { - "$ref": "#/definitions/structs.BudgetRes" + "$ref": "#/definitions/structs.SessionsRes" } } } @@ -856,7 +913,7 @@ const docTemplate = `{ "application/json" ], "tags": [ - "healthcheck" + "system" ], "summary": "Get Config", "responses": { @@ -869,6 +926,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.ConfigResponse" + } + } + } + }, + "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.ConfigResponse" + } + } + } + } + }, "/files": { "get": { "description": "Returns opened files", @@ -876,7 +985,7 @@ const docTemplate = `{ "application/json" ], "tags": [ - "healthcheck" + "system" ], "summary": "Get files", "responses": { @@ -899,7 +1008,7 @@ const docTemplate = `{ "application/json" ], "tags": [ - "healthcheck" + "system" ], "summary": "Healthcheck example", "responses": { @@ -954,15 +1063,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,13 +1135,105 @@ 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" + "type": "string" + } + } + ], + "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" } } ], @@ -1049,7 +1241,33 @@ const docTemplate = `{ "200": { "description": "OK", "schema": { - "$ref": "#/definitions/proxyapi.ChatCompletionResponse" + "$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.ResultResponse" } } } @@ -1203,71 +1421,32 @@ const docTemplate = `{ } } }, - "morrpcmesssage.SessionRes": { + "genericchatstorage.Chat": { "type": "object", - "required": [ - "approval", - "approvalSig", - "message", - "signature", - "timestamp", - "user" - ], "properties": { - "approval": { + "chatId": { "type": "string" }, - "approvalSig": { - "type": "string" + "createdAt": { + "type": "integer" }, - "message": { - "type": "string" + "isLocal": { + "type": "boolean" }, - "signature": { + "modelId": { "type": "string" }, - "timestamp": { - "type": "integer" - }, - "user": { + "title": { "type": "string" } } }, - "proxyapi.ChatCompletionChoice": { - "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" - } - ] - }, - "index": { - "type": "integer" - }, - "logprobs": { - "$ref": "#/definitions/proxyapi.LogProbs" - }, - "message": { - "$ref": "#/definitions/proxyapi.ChatCompletionMessage" - } - } - }, - "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 +1460,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 +1468,47 @@ const docTemplate = `{ } } }, - "proxyapi.ChatMessageImageURL": { - "type": "object", - "properties": { - "detail": { - "$ref": "#/definitions/proxyapi.ImageURLDetail" - }, - "url": { - "type": "string" - } - } - }, - "proxyapi.ChatMessagePart": { - "type": "object", - "properties": { - "image_url": { - "$ref": "#/definitions/proxyapi.ChatMessageImageURL" - }, - "text": { - "type": "string" - }, - "type": { - "$ref": "#/definitions/proxyapi.ChatMessagePartType" - } - } - }, - "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.ChatHistory": { "type": "object", - "required": [ - "bidId", - "provider", - "providerUrl", - "spend", - "user" - ], "properties": { - "bidId": { - "type": "string" - }, - "provider": { - "type": "string" + "isLocal": { + "type": "boolean" }, - "providerUrl": { - "type": "string" + "messages": { + "type": "array", + "items": { + "$ref": "#/definitions/genericchatstorage.ChatMessage" + } }, - "spend": { + "modelId": { "type": "string" }, - "user": { + "title": { "type": "string" } } }, - "proxyapi.LogProb": { + "genericchatstorage.ChatMessage": { "type": "object", "properties": { - "bytes": { - "description": "Omitting the field if it is null", - "type": "array", - "items": { - "type": "integer" - } + "isImageContent": { + "type": "boolean" }, - "logprob": { - "type": "number" + "prompt": { + "$ref": "#/definitions/genericchatstorage.OpenAiCompletionRequest" + }, + "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 +1534,7 @@ const docTemplate = `{ "messages": { "type": "array", "items": { - "$ref": "#/definitions/proxyapi.ChatCompletionMessage" + "$ref": "#/definitions/genericchatstorage.ChatCompletionMessage" } }, "model": { @@ -1479,7 +1547,7 @@ const docTemplate = `{ "type": "number" }, "response_format": { - "$ref": "#/definitions/proxyapi.ChatCompletionResponseFormat" + "$ref": "#/definitions/genericchatstorage.ChatCompletionResponseFormat" }, "seed": { "type": "integer" @@ -1511,57 +1579,92 @@ const docTemplate = `{ } } }, - "proxyapi.TopLogProbs": { + "morrpcmesssage.SessionRes": { "type": "object", + "required": [ + "approval", + "approvalSig", + "message", + "signature", + "timestamp", + "user" + ], "properties": { - "bytes": { - "type": "array", - "items": { - "type": "integer" - } + "approval": { + "type": "string" }, - "logprob": { - "type": "number" + "approvalSig": { + "type": "string" + }, + "message": { + "type": "string" + }, + "signature": { + "type": "string" + }, + "timestamp": { + "type": "integer" }, - "token": { + "user": { "type": "string" } } }, - "proxyapi.Usage": { + "proxyapi.InitiateSessionReq": { "type": "object", + "required": [ + "bidId", + "provider", + "providerUrl", + "spend", + "user" + ], "properties": { - "completion_tokens": { - "type": "integer" + "bidId": { + "type": "string" }, - "prompt_tokens": { - "type": "integer" + "provider": { + "type": "string" }, - "total_tokens": { - "type": "integer" + "providerUrl": { + "type": "string" + }, + "spend": { + "type": "string" + }, + "user": { + "type": "string" } } }, - "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": { @@ -1802,6 +1905,17 @@ const docTemplate = `{ } } }, + "structs.OpenSessionWithFailover": { + "type": "object", + "properties": { + "failover": { + "type": "boolean" + }, + "sessionDuration": { + "type": "string" + } + } + }, "structs.Provider": { "type": "object", "properties": { @@ -2091,6 +2205,20 @@ const docTemplate = `{ "type": "string" } } + }, + "system.SetEthNodeURLReq": { + "type": "object", + "required": [ + "urls" + ], + "properties": { + "urls": { + "type": "array", + "items": { + "type": "string" + } + } + } } }, "externalDocs": { diff --git a/proxy-router/docs/swagger.json b/proxy-router/docs/swagger.json index 45a112c9..895f45a6 100644 --- a/proxy-router/docs/swagger.json +++ b/proxy-router/docs/swagger.json @@ -253,6 +253,20 @@ "models" ], "summary": "Get models list", + "parameters": [ + { + "type": "string", + "description": "Offset", + "name": "offset", + "in": "query" + }, + { + "type": "string", + "description": "Limit", + "name": "limit", + "in": "query" + } + ], "responses": { "200": { "description": "OK", @@ -400,7 +414,7 @@ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/structs.OpenSessionWithDurationRequest" + "$ref": "#/definitions/structs.OpenSessionWithFailover" } }, { @@ -431,6 +445,20 @@ "providers" ], "summary": "Get providers list", + "parameters": [ + { + "type": "string", + "description": "Offset", + "name": "offset", + "in": "query" + }, + { + "type": "string", + "description": "Limit", + "name": "limit", + "in": "query" + } + ], "responses": { "200": { "description": "OK", @@ -481,15 +509,6 @@ "providers" ], "summary": "Deregister Provider", - "parameters": [ - { - "type": "string", - "description": "Provider Address", - "name": "id", - "in": "path", - "required": true - } - ], "responses": { "200": { "description": "OK", @@ -633,98 +652,136 @@ } }, "/blockchain/sessions": { - "get": { - "description": "Get sessions from blockchain by user or provider", + "post": { + "description": "Sends transaction in blockchain to open a session", + "consumes": [ + "application/json" + ], "produces": [ "application/json" ], "tags": [ "sessions" ], - "summary": "Get Sessions", + "summary": "Open Session with Provider in blockchain", "parameters": [ { - "type": "string", - "description": "Offset", - "name": "offset", - "in": "query" - }, - { - "type": "string", - "description": "Limit", - "name": "limit", - "in": "query" - }, - { - "type": "string", - "description": "Provider address", - "name": "provider", - "in": "query" - }, - { - "type": "string", - "description": "User address", - "name": "user", - "in": "query" + "description": "Open session", + "name": "opensession", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/structs.OpenSessionRequest" + } } ], "responses": { "200": { "description": "OK", "schema": { - "$ref": "#/definitions/structs.SessionsRes" + "$ref": "#/definitions/structs.OpenSessionRes" } } } - }, - "post": { - "description": "Sends transaction in blockchain to open a session", - "consumes": [ + } + }, + "/blockchain/sessions/budget": { + "get": { + "description": "Get todays budget from blockchain", + "produces": [ "application/json" ], + "tags": [ + "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": "Open Session with Provider in blockchain", + "summary": "Get Sessions for Provider", "parameters": [ { - "description": "Open session", - "name": "opensession", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/structs.OpenSessionRequest" - } + "type": "string", + "description": "Offset", + "name": "offset", + "in": "query" + }, + { + "type": "string", + "description": "Limit", + "name": "limit", + "in": "query" + }, + { + "type": "string", + "description": "Provider address", + "name": "provider", + "in": "query", + "required": true } ], "responses": { "200": { "description": "OK", "schema": { - "$ref": "#/definitions/structs.OpenSessionRes" + "$ref": "#/definitions/structs.SessionsRes" } } } } }, - "/blockchain/sessions/budget": { + "/blockchain/sessions/user": { "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": "Offset", + "name": "offset", + "in": "query" + }, + { + "type": "string", + "description": "Limit", + "name": "limit", + "in": "query" + }, + { + "type": "string", + "description": "User address", + "name": "user", + "in": "query", + "required": true + } + ], "responses": { "200": { "description": "OK", "schema": { - "$ref": "#/definitions/structs.BudgetRes" + "$ref": "#/definitions/structs.SessionsRes" } } } @@ -849,7 +906,7 @@ "application/json" ], "tags": [ - "healthcheck" + "system" ], "summary": "Get Config", "responses": { @@ -862,6 +919,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.ConfigResponse" + } + } + } + }, + "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.ConfigResponse" + } + } + } + } + }, "/files": { "get": { "description": "Returns opened files", @@ -869,7 +978,7 @@ "application/json" ], "tags": [ - "healthcheck" + "system" ], "summary": "Get files", "responses": { @@ -892,7 +1001,7 @@ "application/json" ], "tags": [ - "healthcheck" + "system" ], "summary": "Healthcheck example", "responses": { @@ -947,15 +1056,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,13 +1128,105 @@ "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" + "type": "string" + } + } + ], + "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" } } ], @@ -1042,7 +1234,33 @@ "200": { "description": "OK", "schema": { - "$ref": "#/definitions/proxyapi.ChatCompletionResponse" + "$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.ResultResponse" } } } @@ -1196,71 +1414,32 @@ } } }, - "morrpcmesssage.SessionRes": { + "genericchatstorage.Chat": { "type": "object", - "required": [ - "approval", - "approvalSig", - "message", - "signature", - "timestamp", - "user" - ], "properties": { - "approval": { + "chatId": { "type": "string" }, - "approvalSig": { - "type": "string" + "createdAt": { + "type": "integer" }, - "message": { - "type": "string" + "isLocal": { + "type": "boolean" }, - "signature": { + "modelId": { "type": "string" }, - "timestamp": { - "type": "integer" - }, - "user": { + "title": { "type": "string" } } }, - "proxyapi.ChatCompletionChoice": { - "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" - } - ] - }, - "index": { - "type": "integer" - }, - "logprobs": { - "$ref": "#/definitions/proxyapi.LogProbs" - }, - "message": { - "$ref": "#/definitions/proxyapi.ChatCompletionMessage" - } - } - }, - "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 +1453,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 +1461,47 @@ } } }, - "proxyapi.ChatMessageImageURL": { - "type": "object", - "properties": { - "detail": { - "$ref": "#/definitions/proxyapi.ImageURLDetail" - }, - "url": { - "type": "string" - } - } - }, - "proxyapi.ChatMessagePart": { - "type": "object", - "properties": { - "image_url": { - "$ref": "#/definitions/proxyapi.ChatMessageImageURL" - }, - "text": { - "type": "string" - }, - "type": { - "$ref": "#/definitions/proxyapi.ChatMessagePartType" - } - } - }, - "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.ChatHistory": { "type": "object", - "required": [ - "bidId", - "provider", - "providerUrl", - "spend", - "user" - ], "properties": { - "bidId": { - "type": "string" - }, - "provider": { - "type": "string" + "isLocal": { + "type": "boolean" }, - "providerUrl": { - "type": "string" + "messages": { + "type": "array", + "items": { + "$ref": "#/definitions/genericchatstorage.ChatMessage" + } }, - "spend": { + "modelId": { "type": "string" }, - "user": { + "title": { "type": "string" } } }, - "proxyapi.LogProb": { + "genericchatstorage.ChatMessage": { "type": "object", "properties": { - "bytes": { - "description": "Omitting the field if it is null", - "type": "array", - "items": { - "type": "integer" - } + "isImageContent": { + "type": "boolean" }, - "logprob": { - "type": "number" + "prompt": { + "$ref": "#/definitions/genericchatstorage.OpenAiCompletionRequest" + }, + "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 +1527,7 @@ "messages": { "type": "array", "items": { - "$ref": "#/definitions/proxyapi.ChatCompletionMessage" + "$ref": "#/definitions/genericchatstorage.ChatCompletionMessage" } }, "model": { @@ -1472,7 +1540,7 @@ "type": "number" }, "response_format": { - "$ref": "#/definitions/proxyapi.ChatCompletionResponseFormat" + "$ref": "#/definitions/genericchatstorage.ChatCompletionResponseFormat" }, "seed": { "type": "integer" @@ -1504,57 +1572,92 @@ } } }, - "proxyapi.TopLogProbs": { + "morrpcmesssage.SessionRes": { "type": "object", + "required": [ + "approval", + "approvalSig", + "message", + "signature", + "timestamp", + "user" + ], "properties": { - "bytes": { - "type": "array", - "items": { - "type": "integer" - } + "approval": { + "type": "string" }, - "logprob": { - "type": "number" + "approvalSig": { + "type": "string" + }, + "message": { + "type": "string" + }, + "signature": { + "type": "string" + }, + "timestamp": { + "type": "integer" }, - "token": { + "user": { "type": "string" } } }, - "proxyapi.Usage": { + "proxyapi.InitiateSessionReq": { "type": "object", + "required": [ + "bidId", + "provider", + "providerUrl", + "spend", + "user" + ], "properties": { - "completion_tokens": { - "type": "integer" + "bidId": { + "type": "string" }, - "prompt_tokens": { - "type": "integer" + "provider": { + "type": "string" }, - "total_tokens": { - "type": "integer" + "providerUrl": { + "type": "string" + }, + "spend": { + "type": "string" + }, + "user": { + "type": "string" } } }, - "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": { @@ -1795,6 +1898,17 @@ } } }, + "structs.OpenSessionWithFailover": { + "type": "object", + "properties": { + "failover": { + "type": "boolean" + }, + "sessionDuration": { + "type": "string" + } + } + }, "structs.Provider": { "type": "object", "properties": { @@ -2084,6 +2198,20 @@ "type": "string" } } + }, + "system.SetEthNodeURLReq": { + "type": "object", + "required": [ + "urls" + ], + "properties": { + "urls": { + "type": "array", + "items": { + "type": "string" + } + } + } } }, "externalDocs": { diff --git a/proxy-router/docs/swagger.yaml b/proxy-router/docs/swagger.yaml index ee876b25..845f49a5 100644 --- a/proxy-router/docs/swagger.yaml +++ b/proxy-router/docs/swagger.yaml @@ -11,56 +11,23 @@ definitions: name: type: string type: object - morrpcmesssage.SessionRes: + genericchatstorage.Chat: properties: - approval: - type: string - approvalSig: - type: string - message: + chatId: 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 +42,38 @@ 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: - properties: - type: - type: string - type: object - proxyapi.ChatMessageImageURL: - properties: - detail: - $ref: '#/definitions/proxyapi.ImageURLDetail' - url: - type: string - type: object - proxyapi.ChatMessagePart: + genericchatstorage.ChatCompletionResponseFormat: 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 + 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 +97,7 @@ definitions: type: integer messages: items: - $ref: '#/definitions/proxyapi.ChatCompletionMessage' + $ref: '#/definitions/genericchatstorage.ChatCompletionMessage' type: array model: type: string @@ -219,7 +106,7 @@ definitions: presence_penalty: type: number response_format: - $ref: '#/definitions/proxyapi.ChatCompletionResponseFormat' + $ref: '#/definitions/genericchatstorage.ChatCompletionResponseFormat' seed: type: integer stop: @@ -243,38 +130,64 @@ definitions: user: type: string type: object - proxyapi.TopLogProbs: + morrpcmesssage.SessionRes: properties: - bytes: - items: - type: integer - type: array - logprob: - type: number - token: + approval: type: string - type: object - proxyapi.Usage: - properties: - completion_tokens: - type: integer - prompt_tokens: - type: integer - total_tokens: + approvalSig: + type: string + message: + type: string + signature: + type: string + timestamp: type: integer + user: + type: string + required: + - approval + - approvalSig + - message + - signature + - timestamp + - user type: object - structs.AllowanceRes: + proxyapi.InitiateSessionReq: properties: - allowance: - example: "100000000" + bidId: + type: string + provider: + type: string + providerUrl: type: string + spend: + type: string + user: + type: string + required: + - bidId + - provider + - providerUrl + - spend + - user type: object - structs.AmountReq: + proxyapi.ResultResponse: properties: - amount: + result: + type: boolean + type: object + proxyapi.UpdateChatTitleReq: + properties: + title: type: string required: - - amount + - title + type: object + structs.AllowanceRes: + properties: + allowance: + example: "100000000" + type: string type: object structs.BalanceRes: properties: @@ -440,6 +353,13 @@ definitions: sessionDuration: type: string type: object + structs.OpenSessionWithFailover: + properties: + failover: + type: boolean + sessionDuration: + type: string + type: object structs.Provider: properties: address: @@ -630,6 +550,15 @@ definitions: version: type: string type: object + system.SetEthNodeURLReq: + properties: + urls: + items: + type: string + type: array + required: + - urls + type: object externalDocs: description: OpenAPI url: https://swagger.io/resources/open-api/ @@ -796,6 +725,15 @@ paths: /blockchain/models: get: description: Get models list from blokchain + parameters: + - description: Offset + in: query + name: offset + type: string + - description: Limit + in: query + name: limit + type: string produces: - application/json responses: @@ -893,7 +831,7 @@ paths: name: opensession required: true schema: - $ref: '#/definitions/structs.OpenSessionWithDurationRequest' + $ref: '#/definitions/structs.OpenSessionWithFailover' - description: Model ID in: path name: id @@ -912,6 +850,15 @@ paths: /blockchain/providers: get: description: Get providers list from blokchain + parameters: + - description: Offset + in: query + name: offset + type: string + - description: Limit + in: query + name: limit + type: string produces: - application/json responses: @@ -944,12 +891,6 @@ paths: - providers /blockchain/providers/{id}: delete: - parameters: - - description: Provider Address - in: path - name: id - required: true - type: string produces: - application/json responses: @@ -1047,35 +988,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 +1060,60 @@ paths: summary: Get Todays Budget tags: - sessions + /blockchain/sessions/provider: + get: + description: Get sessions from blockchain by 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 + 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: Offset + in: query + name: offset + type: string + - description: Limit + in: query + name: limit + type: string + - description: User address + in: query + name: user + required: true + 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 +1161,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.ConfigResponse' + 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.ConfigResponse' + summary: Set Eth Node URLs + tags: + - system /files: get: description: Returns opened files @@ -1210,7 +1210,7 @@ paths: type: array summary: Get files tags: - - healthcheck + - system /healthcheck: get: description: do ping @@ -1223,17 +1223,11 @@ paths: $ref: '#/definitions/system.HealthCheckResponse' summary: Healthcheck example tags: - - healthcheck + - system /proxy/sessions/{id}/providerClaim: post: description: Claim provider balance from session parameters: - - description: Claim - in: body - name: claim - required: true - schema: - $ref: '#/definitions/structs.AmountReq' - description: Session ID in: path name: id @@ -1302,22 +1296,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' + type: string 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: 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..633716b0 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,246 +27,38 @@ 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 - } - 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) - } - 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 err != nil { - return nil, fmt.Errorf("callback failed: %v", err) - } + var ok bool + engine, ok = ApiAdapterFactory(modelConfig.ApiType, modelConfig.ModelName, modelConfig.ApiURL, modelConfig.ApiKey, a.log) + if !ok { + return nil, fmt.Errorf("api adapter not found: %s", modelConfig.ApiType) } + } else { + // remote model + engine = &RemoteModel{sessionID: sessionID, service: a.service} } - if err := scanner.Err(); err != nil { - return nil, fmt.Errorf("error reading stream: %v", err) + if storeChatContext { + engine = NewHistory(engine, a.storage, chatID, modelID, forwardChatContext, a.log) } - return nil, err + return engine, nil } func (a *AiEngine) GetModelsConfig() ([]string, []config.ModelConfig) { diff --git a/proxy-router/internal/aiengine/factory.go b/proxy-router/internal/aiengine/factory.go new file mode 100644 index 00000000..820f82e3 --- /dev/null +++ b/proxy-router/internal/aiengine/factory.go @@ -0,0 +1,15 @@ +package aiengine + +import "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/lib" + +func ApiAdapterFactory(apiType string, modelName string, url string, apikey string, 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 + } + 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/interfaces.go b/proxy-router/internal/aiengine/interfaces.go index 8b454dfe..9424a252 100644 --- a/proxy-router/internal/aiengine/interfaces.go +++ b/proxy-router/internal/aiengine/interfaces.go @@ -1,34 +1,13 @@ package aiengine import ( - "net/http" -) - -type ResponderFlusher interface { - http.ResponseWriter - http.Flusher -} - -type ProdiaGenerationResult struct { - Job string `json:"job"` - Status string `json:"status"` - ImageUrl string `json:"imageUrl" binding:"omitempty"` -} + "context" -type ProdiaGenerationRequest struct { - Model string `json:"model"` - Prompt string `json:"prompt"` - ApiUrl string `json:"apiUrl"` - ApiKey string `json:"apiKey"` -} - -type CompletionCallback func(completion interface{}) error - -type ProdiaImageGenerationCallback func(completion *ProdiaGenerationResult) error + "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/chatstorage/genericchatstorage" + "github.com/sashabaranov/go-openai" +) -type LocalModel struct { - Id string - Name string - Model string - ApiType string +type AIEngineStream interface { + Prompt(ctx context.Context, prompt *openai.ChatCompletionRequest, cb genericchatstorage.CompletionCallback) error + ApiType() string } diff --git a/proxy-router/internal/aiengine/openai.go b/proxy-router/internal/aiengine/openai.go new file mode 100644 index 00000000..cf1edb3b --- /dev/null +++ b/proxy-router/internal/aiengine/openai.go @@ -0,0 +1,138 @@ +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() + + contentType := resp.Header.Get(c.HEADER_CONTENT_TYPE) + if contentType == c.CONTENT_TYPE_EVENT_STREAM { + 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) { + a.log.Debugf("reached end of the response") + 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 +} + +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..782bf335 --- /dev/null +++ b/proxy-router/internal/aiengine/prodia_sd.go @@ -0,0 +1,115 @@ +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 + } + + s.log.Debugf("payload: %s", payload) + + 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 + } + + s.log.Debugf("response: %s", response) + + 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..ff856100 --- /dev/null +++ b/proxy-router/internal/aiengine/prodia_sdxl.go @@ -0,0 +1,113 @@ +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 + } + + s.log.Debugf("response: %s", response) + + 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/remote.go b/proxy-router/internal/aiengine/remote.go new file mode 100644 index 00000000..86088600 --- /dev/null +++ b/proxy-router/internal/aiengine/remote.go @@ -0,0 +1,29 @@ +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) +} + +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..99e5e568 --- /dev/null +++ b/proxy-router/internal/aiengine/structs.go @@ -0,0 +1,8 @@ +package aiengine + +type LocalModel struct { + Id string + Name string + Model string + ApiType string +} diff --git a/proxy-router/internal/blockchainapi/controller.go b/proxy-router/internal/blockchainapi/controller.go index e3666759..fb115866 100644 --- a/proxy-router/internal/blockchainapi/controller.go +++ b/proxy-router/internal/blockchainapi/controller.go @@ -2,7 +2,6 @@ package blockchainapi import ( "crypto/rand" - "fmt" "math/big" "net/http" @@ -60,7 +59,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 +85,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 +105,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}) - return - } - - _, 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.ClaimProviderBalance(ctx, params.ID.Hash, amount) + txHash, err := c.service.ClaimProviderBalance(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 } @@ -141,13 +134,31 @@ func (c *BlockchainController) claimProviderBalance(ctx *gin.Context) { // @Description Get providers list from blokchain // @Tags providers // @Produce json -// @Success 200 {object} structs.ProvidersRes +// @Param offset query string false "Offset" +// @Param limit query string false "Limit" +// @Success 200 {object} structs.ProvidersRes // @Router /blockchain/providers [get] func (c *BlockchainController) getAllProviders(ctx *gin.Context) { - providers, err := c.service.GetAllProviders(ctx) + offset, limit, err := getOffsetLimitNoDefault(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) + } + 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 } @@ -226,21 +237,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) 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) 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 } @@ -262,14 +273,21 @@ func (c *BlockchainController) getActiveBidsByProvider(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.GetActiveBidsByProvider(ctx, params.ID.Address) + offset, limit, err := getOffsetLimit(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.GetActiveBidsByProvider(ctx, params.ID.Address, offset, limit) + if err != nil { + c.log.Error(err) + ctx.JSON(http.StatusInternalServerError, structs.ErrRes{Error: err.Error()}) return } @@ -283,13 +301,30 @@ func (c *BlockchainController) getActiveBidsByProvider(ctx *gin.Context) { // @Description Get models list from blokchain // @Tags models // @Produce json -// @Success 200 {object} structs.ModelsRes +// @Param offset query string false "Offset" +// @Param limit query string false "Limit" +// @Success 200 {object} structs.ModelsRes // @Router /blockchain/models [get] func (c *BlockchainController) getAllModels(ctx *gin.Context) { - models, err := c.service.GetAllModels(ctx) + offset, limit, err := getOffsetLimitNoDefault(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) + } 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 } @@ -313,21 +348,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) 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) 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 } @@ -349,14 +384,21 @@ func (c *BlockchainController) getActiveBidsByModel(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) + if err != nil { + c.log.Error(err) + ctx.JSON(http.StatusBadRequest, structs.ErrRes{Error: err.Error()}) return } - bids, err := c.service.GetActiveBidsByModel(ctx, params.ID.Hash) + bids, err := c.service.GetActiveBidsByModel(ctx, params.ID.Hash, offset, 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 } @@ -376,7 +418,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 +443,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 +471,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 +501,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 +530,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()) 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 +559,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 +587,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 +607,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(), 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 +633,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 +662,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 +679,111 @@ 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) { +// @Param offset query string false "Offset" +// @Param limit query string false "Limit" +// @Param user query string true "User address" +// @Success 200 {object} structs.SessionsRes +// @Router /blockchain/sessions/user [get] +func (c *BlockchainController) getSessionsForUser(ctx *gin.Context) { offset, limit, err := getOffsetLimit(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 } - hasUser := req.User != lib.Address{} - hasProvider := req.Provider != lib.Address{} + sessions, err := c.service.GetSessions(ctx, req.User.Address, common.Address{}, offset, limit) + if err != nil { + c.log.Error(err) + ctx.JSON(http.StatusInternalServerError, structs.ErrRes{Error: err.Error()}) + return + } + + 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 offset query string false "Offset" +// @Param limit query string false "Limit" +// @Param user query string true "User address" +// @Success 200 {object} structs.SessionsRes +// @Router /blockchain/sessions/user/ids [get] +func (c *BlockchainController) getSessionsIdsForUser(ctx *gin.Context) { + offset, limit, err := getOffsetLimit(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) 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 offset query string false "Offset" +// @Param limit query string false "Limit" +// @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, err := getOffsetLimit(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) + if err != nil { + c.log.Error(err) + ctx.JSON(http.StatusInternalServerError, structs.ErrRes{Error: err.Error()}) return } @@ -699,7 +803,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 +823,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 +843,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 +864,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 +893,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 +921,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 +941,13 @@ func (c *BlockchainController) createProvider(ctx *gin.Context) { // @Summary Deregister Provider // @Tags providers // @Produce json -// @Param id path string true "Provider Address" // @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) - 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) + txHash, err := c.service.DeregisterProdiver(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 } @@ -873,7 +968,7 @@ 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 +978,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 +990,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 +1012,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 +1040,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 +1048,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 +1069,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 } @@ -1010,6 +1105,17 @@ func getOffsetLimit(ctx *gin.Context) (offset *big.Int, limit uint8, err error) return paging.Offset.Unpack(), paging.Limit, nil } +func getOffsetLimitNoDefault(ctx *gin.Context) (offset *big.Int, limit uint8, err error) { + var paging structs.QueryOffsetLimitNoDefault + + err = ctx.ShouldBindQuery(&paging) + if err != nil { + return nil, 0, err + } + + return paging.Offset.Unpack(), paging.Limit, nil +} + func getPageLimit(ctx *gin.Context) (page uint64, limit uint8, err error) { var paging structs.QueryPageLimit diff --git a/proxy-router/internal/blockchainapi/event_listener.go b/proxy-router/internal/blockchainapi/event_listener.go index 606bd96c..9d54d6ba 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.Logger + 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.Logger) *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/mappers.go b/proxy-router/internal/blockchainapi/mappers.go index 139fbe69..15312db2 100644 --- a/proxy-router/internal/blockchainapi/mappers.go +++ b/proxy-router/internal/blockchainapi/mappers.go @@ -3,14 +3,16 @@ 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/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 +20,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 +32,68 @@ 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}, } } diff --git a/proxy-router/internal/blockchainapi/rating.go b/proxy-router/internal/blockchainapi/rating.go index 46c63562..eedf5c73 100644 --- a/proxy-router/internal/blockchainapi/rating.go +++ b/proxy-router/internal/blockchainapi/rating.go @@ -4,16 +4,18 @@ 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" + 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" ) -func rateBids(bidIds [][32]byte, bids []m.Bid, pmStats []m.ProviderModelStats, mStats m.ModelStats, log lib.ILogger) []structs.ScoredBid { +func rateBids(bidIds [][32]byte, bids []m.IBidStorageBid, pmStats []s.IStatsStorageProviderModelStats, provider []pr.IProviderStorageProvider, mStats *s.IStatsStorageModelStats, log lib.ILogger) []structs.ScoredBid { scoredBids := make([]structs.ScoredBid, len(bids)) for i := range bids { - score := getScore(bids[i], pmStats[i], mStats) + score := getScore(bids[i], pmStats[i], provider[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 @@ -22,7 +24,7 @@ func rateBids(bidIds [][32]byte, bids []m.Bid, pmStats []m.ProviderModelStats, m Bid: structs.Bid{ Id: bidIds[i], Provider: bids[i].Provider, - ModelAgentId: bids[i].ModelAgentId, + ModelAgentId: bids[i].ModelId, PricePerSecond: &lib.BigInt{Int: *(bids[i].PricePerSecond)}, Nonce: &lib.BigInt{Int: *(bids[i].Nonce)}, CreatedAt: &lib.BigInt{Int: *(bids[i].CreatedAt)}, @@ -40,20 +42,22 @@ func rateBids(bidIds [][32]byte, bids []m.Bid, pmStats []m.ProviderModelStats, m 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 +func getScore(bid m.IBidStorageBid, pmStats s.IStatsStorageProviderModelStats, pr pr.IProviderStorageProvider, mStats *s.IStatsStorageModelStats) float64 { + tpsWeight, ttftWeight, durationWeight, successWeight, stakeWeight := 0.24, 0.08, 0.24, 0.32, 0.12 count := int64(mStats.Count) + minStake := int64(0.2 * math.Pow10(18)) // 0.2 MOR 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) + stakeScore := stakeWeight * normMinMax(pr.Stake.Int64(), minStake, 10*minStake) priceFloatDecimal, _ := bid.PricePerSecond.Float64() priceFloat := priceFloatDecimal / math.Pow10(18) - result := (tpsScore + ttftScore + durationScore + successScore) / priceFloat + result := (tpsScore + ttftScore + durationScore + successScore + stakeScore) / priceFloat return result } @@ -66,7 +70,7 @@ func ratioScore(num, denom uint32) float64 { } // normZIndex normalizes the value using z-index -func normZIndex(pmMean int64, mSD m.LibSDSD, obsNum int64) float64 { +func normZIndex(pmMean int64, mSD s.LibSDSD, obsNum int64) float64 { sd := getSD(mSD, obsNum) if sd == 0 { return 0 @@ -81,11 +85,11 @@ func normRange(input float64, normRange float64) float64 { return cutRange01((input + normRange) / (2.0 * normRange)) } -func getSD(sd m.LibSDSD, obsNum int64) float64 { +func getSD(sd s.LibSDSD, obsNum int64) float64 { return math.Sqrt(getVariance(sd, obsNum)) } -func getVariance(sd m.LibSDSD, obsNum int64) float64 { +func getVariance(sd s.LibSDSD, obsNum int64) float64 { if obsNum <= 1 { return 0 } @@ -101,3 +105,10 @@ func cutRange01(val float64) float64 { } return val } + +func normMinMax(val, min, max int64) float64 { + if max == min { + return 0 + } + return float64(val-min) / float64(max-min) +} diff --git a/proxy-router/internal/blockchainapi/rating_mock.go b/proxy-router/internal/blockchainapi/rating_mock.go index 31ca684e..19a9be82 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, ModelStats) { 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 := ModelStats{ + 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..7e4c03a0 100644 --- a/proxy-router/internal/blockchainapi/rating_test.go +++ b/proxy-router/internal/blockchainapi/rating_test.go @@ -4,8 +4,8 @@ import ( "math" "testing" - m "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/contracts/marketplace" "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/lib" + s "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/repositories/contracts/bindings/sessionrouter" "github.com/stretchr/testify/require" ) @@ -21,7 +21,7 @@ func TestRating(t *testing.T) { func TestGetScoreZeroObservations(t *testing.T) { _, bids, _, _ := sampleDataTPS() - score := getScore(bids[0], m.ProviderModelStats{}, m.ModelStats{}) + score := getScore(bids[0], s.IStatsStorageProviderModelStats{}, ModelStats{}) if math.IsNaN(score) { require.Fail(t, "score is NaN") } @@ -29,17 +29,17 @@ func TestGetScoreZeroObservations(t *testing.T) { func TestGetScoreSingleObservation(t *testing.T) { _, bids, _, _ := sampleDataTPS() - pmStats := m.ProviderModelStats{ - TpsScaled1000: m.LibSDSD{Mean: 1000, SqSum: 0}, - TtftMs: m.LibSDSD{Mean: 1000, SqSum: 0}, + pmStats := s.IStatsStorageProviderModelStats{ + TpsScaled1000: s.LibSDSD{Mean: 1000, SqSum: 0}, + TtftMs: s.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}, + mStats := ModelStats{ + TpsScaled1000: s.LibSDSD{Mean: 1000, SqSum: 0}, + TtftMs: s.LibSDSD{Mean: 1000, SqSum: 0}, + TotalDuration: s.LibSDSD{Mean: 1000, SqSum: 0}, Count: 1, } score := getScore(bids[0], pmStats, mStats) diff --git a/proxy-router/internal/blockchainapi/service.go b/proxy-router/internal/blockchainapi/service.go index fd0b010e..e51d305a 100644 --- a/proxy-router/internal/blockchainapi/service.go +++ b/proxy-router/internal/blockchainapi/service.go @@ -7,14 +7,18 @@ import ( "math/big" "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" + 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" + 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" "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/repositories/registries" - "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/storages" + sessionrepo "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/repositories/session" "github.com/gin-gonic/gin" "github.com/ethereum/go-ethereum" @@ -22,36 +26,38 @@ import ( "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" ) type BlockchainService struct { - ethClient *ethclient.Client + ethClient i.EthClient providerRegistry *registries.ProviderRegistry modelRegistry *registries.ModelRegistry marketplace *registries.Marketplace sessionRouter *registries.SessionRouter morToken *registries.MorToken explorerClient *ExplorerClient - sessionStorage *storages.SessionStorage + sessionRepo *sessionrepo.SessionRepositoryCached proxyService *proxyapi.ProxyServiceSender diamonContractAddr common.Address + providerAllowList []common.Address + 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") @@ -67,20 +73,22 @@ var ( ) 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, + privateKey i.PrKeyProvider, proxyService *proxyapi.ProxyServiceSender, + sessionRepo *sessionrepo.SessionRepositoryCached, + providerAllowList []common.Address, log 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) + providerRegistry := registries.NewProviderRegistry(diamonContractAddr, ethClient, mc, log) + modelRegistry := registries.NewModelRegistry(diamonContractAddr, ethClient, mc, log) + marketplace := registries.NewMarketplace(diamonContractAddr, ethClient, mc, log) + sessionRouter := registries.NewSessionRouter(diamonContractAddr, ethClient, mc, log) morToken := registries.NewMorToken(morTokenAddr, ethClient, log) explorerClient := NewExplorerClient(explorerApiUrl, morTokenAddr.String()) @@ -95,8 +103,9 @@ func NewBlockchainService( morToken: morToken, explorerClient: explorerClient, proxyService: proxyService, - sessionStorage: sessionStorage, diamonContractAddr: diamonContractAddr, + providerAllowList: providerAllowList, + sessionRepo: sessionRepo, log: log, } } @@ -111,18 +120,16 @@ 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) ([]*structs.Provider, error) { + addrs, providers, err := s.providerRegistry.GetProviders(ctx, offset, limit) + if err != nil { + return nil, err } - return result, nil + return mapProviders(addrs, providers), nil } func (s *BlockchainService) GetAllModels(ctx context.Context) ([]*structs.Model, error) { @@ -131,22 +138,16 @@ 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) ([]*structs.Model, error) { + ids, models, err := s.modelRegistry.GetModels(ctx, offset, limit) + 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) { @@ -167,8 +168,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) ([]*structs.Bid, error) { + ids, bids, err := s.marketplace.GetActiveBidsByModel(ctx, modelId, offset, limit) if err != nil { return nil, err } @@ -176,8 +177,8 @@ 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) GetActiveBidsByProvider(ctx context.Context, provider common.Address, offset *big.Int, limit uint8) ([]*structs.Bid, error) { + ids, bids, err := s.marketplace.GetActiveBidsByProvider(ctx, provider, offset, limit) if err != nil { return nil, err } @@ -195,17 +196,17 @@ 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 } - ratedBids := rateBids(bidIDs, bids, providerModelStats, modelStats, s.log) + ratedBids := rateBids(bidIDs, bids, providerModelStats, provider, modelStats, s.log) return ratedBids, nil } @@ -240,7 +241,7 @@ 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.providerRegistry.CreateNewProvider(transactOpt, stake, endpoint) if err != nil { return nil, lib.WrapError(ErrSendTx, err) } @@ -270,7 +271,7 @@ 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.modelRegistry.CreateNewModel(transactOpt, modelID, ipfsID, fee, stake, name, tags) if err != nil { return nil, lib.WrapError(ErrSendTx, err) } @@ -323,21 +324,19 @@ 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) + newBidId, err := s.marketplace.PostModelBid(transactOpt, modelID, &pricePerSecond.Int) if err != nil { return nil, lib.WrapError(ErrSendTx, err) } + s.log.Infof("Created new Bid with Id %s", newBidId) - ids, bids, err := s.marketplace.GetBidsByProvider(ctx, transactOpt.From, big.NewInt(0), 1) - if err != nil { - return nil, err - } + bid, err := s.GetBidByID(ctx, newBidId) - if len(ids) == 0 { - return nil, ErrNoBid + 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 +358,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 +369,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 +383,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.Errorf("Failed to get session report from provider", err) + + s.log.Info("Trying to get session report from user") + 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 +405,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) } @@ -407,7 +418,11 @@ func (s *BlockchainService) GetSession(ctx *gin.Context, sessionID common.Hash) 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) { @@ -542,11 +557,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 +568,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 +577,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) GetTodaysBudget(ctx context.Context) (*big.Int, error) { + return s.sessionRouter.GetTodaysBudget(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) { 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, common.HexToAddress(ctx.Query("user")), offset, limit) } else { // hasProvider - sessions, err = s.sessionRouter.GetSessionsByProvider(ctx, common.HexToAddress(ctx.Query("provider")), offset, limit) + ids, sessions, err = s.sessionRouter.GetSessionsByProvider(ctx, common.HexToAddress(ctx.Query("provider")), offset, limit) + } + if err != nil { + return nil, err + } + + 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(sessions), nil + + 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) ([]common.Hash, error) { + ids, err := s.sessionRouter.GetSessionsIdsByUser(ctx, user, offset, limit) + 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) @@ -667,7 +708,7 @@ func (s *BlockchainService) openSessionByBid(ctx context.Context, bidID common.H return s.OpenSession(ctx, initRes.Approval, initRes.ApprovalSig, stake) } -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, 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 +719,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,27 +738,92 @@ func (s *BlockchainService) OpenSessionByModelId(ctx context.Context, modelID co return common.Hash{}, lib.WrapError(ErrMyAddress, err) } - scoredBids := rateBids(bidIDs, bids, providerStats, modelStats, s.log) + scoredBids := rateBids(bidIDs, bids, providerStats, providers, modelStats, 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 !s.isProviderAllowed(providerAddr) { + s.log.Infof("skipping not allowed provider #%d %s", i, providerAddr.String()) + 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, err := s.tryOpenSession(ctx, bid, durationCopy, supply, budget, userAddr, isFailoverEnabled) + if err != nil { + s.log.Errorf("failed to open session with provider %s: %s", bid.Bid.Provider.String(), err.Error()) + continue } - 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) { +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) + 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.ScoredBid, duration, supply, budget *big.Int, userAddr common.Address, failoverEnabled bool) (common.Hash, error) { provider, err := s.providerRegistry.GetProviderById(ctx, bid.Bid.Provider) if err != nil { return common.Hash{}, lib.WrapError(ErrProvider, err) } - totalCost := duration.Mul(&bid.Bid.PricePerSecond.Int, duration) - stake := totalCost.Div(totalCost.Mul(supply, totalCost), budget) + totalCost := (&big.Int{}).Mul(&bid.Bid.PricePerSecond.Int, duration) + stake := (&big.Int{}).Div((&big.Int{}).Mul(supply, totalCost), budget) + + s.log.Infof("attempting to initiate session with provider %s", bid.Bid.Provider.String()) + s.log.Infof("stake %s", stake.String()) + s.log.Infof("duration %s", time.Duration(duration.Int64())*time.Second) + s.log.Infof("total cost %s", totalCost.String()) initRes, err := s.proxyService.InitiateSession(ctx, userAddr, bid.Bid.Provider, stake, bid.Bid.Id, provider.Endpoint) if err != nil { @@ -729,7 +835,24 @@ func (s *BlockchainService) tryOpenSession(ctx context.Context, bid structs.Scor return common.Hash{}, lib.WrapError(ErrApprove, err) } - return s.OpenSession(ctx, initRes.Approval, initRes.ApprovalSig, stake) + hash, err := s.OpenSession(ctx, initRes.Approval, initRes.ApprovalSig, stake) + if err != nil { + return common.Hash{}, err + } + + session, err := s.sessionRepo.GetSession(ctx, hash) + if err != nil { + return hash, fmt.Errorf("failed to get session: %s", err.Error()) + } + + session.SetFailoverEnabled(failoverEnabled) + + err = s.sessionRepo.SaveSession(ctx, session) + if err != nil { + return hash, fmt.Errorf("failed to store session: %s", err.Error()) + } + + return hash, nil } func (s *BlockchainService) GetMyAddress(ctx context.Context) (common.Address, error) { @@ -741,6 +864,19 @@ func (s *BlockchainService) GetMyAddress(ctx context.Context) (common.Address, e return lib.PrivKeyBytesToAddr(prKey) } +func (s *BlockchainService) isProviderAllowed(providerAddr common.Address) bool { + if len(s.providerAllowList) == 0 { + return true + } + + for _, addr := range s.providerAllowList { + if addr.Hex() == providerAddr.Hex() { + return true + } + } + return false +} + func (s *BlockchainService) getTransactOpts(ctx context.Context, privKey lib.HexString) (*bind.TransactOpts, error) { privateKey, err := crypto.ToECDSA(privKey) if err != 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..30ada6eb --- /dev/null +++ b/proxy-router/internal/blockchainapi/session_expiry_handler.go @@ -0,0 +1,58 @@ +package blockchainapi + +import ( + "context" + "time" + + "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 + log lib.ILogger +} + +func NewSessionExpiryHandler(blockchainService *BlockchainService, sessionStorage *storages.SessionStorage, log lib.ILogger) *SessionExpiryHandler { + return &SessionExpiryHandler{ + blockchainService: blockchainService, + sessionStorage: sessionStorage, + log: log, + } +} + +// 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 + } + for _, session := range sessions { + if session.EndsAt.Int64() < time.Now().Unix() { + sessionId, err := lib.HexToHash(session.Id) + if err != nil { + s.log.Error(err) + continue + } + _, err = s.blockchainService.CloseSession(ctx, sessionId) + if err != nil { + s.log.Error(err) + 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..5c0f80f1 100644 --- a/proxy-router/internal/blockchainapi/structs/req.go +++ b/proxy-router/internal/blockchainapi/structs/req.go @@ -33,6 +33,11 @@ type QueryOffsetLimit struct { Limit uint8 `form:"limit,default=10" binding:"omitempty" validate:"number"` } +type QueryOffsetLimitNoDefault struct { + Offset lib.BigInt `form:"offset,default=0" binding:"omitempty" validate:"number"` + Limit uint8 `form:"limit,default=0" binding:"omitempty" validate:"number"` +} + type QueryPageLimit struct { Page uint64 `form:"page,default=0" binding:"omitempty" validate:"number"` Limit uint8 `form:"limit,default=10" binding:"omitempty" validate:"number"` @@ -47,15 +52,23 @@ 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"` + 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/chatstorage/file_chat_storage.go b/proxy-router/internal/chatstorage/file_chat_storage.go new file mode 100644 index 00000000..d10c7325 --- /dev/null +++ b/proxy-router/internal/chatstorage/file_chat_storage.go @@ -0,0 +1,206 @@ +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 + if len(responses) > 0 { + isImageContent = responses[0].Type() == gcs.ChunkTypeImage + } + + newEntry := gcs.ChatMessage{ + Prompt: p, + Response: strings.Join(resps, ""), + PromptAt: promptAt.Unix(), + ResponseAt: responseAt.Unix(), + IsImageContent: isImageContent, + } + + 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 94% rename from proxy-router/internal/proxyapi/chat_responses.go rename to proxy-router/internal/chatstorage/genericchatstorage/chat_responses.go index 76622cd3..4eb6129d 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,11 @@ 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 diff --git a/proxy-router/internal/chatstorage/genericchatstorage/completion.go b/proxy-router/internal/chatstorage/genericchatstorage/completion.go new file mode 100644 index 00000000..eb9fd0fc --- /dev/null +++ b/proxy-router/internal/chatstorage/genericchatstorage/completion.go @@ -0,0 +1,153 @@ +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 Chunk interface { + IsStreaming() bool + Tokens() int + Type() ChunkType + String() string + Data() interface{} +} + +var _ Chunk = &ChunkText{} +var _ Chunk = &ChunkImage{} +var _ Chunk = &ChunkControl{} +var _ Chunk = &ChunkStreaming{} diff --git a/proxy-router/internal/proxyapi/chat_requests.go b/proxy-router/internal/chatstorage/genericchatstorage/interface.go similarity index 51% rename from proxy-router/internal/proxyapi/chat_requests.go rename to proxy-router/internal/chatstorage/genericchatstorage/interface.go index 23ccb273..690c00f1 100644 --- a/proxy-router/internal/proxyapi/chat_requests.go +++ b/proxy-router/internal/chatstorage/genericchatstorage/interface.go @@ -1,58 +1,67 @@ -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"` +} +type Chat struct { + ChatID string `json:"chatId"` + ModelID string `json:"modelId"` + Title string `json:"title"` + IsLocal bool `json:"isLocal"` + CreatedAt int64 `json:"createdAt"` } -type ChatCompletionResponseFormatType string - -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..9756f105 100644 --- a/proxy-router/internal/config/config.go +++ b/proxy-router/internal/config/config.go @@ -4,26 +4,34 @@ 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"` + 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 { @@ -41,12 +49,16 @@ type Config struct { 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"` + LevelRPC string `env:"LOG_LEVEL_RPC" flag:"log-level-rpc" validate:"omitempty,oneof=debug info warn error dpanic panic fatal"` + LevelBadger string `env:"LOG_LEVEL_BADGER" flag:"log-level-badger" 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"` + ProviderAllowList string `env:"PROVIDER_ALLOW_LIST" flag:"provider-allow-list" validate:"omitempty" desc:"comma separated list of provider addresses allowed to open session with"` } System struct { Enable bool `env:"SYS_ENABLE" flag:"sys-enable" desc:"enable system level configuration adjustments"` @@ -68,6 +80,17 @@ func (cfg *Config) SetDefaults() { cfg.Environment = "development" } + // Blockchain + if cfg.Blockchain.MaxReconnects == 0 { + cfg.Blockchain.MaxReconnects = 30 + } + if cfg.Blockchain.PollingInterval == 0 { + cfg.Blockchain.PollingInterval = 1 * time.Second + } + if cfg.Blockchain.Multicall3Addr.Cmp(common.Address{}) == 0 { + cfg.Blockchain.Multicall3Addr = &multicall.MULTICALL3_ADDR + } + // Log if cfg.Log.LevelConnection == "" { @@ -85,16 +108,15 @@ func (cfg *Config) SetDefaults() { if cfg.Log.LevelApp == "" { cfg.Log.LevelApp = "debug" } - - // Proxy - if cfg.Proxy.MaxCachedDests == 0 { - cfg.Proxy.MaxCachedDests = 5 + if cfg.Log.LevelRPC == "" { + cfg.Log.LevelRPC = "info" + } + if cfg.Log.LevelBadger == "" { + cfg.Log.LevelBadger = "info" } // System - // cfg.System.Enable = true // TODO: Temporary override, remove this line - if cfg.System.LocalPortRange == "" { cfg.System.LocalPortRange = "1024 65535" } @@ -126,15 +148,27 @@ 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} + } } // GetSanitized returns a copy of the config with sensitive data removed @@ -143,6 +177,11 @@ 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.Environment = cfg.Environment publicCfg.Marketplace.DiamondContractAddress = cfg.Marketplace.DiamondContractAddress @@ -156,9 +195,14 @@ func (cfg *Config) GetSanitized() interface{} { publicCfg.Log.LevelConnection = cfg.Log.LevelConnection publicCfg.Log.LevelProxy = cfg.Log.LevelProxy publicCfg.Log.LevelScheduler = cfg.Log.LevelScheduler + publicCfg.Log.LevelRPC = cfg.Log.LevelRPC publicCfg.Proxy.Address = cfg.Proxy.Address - publicCfg.Proxy.MaxCachedDests = cfg.Proxy.MaxCachedDests + publicCfg.Proxy.ModelsConfigPath = cfg.Proxy.ModelsConfigPath + publicCfg.Proxy.ProviderAllowList = cfg.Proxy.ProviderAllowList + publicCfg.Proxy.StoragePath = cfg.Proxy.StoragePath + publicCfg.Proxy.StoreChatContext = cfg.Proxy.StoreChatContext + publicCfg.Proxy.ForwardChatContext = cfg.Proxy.ForwardChatContext 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.go b/proxy-router/internal/config/models_config.go index 942e95c4..02c11f55 100644 --- a/proxy-router/internal/config/models_config.go +++ b/proxy-router/internal/config/models_config.go @@ -13,10 +13,12 @@ type ModelConfigLoader struct { } type ModelConfig struct { - ModelName string `json:"modelName"` - ApiType string `json:"apiType"` - ApiURL string `json:"apiUrl"` - ApiKey string `json:"apiKey"` + ModelName string `json:"modelName"` + ApiType string `json:"apiType"` + ApiURL string `json:"apiUrl"` + ApiKey string `json:"apiKey"` + ConcurrentSlots int `json:"concurrentSlots"` + CapacityPolicy string `json:"capacityPolicy"` } type ModelConfigs map[string]ModelConfig @@ -63,7 +65,7 @@ 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) + e.log.Warnf("model config not found for ID: %s", ID) return &ModelConfig{} } diff --git a/proxy-router/internal/handlers/httphandlers/http.go b/proxy-router/internal/handlers/httphandlers/http.go index 6f96504d..1be68451 100644 --- a/proxy-router/internal/handlers/httphandlers/http.go +++ b/proxy-router/internal/handlers/httphandlers/http.go @@ -49,13 +49,13 @@ func CreateHTTPServer(log lib.ILogger, controllers ...Registrable) *gin.Engine { panic(err) } - // gin.SetMode(gin.ReleaseMode) + gin.SetMode(gin.ReleaseMode) r := gin.New() 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)) 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..ce8fea32 --- /dev/null +++ b/proxy-router/internal/interfaces/rpc_multi.go @@ -0,0 +1,7 @@ +package interfaces + +type RPCEndpoints interface { + GetURLs() []string + SetURLs(urls []string) error + RemoveURLs() error +} 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/ethclient.go b/proxy-router/internal/lib/ethclient.go index 9128d660..640ddd84 100644 --- a/proxy-router/internal/lib/ethclient.go +++ b/proxy-router/internal/lib/ethclient.go @@ -1,12 +1,12 @@ 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" + "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" ) 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/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..5e3a03a6 100644 --- a/proxy-router/internal/proxyapi/controller_http.go +++ b/proxy-router/internal/proxyapi/controller_http.go @@ -1,30 +1,44 @@ 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 @@ -34,6 +48,10 @@ func (s *ProxyController) RegisterRoutes(r interfaces.Router) { 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) } // InitiateSession godoc @@ -68,17 +86,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 string 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,60 +107,51 @@ 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 + } + + ctx.Writer.Header().Set(constants.HEADER_CONTENT_TYPE, contentType) - 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) - } + 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 @@ -161,35 +170,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..d4cbbbde 100644 --- a/proxy-router/internal/proxyapi/controller_morrpc.go +++ b/proxy-router/internal/proxyapi/controller_morrpc.go @@ -9,12 +9,14 @@ 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 @@ -26,11 +28,12 @@ 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) *MORRPCController { c := &MORRPCController{ service: service, validator: validator, sessionStorage: sessionStorage, + sessionRepo: sessionRepo, morRpc: m.NewMorRpc(), } @@ -88,42 +91,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 + 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 +137,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..86b10bda 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, 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..d9733119 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" @@ -59,7 +58,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}) @@ -283,7 +282,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 diff --git a/proxy-router/internal/proxyapi/proxy_receiver.go b/proxy-router/internal/proxyapi/proxy_receiver.go index 11182487..de4c1fa4 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,9 +166,10 @@ 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 } @@ -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..a41f0ce8 100644 --- a/proxy-router/internal/proxyapi/proxy_sender.go +++ b/proxy-router/internal/proxyapi/proxy_sender.go @@ -9,12 +9,13 @@ import ( "net" "net/http" "net/url" + "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" @@ -34,29 +35,39 @@ 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") ) type ProxyServiceSender struct { + chainID *big.Int publicUrl *url.URL 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, publicUrl *url.URL, privateKey interfaces.PrKeyProvider, logStorage *lib.Collection[*interfaces.LogStorage], sessionStorage *storages.SessionStorage, sessionRepo *sessionrepo.SessionRepositoryCached, log lib.ILogger) *ProxyServiceSender { return &ProxyServiceSender{ + chainID: chainID, publicUrl: publicUrl, 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) InitiateSession(ctx context.Context, user common.Address, provider common.Address, spend *big.Int, bidID common.Hash, providerURL string) (*msgs.SessionRes, error) { requestID := "1" @@ -114,7 +125,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 +133,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 } @@ -175,39 +186,62 @@ 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) + 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) @@ -242,116 +276,222 @@ func (p *ProxyServiceSender) rpcRequest(url string, rpcMessage *msgs.RPCMessage) 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) 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 { + 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.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) { + TIMEOUT_TO_ESTABLISH_CONNECTION := time.Second * 3 + 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(fmt.Errorf("failed to connect to provider"), err) p.log.Errorf("%s", err) - return nil, err + return nil, 0, 0, err } defer conn.Close() + TIMEOUT_TO_RECEIVE_FIRST_RESPONSE := time.Second * 5 + 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) responses := make([]interface{}, 0) for { if ctx.Err() != nil { - return nil, ctx.Err() + return nil, ttftMs, totalTokens, ctx.Err() } var msg *msgs.RpcResponse err = d.Decode(&msg) p.log.Debugf("Received stream msg:", msg) if err != nil { + if netErr, ok := err.(net.Error); ok && netErr.Timeout() { + p.log.Warnf("Read operation timed out: %v", err) + return nil, ttftMs, totalTokens, fmt.Errorf("first response timed out after 3 seconds: %w", err) + } p.log.Warnf("Failed to decode response: %v", err) - return responses, nil + return responses, ttftMs, totalTokens, nil } 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, fmt.Errorf("empty result and no error")) + } + + if ttftMs == 0 { + ttftMs = int(time.Now().UnixMilli() - now) + conn.SetReadDeadline(time.Time{}) } var inferenceRes 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) + var imageGenerationResult gcs.ImageGenerationResult + err = json.Unmarshal(aiResponse, &imageGenerationResult) if err != nil { - return nil, lib.WrapError(ErrInvalidResponse, err) + return nil, ttftMs, totalTokens, lib.WrapError(ErrInvalidResponse, err) } - responses = append(responses, prodiaPayload) + totalTokens += 1 + responses = append(responses, imageGenerationResult) + chunk = gcs.NewChunkImage(&imageGenerationResult) } 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 -} - -func (p *ProxyServiceSender) validateMsgSignature(result any, signature lib.HexString, providerPubicKey lib.HexString) bool { - return p.morRPC.VerifySignature(result, signature, providerPubicKey, p.log) + return responses, ttftMs, totalTokens, nil } diff --git a/proxy-router/internal/proxyapi/requests.go b/proxy-router/internal/proxyapi/requests.go index 7664b796..93bc4299 100644 --- a/proxy-router/internal/proxyapi/requests.go +++ b/proxy-router/internal/proxyapi/requests.go @@ -24,6 +24,7 @@ type PromptReq struct { type PromptHead struct { SessionID lib.Hash `header:"session_id" validate:"hex32"` ModelID lib.Hash `header:"model_id" validate:"hex32"` + ChatID lib.Hash `header:"chat_id" validate:"hex32"` } type InferenceRes struct { @@ -31,3 +32,11 @@ 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"` +} diff --git a/proxy-router/internal/proxyctl/proxyctl.go b/proxy-router/internal/proxyctl/proxyctl.go index 43bef0d5..1fa6e738 100644 --- a/proxy-router/internal/proxyctl/proxyctl.go +++ b/proxy-router/internal/proxyctl/proxyctl.go @@ -11,6 +11,7 @@ import ( "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" + 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/go-playground/validator/v10" @@ -44,36 +45,42 @@ 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 + eventListener *blockchainapi.EventsListener + wallet interfaces.PrKeyProvider + proxyAddr string + chainID *big.Int + sessionStorage *storages.SessionStorage + sessionRepo *sessionrepo.SessionRepositoryCached + log *lib.Logger + connLog *lib.Logger + schedulerLogFactory SchedulerLogFactory + aiEngine *aiengine.AiEngine + validator *validator.Validate + modelConfigLoader *config.ModelConfigLoader + blockchainService *blockchainapi.BlockchainService + sessionExpiryHandler *blockchainapi.SessionExpiryHandler state lib.AtomicValue[ProxyState] tsk *lib.Task } // 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.Logger, connLog *lib.Logger, proxyAddr string, scl SchedulerLogFactory, 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, + connLog: connLog, + proxyAddr: proxyAddr, + schedulerLogFactory: scl, + sessionStorage: sessionStorage, + aiEngine: aiEngine, + validator: valid, + modelConfigLoader: modelConfigLoader, + blockchainService: blockchainService, + sessionRepo: sessionRepo, + sessionExpiryHandler: sessionExpiryHandler, } } @@ -136,9 +143,9 @@ func (p *Proxy) run(ctx context.Context, prKey lib.HexString) error { return err } - proxyReceiver := proxyapi.NewProxyReceiver(prKey, pubKey, p.sessionStorage, p.aiEngine, p.chainID, p.modelConfigLoader) + proxyReceiver := proxyapi.NewProxyReceiver(prKey, pubKey, p.sessionStorage, p.aiEngine, p.chainID, p.modelConfigLoader, p.blockchainService, p.sessionRepo) - morTcpHandler := proxyapi.NewMORRPCController(proxyReceiver, p.validator, p.sessionStorage) + morTcpHandler := proxyapi.NewMORRPCController(proxyReceiver, p.validator, p.sessionRepo, p.sessionStorage) tcpHandler := tcphandlers.NewTCPHandler( p.log, p.connLog, p.schedulerLogFactory, morTcpHandler, ) @@ -153,6 +160,10 @@ func (p *Proxy) run(ctx context.Context, prKey lib.HexString) error { return p.eventListener.Run(errCtx) }) + g.Go(func() error { + return p.sessionExpiryHandler.Run(errCtx) + }) + return g.Wait() } 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..98bc4d3e --- /dev/null +++ b/proxy-router/internal/repositories/contracts/bindings/marketplace/Marketplace.go @@ -0,0 +1,1888 @@ +// 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\":[],\"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\":\"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[]\"}],\"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[]\"}],\"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[]\"}],\"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[]\"}],\"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[]\"}],\"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[]\"}],\"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[]\"}],\"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\":\"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\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"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) +} + +// 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[]) +func (_Marketplace *MarketplaceCaller) GetActiveModelIds(opts *bind.CallOpts, offset_ *big.Int, limit_ *big.Int) ([][32]byte, error) { + var out []interface{} + err := _Marketplace.contract.Call(opts, &out, "getActiveModelIds", offset_, limit_) + + if err != nil { + return *new([][32]byte), err + } + + out0 := *abi.ConvertType(out[0], new([][32]byte)).(*[][32]byte) + + return out0, err + +} + +// GetActiveModelIds is a free data retrieval call binding the contract method 0x3839d3dc. +// +// Solidity: function getActiveModelIds(uint256 offset_, uint256 limit_) view returns(bytes32[]) +func (_Marketplace *MarketplaceSession) GetActiveModelIds(offset_ *big.Int, limit_ *big.Int) ([][32]byte, 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[]) +func (_Marketplace *MarketplaceCallerSession) GetActiveModelIds(offset_ *big.Int, limit_ *big.Int) ([][32]byte, 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[]) +func (_Marketplace *MarketplaceCaller) GetActiveProviders(opts *bind.CallOpts, offset_ *big.Int, limit_ *big.Int) ([]common.Address, error) { + var out []interface{} + err := _Marketplace.contract.Call(opts, &out, "getActiveProviders", offset_, limit_) + + if err != nil { + return *new([]common.Address), err + } + + out0 := *abi.ConvertType(out[0], new([]common.Address)).(*[]common.Address) + + return out0, err + +} + +// GetActiveProviders is a free data retrieval call binding the contract method 0xd5472642. +// +// Solidity: function getActiveProviders(uint256 offset_, uint256 limit_) view returns(address[]) +func (_Marketplace *MarketplaceSession) GetActiveProviders(offset_ *big.Int, limit_ *big.Int) ([]common.Address, 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[]) +func (_Marketplace *MarketplaceCallerSession) GetActiveProviders(offset_ *big.Int, limit_ *big.Int) ([]common.Address, 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[]) +func (_Marketplace *MarketplaceCaller) GetModelActiveBids(opts *bind.CallOpts, modelId_ [32]byte, offset_ *big.Int, limit_ *big.Int) ([][32]byte, error) { + var out []interface{} + err := _Marketplace.contract.Call(opts, &out, "getModelActiveBids", modelId_, offset_, limit_) + + if err != nil { + return *new([][32]byte), err + } + + out0 := *abi.ConvertType(out[0], new([][32]byte)).(*[][32]byte) + + return out0, 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[]) +func (_Marketplace *MarketplaceSession) GetModelActiveBids(modelId_ [32]byte, offset_ *big.Int, limit_ *big.Int) ([][32]byte, 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[]) +func (_Marketplace *MarketplaceCallerSession) GetModelActiveBids(modelId_ [32]byte, offset_ *big.Int, limit_ *big.Int) ([][32]byte, 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[]) +func (_Marketplace *MarketplaceCaller) GetModelBids(opts *bind.CallOpts, modelId_ [32]byte, offset_ *big.Int, limit_ *big.Int) ([][32]byte, error) { + var out []interface{} + err := _Marketplace.contract.Call(opts, &out, "getModelBids", modelId_, offset_, limit_) + + if err != nil { + return *new([][32]byte), err + } + + out0 := *abi.ConvertType(out[0], new([][32]byte)).(*[][32]byte) + + return out0, 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[]) +func (_Marketplace *MarketplaceSession) GetModelBids(modelId_ [32]byte, offset_ *big.Int, limit_ *big.Int) ([][32]byte, 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[]) +func (_Marketplace *MarketplaceCallerSession) GetModelBids(modelId_ [32]byte, offset_ *big.Int, limit_ *big.Int) ([][32]byte, 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[]) +func (_Marketplace *MarketplaceCaller) GetModelIds(opts *bind.CallOpts, offset_ *big.Int, limit_ *big.Int) ([][32]byte, error) { + var out []interface{} + err := _Marketplace.contract.Call(opts, &out, "getModelIds", offset_, limit_) + + if err != nil { + return *new([][32]byte), err + } + + out0 := *abi.ConvertType(out[0], new([][32]byte)).(*[][32]byte) + + return out0, err + +} + +// GetModelIds is a free data retrieval call binding the contract method 0x08d0aab4. +// +// Solidity: function getModelIds(uint256 offset_, uint256 limit_) view returns(bytes32[]) +func (_Marketplace *MarketplaceSession) GetModelIds(offset_ *big.Int, limit_ *big.Int) ([][32]byte, 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[]) +func (_Marketplace *MarketplaceCallerSession) GetModelIds(offset_ *big.Int, limit_ *big.Int) ([][32]byte, 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[]) +func (_Marketplace *MarketplaceCaller) GetProviderActiveBids(opts *bind.CallOpts, provider_ common.Address, offset_ *big.Int, limit_ *big.Int) ([][32]byte, error) { + var out []interface{} + err := _Marketplace.contract.Call(opts, &out, "getProviderActiveBids", provider_, offset_, limit_) + + if err != nil { + return *new([][32]byte), err + } + + out0 := *abi.ConvertType(out[0], new([][32]byte)).(*[][32]byte) + + return out0, 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[]) +func (_Marketplace *MarketplaceSession) GetProviderActiveBids(provider_ common.Address, offset_ *big.Int, limit_ *big.Int) ([][32]byte, 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[]) +func (_Marketplace *MarketplaceCallerSession) GetProviderActiveBids(provider_ common.Address, offset_ *big.Int, limit_ *big.Int) ([][32]byte, 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[]) +func (_Marketplace *MarketplaceCaller) GetProviderBids(opts *bind.CallOpts, provider_ common.Address, offset_ *big.Int, limit_ *big.Int) ([][32]byte, error) { + var out []interface{} + err := _Marketplace.contract.Call(opts, &out, "getProviderBids", provider_, offset_, limit_) + + if err != nil { + return *new([][32]byte), err + } + + out0 := *abi.ConvertType(out[0], new([][32]byte)).(*[][32]byte) + + return out0, 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[]) +func (_Marketplace *MarketplaceSession) GetProviderBids(provider_ common.Address, offset_ *big.Int, limit_ *big.Int) ([][32]byte, 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[]) +func (_Marketplace *MarketplaceCallerSession) GetProviderBids(provider_ common.Address, offset_ *big.Int, limit_ *big.Int) ([][32]byte, 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_) +} + +// 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_) +} + +// 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 0x70ccc166. +// +// Solidity: function postModelBid(bytes32 modelId_, uint256 pricePerSecond_) returns(bytes32 bidId) +func (_Marketplace *MarketplaceTransactor) PostModelBid(opts *bind.TransactOpts, modelId_ [32]byte, pricePerSecond_ *big.Int) (*types.Transaction, error) { + return _Marketplace.contract.Transact(opts, "postModelBid", modelId_, pricePerSecond_) +} + +// PostModelBid is a paid mutator transaction binding the contract method 0x70ccc166. +// +// Solidity: function postModelBid(bytes32 modelId_, uint256 pricePerSecond_) returns(bytes32 bidId) +func (_Marketplace *MarketplaceSession) PostModelBid(modelId_ [32]byte, pricePerSecond_ *big.Int) (*types.Transaction, error) { + return _Marketplace.Contract.PostModelBid(&_Marketplace.TransactOpts, modelId_, pricePerSecond_) +} + +// PostModelBid is a paid mutator transaction binding the contract method 0x70ccc166. +// +// Solidity: function postModelBid(bytes32 modelId_, uint256 pricePerSecond_) returns(bytes32 bidId) +func (_Marketplace *MarketplaceTransactorSession) PostModelBid(modelId_ [32]byte, pricePerSecond_ *big.Int) (*types.Transaction, error) { + return _Marketplace.Contract.PostModelBid(&_Marketplace.TransactOpts, 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..4f6f09af --- /dev/null +++ b/proxy-router/internal/repositories/contracts/bindings/modelregistry/ModelRegistry.go @@ -0,0 +1,1357 @@ +// 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\":[],\"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\":\"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[]\"}],\"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[]\"}],\"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[]\"}],\"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[]\"}],\"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[]\"}],\"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[]\"}],\"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\":\"bytes32\",\"name\":\"modelId_\",\"type\":\"bytes32\"}],\"name\":\"modelDeregister\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"modelId_\",\"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) +} + +// 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[]) +func (_ModelRegistry *ModelRegistryCaller) GetActiveModelIds(opts *bind.CallOpts, offset_ *big.Int, limit_ *big.Int) ([][32]byte, error) { + var out []interface{} + err := _ModelRegistry.contract.Call(opts, &out, "getActiveModelIds", offset_, limit_) + + if err != nil { + return *new([][32]byte), err + } + + out0 := *abi.ConvertType(out[0], new([][32]byte)).(*[][32]byte) + + return out0, err + +} + +// GetActiveModelIds is a free data retrieval call binding the contract method 0x3839d3dc. +// +// Solidity: function getActiveModelIds(uint256 offset_, uint256 limit_) view returns(bytes32[]) +func (_ModelRegistry *ModelRegistrySession) GetActiveModelIds(offset_ *big.Int, limit_ *big.Int) ([][32]byte, 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[]) +func (_ModelRegistry *ModelRegistryCallerSession) GetActiveModelIds(offset_ *big.Int, limit_ *big.Int) ([][32]byte, 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[]) +func (_ModelRegistry *ModelRegistryCaller) GetModelActiveBids(opts *bind.CallOpts, modelId_ [32]byte, offset_ *big.Int, limit_ *big.Int) ([][32]byte, error) { + var out []interface{} + err := _ModelRegistry.contract.Call(opts, &out, "getModelActiveBids", modelId_, offset_, limit_) + + if err != nil { + return *new([][32]byte), err + } + + out0 := *abi.ConvertType(out[0], new([][32]byte)).(*[][32]byte) + + return out0, 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[]) +func (_ModelRegistry *ModelRegistrySession) GetModelActiveBids(modelId_ [32]byte, offset_ *big.Int, limit_ *big.Int) ([][32]byte, 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[]) +func (_ModelRegistry *ModelRegistryCallerSession) GetModelActiveBids(modelId_ [32]byte, offset_ *big.Int, limit_ *big.Int) ([][32]byte, 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[]) +func (_ModelRegistry *ModelRegistryCaller) GetModelBids(opts *bind.CallOpts, modelId_ [32]byte, offset_ *big.Int, limit_ *big.Int) ([][32]byte, error) { + var out []interface{} + err := _ModelRegistry.contract.Call(opts, &out, "getModelBids", modelId_, offset_, limit_) + + if err != nil { + return *new([][32]byte), err + } + + out0 := *abi.ConvertType(out[0], new([][32]byte)).(*[][32]byte) + + return out0, 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[]) +func (_ModelRegistry *ModelRegistrySession) GetModelBids(modelId_ [32]byte, offset_ *big.Int, limit_ *big.Int) ([][32]byte, 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[]) +func (_ModelRegistry *ModelRegistryCallerSession) GetModelBids(modelId_ [32]byte, offset_ *big.Int, limit_ *big.Int) ([][32]byte, error) { + return _ModelRegistry.Contract.GetModelBids(&_ModelRegistry.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[]) +func (_ModelRegistry *ModelRegistryCaller) GetModelIds(opts *bind.CallOpts, offset_ *big.Int, limit_ *big.Int) ([][32]byte, error) { + var out []interface{} + err := _ModelRegistry.contract.Call(opts, &out, "getModelIds", offset_, limit_) + + if err != nil { + return *new([][32]byte), err + } + + out0 := *abi.ConvertType(out[0], new([][32]byte)).(*[][32]byte) + + return out0, err + +} + +// GetModelIds is a free data retrieval call binding the contract method 0x08d0aab4. +// +// Solidity: function getModelIds(uint256 offset_, uint256 limit_) view returns(bytes32[]) +func (_ModelRegistry *ModelRegistrySession) GetModelIds(offset_ *big.Int, limit_ *big.Int) ([][32]byte, 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[]) +func (_ModelRegistry *ModelRegistryCallerSession) GetModelIds(offset_ *big.Int, limit_ *big.Int) ([][32]byte, 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[]) +func (_ModelRegistry *ModelRegistryCaller) GetProviderActiveBids(opts *bind.CallOpts, provider_ common.Address, offset_ *big.Int, limit_ *big.Int) ([][32]byte, error) { + var out []interface{} + err := _ModelRegistry.contract.Call(opts, &out, "getProviderActiveBids", provider_, offset_, limit_) + + if err != nil { + return *new([][32]byte), err + } + + out0 := *abi.ConvertType(out[0], new([][32]byte)).(*[][32]byte) + + return out0, 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[]) +func (_ModelRegistry *ModelRegistrySession) GetProviderActiveBids(provider_ common.Address, offset_ *big.Int, limit_ *big.Int) ([][32]byte, 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[]) +func (_ModelRegistry *ModelRegistryCallerSession) GetProviderActiveBids(provider_ common.Address, offset_ *big.Int, limit_ *big.Int) ([][32]byte, 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[]) +func (_ModelRegistry *ModelRegistryCaller) GetProviderBids(opts *bind.CallOpts, provider_ common.Address, offset_ *big.Int, limit_ *big.Int) ([][32]byte, error) { + var out []interface{} + err := _ModelRegistry.contract.Call(opts, &out, "getProviderBids", provider_, offset_, limit_) + + if err != nil { + return *new([][32]byte), err + } + + out0 := *abi.ConvertType(out[0], new([][32]byte)).(*[][32]byte) + + return out0, 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[]) +func (_ModelRegistry *ModelRegistrySession) GetProviderBids(provider_ common.Address, offset_ *big.Int, limit_ *big.Int) ([][32]byte, 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[]) +func (_ModelRegistry *ModelRegistryCallerSession) GetProviderBids(provider_ common.Address, offset_ *big.Int, limit_ *big.Int) ([][32]byte, error) { + return _ModelRegistry.Contract.GetProviderBids(&_ModelRegistry.CallOpts, provider_, offset_, limit_) +} + +// 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_) +} + +// 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 0xec2581a1. +// +// Solidity: function modelRegister(bytes32 modelId_, bytes32 ipfsCID_, uint256 fee_, uint256 amount_, string name_, string[] tags_) returns() +func (_ModelRegistry *ModelRegistryTransactor) ModelRegister(opts *bind.TransactOpts, modelId_ [32]byte, ipfsCID_ [32]byte, fee_ *big.Int, amount_ *big.Int, name_ string, tags_ []string) (*types.Transaction, error) { + return _ModelRegistry.contract.Transact(opts, "modelRegister", modelId_, ipfsCID_, fee_, amount_, name_, tags_) +} + +// ModelRegister is a paid mutator transaction binding the contract method 0xec2581a1. +// +// Solidity: function modelRegister(bytes32 modelId_, bytes32 ipfsCID_, uint256 fee_, uint256 amount_, string name_, string[] tags_) returns() +func (_ModelRegistry *ModelRegistrySession) ModelRegister(modelId_ [32]byte, ipfsCID_ [32]byte, fee_ *big.Int, amount_ *big.Int, name_ string, tags_ []string) (*types.Transaction, error) { + return _ModelRegistry.Contract.ModelRegister(&_ModelRegistry.TransactOpts, modelId_, ipfsCID_, fee_, amount_, name_, tags_) +} + +// ModelRegister is a paid mutator transaction binding the contract method 0xec2581a1. +// +// Solidity: function modelRegister(bytes32 modelId_, bytes32 ipfsCID_, uint256 fee_, uint256 amount_, string name_, string[] tags_) returns() +func (_ModelRegistry *ModelRegistryTransactorSession) ModelRegister(modelId_ [32]byte, ipfsCID_ [32]byte, fee_ *big.Int, amount_ *big.Int, name_ string, tags_ []string) (*types.Transaction, error) { + return _ModelRegistry.Contract.ModelRegister(&_ModelRegistry.TransactOpts, modelId_, 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..f49c833d --- /dev/null +++ b/proxy-router/internal/repositories/contracts/bindings/providerregistry/ProviderRegistry.go @@ -0,0 +1,1451 @@ +// 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\":\"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\":\"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[]\"}],\"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[]\"}],\"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[]\"}],\"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[]\"}],\"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[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getProviderMinimumStake\",\"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\":\"bytes32\",\"name\":\"bidId_\",\"type\":\"bytes32\"}],\"name\":\"isBidActive\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"providerDeregister\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"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) +} + +// 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[]) +func (_ProviderRegistry *ProviderRegistryCaller) GetActiveProviders(opts *bind.CallOpts, offset_ *big.Int, limit_ *big.Int) ([]common.Address, error) { + var out []interface{} + err := _ProviderRegistry.contract.Call(opts, &out, "getActiveProviders", offset_, limit_) + + if err != nil { + return *new([]common.Address), err + } + + out0 := *abi.ConvertType(out[0], new([]common.Address)).(*[]common.Address) + + return out0, err + +} + +// GetActiveProviders is a free data retrieval call binding the contract method 0xd5472642. +// +// Solidity: function getActiveProviders(uint256 offset_, uint256 limit_) view returns(address[]) +func (_ProviderRegistry *ProviderRegistrySession) GetActiveProviders(offset_ *big.Int, limit_ *big.Int) ([]common.Address, 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[]) +func (_ProviderRegistry *ProviderRegistryCallerSession) GetActiveProviders(offset_ *big.Int, limit_ *big.Int) ([]common.Address, 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[]) +func (_ProviderRegistry *ProviderRegistryCaller) GetModelActiveBids(opts *bind.CallOpts, modelId_ [32]byte, offset_ *big.Int, limit_ *big.Int) ([][32]byte, error) { + var out []interface{} + err := _ProviderRegistry.contract.Call(opts, &out, "getModelActiveBids", modelId_, offset_, limit_) + + if err != nil { + return *new([][32]byte), err + } + + out0 := *abi.ConvertType(out[0], new([][32]byte)).(*[][32]byte) + + return out0, 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[]) +func (_ProviderRegistry *ProviderRegistrySession) GetModelActiveBids(modelId_ [32]byte, offset_ *big.Int, limit_ *big.Int) ([][32]byte, 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[]) +func (_ProviderRegistry *ProviderRegistryCallerSession) GetModelActiveBids(modelId_ [32]byte, offset_ *big.Int, limit_ *big.Int) ([][32]byte, 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[]) +func (_ProviderRegistry *ProviderRegistryCaller) GetModelBids(opts *bind.CallOpts, modelId_ [32]byte, offset_ *big.Int, limit_ *big.Int) ([][32]byte, error) { + var out []interface{} + err := _ProviderRegistry.contract.Call(opts, &out, "getModelBids", modelId_, offset_, limit_) + + if err != nil { + return *new([][32]byte), err + } + + out0 := *abi.ConvertType(out[0], new([][32]byte)).(*[][32]byte) + + return out0, 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[]) +func (_ProviderRegistry *ProviderRegistrySession) GetModelBids(modelId_ [32]byte, offset_ *big.Int, limit_ *big.Int) ([][32]byte, 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[]) +func (_ProviderRegistry *ProviderRegistryCallerSession) GetModelBids(modelId_ [32]byte, offset_ *big.Int, limit_ *big.Int) ([][32]byte, 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[]) +func (_ProviderRegistry *ProviderRegistryCaller) GetProviderActiveBids(opts *bind.CallOpts, provider_ common.Address, offset_ *big.Int, limit_ *big.Int) ([][32]byte, error) { + var out []interface{} + err := _ProviderRegistry.contract.Call(opts, &out, "getProviderActiveBids", provider_, offset_, limit_) + + if err != nil { + return *new([][32]byte), err + } + + out0 := *abi.ConvertType(out[0], new([][32]byte)).(*[][32]byte) + + return out0, 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[]) +func (_ProviderRegistry *ProviderRegistrySession) GetProviderActiveBids(provider_ common.Address, offset_ *big.Int, limit_ *big.Int) ([][32]byte, 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[]) +func (_ProviderRegistry *ProviderRegistryCallerSession) GetProviderActiveBids(provider_ common.Address, offset_ *big.Int, limit_ *big.Int) ([][32]byte, 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[]) +func (_ProviderRegistry *ProviderRegistryCaller) GetProviderBids(opts *bind.CallOpts, provider_ common.Address, offset_ *big.Int, limit_ *big.Int) ([][32]byte, error) { + var out []interface{} + err := _ProviderRegistry.contract.Call(opts, &out, "getProviderBids", provider_, offset_, limit_) + + if err != nil { + return *new([][32]byte), err + } + + out0 := *abi.ConvertType(out[0], new([][32]byte)).(*[][32]byte) + + return out0, 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[]) +func (_ProviderRegistry *ProviderRegistrySession) GetProviderBids(provider_ common.Address, offset_ *big.Int, limit_ *big.Int) ([][32]byte, 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[]) +func (_ProviderRegistry *ProviderRegistryCallerSession) GetProviderBids(provider_ common.Address, offset_ *big.Int, limit_ *big.Int) ([][32]byte, 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) +} + +// 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_) +} + +// 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 0x58e0bd1c. +// +// Solidity: function providerDeregister() returns() +func (_ProviderRegistry *ProviderRegistryTransactor) ProviderDeregister(opts *bind.TransactOpts) (*types.Transaction, error) { + return _ProviderRegistry.contract.Transact(opts, "providerDeregister") +} + +// ProviderDeregister is a paid mutator transaction binding the contract method 0x58e0bd1c. +// +// Solidity: function providerDeregister() returns() +func (_ProviderRegistry *ProviderRegistrySession) ProviderDeregister() (*types.Transaction, error) { + return _ProviderRegistry.Contract.ProviderDeregister(&_ProviderRegistry.TransactOpts) +} + +// ProviderDeregister is a paid mutator transaction binding the contract method 0x58e0bd1c. +// +// Solidity: function providerDeregister() returns() +func (_ProviderRegistry *ProviderRegistryTransactorSession) ProviderDeregister() (*types.Transaction, error) { + return _ProviderRegistry.Contract.ProviderDeregister(&_ProviderRegistry.TransactOpts) +} + +// ProviderRegister is a paid mutator transaction binding the contract method 0x17028d92. +// +// Solidity: function providerRegister(uint256 amount_, string endpoint_) returns() +func (_ProviderRegistry *ProviderRegistryTransactor) ProviderRegister(opts *bind.TransactOpts, amount_ *big.Int, endpoint_ string) (*types.Transaction, error) { + return _ProviderRegistry.contract.Transact(opts, "providerRegister", amount_, endpoint_) +} + +// ProviderRegister is a paid mutator transaction binding the contract method 0x17028d92. +// +// Solidity: function providerRegister(uint256 amount_, string endpoint_) returns() +func (_ProviderRegistry *ProviderRegistrySession) ProviderRegister(amount_ *big.Int, endpoint_ string) (*types.Transaction, error) { + return _ProviderRegistry.Contract.ProviderRegister(&_ProviderRegistry.TransactOpts, amount_, endpoint_) +} + +// ProviderRegister is a paid mutator transaction binding the contract method 0x17028d92. +// +// Solidity: function providerRegister(uint256 amount_, string endpoint_) returns() +func (_ProviderRegistry *ProviderRegistryTransactorSession) ProviderRegister(amount_ *big.Int, endpoint_ string) (*types.Transaction, error) { + return _ProviderRegistry.Contract.ProviderRegister(&_ProviderRegistry.TransactOpts, 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..bb424f64 --- /dev/null +++ b/proxy-router/internal/repositories/contracts/bindings/sessionrouter/SessionRouter.go @@ -0,0 +1,2313 @@ +// 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\":\"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\":\"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[]\"}],\"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[]\"}],\"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[]\"}],\"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[]\"}],\"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[]\"}],\"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[]\"}],\"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[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getProvidersTotalClaimed\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"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[]\"}],\"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\":\"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\":\"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) +} + +// 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[]) +func (_SessionRouter *SessionRouterCaller) GetActiveProviders(opts *bind.CallOpts, offset_ *big.Int, limit_ *big.Int) ([]common.Address, error) { + var out []interface{} + err := _SessionRouter.contract.Call(opts, &out, "getActiveProviders", offset_, limit_) + + if err != nil { + return *new([]common.Address), err + } + + out0 := *abi.ConvertType(out[0], new([]common.Address)).(*[]common.Address) + + return out0, err + +} + +// GetActiveProviders is a free data retrieval call binding the contract method 0xd5472642. +// +// Solidity: function getActiveProviders(uint256 offset_, uint256 limit_) view returns(address[]) +func (_SessionRouter *SessionRouterSession) GetActiveProviders(offset_ *big.Int, limit_ *big.Int) ([]common.Address, 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[]) +func (_SessionRouter *SessionRouterCallerSession) GetActiveProviders(offset_ *big.Int, limit_ *big.Int) ([]common.Address, 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[]) +func (_SessionRouter *SessionRouterCaller) GetModelActiveBids(opts *bind.CallOpts, modelId_ [32]byte, offset_ *big.Int, limit_ *big.Int) ([][32]byte, error) { + var out []interface{} + err := _SessionRouter.contract.Call(opts, &out, "getModelActiveBids", modelId_, offset_, limit_) + + if err != nil { + return *new([][32]byte), err + } + + out0 := *abi.ConvertType(out[0], new([][32]byte)).(*[][32]byte) + + return out0, 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[]) +func (_SessionRouter *SessionRouterSession) GetModelActiveBids(modelId_ [32]byte, offset_ *big.Int, limit_ *big.Int) ([][32]byte, 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[]) +func (_SessionRouter *SessionRouterCallerSession) GetModelActiveBids(modelId_ [32]byte, offset_ *big.Int, limit_ *big.Int) ([][32]byte, 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[]) +func (_SessionRouter *SessionRouterCaller) GetModelBids(opts *bind.CallOpts, modelId_ [32]byte, offset_ *big.Int, limit_ *big.Int) ([][32]byte, error) { + var out []interface{} + err := _SessionRouter.contract.Call(opts, &out, "getModelBids", modelId_, offset_, limit_) + + if err != nil { + return *new([][32]byte), err + } + + out0 := *abi.ConvertType(out[0], new([][32]byte)).(*[][32]byte) + + return out0, 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[]) +func (_SessionRouter *SessionRouterSession) GetModelBids(modelId_ [32]byte, offset_ *big.Int, limit_ *big.Int) ([][32]byte, 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[]) +func (_SessionRouter *SessionRouterCallerSession) GetModelBids(modelId_ [32]byte, offset_ *big.Int, limit_ *big.Int) ([][32]byte, 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[]) +func (_SessionRouter *SessionRouterCaller) GetModelSessions(opts *bind.CallOpts, modelId_ [32]byte, offset_ *big.Int, limit_ *big.Int) ([][32]byte, error) { + var out []interface{} + err := _SessionRouter.contract.Call(opts, &out, "getModelSessions", modelId_, offset_, limit_) + + if err != nil { + return *new([][32]byte), err + } + + out0 := *abi.ConvertType(out[0], new([][32]byte)).(*[][32]byte) + + return out0, 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[]) +func (_SessionRouter *SessionRouterSession) GetModelSessions(modelId_ [32]byte, offset_ *big.Int, limit_ *big.Int) ([][32]byte, 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[]) +func (_SessionRouter *SessionRouterCallerSession) GetModelSessions(modelId_ [32]byte, offset_ *big.Int, limit_ *big.Int) ([][32]byte, 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[]) +func (_SessionRouter *SessionRouterCaller) GetProviderActiveBids(opts *bind.CallOpts, provider_ common.Address, offset_ *big.Int, limit_ *big.Int) ([][32]byte, error) { + var out []interface{} + err := _SessionRouter.contract.Call(opts, &out, "getProviderActiveBids", provider_, offset_, limit_) + + if err != nil { + return *new([][32]byte), err + } + + out0 := *abi.ConvertType(out[0], new([][32]byte)).(*[][32]byte) + + return out0, 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[]) +func (_SessionRouter *SessionRouterSession) GetProviderActiveBids(provider_ common.Address, offset_ *big.Int, limit_ *big.Int) ([][32]byte, 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[]) +func (_SessionRouter *SessionRouterCallerSession) GetProviderActiveBids(provider_ common.Address, offset_ *big.Int, limit_ *big.Int) ([][32]byte, 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[]) +func (_SessionRouter *SessionRouterCaller) GetProviderBids(opts *bind.CallOpts, provider_ common.Address, offset_ *big.Int, limit_ *big.Int) ([][32]byte, error) { + var out []interface{} + err := _SessionRouter.contract.Call(opts, &out, "getProviderBids", provider_, offset_, limit_) + + if err != nil { + return *new([][32]byte), err + } + + out0 := *abi.ConvertType(out[0], new([][32]byte)).(*[][32]byte) + + return out0, 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[]) +func (_SessionRouter *SessionRouterSession) GetProviderBids(provider_ common.Address, offset_ *big.Int, limit_ *big.Int) ([][32]byte, 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[]) +func (_SessionRouter *SessionRouterCallerSession) GetProviderBids(provider_ common.Address, offset_ *big.Int, limit_ *big.Int) ([][32]byte, 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[]) +func (_SessionRouter *SessionRouterCaller) GetProviderSessions(opts *bind.CallOpts, provider_ common.Address, offset_ *big.Int, limit_ *big.Int) ([][32]byte, error) { + var out []interface{} + err := _SessionRouter.contract.Call(opts, &out, "getProviderSessions", provider_, offset_, limit_) + + if err != nil { + return *new([][32]byte), err + } + + out0 := *abi.ConvertType(out[0], new([][32]byte)).(*[][32]byte) + + return out0, 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[]) +func (_SessionRouter *SessionRouterSession) GetProviderSessions(provider_ common.Address, offset_ *big.Int, limit_ *big.Int) ([][32]byte, 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[]) +func (_SessionRouter *SessionRouterCallerSession) GetProviderSessions(provider_ common.Address, offset_ *big.Int, limit_ *big.Int) ([][32]byte, 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) +} + +// 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[]) +func (_SessionRouter *SessionRouterCaller) GetUserSessions(opts *bind.CallOpts, user_ common.Address, offset_ *big.Int, limit_ *big.Int) ([][32]byte, error) { + var out []interface{} + err := _SessionRouter.contract.Call(opts, &out, "getUserSessions", user_, offset_, limit_) + + if err != nil { + return *new([][32]byte), err + } + + out0 := *abi.ConvertType(out[0], new([][32]byte)).(*[][32]byte) + + return out0, 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[]) +func (_SessionRouter *SessionRouterSession) GetUserSessions(user_ common.Address, offset_ *big.Int, limit_ *big.Int) ([][32]byte, 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[]) +func (_SessionRouter *SessionRouterCallerSession) GetUserSessions(user_ common.Address, offset_ *big.Int, limit_ *big.Int) ([][32]byte, 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_) +} + +// 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 0x1c3744c3. +// +// Solidity: function openSession(uint256 amount_, bool isDirectPaymentFromUser_, bytes approvalEncoded_, bytes signature_) returns(bytes32) +func (_SessionRouter *SessionRouterTransactor) OpenSession(opts *bind.TransactOpts, amount_ *big.Int, isDirectPaymentFromUser_ bool, approvalEncoded_ []byte, signature_ []byte) (*types.Transaction, error) { + return _SessionRouter.contract.Transact(opts, "openSession", amount_, isDirectPaymentFromUser_, approvalEncoded_, signature_) +} + +// OpenSession is a paid mutator transaction binding the contract method 0x1c3744c3. +// +// Solidity: function openSession(uint256 amount_, bool isDirectPaymentFromUser_, bytes approvalEncoded_, bytes signature_) returns(bytes32) +func (_SessionRouter *SessionRouterSession) OpenSession(amount_ *big.Int, isDirectPaymentFromUser_ bool, approvalEncoded_ []byte, signature_ []byte) (*types.Transaction, error) { + return _SessionRouter.Contract.OpenSession(&_SessionRouter.TransactOpts, amount_, isDirectPaymentFromUser_, approvalEncoded_, signature_) +} + +// OpenSession is a paid mutator transaction binding the contract method 0x1c3744c3. +// +// Solidity: function openSession(uint256 amount_, bool isDirectPaymentFromUser_, bytes approvalEncoded_, bytes signature_) returns(bytes32) +func (_SessionRouter *SessionRouterTransactorSession) OpenSession(amount_ *big.Int, isDirectPaymentFromUser_ bool, approvalEncoded_ []byte, signature_ []byte) (*types.Transaction, error) { + return _SessionRouter.Contract.OpenSession(&_SessionRouter.TransactOpts, 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 0x8293617a. +// +// Solidity: function withdrawUserStakes(uint8 iterations_) returns() +func (_SessionRouter *SessionRouterTransactor) WithdrawUserStakes(opts *bind.TransactOpts, iterations_ uint8) (*types.Transaction, error) { + return _SessionRouter.contract.Transact(opts, "withdrawUserStakes", iterations_) +} + +// WithdrawUserStakes is a paid mutator transaction binding the contract method 0x8293617a. +// +// Solidity: function withdrawUserStakes(uint8 iterations_) returns() +func (_SessionRouter *SessionRouterSession) WithdrawUserStakes(iterations_ uint8) (*types.Transaction, error) { + return _SessionRouter.Contract.WithdrawUserStakes(&_SessionRouter.TransactOpts, iterations_) +} + +// WithdrawUserStakes is a paid mutator transaction binding the contract method 0x8293617a. +// +// Solidity: function withdrawUserStakes(uint8 iterations_) returns() +func (_SessionRouter *SessionRouterTransactorSession) WithdrawUserStakes(iterations_ uint8) (*types.Transaction, error) { + return _SessionRouter.Contract.WithdrawUserStakes(&_SessionRouter.TransactOpts, 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..c43808e0 --- /dev/null +++ b/proxy-router/internal/repositories/contracts/log_watcher_polling.go @@ -0,0 +1,140 @@ +package contracts + +import ( + "context" + "errors" + "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" + "github.com/ethereum/go-ethereum/core/types" +) + +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, + } +} + +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 { + currentBlock, err := w.client.HeaderByNumber(ctx, nil) + if err != nil { + return 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 + if currentBlock.Number.Cmp(nextFromBlock) < 0 { + select { + case <-quit: + return SubClosedError + case <-ctx.Done(): + return ctx.Err() + case <-time.After(w.pollInterval): + } + continue + } + + query := ethereum.FilterQuery{ + Addresses: []common.Address{contractAddr}, + FromBlock: nextFromBlock, + ToBlock: currentBlock.Number, + } + sub, err := w.filterLogsRetry(ctx, query, quit) + if err != nil { + return err + } + + for _, log := range sub { + if log.Removed { + continue + } + event, err := mapper(log) + if err != nil { + w.log.Debugf("error mapping event: %s", err) + continue // mapper error, retry won't help, but we can continue + } + + select { + case <-quit: + return SubClosedError + case <-ctx.Done(): + return ctx.Err() + case sink <- event: + } + } + + nextFromBlock.Add(currentBlock.Number, big.NewInt(1)) + + select { + case <-quit: + return SubClosedError + case <-ctx.Done(): + return ctx.Err() + case <-time.After(w.pollInterval): + } + } + }, sink), nil +} + +func (w *LogWatcherPolling) filterLogsRetry(ctx context.Context, query ethereum.FilterQuery, quit <-chan struct{}) ([]types.Log, error) { + var lastErr error + + for attempts := 0; attempts < w.maxReconnects; attempts++ { + logs, err := w.client.FilterLogs(ctx, query) + if err == nil { + if attempts > 0 { + w.log.Warnf("subscription successfully reconnected after error: %s", lastErr) + } + + return logs, nil + } + + w.log.Debugf("subscription error: %s, retrying in %s", err, w.pollInterval.String()) + lastErr = err + + select { + case <-quit: + return nil, SubClosedError + case <-ctx.Done(): + return nil, ctx.Err() + case <-time.After(w.pollInterval): + } + } + + return nil, lastErr +} 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..42c7fb6c --- /dev/null +++ b/proxy-router/internal/repositories/contracts/log_watcher_subscription.go @@ -0,0 +1,106 @@ +package contracts + +import ( + "context" + "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; attempts++ { + sub, err := w.client.SubscribeFilterLogs(ctx, query, ch) + if err != nil { + lastErr = err + continue + } + if attempts > 0 { + w.log.Warnf("subscription successfully reconnected after error: %s", lastErr) + } + + return sub, nil + } + + return nil, lastErr +} 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..842e8689 --- /dev/null +++ b/proxy-router/internal/repositories/ethclient/ethclient.go @@ -0,0 +1,273 @@ +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 +} + +// NewClient creates a client that uses the given RPC client. +func NewClient(c RPCClient) *Client { + return &Client{c} +} + +// 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) { + var result hexutil.Big + err := ec.c.CallContext(ctx, &result, "eth_chainId") + if err != nil { + return nil, err + } + return (*big.Int)(&result), err +} + +// 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..894b7ff2 --- /dev/null +++ b/proxy-router/internal/repositories/ethclient/rpcclient_store_env.go @@ -0,0 +1,27 @@ +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) 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..2a7b063d --- /dev/null +++ b/proxy-router/internal/repositories/ethclient/rpcclient_store_factory.go @@ -0,0 +1,83 @@ +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 + 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..3112d772 --- /dev/null +++ b/proxy-router/internal/repositories/ethclient/rpcclient_store_keychain.go @@ -0,0 +1,81 @@ +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) RemoveURLs() error { + return p.deleteURLsInStorage() +} + +func (p *RPCClientStoreKeychain) GetClient() RPCClient { + return p.rpcClient +} + +func (p *RPCClientStoreKeychain) loadURLsFromStorage() ([]string, error) { + // return []string{"https://arb-sepolia.g.alchemy.com/v2/3-pxwBaJ7vilkz1jl-fMmCvZThGxpmo2"}, nil + 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..a64bd4d8 --- /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 { + 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() + } + + c.log.Debugf("calling eth endpoint %s", rpcClient.url) + 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..9832eca4 100644 --- a/proxy-router/internal/repositories/registries/marketplace.go +++ b/proxy-router/internal/repositories/registries/marketplace.go @@ -5,11 +5,13 @@ import ( "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 +19,156 @@ 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 { +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, model, pricePerSecond) if err != nil { - return lib.TryConvertGethError(err) + 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) ([][32]byte, []marketplace.IBidStorageBid, error) { + bidIDs, err := g.marketplace.GetProviderBids(&bind.CallOpts{Context: ctx}, provider, offset, big.NewInt(int64(limit))) + 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) + return g.GetMultipleBids(ctx, bidIDs) } -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) +func (g *Marketplace) GetBidsByModelAgent(ctx context.Context, modelAgentId common.Hash, offset *big.Int, limit uint8) ([][32]byte, []marketplace.IBidStorageBid, error) { + bidIDs, err := g.marketplace.GetModelBids(&bind.CallOpts{Context: ctx}, modelAgentId, offset, big.NewInt(int64(limit))) + if err != nil { + return nil, nil, err + } + 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) GetActiveBidsByProvider(ctx context.Context, provider common.Address, offset *big.Int, limit uint8) ([][32]byte, []marketplace.IBidStorageBid, error) { + bidIDs, err := g.marketplace.GetProviderActiveBids(&bind.CallOpts{Context: ctx}, provider, offset, big.NewInt(int64(limit))) + if err != nil { + return nil, nil, err + } + 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) GetActiveBidsByModel(ctx context.Context, modelAgentId common.Hash, offset *big.Int, limit uint8) ([][32]byte, []marketplace.IBidStorageBid, error) { + bidIDs, err := g.marketplace.GetModelActiveBids(&bind.CallOpts{Context: ctx}, modelAgentId, offset, big.NewInt(int64(limit))) + if err != nil { + return nil, nil, err + } + return g.GetMultipleBids(ctx, bidIDs) } -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) - - for { - if ctx.Err() != nil { - return nil, nil, nil, ctx.Err() - } - - idsBatch, bidsBatch, providerModelStatsBatch, err := bidsGetter(ctx, modelAgentID, offset, batchSize) - if err != nil { - return nil, nil, nil, err - } - - ids = append(ids, idsBatch...) - bids = append(bids, bidsBatch...) - providerModelStats = append(providerModelStats, providerModelStatsBatch...) - - if len(bidsBatch) < int(batchSize) { - break - } - - offset.Add(offset, big.NewInt(int64(batchSize))) +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} } - - return ids, bids, providerModelStats, nil + 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 } 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..9990d819 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,66 @@ 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)) + 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) ([][32]byte, []modelregistry.IModelStorageModel, error) { + ids, err := g.modelRegistry.GetActiveModelIds(&bind.CallOpts{Context: ctx}, offset, big.NewInt(int64(limit))) if err != nil { return nil, nil, err } - return adresses, models, nil + 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, modelId, ipfsID, &fee.Int, &stake.Int, name, tags) if err != nil { return lib.TryConvertGethError(err) } @@ -99,10 +133,22 @@ 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) 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/provider_registry.go b/proxy-router/internal/repositories/registries/provider_registry.go index 66afb10a..d2ec7332 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,66 @@ 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}) - if err != nil { - return nil, nil, err +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)) + 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 +} - addresses := make([]common.Address, len(providerAddrs)) - for i, address := range providerAddrs { - addresses[i] = address +func (g *ProviderRegistry) GetProviders(ctx context.Context, offset *big.Int, limit uint8) ([]common.Address, []providerregistry.IProviderStorageProvider, error) { + ids, err := g.providerRegistry.GetActiveProviders(&bind.CallOpts{Context: ctx}, offset, big.NewInt(int64(limit))) + if err != nil { + return nil, nil, err } - return addresses, providers, nil + 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, &addStake.Int, endpoint) if err != nil { return lib.TryConvertGethError(err) @@ -64,23 +93,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) if err != nil { return common.Hash{}, lib.TryConvertGethError(err) @@ -92,25 +113,30 @@ 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 err != nil { - continue // not our event, skip it - } - - return providerTx.Hash(), nil + if receipt.Status != 1 { + return receipt.TxHash, fmt.Errorf("Transaction failed with status %d", receipt.Status) } - return common.Hash{}, fmt.Errorf("ProviderDeregistered event not found in transaction logs") + return receipt.TxHash, 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) 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 &provider, 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..02416814 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) + sessionTx, err := g.sessionRouter.OpenSession(opts, stake, false, approval, approvalSig) if err != nil { return common.Hash{}, common.Address{}, common.Address{}, lib.TryConvertGethError(err) } @@ -69,14 +73,14 @@ func (g *SessionRouter) OpenSession(opts *bind.TransactOpts, approval []byte, ap // 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 +89,36 @@ 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) ([][32]byte, []src.ISessionStorageSession, error) { + sessionIDs, err := g.sessionRouter.GetProviderSessions(&bind.CallOpts{Context: ctx}, providerAddr, offset, big.NewInt(int64(limit))) + if err != nil { + return nil, nil, lib.TryConvertGethError(err) + } + return g.getMultipleSessions(ctx, sessionIDs) +} + +func (g *SessionRouter) GetSessionsByUser(ctx context.Context, userAddr common.Address, offset *big.Int, limit uint8) ([][32]byte, []src.ISessionStorageSession, error) { + IDs, err := g.sessionRouter.GetUserSessions(&bind.CallOpts{Context: ctx}, userAddr, offset, big.NewInt(int64(limit))) + if err != nil { + return nil, nil, lib.TryConvertGethError(err) + } + return g.getMultipleSessions(ctx, IDs) +} + +func (g *SessionRouter) GetSessionsIdsByUser(ctx context.Context, userAddr common.Address, offset *big.Int, limit uint8) ([][32]byte, error) { + IDs, err := g.sessionRouter.GetUserSessions(&bind.CallOpts{Context: ctx}, userAddr, offset, big.NewInt(int64(limit))) if err != nil { return nil, lib.TryConvertGethError(err) } - return sessions, nil + 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) ([][32]byte, error) { + IDs, err := g.sessionRouter.GetProviderSessions(&bind.CallOpts{Context: ctx}, userAddr, offset, big.NewInt(int64(limit))) if err != nil { return nil, lib.TryConvertGethError(err) } - return sessions, nil + 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 +128,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 +184,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 +192,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 +215,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..02d1a8b4 --- /dev/null +++ b/proxy-router/internal/repositories/registries/session_router_test.go @@ -0,0 +1,33 @@ +package registries + +import ( + "context" + "fmt" + "math/big" + "testing" + + "github.com/MorpheusAIs/Morpheus-Lumerin-Node/proxy-router/internal/lib" + "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) + + diamondAddr := common.HexToAddress("0x10777866547c53cbd69b02c5c76369d7e24e7b10") + sr := NewSessionRouter(diamondAddr, ethClient, lib.NewTestLogger()) + sessionIDs, err := sr.GetSessionsIDsByProvider(context.Background(), common.HexToAddress("0x1441Bc52156Cf18c12cde6A92aE6BDE8B7f775D4"), big.NewInt(0), 2) + 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..a42f56a5 --- /dev/null +++ b/proxy-router/internal/repositories/session/session_model.go @@ -0,0 +1,57 @@ +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 +} + +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) 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..5a778e29 --- /dev/null +++ b/proxy-router/internal/repositories/session/session_repo.go @@ -0,0 +1,114 @@ +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, + }, 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, + }) +} 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/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..84789bee 100644 --- a/proxy-router/internal/storages/storage.go +++ b/proxy-router/internal/storages/storage.go @@ -26,6 +26,16 @@ func NewStorage(log lib.ILogger, path string) *Storage { 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} +} + func (s *Storage) Close() { s.db.Close() } @@ -50,6 +60,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..f6b146ee --- /dev/null +++ b/proxy-router/internal/storages/structs.go @@ -0,0 +1,27 @@ +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 +} + +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..833bda71 100644 --- a/proxy-router/internal/system/controller.go +++ b/proxy-router/internal/system/controller.go @@ -10,57 +10,50 @@ 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/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 -} - -type ConfigResponse struct { - Version string - Commit string - DerivedConfig interface{} - Config interface{} + config *config.Config + wallet i.Wallet + ethRPC i.RPCEndpoints + sysConfig *SystemConfigurator + appStartTime time.Time + chainID *big.Int + log lib.ILogger + ethConnectionValidator IEthConnectionValidator } -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) } // HealthCheck godoc // // @Summary Healthcheck example // @Description do ping -// @Tags healthcheck +// @Tags system // @Produce json // @Success 200 {object} HealthCheckResponse // @Router /healthcheck [get] @@ -76,7 +69,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 +91,7 @@ func (s *SystemController) GetConfig(ctx *gin.Context) { DerivedConfig: config.DerivedConfig{ WalletAddress: addr, ChainID: s.chainID, + EthNodeURLs: s.ethRPC.GetURLs(), }, }) } @@ -106,7 +100,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 +134,58 @@ 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} ConfigResponse +// @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, gin.H{"status": "ok"}) +} + +// DeleteEthNode godoc +// +// @Summary Delete Eth Node URLs +// @Description Delete the Eth Node URLs +// @Tags system +// @Produce json +// @Success 200 {object} ConfigResponse +// @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 + } + + ctx.JSON(http.StatusOK, gin.H{"status": "ok"}) +} + 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..1a495da1 100644 --- a/proxy-router/internal/system/structs.go +++ b/proxy-router/internal/system/structs.go @@ -4,3 +4,20 @@ 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 +} 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..b9d1391a 100644 --- a/proxy-router/models-config.json.example +++ b/proxy-router/models-config.json.example @@ -1,12 +1,13 @@ { - "0x2d4b79107cc0b262f29628d97e6a4905a37e7fc9cd820dbdaf359e9ff5f5d9cf": { - "modelName": "v1-5-pruned-emaonly.safetensors [d7049739]", - "apiType": "prodia", - "apiUrl": "https://api.prodia.com/v1/sd/generate", - "apiKey": "API_KEY_HERE" - }, - "0x6a4813e866a48da528c533e706344ea853a1d3f21e37b4c8e7ffd5ff25779018": { - "modelName": "llama2", - "apiType": "openai" - } -} \ No newline at end of file + "0x0000000000000000000000000000000000000000000000000000000000000000": { + "modelName": "llama2", + "apiType": "openai", + "apiUrl": "http://localhost:8080/v1" + }, + "0x0000000000000000000000000000000000000000000000000000000000000001": { + "modelName": "v1-5-pruned-emaonly.safetensors [d7049739]", + "apiType": "prodia-sd", + "apiUrl": "https://api.prodia.com/v1", + "apiKey": "" + } +} 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..ff95ddcc 100644 --- a/readme.md +++ b/readme.md @@ -20,9 +20,9 @@ manages secure sessions between consumers and providers and routes prompts and r * 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 +* Morpheus saMOR Token (as of 10/30/2024): `0x34a285a1b1c166420df5b6630132542923b5b27e` +* Lumerin Morpheus Smart Contract (as of 10/30/2024) : `0x10777866547c53cbd69b02c5c76369d7e24e7b10` + * Interact with the Morpheus Contract: https://louper.dev/diamond/0x10777866547c53cbd69b02c5c76369d7e24e7b10?network=arbitrumSepolia#write * Blockchain Explorer: `https://sepolia.arbiscan.io/` * Swagger API: `http://localhost:8082/swagger/index.html` diff --git a/smart-contracts/.env.example b/smart-contracts/.env.example index 54ead7ba..aa0dc9d2 100644 --- a/smart-contracts/.env.example +++ b/smart-contracts/.env.example @@ -1,5 +1,7 @@ COINMARKETCAP_API_KEY= # for coverage report to estimate deployment and calls price ETH_NODE_ADDRESS=https://arb-sepolia.g.alchemy.com/v2/SOME_API_KEY ETHERSCAN_API_KEY= # for coverage report to estimate deployment and calls price +ARBITRUM_API_KEY= # for coverage report to estimate deployment and calls price MOR_TOKEN_ADDRESS= # MOR token address -OWNER_PRIVATE_KEY= # contract owner private key \ No newline at end of file +OWNER_PRIVATE_KEY= # contract owner private key +PRIVATE_KEY= # deployer private key \ No newline at end of file diff --git a/smart-contracts/.eslintrc.json b/smart-contracts/.eslintrc.json new file mode 100644 index 00000000..402a5fba --- /dev/null +++ b/smart-contracts/.eslintrc.json @@ -0,0 +1,22 @@ +{ + "parser": "@typescript-eslint/parser", + "parserOptions": { + "ecmaVersion": 12, + "sourceType": "module", + "project": "./tsconfig.json" + }, + "plugins": ["@typescript-eslint"], + "extends": [ + "eslint:recommended", + "plugin:@typescript-eslint/recommended", + "plugin:prettier/recommended" + ], + "rules": { + "@typescript-eslint/no-unused-vars": "error", + "@typescript-eslint/no-floating-promises": "error" + }, + "env": { + "browser": true, + "es2021": true + } +} diff --git a/smart-contracts/contracts/diamond/facets/Marketplace.sol b/smart-contracts/contracts/diamond/facets/Marketplace.sol index 4e4a79d9..e5d47c0a 100644 --- a/smart-contracts/contracts/diamond/facets/Marketplace.sol +++ b/smart-contracts/contracts/diamond/facets/Marketplace.sol @@ -1,6 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.24; +import {EnumerableSet} from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol"; import {SafeERC20, IERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import {OwnableDiamondStorage} from "../presets/OwnableDiamondStorage.sol"; @@ -21,102 +22,128 @@ contract Marketplace is BidStorage { using SafeERC20 for IERC20; + using EnumerableSet for EnumerableSet.Bytes32Set; function __Marketplace_init( - address token_ - ) external initializer(MARKETPLACE_STORAGE_SLOT) initializer(BID_STORAGE_SLOT) { - _getBidStorage().token = IERC20(token_); + address token_, + uint256 bidMinPricePerSecond_, + uint256 bidMaxPricePerSecond_ + ) external initializer(BIDS_STORAGE_SLOT) { + BidsStorage storage bidsStorage = _getBidsStorage(); + bidsStorage.token = token_; + + setMinMaxBidPricePerSecond(bidMinPricePerSecond_, bidMaxPricePerSecond_); } - /// @notice sets a bid fee - function setBidFee(uint256 bidFee_) external onlyOwner { - _getMarketplaceStorage().bidFee = bidFee_; - emit FeeUpdated(bidFee_); + function setMarketplaceBidFee(uint256 bidFee_) external onlyOwner { + MarketStorage storage marketStorage = _getMarketStorage(); + marketStorage.bidFee = bidFee_; + + emit MaretplaceFeeUpdated(bidFee_); } - /// @notice posts a new bid for a model - function postModelBid( - address provider_, - bytes32 modelId_, - uint256 pricePerSecond_ - ) external returns (bytes32 bidId) { - if (!_ownerOrProvider(provider_)) { - revert NotOwnerOrProvider(); - } - if (!isProviderActive(provider_)) { - revert ProviderNotFound(); + function setMinMaxBidPricePerSecond( + uint256 bidMinPricePerSecond_, + uint256 bidMaxPricePerSecond_ + ) public onlyOwner { + if (bidMinPricePerSecond_ == 0) { + revert MarketplaceBidMinPricePerSecondIsZero(); } - if (!isModelActive(modelId_)) { - revert ModelNotFound(); + + if (bidMinPricePerSecond_ > bidMaxPricePerSecond_) { + revert MarketplaceBidMinPricePerSecondIsInvalid(); } - return _postModelBid(provider_, modelId_, pricePerSecond_); + MarketStorage storage marketStorage = _getMarketStorage(); + marketStorage.bidMinPricePerSecond = bidMinPricePerSecond_; + marketStorage.bidMaxPricePerSecond = bidMaxPricePerSecond_; + + emit MarketplaceBidMinMaxPriceUpdated(bidMinPricePerSecond_, bidMaxPricePerSecond_); } - /// @notice deletes a bid - function deleteModelBid(bytes32 bidId_) external { - if (!_isBidActive(bidId_)) { - revert ActiveBidNotFound(); + function postModelBid(bytes32 modelId_, uint256 pricePerSecond_) external returns (bytes32 bidId) { + address provider_ = _msgSender(); + + if (!getIsProviderActive(provider_)) { + revert MarketplaceProviderNotFound(); } - if (!_ownerOrProvider(getBid(bidId_).provider)) { - revert NotOwnerOrProvider(); + if (!getIsModelActive(modelId_)) { + revert MarketplaceModelNotFound(); } - _deleteBid(bidId_); - } + BidsStorage storage bidsStorage = _getBidsStorage(); + MarketStorage storage marketStorage = _getMarketStorage(); - /// @notice withdraws the fee balance - function withdraw(address recipient_, uint256 amount_) external onlyOwner { - if (amount_ > getFeeBalance()) { - revert NotEnoughBalance(); + if (pricePerSecond_ < marketStorage.bidMinPricePerSecond || pricePerSecond_ > marketStorage.bidMaxPricePerSecond) { + revert MarketplaceBidPricePerSecondInvalid(); } - decreaseFeeBalance(amount_); - getToken().safeTransfer(recipient_, amount_); - } - - function _incrementBidNonce(address provider_, bytes32 modelId_) private returns (uint256) { - return _incrementBidNonce(getProviderModelId(provider_, modelId_)); - } + IERC20(bidsStorage.token).safeTransferFrom(provider_, address(this), marketStorage.bidFee); + marketStorage.feeBalance += marketStorage.bidFee; - function _postModelBid(address provider_, bytes32 modelId_, uint256 pricePerSecond_) private returns (bytes32) { - uint256 fee_ = getBidFee(); - getToken().safeTransferFrom(_msgSender(), address(this), fee_); - increaseFeeBalance(fee_); + bytes32 providerModelId_ = getProviderModelId(provider_, modelId_); + uint256 providerModelNonce_ = bidsStorage.providerModelNonce[providerModelId_]++; + bytes32 bidId_ = getBidId(provider_, modelId_, providerModelNonce_); - // TEST IT if it increments nonce correctly - uint256 nonce_ = _incrementBidNonce(provider_, modelId_); - if (nonce_ != 0) { - bytes32 oldBidId_ = getBidId(provider_, modelId_, nonce_ - 1); - if (_isBidActive(oldBidId_)) { + if (providerModelNonce_ != 0) { + bytes32 oldBidId_ = getBidId(provider_, modelId_, providerModelNonce_ - 1); + if (isBidActive(oldBidId_)) { _deleteBid(oldBidId_); } } - bytes32 bidId_ = getBidId(provider_, modelId_, nonce_); + Bid storage bid = bidsStorage.bids[bidId_]; + bid.provider = provider_; + bid.modelId = modelId_; + bid.pricePerSecond = pricePerSecond_; + bid.nonce = providerModelNonce_; + bid.createdAt = uint128(block.timestamp); - setBid(bidId_, Bid(provider_, modelId_, pricePerSecond_, nonce_, uint128(block.timestamp), 0)); + bidsStorage.providerBids[provider_].add(bidId_); + bidsStorage.providerActiveBids[provider_].add(bidId_); + bidsStorage.modelBids[modelId_].add(bidId_); + bidsStorage.modelActiveBids[modelId_].add(bidId_); - addProviderBid(provider_, bidId_); - addModelBid(modelId_, bidId_); + emit MarketplaceBidPosted(provider_, modelId_, providerModelNonce_); - addProviderActiveBids(provider_, bidId_); - addModelActiveBids(modelId_, bidId_); + return bidId_; + } - emit BidPosted(provider_, modelId_, nonce_); + function deleteModelBid(bytes32 bidId_) external { + BidsStorage storage bidsStorage = _getBidsStorage(); + _onlyAccount(bidsStorage.bids[bidId_].provider); - return bidId_; + if (!isBidActive(bidId_)) { + revert MarketplaceActiveBidNotFound(); + } + + _deleteBid(bidId_); + } + + function withdrawFee(address recipient_, uint256 amount_) external onlyOwner { + BidsStorage storage bidsStorage = _getBidsStorage(); + MarketStorage storage marketStorage = _getMarketStorage(); + + amount_ = amount_ > marketStorage.feeBalance ? marketStorage.feeBalance : amount_; + if (amount_ == 0) { + revert MarketplaceFeeAmountIsZero(); + } + + marketStorage.feeBalance -= amount_; + + IERC20(bidsStorage.token).safeTransfer(recipient_, amount_); } function _deleteBid(bytes32 bidId_) private { - Bid storage bid = getBid(bidId_); + BidsStorage storage bidsStorage = _getBidsStorage(); + Bid storage bid = bidsStorage.bids[bidId_]; bid.deletedAt = uint128(block.timestamp); - removeProviderActiveBids(bid.provider, bidId_); - removeModelActiveBids(bid.modelId, bidId_); + bidsStorage.providerActiveBids[bid.provider].remove(bidId_); + bidsStorage.modelActiveBids[bid.modelId].remove(bidId_); - emit BidDeleted(bid.provider, bid.modelId, bid.nonce); + emit MarketplaceBidDeleted(bid.provider, bid.modelId, bid.nonce); } function getBidId(address provider_, bytes32 modelId_, uint256 nonce_) public pure returns (bytes32) { @@ -126,14 +153,4 @@ contract Marketplace is function getProviderModelId(address provider_, bytes32 modelId_) public pure returns (bytes32) { return keccak256(abi.encodePacked(provider_, modelId_)); } - - function _ownerOrProvider(address provider_) private view returns (bool) { - return _msgSender() == owner() || _msgSender() == provider_; - } - - function _isBidActive(bytes32 bidId_) private view returns (bool) { - Bid memory bid_ = getBid(bidId_); - - return bid_.createdAt != 0 && bid_.deletedAt == 0; - } } diff --git a/smart-contracts/contracts/diamond/facets/ModelRegistry.sol b/smart-contracts/contracts/diamond/facets/ModelRegistry.sol index ec2037c2..5c4571d8 100644 --- a/smart-contracts/contracts/diamond/facets/ModelRegistry.sol +++ b/smart-contracts/contracts/diamond/facets/ModelRegistry.sol @@ -1,6 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.24; +import {EnumerableSet} from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol"; import {SafeERC20, IERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import {OwnableDiamondStorage} from "../presets/OwnableDiamondStorage.sol"; @@ -11,91 +12,83 @@ import {ModelStorage} from "../storages/ModelStorage.sol"; import {IModelRegistry} from "../../interfaces/facets/IModelRegistry.sol"; contract ModelRegistry is IModelRegistry, OwnableDiamondStorage, ModelStorage, BidStorage { + using EnumerableSet for EnumerableSet.Bytes32Set; using SafeERC20 for IERC20; - function __ModelRegistry_init() external initializer(MODEL_STORAGE_SLOT) {} + function __ModelRegistry_init() external initializer(MODELS_STORAGE_SLOT) {} - function setModelMinimumStake(uint256 modelMinimumStake_) external onlyOwner { - _setModelMinimumStake(modelMinimumStake_); - emit ModelMinimumStakeSet(modelMinimumStake_); + function modelSetMinStake(uint256 modelMinimumStake_) external onlyOwner { + ModelsStorage storage modelsStorage = _getModelsStorage(); + modelsStorage.modelMinimumStake = modelMinimumStake_; + + emit ModelMinimumStakeUpdated(modelMinimumStake_); } - /// @notice Registers or updates existing model function modelRegister( - // TODO: it is not secure (frontrunning) to take the modelId as key bytes32 modelId_, bytes32 ipfsCID_, uint256 fee_, - uint256 addStake_, - address owner_, + uint256 amount_, string calldata name_, - string[] calldata tags_ + string[] memory tags_ ) external { - if (!_isOwnerOrModelOwner(owner_)) { - revert NotOwnerOrModelOwner(); - } + ModelsStorage storage modelsStorage = _getModelsStorage(); + Model storage model = modelsStorage.models[modelId_]; - Model memory model_ = models(modelId_); - // TODO: there is no way to decrease the stake - uint256 newStake_ = model_.stake + addStake_; - if (newStake_ < modelMinimumStake()) { - revert StakeTooLow(); + uint256 newStake_ = model.stake + amount_; + uint256 minStake_ = modelsStorage.modelMinimumStake; + if (newStake_ < minStake_) { + revert ModelStakeTooLow(newStake_, minStake_); } - if (addStake_ > 0) { - getToken().safeTransferFrom(_msgSender(), address(this), addStake_); + if (amount_ > 0) { + BidsStorage storage bidsStorage = _getBidsStorage(); + IERC20(bidsStorage.token).safeTransferFrom(_msgSender(), address(this), amount_); } - uint128 createdAt_ = model_.createdAt; - if (createdAt_ == 0) { - // model never existed - addModel(modelId_); - setModelActive(modelId_, true); - createdAt_ = uint128(block.timestamp); + if (model.createdAt == 0) { + modelsStorage.modelIds.add(modelId_); + + model.createdAt = uint128(block.timestamp); + model.owner = _msgSender(); } else { - if (!_isOwnerOrModelOwner(model_.owner)) { - revert NotOwnerOrModelOwner(); - } - if (model_.isDeleted) { - setModelActive(modelId_, true); - } + _onlyAccount(model.owner); } - setModel(modelId_, Model(ipfsCID_, fee_, newStake_, owner_, name_, tags_, createdAt_, false)); + model.stake = newStake_; + model.ipfsCID = ipfsCID_; + model.fee = fee_; // TODO: validate fee and get usage places + model.name = name_; + model.tags = tags_; + model.isDeleted = false; - emit ModelRegisteredUpdated(owner_, modelId_); + modelsStorage.activeModels.add(modelId_); + + emit ModelRegisteredUpdated(_msgSender(), modelId_); } function modelDeregister(bytes32 modelId_) external { - Model storage model = models(modelId_); + ModelsStorage storage modelsStorage = _getModelsStorage(); + Model storage model = modelsStorage.models[modelId_]; - if (!isModelExists(modelId_)) { - revert ModelNotFound(); - } - if (!_isOwnerOrModelOwner(model.owner)) { - revert NotOwnerOrModelOwner(); - } - if (!isModelActiveBidsEmpty(modelId_)) { + _onlyAccount(model.owner); + if (!_isModelActiveBidsEmpty(modelId_)) { revert ModelHasActiveBids(); } + if (model.isDeleted) { + revert ModelHasAlreadyDeregistered(); + } - uint256 stake_ = model.stake; + uint256 withdrawAmount_ = model.stake; model.stake = 0; model.isDeleted = true; - setModelActive(modelId_, false); + modelsStorage.activeModels.remove(modelId_); - getToken().safeTransfer(model.owner, stake_); + BidsStorage storage bidsStorage = _getBidsStorage(); + IERC20(bidsStorage.token).safeTransfer(model.owner, withdrawAmount_); emit ModelDeregistered(model.owner, modelId_); } - - function isModelExists(bytes32 modelId_) public view returns (bool) { - return models(modelId_).createdAt != 0; - } - - function _isOwnerOrModelOwner(address modelOwner_) internal view returns (bool) { - return _msgSender() == owner() || _msgSender() == modelOwner_; - } } diff --git a/smart-contracts/contracts/diamond/facets/ProviderRegistry.sol b/smart-contracts/contracts/diamond/facets/ProviderRegistry.sol index 8ff515a7..13dcbca6 100644 --- a/smart-contracts/contracts/diamond/facets/ProviderRegistry.sol +++ b/smart-contracts/contracts/diamond/facets/ProviderRegistry.sol @@ -2,6 +2,7 @@ pragma solidity ^0.8.24; import {SafeERC20, IERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; +import {EnumerableSet} from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol"; import {OwnableDiamondStorage} from "../presets/OwnableDiamondStorage.sol"; @@ -11,124 +12,118 @@ import {ProviderStorage} from "../storages/ProviderStorage.sol"; import {IProviderRegistry} from "../../interfaces/facets/IProviderRegistry.sol"; contract ProviderRegistry is IProviderRegistry, OwnableDiamondStorage, ProviderStorage, BidStorage { + using EnumerableSet for EnumerableSet.AddressSet; using SafeERC20 for IERC20; - function __ProviderRegistry_init() external initializer(PROVIDER_STORAGE_SLOT) {} + function __ProviderRegistry_init() external initializer(PROVIDERS_STORAGE_SLOT) {} - /// @notice Sets the minimum stake required for a provider function providerSetMinStake(uint256 providerMinimumStake_) external onlyOwner { - setProviderMinimumStake(providerMinimumStake_); - emit ProviderMinStakeUpdated(providerMinimumStake_); + PovidersStorage storage providersStorage = _getProvidersStorage(); + providersStorage.providerMinimumStake = providerMinimumStake_; + + emit ProviderMinimumStakeUpdated(providerMinimumStake_); } - /// @notice Registers a provider - /// @param providerAddress_ provider address - /// @param amount_ amount of stake to add - /// @param endpoint_ provider endpoint (host.com:1234) - function providerRegister(address providerAddress_, uint256 amount_, string calldata endpoint_) external { - if (!_ownerOrProvider(providerAddress_)) { - // TODO: such that we cannon create a provider with the owner as another address - // Do we need this check? - revert NotOwnerOrProvider(); - } + function providerRegister(uint256 amount_, string calldata endpoint_) external { + BidsStorage storage bidsStorage = _getBidsStorage(); - Provider memory provider_ = providers(providerAddress_); - uint256 newStake_ = provider_.stake + amount_; - if (newStake_ < providerMinimumStake()) { - revert StakeTooLow(); + if (amount_ > 0) { + IERC20(bidsStorage.token).safeTransferFrom(_msgSender(), address(this), amount_); } - if (amount_ > 0) { - getToken().safeTransferFrom(_msgSender(), address(this), amount_); + PovidersStorage storage providersStorage = _getProvidersStorage(); + Provider storage provider = providersStorage.providers[_msgSender()]; + + uint256 newStake_ = provider.stake + amount_; + uint256 minStake_ = providersStorage.providerMinimumStake; + if (newStake_ < minStake_) { + revert ProviderStakeTooLow(newStake_, minStake_); } - // if we add stake to an existing provider the limiter period is not reset - uint128 createdAt_ = provider_.createdAt; - uint128 periodEnd_ = provider_.limitPeriodEnd; - if (createdAt_ == 0) { - setProviderActive(providerAddress_, true); - createdAt_ = uint128(block.timestamp); - periodEnd_ = createdAt_ + PROVIDER_REWARD_LIMITER_PERIOD; - } else if (provider_.isDeleted) { - setProviderActive(providerAddress_, true); + if (provider.createdAt == 0) { + provider.createdAt = uint128(block.timestamp); + provider.limitPeriodEnd = uint128(block.timestamp) + PROVIDER_REWARD_LIMITER_PERIOD; + } else if (provider.isDeleted) { + provider.isDeleted = false; } - setProvider( - providerAddress_, - Provider(endpoint_, newStake_, createdAt_, periodEnd_, provider_.limitPeriodEarned, false) - ); + provider.endpoint = endpoint_; + provider.stake = newStake_; + + providersStorage.activeProviders.add(_msgSender()); - emit ProviderRegisteredUpdated(providerAddress_); + emit ProviderRegistered(_msgSender()); } - /// @notice Deregisters a provider - function providerDeregister(address provider_) external { - if (!_ownerOrProvider(provider_)) { - revert NotOwnerOrProvider(); - } - if (!isProviderExists(provider_)) { + function providerDeregister() external { + address provider_ = _msgSender(); + + PovidersStorage storage providersStorage = _getProvidersStorage(); + Provider storage provider = providersStorage.providers[provider_]; + + if (provider.createdAt == 0) { revert ProviderNotFound(); } - if (!isProviderActiveBidsEmpty(provider_)) { + if (!_isProviderActiveBidsEmpty(provider_)) { revert ProviderHasActiveBids(); } + if (provider.isDeleted) { + revert ProviderHasAlreadyDeregistered(); + } - setProviderActive(provider_, false); - - Provider storage provider = providers(provider_); - uint256 withdrawable_ = _getWithdrawableStake(provider); + uint256 withdrawAmount_ = _getWithdrawAmount(provider); - provider.stake -= withdrawable_; + provider.stake -= withdrawAmount_; provider.isDeleted = true; - if (withdrawable_ > 0) { - getToken().safeTransfer(_msgSender(), withdrawable_); - } + providersStorage.activeProviders.remove(provider_); - 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(address provider_) external { - Provider storage provider = providers(provider_); - if (!provider.isDeleted) { - revert ErrProviderNotDeleted(); - } - if (provider.stake == 0) { - revert ErrNoStake(); + if (withdrawAmount_ > 0) { + BidsStorage storage bidsStorage = _getBidsStorage(); + IERC20(bidsStorage.token).safeTransfer(provider_, withdrawAmount_); } - uint256 withdrawable_ = _getWithdrawableStake(provider); - if (withdrawable_ == 0) { - revert ErrNoWithdrawableStake(); - } - - provider.stake -= withdrawable_; - - getToken().safeTransfer(provider_, withdrawable_); - - emit ProviderWithdrawnStake(provider_, withdrawable_); - } - - function isProviderExists(address provider_) public view returns (bool) { - return providers(provider_).createdAt != 0; + emit ProviderDeregistered(provider_); } - /// @notice Returns the withdrawable stake for a provider - /// @dev If the provider already earned this period then withdrawable stake - /// is limited by the amount earning that remains in the current period. - /// It is done to prevent the provider from withdrawing and then staking - /// again from a different address, which bypasses the limitation. - function _getWithdrawableStake(Provider memory provider_) private view returns (uint256) { - if (uint128(block.timestamp) > provider_.limitPeriodEnd) { - return provider_.stake; + // /** + // * + // * @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 + * is limited by the amount earning that remains in the current period. + * It is done to prevent the provider from withdrawing and then staking + * again from a different address, which bypasses the limitation. + */ + function _getWithdrawAmount(Provider storage provider) private view returns (uint256) { + if (block.timestamp > provider.limitPeriodEnd) { + return provider.stake; } - return provider_.stake - provider_.limitPeriodEarned; - } - - function _ownerOrProvider(address provider_) internal view returns (bool) { - return _msgSender() == owner() || _msgSender() == provider_; + return provider.stake - provider.limitPeriodEarned; } } diff --git a/smart-contracts/contracts/diamond/facets/SessionRouter.sol b/smart-contracts/contracts/diamond/facets/SessionRouter.sol index 9f9b1ed4..e7edf4a3 100644 --- a/smart-contracts/contracts/diamond/facets/SessionRouter.sol +++ b/smart-contracts/contracts/diamond/facets/SessionRouter.sol @@ -5,6 +5,8 @@ import {Math} from "@openzeppelin/contracts/utils/math/Math.sol"; import {ECDSA} from "@openzeppelin/contracts/utils/cryptography/ECDSA.sol"; import {SafeERC20, IERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; +import {LinearDistributionIntervalDecrease} from "morpheus-smart-contracts/contracts/libs/LinearDistributionIntervalDecrease.sol"; + import {OwnableDiamondStorage} from "../presets/OwnableDiamondStorage.sol"; import {BidStorage, EnumerableSet} from "../storages/BidStorage.sol"; @@ -16,7 +18,7 @@ import {LibSD} from "../../libs/LibSD.sol"; import {ISessionRouter} from "../../interfaces/facets/ISessionRouter.sol"; -import {LinearDistributionIntervalDecrease} from "morpheus-smart-contracts/contracts/libs/LinearDistributionIntervalDecrease.sol"; +import "hardhat/console.sol"; contract SessionRouter is ISessionRouter, @@ -26,519 +28,489 @@ contract SessionRouter is BidStorage, StatsStorage { - using Math for uint256; + using Math for *; using LibSD for LibSD.SD; using SafeERC20 for IERC20; using EnumerableSet for EnumerableSet.Bytes32Set; - uint32 public constant MIN_SESSION_DURATION = 5 minutes; - uint32 public constant MAX_SESSION_DURATION = 1 days; - uint32 public constant SIGNATURE_TTL = 10 minutes; - uint256 public constant COMPUTE_POOL_INDEX = 3; - function __SessionRouter_init( address fundingAccount_, + uint128 maxSessionDuration_, Pool[] calldata pools_ - ) external initializer(SESSION_STORAGE_SLOT) { - SNStorage storage s = _getSessionStorage(); - - s.fundingAccount = fundingAccount_; + ) external initializer(SESSIONS_STORAGE_SLOT) { + SessionsStorage storage sessionsStorage = _getSessionsStorage(); + setMaxSessionDuration(maxSessionDuration_); + sessionsStorage.fundingAccount = fundingAccount_; for (uint256 i = 0; i < pools_.length; i++) { - s.pools.push(pools_[i]); + sessionsStorage.pools.push(pools_[i]); } } + //////////////////////////// + /// CONTRACT CONFIGS /// + //////////////////////////// + /** + * @notice Sets distibution pool configuration + * @dev parameters should be the same as in Ethereum L1 Distribution contract + * @dev at address 0x47176B2Af9885dC6C4575d4eFd63895f7Aaa4790 + * @dev call 'Distribution.pools(3)' where '3' is a poolId + */ + function setPoolConfig(uint256 index_, Pool calldata pool_) external onlyOwner { + SessionsStorage storage sessionsStorage = _getSessionsStorage(); + + if (index_ >= sessionsStorage.pools.length) { + revert SessionPoolIndexOutOfBounds(); + } + + sessionsStorage.pools[index_] = pool_; + } + + function setMaxSessionDuration(uint128 maxSessionDuration_) public onlyOwner { + if (maxSessionDuration_ < MIN_SESSION_DURATION) { + revert SessionMaxDurationTooShort(); + } + + _getSessionsStorage().maxSessionDuration = maxSessionDuration_; + } + + //////////////////////// + /// OPEN SESSION /// + //////////////////////// function openSession( uint256 amount_, - bytes calldata providerApproval_, + bool isDirectPaymentFromUser_, + bytes calldata approvalEncoded_, bytes calldata signature_ ) external returns (bytes32) { - // should a user pass the bidId to compare with a providerApproval? - bytes32 bidId_ = _extractProviderApproval(providerApproval_); + SessionsStorage storage sessionsStorage = _getSessionsStorage(); - Bid memory bid_ = getBid(bidId_); - if (bid_.deletedAt != 0 || bid_.createdAt == 0) { - // wtf? - revert BidNotFound(); - } - if (!_isValidReceipt(bid_.provider, providerApproval_, signature_)) { - revert ProviderSignatureMismatch(); - } - if (isApprovalUsed(providerApproval_)) { - revert DuplicateApproval(); - } - setApprovalUsed(providerApproval_); + bytes32 bidId_ = _extractProviderApproval(approvalEncoded_); + Bid storage bid = _getBidsStorage().bids[bidId_]; - uint256 endsAt_ = whenSessionEnds(amount_, bid_.pricePerSecond, block.timestamp); - if (endsAt_ - block.timestamp < MIN_SESSION_DURATION) { - revert SessionTooShort(); - } + bytes32 sessionId_ = getSessionId(_msgSender(), bid.provider, bidId_, sessionsStorage.sessionNonce++); + Session storage session = sessionsStorage.sessions[sessionId_]; - // do we need to specify the amount in id? - bytes32 sessionId_ = getSessionId(_msgSender(), bid_.provider, amount_, incrementSessionNonce()); - setSession( - sessionId_, - Session({ - id: sessionId_, - user: _msgSender(), - provider: bid_.provider, - modelId: bid_.modelId, - bidId: bidId_, - stake: amount_, - pricePerSecond: bid_.pricePerSecond, - closeoutReceipt: "", - closeoutType: 0, - providerWithdrawnAmount: 0, - openedAt: block.timestamp, - endsAt: endsAt_, - closedAt: 0 - }) - ); + uint128 endsAt_ = _validateSession(bidId_, amount_, isDirectPaymentFromUser_, approvalEncoded_, signature_); - addUserSessionId(_msgSender(), sessionId_); - addProviderSessionId(bid_.provider, sessionId_); - addModelSessionId(bid_.modelId, sessionId_); + IERC20(_getBidsStorage().token).safeTransferFrom(_msgSender(), address(this), amount_); - setUserSessionActive(_msgSender(), sessionId_, true); - setProviderSessionActive(bid_.provider, sessionId_, true); + session.user = _msgSender(); + session.stake = amount_; + session.bidId = bidId_; + session.openedAt = uint128(block.timestamp); + session.endsAt = endsAt_; + session.isActive = true; + session.isDirectPaymentFromUser = isDirectPaymentFromUser_; - // try to use locked stake first, but limit iterations to 20 - // if user has more than 20 onHold entries, they will have to use withdrawUserStake separately - amount_ -= _removeUserStake(amount_, 10); + sessionsStorage.userSessions[_msgSender()].add(sessionId_); + sessionsStorage.providerSessions[bid.provider].add(sessionId_); + sessionsStorage.modelSessions[bid.modelId].add(sessionId_); - getToken().safeTransferFrom(_msgSender(), address(this), amount_); + sessionsStorage.isProviderApprovalUsed[approvalEncoded_] = true; - emit SessionOpened(_msgSender(), sessionId_, bid_.provider); + emit SessionOpened(_msgSender(), sessionId_, bid.provider); return sessionId_; } - function closeSession(bytes calldata receiptEncoded_, bytes calldata signature_) external { - (bytes32 sessionId_, uint32 tpsScaled1000_, uint32 ttftMs_) = _extractReceipt(receiptEncoded_); + function _validateSession( + bytes32 bidId_, + uint256 amount_, + bool isDirectPaymentFromUser_, + bytes calldata approvalEncoded_, + bytes calldata signature_ + ) private view returns (uint128) { + if (!isBidActive(bidId_)) { + revert SessionBidNotFound(); + } - Session storage session = _getSession(sessionId_); - if (session.openedAt == 0) { - revert SessionNotFound(); + Bid storage bid = _getBidsStorage().bids[bidId_]; + if (!_isValidProviderReceipt(bid.provider, approvalEncoded_, signature_)) { + revert SessionProviderSignatureMismatch(); } - if (!_ownerOrUser(session.user)) { - revert NotOwnerOrUser(); - } - if (session.closedAt != 0) { - revert SessionAlreadyClosed(); + if (_getSessionsStorage().isProviderApprovalUsed[approvalEncoded_]) { + revert SessionDuplicateApproval(); } - // update indexes - setUserSessionActive(session.user, sessionId_, false); - setProviderSessionActive(session.provider, sessionId_, false); - - // update session record - session.closeoutReceipt = receiptEncoded_; //TODO: remove that field in favor of tps and ttftMs - session.closedAt = block.timestamp; - - // calculate provider withdraw - uint256 providerWithdraw_; - uint256 startOfToday_ = startOfTheDay(block.timestamp); - bool isClosingLate_ = startOfToday_ > startOfTheDay(session.endsAt); - bool noDispute_ = _isValidReceipt(session.provider, receiptEncoded_, signature_); - - if (noDispute_ || isClosingLate_) { - // session was closed without dispute or next day after it expected to end - uint256 duration_ = session.endsAt.min(block.timestamp) - session.openedAt; - uint256 cost_ = duration_ * session.pricePerSecond; - providerWithdraw_ = cost_ - session.providerWithdrawnAmount; - } else { - // session was closed on the same day or earlier with dispute - // withdraw all funds except for today's session cost - uint256 durationTillToday_ = startOfToday_ - session.openedAt.min(startOfToday_); - uint256 costTillToday_ = durationTillToday_ * session.pricePerSecond; - providerWithdraw_ = costTillToday_ - session.providerWithdrawnAmount; - } + uint128 endsAt_ = getSessionEnd(amount_, bid.pricePerSecond, uint128(block.timestamp)); + uint128 duration_ = endsAt_ - uint128(block.timestamp); - // updating provider stats - ProviderModelStats storage prStats = _getProviderModelStats(session.modelId, session.provider); - ModelStats storage modelStats = _getModelStats(session.modelId); + if (duration_ < MIN_SESSION_DURATION) { + revert SessionTooShort(); + } - prStats.totalCount++; + // This situation cannot be achieved in theory, but just in case, I'll leave it at that + if (isDirectPaymentFromUser_ && (duration_ * bid.pricePerSecond) > amount_) { + revert SessionStakeTooLow(); + } - if (noDispute_) { - if (prStats.successCount > 0) { - // stats for this provider-model pair already contribute to average model stats - modelStats.tpsScaled1000.remove(int32(prStats.tpsScaled1000.mean), int32(modelStats.count - 1)); - modelStats.ttftMs.remove(int32(prStats.ttftMs.mean), int32(modelStats.count - 1)); - } else { - // stats for this provider-model pair do not contribute - modelStats.count++; - } + return endsAt_; + } - // update provider-model stats - prStats.successCount++; - prStats.totalDuration += uint32(session.closedAt - session.openedAt); - prStats.tpsScaled1000.add(int32(tpsScaled1000_), int32(prStats.successCount)); - prStats.ttftMs.add(int32(ttftMs_), int32(prStats.successCount)); + function getSessionId( + address user_, + address provider_, + bytes32 bidId_, + uint256 sessionNonce_ + ) public pure returns (bytes32) { + return keccak256(abi.encodePacked(user_, provider_, bidId_, sessionNonce_)); + } - // update model stats - modelStats.totalDuration.add(int32(prStats.totalDuration), int32(modelStats.count)); - modelStats.tpsScaled1000.add(int32(prStats.tpsScaled1000.mean), int32(modelStats.count)); - modelStats.ttftMs.add(int32(prStats.ttftMs.mean), int32(modelStats.count)); - } else { - session.closeoutType = 1; - } + function getSessionEnd(uint256 amount_, uint256 pricePerSecond_, uint128 openedAt_) public view returns (uint128) { + uint128 duration_ = uint128(stakeToStipend(amount_, openedAt_) / pricePerSecond_); - // we have to lock today's stake so the user won't get the reward twice - uint256 userStakeToLock_ = 0; - if (!isClosingLate_) { - // session was closed on the same day - // lock today's stake - uint256 todaysDuration_ = session.endsAt.min(block.timestamp) - session.openedAt.max(startOfToday_); - uint256 todaysCost_ = todaysDuration_ * session.pricePerSecond; - userStakeToLock_ = session.stake.min(stipendToStake(todaysCost_, startOfToday_)); - addOnHold(session.user, OnHold(userStakeToLock_, uint128(startOfToday_ + 1 days))); + if (duration_ > _getSessionsStorage().maxSessionDuration) { + duration_ = _getSessionsStorage().maxSessionDuration; } - uint256 userWithdraw_ = session.stake - userStakeToLock_; - emit SessionClosed(session.user, sessionId_, session.provider); + return openedAt_ + duration_; + } - // withdraw provider - _rewardProvider(session, providerWithdraw_, false); + /** + * @dev Returns stipend of user based on their stake + * (User session stake amount / MOR Supply without Compute) * (MOR Compute Supply / 100) + * (User share) * (Rewards for all computes) + */ + function stakeToStipend(uint256 amount_, uint128 timestamp_) public view returns (uint256) { + uint256 totalMorSupply_ = totalMORSupply(timestamp_); + if (totalMorSupply_ == 0) { + return 0; + } - getToken().safeTransfer(session.user, userWithdraw_); + return (amount_ * getComputeBalance(timestamp_)) / (totalMorSupply_ * 100); } - /// @notice allows provider to claim their funds - function claimProviderBalance(bytes32 sessionId_, uint256 amountToWithdraw_) external { - Session storage session = _getSession(sessionId_); - if (session.openedAt == 0) { - revert SessionNotFound(); + function _extractProviderApproval(bytes calldata providerApproval_) private view returns (bytes32) { + (bytes32 bidId_, uint256 chainId_, address user_, uint128 timestamp_) = abi.decode( + providerApproval_, + (bytes32, uint256, address, uint128) + ); + + if (user_ != _msgSender()) { + revert SessionApprovedForAnotherUser(); } - if (!_ownerOrProvider(session.provider)) { - revert NotOwnerOrProvider(); + if (chainId_ != block.chainid) { + revert SesssionApprovedForAnotherChainId(); + } + if (block.timestamp > timestamp_ + SIGNATURE_TTL) { + revert SesssionApproveExpired(); } - uint256 withdrawableAmount = _getProviderClaimableBalance(session); - if (amountToWithdraw_ > withdrawableAmount) { - revert NotEnoughWithdrawableBalance(); + return bidId_; + } + + /////////////////////////////////// + /// CLOSE SESSION, WITHDRAW /// + /////////////////////////////////// + function closeSession(bytes calldata receiptEncoded_, bytes calldata signature_) external { + (bytes32 sessionId_, uint32 tpsScaled1000_, uint32 ttftMs_) = _extractProviderReceipt(receiptEncoded_); + + Session storage session = _getSessionsStorage().sessions[sessionId_]; + Bid storage bid = _getBidsStorage().bids[session.bidId]; + + _onlyAccount(session.user); + if (session.closedAt != 0) { + revert SessionAlreadyClosed(); } - _rewardProvider(session, amountToWithdraw_, true); + session.isActive = false; + session.closeoutReceipt = receiptEncoded_; // TODO: Remove that field in favor of tps and ttftMs + session.closedAt = uint128(block.timestamp); + + bool noDispute_ = _isValidProviderReceipt(bid.provider, receiptEncoded_, signature_); + + _rewardUserAfterClose(session, bid); + _rewardProviderAfterClose(noDispute_, session, bid); + _setStats(noDispute_, ttftMs_, tpsScaled1000_, session, bid); + + emit SessionClosed(session.user, sessionId_, bid.provider); } - /// @notice deletes session from the history - function deleteHistory(bytes32 sessionId_) external { - // Why do we need this function? - Session storage session = _getSession(sessionId_); - if (!_ownerOrUser(session.user)) { - revert NotOwnerOrUser(); + function _extractProviderReceipt(bytes calldata receiptEncoded_) private view returns (bytes32, uint32, uint32) { + (bytes32 sessionId_, uint256 chainId_, uint128 timestamp_, uint32 tpsScaled1000_, uint32 ttftMs_) = abi.decode( + receiptEncoded_, + (bytes32, uint256, uint128, uint32, uint32) + ); + + if (chainId_ != block.chainid) { + revert SesssionReceiptForAnotherChainId(); } - if (session.closedAt == 0) { - revert SessionNotClosed(); + if (block.timestamp > timestamp_ + SIGNATURE_TTL) { + revert SesssionReceiptExpired(); } - session.user = address(0); + return (sessionId_, tpsScaled1000_, ttftMs_); } - /// @notice withdraws user stake - /// @param amountToWithdraw_ amount of funds to withdraw, maxUint256 means all available - /// @param iterations_ number of entries to process - function withdrawUserStake(uint256 amountToWithdraw_, uint8 iterations_) external { - // withdraw all available funds if amountToWithdraw is 0 - if (amountToWithdraw_ == 0) { - revert AmountToWithdrawIsZero(); + function _getProviderRewards( + Session storage session, + Bid storage bid, + bool isIncludeWithdrawnAmount_ + ) private view returns (uint256) { + uint256 sessionEnd_ = session.closedAt == 0 ? session.endsAt : session.closedAt.min(session.endsAt); + if (block.timestamp < sessionEnd_) { + return 0; } - uint256 removed_ = _removeUserStake(amountToWithdraw_, iterations_); - if (removed_ < amountToWithdraw_) { - revert NotEnoughWithdrawableBalance(); + uint256 withdrawnAmount = isIncludeWithdrawnAmount_ ? session.providerWithdrawnAmount : 0; + + return (sessionEnd_ - session.openedAt) * bid.pricePerSecond - withdrawnAmount; + } + + function _rewardProviderAfterClose(bool noDispute_, Session storage session, Bid storage bid) internal { + uint128 startOfToday_ = startOfTheDay(uint128(block.timestamp)); + bool isClosingLate_ = uint128(block.timestamp) > session.endsAt; + + uint256 providerAmountToWithdraw_ = _getProviderRewards(session, bid, true); + uint256 providerOnHoldAmount = 0; + if (!noDispute_ && !isClosingLate_) { + providerOnHoldAmount = + (session.endsAt.min(session.closedAt) - startOfToday_.max(session.openedAt)) * + bid.pricePerSecond; } + providerAmountToWithdraw_ -= providerOnHoldAmount; - getToken().safeTransfer(_msgSender(), amountToWithdraw_); + _claimForProvider(session, providerAmountToWithdraw_); } - /// @dev removes user stake amount from onHold entries - function _removeUserStake(uint256 amountToRemove_, uint8 iterations_) private returns (uint256) { - uint256 balance_ = 0; + function _rewardUserAfterClose(Session storage session, Bid storage bid) private { + uint128 startOfToday_ = startOfTheDay(uint128(block.timestamp)); + bool isClosingLate_ = uint128(block.timestamp) > session.endsAt; - OnHold[] storage onHoldEntries = getOnHold(_msgSender()); - iterations_ = iterations_ > onHoldEntries.length ? uint8(onHoldEntries.length) : iterations_; + 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 userInitialLock_ = userDuration_ * bid.pricePerSecond; + userStakeToLock_ = userStake.min(stipendToStake(userInitialLock_, startOfToday_)); - // the only loop that is not avoidable - for (uint256 i = 0; i < onHoldEntries.length && iterations_ > 0; i++) { - if (block.timestamp < onHoldEntries[i].releaseAt) { - continue; - } + _getSessionsStorage().userStakesOnHold[session.user].push( + OnHold(userStakeToLock_, uint128(startOfToday_ + 1 days)) + ); + } + uint256 userAmountToWithdraw_ = userStake - userStakeToLock_; + IERC20(_getBidsStorage().token).safeTransfer(session.user, userAmountToWithdraw_); + } - balance_ += onHoldEntries[i].amount; + function _setStats( + bool noDispute_, + uint32 ttftMs_, + uint32 tpsScaled1000_, + Session storage session, + Bid storage bid + ) internal { + ProviderModelStats storage prStats = _providerModelStats(bid.modelId, bid.provider); + ModelStats storage modelStats = _modelStats(bid.modelId); - if (balance_ >= amountToRemove_) { - onHoldEntries[i].amount = balance_ - amountToRemove_; - return amountToRemove_; - } + prStats.totalCount++; - // Remove entry by swapping with last element and popping - uint256 lastIndex_ = onHoldEntries.length - 1; - if (i < lastIndex_) { - onHoldEntries[i] = onHoldEntries[lastIndex_]; - i--; // TODO: is it correct? + if (noDispute_) { + if (prStats.successCount > 0) { + // Stats for this provider-model pair already contribute to average model stats + modelStats.tpsScaled1000.remove(int32(prStats.tpsScaled1000.mean), int32(modelStats.count - 1)); + modelStats.ttftMs.remove(int32(prStats.ttftMs.mean), int32(modelStats.count - 1)); + } else { + // Stats for this provider-model pair do not contribute + modelStats.count++; } - onHoldEntries.pop(); - iterations_--; - } + // Update provider model stats + prStats.successCount++; + prStats.totalDuration += uint32(session.closedAt - session.openedAt); + prStats.tpsScaled1000.add(int32(tpsScaled1000_), int32(prStats.successCount)); + prStats.ttftMs.add(int32(ttftMs_), int32(prStats.successCount)); - return balance_; + // Update model stats + modelStats.totalDuration.add(int32(prStats.totalDuration), int32(modelStats.count)); + modelStats.tpsScaled1000.add(int32(prStats.tpsScaled1000.mean), int32(modelStats.count)); + modelStats.ttftMs.add(int32(prStats.ttftMs.mean), int32(modelStats.count)); + } else { + session.closeoutType = 1; + } } - ///////////////////////// - // STATS FUNCTIONS // - ///////////////////////// - - /// @notice sets distibution pool configuration - /// @dev parameters should be the same as in Ethereum L1 Distribution contract - /// @dev at address 0x47176B2Af9885dC6C4575d4eFd63895f7Aaa4790 - /// @dev call 'Distribution.pools(3)' where '3' is a poolId - function setPoolConfig(uint256 index, Pool calldata pool) external onlyOwner { - if (index >= getPools().length) { - revert PoolIndexOutOfBounds(); - } - _getSessionStorage().pools[index] = pool; + /** + * @dev Allows providers to receive their funds after the end or closure of the session + */ + function claimForProvider(bytes32 sessionId_) external { + Session storage session = _getSessionsStorage().sessions[sessionId_]; + Bid storage bid = _getBidsStorage().bids[session.bidId]; + + _onlyAccount(bid.provider); + _claimForProvider(session, _getProviderRewards(session, bid, true)); } - function _maybeResetProviderRewardLimiter(Provider storage provider) private { + /** + * @dev Sends provider reward considering stake as the limit for the reward + * @param session Storage session object + * @param amount_ Amount of reward to send + */ + function _claimForProvider(Session storage session, uint256 amount_) private { + Bid storage bid = _getBidsStorage().bids[session.bidId]; + Provider storage provider = _getProvidersStorage().providers[bid.provider]; + if (block.timestamp > provider.limitPeriodEnd) { - provider.limitPeriodEnd += PROVIDER_REWARD_LIMITER_PERIOD; + provider.limitPeriodEnd = uint128(block.timestamp) + PROVIDER_REWARD_LIMITER_PERIOD; provider.limitPeriodEarned = 0; } - } - /// @notice sends provider reward considering stake as the limit for the reward - /// @param session session storage object - /// @param reward_ amount of reward to send - /// @param revertOnReachingLimit_ if true function will revert if reward is more than stake, otherwise just limit the reward - function _rewardProvider(Session storage session, uint256 reward_, bool revertOnReachingLimit_) private { - Provider storage provider = providers(session.provider); - _maybeResetProviderRewardLimiter(provider); - uint256 limit_ = provider.stake - provider.limitPeriodEarned; - - if (reward_ > limit_) { - if (revertOnReachingLimit_) { - revert WithdrawableBalanceLimitByStakeReached(); - } - reward_ = limit_; + uint256 providerClaimLimit_ = provider.stake - provider.limitPeriodEarned; + + amount_ = amount_.min(providerClaimLimit_); + if (amount_ == 0) { + return; + } + + session.providerWithdrawnAmount += amount_; + provider.limitPeriodEarned += amount_; + _getSessionsStorage().providersTotalClaimed += amount_; + + if (session.isDirectPaymentFromUser) { + IERC20(_getBidsStorage().token).safeTransfer(bid.provider, amount_); + } else { + IERC20(_getBidsStorage().token).safeTransferFrom(_getSessionsStorage().fundingAccount, bid.provider, amount_); } + } - getToken().safeTransferFrom(getFundingAccount(), session.provider, reward_); + /** + * @notice Returns stake of user based on their stipend + */ + function stipendToStake(uint256 stipend_, uint128 timestamp_) public view returns (uint256) { + uint256 computeBalance_ = getComputeBalance(timestamp_); + if (computeBalance_ == 0) { + return 0; + } - session.providerWithdrawnAmount += reward_; - increaseTotalClaimed(reward_); - provider.limitPeriodEarned += reward_; + return (stipend_ * totalMORSupply(timestamp_) * 100) / computeBalance_; } - /// @notice returns amount of withdrawable user stake and one on hold - function withdrawableUserStake( + function getUserStakesOnHold( address user_, uint8 iterations_ - ) external view returns (uint256 avail_, uint256 hold_) { - OnHold[] memory onHold = getOnHold(user_); + ) external view returns (uint256 available_, uint256 hold_) { + OnHold[] memory onHold = _getSessionsStorage().userStakesOnHold[user_]; iterations_ = iterations_ > onHold.length ? uint8(onHold.length) : iterations_; for (uint256 i = 0; i < onHold.length; i++) { uint256 amount = onHold[i].amount; + if (block.timestamp < onHold[i].releaseAt) { hold_ += amount; } else { - avail_ += amount; + available_ += amount; } } } - function getSessionId( - address user_, - address provider_, - uint256 stake_, - uint256 sessionNonce_ - ) public pure returns (bytes32) { - return keccak256(abi.encodePacked(user_, provider_, stake_, sessionNonce_)); - } + function withdrawUserStakes(uint8 iterations_) external { + OnHold[] storage onHoldEntries = _getSessionsStorage().userStakesOnHold[_msgSender()]; + uint8 count_ = iterations_ >= onHoldEntries.length ? uint8(onHoldEntries.length) : iterations_; + uint256 length_ = onHoldEntries.length; + uint256 amount_ = 0; - /// @notice returns stipend of user based on their stake - function stakeToStipend(uint256 sessionStake_, uint256 timestamp_) public view returns (uint256) { - // inlined getTodaysBudget call to get a better precision - return (sessionStake_ * getComputeBalance(timestamp_)) / (totalMORSupply(timestamp_) * 100); - } + if (length_ == 0 || count_ == 0) { + revert SessionUserAmountToWithdrawIsZero(); + } - /// @notice returns stake of user based on their stipend - function stipendToStake(uint256 stipend_, uint256 timestamp_) public view returns (uint256) { - // inlined getTodaysBudget call to get a better precision - // return (stipend * totalMORSupply(timestamp)) / getTodaysBudget(timestamp); - return (stipend_ * totalMORSupply(timestamp_) * 100) / getComputeBalance(timestamp_); - } + uint8 removedCount_; + for (uint256 i = length_; i > 0 && removedCount_ < count_; i--) { + if (block.timestamp < onHoldEntries[i - 1].releaseAt) { + continue; + } + + amount_ += onHoldEntries[i - 1].amount; + + onHoldEntries[i - 1] = onHoldEntries[length_ - 1]; + onHoldEntries.pop(); + length_--; + removedCount_++; + } - /// @dev make it pure - function whenSessionEnds( - uint256 sessionStake_, - uint256 pricePerSecond_, - uint256 openedAt_ - ) public view returns (uint256) { - // if session stake is more than daily price then session will last for its max duration - uint256 duration = stakeToStipend(sessionStake_, openedAt_) / pricePerSecond_; - if (duration >= MAX_SESSION_DURATION) { - return openedAt_ + MAX_SESSION_DURATION; + if (amount_ == 0) { + revert SessionUserAmountToWithdrawIsZero(); } - return openedAt_ + duration; + IERC20(_getBidsStorage().token).safeTransfer(_msgSender(), amount_); + + emit UserWithdrawn(_msgSender(), amount_); } - /// @notice returns today's budget in MOR - function getTodaysBudget(uint256 timestamp_) public view returns (uint256) { - return getComputeBalance(timestamp_) / 100; // 1% of Compute Balance + //////////////////////// + /// GLOBAL PUBLIC /// + //////////////////////// + + /** + * @dev Returns today's budget in MOR. 1% + */ + function getTodaysBudget(uint128 timestamp_) external view returns (uint256) { + return getComputeBalance(timestamp_) / 100; } - /// @notice returns today's compute balance in MOR - function getComputeBalance(uint256 timestamp_) public view returns (uint256) { - Pool memory pool = getPool(COMPUTE_POOL_INDEX); + /** + * @dev Returns today's compute balance in MOR without claimed amount + */ + function getComputeBalance(uint128 timestamp_) public view returns (uint256) { + SessionsStorage storage sessionsStorage = _getSessionsStorage(); + Pool memory pool_ = sessionsStorage.pools[COMPUTE_POOL_INDEX]; + uint256 periodReward = LinearDistributionIntervalDecrease.getPeriodReward( - pool.initialReward, - pool.rewardDecrease, - pool.payoutStart, - pool.decreaseInterval, - pool.payoutStart, + pool_.initialReward, + pool_.rewardDecrease, + pool_.payoutStart, + pool_.decreaseInterval, + pool_.payoutStart, uint128(startOfTheDay(timestamp_)) ); - return periodReward - totalClaimed(); + return periodReward - sessionsStorage.providersTotalClaimed; } - // returns total amount of MOR tokens that were distributed across all pools - function totalMORSupply(uint256 timestamp_) public view returns (uint256) { + /** + * @dev Total amount of MOR tokens that were distributed across all pools + * without compute pool rewards and with compute claimed rewards + */ + function totalMORSupply(uint128 timestamp_) public view returns (uint256) { uint256 startOfTheDay_ = startOfTheDay(timestamp_); uint256 totalSupply_ = 0; - Pool[] memory pools = getPools(); - for (uint256 i = 0; i < pools.length; i++) { - if (i == COMPUTE_POOL_INDEX) continue; // skip compute pool (it's calculated separately) + SessionsStorage storage sessionsStorage = _getSessionsStorage(); + uint256 poolsLength_ = sessionsStorage.pools.length; + + for (uint256 i = 0; i < poolsLength_; i++) { + if (i == COMPUTE_POOL_INDEX) continue; - Pool memory pool = pools[i]; + Pool memory pool_ = sessionsStorage.pools[i]; totalSupply_ += LinearDistributionIntervalDecrease.getPeriodReward( - pool.initialReward, - pool.rewardDecrease, - pool.payoutStart, - pool.decreaseInterval, - pool.payoutStart, + pool_.initialReward, + pool_.rewardDecrease, + pool_.payoutStart, + pool_.decreaseInterval, + pool_.payoutStart, uint128(startOfTheDay_) ); } - return totalSupply_ + totalClaimed(); + return totalSupply_ + sessionsStorage.providersTotalClaimed; } - function getActiveBidsRatingByModel( - bytes32 modelId_, - uint256 offset_, - uint8 limit_ - ) external view returns (bytes32[] memory, Bid[] memory, ProviderModelStats[] memory) { - bytes32[] memory modelBidsSet_ = modelActiveBids(modelId_, offset_, limit_); - uint256 length_ = modelBidsSet_.length; - - Bid[] memory bids_ = new Bid[](length_); - bytes32[] memory bidIds_ = new bytes32[](length_); - ProviderModelStats[] memory stats_ = new ProviderModelStats[](length_); - - for (uint i = 0; i < length_; i++) { - bytes32 id_ = modelBidsSet_[i]; - bidIds_[i] = id_; - Bid memory bid_ = getBid(id_); - bids_[i] = bid_; - stats_[i] = _getProviderModelStats(modelId_, bid_.provider); - } - - return (bidIds_, bids_, stats_); - } - - function startOfTheDay(uint256 timestamp_) public pure returns (uint256) { + function startOfTheDay(uint128 timestamp_) public pure returns (uint128) { return timestamp_ - (timestamp_ % 1 days); } - function _extractProviderApproval(bytes calldata providerApproval_) private view returns (bytes32) { - (bytes32 bidId_, uint256 chainId_, address user_, uint128 timestamp_) = abi.decode( - providerApproval_, - (bytes32, uint256, address, uint128) - ); + ////////////////////////// + /// GLOBAL PRIVATE /// + ////////////////////////// - if (user_ != _msgSender()) { - revert ApprovedForAnotherUser(); - } - if (chainId_ != block.chainid) { - revert WrongChainId(); - } - if (timestamp_ < block.timestamp - SIGNATURE_TTL) { - revert SignatureExpired(); - } - - return bidId_; - } - - function _extractReceipt(bytes calldata receiptEncoded_) private view returns (bytes32, uint32, uint32) { - (bytes32 sessionId_, uint256 chainId_, uint128 timestamp_, uint32 tpsScaled1000_, uint32 ttftMs_) = abi.decode( - receiptEncoded_, - (bytes32, uint256, uint128, uint32, uint32) - ); - - if (chainId_ != block.chainid) { - revert WrongChainId(); - } - if (timestamp_ < block.timestamp - SIGNATURE_TTL) { - revert SignatureExpired(); - } - - return (sessionId_, tpsScaled1000_, ttftMs_); - } - - function _getProviderClaimableBalance(Session memory session_) private view returns (uint256) { - // if session was closed with no dispute - provider already got all funds - // - // if session was closed with dispute - - // if session was ended but not closed - - // if session was not ended - provider can claim all funds except for today's session cost - - uint256 claimIntervalEnd_ = session_.closedAt.min(session_.endsAt.min(startOfTheDay(block.timestamp))); - uint256 claimableDuration_ = claimIntervalEnd_.max(session_.openedAt) - session_.openedAt; - uint256 totalCost_ = claimableDuration_ * session_.pricePerSecond; - uint256 withdrawableAmount_ = totalCost_ - session_.providerWithdrawnAmount; - - return withdrawableAmount_; - } - - /// @notice returns total claimanble balance for the provider for particular session - function getProviderClaimableBalance(bytes32 sessionId_) public view returns (uint256) { - Session memory session_ = _getSession(sessionId_); - if (session_.openedAt == 0) { - revert SessionNotFound(); - } - - return _getProviderClaimableBalance(session_); - } - - /// @notice checks if receipt is valid - function _isValidReceipt( - address signer_, + function _isValidProviderReceipt( + address provider_, bytes calldata receipt_, bytes calldata signature_ ) private pure returns (bool) { - if (signature_.length == 0) { - return false; - } - bytes32 receiptHash_ = ECDSA.toEthSignedMessageHash(keccak256(receipt_)); - return ECDSA.recover(receiptHash_, signature_) == signer_; - } - - function _ownerOrProvider(address provider_) private view returns (bool) { - return _msgSender() == owner() || _msgSender() == provider_; - } - - function _ownerOrUser(address user_) private view returns (bool) { - return _msgSender() == owner() || _msgSender() == user_; + return ECDSA.recover(receiptHash_, signature_) == provider_; } } diff --git a/smart-contracts/contracts/diamond/presets/OwnableDiamondStorage.sol b/smart-contracts/contracts/diamond/presets/OwnableDiamondStorage.sol index e03351a5..d671a880 100644 --- a/smart-contracts/contracts/diamond/presets/OwnableDiamondStorage.sol +++ b/smart-contracts/contracts/diamond/presets/OwnableDiamondStorage.sol @@ -7,7 +7,7 @@ import {Context} from "@openzeppelin/contracts/utils/Context.sol"; abstract contract OwnableDiamondStorage is DiamondOwnableStorage, Context { /** - * @dev The caller account is not authorized to perform an operation. + * @dev The caller account is not authorized to perform an operation as owner. */ error OwnableUnauthorizedAccount(address account_); @@ -16,4 +16,10 @@ 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 8c418ace..7a2db7ee 100644 --- a/smart-contracts/contracts/diamond/storages/BidStorage.sol +++ b/smart-contracts/contracts/diamond/storages/BidStorage.sol @@ -3,7 +3,6 @@ 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 {IBidStorage} from "../../interfaces/storage/IBidStorage.sol"; @@ -12,99 +11,75 @@ contract BidStorage is IBidStorage { using Paginator for *; using EnumerableSet for EnumerableSet.Bytes32Set; - struct BDStorage { - IERC20 token; // MOR token + struct BidsStorage { + address token; // MOR token mapping(bytes32 bidId => Bid) bids; // bidId = keccak256(provider, modelId, nonce) - mapping(bytes32 modelId => bytes32[]) modelBids; // keccak256(provider, modelId) => all bidIds + mapping(bytes32 modelId => EnumerableSet.Bytes32Set) modelBids; // keccak256(provider, modelId) => all bidIds mapping(bytes32 modelId => EnumerableSet.Bytes32Set) modelActiveBids; // modelId => active bidIds - mapping(address provider => bytes32[]) providerBids; // provider => all bidIds + mapping(address provider => EnumerableSet.Bytes32Set) providerBids; // provider => all bidIds mapping(address provider => EnumerableSet.Bytes32Set) providerActiveBids; // provider => active bidIds mapping(bytes32 providerModelId => uint256) providerModelNonce; // keccak256(provider, modelId) => last nonce } - bytes32 public constant BID_STORAGE_SLOT = keccak256("diamond.standard.bid.storage"); + bytes32 public constant BIDS_STORAGE_SLOT = keccak256("diamond.standard.bids.storage"); - function bids(bytes32 bidId) external view returns (Bid memory) { - return _getBidStorage().bids[bidId]; + /** PUBLIC, GETTERS */ + function getBid(bytes32 bidId_) external view returns (Bid memory) { + return _getBidsStorage().bids[bidId_]; } - function providerActiveBids( + function getProviderActiveBids( address provider_, uint256 offset_, uint256 limit_ ) external view returns (bytes32[] memory) { - return _getBidStorage().providerActiveBids[provider_].part(offset_, limit_); - } - - function modelActiveBids(bytes32 modelId_, uint256 offset_, uint256 limit_) public view returns (bytes32[] memory) { - return _getBidStorage().modelActiveBids[modelId_].part(offset_, limit_); - } - - function providerBids(address provider_, uint256 offset_, uint256 limit_) external view returns (bytes32[] memory) { - return _getBidStorage().providerBids[provider_].part(offset_, limit_); - } - - function modelBids(bytes32 modelId_, uint256 offset_, uint256 limit_) external view returns (bytes32[] memory) { - return _getBidStorage().modelBids[modelId_].part(offset_, limit_); - } - - function getToken() public view returns (IERC20) { - return _getBidStorage().token; - } - - function getBid(bytes32 bidId) internal view returns (Bid storage) { - return _getBidStorage().bids[bidId]; - } - - function addProviderActiveBids(address provider, bytes32 bidId) internal { - _getBidStorage().providerActiveBids[provider].add(bidId); + return _getBidsStorage().providerActiveBids[provider_].part(offset_, limit_); } - function addModelActiveBids(bytes32 modelId, bytes32 bidId) internal { - _getBidStorage().modelActiveBids[modelId].add(bidId); - } - - function removeProviderActiveBids(address provider, bytes32 bidId) internal { - _getBidStorage().providerActiveBids[provider].remove(bidId); - } - - function getModelActiveBids(bytes32 modelId) internal view returns (EnumerableSet.Bytes32Set storage) { - return _getBidStorage().modelActiveBids[modelId]; + function getModelActiveBids( + bytes32 modelId_, + uint256 offset_, + uint256 limit_ + ) external view returns (bytes32[] memory) { + return _getBidsStorage().modelActiveBids[modelId_].part(offset_, limit_); } - function removeModelActiveBids(bytes32 modelId, bytes32 bidId) internal { - _getBidStorage().modelActiveBids[modelId].remove(bidId); + function getProviderBids( + address provider_, + uint256 offset_, + uint256 limit_ + ) external view returns (bytes32[] memory) { + return _getBidsStorage().providerBids[provider_].part(offset_, limit_); } - function isModelActiveBidsEmpty(bytes32 modelId) internal view returns (bool) { - return _getBidStorage().modelActiveBids[modelId].length() == 0; + function getModelBids(bytes32 modelId_, uint256 offset_, uint256 limit_) external view returns (bytes32[] memory) { + return _getBidsStorage().modelBids[modelId_].part(offset_, limit_); } - function isProviderActiveBidsEmpty(address provider) internal view returns (bool) { - return _getBidStorage().providerActiveBids[provider].length() == 0; + function getToken() external view returns (address) { + return _getBidsStorage().token; } - function addProviderBid(address provider, bytes32 bidId) internal { - _getBidStorage().providerBids[provider].push(bidId); - } + function isBidActive(bytes32 bidId_) public view returns (bool) { + Bid storage bid = _getBidsStorage().bids[bidId_]; - function addModelBid(bytes32 modelId, bytes32 bidId) internal { - _getBidStorage().modelBids[modelId].push(bidId); + return bid.createdAt != 0 && bid.deletedAt == 0; } - function setBid(bytes32 bidId, Bid memory bid) internal { - _getBidStorage().bids[bidId] = bid; + /** INTERNAL */ + function _isModelActiveBidsEmpty(bytes32 modelId) internal view returns (bool) { + return _getBidsStorage().modelActiveBids[modelId].length() == 0; } - function _incrementBidNonce(bytes32 providerModelId) internal returns (uint256) { - return _getBidStorage().providerModelNonce[providerModelId]++; + function _isProviderActiveBidsEmpty(address provider) internal view returns (bool) { + return _getBidsStorage().providerActiveBids[provider].length() == 0; } - function _getBidStorage() internal pure returns (BDStorage storage _ds) { - bytes32 slot_ = BID_STORAGE_SLOT; + function _getBidsStorage() internal pure returns (BidsStorage storage ds) { + bytes32 slot_ = BIDS_STORAGE_SLOT; assembly { - _ds.slot := slot_ + ds.slot := slot_ } } } diff --git a/smart-contracts/contracts/diamond/storages/MarketplaceStorage.sol b/smart-contracts/contracts/diamond/storages/MarketplaceStorage.sol index a7230d1d..11fe62f9 100644 --- a/smart-contracts/contracts/diamond/storages/MarketplaceStorage.sol +++ b/smart-contracts/contracts/diamond/storages/MarketplaceStorage.sol @@ -4,34 +4,34 @@ pragma solidity ^0.8.24; import {IMarketplaceStorage} from "../../interfaces/storage/IMarketplaceStorage.sol"; contract MarketplaceStorage is IMarketplaceStorage { - struct MPStorage { - uint256 feeBalance; // total fees balance of the contract + struct MarketStorage { + uint256 feeBalance; // Total fees balance of the contract uint256 bidFee; + uint256 bidMinPricePerSecond; + uint256 bidMaxPricePerSecond; } - bytes32 public constant MARKETPLACE_STORAGE_SLOT = keccak256("diamond.standard.marketplace.storage"); + bytes32 public constant MARKET_STORAGE_SLOT = keccak256("diamond.standard.market.storage"); - function getBidFee() public view returns (uint256) { - return _getMarketplaceStorage().bidFee; + /** PUBLIC, GETTERS */ + function getBidFee() external view returns (uint256) { + return _getMarketStorage().bidFee; } - function getFeeBalance() internal view returns (uint256) { - return _getMarketplaceStorage().feeBalance; + function getFeeBalance() external view returns (uint256) { + return _getMarketStorage().feeBalance; } - function increaseFeeBalance(uint256 amount) internal { - _getMarketplaceStorage().feeBalance += amount; + function getMinMaxBidPricePerSecond() external view returns (uint256, uint256) { + return (_getMarketStorage().bidMinPricePerSecond, _getMarketStorage().bidMaxPricePerSecond); } - function decreaseFeeBalance(uint256 amount) internal { - _getMarketplaceStorage().feeBalance -= amount; - } - - function _getMarketplaceStorage() internal pure returns (MPStorage storage _ds) { - bytes32 slot_ = MARKETPLACE_STORAGE_SLOT; + /** INTERNAL */ + function _getMarketStorage() internal pure returns (MarketStorage storage ds) { + bytes32 slot_ = MARKET_STORAGE_SLOT; assembly { - _ds.slot := slot_ + ds.slot := slot_ } } } diff --git a/smart-contracts/contracts/diamond/storages/ModelStorage.sol b/smart-contracts/contracts/diamond/storages/ModelStorage.sol index 22e8fc8f..90df70cb 100644 --- a/smart-contracts/contracts/diamond/storages/ModelStorage.sol +++ b/smart-contracts/contracts/diamond/storages/ModelStorage.sol @@ -1,59 +1,52 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.24; +import {EnumerableSet} from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol"; +import {Paginator} from "@solarity/solidity-lib/libs/arrays/Paginator.sol"; + import {IModelStorage} from "../../interfaces/storage/IModelStorage.sol"; contract ModelStorage is IModelStorage { - struct MDLStorage { + using Paginator for *; + using EnumerableSet for EnumerableSet.Bytes32Set; + + struct ModelsStorage { uint256 modelMinimumStake; - bytes32[] modelIds; // all model ids + EnumerableSet.Bytes32Set modelIds; mapping(bytes32 modelId => Model) models; - mapping(bytes32 modelId => bool) isModelActive; - } - - bytes32 public constant MODEL_STORAGE_SLOT = keccak256("diamond.standard.model.storage"); - - function getModel(bytes32 modelId) external view returns (Model memory) { - return _getModelStorage().models[modelId]; + // TODO: move vars below to the graph in the future + EnumerableSet.Bytes32Set activeModels; } - function models(uint256 index) external view returns (bytes32) { - return _getModelStorage().modelIds[index]; - } - - function modelMinimumStake() public view returns (uint256) { - return _getModelStorage().modelMinimumStake; - } - - function setModelActive(bytes32 modelId, bool isActive) internal { - _getModelStorage().isModelActive[modelId] = isActive; - } + bytes32 public constant MODELS_STORAGE_SLOT = keccak256("diamond.standard.models.storage"); - function addModel(bytes32 modelId) internal { - _getModelStorage().modelIds.push(modelId); + /** PUBLIC, GETTERS */ + function getModel(bytes32 modelId_) external view returns (Model memory) { + return _getModelsStorage().models[modelId_]; } - function setModel(bytes32 modelId, Model memory model) internal { - _getModelStorage().models[modelId] = model; + function getModelIds(uint256 offset_, uint256 limit_) external view returns (bytes32[] memory) { + return _getModelsStorage().modelIds.part(offset_, limit_); } - function _setModelMinimumStake(uint256 modelMinimumStake_) internal { - _getModelStorage().modelMinimumStake = modelMinimumStake_; + function getModelMinimumStake() external view returns (uint256) { + return _getModelsStorage().modelMinimumStake; } - function models(bytes32 id) internal view returns (Model storage) { - return _getModelStorage().models[id]; + function getActiveModelIds(uint256 offset_, uint256 limit_) external view returns (bytes32[] memory) { + return _getModelsStorage().activeModels.part(offset_, limit_); } - function isModelActive(bytes32 modelId) internal view returns (bool) { - return _getModelStorage().isModelActive[modelId]; + function getIsModelActive(bytes32 modelId_) public view returns (bool) { + return !_getModelsStorage().models[modelId_].isDeleted; } - function _getModelStorage() internal pure returns (MDLStorage storage _ds) { - bytes32 slot_ = MODEL_STORAGE_SLOT; + /** INTERNAL */ + function _getModelsStorage() internal pure returns (ModelsStorage storage ds) { + bytes32 slot_ = MODELS_STORAGE_SLOT; assembly { - _ds.slot := slot_ + ds.slot := slot_ } } } diff --git a/smart-contracts/contracts/diamond/storages/ProviderStorage.sol b/smart-contracts/contracts/diamond/storages/ProviderStorage.sol index f5db0e3f..ae87e2ce 100644 --- a/smart-contracts/contracts/diamond/storages/ProviderStorage.sol +++ b/smart-contracts/contracts/diamond/storages/ProviderStorage.sol @@ -1,52 +1,50 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.24; +import {EnumerableSet} from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol"; +import {Paginator} from "@solarity/solidity-lib/libs/arrays/Paginator.sol"; + import {IProviderStorage} from "../../interfaces/storage/IProviderStorage.sol"; contract ProviderStorage is IProviderStorage { - struct PRVDRStorage { + using Paginator for *; + using EnumerableSet for EnumerableSet.AddressSet; + + struct PovidersStorage { uint256 providerMinimumStake; mapping(address => Provider) providers; - mapping(address => bool) isProviderActive; - } - - uint128 constant PROVIDER_REWARD_LIMITER_PERIOD = 365 days; // reward for this period will be limited by the stake - - bytes32 public constant PROVIDER_STORAGE_SLOT = keccak256("diamond.standard.provider.storage"); - - function getProvider(address provider) external view returns (Provider memory) { - return _getProviderStorage().providers[provider]; + // TODO: move vars below to the graph in the future + EnumerableSet.AddressSet activeProviders; } - function providerMinimumStake() public view returns (uint256) { - return _getProviderStorage().providerMinimumStake; - } + // Reward for this period will be limited by the stake + uint128 constant PROVIDER_REWARD_LIMITER_PERIOD = 365 days; - function setProviderActive(address provider, bool isActive) internal { - _getProviderStorage().isProviderActive[provider] = isActive; - } + bytes32 public constant PROVIDERS_STORAGE_SLOT = keccak256("diamond.standard.providers.storage"); - function setProvider(address provider, Provider memory provider_) internal { - _getProviderStorage().providers[provider] = provider_; + /** PUBLIC, GETTERS */ + function getProvider(address provider_) external view returns (Provider memory) { + return _getProvidersStorage().providers[provider_]; } - function setProviderMinimumStake(uint256 _providerMinimumStake) internal { - _getProviderStorage().providerMinimumStake = _providerMinimumStake; + function getProviderMinimumStake() external view returns (uint256) { + return _getProvidersStorage().providerMinimumStake; } - function providers(address addr) internal view returns (Provider storage) { - return _getProviderStorage().providers[addr]; + function getActiveProviders(uint256 offset_, uint256 limit_) external view returns (address[] memory) { + return _getProvidersStorage().activeProviders.part(offset_, limit_); } - function isProviderActive(address provider) internal view returns (bool) { - return _getProviderStorage().isProviderActive[provider]; + function getIsProviderActive(address provider_) public view returns (bool) { + return !_getProvidersStorage().providers[provider_].isDeleted; } - function _getProviderStorage() internal pure returns (PRVDRStorage storage _ds) { - bytes32 slot_ = PROVIDER_STORAGE_SLOT; + /** INTERNAL */ + function _getProvidersStorage() internal pure returns (PovidersStorage storage ds) { + bytes32 slot_ = PROVIDERS_STORAGE_SLOT; assembly { - _ds.slot := slot_ + ds.slot := slot_ } } } diff --git a/smart-contracts/contracts/diamond/storages/SessionStorage.sol b/smart-contracts/contracts/diamond/storages/SessionStorage.sol index 1c469c1c..eb33f9ae 100644 --- a/smart-contracts/contracts/diamond/storages/SessionStorage.sol +++ b/smart-contracts/contracts/diamond/storages/SessionStorage.sol @@ -1,122 +1,99 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.24; -import {ISessionStorage} from "../../interfaces/storage/ISessionStorage.sol"; - +import {EnumerableSet} from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol"; import {Paginator} from "@solarity/solidity-lib/libs/arrays/Paginator.sol"; +import {ISessionStorage} from "../../interfaces/storage/ISessionStorage.sol"; + contract SessionStorage is ISessionStorage { using Paginator for *; - - struct SNStorage { - // all sessions - uint256 sessionNonce; // used to generate unique session id + using EnumerableSet for EnumerableSet.Bytes32Set; + + struct SessionsStorage { + // Account which stores the MOR tokens with infinite allowance for this contract + address fundingAccount; + // Distribution pools configuration that mirrors L1 contract + Pool[] pools; + // Total amount of MOR claimed by providers + uint256 providersTotalClaimed; + // Used to generate unique session ID + uint256 sessionNonce; mapping(bytes32 sessionId => Session) sessions; - mapping(address user => bytes32[]) userSessionIds; - mapping(address provider => bytes32[]) providerSessionIds; - mapping(bytes32 modelId => bytes32[]) modelSessionIds; - // active sessions - uint256 totalClaimed; // total amount of MOR claimed by providers - mapping(address user => mapping(bytes32 => bool)) isUserSessionActive; // user address => active session indexes - mapping(address provider => mapping(bytes32 => bool)) isProviderSessionActive; // provider address => active session indexes - mapping(address user => OnHold[]) userOnHold; // user address => balance - mapping(bytes providerApproval => bool) isApprovalUsed; - // other - address fundingAccount; // account which stores the MOR tokens with infinite allowance for this contract - Pool[] pools; // distribution pools configuration that mirrors L1 contract + // Max ession duration + uint128 maxSessionDuration; + // Session registry for providers, users and models + mapping(address user => EnumerableSet.Bytes32Set) userSessions; + mapping(address provider => EnumerableSet.Bytes32Set) providerSessions; + mapping(bytes32 modelId => EnumerableSet.Bytes32Set) modelSessions; + mapping(address user => OnHold[]) userStakesOnHold; + mapping(bytes providerApproval => bool) isProviderApprovalUsed; } - bytes32 public constant SESSION_STORAGE_SLOT = keccak256("diamond.standard.session.storage"); - - function sessions(bytes32 sessionId) external view returns (Session memory) { - return _getSessionStorage().sessions[sessionId]; - } - - function getSessionsByUser(address user, uint256 offset_, uint256 limit_) external view returns (bytes32[] memory) { - return _getSessionStorage().userSessionIds[user].part(offset_, limit_); - } - - function pools() external view returns (Pool[] memory) { - return _getSessionStorage().pools; - } - - function getPools() internal view returns (Pool[] storage) { - return _getSessionStorage().pools; - } - - function getPool(uint256 poolIndex) internal view returns (Pool storage) { - return _getSessionStorage().pools[poolIndex]; - } - - function getFundingAccount() public view returns (address) { - return _getSessionStorage().fundingAccount; - } - - function setSession(bytes32 sessionId, Session memory session) internal { - _getSessionStorage().sessions[sessionId] = session; - } - - function setUserSessionActive(address user, bytes32 sessionId, bool active) internal { - _getSessionStorage().isUserSessionActive[user][sessionId] = active; - } - - function setProviderSessionActive(address provider, bytes32 sessionId, bool active) internal { - _getSessionStorage().isProviderSessionActive[provider][sessionId] = active; - } - - function addUserSessionId(address user, bytes32 sessionId) internal { - _getSessionStorage().userSessionIds[user].push(sessionId); - } + bytes32 public constant SESSIONS_STORAGE_SLOT = keccak256("diamond.standard.sessions.storage"); + uint32 public constant MIN_SESSION_DURATION = 5 minutes; + uint32 public constant SIGNATURE_TTL = 10 minutes; + uint256 public constant COMPUTE_POOL_INDEX = 3; - function addProviderSessionId(address provider, bytes32 sessionId) internal { - _getSessionStorage().providerSessionIds[provider].push(sessionId); + /** PUBLIC, GETTERS */ + function getSession(bytes32 sessionId_) external view returns (Session memory) { + return _getSessionsStorage().sessions[sessionId_]; } - function totalSessions(address providerAddr) internal view returns (uint256) { - return _getSessionStorage().providerSessionIds[providerAddr].length; + function getUserSessions(address user_, uint256 offset_, uint256 limit_) external view returns (bytes32[] memory) { + return _getSessionsStorage().userSessions[user_].part(offset_, limit_); } - function addModelSessionId(bytes32 modelId, bytes32 sessionId) internal { - _getSessionStorage().modelSessionIds[modelId].push(sessionId); + function getProviderSessions( + address provider_, + uint256 offset_, + uint256 limit_ + ) external view returns (bytes32[] memory) { + return _getSessionsStorage().providerSessions[provider_].part(offset_, limit_); } - function addOnHold(address user, OnHold memory onHold) internal { - _getSessionStorage().userOnHold[user].push(onHold); + function getModelSessions( + bytes32 modelId_, + uint256 offset_, + uint256 limit_ + ) external view returns (bytes32[] memory) { + return _getSessionsStorage().modelSessions[modelId_].part(offset_, limit_); } - function increaseTotalClaimed(uint256 amount) internal { - _getSessionStorage().totalClaimed += amount; + function getPools() external view returns (Pool[] memory) { + return _getSessionsStorage().pools; } - function totalClaimed() internal view returns (uint256) { - return _getSessionStorage().totalClaimed; + function getPool(uint256 index_) external view returns (Pool memory) { + return _getSessionsStorage().pools[index_]; } - function getOnHold(address user) internal view returns (OnHold[] storage) { - return _getSessionStorage().userOnHold[user]; + function getFundingAccount() external view returns (address) { + return _getSessionsStorage().fundingAccount; } - function _getSession(bytes32 sessionId) internal view returns (Session storage) { - return _getSessionStorage().sessions[sessionId]; + function getTotalSessions(address provider_) public view returns (uint256) { + return _getSessionsStorage().providerSessions[provider_].length(); } - function incrementSessionNonce() internal returns (uint256) { - return _getSessionStorage().sessionNonce++; + function getProvidersTotalClaimed() external view returns (uint256) { + return _getSessionsStorage().providersTotalClaimed; } - function isApprovalUsed(bytes memory approval) internal view returns (bool) { - return _getSessionStorage().isApprovalUsed[approval]; + function getIsProviderApprovalUsed(bytes memory approval_) external view returns (bool) { + return _getSessionsStorage().isProviderApprovalUsed[approval_]; } - function setApprovalUsed(bytes memory approval) internal { - _getSessionStorage().isApprovalUsed[approval] = true; + function getMaxSessionDuration() external view returns (uint128) { + return _getSessionsStorage().maxSessionDuration; } - function _getSessionStorage() internal pure returns (SNStorage storage _ds) { - bytes32 slot_ = SESSION_STORAGE_SLOT; + /** INTERNAL */ + function _getSessionsStorage() internal pure returns (SessionsStorage storage ds) { + bytes32 slot_ = SESSIONS_STORAGE_SLOT; assembly { - _ds.slot := slot_ + ds.slot := slot_ } } } diff --git a/smart-contracts/contracts/diamond/storages/StatsStorage.sol b/smart-contracts/contracts/diamond/storages/StatsStorage.sol index c86751da..96fafeff 100644 --- a/smart-contracts/contracts/diamond/storages/StatsStorage.sol +++ b/smart-contracts/contracts/diamond/storages/StatsStorage.sol @@ -3,39 +3,41 @@ pragma solidity ^0.8.24; import {IStatsStorage} from "../../interfaces/storage/IStatsStorage.sol"; -import {LibSD} from "../../libs/LibSD.sol"; - contract StatsStorage is IStatsStorage { - struct ModelStats { - LibSD.SD tpsScaled1000; - LibSD.SD ttftMs; - LibSD.SD totalDuration; - uint32 count; - } - struct STTSStorage { - mapping(bytes32 => mapping(address => ProviderModelStats)) stats; // modelId => provider => stats + mapping(bytes32 => mapping(address => ProviderModelStats)) providerModelStats; // modelId => provider => stats mapping(bytes32 => ModelStats) modelStats; } bytes32 public constant STATS_STORAGE_SLOT = keccak256("diamond.stats.storage"); - function _getModelStats(bytes32 modelId) internal view returns (ModelStats storage) { + /** PUBLIC, GETTERS */ + function getProviderModelStats( + bytes32 modelId_, + address provider_ + ) external view returns (ProviderModelStats memory) { + return _getStatsStorage().providerModelStats[modelId_][provider_]; + } + + function getModelStats(bytes32 modelId_) external view returns (ModelStats memory) { + return _getStatsStorage().modelStats[modelId_]; + } + + /** INTERNAL, GETTERS */ + function _modelStats(bytes32 modelId) internal view returns (ModelStats storage) { return _getStatsStorage().modelStats[modelId]; } - function _getProviderModelStats( - bytes32 modelId, - address provider - ) internal view returns (ProviderModelStats storage) { - return _getStatsStorage().stats[modelId][provider]; + function _providerModelStats(bytes32 modelId, address provider) internal view returns (ProviderModelStats storage) { + return _getStatsStorage().providerModelStats[modelId][provider]; } - function _getStatsStorage() internal pure returns (STTSStorage storage _ds) { + /** PRIVATE */ + function _getStatsStorage() private pure returns (STTSStorage storage ds) { bytes32 slot_ = STATS_STORAGE_SLOT; assembly { - _ds.slot := slot_ + ds.slot := slot_ } } } diff --git a/smart-contracts/contracts/interfaces/facets/IMarketplace.sol b/smart-contracts/contracts/interfaces/facets/IMarketplace.sol index bd68ca44..8a61e14c 100644 --- a/smart-contracts/contracts/interfaces/facets/IMarketplace.sol +++ b/smart-contracts/contracts/interfaces/facets/IMarketplace.sol @@ -1,36 +1,78 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.24; -import {IBidStorage} from "../storage/IBidStorage.sol"; import {IMarketplaceStorage} from "../storage/IMarketplaceStorage.sol"; -interface IMarketplace is IBidStorage, IMarketplaceStorage { - event BidPosted(address indexed provider, bytes32 indexed modelId, uint256 nonce); - event BidDeleted(address indexed provider, bytes32 indexed modelId, uint256 nonce); - event FeeUpdated(uint256 bidFee); +interface IMarketplace is IMarketplaceStorage { + event MaretplaceFeeUpdated(uint256 bidFee); + event MarketplaceBidPosted(address indexed provider, bytes32 indexed modelId, uint256 nonce); + event MarketplaceBidDeleted(address indexed provider, bytes32 indexed modelId, uint256 nonce); + event MarketplaceBidMinMaxPriceUpdated(uint256 bidMinPricePerSecond, uint256 bidMaxPricePerSecond); - error ProviderNotFound(); - error ModelNotFound(); - error ActiveBidNotFound(); - error BidTaken(); - error NotEnoughBalance(); - error NotOwnerOrProvider(); + error MarketplaceProviderNotFound(); + error MarketplaceModelNotFound(); + error MarketplaceActiveBidNotFound(); + error MarketplaceBidMinPricePerSecondIsZero(); + error MarketplaceBidMinPricePerSecondIsInvalid(); + error MarketplaceBidPricePerSecondInvalid(); + error MarketplaceFeeAmountIsZero(); - function __Marketplace_init(address token_) external; + /** + * 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 + */ + function __Marketplace_init(address token_, uint256 bidMinPricePerSecond_, uint256 bidMaxPricePerSecond_) external; - function setBidFee(uint256 bidFee_) external; + /** + * The function to set the bidFee. + * @param bidFee_ Amount of tokens + */ + function setMarketplaceBidFee(uint256 bidFee_) external; - function postModelBid( - address provider_, - bytes32 modelId_, - uint256 pricePerSecond_ - ) external returns (bytes32 bidId); + /** + * 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 + */ + function setMinMaxBidPricePerSecond( + uint256 bidMinPricePerSecond_, + uint256 bidMaxPricePerSecond_ + ) external; + /** + * The function to create the bid. + * @param modelId_ The mode ID + * @param pricePerSecond_ The price per second + */ + function postModelBid(bytes32 modelId_, uint256 pricePerSecond_) external returns (bytes32); + + /** + * The function to delete the bid. + * @param bidId_ The bid ID + */ function deleteModelBid(bytes32 bidId_) external; - function withdraw(address recipient_, uint256 amount_) external; + /** + * The function to withdraw the stake amount. + * @param recipient_ The recipient address. + * @param amount_ The amount. + */ + function withdrawFee(address recipient_, uint256 amount_) external; + /** + * The function to get bid ID. + * @param provider_ The provider address. + * @param modelId_ The model ID. + * @param nonce_ The nonce. + */ function getBidId(address provider_, bytes32 modelId_, uint256 nonce_) external view returns (bytes32); + /** + * The function to returns provider model ID + * @param provider_ The provider address. + * @param modelId_ The model ID. + */ function getProviderModelId(address provider_, bytes32 modelId_) external view returns (bytes32); } diff --git a/smart-contracts/contracts/interfaces/facets/IModelRegistry.sol b/smart-contracts/contracts/interfaces/facets/IModelRegistry.sol index 61cad56a..c842a04d 100644 --- a/smart-contracts/contracts/interfaces/facets/IModelRegistry.sol +++ b/smart-contracts/contracts/interfaces/facets/IModelRegistry.sol @@ -6,26 +6,44 @@ import {IModelStorage} from "../storage/IModelStorage.sol"; interface IModelRegistry is IModelStorage { event ModelRegisteredUpdated(address indexed owner, bytes32 indexed modelId); event ModelDeregistered(address indexed owner, bytes32 indexed modelId); - event ModelMinimumStakeSet(uint256 newStake); - + event ModelMinimumStakeUpdated(uint256 modelMinimumStake); + error ModelStakeTooLow(uint256 amount, uint256 minAmount); + error ModelHasAlreadyDeregistered(); error ModelNotFound(); - error StakeTooLow(); error ModelHasActiveBids(); - error NotOwnerOrModelOwner(); + /** + * The function to initialize the facet. + */ function __ModelRegistry_init() external; - function setModelMinimumStake(uint256 modelMinimumStake_) external; + /** + * The function to set the minimal stake for models. + * @param modelMinimumStake_ Amount of tokens + */ + function modelSetMinStake(uint256 modelMinimumStake_) external; + /** + * The function to register the model. + * @param modelId_ The model ID. + * @param ipfsCID_ The model IPFS CID. + * @param fee_ The model fee. + * @param amount_ The model stake amount. + * @param name_ The model name. + * @param tags_ The model tags. + */ function modelRegister( bytes32 modelId_, bytes32 ipfsCID_, uint256 fee_, - uint256 stake_, - address owner_, - string memory name_, - string[] memory tags_ + uint256 amount_, + string calldata name_, + string[] calldata tags_ ) external; + /** + * The function to deregister the model. + * @param modelId_ The model ID. + */ function modelDeregister(bytes32 modelId_) external; } diff --git a/smart-contracts/contracts/interfaces/facets/IProviderRegistry.sol b/smart-contracts/contracts/interfaces/facets/IProviderRegistry.sol index c950237c..3c05429d 100644 --- a/smart-contracts/contracts/interfaces/facets/IProviderRegistry.sol +++ b/smart-contracts/contracts/interfaces/facets/IProviderRegistry.sol @@ -4,25 +4,38 @@ pragma solidity ^0.8.24; import {IProviderStorage} from "../storage/IProviderStorage.sol"; interface IProviderRegistry is IProviderStorage { - event ProviderRegisteredUpdated(address indexed provider); + event ProviderRegistered(address indexed provider); event ProviderDeregistered(address indexed provider); - event ProviderMinStakeUpdated(uint256 newStake); - event ProviderWithdrawnStake(address indexed provider, uint256 amount); - error StakeTooLow(); - error ErrProviderNotDeleted(); - error ErrNoStake(); - error ErrNoWithdrawableStake(); + event ProviderMinimumStakeUpdated(uint256 providerMinimumStake); + event ProviderWithdrawn(address indexed provider, uint256 amount); + error ProviderStakeTooLow(uint256 amount, uint256 minAmount); + error ProviderNotDeregistered(); + error ProviderNoStake(); + error ProviderNothingToWithdraw(); error ProviderHasActiveBids(); - error NotOwnerOrProvider(); error ProviderNotFound(); + error ProviderHasAlreadyDeregistered(); + /** + * The function to initialize the facet. + */ function __ProviderRegistry_init() external; + /** + * @notice The function to the minimum stake required for a provider + * @param providerMinimumStake_ The minimal stake + */ function providerSetMinStake(uint256 providerMinimumStake_) external; - function providerRegister(address providerAddress_, uint256 amount_, string memory endpoint_) external; + /** + * @notice The function to register the provider + * @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 providerDeregister(address provider_) external; - - function providerWithdrawStake(address provider_) external; + /** + * @notice The function to deregister the provider + */ + function providerDeregister() external; } diff --git a/smart-contracts/contracts/interfaces/facets/ISessionRouter.sol b/smart-contracts/contracts/interfaces/facets/ISessionRouter.sol index 513dd717..f58439bd 100644 --- a/smart-contracts/contracts/interfaces/facets/ISessionRouter.sol +++ b/smart-contracts/contracts/interfaces/facets/ISessionRouter.sol @@ -8,83 +8,156 @@ import {IStatsStorage} from "../storage/IStatsStorage.sol"; interface ISessionRouter is ISessionStorage { event SessionOpened(address indexed user, bytes32 indexed sessionId, address indexed providerId); event SessionClosed(address indexed user, bytes32 indexed sessionId, address indexed providerId); - - error NotEnoughWithdrawableBalance(); // means that there is not enough funds at all or some funds are still locked - error WithdrawableBalanceLimitByStakeReached(); // means that user can't withdraw more funds because of the limit which equals to the stake - error ProviderSignatureMismatch(); - error SignatureExpired(); - error WrongChainId(); - error DuplicateApproval(); - error ApprovedForAnotherUser(); // means that approval generated for another user address, protection from front-running - + event UserWithdrawn(address indexed user, uint256 amount_); + error SessionProviderSignatureMismatch(); + error SesssionApproveExpired(); + error SesssionApprovedForAnotherChainId(); + error SessionDuplicateApproval(); + error SessionApprovedForAnotherUser(); + error SesssionReceiptForAnotherChainId(); + error SesssionReceiptExpired(); error SessionTooShort(); - error SessionNotFound(); error SessionAlreadyClosed(); - error SessionNotClosed(); - - error BidNotFound(); - error CannotDecodeAbi(); - - error AmountToWithdrawIsZero(); - error NotOwnerOrProvider(); - error NotOwnerOrUser(); - error PoolIndexOutOfBounds(); - - function __SessionRouter_init(address fundingAccount_, Pool[] memory pools_) external; - + error SessionNotEndedOrNotExist(); + error SessionProviderNothingToClaimInThisPeriod(); + error SessionBidNotFound(); + error SessionPoolIndexOutOfBounds(); + error SessionUserAmountToWithdrawIsZero(); + error SessionMaxDurationTooShort(); + error SessionStakeTooLow(); + + /** + * The function to initialize the facet. + * @param fundingAccount_ The funding address (treaasury) + * @param maxSessionDuration_ The max session duration + * @param pools_ The pools data + */ + function __SessionRouter_init( + address fundingAccount_, + uint128 maxSessionDuration_, + Pool[] calldata pools_ + ) external; + + /** + * @notice Sets distibution pool configuration + * @dev parameters should be the same as in Ethereum L1 Distribution contract + * @dev at address 0x47176B2Af9885dC6C4575d4eFd63895f7Aaa4790 + * @dev call 'Distribution.pools(3)' where '3' is a poolId. + * @param index_ The pool index. + * @param pool_ The pool data. + */ + function setPoolConfig(uint256 index_, Pool calldata pool_) external; + + /** + * The function to set the max session duration. + * @param maxSessionDuration_ The max session duration. + */ + function setMaxSessionDuration(uint128 maxSessionDuration_) external; + + /** + * The function to open the session. + * @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( uint256 amount_, - bytes memory providerApproval_, - bytes memory signature_ + bool isDirectPaymentFromUser_, + bytes calldata approvalEncoded_, + bytes calldata signature_ ) external returns (bytes32); - function closeSession(bytes memory receiptEncoded_, bytes memory signature_) external; - - function claimProviderBalance(bytes32 sessionId_, uint256 amountToWithdraw_) external; - - function deleteHistory(bytes32 sessionId_) external; - - function withdrawUserStake(uint256 amountToWithdraw_, uint8 iterations_) external; - - function withdrawableUserStake( - address user_, - uint8 iterations_ - ) external view returns (uint256 avail_, uint256 hold_); - + /** + * The function to get session ID/ + * @param user_ The user address. + * @param provider_ The provider address. + * @param bidId_ The bid ID. + * @param sessionNonce_ The session nounce. + */ function getSessionId( address user_, address provider_, - uint256 stake_, + bytes32 bidId_, uint256 sessionNonce_ ) external pure returns (bytes32); - function stakeToStipend(uint256 sessionStake_, uint256 timestamp_) external view returns (uint256); - - function stipendToStake(uint256 stipend_, uint256 timestamp_) external view returns (uint256); - - function whenSessionEnds( - uint256 sessionStake_, - uint256 pricePerSecond_, - uint256 openedAt_ - ) external view returns (uint256); - - function getTodaysBudget(uint256 timestamp_) external view returns (uint256); - - function getComputeBalance(uint256 timestamp_) external view returns (uint256); - - function totalMORSupply(uint256 timestamp_) external view returns (uint256); - - function startOfTheDay(uint256 timestamp_) external pure returns (uint256); - - function getProviderClaimableBalance(bytes32 sessionId_) external view returns (uint256); - - function setPoolConfig(uint256 index, Pool calldata pool) external; - - function SIGNATURE_TTL() external view returns (uint32); - - function getActiveBidsRatingByModel( - bytes32 modelId_, - uint256 offset_, - uint8 limit_ - ) external view returns (bytes32[] memory, IBidStorage.Bid[] memory, IStatsStorage.ProviderModelStats[] memory); + /** + * The function to returns the session end timestamp + * @param amount_ The stake amount. + * @param pricePerSecond_ The price per second. + * @param openedAt_ The opened at timestamp. + */ + function getSessionEnd(uint256 amount_, uint256 pricePerSecond_, uint128 openedAt_) external view returns (uint128); + + /** + * Returns stipend of user based on their stake + * (User session stake amount / MOR Supply without Compute) * (MOR Compute Supply / 100) + * @param amount_ The amount of tokens. + * @param timestamp_ The timestamp when the TX executes. + */ + function stakeToStipend(uint256 amount_, uint128 timestamp_) external view returns (uint256); + + /** + * The function to close session. + * @param receiptEncoded_ Provider receipt + * @param signature_ Provider signature + */ + function closeSession(bytes calldata receiptEncoded_, bytes calldata signature_) external; + + /** + * Allows providers to receive their funds after the end or closure of the session. + * @param sessionId_ The session ID. + */ + function claimForProvider(bytes32 sessionId_) external; + + /** + * Returns stake of user based on their stipend. + * @param stipend_ The stake amount. + * @param timestamp_ The timestamp when the TX executed. + */ + function stipendToStake(uint256 stipend_, uint128 timestamp_) external view returns (uint256); + + /** + * The function to return available and locked amount of the user tokens. + * @param user_ The user address. + * @param iterations_ The loop interaction amount. + * @return available_ The available to withdraw. + * @return hold_ The locked amount. + */ + function getUserStakesOnHold( + address user_, + uint8 iterations_ + ) external view returns (uint256 available_, uint256 hold_); + + /** + * The function to withdraw user stakes. + * @param iterations_ The loop interaction amount. + */ + function withdrawUserStakes(uint8 iterations_) external; + + /** + * Returns today's budget in MOR. 1%. + * @param timestamp_ The timestamp when the TX executed. + */ + function getTodaysBudget(uint128 timestamp_) external view returns (uint256); + + /** + * Returns today's compute balance in MOR without claimed amount. + * @param timestamp_ The timestamp when the TX executed. + */ + function getComputeBalance(uint128 timestamp_) external view returns (uint256); + + /** + * Total amount of MOR tokens that were distributed across all pools + * without compute pool rewards and with compute claimed rewards. + * @param timestamp_ The timestamp when the TX executed. + */ + function totalMORSupply(uint128 timestamp_) external view returns (uint256); + + /** + * The function to return the timestamp on the start of day + * @param timestamp_ The timestamp when the TX executed. + */ + function startOfTheDay(uint128 timestamp_) external pure returns (uint128); } diff --git a/smart-contracts/contracts/interfaces/storage/IBidStorage.sol b/smart-contracts/contracts/interfaces/storage/IBidStorage.sol index 5282bd46..708bf7e8 100644 --- a/smart-contracts/contracts/interfaces/storage/IBidStorage.sol +++ b/smart-contracts/contracts/interfaces/storage/IBidStorage.sol @@ -1,35 +1,83 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.24; -import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; - interface IBidStorage { + /** + * The structure that stores the bid data. + * @param provider The provider addres. + * @param modelId The model ID. + * @param pricePerSecond The price per second. + * @param nonce The bid creates with this nounce (related to provider nounce). + * @param createdAt The timestamp when the bid is created. + * @param deletedAt The timestamp when the bid is deleted. + */ struct Bid { address provider; bytes32 modelId; - uint256 pricePerSecond; // hourly price + uint256 pricePerSecond; uint256 nonce; uint128 createdAt; uint128 deletedAt; } - function bids(bytes32 bidId) external view returns (Bid memory); + /** + * The function returns the bid structure. + * @param bidId_ Bid ID. + */ + function getBid(bytes32 bidId_) external view returns (Bid memory); - function providerActiveBids( + /** + * The function returns active provider bids. + * @param provider_ Provider address. + * @param offset_ Offset for the pagination. + * @param limit_ Number of entities to return. + */ + function getProviderActiveBids( address provider_, uint256 offset_, uint256 limit_ ) external view returns (bytes32[] memory); - function modelActiveBids( + /** + * The function returns active model bids. + * @param modelId_ Model ID. + * @param offset_ Offset for the pagination. + * @param limit_ Number of entities to return. + */ + function getModelActiveBids( bytes32 modelId_, uint256 offset_, uint256 limit_ ) external view returns (bytes32[] memory); - function providerBids(address provider_, uint256 offset_, uint256 limit_) external view returns (bytes32[] memory); + /** + * The function returns provider bids. + * @param provider_ Provider address. + * @param offset_ Offset for the pagination. + * @param limit_ Number of entities to return. + */ + function getProviderBids( + address provider_, + uint256 offset_, + uint256 limit_ + ) external view returns (bytes32[] memory); + + /** + * The function returns model bids. + * @param modelId_ Model ID. + * @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 modelBids(bytes32 modelId_, uint256 offset_, uint256 limit_) external view returns (bytes32[] memory); + /** + * The function returns stake token (MOR). + */ + function getToken() external view returns (address); - function getToken() external view returns (IERC20); + /** + * The function returns bid status, active or not. + * @param bidId_ Bid ID. + */ + function isBidActive(bytes32 bidId_) external view returns (bool); } diff --git a/smart-contracts/contracts/interfaces/storage/IMarketplaceStorage.sol b/smart-contracts/contracts/interfaces/storage/IMarketplaceStorage.sol index e7d4987a..bbf05153 100644 --- a/smart-contracts/contracts/interfaces/storage/IMarketplaceStorage.sol +++ b/smart-contracts/contracts/interfaces/storage/IMarketplaceStorage.sol @@ -2,5 +2,20 @@ pragma solidity ^0.8.24; interface IMarketplaceStorage { + /** + * The function returns bid fee on creation. + */ function getBidFee() external view returns (uint256); + + /** + * The function returns fee balance. + */ + function getFeeBalance() external view returns (uint256); + + /** + * The function returns min and max price per second for bid. + * @return Min bid price per second + * @return Max bid price per second + */ + function getMinMaxBidPricePerSecond() external view returns (uint256, uint256); } diff --git a/smart-contracts/contracts/interfaces/storage/IModelStorage.sol b/smart-contracts/contracts/interfaces/storage/IModelStorage.sol index 190f9260..64529112 100644 --- a/smart-contracts/contracts/interfaces/storage/IModelStorage.sol +++ b/smart-contracts/contracts/interfaces/storage/IModelStorage.sol @@ -2,20 +2,56 @@ pragma solidity ^0.8.24; interface IModelStorage { + /** + * The structure that stores the model data. + * @param ipfsCID https://docs.ipfs.tech/concepts/content-addressing/#what-is-a-cid. Up to the model maintainer to keep up to date. + * @param fee The model fee. Readonly for now. + * @param stake The stake amount. + * @param owner The owner. + * @param name The name. Readonly for now. + * @param tags The tags. Readonly for now. + * @param createdAt The timestamp when the model is created. + * @param isDeleted The model status. + */ struct Model { - bytes32 ipfsCID; // https://docs.ipfs.tech/concepts/content-addressing/#what-is-a-cid - uint256 fee; + bytes32 ipfsCID; + uint256 fee; // The fee is a royalty placeholder that isn't currently used uint256 stake; address owner; - string name; // limit name length - string[] tags; // TODO: limit tags amount + string name; // TODO: Limit name length. Up to the model maintainer to keep up to date + string[] tags; // TODO: Limit tags amount. Up to the model maintainer to keep up to date uint128 createdAt; bool isDeleted; } - function getModel(bytes32 modelId) external view returns (Model memory); + /** + * The function returns the model structure. + * @param modelId_ Model ID. + */ + function getModel(bytes32 modelId_) external view returns (Model memory); - function models(uint256 index) external view returns (bytes32); + /** + * The function returns the model IDs. + * @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 modelMinimumStake() external view returns (uint256); + /** + * The function returns the model minimal stake. + */ + function getModelMinimumStake() external view returns (uint256); + + /** + * The function returns active model IDs. + * @param offset_ Offset for the pagination. + * @param limit_ Number of entities to return. + */ + function getActiveModelIds(uint256 offset_, uint256 limit_) external view returns (bytes32[] memory); + + /** + * The function returns the model status, active or not. + * @param modelId_ Model ID. + */ + function getIsModelActive(bytes32 modelId_) external view returns (bool); } diff --git a/smart-contracts/contracts/interfaces/storage/IProviderStorage.sol b/smart-contracts/contracts/interfaces/storage/IProviderStorage.sol index db0c9b38..74fc8e1d 100644 --- a/smart-contracts/contracts/interfaces/storage/IProviderStorage.sol +++ b/smart-contracts/contracts/interfaces/storage/IProviderStorage.sol @@ -2,16 +2,45 @@ pragma solidity ^0.8.24; interface IProviderStorage { + /** + * The structure that stores the provider data. + * @param endpoint Example 'domain.com:1234'. Readonly for now. + * @param stake The stake amount. + * @param createdAt The timestamp when the provider is created. + * @param limitPeriodEnd Timestamp that indicate limit period end for provider rewards. + * @param limitPeriodEarned The amount of tokens that provider can receive before `limitPeriodEnd`. + * @param isDeleted The provider status. + */ struct Provider { - string endpoint; // example 'domain.com:1234' - uint256 stake; // stake amount, which also server as a reward limiter - uint128 createdAt; // timestamp of the registration - uint128 limitPeriodEnd; // timestamp of the limiter period end - uint256 limitPeriodEarned; // total earned during the last limiter period + string endpoint; + uint256 stake; + uint128 createdAt; + uint128 limitPeriodEnd; + uint256 limitPeriodEarned; bool isDeleted; } - function getProvider(address provider) external view returns (Provider memory); + /** + * The function returns provider structure. + * @param provider_ Provider address + */ + function getProvider(address provider_) external view returns (Provider memory); - function providerMinimumStake() external view returns (uint256); + /** + * The function returns provider minimal stake. + */ + function getProviderMinimumStake() external view returns (uint256); + + /** + * The function returns list of active providers. + * @param offset_ Offset for the pagination. + * @param limit_ Number of entities to return. + */ + function getActiveProviders(uint256 offset_, uint256 limit_) external view returns (address[] memory); + + /** + * The function returns provider status, active or not. + * @param provider_ Provider address + */ + function getIsProviderActive(address provider_) external view returns (bool); } diff --git a/smart-contracts/contracts/interfaces/storage/ISessionStorage.sol b/smart-contracts/contracts/interfaces/storage/ISessionStorage.sol index 6843c89e..b2eb97ed 100644 --- a/smart-contracts/contracts/interfaces/storage/ISessionStorage.sol +++ b/smart-contracts/contracts/interfaces/storage/ISessionStorage.sol @@ -2,28 +2,48 @@ pragma solidity ^0.8.24; interface ISessionStorage { + /** + * The structure that stores the bid data. + * @param user The user address. User opens the session + * @param bidId The bid ID. + * @param stake The stake amount. + * @param closeoutReceipt The receipt from provider when session closed. + * @param closeoutType The closeout type. + * @param providerWithdrawnAmount Provider withdrawn amount fot this session. + * @param openedAt The timestamp when the session is opened. Setted on creation. + * @param endsAt The timestamp when the session is ends. Setted on creation. + * @param closedAt The timestamp when the session is closed. Setted on close. + * @param isActive The session status. + * @param isDirectPaymentFromUser If active, user pay for provider from his stake. + */ struct Session { - bytes32 id; address user; - address provider; - bytes32 modelId; bytes32 bidId; uint256 stake; - uint256 pricePerSecond; bytes closeoutReceipt; - uint256 closeoutType; // use enum ?? - // amount of funds that was already withdrawn by provider (we allow to withdraw for the previous day) + uint256 closeoutType; uint256 providerWithdrawnAmount; - uint256 openedAt; - uint256 endsAt; // expected end time considering the stake provided - uint256 closedAt; + uint128 openedAt; + uint128 endsAt; + uint128 closedAt; + bool isActive; + bool isDirectPaymentFromUser; } + /** + * The structure that stores information about locked user funds. + * @param amount The locked amount. + * @param releaseAt The timestampl when funds will be available. + */ struct OnHold { uint256 amount; - uint128 releaseAt; // in epoch seconds TODO: consider using hours to reduce storage cost + // In epoch seconds. TODO: consider using hours to reduce storage cost + uint128 releaseAt; } + /** + * The structure that stores the Pool data. Should be the same with 0x47176B2Af9885dC6C4575d4eFd63895f7Aaa4790 on the Eth mainnet + */ struct Pool { uint256 initialReward; uint256 rewardDecrease; @@ -31,11 +51,79 @@ interface ISessionStorage { uint128 decreaseInterval; } - function sessions(bytes32 sessionId) external view returns (Session memory); + /** + * The function returns the session structure. + * @param sessionId_ Session ID + */ + function getSession(bytes32 sessionId_) external view returns (Session memory); - function getSessionsByUser(address user, uint256 offset_, uint256 limit_) external view returns (bytes32[] memory); + /** + * The function returns the user session IDs. + * @param user_ The user address + * @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); + /** + * The function returns the provider session IDs. + * @param provider_ The provider address + * @param offset_ Offset for the pagination. + * @param limit_ Number of entities to return. + */ + function getProviderSessions( + address provider_, + uint256 offset_, + uint256 limit_ + ) external view returns (bytes32[] memory); + + /** + * The function returns the model session IDs. + * @param modelId_ The model ID + * @param offset_ Offset for the pagination. + * @param limit_ Number of entities to return. + */ + function getModelSessions( + bytes32 modelId_, + uint256 offset_, + uint256 limit_ + ) external view returns (bytes32[] memory); + + /** + * The function returns the pools info. + */ + function getPools() external view returns (Pool[] memory); + + /** + * The function returns the pools info. + * @param index_ Pool index + */ + function getPool(uint256 index_) external view returns (Pool memory); + + /** + * The function returns the funcding (treasury) address for providers payments. + */ function getFundingAccount() external view returns (address); - function pools() external view returns (Pool[] memory); + /** + * The function returns total amount of sessions for the provider. + * @param provider_ Provider address + */ + function getTotalSessions(address provider_) external view returns (uint256); + + /** + * The function returns total amount of claimed token by providers. + */ + function getProvidersTotalClaimed() external view returns (uint256); + + /** + * Check the approval for usage. + * @param approval_ Approval from provider + */ + function getIsProviderApprovalUsed(bytes memory approval_) external view returns (bool); + + /** + * The function returns max session duration. + */ + function getMaxSessionDuration() external view returns (uint128); } diff --git a/smart-contracts/contracts/interfaces/storage/IStatsStorage.sol b/smart-contracts/contracts/interfaces/storage/IStatsStorage.sol index 7e25b9b3..6d2b15d0 100644 --- a/smart-contracts/contracts/interfaces/storage/IStatsStorage.sol +++ b/smart-contracts/contracts/interfaces/storage/IStatsStorage.sol @@ -4,12 +4,41 @@ pragma solidity ^0.8.24; import {LibSD} from "../../libs/LibSD.sol"; interface IStatsStorage { + struct ModelStats { + LibSD.SD tpsScaled1000; + LibSD.SD ttftMs; + LibSD.SD totalDuration; + uint32 count; + } + + /** + * The structure that stores the provider model stats. + * @param tpsScaled1000 Tokens per second running average + * @param ttftMs Time to first token running average in milliseconds + * @param totalDuration Total duration of sessions + * @param successCount Number of observations + * @param totalCount + */ struct ProviderModelStats { - LibSD.SD tpsScaled1000; // tokens per second running average - LibSD.SD ttftMs; // time to first token running average in milliseconds - uint32 totalDuration; // total duration of sessions - uint32 successCount; // number of observations + LibSD.SD tpsScaled1000; + LibSD.SD ttftMs; + uint32 totalDuration; + uint32 successCount; uint32 totalCount; // TODO: consider adding SD with weldford algorithm } + + /** + * @param modelId_ The model ID. + * @param provider_ The provider address. + */ + function getProviderModelStats( + bytes32 modelId_, + address provider_ + ) external view returns (ProviderModelStats memory); + + /** + * @param modelId_ The model ID. + */ + function getModelStats(bytes32 modelId_) external view returns (ModelStats memory); } diff --git a/smart-contracts/contracts/mock/tokens/MorpheusToken.sol b/smart-contracts/contracts/mock/tokens/MorpheusToken.sol index 8b5241dc..fe5b5110 100644 --- a/smart-contracts/contracts/mock/tokens/MorpheusToken.sol +++ b/smart-contracts/contracts/mock/tokens/MorpheusToken.sol @@ -5,9 +5,9 @@ import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; contract MorpheusToken is ERC20 { // set the initial supply to 42 million like in whitepaper - uint256 constant initialSupply = 42_000_000 * (10 ** 18); + uint256 public constant INITIAL_SUPPLUY = 42_000_000 ether; constructor() ERC20("Morpheus dev", "MOR") { - _mint(_msgSender(), initialSupply); + _mint(_msgSender(), INITIAL_SUPPLUY); } } diff --git a/smart-contracts/contracts/tokens/LumerinToken.sol b/smart-contracts/contracts/tokens/LumerinToken.sol index ede14ac5..e08234f4 100644 --- a/smart-contracts/contracts/tokens/LumerinToken.sol +++ b/smart-contracts/contracts/tokens/LumerinToken.sol @@ -4,10 +4,10 @@ pragma solidity ^0.8.24; import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; contract LumerinToken is ERC20 { - uint256 constant initialSupply = 1_000_000_000 * (10 ** 8); + uint256 public constant INITIAL_SUPPLUY = 1_000_000_000 * (10 ** 8); constructor(string memory name_, string memory symbol_) ERC20(name_, symbol_) { - _mint(_msgSender(), initialSupply); + _mint(_msgSender(), INITIAL_SUPPLUY); } function decimals() public pure override returns (uint8) { diff --git a/smart-contracts/deploy/1_full_protocol.migration.ts b/smart-contracts/deploy/1_full_protocol.migration.ts new file mode 100644 index 00000000..ac3b6c87 --- /dev/null +++ b/smart-contracts/deploy/1_full_protocol.migration.ts @@ -0,0 +1,120 @@ +import { Deployer, Reporter } from '@solarity/hardhat-migrate'; +import { Fragment } from 'ethers'; + +import { parseConfig } from './helpers/config-parser'; + +import { + IBidStorage__factory, + IMarketplace__factory, + IModelRegistry__factory, + IProviderRegistry__factory, + ISessionRouter__factory, + IStatsStorage__factory, + LinearDistributionIntervalDecrease__factory, + LumerinDiamond__factory, + Marketplace, + Marketplace__factory, + ModelRegistry, + ModelRegistry__factory, + ProviderRegistry, + ProviderRegistry__factory, + SessionRouter, + SessionRouter__factory, +} from '@/generated-types/ethers'; +import { FacetAction } from '@/test/helpers/deployers'; +import { DAY } from '@/utils/time'; + +module.exports = async function (deployer: Deployer) { + const config = parseConfig(); + + const lumerinDiamond = await deployer.deploy(LumerinDiamond__factory); + await lumerinDiamond.__LumerinDiamond_init(); + + const ldid = await deployer.deploy(LinearDistributionIntervalDecrease__factory); + + let providerRegistryFacet = await deployer.deploy(ProviderRegistry__factory); + let modelRegistryFacet = await deployer.deploy(ModelRegistry__factory); + let marketplaceFacet = await deployer.deploy(Marketplace__factory); + let sessionRouterFacet = await deployer.deploy(SessionRouter__factory, { + libraries: { + LinearDistributionIntervalDecrease: ldid, + }, + }); + + await lumerinDiamond['diamondCut((address,uint8,bytes4[])[])']([ + { + facetAddress: providerRegistryFacet, + action: FacetAction.Add, + functionSelectors: IProviderRegistry__factory.createInterface() + .fragments.filter(Fragment.isFunction) + .map((f) => f.selector), + }, + { + facetAddress: modelRegistryFacet, + action: FacetAction.Add, + functionSelectors: IModelRegistry__factory.createInterface() + .fragments.filter(Fragment.isFunction) + .map((f) => f.selector), + }, + { + facetAddress: marketplaceFacet, + action: FacetAction.Add, + functionSelectors: IMarketplace__factory.createInterface() + .fragments.filter(Fragment.isFunction) + .map((f) => f.selector), + }, + { + facetAddress: marketplaceFacet, + action: FacetAction.Add, + functionSelectors: IBidStorage__factory.createInterface() + .fragments.filter(Fragment.isFunction) + .map((f) => f.selector), + }, + { + facetAddress: sessionRouterFacet, + action: FacetAction.Add, + functionSelectors: ISessionRouter__factory.createInterface() + .fragments.filter(Fragment.isFunction) + .map((f) => f.selector), + }, + { + facetAddress: sessionRouterFacet, + action: FacetAction.Add, + functionSelectors: IStatsStorage__factory.createInterface() + .fragments.filter(Fragment.isFunction) + .map((f) => f.selector), + }, + ]); + + providerRegistryFacet = providerRegistryFacet.attach(lumerinDiamond.target) as ProviderRegistry; + await providerRegistryFacet.__ProviderRegistry_init(); + modelRegistryFacet = modelRegistryFacet.attach(lumerinDiamond.target) as ModelRegistry; + await modelRegistryFacet.__ModelRegistry_init(); + marketplaceFacet = marketplaceFacet.attach(lumerinDiamond.target) as Marketplace; + await marketplaceFacet.__Marketplace_init( + config.MOR, + config.marketplaceMinBidPricePerSecond, + config.marketplaceMaxBidPricePerSecond, + ); + sessionRouterFacet = sessionRouterFacet.attach(lumerinDiamond.target) as SessionRouter; + await sessionRouterFacet.__SessionRouter_init(config.fundingAccount, 7 * DAY, config.pools); + + await providerRegistryFacet.providerSetMinStake(config.providerMinStake); + await modelRegistryFacet.modelSetMinStake(config.modelMinStake); + await marketplaceFacet.setMarketplaceBidFee(config.marketplaceBidFee); + + // TODO: add allowance from the treasury + + Reporter.reportContracts( + ['Lumerin Diamond', await lumerinDiamond.getAddress()], + ['Linear Distribution Interval Decrease Library', await ldid.getAddress()], + ); +}; + +// npx hardhat migrate --only 1 + +// npx hardhat migrate --network arbitrum_sepolia --only 1 --verify +// npx hardhat migrate --network arbitrum_sepolia --only 1 --verify --continue + +// npx hardhat migrate --network arbitrum --only 1 --verify +// npx hardhat migrate --network arbitrum --only 1 --verify --continue diff --git a/smart-contracts/deploy/data/config_arbitrum_sepolia.json b/smart-contracts/deploy/data/config_arbitrum_sepolia.json new file mode 100644 index 00000000..2436772e --- /dev/null +++ b/smart-contracts/deploy/data/config_arbitrum_sepolia.json @@ -0,0 +1,42 @@ +{ + "MOR": "0x34a285a1b1c166420df5b6630132542923b5b27e", + "fundingAccount": "0x19ec1E4b714990620edf41fE28e9a1552953a7F4", + "providerMinStake": "200000000000000000", + "modelMinStake": "100000000000000000", + "marketplaceBidFee": "300000000000000000", + "marketplaceMinBidPricePerSecond": "5000000000000000", + "marketplaceMaxBidPricePerSecond": "20000000000000000000", + + "pools": [ + { + "payoutStart": 1707393600, + "decreaseInterval": 86400, + "initialReward": "3456000000000000000000", + "rewardDecrease": "592558728240000000" + }, + { + "payoutStart": 1707393600, + "decreaseInterval": 86400, + "initialReward": "3456000000000000000000", + "rewardDecrease": "592558728240000000" + }, + { + "payoutStart": 1707393600, + "decreaseInterval": 86400, + "initialReward": "3456000000000000000000", + "rewardDecrease": "592558728240000000" + }, + { + "payoutStart": 1707393600, + "decreaseInterval": 86400, + "initialReward": "3456000000000000000000", + "rewardDecrease": "592558728240000000" + }, + { + "payoutStart": 1707393600, + "decreaseInterval": 86400, + "initialReward": "576000000000000000000", + "rewardDecrease": "98759788040000000" + } + ] +} diff --git a/smart-contracts/deploy/helpers/config-parser.ts b/smart-contracts/deploy/helpers/config-parser.ts new file mode 100644 index 00000000..a17a6f71 --- /dev/null +++ b/smart-contracts/deploy/helpers/config-parser.ts @@ -0,0 +1,20 @@ +import { readFileSync } from 'fs'; + +import { ISessionStorage } from '@/generated-types/ethers'; + +export type Config = { + MOR: string; + fundingAccount: string; + pools: ISessionStorage.PoolStruct[]; + providerMinStake: string; + modelMinStake: string; + marketplaceBidFee: string; + marketplaceMinBidPricePerSecond: string; + marketplaceMaxBidPricePerSecond: string; +}; + +export function parseConfig(): Config { + const configPath = `deploy/data/config_arbitrum_sepolia.json`; + + return JSON.parse(readFileSync(configPath, 'utf-8')) as Config; +} diff --git a/smart-contracts/hardhat.config.ts b/smart-contracts/hardhat.config.ts index 41c1d579..953250c8 100644 --- a/smart-contracts/hardhat.config.ts +++ b/smart-contracts/hardhat.config.ts @@ -12,6 +12,10 @@ import 'tsconfig-paths/register'; dotenv.config(); +function privateKey() { + return process.env.PRIVATE_KEY !== undefined ? [process.env.PRIVATE_KEY] : []; +} + function typechainTarget() { const target = process.env.TYPECHAIN_TARGET; @@ -25,13 +29,16 @@ function forceTypechain() { const config: HardhatUserConfig = { networks: { hardhat: { - initialDate: '2024-07-15T01:00:00.000Z', + initialDate: '1970-01-01T00:00:00Z', gas: 'auto', // required for tests where two transactions should be mined in the same block // loggingEnabled: true, // mining: { // auto: true, // interval: 10_000, // }, + // forking: { + // url: `https://arbitrum-sepolia.infura.io/v3/${process.env.INFURA_KEY}`, + // }, }, localhost: { url: 'http://127.0.0.1:8545', @@ -39,6 +46,11 @@ const config: HardhatUserConfig = { gasMultiplier: 1.2, timeout: 1000000000000000, }, + arbitrum_sepolia: { + url: `https://arbitrum-sepolia.infura.io/v3/${process.env.INFURA_KEY}`, + accounts: privateKey(), + gasMultiplier: 1.1, + }, }, solidity: { version: '0.8.24', @@ -78,6 +90,12 @@ const config: HardhatUserConfig = { discriminateTypes: true, dontOverrideCompile: forceTypechain(), }, + etherscan: { + apiKey: { + mainnet: `${process.env.ETHERSCAN_API_KEY}`, + arbitrumSepolia: `${process.env.ARBITRUM_API_KEY}`, + }, + }, }; export default config; diff --git a/smart-contracts/package.json b/smart-contracts/package.json index c02a5dc1..788f380c 100644 --- a/smart-contracts/package.json +++ b/smart-contracts/package.json @@ -5,7 +5,7 @@ "license": "MIT", "scripts": { "compile": "hardhat compile", - "test": "hardhat test", + "test": "npm run generate-types && hardhat test", "test:gas": "REPORT_GAS=true hardhat test", "coverage": "hardhat coverage --solcoverjs ./.solcover.ts", "report": "open ./coverage/index.html", diff --git a/smart-contracts/test/diamond/LumerinDiamond.test.ts b/smart-contracts/test/diamond/LumerinDiamond.test.ts index 1e9c804c..a4b8e134 100644 --- a/smart-contracts/test/diamond/LumerinDiamond.test.ts +++ b/smart-contracts/test/diamond/LumerinDiamond.test.ts @@ -3,6 +3,7 @@ import { SignerWithAddress } from '@nomicfoundation/hardhat-ethers/signers'; import { expect } from 'chai'; import { ethers } from 'hardhat'; +import { deployLumerinDiamond } from '../helpers/deployers'; import { Reverter } from '../helpers/reverter'; describe('LumerinDiamond', () => { @@ -12,30 +13,27 @@ describe('LumerinDiamond', () => { let diamond: LumerinDiamond; - before('setup', async () => { + before(async () => { [OWNER] = await ethers.getSigners(); - const [LumerinDiamond] = await Promise.all([ethers.getContractFactory('LumerinDiamond')]); - - [diamond] = await Promise.all([LumerinDiamond.deploy()]); - - await diamond.__LumerinDiamond_init(); + diamond = await deployLumerinDiamond(); await reverter.snapshot(); }); afterEach(reverter.revert); - describe('Diamond functionality', () => { - describe('#__LumerinDiamond_init', () => { - it('should set correct data after creation', async () => { - expect(await diamond.owner()).to.eq(await OWNER.getAddress()); - }); - it('should revert if try to call init function twice', async () => { - const reason = 'Initializable: contract is already initialized'; - - await expect(diamond.__LumerinDiamond_init()).to.be.rejectedWith(reason); - }); + describe('#__LumerinDiamond_init', () => { + it('should set correct data after creation', async () => { + expect(await diamond.owner()).to.eq(await OWNER.getAddress()); + }); + it('should revert if try to call init function twice', async () => { + await expect(diamond.__LumerinDiamond_init()).to.be.rejectedWith( + 'Initializable: contract is already initialized', + ); }); }); }); + +// npx hardhat test "test/diamond/LumerinDiamond.test.ts" +// npx hardhat coverage --solcoverjs ./.solcover.ts --testfiles "test/diamond/LumerinDiamond.test.ts" diff --git a/smart-contracts/test/diamond/Marketplace.test.ts b/smart-contracts/test/diamond/Marketplace.test.ts deleted file mode 100644 index 5016f1fe..00000000 --- a/smart-contracts/test/diamond/Marketplace.test.ts +++ /dev/null @@ -1,476 +0,0 @@ -import { - IBidStorage, - IMarketplace__factory, - IModelRegistry__factory, - IModelStorage, - IProviderRegistry__factory, - IProviderStorage, - ISessionRouter__factory, - LumerinDiamond, - Marketplace, - ModelRegistry, - MorpheusToken, - ProviderRegistry, - SessionRouter, -} from '@ethers-v6'; -import { SignerWithAddress } from '@nomicfoundation/hardhat-ethers/signers'; -import { expect } from 'chai'; -import { Addressable, Fragment, resolveAddress } from 'ethers'; -import { ethers } from 'hardhat'; - -import { FacetAction } from '../helpers/enums'; -import { getDefaultPools } from '../helpers/pool-helper'; -import { Reverter } from '../helpers/reverter'; - -import { getHex, randomBytes32, wei } from '@/scripts/utils/utils'; -import { getCurrentBlockTime } from '@/utils/block-helper'; -import { HOUR, YEAR } from '@/utils/time'; - -describe('Marketplace', () => { - const reverter = new Reverter(); - - let OWNER: SignerWithAddress; - let SECOND: SignerWithAddress; - let THIRD: SignerWithAddress; - let PROVIDER: SignerWithAddress; - - let diamond: LumerinDiamond; - let marketplace: Marketplace; - let modelRegistry: ModelRegistry; - let providerRegistry: ProviderRegistry; - let sessionRouter: SessionRouter; - - let MOR: MorpheusToken; - - async function deployProvider(): Promise< - IProviderStorage.ProviderStruct & { - address: Addressable; - } - > { - const expectedProvider = { - endpoint: 'localhost:3334', - stake: wei(100), - createdAt: 0n, - limitPeriodEnd: 0n, - limitPeriodEarned: 0n, - isDeleted: false, - address: PROVIDER, - }; - - await MOR.transfer(PROVIDER, expectedProvider.stake * 100n); - await MOR.connect(PROVIDER).approve(sessionRouter, expectedProvider.stake); - - await providerRegistry - .connect(PROVIDER) - .providerRegister(expectedProvider.address, expectedProvider.stake, expectedProvider.endpoint); - expectedProvider.createdAt = await getCurrentBlockTime(); - expectedProvider.limitPeriodEnd = expectedProvider.createdAt + YEAR; - - return expectedProvider; - } - - async function deployModel(): Promise< - IModelStorage.ModelStruct & { - modelId: string; - } - > { - const expectedModel = { - modelId: randomBytes32(), - ipfsCID: getHex(Buffer.from('ipfs://ipfsaddress')), - fee: 100, - stake: 100, - owner: OWNER, - name: 'Llama 2.0', - tags: ['llama', 'animal', 'cute'], - createdAt: 0n, - isDeleted: false, - }; - - await MOR.approve(modelRegistry, expectedModel.stake); - - await modelRegistry.modelRegister( - expectedModel.modelId, - expectedModel.ipfsCID, - expectedModel.fee, - expectedModel.stake, - expectedModel.owner, - expectedModel.name, - expectedModel.tags, - ); - expectedModel.createdAt = await getCurrentBlockTime(); - - return expectedModel; - } - - async function deployBid(model: any): Promise< - IBidStorage.BidStruct & { - id: string; - modelId: string; - } - > { - let bid = { - id: '', - modelId: model.modelId, - pricePerSecond: wei(0.0001), - nonce: 0, - createdAt: 0n, - deletedAt: 0, - provider: PROVIDER, - }; - - await MOR.approve(modelRegistry, 10000n * 10n ** 18n); - - bid.id = await marketplace.connect(PROVIDER).postModelBid.staticCall(bid.provider, bid.modelId, bid.pricePerSecond); - await marketplace.connect(PROVIDER).postModelBid(bid.provider, bid.modelId, bid.pricePerSecond); - - bid.createdAt = await getCurrentBlockTime(); - - // generating data for sample session - const durationSeconds = HOUR; - const totalCost = bid.pricePerSecond * durationSeconds; - const totalSupply = await sessionRouter.totalMORSupply(await getCurrentBlockTime()); - const todaysBudget = await sessionRouter.getTodaysBudget(await getCurrentBlockTime()); - - const expectedSession = { - durationSeconds, - totalCost, - pricePerSecond: bid.pricePerSecond, - user: SECOND, - provider: bid.provider, - modelId: bid.modelId, - bidId: bid.id, - stake: (totalCost * totalSupply) / todaysBudget, - }; - - await MOR.transfer(SECOND, expectedSession.stake); - await MOR.connect(SECOND).approve(modelRegistry, expectedSession.stake); - - return bid; - } - before('setup', async () => { - [OWNER, SECOND, THIRD, PROVIDER] = await ethers.getSigners(); - - const LinearDistributionIntervalDecrease = await ethers.getContractFactory('LinearDistributionIntervalDecrease'); - const linearDistributionIntervalDecrease = await LinearDistributionIntervalDecrease.deploy(); - - const [LumerinDiamond, Marketplace, ModelRegistry, ProviderRegistry, SessionRouter, MorpheusToken] = - await Promise.all([ - ethers.getContractFactory('LumerinDiamond'), - ethers.getContractFactory('Marketplace'), - ethers.getContractFactory('ModelRegistry'), - ethers.getContractFactory('ProviderRegistry'), - ethers.getContractFactory('SessionRouter', { - libraries: { - LinearDistributionIntervalDecrease: linearDistributionIntervalDecrease, - }, - }), - ethers.getContractFactory('MorpheusToken'), - ]); - - [diamond, marketplace, modelRegistry, providerRegistry, sessionRouter, MOR] = await Promise.all([ - LumerinDiamond.deploy(), - Marketplace.deploy(), - ModelRegistry.deploy(), - ProviderRegistry.deploy(), - SessionRouter.deploy(), - MorpheusToken.deploy(), - ]); - - await diamond.__LumerinDiamond_init(); - - await diamond['diamondCut((address,uint8,bytes4[])[])']([ - { - facetAddress: marketplace, - action: FacetAction.Add, - functionSelectors: IMarketplace__factory.createInterface() - .fragments.filter(Fragment.isFunction) - .map((f) => f.selector), - }, - { - facetAddress: providerRegistry, - action: FacetAction.Add, - functionSelectors: IProviderRegistry__factory.createInterface() - .fragments.filter(Fragment.isFunction) - .map((f) => f.selector), - }, - { - facetAddress: sessionRouter, - action: FacetAction.Add, - functionSelectors: ISessionRouter__factory.createInterface() - .fragments.filter(Fragment.isFunction) - .map((f) => f.selector), - }, - { - facetAddress: modelRegistry, - action: FacetAction.Add, - functionSelectors: IModelRegistry__factory.createInterface() - .fragments.filter(Fragment.isFunction) - .map((f) => f.selector), - }, - ]); - - marketplace = marketplace.attach(diamond) as Marketplace; - providerRegistry = providerRegistry.attach(diamond) as ProviderRegistry; - modelRegistry = modelRegistry.attach(diamond) as ModelRegistry; - sessionRouter = sessionRouter.attach(diamond) as SessionRouter; - - await marketplace.__Marketplace_init(MOR); - await modelRegistry.__ModelRegistry_init(); - await providerRegistry.__ProviderRegistry_init(); - - await sessionRouter.__SessionRouter_init(OWNER, getDefaultPools()); - - await reverter.snapshot(); - }); - - afterEach(reverter.revert); - - describe('Diamond functionality', () => { - describe('#__Marketplace_init', () => { - it('should set correct data after creation', async () => { - expect(await marketplace.getToken()).to.eq(await MOR.getAddress()); - }); - it('should revert if try to call init function twice', async () => { - const reason = 'Initializable: contract is already initialized'; - - await expect(marketplace.__Marketplace_init(MOR)).to.be.rejectedWith(reason); - }); - }); - }); - - describe('bid actions', () => { - let provider: IProviderStorage.ProviderStruct; - let model: IModelStorage.ModelStruct & { - modelId: string; - }; - let bid: IBidStorage.BidStruct & { - id: string; - modelId: string; - }; - - beforeEach(async () => { - provider = await deployProvider(); - model = await deployModel(); - bid = await deployBid(model); - }); - - it('Should create a bid and query by id', async () => { - const data = await marketplace.bids(bid.id); - - expect(data).to.be.deep.equal([ - await resolveAddress(bid.provider), - bid.modelId, - bid.pricePerSecond, - bid.nonce, - bid.createdAt, - bid.deletedAt, - ]); - }); - - it("Should error if provider doesn't exist", async () => { - await expect( - marketplace.connect(SECOND).postModelBid(SECOND, bid.modelId, bid.pricePerSecond), - ).to.be.revertedWithCustomError(marketplace, 'ProviderNotFound'); - }); - - it("Should error if model doesn't exist", async () => { - const unknownModel = randomBytes32(); - - await expect( - marketplace.connect(PROVIDER).postModelBid(bid.provider, unknownModel, bid.pricePerSecond), - ).to.be.revertedWithCustomError(marketplace, 'ModelNotFound'); - }); - - it('should error if caller is not an owner or provider', async () => { - await expect( - marketplace.connect(SECOND).postModelBid(bid.provider, bid.modelId, bid.pricePerSecond), - ).to.be.revertedWithCustomError(marketplace, 'NotOwnerOrProvider'); - }); - - it('Should create second bid', async () => { - // create new bid with same provider and modelId - await marketplace.connect(PROVIDER).postModelBid(bid.provider, bid.modelId, bid.pricePerSecond); - const timestamp = await getCurrentBlockTime(); - - // check indexes are updated - const newBids1 = await marketplace.providerActiveBids(bid.provider, 0, 10); - const newBids2 = await marketplace.modelActiveBids(bid.modelId, 0, 10); - - expect(newBids1).to.be.deep.equal(newBids2); - expect(await marketplace.bids(newBids1[0])).to.be.deep.equal([ - await resolveAddress(bid.provider), - bid.modelId, - bid.pricePerSecond, - BigInt(bid.nonce) + 1n, - timestamp, - bid.deletedAt, - ]); - - // check old bid is deleted - const oldBid = await marketplace.bids(bid.id); - expect(oldBid).to.be.deep.equal([ - await resolveAddress(bid.provider), - bid.modelId, - bid.pricePerSecond, - bid.nonce, - bid.createdAt, - timestamp, - ]); - - // check old bid is still queried - const oldBids1 = await marketplace.providerBids(bid.provider, 0, 100); - const oldBids2 = await marketplace.modelBids(bid.modelId, 0, 100); - expect(oldBids1).to.be.deep.equal(oldBids2); - expect(oldBids1.length).to.be.equal(2); - expect(await marketplace.bids(oldBids1[0])).to.be.deep.equal([ - await resolveAddress(bid.provider), - bid.modelId, - bid.pricePerSecond, - bid.nonce, - bid.createdAt, - timestamp, - ]); - }); - - it('Should query by provider', async () => { - const activeBidIds = await marketplace.providerActiveBids(bid.provider, 0, 10); - - expect(activeBidIds.length).to.equal(1); - expect(activeBidIds[0]).to.equal(bid.id); - expect(await marketplace.bids(activeBidIds[0])).to.deep.equal([ - await resolveAddress(bid.provider), - bid.modelId, - bid.pricePerSecond, - bid.nonce, - bid.createdAt, - bid.deletedAt, - ]); - }); - - describe('delete bid', () => { - it('Should delete a bid', async () => { - // delete bid - await marketplace.connect(PROVIDER).deleteModelBid(bid.id); - - // check indexes are updated - const activeBidIds1 = await marketplace.providerActiveBids(bid.provider, 0, 10); - const activeBidIds2 = await marketplace.modelActiveBids(bid.modelId, 0, 10); - - expect(activeBidIds1.length).to.be.equal(0); - expect(activeBidIds2.length).to.be.equal(0); - - // check bid is deleted - const data = await marketplace.bids(bid.id); - expect(data).to.be.deep.equal([ - await resolveAddress(bid.provider), - bid.modelId, - bid.pricePerSecond, - bid.nonce, - bid.createdAt, - await getCurrentBlockTime(), - ]); - }); - - it("Should error if bid doesn't exist", async () => { - const unknownBid = randomBytes32(); - - await expect(marketplace.connect(PROVIDER).deleteModelBid(unknownBid)).to.be.revertedWithCustomError( - marketplace, - 'ActiveBidNotFound', - ); - }); - - it('Should error if not owner', async () => { - await expect(marketplace.connect(THIRD).deleteModelBid(bid.id)).to.be.revertedWithCustomError( - marketplace, - 'NotOwnerOrProvider', - ); - }); - - it('Should allow bid owner to delete bid', async () => { - // delete bid - await marketplace.connect(PROVIDER).deleteModelBid(bid.id); - }); - - it('Should allow contract owner to delete bid', async () => { - // delete bid - await marketplace.deleteModelBid(bid.id); - }); - - it('Should allow to create bid after it was deleted [H-1]', async () => { - // delete bid - await marketplace.connect(PROVIDER).deleteModelBid(bid.id); - - // create new bid with same provider and modelId - await marketplace.connect(PROVIDER).postModelBid(bid.provider, bid.modelId, bid.pricePerSecond); - }); - }); - - describe('bid fee', () => { - it('should set bid fee', async () => { - const newFee = 100; - await marketplace.setBidFee(newFee); - - const modelBidFee = await marketplace.getBidFee(); - expect(modelBidFee).to.be.equal(newFee); - }); - - it('should collect bid fee', async () => { - const newFee = 100; - await marketplace.setBidFee(newFee); - await MOR.transfer(bid.provider, 100); - - // check balance before - const balanceBefore = await MOR.balanceOf(marketplace); - // add bid - await MOR.connect(PROVIDER).approve(marketplace, Number(bid.pricePerSecond) + newFee); - await marketplace.connect(PROVIDER).postModelBid(bid.provider, bid.modelId, bid.pricePerSecond); - // check balance after - const balanceAfter = await MOR.balanceOf(marketplace); - expect(balanceAfter - balanceBefore).to.be.equal(newFee); - }); - - it('should allow withdrawal by owner', async () => { - const newFee = 100; - await marketplace.setBidFee(newFee); - await MOR.transfer(bid.provider, 100); - // add bid - await MOR.connect(PROVIDER).approve(marketplace, Number(bid.pricePerSecond) + newFee); - await marketplace.connect(PROVIDER).postModelBid(bid.provider, bid.modelId, bid.pricePerSecond); - // check balance after - const balanceBefore = await MOR.balanceOf(OWNER); - await marketplace.withdraw(OWNER, newFee); - const balanceAfter = await MOR.balanceOf(OWNER); - expect(balanceAfter - balanceBefore).to.be.equal(newFee); - }); - - it('should not allow withdrawal by any other account except owner', async () => { - const newFee = 100; - await marketplace.setBidFee(newFee); - await MOR.transfer(bid.provider, 100); - // add bid - await MOR.connect(PROVIDER).approve(marketplace, Number(bid.pricePerSecond) + newFee); - await marketplace.connect(PROVIDER).postModelBid(bid.provider, bid.modelId, bid.pricePerSecond); - // check balance after - await expect(marketplace.connect(PROVIDER).withdraw(bid.provider, newFee)).to.be.revertedWithCustomError( - diamond, - 'OwnableUnauthorizedAccount', - ); - }); - - it('should not allow withdrawal if not enough balance', async () => { - await expect(marketplace.withdraw(OWNER, 100000000)).to.be.revertedWithCustomError( - marketplace, - 'NotEnoughBalance', - ); - }); - - it('should revert if caller is not an owner', async () => { - await expect(marketplace.connect(SECOND).setBidFee(1)).to.be.revertedWithCustomError( - diamond, - 'OwnableUnauthorizedAccount', - ); - }); - }); - }); -}); diff --git a/smart-contracts/test/diamond/ModelRegistry.test.ts b/smart-contracts/test/diamond/ModelRegistry.test.ts deleted file mode 100644 index 5a43b624..00000000 --- a/smart-contracts/test/diamond/ModelRegistry.test.ts +++ /dev/null @@ -1,508 +0,0 @@ -import { - IBidStorage, - IMarketplace__factory, - IModelRegistry__factory, - IModelStorage, - IProviderRegistry__factory, - IProviderStorage, - ISessionRouter__factory, - LumerinDiamond, - Marketplace, - ModelRegistry, - MorpheusToken, - ProviderRegistry, - SessionRouter, -} from '@ethers-v6'; -import { SignerWithAddress } from '@nomicfoundation/hardhat-ethers/signers'; -import { expect } from 'chai'; -import { Addressable, Fragment, resolveAddress } from 'ethers'; -import { ethers } from 'hardhat'; - -import { FacetAction } from '../helpers/enums'; -import { getDefaultPools } from '../helpers/pool-helper'; -import { Reverter } from '../helpers/reverter'; - -import { getHex, randomBytes32, wei } from '@/scripts/utils/utils'; -import { getCurrentBlockTime } from '@/utils/block-helper'; -import { HOUR, YEAR } from '@/utils/time'; - -describe('Model registry', () => { - const reverter = new Reverter(); - - let OWNER: SignerWithAddress; - let SECOND: SignerWithAddress; - let THIRD: SignerWithAddress; - let PROVIDER: SignerWithAddress; - - let diamond: LumerinDiamond; - let marketplace: Marketplace; - let modelRegistry: ModelRegistry; - let providerRegistry: ProviderRegistry; - let sessionRouter: SessionRouter; - - let MOR: MorpheusToken; - - async function deployProvider(): Promise< - IProviderStorage.ProviderStruct & { - address: Addressable; - } - > { - const expectedProvider = { - endpoint: 'localhost:3334', - stake: wei(100), - createdAt: 0n, - limitPeriodEnd: 0n, - limitPeriodEarned: 0n, - isDeleted: false, - address: PROVIDER, - }; - - await MOR.transfer(PROVIDER, expectedProvider.stake * 100n); - await MOR.connect(PROVIDER).approve(sessionRouter, expectedProvider.stake); - - await providerRegistry - .connect(PROVIDER) - .providerRegister(expectedProvider.address, expectedProvider.stake, expectedProvider.endpoint); - expectedProvider.createdAt = await getCurrentBlockTime(); - expectedProvider.limitPeriodEnd = expectedProvider.createdAt + YEAR; - - return expectedProvider; - } - - async function deployModel(): Promise< - IModelStorage.ModelStruct & { - modelId: string; - } - > { - const model = { - modelId: randomBytes32(), - ipfsCID: getHex(Buffer.from('ipfs://ipfsaddress')), - fee: 100, - stake: 100, - owner: OWNER, - name: 'Llama 2.0', - tags: ['llama', 'animal', 'cute'], - createdAt: 0n, - isDeleted: false, - }; - - await MOR.approve(modelRegistry, model.stake); - - await modelRegistry.modelRegister( - model.modelId, - model.ipfsCID, - model.fee, - model.stake, - model.owner, - model.name, - model.tags, - ); - model.createdAt = await getCurrentBlockTime(); - - return model; - } - - async function deployBid(model: any): Promise< - IBidStorage.BidStruct & { - id: string; - modelId: string; - } - > { - let bid = { - id: '', - modelId: model.modelId, - pricePerSecond: wei(0.0001), - nonce: 0, - createdAt: 0n, - deletedAt: 0, - provider: PROVIDER, - }; - - await MOR.approve(modelRegistry, 10000n * 10n ** 18n); - - bid.id = await marketplace.connect(PROVIDER).postModelBid.staticCall(bid.provider, bid.modelId, bid.pricePerSecond); - await marketplace.connect(PROVIDER).postModelBid(bid.provider, bid.modelId, bid.pricePerSecond); - - bid.createdAt = await getCurrentBlockTime(); - - // generating data for sample session - const durationSeconds = HOUR; - const totalCost = bid.pricePerSecond * durationSeconds; - const totalSupply = await sessionRouter.totalMORSupply(await getCurrentBlockTime()); - const todaysBudget = await sessionRouter.getTodaysBudget(await getCurrentBlockTime()); - - const expectedSession = { - durationSeconds, - totalCost, - pricePerSecond: bid.pricePerSecond, - user: SECOND, - provider: bid.provider, - modelId: bid.modelId, - bidId: bid.id, - stake: (totalCost * totalSupply) / todaysBudget, - }; - - await MOR.transfer(SECOND, expectedSession.stake); - await MOR.connect(SECOND).approve(modelRegistry, expectedSession.stake); - - return bid; - } - - before('setup', async () => { - [OWNER, SECOND, THIRD, PROVIDER] = await ethers.getSigners(); - - const LinearDistributionIntervalDecrease = await ethers.getContractFactory('LinearDistributionIntervalDecrease'); - const linearDistributionIntervalDecrease = await LinearDistributionIntervalDecrease.deploy(); - - const [LumerinDiamond, Marketplace, ModelRegistry, ProviderRegistry, SessionRouter, MorpheusToken] = - await Promise.all([ - ethers.getContractFactory('LumerinDiamond'), - ethers.getContractFactory('Marketplace'), - ethers.getContractFactory('ModelRegistry'), - ethers.getContractFactory('ProviderRegistry'), - ethers.getContractFactory('SessionRouter', { - libraries: { - LinearDistributionIntervalDecrease: linearDistributionIntervalDecrease, - }, - }), - ethers.getContractFactory('MorpheusToken'), - ]); - - [diamond, marketplace, modelRegistry, providerRegistry, sessionRouter, MOR] = await Promise.all([ - LumerinDiamond.deploy(), - Marketplace.deploy(), - ModelRegistry.deploy(), - ProviderRegistry.deploy(), - SessionRouter.deploy(), - MorpheusToken.deploy(), - ]); - - await diamond.__LumerinDiamond_init(); - - await diamond['diamondCut((address,uint8,bytes4[])[])']([ - { - facetAddress: marketplace, - action: FacetAction.Add, - functionSelectors: IMarketplace__factory.createInterface() - .fragments.filter(Fragment.isFunction) - .map((f) => f.selector), - }, - { - facetAddress: providerRegistry, - action: FacetAction.Add, - functionSelectors: IProviderRegistry__factory.createInterface() - .fragments.filter(Fragment.isFunction) - .map((f) => f.selector), - }, - { - facetAddress: sessionRouter, - action: FacetAction.Add, - functionSelectors: ISessionRouter__factory.createInterface() - .fragments.filter(Fragment.isFunction) - .map((f) => f.selector), - }, - { - facetAddress: modelRegistry, - action: FacetAction.Add, - functionSelectors: IModelRegistry__factory.createInterface() - .fragments.filter(Fragment.isFunction) - .map((f) => f.selector), - }, - ]); - - marketplace = marketplace.attach(diamond.target) as Marketplace; - providerRegistry = providerRegistry.attach(diamond.target) as ProviderRegistry; - modelRegistry = modelRegistry.attach(diamond.target) as ModelRegistry; - sessionRouter = sessionRouter.attach(diamond.target) as SessionRouter; - - await marketplace.__Marketplace_init(MOR); - await modelRegistry.__ModelRegistry_init(); - await providerRegistry.__ProviderRegistry_init(); - - await sessionRouter.__SessionRouter_init(OWNER, getDefaultPools()); - - await reverter.snapshot(); - }); - - afterEach(reverter.revert); - - describe('Diamond functionality', () => { - describe('#__ModelRegistry_init', () => { - it('should revert if try to call init function twice', async () => { - const reason = 'Initializable: contract is already initialized'; - - await expect(modelRegistry.__ModelRegistry_init()).to.be.rejectedWith(reason); - }); - }); - }); - - describe('Actions', () => { - let provider: IProviderStorage.ProviderStruct; - let model: IModelStorage.ModelStruct & { - modelId: string; - }; - let bid: IBidStorage.BidStruct & { - id: string; - modelId: string; - }; - - beforeEach(async () => { - provider = await deployProvider(); - model = await deployModel(); - bid = await deployBid(model); - }); - - it('Should register', async () => { - const data = await modelRegistry.getModel(model.modelId); - - expect(await modelRegistry.models(0)).eq(model.modelId); - expect(data).deep.equal([ - model.ipfsCID, - model.fee, - model.stake, - await resolveAddress(model.owner), - model.name, - model.tags, - model.createdAt, - model.isDeleted, - ]); - }); - - it('Should error when registering with insufficient stake', async () => { - const minStake = 100n; - await modelRegistry.setModelMinimumStake(minStake); - - await expect( - modelRegistry.modelRegister(randomBytes32(), randomBytes32(), 0n, 0n, OWNER, 'a', []), - ).revertedWithCustomError(modelRegistry, 'StakeTooLow'); - }); - - it('Should error when registering with insufficient allowance', async () => { - await expect( - modelRegistry.connect(THIRD).modelRegister(randomBytes32(), randomBytes32(), 0n, 100n, THIRD, 'a', []), - ).to.rejectedWith('ERC20: insufficient allowance'); - }); - - it('Should error when register account doesnt match sender account', async () => { - await MOR.approve(modelRegistry, 100n); - - await expect( - modelRegistry.connect(THIRD).modelRegister(randomBytes32(), randomBytes32(), 0n, 100n, SECOND, 'a', []), - ).to.revertedWithCustomError(modelRegistry, 'NotOwnerOrModelOwner'); - }); - - it('Should deregister by owner', async () => { - await marketplace.connect(PROVIDER).deleteModelBid(bid.id); - - await modelRegistry.modelDeregister(model.modelId); - - expect((await modelRegistry.getModel(model.modelId)).isDeleted).to.equal(true); - expect(await modelRegistry.models(0n)).equals(model.modelId); - }); - - it('Should error if model not known by admin', async () => { - await expect(modelRegistry.modelDeregister(randomBytes32())).to.revertedWithCustomError( - modelRegistry, - 'ModelNotFound', - ); - }); - - it('Should error if caller is not owner or model owner', async () => { - await expect(modelRegistry.connect(SECOND).modelDeregister(model.modelId)).to.revertedWithCustomError( - modelRegistry, - 'NotOwnerOrModelOwner', - ); - }); - - it('Should return stake on deregister', async () => { - await marketplace.connect(PROVIDER).deleteModelBid(bid.id); - - const balanceBefore = await MOR.balanceOf(model.owner); - await modelRegistry.modelDeregister(model.modelId); - const balanceAfter = await MOR.balanceOf(model.owner); - - expect(balanceAfter - balanceBefore).eq(model.stake); - }); - - it('should error when deregistering a model that has bids', async () => { - // try deregistering model - await expect(modelRegistry.modelDeregister(model.modelId)).to.revertedWithCustomError( - modelRegistry, - 'ModelHasActiveBids', - ); - - // remove bid - await marketplace.connect(PROVIDER).deleteModelBid(bid.id); - - // deregister model - await modelRegistry.modelDeregister(model.modelId); - }); - - it('Should update existing model', async () => { - const updates = { - ipfsCID: getHex(Buffer.from('ipfs://new-ipfsaddress')), - fee: BigInt(model.fee) * 2n, - addStake: BigInt(model.stake) * 2n, - owner: PROVIDER, - name: 'Llama 3.0', - tags: ['llama', 'smart', 'angry'], - }; - await MOR.approve(modelRegistry, updates.addStake); - - await modelRegistry.modelRegister( - model.modelId, - updates.ipfsCID, - updates.fee, - updates.addStake, - updates.owner, - updates.name, - updates.tags, - ); - const providerData = await modelRegistry.getModel(model.modelId); - - expect(providerData).deep.equal([ - updates.ipfsCID, - updates.fee, - BigInt(model.stake) + updates.addStake, - await resolveAddress(updates.owner), - updates.name, - updates.tags, - model.createdAt, - model.isDeleted, - ]); - }); - - it('Should emit event on update', async () => { - const updates = { - ipfsCID: getHex(Buffer.from('ipfs://new-ipfsaddress')), - fee: BigInt(model.fee) * 2n, - addStake: BigInt(model.stake) * 2n, - owner: PROVIDER, - name: 'Llama 3.0', - tags: ['llama', 'smart', 'angry'], - }; - - await MOR.approve(modelRegistry, updates.addStake); - - await expect( - modelRegistry.modelRegister( - model.modelId, - updates.ipfsCID, - updates.fee, - updates.addStake, - updates.owner, - updates.name, - updates.tags, - ), - ).to.emit(modelRegistry, 'ModelRegisteredUpdated'); - }); - - it('should reregister model', async () => { - await marketplace.connect(PROVIDER).deleteModelBid(bid.id); - - // check indexes - expect(await modelRegistry.models(0)).eq(model.modelId); - - // deregister - await modelRegistry.modelDeregister(model.modelId); - - // check indexes - expect(await modelRegistry.models(0)).eq(model.modelId); - - // reregister - const modelId = model.modelId; - const model2 = { - ipfsCID: randomBytes32(), - fee: 100n, - stake: 100n, - owner: await resolveAddress(OWNER), - name: 'model2', - tags: ['model', '2'], - createdAt: model.createdAt, - }; - await MOR.transfer(OWNER, model2.stake); - await MOR.approve(modelRegistry, model2.stake); - await modelRegistry.modelRegister( - modelId, - model2.ipfsCID, - model2.fee, - model2.stake, - model2.owner, - model2.name, - model2.tags, - ); - // check indexes - expect(await modelRegistry.models(0)).eq(modelId); - expect(await modelRegistry.getModel(modelId)).deep.equal([ - model2.ipfsCID, - model2.fee, - model2.stake, - model2.owner, - model2.name, - model2.tags, - model2.createdAt, - false, - ]); - }); - - it('Should error if reregister model by caller is not owner or model owner', async () => { - await expect( - modelRegistry - .connect(SECOND) - .modelRegister(model.modelId, model.ipfsCID, model.fee, model.stake, model.owner, model.name, model.tags), - ).to.revertedWithCustomError(modelRegistry, 'NotOwnerOrModelOwner'); - }); - - describe('Getters', () => { - it('Should get by address', async () => { - const providerData = await modelRegistry.getModel(model.modelId); - expect(providerData).deep.equal([ - model.ipfsCID, - model.fee, - model.stake, - await resolveAddress(model.owner), - model.name, - model.tags, - model.createdAt, - model.isDeleted, - ]); - }); - }); - - describe('Min stake', () => { - it('Should set min stake', async () => { - const minStake = 100n; - await expect(modelRegistry.setModelMinimumStake(minStake)) - .to.emit(modelRegistry, 'ModelMinimumStakeSet') - .withArgs(minStake); - - expect(await modelRegistry.modelMinimumStake()).eq(minStake); - }); - it('Should error when not owner is setting min stake', async () => { - await expect(modelRegistry.connect(THIRD).setModelMinimumStake(0)).to.revertedWithCustomError( - diamond, - 'OwnableUnauthorizedAccount', - ); - }); - // it("Should get model stats", async () => { - // const stats = await modelRegistry.modelStats([model.modelId]); - - // expect(stats).deep.equal({ - // count: 0, - // totalDuration: { - // mean: 0n, - // sqSum: 0n, - // }, - // tpsScaled1000: { - // mean: 0n, - // sqSum: 0n, - // }, - // ttftMs: { - // mean: 0n, - // sqSum: 0n, - // }, - // }); - // }); - }); - }); -}); diff --git a/smart-contracts/test/diamond/ProviderRegistry.test.ts b/smart-contracts/test/diamond/ProviderRegistry.test.ts deleted file mode 100644 index 061f3dcd..00000000 --- a/smart-contracts/test/diamond/ProviderRegistry.test.ts +++ /dev/null @@ -1,444 +0,0 @@ -import { - IBidStorage, - IMarketplace__factory, - IModelRegistry__factory, - IModelStorage, - IProviderRegistry__factory, - IProviderStorage, - ISessionRouter__factory, - LumerinDiamond, - Marketplace, - ModelRegistry, - MorpheusToken, - ProviderRegistry, - SessionRouter, -} from '@ethers-v6'; -import { SignerWithAddress } from '@nomicfoundation/hardhat-ethers/signers'; -import { expect } from 'chai'; -import { Addressable, Fragment, resolveAddress } from 'ethers'; -import { ethers } from 'hardhat'; - -import { FacetAction } from '../helpers/enums'; -import { getDefaultPools } from '../helpers/pool-helper'; -import { Reverter } from '../helpers/reverter'; - -import { getHex, randomBytes32, wei } from '@/scripts/utils/utils'; -import { getCurrentBlockTime } from '@/utils/block-helper'; -import { HOUR, YEAR } from '@/utils/time'; - -describe('Provider registry', () => { - const reverter = new Reverter(); - - let OWNER: SignerWithAddress; - let SECOND: SignerWithAddress; - let THIRD: SignerWithAddress; - let PROVIDER: SignerWithAddress; - - let diamond: LumerinDiamond; - let marketplace: Marketplace; - let modelRegistry: ModelRegistry; - let providerRegistry: ProviderRegistry; - let sessionRouter: SessionRouter; - - let MOR: MorpheusToken; - - async function deployProvider(): Promise< - IProviderStorage.ProviderStruct & { - address: Addressable; - } - > { - const provider = { - endpoint: 'localhost:3334', - stake: wei(100), - createdAt: 0n, - limitPeriodEnd: 0n, - limitPeriodEarned: 0n, - isDeleted: false, - address: PROVIDER, - }; - - await MOR.transfer(PROVIDER, provider.stake * 100n); - await MOR.connect(PROVIDER).approve(sessionRouter, provider.stake); - - await providerRegistry.connect(PROVIDER).providerRegister(provider.address, provider.stake, provider.endpoint); - provider.createdAt = await getCurrentBlockTime(); - provider.limitPeriodEnd = provider.createdAt + YEAR; - - return provider; - } - - async function deployModel(): Promise< - IModelStorage.ModelStruct & { - modelId: string; - } - > { - const model = { - modelId: randomBytes32(), - ipfsCID: getHex(Buffer.from('ipfs://ipfsaddress')), - fee: 100, - stake: 100, - owner: OWNER, - name: 'Llama 2.0', - tags: ['llama', 'animal', 'cute'], - createdAt: 0n, - isDeleted: false, - }; - - await MOR.approve(modelRegistry, model.stake); - - await modelRegistry.modelRegister( - model.modelId, - model.ipfsCID, - model.fee, - model.stake, - model.owner, - model.name, - model.tags, - ); - model.createdAt = await getCurrentBlockTime(); - - return model; - } - - async function deployBid(model: any): Promise< - IBidStorage.BidStruct & { - id: string; - modelId: string; - } - > { - let bid = { - id: '', - modelId: model.modelId, - pricePerSecond: wei(0.0001), - nonce: 0, - createdAt: 0n, - deletedAt: 0, - provider: PROVIDER, - }; - - await MOR.approve(modelRegistry, 10000n * 10n ** 18n); - - bid.id = await marketplace.connect(PROVIDER).postModelBid.staticCall(bid.provider, bid.modelId, bid.pricePerSecond); - await marketplace.connect(PROVIDER).postModelBid(bid.provider, bid.modelId, bid.pricePerSecond); - - bid.createdAt = await getCurrentBlockTime(); - - // generating data for sample session - const durationSeconds = HOUR; - const totalCost = bid.pricePerSecond * durationSeconds; - const totalSupply = await sessionRouter.totalMORSupply(await getCurrentBlockTime()); - const todaysBudget = await sessionRouter.getTodaysBudget(await getCurrentBlockTime()); - - const expectedSession = { - durationSeconds, - totalCost, - pricePerSecond: bid.pricePerSecond, - user: SECOND, - provider: bid.provider, - modelId: bid.modelId, - bidId: bid.id, - stake: (totalCost * totalSupply) / todaysBudget, - }; - - await MOR.transfer(SECOND, expectedSession.stake); - await MOR.connect(SECOND).approve(modelRegistry, expectedSession.stake); - - return bid; - } - - before('setup', async () => { - [OWNER, SECOND, THIRD, PROVIDER] = await ethers.getSigners(); - - const LinearDistributionIntervalDecrease = await ethers.getContractFactory('LinearDistributionIntervalDecrease'); - const linearDistributionIntervalDecrease = await LinearDistributionIntervalDecrease.deploy(); - - const [LumerinDiamond, Marketplace, ModelRegistry, ProviderRegistry, SessionRouter, MorpheusToken] = - await Promise.all([ - ethers.getContractFactory('LumerinDiamond'), - ethers.getContractFactory('Marketplace'), - ethers.getContractFactory('ModelRegistry'), - ethers.getContractFactory('ProviderRegistry'), - ethers.getContractFactory('SessionRouter', { - libraries: { - LinearDistributionIntervalDecrease: linearDistributionIntervalDecrease, - }, - }), - ethers.getContractFactory('MorpheusToken'), - ]); - - [diamond, marketplace, modelRegistry, providerRegistry, sessionRouter, MOR] = await Promise.all([ - LumerinDiamond.deploy(), - Marketplace.deploy(), - ModelRegistry.deploy(), - ProviderRegistry.deploy(), - SessionRouter.deploy(), - MorpheusToken.deploy(), - ]); - - await diamond.__LumerinDiamond_init(); - - await diamond['diamondCut((address,uint8,bytes4[])[])']([ - { - facetAddress: marketplace, - action: FacetAction.Add, - functionSelectors: IMarketplace__factory.createInterface() - .fragments.filter(Fragment.isFunction) - .map((f) => f.selector), - }, - { - facetAddress: providerRegistry, - action: FacetAction.Add, - functionSelectors: IProviderRegistry__factory.createInterface() - .fragments.filter(Fragment.isFunction) - .map((f) => f.selector), - }, - { - facetAddress: sessionRouter, - action: FacetAction.Add, - functionSelectors: ISessionRouter__factory.createInterface() - .fragments.filter(Fragment.isFunction) - .map((f) => f.selector), - }, - { - facetAddress: modelRegistry, - action: FacetAction.Add, - functionSelectors: IModelRegistry__factory.createInterface() - .fragments.filter(Fragment.isFunction) - .map((f) => f.selector), - }, - ]); - - marketplace = marketplace.attach(diamond.target) as Marketplace; - providerRegistry = providerRegistry.attach(diamond.target) as ProviderRegistry; - modelRegistry = modelRegistry.attach(diamond.target) as ModelRegistry; - sessionRouter = sessionRouter.attach(diamond.target) as SessionRouter; - - await marketplace.__Marketplace_init(MOR); - await modelRegistry.__ModelRegistry_init(); - await providerRegistry.__ProviderRegistry_init(); - - await sessionRouter.__SessionRouter_init(OWNER, getDefaultPools()); - - await reverter.snapshot(); - }); - - afterEach(reverter.revert); - - describe('Diamond functionality', () => { - describe('#__ProviderRegistry_init', () => { - it('should revert if try to call init function twice', async () => { - const reason = 'Initializable: contract is already initialized'; - - await expect(providerRegistry.__ProviderRegistry_init()).to.be.rejectedWith(reason); - }); - }); - }); - - describe('Actions', () => { - let provider: IProviderStorage.ProviderStruct; - let model: IModelStorage.ModelStruct & { - modelId: string; - }; - let bid: IBidStorage.BidStruct & { - id: string; - modelId: string; - }; - - beforeEach(async () => { - provider = await deployProvider(); - model = await deployModel(); - bid = await deployBid(model); - }); - - it('Should register', async () => { - await providerRegistry.connect(SECOND).providerRegister(SECOND, provider.stake, provider.endpoint); - - const data = await providerRegistry.getProvider(SECOND); - - expect(data).deep.equal([ - provider.endpoint, - provider.stake, - await getCurrentBlockTime(), - (await getCurrentBlockTime()) + YEAR, - provider.limitPeriodEarned, - false, - ]); - }); - - it('Should error when registering with insufficient stake', async () => { - const minStake = 100; - await providerRegistry.providerSetMinStake(minStake); - - await expect(providerRegistry.providerRegister(SECOND, minStake - 1, 'endpoint')).to.be.revertedWithCustomError( - providerRegistry, - 'StakeTooLow', - ); - }); - - it('Should error when registering with insufficient allowance', async () => { - // await catchError(MOR.abi, "ERC20InsufficientAllowance", async () => { - // await providerRegistry.providerRegister([PROVIDER, 100n, "endpoint"]); - // }); - await expect(providerRegistry.connect(THIRD).providerRegister(THIRD, 100n, 'endpoint')).to.be.revertedWith( - 'ERC20: insufficient allowance', - ); - }); - - it('Should error when register account doesnt match sender account', async () => { - await expect( - providerRegistry.connect(PROVIDER).providerRegister(THIRD, 100n, 'endpoint'), - ).to.be.revertedWithCustomError(providerRegistry, 'NotOwnerOrProvider'); - }); - - describe('Deregister', () => { - it('Should deregister by provider', async () => { - await marketplace.connect(PROVIDER).deleteModelBid(bid.id); - - await expect(providerRegistry.connect(PROVIDER).providerDeregister(PROVIDER)) - .to.emit(providerRegistry, 'ProviderDeregistered') - .withArgs(PROVIDER); - - expect((await providerRegistry.getProvider(PROVIDER)).isDeleted).to.equal(true); - }); - - it('Should deregister by admin', async () => { - await marketplace.connect(PROVIDER).deleteModelBid(bid.id); - - await expect(providerRegistry.providerDeregister(PROVIDER)) - .to.emit(providerRegistry, 'ProviderDeregistered') - .withArgs(PROVIDER); - }); - - it('Should return stake on deregister', async () => { - await marketplace.connect(PROVIDER).deleteModelBid(bid.id); - - const balanceBefore = await MOR.balanceOf(PROVIDER); - await providerRegistry.connect(PROVIDER).providerDeregister(PROVIDER); - const balanceAfter = await MOR.balanceOf(PROVIDER); - expect(balanceAfter - balanceBefore).eq(provider.stake); - }); - - it('should error when deregistering a model that has bids', async () => { - // try deregistering model - await expect(providerRegistry.connect(PROVIDER).providerDeregister(PROVIDER)).to.be.revertedWithCustomError( - providerRegistry, - 'ProviderHasActiveBids', - ); - - // remove bid - await marketplace.connect(PROVIDER).deleteModelBid(bid.id); - // deregister model - await providerRegistry.connect(PROVIDER).providerDeregister(PROVIDER); - }); - - it('Should correctly reregister provider', async () => { - await marketplace.connect(PROVIDER).deleteModelBid(bid.id); - - // deregister - await providerRegistry.connect(PROVIDER).providerDeregister(PROVIDER); - // check indexes - const provider2 = { - endpoint: 'new-endpoint-2', - stake: 123n, - limitPeriodEarned: provider.limitPeriodEarned, - limitPeriodEnd: provider.limitPeriodEnd, - createdAt: provider.createdAt, - }; - // register again - await MOR.transfer(PROVIDER, provider2.stake); - await MOR.connect(PROVIDER).approve(providerRegistry, provider2.stake); - await providerRegistry.connect(PROVIDER).providerRegister(PROVIDER, provider2.stake, provider2.endpoint); - // check record - expect(await providerRegistry.getProvider(PROVIDER)).deep.equal([ - provider2.endpoint, - provider2.stake, - provider2.createdAt, - provider2.limitPeriodEnd, - provider2.limitPeriodEarned, - false, - ]); - }); - - it('should error if caller is not an owner or provider', async () => { - await marketplace.connect(PROVIDER).deleteModelBid(bid.id); - - await expect(providerRegistry.connect(SECOND).providerDeregister(PROVIDER)).to.revertedWithCustomError( - providerRegistry, - 'NotOwnerOrProvider', - ); - }); - - it('should error if provider is not exists', async () => { - await marketplace.connect(PROVIDER).deleteModelBid(bid.id); - - await expect(providerRegistry.connect(SECOND).providerDeregister(SECOND)).to.revertedWithCustomError( - providerRegistry, - 'ProviderNotFound', - ); - }); - }); - - it('Should update stake and url', async () => { - const updates = { - addStake: BigInt(provider.stake) * 2n, - endpoint: 'new-endpoint', - }; - await MOR.connect(PROVIDER).approve(providerRegistry, updates.addStake); - - await providerRegistry.connect(PROVIDER).providerRegister(PROVIDER, updates.addStake, updates.endpoint); - - const providerData = await providerRegistry.getProvider(PROVIDER); - expect(providerData).deep.equal([ - updates.endpoint, - BigInt(provider.stake) + updates.addStake, - provider.createdAt, - provider.limitPeriodEnd, - provider.limitPeriodEarned, - provider.isDeleted, - ]); - }); - - it('Should emit event on update', async () => { - const updates = { - addStake: BigInt(provider.stake) * 2n, - endpoint: 'new-endpoint', - }; - await MOR.connect(PROVIDER).approve(providerRegistry, updates.addStake); - await expect(providerRegistry.connect(PROVIDER).providerRegister(PROVIDER, updates.addStake, updates.endpoint)) - .to.emit(providerRegistry, 'ProviderRegisteredUpdated') - .withArgs(PROVIDER); - }); - - describe('Getters', () => { - it('Should get by address', async () => { - const providerData = await providerRegistry.getProvider(PROVIDER); - expect(providerData).deep.equal([ - provider.endpoint, - provider.stake, - provider.createdAt, - provider.limitPeriodEnd, - provider.limitPeriodEarned, - provider.isDeleted, - ]); - }); - }); - - describe('Min stake', () => { - it('Should set min stake', async () => { - const minStake = 100n; - await expect(providerRegistry.providerSetMinStake(minStake)) - .to.emit(providerRegistry, 'ProviderMinStakeUpdated') - .withArgs(minStake); - - expect(await providerRegistry.providerMinimumStake()).eq(minStake); - }); - - it('Should error when not owner is setting min stake', async () => { - await expect(providerRegistry.connect(SECOND).providerSetMinStake(100)).to.be.revertedWithCustomError( - diamond, - 'OwnableUnauthorizedAccount', - ); - }); - }); - }); -}); diff --git a/smart-contracts/test/diamond/SessionRouter/closeSession.test.ts b/smart-contracts/test/diamond/SessionRouter/closeSession.test.ts deleted file mode 100644 index eaf4414f..00000000 --- a/smart-contracts/test/diamond/SessionRouter/closeSession.test.ts +++ /dev/null @@ -1,512 +0,0 @@ -import { - IBidStorage, - IMarketplace__factory, - IModelRegistry__factory, - IModelStorage, - IProviderRegistry__factory, - IProviderStorage, - ISessionRouter__factory, - LumerinDiamond, - Marketplace, - ModelRegistry, - MorpheusToken, - ProviderRegistry, - SessionRouter, -} from '@ethers-v6'; -import { SignerWithAddress } from '@nomicfoundation/hardhat-ethers/signers'; -import { expect } from 'chai'; -import { Addressable, Fragment } from 'ethers'; -import { ethers } from 'hardhat'; - -import { MAX_UINT8 } from '@/scripts/utils/constants'; -import { getHex, randomBytes32, wei } from '@/scripts/utils/utils'; -import { FacetAction } from '@/test/helpers/enums'; -import { getDefaultPools } from '@/test/helpers/pool-helper'; -import { Reverter } from '@/test/helpers/reverter'; -import { getCurrentBlockTime, setTime } from '@/utils/block-helper'; -import { getProviderApproval, getReport } from '@/utils/provider-helper'; -import { DAY, HOUR, YEAR } from '@/utils/time'; - -describe('Session closeout', () => { - const reverter = new Reverter(); - - let OWNER: SignerWithAddress; - let SECOND: SignerWithAddress; - let THIRD: SignerWithAddress; - let PROVIDER: SignerWithAddress; - - let diamond: LumerinDiamond; - let marketplace: Marketplace; - let modelRegistry: ModelRegistry; - let providerRegistry: ProviderRegistry; - let sessionRouter: SessionRouter; - - let MOR: MorpheusToken; - - async function deployProvider(): Promise< - IProviderStorage.ProviderStruct & { - address: Addressable; - } - > { - const provider = { - endpoint: 'localhost:3334', - stake: wei(100), - createdAt: 0n, - limitPeriodEnd: 0n, - limitPeriodEarned: 0n, - isDeleted: false, - address: PROVIDER, - }; - - await MOR.transfer(PROVIDER, provider.stake * 100n); - await MOR.connect(PROVIDER).approve(sessionRouter, provider.stake); - - await providerRegistry.connect(PROVIDER).providerRegister(provider.address, provider.stake, provider.endpoint); - provider.createdAt = await getCurrentBlockTime(); - provider.limitPeriodEnd = provider.createdAt + YEAR; - - return provider; - } - - async function deployModel(): Promise< - IModelStorage.ModelStruct & { - modelId: string; - } - > { - const model = { - modelId: randomBytes32(), - ipfsCID: getHex(Buffer.from('ipfs://ipfsaddress')), - fee: 100, - stake: 100, - owner: OWNER, - name: 'Llama 2.0', - tags: ['llama', 'animal', 'cute'], - createdAt: 0n, - isDeleted: false, - }; - - await MOR.approve(modelRegistry, model.stake); - - await modelRegistry.modelRegister( - model.modelId, - model.ipfsCID, - model.fee, - model.stake, - model.owner, - model.name, - model.tags, - ); - model.createdAt = await getCurrentBlockTime(); - - return model; - } - - async function deployBid(model: any): Promise< - [ - IBidStorage.BidStruct & { - id: string; - modelId: string; - }, - { - durationSeconds: bigint; - totalCost: bigint; - pricePerSecond: bigint; - user: SignerWithAddress; - provider: SignerWithAddress; - modelId: any; - bidId: string; - stake: bigint; - }, - ] - > { - let bid = { - id: '', - modelId: model.modelId, - pricePerSecond: wei(0.0001), - nonce: 0, - createdAt: 0n, - deletedAt: 0, - provider: PROVIDER, - }; - - await MOR.approve(modelRegistry, 10000n * 10n ** 18n); - - bid.id = await marketplace.connect(PROVIDER).postModelBid.staticCall(bid.provider, bid.modelId, bid.pricePerSecond); - await marketplace.connect(PROVIDER).postModelBid(bid.provider, bid.modelId, bid.pricePerSecond); - - bid.createdAt = await getCurrentBlockTime(); - - // generating data for sample session - const durationSeconds = HOUR; - const totalCost = bid.pricePerSecond * durationSeconds; - const totalSupply = await sessionRouter.totalMORSupply(await getCurrentBlockTime()); - const todaysBudget = await sessionRouter.getTodaysBudget(await getCurrentBlockTime()); - - const expectedSession = { - durationSeconds, - totalCost, - pricePerSecond: bid.pricePerSecond, - user: SECOND, - provider: bid.provider, - modelId: bid.modelId, - bidId: bid.id, - stake: (totalCost * totalSupply) / todaysBudget, - }; - - await MOR.transfer(SECOND, expectedSession.stake); - await MOR.connect(SECOND).approve(modelRegistry, expectedSession.stake); - - return [bid, expectedSession]; - } - - before('setup', async () => { - [OWNER, SECOND, THIRD, PROVIDER] = await ethers.getSigners(); - - const LinearDistributionIntervalDecrease = await ethers.getContractFactory('LinearDistributionIntervalDecrease'); - const linearDistributionIntervalDecrease = await LinearDistributionIntervalDecrease.deploy(); - - const [LumerinDiamond, Marketplace, ModelRegistry, ProviderRegistry, SessionRouter, MorpheusToken] = - await Promise.all([ - ethers.getContractFactory('LumerinDiamond'), - ethers.getContractFactory('Marketplace'), - ethers.getContractFactory('ModelRegistry'), - ethers.getContractFactory('ProviderRegistry'), - ethers.getContractFactory('SessionRouter', { - libraries: { - LinearDistributionIntervalDecrease: linearDistributionIntervalDecrease, - }, - }), - ethers.getContractFactory('MorpheusToken'), - ]); - - [diamond, marketplace, modelRegistry, providerRegistry, sessionRouter, MOR] = await Promise.all([ - LumerinDiamond.deploy(), - Marketplace.deploy(), - ModelRegistry.deploy(), - ProviderRegistry.deploy(), - SessionRouter.deploy(), - MorpheusToken.deploy(), - ]); - - await diamond.__LumerinDiamond_init(); - - await diamond['diamondCut((address,uint8,bytes4[])[])']([ - { - facetAddress: marketplace, - action: FacetAction.Add, - functionSelectors: IMarketplace__factory.createInterface() - .fragments.filter(Fragment.isFunction) - .map((f) => f.selector), - }, - { - facetAddress: providerRegistry, - action: FacetAction.Add, - functionSelectors: IProviderRegistry__factory.createInterface() - .fragments.filter(Fragment.isFunction) - .map((f) => f.selector), - }, - { - facetAddress: sessionRouter, - action: FacetAction.Add, - functionSelectors: ISessionRouter__factory.createInterface() - .fragments.filter(Fragment.isFunction) - .map((f) => f.selector), - }, - { - facetAddress: modelRegistry, - action: FacetAction.Add, - functionSelectors: IModelRegistry__factory.createInterface() - .fragments.filter(Fragment.isFunction) - .map((f) => f.selector), - }, - ]); - - marketplace = marketplace.attach(diamond.target) as Marketplace; - providerRegistry = providerRegistry.attach(diamond.target) as ProviderRegistry; - modelRegistry = modelRegistry.attach(diamond.target) as ModelRegistry; - sessionRouter = sessionRouter.attach(diamond.target) as SessionRouter; - - await marketplace.__Marketplace_init(MOR); - await modelRegistry.__ModelRegistry_init(); - await providerRegistry.__ProviderRegistry_init(); - - await sessionRouter.__SessionRouter_init(OWNER, getDefaultPools()); - - await reverter.snapshot(); - }); - - afterEach(reverter.revert); - - describe('Actions', () => { - let provider: IProviderStorage.ProviderStruct; - let model: IModelStorage.ModelStruct & { - modelId: string; - }; - let bid: IBidStorage.BidStruct & { - id: string; - modelId: string; - }; - let session: { - durationSeconds: bigint; - totalCost: bigint; - pricePerSecond: bigint; - user: SignerWithAddress; - provider: SignerWithAddress; - modelId: any; - bidId: string; - stake: bigint; - }; - - beforeEach(async () => { - provider = await deployProvider(); - model = await deployModel(); - [bid, session] = await deployBid(model); - }); - - it('should open short (<1D) session and close after expiration', async () => { - // open session - const { msg, signature } = await getProviderApproval(PROVIDER, await SECOND.getAddress(), session.bidId); - - const sessionId = await sessionRouter.connect(SECOND).openSession.staticCall(session.stake, msg, signature); - await sessionRouter.connect(SECOND).openSession(session.stake, msg, signature); - - await setTime(Number((await getCurrentBlockTime()) + session.durationSeconds * 2n)); - - const userBalanceBefore = await MOR.balanceOf(SECOND); - const providerBalanceBefore = await MOR.balanceOf(PROVIDER); - - // close session - const report = await getReport(PROVIDER, sessionId, 10, 1000); - await sessionRouter.connect(SECOND).closeSession(report.msg, report.signature); - - // verify session is closed without dispute - const sessionData = await sessionRouter.sessions(sessionId); - expect(sessionData.closeoutType).to.equal(0n); - - // verify balances - const userBalanceAfter = await MOR.balanceOf(SECOND); - const providerBalanceAfter = await MOR.balanceOf(PROVIDER); - - const userStakeReturned = userBalanceAfter - userBalanceBefore; - const providerEarned = providerBalanceAfter - providerBalanceBefore; - - const totalPrice = (sessionData.endsAt - sessionData.openedAt) * session.pricePerSecond; - - expect(userStakeReturned).to.closeTo(0, Number(session.pricePerSecond) * 5); - expect(providerEarned).to.closeTo(totalPrice, 1); - }); - - it('should open short (<1D) session and close early', async () => { - // open session - const { msg, signature } = await getProviderApproval(PROVIDER, await SECOND.getAddress(), session.bidId); - const sessionId = await sessionRouter.connect(SECOND).openSession.staticCall(session.stake, msg, signature); - await sessionRouter.connect(SECOND).openSession(session.stake, msg, signature); - - await setTime(Number((await getCurrentBlockTime()) + session.durationSeconds / 2n - 1n)); - - const userBalanceBefore = await MOR.balanceOf(SECOND); - const providerBalanceBefore = await MOR.balanceOf(PROVIDER); - - // close session - const report = await getReport(PROVIDER, sessionId, 10, 1000); - await sessionRouter.connect(SECOND).closeSession(report.msg, report.signature); - - // verify session is closed without dispute - const sessionData = await sessionRouter.sessions(sessionId); - expect(sessionData.closeoutType).to.equal(0n); - - // verify balances - const userBalanceAfter = await MOR.balanceOf(SECOND); - const providerBalanceAfter = await MOR.balanceOf(PROVIDER); - - const userStakeReturned = userBalanceAfter - userBalanceBefore; - const providerEarned = providerBalanceAfter - providerBalanceBefore; - - expect(userStakeReturned).to.closeTo(session.stake / 2n, Number(session.pricePerSecond) * 5); - expect(providerEarned).to.closeTo(session.totalCost / 2n, 1); - }); - - it('should open and close early with user report - dispute', async () => { - // open session - const { msg, signature } = await getProviderApproval(PROVIDER, await SECOND.getAddress(), session.bidId); - const sessionId = await sessionRouter.connect(SECOND).openSession.staticCall(session.stake, msg, signature); - await sessionRouter.connect(SECOND).openSession(session.stake, msg, signature); - - // wait half of the session - await setTime(Number((await getCurrentBlockTime()) + session.durationSeconds / 2n - 1n)); - - const userBalanceBefore = await MOR.balanceOf(SECOND); - const providerBalanceBefore = await MOR.balanceOf(PROVIDER); - - // close session with user signature - const report = await getReport(SECOND, sessionId, 10, 1000); - await sessionRouter.connect(SECOND).closeSession(report.msg, report.signature); - - // verify session is closed with dispute - const sessionData = await sessionRouter.sessions(sessionId); - const totalCost = sessionData.pricePerSecond * (sessionData.closedAt - sessionData.openedAt); - - // verify balances - const userBalanceAfter = await MOR.balanceOf(SECOND); - const providerBalanceAfter = await MOR.balanceOf(PROVIDER); - - const claimableProvider = await sessionRouter.getProviderClaimableBalance(sessionData.id); - - const [userAvail, userHold] = await sessionRouter.withdrawableUserStake(sessionData.user, MAX_UINT8); - - expect(sessionData.closeoutType).to.equal(1n); - expect(providerBalanceAfter - providerBalanceBefore).to.equal(0n); - expect(claimableProvider).to.equal(0n); - expect(session.stake / 2n).to.closeTo(userBalanceAfter - userBalanceBefore, 1); - expect(userAvail).to.equal(0n); - expect(userHold).to.closeTo(userBalanceAfter - userBalanceBefore, 1); - - // verify provider balance after dispute is released - await setTime(Number((await getCurrentBlockTime()) + DAY)); - const claimableProvider2 = await sessionRouter.getProviderClaimableBalance(sessionId); - expect(claimableProvider2).to.equal(totalCost); - - // claim provider balance - await sessionRouter.claimProviderBalance(sessionId, claimableProvider2); - - // verify provider balance after claim - const providerBalanceAfterClaim = await MOR.balanceOf(PROVIDER); - const providerClaimed = providerBalanceAfterClaim - providerBalanceAfter; - expect(providerClaimed).to.equal(totalCost); - }); - - it('should error when not a user trying to close', async () => { - // open session - const { msg, signature } = await getProviderApproval(PROVIDER, await SECOND.getAddress(), session.bidId); - const sessionId = await sessionRouter.connect(SECOND).openSession.staticCall(session.stake, msg, signature); - await sessionRouter.connect(SECOND).openSession(session.stake, msg, signature); - - // wait half of the session - await setTime(Number((await getCurrentBlockTime()) + session.durationSeconds / 2n - 1n)); - - // close session with user signature - const report = await getReport(SECOND, sessionId, 10, 10); - - await expect( - sessionRouter.connect(THIRD).closeSession(report.msg, report.signature), - ).to.be.revertedWithCustomError(sessionRouter, 'NotOwnerOrUser'); - }); - - it('should limit reward by stake amount', async () => { - // expected bid - const expectedBid = { - id: '', - providerAddr: await PROVIDER.getAddress(), - modelId: model.modelId, - pricePerSecond: wei('0.1'), - nonce: 0n, - createdAt: 0n, - deletedAt: 0n, - }; - - // add single bid - const postBidId = await marketplace - .connect(PROVIDER) - .postModelBid.staticCall(expectedBid.providerAddr, expectedBid.modelId, expectedBid.pricePerSecond); - await marketplace - .connect(PROVIDER) - .postModelBid(expectedBid.providerAddr, expectedBid.modelId, expectedBid.pricePerSecond); - - expectedBid.id = postBidId; - expectedBid.createdAt = await getCurrentBlockTime(); - - // calculate data for session opening - const totalCost = BigInt(provider.stake) * 2n; - const durationSeconds = totalCost / expectedBid.pricePerSecond; - const totalSupply = await sessionRouter.totalMORSupply(await getCurrentBlockTime()); - const todaysBudget = await sessionRouter.getTodaysBudget(await getCurrentBlockTime()); - - const expectedSession = { - durationSeconds, - totalCost, - pricePerSecond: expectedBid.pricePerSecond, - user: await SECOND.getAddress(), - provider: expectedBid.providerAddr, - modelId: expectedBid.modelId, - bidId: expectedBid.id, - stake: (totalCost * totalSupply) / todaysBudget, - }; - - // set user balance and approve funds - await MOR.transfer(SECOND, expectedSession.stake); - await MOR.connect(SECOND).approve(modelRegistry, expectedSession.stake); - - // open session - const { msg, signature } = await getProviderApproval(PROVIDER, await SECOND.getAddress(), expectedSession.bidId); - const sessionId = await sessionRouter - .connect(SECOND) - .openSession.staticCall(expectedSession.stake, msg, signature); - await sessionRouter.connect(SECOND).openSession(expectedSession.stake, msg, signature); - - // wait till session ends - await setTime(Number((await getCurrentBlockTime()) + expectedSession.durationSeconds)); - - const providerBalanceBefore = await MOR.balanceOf(PROVIDER); - // close session without dispute - const report = await getReport(PROVIDER, sessionId, 10, 1000); - await sessionRouter.connect(SECOND).closeSession(report.msg, report.signature); - - const providerBalanceAfter = await MOR.balanceOf(PROVIDER); - - const providerEarned = providerBalanceAfter - providerBalanceBefore; - - expect(providerEarned).to.equal(provider.stake); - - // check provider record if earning was updated - const providerRecord = await providerRegistry.getProvider(PROVIDER); - expect(providerRecord.limitPeriodEarned).to.equal(provider.stake); - }); - - it('should error if session is not exists', async () => { - // close session - const report = await getReport(PROVIDER, randomBytes32(), 10, 1000); - - await expect(sessionRouter.connect(SECOND).closeSession(report.msg, report.signature)).to.revertedWithCustomError( - sessionRouter, - 'SessionNotFound', - ); - }); - - it('should error if session is already closed', async () => { - // open session - const { msg, signature } = await getProviderApproval(PROVIDER, await SECOND.getAddress(), session.bidId); - - const sessionId = await sessionRouter.connect(SECOND).openSession.staticCall(session.stake, msg, signature); - await sessionRouter.connect(SECOND).openSession(session.stake, msg, signature); - - await setTime(Number((await getCurrentBlockTime()) + session.durationSeconds * 2n)); - - // close session - const report = await getReport(PROVIDER, sessionId, 10, 1000); - await sessionRouter.connect(SECOND).closeSession(report.msg, report.signature); - - await expect(sessionRouter.connect(SECOND).closeSession(report.msg, report.signature)).to.revertedWithCustomError( - sessionRouter, - 'SessionAlreadyClosed', - ); - }); - - it('should error when approval expired', async () => { - const { msg, signature } = await getProviderApproval(PROVIDER, await SECOND.getAddress(), session.bidId); - // open session - const sessionId = await sessionRouter.connect(SECOND).openSession.staticCall(session.stake, msg, signature); - await sessionRouter.connect(SECOND).openSession(session.stake, msg, signature); - // close session - const report = await getReport(PROVIDER, sessionId, 10, 1000); - const ttl = await sessionRouter.SIGNATURE_TTL(); - await setTime(Number((await getCurrentBlockTime()) + ttl + 1n)); - await expect( - sessionRouter.connect(SECOND).closeSession(report.msg, report.signature), - ).to.be.revertedWithCustomError(sessionRouter, 'SignatureExpired'); - }); - - it('should reset provider limitPeriodEarned after period', async () => {}); - - it('should error with WithdrawableBalanceLimitByStakeReached() if claiming more that stake for a period', async () => {}); - }); -}); diff --git a/smart-contracts/test/diamond/SessionRouter/openSession.test.ts b/smart-contracts/test/diamond/SessionRouter/openSession.test.ts deleted file mode 100644 index 47d75d70..00000000 --- a/smart-contracts/test/diamond/SessionRouter/openSession.test.ts +++ /dev/null @@ -1,612 +0,0 @@ -import { - IBidStorage, - IMarketplace__factory, - IModelRegistry__factory, - IModelStorage, - IProviderRegistry__factory, - IProviderStorage, - ISessionRouter__factory, - LumerinDiamond, - Marketplace, - ModelRegistry, - MorpheusToken, - ProviderRegistry, - SessionRouter, -} from '@ethers-v6'; -import { SignerWithAddress } from '@nomicfoundation/hardhat-ethers/signers'; -import { expect } from 'chai'; -import { Addressable, Fragment, randomBytes, resolveAddress } from 'ethers'; -import { ethers } from 'hardhat'; - -import { getHex, randomBytes32, startOfTheDay, wei } from '@/scripts/utils/utils'; -import { FacetAction } from '@/test/helpers/enums'; -import { getDefaultPools } from '@/test/helpers/pool-helper'; -import { Reverter } from '@/test/helpers/reverter'; -import { getCurrentBlockTime, setTime } from '@/utils/block-helper'; -import { getProviderApproval, getReport } from '@/utils/provider-helper'; -import { DAY, HOUR, YEAR } from '@/utils/time'; - -describe('session actions', () => { - const reverter = new Reverter(); - - let OWNER: SignerWithAddress; - let SECOND: SignerWithAddress; - let THIRD: SignerWithAddress; - let PROVIDER: SignerWithAddress; - - let diamond: LumerinDiamond; - let marketplace: Marketplace; - let modelRegistry: ModelRegistry; - let providerRegistry: ProviderRegistry; - let sessionRouter: SessionRouter; - - let MOR: MorpheusToken; - - async function deployProvider(): Promise< - IProviderStorage.ProviderStruct & { - address: Addressable; - } - > { - const provider = { - endpoint: 'localhost:3334', - stake: wei(100), - createdAt: 0n, - limitPeriodEnd: 0n, - limitPeriodEarned: 0n, - isDeleted: false, - address: PROVIDER, - }; - - await MOR.transfer(PROVIDER, provider.stake * 100n); - await MOR.connect(PROVIDER).approve(sessionRouter, provider.stake); - - await providerRegistry.connect(PROVIDER).providerRegister(provider.address, provider.stake, provider.endpoint); - provider.createdAt = await getCurrentBlockTime(); - provider.limitPeriodEnd = provider.createdAt + YEAR; - - return provider; - } - - async function deployModel(): Promise< - IModelStorage.ModelStruct & { - modelId: string; - } - > { - const model = { - modelId: randomBytes32(), - ipfsCID: getHex(Buffer.from('ipfs://ipfsaddress')), - fee: 100, - stake: 100, - owner: OWNER, - name: 'Llama 2.0', - tags: ['llama', 'animal', 'cute'], - createdAt: 0n, - isDeleted: false, - }; - - await MOR.approve(modelRegistry, model.stake); - - await modelRegistry.modelRegister( - model.modelId, - model.ipfsCID, - model.fee, - model.stake, - model.owner, - model.name, - model.tags, - ); - model.createdAt = await getCurrentBlockTime(); - - return model; - } - - async function deployBid(model: any): Promise< - [ - IBidStorage.BidStruct & { - id: string; - modelId: string; - }, - { - durationSeconds: bigint; - totalCost: bigint; - pricePerSecond: bigint; - user: SignerWithAddress; - provider: SignerWithAddress; - modelId: any; - bidId: string; - stake: bigint; - }, - ] - > { - let bid = { - id: '', - modelId: model.modelId, - pricePerSecond: wei(0.0001), - nonce: 0, - createdAt: 0n, - deletedAt: 0, - provider: PROVIDER, - }; - - await MOR.approve(modelRegistry, 10000n * 10n ** 18n); - - bid.id = await marketplace.connect(PROVIDER).postModelBid.staticCall(bid.provider, bid.modelId, bid.pricePerSecond); - await marketplace.connect(PROVIDER).postModelBid(bid.provider, bid.modelId, bid.pricePerSecond); - - bid.createdAt = await getCurrentBlockTime(); - - // generating data for sample session - const durationSeconds = HOUR; - const totalCost = bid.pricePerSecond * durationSeconds; - const totalSupply = await sessionRouter.totalMORSupply(await getCurrentBlockTime()); - const todaysBudget = await sessionRouter.getTodaysBudget(await getCurrentBlockTime()); - - const expectedSession = { - durationSeconds, - totalCost, - pricePerSecond: bid.pricePerSecond, - user: SECOND, - provider: bid.provider, - modelId: bid.modelId, - bidId: bid.id, - stake: (totalCost * totalSupply) / todaysBudget, - }; - - await MOR.transfer(SECOND, expectedSession.stake); - await MOR.connect(SECOND).approve(modelRegistry, expectedSession.stake); - - return [bid, expectedSession]; - } - - async function openSession(session: any) { - // open session - const { msg, signature } = await getProviderApproval(PROVIDER, await SECOND.getAddress(), session.bidId); - const sessionId = await sessionRouter.connect(SECOND).openSession.staticCall(session.stake, msg, signature); - await sessionRouter.connect(SECOND).openSession(session.stake, msg, signature); - - return sessionId; - } - - before('setup', async () => { - [OWNER, SECOND, THIRD, PROVIDER] = await ethers.getSigners(); - - const LinearDistributionIntervalDecrease = await ethers.getContractFactory('LinearDistributionIntervalDecrease'); - const linearDistributionIntervalDecrease = await LinearDistributionIntervalDecrease.deploy(); - - const [LumerinDiamond, Marketplace, ModelRegistry, ProviderRegistry, SessionRouter, MorpheusToken] = - await Promise.all([ - ethers.getContractFactory('LumerinDiamond'), - ethers.getContractFactory('Marketplace'), - ethers.getContractFactory('ModelRegistry'), - ethers.getContractFactory('ProviderRegistry'), - ethers.getContractFactory('SessionRouter', { - libraries: { - LinearDistributionIntervalDecrease: linearDistributionIntervalDecrease, - }, - }), - ethers.getContractFactory('MorpheusToken'), - ]); - - [diamond, marketplace, modelRegistry, providerRegistry, sessionRouter, MOR] = await Promise.all([ - LumerinDiamond.deploy(), - Marketplace.deploy(), - ModelRegistry.deploy(), - ProviderRegistry.deploy(), - SessionRouter.deploy(), - MorpheusToken.deploy(), - ]); - - await diamond.__LumerinDiamond_init(); - - await diamond['diamondCut((address,uint8,bytes4[])[])']([ - { - facetAddress: marketplace, - action: FacetAction.Add, - functionSelectors: IMarketplace__factory.createInterface() - .fragments.filter(Fragment.isFunction) - .map((f) => f.selector), - }, - { - facetAddress: providerRegistry, - action: FacetAction.Add, - functionSelectors: IProviderRegistry__factory.createInterface() - .fragments.filter(Fragment.isFunction) - .map((f) => f.selector), - }, - { - facetAddress: sessionRouter, - action: FacetAction.Add, - functionSelectors: ISessionRouter__factory.createInterface() - .fragments.filter(Fragment.isFunction) - .map((f) => f.selector), - }, - { - facetAddress: modelRegistry, - action: FacetAction.Add, - functionSelectors: IModelRegistry__factory.createInterface() - .fragments.filter(Fragment.isFunction) - .map((f) => f.selector), - }, - ]); - - marketplace = marketplace.attach(diamond.target) as Marketplace; - providerRegistry = providerRegistry.attach(diamond.target) as ProviderRegistry; - modelRegistry = modelRegistry.attach(diamond.target) as ModelRegistry; - sessionRouter = sessionRouter.attach(diamond.target) as SessionRouter; - - await marketplace.__Marketplace_init(MOR); - await modelRegistry.__ModelRegistry_init(); - await providerRegistry.__ProviderRegistry_init(); - - await sessionRouter.__SessionRouter_init(OWNER, getDefaultPools()); - - await reverter.snapshot(); - }); - - afterEach(reverter.revert); - - describe('Actions', () => { - let provider: IProviderStorage.ProviderStruct; - let model: IModelStorage.ModelStruct & { - modelId: string; - }; - let bid: IBidStorage.BidStruct & { - id: string; - modelId: string; - }; - let session: { - durationSeconds: bigint; - totalCost: bigint; - pricePerSecond: bigint; - user: SignerWithAddress; - provider: SignerWithAddress; - modelId: any; - bidId: string; - stake: bigint; - }; - - beforeEach(async () => { - provider = await deployProvider(); - model = await deployModel(); - [bid, session] = await deployBid(model); - }); - - describe('positive cases', () => { - it('should open session without error', async () => { - const { msg, signature } = await getProviderApproval(PROVIDER, await SECOND.getAddress(), session.bidId); - const sessionId = await sessionRouter.connect(SECOND).openSession.staticCall(session.stake, msg, signature); - await sessionRouter.connect(SECOND).openSession(session.stake, msg, signature); - - expect(sessionId).to.be.a('string'); - }); - - it('should emit SessionOpened event', async () => { - const { msg, signature } = await getProviderApproval(PROVIDER, await SECOND.getAddress(), session.bidId); - - const sessionId = await sessionRouter.connect(SECOND).openSession.staticCall(session.stake, msg, signature); - await expect(sessionRouter.connect(SECOND).openSession(session.stake, msg, signature)) - .to.emit(sessionRouter, 'SessionOpened') - .withArgs(session.user, sessionId, session.provider); - }); - - it('should verify session fields after opening', async () => { - const { msg, signature } = await getProviderApproval(PROVIDER, await SECOND.getAddress(), session.bidId); - const sessionId = await sessionRouter.connect(SECOND).openSession.staticCall(session.stake, msg, signature); - await sessionRouter.connect(SECOND).openSession(session.stake, msg, signature); - - const sessionData = await sessionRouter.sessions(sessionId); - const createdAt = await getCurrentBlockTime(); - - expect(sessionData).to.deep.equal([ - sessionId, - await resolveAddress(session.user), - await resolveAddress(session.provider), - session.modelId, - session.bidId, - session.stake, - session.pricePerSecond, - getHex(Buffer.from(''), 0), - 0n, - 0n, - createdAt, - sessionData.endsAt, // skipped in this test - 0n, - ]); - }); - - it('should verify balances after opening', async () => { - const srBefore = await MOR.balanceOf(sessionRouter); - const userBefore = await MOR.balanceOf(SECOND); - - const { msg, signature } = await getProviderApproval(PROVIDER, await SECOND.getAddress(), session.bidId); - await sessionRouter.connect(SECOND).openSession(session.stake, msg, signature); - - const srAfter = await MOR.balanceOf(sessionRouter); - const userAfter = await MOR.balanceOf(SECOND); - - expect(srAfter - srBefore).to.equal(session.stake); - expect(userBefore - userAfter).to.equal(session.stake); - }); - - it('should allow opening two sessions in the same block', async () => { - await MOR.transfer(SECOND, session.stake * 2n); - await MOR.connect(SECOND).approve(sessionRouter, session.stake * 2n); - - const apprv1 = await getProviderApproval(PROVIDER, await SECOND.getAddress(), session.bidId); - await setTime(Number(await getCurrentBlockTime()) + 1); - const apprv2 = await getProviderApproval(PROVIDER, await SECOND.getAddress(), session.bidId); - - await ethers.provider.send('evm_setAutomine', [false]); - - await sessionRouter.connect(SECOND).openSession(session.stake, apprv1.msg, apprv1.signature); - await sessionRouter.connect(SECOND).openSession(session.stake, apprv2.msg, apprv2.signature); - - await ethers.provider.send('evm_setAutomine', [true]); - await ethers.provider.send('evm_mine', []); - - const sessionId1 = await sessionRouter.getSessionId(SECOND, PROVIDER, session.stake, 0); - const sessionId2 = await sessionRouter.getSessionId(SECOND, PROVIDER, session.stake, 1); - - expect(sessionId1).not.to.equal(sessionId2); - - const session1 = await sessionRouter.sessions(sessionId1); - const session2 = await sessionRouter.sessions(sessionId2); - - expect(session1.stake).to.equal(session.stake); - expect(session2.stake).to.equal(session.stake); - }); - - it('should partially use remaining staked tokens for the opening session', async () => { - const sessionId = await openSession(session); - await setTime(Number((await getCurrentBlockTime()) + session.durationSeconds / 2n)); - - // close session - const report = await getReport(PROVIDER, sessionId, 10, 10); - await sessionRouter.connect(SECOND).closeSession(report.msg, report.signature); - - await setTime(Number(startOfTheDay(await getCurrentBlockTime()) + DAY)); - - const [avail] = await sessionRouter.withdrawableUserStake(SECOND, 255); - expect(avail > 0).to.be.true; - - // reset allowance - await MOR.connect(SECOND).approve(sessionRouter, 0n); - - const stake = avail / 2n; - - const approval = await getProviderApproval(PROVIDER, await SECOND.getAddress(), session.bidId); - await sessionRouter.connect(SECOND).openSession(stake, approval.msg, approval.signature); - - const [avail2] = await sessionRouter.withdrawableUserStake(SECOND, 255); - expect(avail2).to.be.equal(stake); - }); - - it('should use all remaining staked tokens for the opening session', async () => { - const sessionId = await openSession(session); - await setTime(Number((await getCurrentBlockTime()) + session.durationSeconds / 2n)); - - // close session - const report = await getReport(PROVIDER, sessionId, 10, 10); - await sessionRouter.connect(SECOND).closeSession(report.msg, report.signature); - - await setTime(Number(startOfTheDay(await getCurrentBlockTime()) + DAY)); - - const [avail] = await sessionRouter.withdrawableUserStake(SECOND, 255); - expect(avail > 0).to.be.true; - - // reset allowance - await MOR.connect(SECOND).approve(sessionRouter, 0n); - - const approval = await getProviderApproval(PROVIDER, await SECOND.getAddress(), session.bidId); - await sessionRouter.connect(SECOND).openSession(avail, approval.msg, approval.signature); - - const [avail2] = await sessionRouter.withdrawableUserStake(SECOND, 255); - expect(avail2).to.be.equal(0n); - }); - - it('should use remaining staked tokens and allowance for opening session', async () => { - const sessionId = await openSession(session); - await setTime(Number((await getCurrentBlockTime()) + session.durationSeconds / 2n)); - - // close session - const report = await getReport(PROVIDER, sessionId, 10, 10); - await sessionRouter.connect(SECOND).closeSession(report.msg, report.signature); - - await setTime(Number(startOfTheDay(await getCurrentBlockTime()) + DAY)); - - const [avail] = await sessionRouter.withdrawableUserStake(SECOND, 255); - expect(avail > 0).to.be.true; - - const allowancePart = 1000n; - const balanceBefore = await MOR.balanceOf(SECOND); - - // reset allowance - await MOR.connect(SECOND).approve(sessionRouter, allowancePart); - - const approval = await getProviderApproval(PROVIDER, await SECOND.getAddress(), session.bidId); - await sessionRouter.connect(SECOND).openSession(avail + allowancePart, approval.msg, approval.signature); - - // check all onHold used - const [avail2] = await sessionRouter.withdrawableUserStake(SECOND, 255); - expect(avail2).to.be.equal(0n); - - // check allowance used - const balanceAfter = await MOR.balanceOf(SECOND); - expect(balanceBefore - balanceAfter).to.be.equal(allowancePart); - }); - }); - - describe('negative cases', () => { - it('should error when approval generated for a different user', async () => { - const { msg, signature } = await getProviderApproval(PROVIDER, await THIRD.getAddress(), session.bidId); - - await expect( - sessionRouter.connect(SECOND).openSession(session.stake, msg, signature), - ).to.be.revertedWithCustomError(sessionRouter, 'ApprovedForAnotherUser'); - }); - - it('should error when approval expired', async () => { - const { msg, signature } = await getProviderApproval(PROVIDER, await SECOND.getAddress(), session.bidId); - const ttl = await sessionRouter.SIGNATURE_TTL(); - await setTime(Number((await getCurrentBlockTime()) + ttl) + 1); - - await expect( - sessionRouter.connect(SECOND).openSession(session.stake, msg, signature), - ).to.be.revertedWithCustomError(sessionRouter, 'SignatureExpired'); - }); - - it('should error when bid not exist', async () => { - const { msg, signature } = await getProviderApproval(PROVIDER, await SECOND.getAddress(), randomBytes32()); - await expect( - sessionRouter.connect(SECOND).openSession(session.stake, msg, signature), - ).to.be.revertedWithCustomError(sessionRouter, 'BidNotFound'); - }); - - it('should error when bid is deleted', async () => { - await marketplace.connect(PROVIDER).deleteModelBid(session.bidId); - - const { msg, signature } = await getProviderApproval(PROVIDER, await SECOND.getAddress(), session.bidId); - await expect( - sessionRouter.connect(SECOND).openSession(session.stake, msg, signature), - ).to.be.revertedWithCustomError(sessionRouter, 'BidNotFound'); - }); - - it('should error when signature has invalid length', async () => { - const { msg } = await getProviderApproval(PROVIDER, await SECOND.getAddress(), session.bidId); - - await expect(sessionRouter.connect(SECOND).openSession(session.stake, msg, '0x00')).to.be.revertedWith( - 'ECDSA: invalid signature length', - ); - }); - - it('should error when signature is invalid', async () => { - const { msg } = await getProviderApproval(PROVIDER, await SECOND.getAddress(), session.bidId); - const sig = randomBytes(65); - - await expect(sessionRouter.connect(SECOND).openSession(session.stake, msg, sig)).to.be.reverted; - }); - - it('should error when opening two bids with same signature', async () => { - const { msg, signature } = await getProviderApproval(PROVIDER, await SECOND.getAddress(), session.bidId); - await sessionRouter.connect(SECOND).openSession(session.stake, msg, signature); - - await approveUserFunds(session.stake); - - await expect( - sessionRouter.connect(SECOND).openSession(session.stake, msg, signature), - ).to.be.revertedWithCustomError(sessionRouter, 'DuplicateApproval'); - }); - - it('should not error when opening two bids same time', async () => { - const appr1 = await getProviderApproval(PROVIDER, await SECOND.getAddress(), session.bidId); - await sessionRouter.connect(SECOND).openSession(session.stake, appr1.msg, appr1.signature); - - await approveUserFunds(session.stake); - const appr2 = await getProviderApproval(PROVIDER, await SECOND.getAddress(), session.bidId); - await sessionRouter.connect(SECOND).openSession(session.stake, appr2.msg, appr2.signature); - }); - - it('should error with insufficient allowance', async () => { - const { msg, signature } = await getProviderApproval(PROVIDER, await SECOND.getAddress(), session.bidId); - await expect(sessionRouter.connect(SECOND).openSession(session.stake * 2n, msg, signature)).to.be.revertedWith( - 'ERC20: insufficient allowance', - ); - }); - - it('should error with insufficient allowance', async () => { - const stake = (await MOR.balanceOf(SECOND)) + 1n; - await MOR.connect(SECOND).approve(sessionRouter, stake); - - const { msg, signature } = await getProviderApproval(PROVIDER, await SECOND.getAddress(), session.bidId); - await expect(sessionRouter.connect(SECOND).openSession(stake, msg, signature)).to.be.revertedWith( - 'ERC20: transfer amount exceeds balance', - ); - }); - - it('should error if session time too short', async () => { - const { msg, signature } = await getProviderApproval(PROVIDER, await SECOND.getAddress(), session.bidId); - await expect(sessionRouter.connect(SECOND).openSession(0, msg, signature)).to.be.revertedWithCustomError( - sessionRouter, - 'SessionTooShort', - ); - }); - - it('should error if chainId is invalid', async () => { - const { msg, signature } = await getProviderApproval(PROVIDER, await SECOND.getAddress(), session.bidId, 1n); - await expect(sessionRouter.connect(SECOND).openSession(0, msg, signature)).to.be.revertedWithCustomError( - sessionRouter, - 'WrongChainId', - ); - }); - }); - - describe('verify session end time', () => { - it("session that doesn't span across midnight (1h)", async () => { - const durationSeconds = HOUR; - const stake = await getStake(durationSeconds, session.pricePerSecond); - - const { msg, signature } = await getProviderApproval(PROVIDER, await SECOND.getAddress(), session.bidId); - const sessionId = await sessionRouter.connect(SECOND).openSession.staticCall(stake, msg, signature); - await sessionRouter.connect(SECOND).openSession(stake, msg, signature); - - const sessionData = await sessionRouter.sessions(sessionId); - - expect(sessionData.endsAt).to.equal((await getCurrentBlockTime()) + durationSeconds); - }); - - it('session that spans across midnight (6h) should last 6h', async () => { - const tomorrow9pm = startOfTheDay(await getCurrentBlockTime()) + DAY + 21n * HOUR; - await setTime(Number(tomorrow9pm)); - - // the stake is enough to cover the first day (3h till midnight) and the next day (< 6h) - const durationSeconds = 6n * HOUR; - const stake = await getStake(durationSeconds, session.pricePerSecond); - await approveUserFunds(stake); - - const { msg, signature } = await getProviderApproval(PROVIDER, await SECOND.getAddress(), session.bidId); - const sessionId = await sessionRouter.connect(SECOND).openSession.staticCall(stake, msg, signature); - await sessionRouter.connect(SECOND).openSession(stake, msg, signature); - - const expEndsAt = (await getCurrentBlockTime()) + durationSeconds; - const sessionData = await sessionRouter.sessions(sessionId); - - expect(sessionData.endsAt).closeTo(expEndsAt, 10); - }); - - it('session that lasts multiple days', async () => { - const midnight = startOfTheDay(await getCurrentBlockTime()) + DAY; - await setTime(Number(midnight)); - - // the stake is enough to cover the whole day + extra 1h - const durationSeconds = 25n * HOUR; - const stake = await sessionRouter.stipendToStake( - durationSeconds * session.pricePerSecond, - await getCurrentBlockTime(), - ); - - await approveUserFunds(stake); - - const { msg, signature } = await getProviderApproval(PROVIDER, await SECOND.getAddress(), session.bidId); - const sessionId = await sessionRouter.connect(SECOND).openSession.staticCall(stake, msg, signature); - await sessionRouter.connect(SECOND).openSession(stake, msg, signature); - - const sessionData = await sessionRouter.sessions(sessionId); - const durSeconds = Number(sessionData.endsAt - sessionData.openedAt); - - expect(durSeconds).to.equal(DAY); - }); - }); - }); - - async function approveUserFunds(amount: bigint) { - await MOR.transfer(SECOND, amount); - await MOR.connect(SECOND).approve(sessionRouter, amount); - } - - async function getStake(durationSeconds: bigint, pricePerSecond: bigint): Promise { - const totalCost = pricePerSecond * durationSeconds; - const totalSupply = await sessionRouter.totalMORSupply(await getCurrentBlockTime()); - const todaysBudget = await sessionRouter.getTodaysBudget(await getCurrentBlockTime()); - return (totalCost * totalSupply) / todaysBudget; - } -}); diff --git a/smart-contracts/test/diamond/SessionRouter/readFunctions.test.ts b/smart-contracts/test/diamond/SessionRouter/readFunctions.test.ts deleted file mode 100644 index b201d62c..00000000 --- a/smart-contracts/test/diamond/SessionRouter/readFunctions.test.ts +++ /dev/null @@ -1,341 +0,0 @@ -import { - IBidStorage, - IMarketplace__factory, - IModelRegistry__factory, - IModelStorage, - IProviderRegistry__factory, - IProviderStorage, - ISessionRouter__factory, - LumerinDiamond, - Marketplace, - ModelRegistry, - MorpheusToken, - ProviderRegistry, - SessionRouter, -} from '@ethers-v6'; -import { SignerWithAddress } from '@nomicfoundation/hardhat-ethers/signers'; -import { expect } from 'chai'; -import { Addressable, Fragment } from 'ethers'; -import { ethers } from 'hardhat'; - -import { getHex, randomBytes32, wei } from '@/scripts/utils/utils'; -import { FacetAction } from '@/test/helpers/enums'; -import { getDefaultPools } from '@/test/helpers/pool-helper'; -import { Reverter } from '@/test/helpers/reverter'; -import { getCurrentBlockTime, setTime } from '@/utils/block-helper'; -import { getProviderApproval, getReport } from '@/utils/provider-helper'; -import { HOUR, YEAR } from '@/utils/time'; - -describe('Session router', () => { - const reverter = new Reverter(); - - let OWNER: SignerWithAddress; - let SECOND: SignerWithAddress; - let THIRD: SignerWithAddress; - let PROVIDER: SignerWithAddress; - - let diamond: LumerinDiamond; - let marketplace: Marketplace; - let modelRegistry: ModelRegistry; - let providerRegistry: ProviderRegistry; - let sessionRouter: SessionRouter; - - let MOR: MorpheusToken; - - async function deployProvider(): Promise< - IProviderStorage.ProviderStruct & { - address: Addressable; - } - > { - const provider = { - endpoint: 'localhost:3334', - stake: wei(100), - createdAt: 0n, - limitPeriodEnd: 0n, - limitPeriodEarned: 0n, - isDeleted: false, - address: PROVIDER, - }; - - await MOR.transfer(PROVIDER, provider.stake * 100n); - await MOR.connect(PROVIDER).approve(sessionRouter, provider.stake); - - await providerRegistry.connect(PROVIDER).providerRegister(provider.address, provider.stake, provider.endpoint); - provider.createdAt = await getCurrentBlockTime(); - provider.limitPeriodEnd = provider.createdAt + YEAR; - - return provider; - } - - async function deployModel(): Promise< - IModelStorage.ModelStruct & { - modelId: string; - } - > { - const model = { - modelId: randomBytes32(), - ipfsCID: getHex(Buffer.from('ipfs://ipfsaddress')), - fee: 100, - stake: 100, - owner: OWNER, - name: 'Llama 2.0', - tags: ['llama', 'animal', 'cute'], - createdAt: 0n, - isDeleted: false, - }; - - await MOR.approve(modelRegistry, model.stake); - - await modelRegistry.modelRegister( - model.modelId, - model.ipfsCID, - model.fee, - model.stake, - model.owner, - model.name, - model.tags, - ); - model.createdAt = await getCurrentBlockTime(); - - return model; - } - - async function deployBid(model: any): Promise< - [ - IBidStorage.BidStruct & { - id: string; - modelId: string; - }, - { - durationSeconds: bigint; - totalCost: bigint; - pricePerSecond: bigint; - user: SignerWithAddress; - provider: SignerWithAddress; - modelId: any; - bidId: string; - stake: bigint; - }, - ] - > { - let bid = { - id: '', - modelId: model.modelId, - pricePerSecond: wei(0.0001), - nonce: 0, - createdAt: 0n, - deletedAt: 0, - provider: PROVIDER, - }; - - await MOR.approve(modelRegistry, 10000n * 10n ** 18n); - - bid.id = await marketplace.connect(PROVIDER).postModelBid.staticCall(bid.provider, bid.modelId, bid.pricePerSecond); - await marketplace.connect(PROVIDER).postModelBid(bid.provider, bid.modelId, bid.pricePerSecond); - - bid.createdAt = await getCurrentBlockTime(); - - // generating data for sample session - const durationSeconds = HOUR; - const totalCost = bid.pricePerSecond * durationSeconds; - const totalSupply = await sessionRouter.totalMORSupply(await getCurrentBlockTime()); - const todaysBudget = await sessionRouter.getTodaysBudget(await getCurrentBlockTime()); - - const expectedSession = { - durationSeconds, - totalCost, - pricePerSecond: bid.pricePerSecond, - user: SECOND, - provider: bid.provider, - modelId: bid.modelId, - bidId: bid.id, - stake: (totalCost * totalSupply) / todaysBudget, - }; - - await MOR.transfer(SECOND, expectedSession.stake); - await MOR.connect(SECOND).approve(modelRegistry, expectedSession.stake); - - return [bid, expectedSession]; - } - - before('setup', async () => { - [OWNER, SECOND, THIRD, PROVIDER] = await ethers.getSigners(); - - const LinearDistributionIntervalDecrease = await ethers.getContractFactory('LinearDistributionIntervalDecrease'); - const linearDistributionIntervalDecrease = await LinearDistributionIntervalDecrease.deploy(); - - const [LumerinDiamond, Marketplace, ModelRegistry, ProviderRegistry, SessionRouter, MorpheusToken] = - await Promise.all([ - ethers.getContractFactory('LumerinDiamond'), - ethers.getContractFactory('Marketplace'), - ethers.getContractFactory('ModelRegistry'), - ethers.getContractFactory('ProviderRegistry'), - ethers.getContractFactory('SessionRouter', { - libraries: { - LinearDistributionIntervalDecrease: linearDistributionIntervalDecrease, - }, - }), - ethers.getContractFactory('MorpheusToken'), - ]); - - [diamond, marketplace, modelRegistry, providerRegistry, sessionRouter, MOR] = await Promise.all([ - LumerinDiamond.deploy(), - Marketplace.deploy(), - ModelRegistry.deploy(), - ProviderRegistry.deploy(), - SessionRouter.deploy(), - MorpheusToken.deploy(), - ]); - - await diamond.__LumerinDiamond_init(); - - await diamond['diamondCut((address,uint8,bytes4[])[])']([ - { - facetAddress: marketplace, - action: FacetAction.Add, - functionSelectors: IMarketplace__factory.createInterface() - .fragments.filter(Fragment.isFunction) - .map((f) => f.selector), - }, - { - facetAddress: providerRegistry, - action: FacetAction.Add, - functionSelectors: IProviderRegistry__factory.createInterface() - .fragments.filter(Fragment.isFunction) - .map((f) => f.selector), - }, - { - facetAddress: sessionRouter, - action: FacetAction.Add, - functionSelectors: ISessionRouter__factory.createInterface() - .fragments.filter(Fragment.isFunction) - .map((f) => f.selector), - }, - { - facetAddress: modelRegistry, - action: FacetAction.Add, - functionSelectors: IModelRegistry__factory.createInterface() - .fragments.filter(Fragment.isFunction) - .map((f) => f.selector), - }, - ]); - - marketplace = marketplace.attach(diamond.target) as Marketplace; - providerRegistry = providerRegistry.attach(diamond.target) as ProviderRegistry; - modelRegistry = modelRegistry.attach(diamond.target) as ModelRegistry; - sessionRouter = sessionRouter.attach(diamond.target) as SessionRouter; - - await marketplace.__Marketplace_init(MOR); - await modelRegistry.__ModelRegistry_init(); - await providerRegistry.__ProviderRegistry_init(); - - await sessionRouter.__SessionRouter_init(OWNER, getDefaultPools()); - - await reverter.snapshot(); - }); - - afterEach(reverter.revert); - - describe('Actions', () => { - let provider: IProviderStorage.ProviderStruct; - let model: IModelStorage.ModelStruct & { - modelId: string; - }; - let bid: IBidStorage.BidStruct & { - id: string; - modelId: string; - }; - let session: { - durationSeconds: bigint; - totalCost: bigint; - pricePerSecond: bigint; - user: SignerWithAddress; - provider: SignerWithAddress; - modelId: any; - bidId: string; - stake: bigint; - }; - - beforeEach(async () => { - provider = await deployProvider(); - model = await deployModel(); - [bid, session] = await deployBid(model); - }); - - describe('session read functions', () => { - const exp = { - initialReward: 3456000000000000000000n, - rewardDecrease: 592558728240000000n, - payoutStart: 1707393600n, - decreaseInterval: 86400n, - blockTimeEpochSeconds: BigInt(new Date('2024-05-02T09:19:57Z').getTime()) / 1000n, - balance: 286534931460577320000000n, - }; - - it('should get compute balance equal to one on L1', async () => { - await sessionRouter.setPoolConfig(3n, { - initialReward: exp.initialReward, - rewardDecrease: exp.rewardDecrease, - payoutStart: exp.payoutStart, - decreaseInterval: exp.decreaseInterval, - }); - - const balance = await sessionRouter.getComputeBalance(exp.blockTimeEpochSeconds); - - expect(balance).to.equal(exp.balance); - }); - - it('should revert if caller is not an owner', async () => { - await expect( - sessionRouter.connect(SECOND).setPoolConfig(3, { - initialReward: exp.initialReward, - rewardDecrease: exp.rewardDecrease, - payoutStart: exp.payoutStart, - decreaseInterval: exp.decreaseInterval, - }), - ).to.revertedWithCustomError(diamond, 'OwnableUnauthorizedAccount'); - }); - - it('should revert if pool is not exists', async () => { - await expect( - sessionRouter.setPoolConfig(9999, { - initialReward: exp.initialReward, - rewardDecrease: exp.rewardDecrease, - payoutStart: exp.payoutStart, - decreaseInterval: exp.decreaseInterval, - }), - ).to.revertedWithCustomError(sessionRouter, 'PoolIndexOutOfBounds'); - }); - }); - - describe('getProviderClaimableBalance', () => { - it('should be correct for contract that closed early due to dispute [H-6]', async () => { - // open session - const { msg, signature } = await getProviderApproval(PROVIDER, await SECOND.getAddress(), session.bidId); - const sessionId = await sessionRouter.connect(SECOND).openSession.staticCall(session.stake, msg, signature); - await sessionRouter.connect(SECOND).openSession(session.stake, msg, signature); - - await setTime(Number((await getCurrentBlockTime()) + session.durationSeconds / 2n - 1n)); - - // close session with dispute / user report - const report = await getReport(SECOND, sessionId, 10, 10); - await sessionRouter.connect(SECOND).closeSession(report.msg, report.signature); - - // verify session is closed with dispute - const sessionData = await sessionRouter.sessions(sessionId); - expect(sessionData.closeoutType).to.equal(1n); - - const sessionCost = session.pricePerSecond * (sessionData.closedAt - sessionData.openedAt); - - // immediately after claimable balance should be 0 - const claimable = await sessionRouter.getProviderClaimableBalance(sessionId); - expect(claimable).to.equal(0n); - - // after 24 hours claimable balance should be correct - await setTime(Number((await getCurrentBlockTime()) + 24n * HOUR)); - const claimable2 = await sessionRouter.getProviderClaimableBalance(sessionId); - expect(claimable2).to.equal(sessionCost); - }); - }); - }); -}); diff --git a/smart-contracts/test/diamond/SessionRouter/stats.test.ts b/smart-contracts/test/diamond/SessionRouter/stats.test.ts deleted file mode 100644 index 6e8fe9af..00000000 --- a/smart-contracts/test/diamond/SessionRouter/stats.test.ts +++ /dev/null @@ -1,320 +0,0 @@ -import { - IBidStorage, - IMarketplace__factory, - IModelRegistry__factory, - IModelStorage, - IProviderRegistry__factory, - IProviderStorage, - ISessionRouter__factory, - LumerinDiamond, - Marketplace, - ModelRegistry, - MorpheusToken, - ProviderRegistry, - SessionRouter, -} from '@ethers-v6'; -import { SignerWithAddress } from '@nomicfoundation/hardhat-ethers/signers'; -import { expect } from 'chai'; -import { Addressable, Fragment, resolveAddress } from 'ethers'; -import { ethers } from 'hardhat'; - -import { getHex, randomBytes32, wei } from '@/scripts/utils/utils'; -import { FacetAction } from '@/test/helpers/enums'; -import { getDefaultPools } from '@/test/helpers/pool-helper'; -import { Reverter } from '@/test/helpers/reverter'; -import { getCurrentBlockTime, setTime } from '@/utils/block-helper'; -import { getProviderApproval, getReport } from '@/utils/provider-helper'; -import { HOUR, YEAR } from '@/utils/time'; - -describe('Session router - stats tests', () => { - const reverter = new Reverter(); - - let OWNER: SignerWithAddress; - let SECOND: SignerWithAddress; - let THIRD: SignerWithAddress; - let PROVIDER: SignerWithAddress; - - let diamond: LumerinDiamond; - let marketplace: Marketplace; - let modelRegistry: ModelRegistry; - let providerRegistry: ProviderRegistry; - let sessionRouter: SessionRouter; - - let MOR: MorpheusToken; - - async function deployProvider(): Promise< - IProviderStorage.ProviderStruct & { - address: Addressable; - } - > { - const provider = { - endpoint: 'localhost:3334', - stake: wei(100), - createdAt: 0n, - limitPeriodEnd: 0n, - limitPeriodEarned: 0n, - isDeleted: false, - address: PROVIDER, - }; - - await MOR.transfer(PROVIDER, provider.stake * 100n); - await MOR.connect(PROVIDER).approve(sessionRouter, provider.stake); - - await providerRegistry.connect(PROVIDER).providerRegister(provider.address, provider.stake, provider.endpoint); - provider.createdAt = await getCurrentBlockTime(); - provider.limitPeriodEnd = provider.createdAt + YEAR; - - return provider; - } - - async function deployModel(): Promise< - IModelStorage.ModelStruct & { - modelId: string; - } - > { - const model = { - modelId: randomBytes32(), - ipfsCID: getHex(Buffer.from('ipfs://ipfsaddress')), - fee: 100, - stake: 100, - owner: OWNER, - name: 'Llama 2.0', - tags: ['llama', 'animal', 'cute'], - createdAt: 0n, - isDeleted: false, - }; - - await MOR.approve(modelRegistry, model.stake); - - await modelRegistry.modelRegister( - model.modelId, - model.ipfsCID, - model.fee, - model.stake, - model.owner, - model.name, - model.tags, - ); - model.createdAt = await getCurrentBlockTime(); - - return model; - } - - async function deployBid(model: any): Promise< - [ - IBidStorage.BidStruct & { - id: string; - modelId: string; - }, - { - durationSeconds: bigint; - totalCost: bigint; - pricePerSecond: bigint; - user: SignerWithAddress; - provider: SignerWithAddress; - modelId: any; - bidId: string; - stake: bigint; - }, - ] - > { - let bid = { - id: '', - modelId: model.modelId, - pricePerSecond: wei(0.0001), - nonce: 0, - createdAt: 0n, - deletedAt: 0, - provider: PROVIDER, - }; - - await MOR.approve(modelRegistry, 10000n * 10n ** 18n); - - bid.id = await marketplace.connect(PROVIDER).postModelBid.staticCall(bid.provider, bid.modelId, bid.pricePerSecond); - await marketplace.connect(PROVIDER).postModelBid(bid.provider, bid.modelId, bid.pricePerSecond); - - bid.createdAt = await getCurrentBlockTime(); - - // generating data for sample session - const durationSeconds = HOUR; - const totalCost = bid.pricePerSecond * durationSeconds; - const totalSupply = await sessionRouter.totalMORSupply(await getCurrentBlockTime()); - const todaysBudget = await sessionRouter.getTodaysBudget(await getCurrentBlockTime()); - - const expectedSession = { - durationSeconds, - totalCost, - pricePerSecond: bid.pricePerSecond, - user: SECOND, - provider: bid.provider, - modelId: bid.modelId, - bidId: bid.id, - stake: (totalCost * totalSupply) / todaysBudget, - }; - - await MOR.transfer(SECOND, expectedSession.stake); - await MOR.connect(SECOND).approve(modelRegistry, expectedSession.stake); - - return [bid, expectedSession]; - } - before('setup', async () => { - [OWNER, SECOND, THIRD, PROVIDER] = await ethers.getSigners(); - - const LinearDistributionIntervalDecrease = await ethers.getContractFactory('LinearDistributionIntervalDecrease'); - const linearDistributionIntervalDecrease = await LinearDistributionIntervalDecrease.deploy(); - - const [LumerinDiamond, Marketplace, ModelRegistry, ProviderRegistry, SessionRouter, MorpheusToken] = - await Promise.all([ - ethers.getContractFactory('LumerinDiamond'), - ethers.getContractFactory('Marketplace'), - ethers.getContractFactory('ModelRegistry'), - ethers.getContractFactory('ProviderRegistry'), - ethers.getContractFactory('SessionRouter', { - libraries: { - LinearDistributionIntervalDecrease: linearDistributionIntervalDecrease, - }, - }), - ethers.getContractFactory('MorpheusToken'), - ]); - - [diamond, marketplace, modelRegistry, providerRegistry, sessionRouter, MOR] = await Promise.all([ - LumerinDiamond.deploy(), - Marketplace.deploy(), - ModelRegistry.deploy(), - ProviderRegistry.deploy(), - SessionRouter.deploy(), - MorpheusToken.deploy(), - ]); - - await diamond.__LumerinDiamond_init(); - - await diamond['diamondCut((address,uint8,bytes4[])[])']([ - { - facetAddress: marketplace, - action: FacetAction.Add, - functionSelectors: IMarketplace__factory.createInterface() - .fragments.filter(Fragment.isFunction) - .map((f) => f.selector), - }, - { - facetAddress: providerRegistry, - action: FacetAction.Add, - functionSelectors: IProviderRegistry__factory.createInterface() - .fragments.filter(Fragment.isFunction) - .map((f) => f.selector), - }, - { - facetAddress: sessionRouter, - action: FacetAction.Add, - functionSelectors: ISessionRouter__factory.createInterface() - .fragments.filter(Fragment.isFunction) - .map((f) => f.selector), - }, - { - facetAddress: modelRegistry, - action: FacetAction.Add, - functionSelectors: IModelRegistry__factory.createInterface() - .fragments.filter(Fragment.isFunction) - .map((f) => f.selector), - }, - ]); - - marketplace = marketplace.attach(diamond.target) as Marketplace; - providerRegistry = providerRegistry.attach(diamond.target) as ProviderRegistry; - modelRegistry = modelRegistry.attach(diamond.target) as ModelRegistry; - sessionRouter = sessionRouter.attach(diamond.target) as SessionRouter; - - await marketplace.__Marketplace_init(MOR); - await modelRegistry.__ModelRegistry_init(); - await providerRegistry.__ProviderRegistry_init(); - - await sessionRouter.__SessionRouter_init(OWNER, getDefaultPools()); - - await reverter.snapshot(); - }); - - afterEach(reverter.revert); - - describe('Actions', () => { - let provider: IProviderStorage.ProviderStruct; - let model: IModelStorage.ModelStruct & { - modelId: string; - }; - let bid: IBidStorage.BidStruct & { - id: string; - modelId: string; - }; - let session: { - durationSeconds: bigint; - totalCost: bigint; - pricePerSecond: bigint; - user: SignerWithAddress; - provider: SignerWithAddress; - modelId: any; - bidId: string; - stake: bigint; - }; - - beforeEach(async () => { - provider = await deployProvider(); - model = await deployModel(); - [bid, session] = await deployBid(model); - }); - - it('should update provider-model stats', async () => { - await openCloseSession(session.bidId, HOUR, session.pricePerSecond, 100, 1000, true); - - await openCloseSession(session.bidId, HOUR, session.pricePerSecond, 150, 2000, true); - - const [bidIds, bids, stats] = await sessionRouter.getActiveBidsRatingByModel(session.modelId, 0n, 100); - - expect(bidIds).to.deep.equal([session.bidId]); - expect(bids[0]).to.deep.equal([ - await resolveAddress(bid.provider), - bid.modelId, - bid.pricePerSecond, - bid.nonce, - bid.createdAt, - bid.deletedAt, - ]); - expect(stats[0].successCount).to.equal(2); - expect(stats[0].totalCount).to.equal(2); - expect(Number(stats[0].tpsScaled1000.mean)).to.greaterThan(0); - expect(Number(stats[0].ttftMs.mean)).to.greaterThan(0); - }); - }); - - async function openCloseSession( - bidId: string, - durationSeconds: bigint, - pricePerSecond: bigint, - tps: number, - ttft: number, - success = true, - ) { - // open session - const { msg, signature } = await getProviderApproval(PROVIDER, await SECOND.getAddress(), bidId); - const stake = await getStake(durationSeconds, pricePerSecond); - - await MOR.transfer(SECOND, stake); - await MOR.connect(SECOND).approve(sessionRouter, stake); - const sessionId = await sessionRouter.connect(SECOND).openSession.staticCall(stake, msg, signature); - await sessionRouter.connect(SECOND).openSession(stake, msg, signature); - - // wait till end of the session - await setTime(Number((await getCurrentBlockTime()) + durationSeconds)); - - // close session - const signer = success ? PROVIDER : SECOND; - const report = await getReport(signer, sessionId, tps, ttft); - - await sessionRouter.connect(SECOND).closeSession(report.msg, report.signature); - } - - async function getStake(durationSeconds: bigint, pricePerSecond: bigint): Promise { - const totalCost = pricePerSecond * durationSeconds; - const totalSupply = await sessionRouter.totalMORSupply(await getCurrentBlockTime()); - const todaysBudget = await sessionRouter.getTodaysBudget(await getCurrentBlockTime()); - return (totalCost * totalSupply) / todaysBudget; - } -}); diff --git a/smart-contracts/test/diamond/SessionRouter/userOnHold.test.ts b/smart-contracts/test/diamond/SessionRouter/userOnHold.test.ts deleted file mode 100644 index c00b2a36..00000000 --- a/smart-contracts/test/diamond/SessionRouter/userOnHold.test.ts +++ /dev/null @@ -1,337 +0,0 @@ -import { - IBidStorage, - IMarketplace__factory, - IModelRegistry__factory, - IModelStorage, - IProviderRegistry__factory, - IProviderStorage, - ISessionRouter__factory, - LumerinDiamond, - Marketplace, - ModelRegistry, - MorpheusToken, - ProviderRegistry, - SessionRouter, -} from '@ethers-v6'; -import { SignerWithAddress } from '@nomicfoundation/hardhat-ethers/signers'; -import { expect } from 'chai'; -import { Addressable, Fragment } from 'ethers'; -import { ethers } from 'hardhat'; - -import { MAX_UINT8 } from '@/scripts/utils/constants'; -import { getHex, randomBytes32, wei } from '@/scripts/utils/utils'; -import { FacetAction } from '@/test/helpers/enums'; -import { getDefaultPools } from '@/test/helpers/pool-helper'; -import { Reverter } from '@/test/helpers/reverter'; -import { getCurrentBlockTime, setTime } from '@/utils/block-helper'; -import { getProviderApproval, getReport } from '@/utils/provider-helper'; -import { DAY, HOUR, YEAR } from '@/utils/time'; - -describe('User on hold tests', () => { - const reverter = new Reverter(); - - let OWNER: SignerWithAddress; - let SECOND: SignerWithAddress; - let THIRD: SignerWithAddress; - let PROVIDER: SignerWithAddress; - - let diamond: LumerinDiamond; - let marketplace: Marketplace; - let modelRegistry: ModelRegistry; - let providerRegistry: ProviderRegistry; - let sessionRouter: SessionRouter; - - let MOR: MorpheusToken; - - async function deployProvider(): Promise< - IProviderStorage.ProviderStruct & { - address: Addressable; - } - > { - const provider = { - endpoint: 'localhost:3334', - stake: wei(100), - createdAt: 0n, - limitPeriodEnd: 0n, - limitPeriodEarned: 0n, - isDeleted: false, - address: PROVIDER, - }; - - await MOR.transfer(PROVIDER, provider.stake * 100n); - await MOR.connect(PROVIDER).approve(sessionRouter, provider.stake); - - await providerRegistry.connect(PROVIDER).providerRegister(provider.address, provider.stake, provider.endpoint); - provider.createdAt = await getCurrentBlockTime(); - provider.limitPeriodEnd = provider.createdAt + YEAR; - - return provider; - } - - async function deployModel(): Promise< - IModelStorage.ModelStruct & { - modelId: string; - } - > { - const model = { - modelId: randomBytes32(), - ipfsCID: getHex(Buffer.from('ipfs://ipfsaddress')), - fee: 100, - stake: 100, - owner: OWNER, - name: 'Llama 2.0', - tags: ['llama', 'animal', 'cute'], - createdAt: 0n, - isDeleted: false, - }; - - await MOR.approve(modelRegistry, model.stake); - - await modelRegistry.modelRegister( - model.modelId, - model.ipfsCID, - model.fee, - model.stake, - model.owner, - model.name, - model.tags, - ); - model.createdAt = await getCurrentBlockTime(); - - return model; - } - - async function deployBid(model: any): Promise< - [ - IBidStorage.BidStruct & { - id: string; - modelId: string; - }, - { - durationSeconds: bigint; - totalCost: bigint; - pricePerSecond: bigint; - user: SignerWithAddress; - provider: SignerWithAddress; - modelId: any; - bidId: string; - stake: bigint; - }, - ] - > { - let bid = { - id: '', - modelId: model.modelId, - pricePerSecond: wei(0.0001), - nonce: 0, - createdAt: 0n, - deletedAt: 0, - provider: PROVIDER, - }; - - await MOR.approve(modelRegistry, 10000n * 10n ** 18n); - - bid.id = await marketplace.connect(PROVIDER).postModelBid.staticCall(bid.provider, bid.modelId, bid.pricePerSecond); - await marketplace.connect(PROVIDER).postModelBid(bid.provider, bid.modelId, bid.pricePerSecond); - - bid.createdAt = await getCurrentBlockTime(); - - // generating data for sample session - const durationSeconds = HOUR; - const totalCost = bid.pricePerSecond * durationSeconds; - const totalSupply = await sessionRouter.totalMORSupply(await getCurrentBlockTime()); - const todaysBudget = await sessionRouter.getTodaysBudget(await getCurrentBlockTime()); - - const expectedSession = { - durationSeconds, - totalCost, - pricePerSecond: bid.pricePerSecond, - user: SECOND, - provider: bid.provider, - modelId: bid.modelId, - bidId: bid.id, - stake: (totalCost * totalSupply) / todaysBudget, - }; - - await MOR.transfer(SECOND, expectedSession.stake); - await MOR.connect(SECOND).approve(modelRegistry, expectedSession.stake); - - return [bid, expectedSession]; - } - - async function openSession(session: any) { - // open session - const { msg, signature } = await getProviderApproval(PROVIDER, await SECOND.getAddress(), session.bidId); - const sessionId = await sessionRouter.connect(SECOND).openSession.staticCall(session.stake, msg, signature); - await sessionRouter.connect(SECOND).openSession(session.stake, msg, signature); - - return sessionId; - } - - async function openEarlyCloseSession(session: any, sessionId: string) { - await setTime(Number(await getCurrentBlockTime()) + Number(session.durationSeconds) / 2); - - // close session - const report = await getReport(PROVIDER, sessionId, 10, 10); - await sessionRouter.connect(SECOND).closeSession(report.msg, report.signature); - - return session.stake / 2n; - } - before('setup', async () => { - [OWNER, SECOND, THIRD, PROVIDER] = await ethers.getSigners(); - - const LinearDistributionIntervalDecrease = await ethers.getContractFactory('LinearDistributionIntervalDecrease'); - const linearDistributionIntervalDecrease = await LinearDistributionIntervalDecrease.deploy(); - - const [LumerinDiamond, Marketplace, ModelRegistry, ProviderRegistry, SessionRouter, MorpheusToken] = - await Promise.all([ - ethers.getContractFactory('LumerinDiamond'), - ethers.getContractFactory('Marketplace'), - ethers.getContractFactory('ModelRegistry'), - ethers.getContractFactory('ProviderRegistry'), - ethers.getContractFactory('SessionRouter', { - libraries: { - LinearDistributionIntervalDecrease: linearDistributionIntervalDecrease, - }, - }), - ethers.getContractFactory('MorpheusToken'), - ]); - - [diamond, marketplace, modelRegistry, providerRegistry, sessionRouter, MOR] = await Promise.all([ - LumerinDiamond.deploy(), - Marketplace.deploy(), - ModelRegistry.deploy(), - ProviderRegistry.deploy(), - SessionRouter.deploy(), - MorpheusToken.deploy(), - ]); - - await diamond.__LumerinDiamond_init(); - - await diamond['diamondCut((address,uint8,bytes4[])[])']([ - { - facetAddress: marketplace, - action: FacetAction.Add, - functionSelectors: IMarketplace__factory.createInterface() - .fragments.filter(Fragment.isFunction) - .map((f) => f.selector), - }, - { - facetAddress: providerRegistry, - action: FacetAction.Add, - functionSelectors: IProviderRegistry__factory.createInterface() - .fragments.filter(Fragment.isFunction) - .map((f) => f.selector), - }, - { - facetAddress: sessionRouter, - action: FacetAction.Add, - functionSelectors: ISessionRouter__factory.createInterface() - .fragments.filter(Fragment.isFunction) - .map((f) => f.selector), - }, - { - facetAddress: modelRegistry, - action: FacetAction.Add, - functionSelectors: IModelRegistry__factory.createInterface() - .fragments.filter(Fragment.isFunction) - .map((f) => f.selector), - }, - ]); - - marketplace = marketplace.attach(diamond.target) as Marketplace; - providerRegistry = providerRegistry.attach(diamond.target) as ProviderRegistry; - modelRegistry = modelRegistry.attach(diamond.target) as ModelRegistry; - sessionRouter = sessionRouter.attach(diamond.target) as SessionRouter; - - await marketplace.__Marketplace_init(MOR); - await modelRegistry.__ModelRegistry_init(); - await providerRegistry.__ProviderRegistry_init(); - - await sessionRouter.__SessionRouter_init(OWNER, getDefaultPools()); - - await reverter.snapshot(); - }); - - afterEach(reverter.revert); - - describe('Actions', () => { - let provider: IProviderStorage.ProviderStruct; - let model: IModelStorage.ModelStruct & { - modelId: string; - }; - let bid: IBidStorage.BidStruct & { - id: string; - modelId: string; - }; - let session: { - durationSeconds: bigint; - totalCost: bigint; - pricePerSecond: bigint; - user: SignerWithAddress; - provider: SignerWithAddress; - modelId: any; - bidId: string; - stake: bigint; - }; - let sessionId: string; - let expectedOnHold: bigint; - - beforeEach(async () => { - provider = await deployProvider(); - model = await deployModel(); - [bid, session] = await deployBid(model); - sessionId = await openSession(session); - expectedOnHold = await openEarlyCloseSession(session, sessionId); - }); - - it('user stake should be locked right after closeout', async () => { - // right after closeout - const [available, onHold] = await sessionRouter.withdrawableUserStake(SECOND, MAX_UINT8); - expect(available).to.equal(0n); - expect(onHold).to.closeTo(expectedOnHold, BigInt(0.01 * Number(expectedOnHold))); - }); - - it('user stake should be locked before the next day', async () => { - // before next day - await setTime(startOfTomorrow(Number(await getCurrentBlockTime())) - Number(HOUR)); - const [available3, onHold3] = await sessionRouter.withdrawableUserStake(SECOND, Number(MAX_UINT8)); - expect(available3).to.equal(0n); - expect(onHold3).to.closeTo(expectedOnHold, BigInt(0.01 * Number(expectedOnHold))); - }); - - it('user stake should be available on the next day and withdrawable', async () => { - await setTime(startOfTomorrow(Number(await getCurrentBlockTime()))); - const [available2, onHold2] = await sessionRouter.withdrawableUserStake(SECOND, Number(MAX_UINT8)); - expect(available2).to.closeTo(expectedOnHold, BigInt(0.01 * Number(expectedOnHold))); - expect(onHold2).to.equal(0n); - - const balanceBefore = await MOR.balanceOf(SECOND); - await sessionRouter.connect(SECOND).withdrawUserStake(available2, Number(MAX_UINT8)); - const balanceAfter = await MOR.balanceOf(SECOND); - const balanceDelta = balanceAfter - balanceBefore; - expect(balanceDelta).to.closeTo(expectedOnHold, BigInt(0.01 * Number(expectedOnHold))); - }); - - it("user shouldn't be able to withdraw more than there is available stake", async () => { - await setTime(startOfTomorrow(Number(await getCurrentBlockTime()))); - const [available2] = await sessionRouter.withdrawableUserStake(SECOND, Number(MAX_UINT8)); - - await expect( - sessionRouter.connect(SECOND).withdrawUserStake(available2 * 2n, Number(MAX_UINT8)), - ).to.be.revertedWithCustomError(sessionRouter, 'NotEnoughWithdrawableBalance'); - }); - - it('should revert if amount to withdraw is 0', async () => { - await expect(sessionRouter.connect(SECOND).withdrawUserStake(0, Number(MAX_UINT8))).to.be.revertedWithCustomError( - sessionRouter, - 'AmountToWithdrawIsZero', - ); - }); - }); -}); - -function startOfTomorrow(epochSeconds: number): number { - const startOfToday = epochSeconds - (epochSeconds % Number(DAY)); - return startOfToday + Number(DAY); -} diff --git a/smart-contracts/test/diamond/SessionRouter/writeFunctions.test.ts b/smart-contracts/test/diamond/SessionRouter/writeFunctions.test.ts deleted file mode 100644 index cb3cbdc5..00000000 --- a/smart-contracts/test/diamond/SessionRouter/writeFunctions.test.ts +++ /dev/null @@ -1,348 +0,0 @@ -import { - IBidStorage, - IMarketplace__factory, - IModelRegistry__factory, - IModelStorage, - IProviderRegistry__factory, - IProviderStorage, - ISessionRouter__factory, - LumerinDiamond, - Marketplace, - ModelRegistry, - MorpheusToken, - ProviderRegistry, - SessionRouter, -} from '@ethers-v6'; -import { SignerWithAddress } from '@nomicfoundation/hardhat-ethers/signers'; -import { expect } from 'chai'; -import { Addressable, Fragment } from 'ethers'; -import { ethers } from 'hardhat'; - -import { ZERO_ADDR } from '@/scripts/utils/constants'; -import { getHex, randomBytes32, wei } from '@/scripts/utils/utils'; -import { FacetAction } from '@/test/helpers/enums'; -import { getDefaultPools } from '@/test/helpers/pool-helper'; -import { Reverter } from '@/test/helpers/reverter'; -import { getCurrentBlockTime, setTime } from '@/utils/block-helper'; -import { getProviderApproval, getReport } from '@/utils/provider-helper'; -import { HOUR, YEAR } from '@/utils/time'; - -describe('Session router', () => { - const reverter = new Reverter(); - - let OWNER: SignerWithAddress; - let SECOND: SignerWithAddress; - let THIRD: SignerWithAddress; - let PROVIDER: SignerWithAddress; - - let diamond: LumerinDiamond; - let marketplace: Marketplace; - let modelRegistry: ModelRegistry; - let providerRegistry: ProviderRegistry; - let sessionRouter: SessionRouter; - - let MOR: MorpheusToken; - - async function deployProvider(): Promise< - IProviderStorage.ProviderStruct & { - address: Addressable; - } - > { - const provider = { - endpoint: 'localhost:3334', - stake: wei(100), - createdAt: 0n, - limitPeriodEnd: 0n, - limitPeriodEarned: 0n, - isDeleted: false, - address: PROVIDER, - }; - - await MOR.transfer(PROVIDER, provider.stake * 100n); - await MOR.connect(PROVIDER).approve(sessionRouter, provider.stake); - - await providerRegistry.connect(PROVIDER).providerRegister(provider.address, provider.stake, provider.endpoint); - provider.createdAt = await getCurrentBlockTime(); - provider.limitPeriodEnd = provider.createdAt + YEAR; - - return provider; - } - - async function deployModel(): Promise< - IModelStorage.ModelStruct & { - modelId: string; - } - > { - const model = { - modelId: randomBytes32(), - ipfsCID: getHex(Buffer.from('ipfs://ipfsaddress')), - fee: 100, - stake: 100, - owner: OWNER, - name: 'Llama 2.0', - tags: ['llama', 'animal', 'cute'], - createdAt: 0n, - isDeleted: false, - }; - - await MOR.approve(modelRegistry, model.stake); - - await modelRegistry.modelRegister( - model.modelId, - model.ipfsCID, - model.fee, - model.stake, - model.owner, - model.name, - model.tags, - ); - model.createdAt = await getCurrentBlockTime(); - - return model; - } - - async function deployBid(model: any): Promise< - [ - IBidStorage.BidStruct & { - id: string; - modelId: string; - }, - { - durationSeconds: bigint; - totalCost: bigint; - pricePerSecond: bigint; - user: SignerWithAddress; - provider: SignerWithAddress; - modelId: any; - bidId: string; - stake: bigint; - }, - ] - > { - let bid = { - id: '', - modelId: model.modelId, - pricePerSecond: wei(0.0001), - nonce: 0, - createdAt: 0n, - deletedAt: 0, - provider: PROVIDER, - }; - - await MOR.approve(modelRegistry, 10000n * 10n ** 18n); - - bid.id = await marketplace.connect(PROVIDER).postModelBid.staticCall(bid.provider, bid.modelId, bid.pricePerSecond); - await marketplace.connect(PROVIDER).postModelBid(bid.provider, bid.modelId, bid.pricePerSecond); - - bid.createdAt = await getCurrentBlockTime(); - - // generating data for sample session - const durationSeconds = HOUR; - const totalCost = bid.pricePerSecond * durationSeconds; - const totalSupply = await sessionRouter.totalMORSupply(await getCurrentBlockTime()); - const todaysBudget = await sessionRouter.getTodaysBudget(await getCurrentBlockTime()); - - const expectedSession = { - durationSeconds, - totalCost, - pricePerSecond: bid.pricePerSecond, - user: SECOND, - provider: bid.provider, - modelId: bid.modelId, - bidId: bid.id, - stake: (totalCost * totalSupply) / todaysBudget, - }; - - await MOR.transfer(SECOND, expectedSession.stake); - await MOR.connect(SECOND).approve(modelRegistry, expectedSession.stake); - - return [bid, expectedSession]; - } - - async function openSession(session: any) { - // open session - const { msg, signature } = await getProviderApproval(PROVIDER, await SECOND.getAddress(), session.bidId); - const sessionId = await sessionRouter.connect(SECOND).openSession.staticCall(session.stake, msg, signature); - await sessionRouter.connect(SECOND).openSession(session.stake, msg, signature); - - return sessionId; - } - - before('setup', async () => { - [OWNER, SECOND, THIRD, PROVIDER] = await ethers.getSigners(); - - const LinearDistributionIntervalDecrease = await ethers.getContractFactory('LinearDistributionIntervalDecrease'); - const linearDistributionIntervalDecrease = await LinearDistributionIntervalDecrease.deploy(); - - const [LumerinDiamond, Marketplace, ModelRegistry, ProviderRegistry, SessionRouter, MorpheusToken] = - await Promise.all([ - ethers.getContractFactory('LumerinDiamond'), - ethers.getContractFactory('Marketplace'), - ethers.getContractFactory('ModelRegistry'), - ethers.getContractFactory('ProviderRegistry'), - ethers.getContractFactory('SessionRouter', { - libraries: { - LinearDistributionIntervalDecrease: linearDistributionIntervalDecrease, - }, - }), - ethers.getContractFactory('MorpheusToken'), - ]); - - [diamond, marketplace, modelRegistry, providerRegistry, sessionRouter, MOR] = await Promise.all([ - LumerinDiamond.deploy(), - Marketplace.deploy(), - ModelRegistry.deploy(), - ProviderRegistry.deploy(), - SessionRouter.deploy(), - MorpheusToken.deploy(), - ]); - - await diamond.__LumerinDiamond_init(); - - await diamond['diamondCut((address,uint8,bytes4[])[])']([ - { - facetAddress: marketplace, - action: FacetAction.Add, - functionSelectors: IMarketplace__factory.createInterface() - .fragments.filter(Fragment.isFunction) - .map((f) => f.selector), - }, - { - facetAddress: providerRegistry, - action: FacetAction.Add, - functionSelectors: IProviderRegistry__factory.createInterface() - .fragments.filter(Fragment.isFunction) - .map((f) => f.selector), - }, - { - facetAddress: sessionRouter, - action: FacetAction.Add, - functionSelectors: ISessionRouter__factory.createInterface() - .fragments.filter(Fragment.isFunction) - .map((f) => f.selector), - }, - { - facetAddress: modelRegistry, - action: FacetAction.Add, - functionSelectors: IModelRegistry__factory.createInterface() - .fragments.filter(Fragment.isFunction) - .map((f) => f.selector), - }, - ]); - - marketplace = marketplace.attach(diamond.target) as Marketplace; - providerRegistry = providerRegistry.attach(diamond.target) as ProviderRegistry; - modelRegistry = modelRegistry.attach(diamond.target) as ModelRegistry; - sessionRouter = sessionRouter.attach(diamond.target) as SessionRouter; - - await marketplace.__Marketplace_init(MOR); - await modelRegistry.__ModelRegistry_init(); - await providerRegistry.__ProviderRegistry_init(); - - await sessionRouter.__SessionRouter_init(OWNER, getDefaultPools()); - - await reverter.snapshot(); - }); - - afterEach(reverter.revert); - - describe('Diamond functionality', () => { - describe('#__SessionRouter_init', () => { - it('should set correct data after creation', async () => { - expect(await sessionRouter.getFundingAccount()).to.eq(await OWNER.getAddress()); - - const pools = await sessionRouter.pools(); - for (let i = 0; i < pools.length; i++) { - const pool = getDefaultPools()[i]; - expect(pools[i].payoutStart).to.eq(pool.payoutStart); - expect(pools[i].decreaseInterval).to.eq(pool.decreaseInterval); - expect(pools[i].initialReward).to.eq(pool.initialReward); - expect(pools[i].rewardDecrease).to.eq(pool.rewardDecrease); - } - }); - it('should revert if try to call init function twice', async () => { - const reason = 'Initializable: contract is already initialized'; - - await expect(sessionRouter.__SessionRouter_init(OWNER, getDefaultPools())).to.be.rejectedWith(reason); - }); - }); - }); - - describe('session write functions', () => { - let provider: IProviderStorage.ProviderStruct; - let model: IModelStorage.ModelStruct & { - modelId: string; - }; - let bid: IBidStorage.BidStruct & { - id: string; - modelId: string; - }; - let session: { - durationSeconds: bigint; - totalCost: bigint; - pricePerSecond: bigint; - user: SignerWithAddress; - provider: SignerWithAddress; - modelId: any; - bidId: string; - stake: bigint; - }; - let sessionId: string; - - beforeEach(async () => { - provider = await deployProvider(); - model = await deployModel(); - [bid, session] = await deployBid(model); - sessionId = await openSession(session); - }); - - it('should block erase if session not closed', async () => { - // check history - const sessionIds = await sessionRouter.getSessionsByUser(SECOND, 0, 10); - expect(sessionIds.length).to.equal(1); - expect((await sessionRouter.sessions(sessionIds[0])).id).to.equal(sessionId); - - // erase history fails - await expect(sessionRouter.connect(SECOND).deleteHistory(sessionId)).to.be.revertedWithCustomError( - sessionRouter, - 'SessionNotClosed', - ); - }); - - it('should block erase if caller is not an owner', async () => { - await expect(sessionRouter.connect(THIRD).deleteHistory(sessionId)).to.be.revertedWithCustomError( - sessionRouter, - 'NotOwnerOrUser', - ); - }); - - it('erase history', async () => { - // wait for half of the session - await setTime(Number((await getCurrentBlockTime()) + session.durationSeconds / 2n)); - - // close session - const report = await getReport(PROVIDER, sessionId, 10, 10); - await sessionRouter.connect(SECOND).closeSession(report.msg, report.signature); - - // check history - const sessionIds = await sessionRouter.getSessionsByUser(SECOND, 0, 10); - expect(sessionIds.length).to.equal(1); - expect((await sessionRouter.sessions(sessionIds[0])).id).to.equal(sessionId); - expect((await sessionRouter.sessions(sessionIds[0])).user).to.equal(await SECOND.getAddress()); - - // erase history - await sessionRouter.connect(SECOND).deleteHistory(sessionId); - - const sessionData = await sessionRouter.sessions(sessionId); - expect(sessionData.user).to.equal(ZERO_ADDR); - - // TODO: fix history so user is not exposed using getSessionsByUser - // const sessionIds2 = await sessionRouter.getSessionsByUser([ - // user.account.address, - // 0n, - // 10, - // ]); - // expect(sessionIds2.length).to.equal(0); - }); - }); -}); diff --git a/smart-contracts/test/diamond/facets/Marketplace.test.ts b/smart-contracts/test/diamond/facets/Marketplace.test.ts new file mode 100644 index 00000000..aa28ee6e --- /dev/null +++ b/smart-contracts/test/diamond/facets/Marketplace.test.ts @@ -0,0 +1,308 @@ +import { 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 { + deployFacetMarketplace, + deployFacetModelRegistry, + deployFacetProviderRegistry, + deployFacetSessionRouter, + deployLumerinDiamond, + deployMORToken, +} from '@/test/helpers/deployers'; +import { Reverter } from '@/test/helpers/reverter'; +import { setNextTime } from '@/utils/block-helper'; + +describe('Marketplace', () => { + const reverter = new Reverter(); + + let OWNER: SignerWithAddress; + let SECOND: SignerWithAddress; + let PROVIDER: SignerWithAddress; + + let diamond: LumerinDiamond; + let marketplace: Marketplace; + let modelRegistry: ModelRegistry; + let providerRegistry: ProviderRegistry; + + let token: MorpheusToken; + + const modelId1 = getHex(Buffer.from('1')); + const modelId2 = getHex(Buffer.from('2')); + + before(async () => { + [OWNER, SECOND, PROVIDER] = await ethers.getSigners(); + + [diamond, token] = await Promise.all([deployLumerinDiamond(), deployMORToken()]); + + [providerRegistry, modelRegistry, , marketplace] = await Promise.all([ + deployFacetProviderRegistry(diamond), + deployFacetModelRegistry(diamond), + deployFacetSessionRouter(diamond, OWNER), + deployFacetMarketplace(diamond, token, wei(0.0001), wei(900)), + ]); + + await token.transfer(SECOND, wei(1000)); + await token.connect(SECOND).approve(providerRegistry, wei(1000)); + await token.approve(providerRegistry, wei(1000)); + await token.connect(SECOND).approve(modelRegistry, wei(1000)); + await token.approve(modelRegistry, wei(1000)); + await token.connect(SECOND).approve(marketplace, wei(1000)); + 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 reverter.snapshot(); + }); + + afterEach(reverter.revert); + + describe('#__Marketplace_init', () => { + it('should set correct data after creation', async () => { + expect(await marketplace.getToken()).to.eq(await token.getAddress()); + }); + it('should revert if try to call init function twice', async () => { + await expect(marketplace.__Marketplace_init(token, wei(0.001), wei(0.002))).to.be.rejectedWith( + 'Initializable: contract is already initialized', + ); + }); + }); + + describe('#setMarketplaceBidFee', async () => { + it('should set marketplace bid fee', async () => { + const fee = wei(100); + + await expect(marketplace.setMarketplaceBidFee(fee)).to.emit(marketplace, 'MaretplaceFeeUpdated').withArgs(fee); + + expect(await marketplace.getBidFee()).eq(fee); + }); + it('should throw error when caller is not an owner', async () => { + await expect(marketplace.connect(SECOND).setMarketplaceBidFee(100)).to.be.revertedWithCustomError( + diamond, + 'OwnableUnauthorizedAccount', + ); + }); + }); + + describe('#setMinMaxBidPricePerSecond', async () => { + it('should set min and max price per second', async () => { + await expect(marketplace.setMinMaxBidPricePerSecond(wei(1), wei(2))) + .to.emit(marketplace, 'MarketplaceBidMinMaxPriceUpdated') + .withArgs(wei(1), wei(2)); + + expect(await marketplace.getMinMaxBidPricePerSecond()).deep.eq([wei(1), wei(2)]); + }); + it('should throw error when caller is not an owner', async () => { + await expect( + marketplace.connect(SECOND).setMinMaxBidPricePerSecond(wei(1), wei(2)), + ).to.be.revertedWithCustomError(diamond, 'OwnableUnauthorizedAccount'); + }); + it('should throw error when min price is zero', async () => { + await expect(marketplace.setMinMaxBidPricePerSecond(wei(0), wei(2))).to.be.revertedWithCustomError( + marketplace, + 'MarketplaceBidMinPricePerSecondIsZero', + ); + }); + it('should throw error when min price greater then max price', async () => { + await expect(marketplace.setMinMaxBidPricePerSecond(wei(3), wei(2))).to.be.revertedWithCustomError( + marketplace, + 'MarketplaceBidMinPricePerSecondIsInvalid', + ); + }); + }); + + describe('#postModelBid', async () => { + beforeEach(async () => { + await marketplace.setMarketplaceBidFee(wei(1)); + }); + + it('should post a model bid', async () => { + await setNextTime(300); + await marketplace.connect(SECOND).postModelBid(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]); + 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]); + }); + 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)); + + const bidId1 = await marketplace.getBidId(SECOND, modelId1, 0); + let data = await marketplace.getBid(bidId1); + 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); + + const bidId2 = await marketplace.getBidId(SECOND, modelId2, 0); + data = await marketplace.getBid(bidId2); + expect(data.provider).to.eq(SECOND); + expect(data.modelId).to.eq(modelId2); + expect(data.pricePerSecond).to.eq(wei(20)); + expect(data.nonce).to.eq(0); + expect(data.createdAt).to.eq(301); + expect(data.deletedAt).to.eq(0); + + 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]); + }); + 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)); + + const bidId1 = await marketplace.getBidId(SECOND, modelId1, 0); + let data = await marketplace.getBid(bidId1); + expect(data.deletedAt).to.eq(301); + + const bidId2 = await marketplace.getBidId(SECOND, modelId1, 1); + data = await marketplace.getBid(bidId2); + expect(data.provider).to.eq(SECOND); + expect(data.modelId).to.eq(modelId1); + expect(data.pricePerSecond).to.eq(wei(20)); + expect(data.nonce).to.eq(1); + expect(data.createdAt).to.eq(301); + expect(data.deletedAt).to.eq(0); + + 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]); + }); + 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)); + + const bidId1 = await marketplace.getBidId(SECOND, modelId1, 0); + await marketplace.connect(SECOND).deleteModelBid(bidId1); + await marketplace.connect(SECOND).postModelBid(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( + 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( + 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( + marketplace, + 'MarketplaceBidPricePerSecondInvalid', + ); + }); + }); + + describe('#deleteModelBid', async () => { + it('should delete a bid', async () => { + await setNextTime(300); + await marketplace.connect(SECOND).postModelBid(modelId1, wei(10)); + + const bidId1 = await marketplace.getBidId(SECOND, modelId1, 0); + await marketplace.connect(SECOND).deleteModelBid(bidId1); + + const data = await marketplace.getBid(bidId1); + expect(data.deletedAt).to.eq(301); + 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)); + + const bidId1 = await marketplace.getBidId(SECOND, modelId1, 0); + await expect(marketplace.connect(PROVIDER).deleteModelBid(bidId1)).to.be.revertedWithCustomError( + diamond, + 'OwnableUnauthorizedAccount', + ); + }); + it('should throw error when bid already deleted', async () => { + await marketplace.connect(SECOND).postModelBid(modelId1, wei(10)); + + const bidId1 = await marketplace.getBidId(SECOND, modelId1, 0); + await marketplace.connect(SECOND).deleteModelBid(bidId1); + await expect(marketplace.connect(SECOND).deleteModelBid(bidId1)).to.be.revertedWithCustomError( + marketplace, + 'MarketplaceActiveBidNotFound', + ); + }); + }); + + describe('#withdraw', async () => { + beforeEach(async () => { + await marketplace.setMarketplaceBidFee(wei(1)); + }); + + it('should withdraw fee, all fee balance', async () => { + await marketplace.connect(SECOND).postModelBid(modelId1, wei(10)); + expect(await marketplace.getFeeBalance()).to.eq(wei(1)); + + await marketplace.withdrawFee(PROVIDER, wei(999)); + + expect(await marketplace.getFeeBalance()).to.eq(wei(0)); + expect(await token.balanceOf(marketplace)).to.eq(wei(300)); + 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)); + expect(await marketplace.getFeeBalance()).to.eq(wei(1)); + + await marketplace.withdrawFee(PROVIDER, wei(0.1)); + + expect(await marketplace.getFeeBalance()).to.eq(wei(0.9)); + expect(await token.balanceOf(marketplace)).to.eq(wei(300.9)); + expect(await token.balanceOf(PROVIDER)).to.eq(wei(0.1)); + }); + it('should throw error when caller is not an owner', async () => { + await expect(marketplace.connect(SECOND).withdrawFee(PROVIDER, wei(1))).to.be.revertedWithCustomError( + diamond, + 'OwnableUnauthorizedAccount', + ); + }); + it('should throw error when withdraw amount is zero', async () => { + await expect(marketplace.withdrawFee(PROVIDER, wei(1))).to.be.revertedWithCustomError( + marketplace, + 'MarketplaceFeeAmountIsZero', + ); + }); + }); +}); + +// npm run generate-types && npx hardhat test "test/diamond/facets/Marketplace.test.ts" +// npx hardhat coverage --solcoverjs ./.solcover.ts --testfiles "test/diamond/facets/Marketplace.test.ts" diff --git a/smart-contracts/test/diamond/facets/ModelRegistry.test.ts b/smart-contracts/test/diamond/facets/ModelRegistry.test.ts new file mode 100644 index 00000000..04bddbc0 --- /dev/null +++ b/smart-contracts/test/diamond/facets/ModelRegistry.test.ts @@ -0,0 +1,228 @@ +import { 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 { + deployFacetMarketplace, + deployFacetModelRegistry, + deployFacetProviderRegistry, + deployFacetSessionRouter, + deployLumerinDiamond, + deployMORToken, +} from '@/test/helpers/deployers'; +import { Reverter } from '@/test/helpers/reverter'; +import { setNextTime } from '@/utils/block-helper'; + +describe('ModelRegistry', () => { + const reverter = new Reverter(); + + let OWNER: SignerWithAddress; + let SECOND: SignerWithAddress; + + let diamond: LumerinDiamond; + let providerRegistry: ProviderRegistry; + let modelRegistry: ModelRegistry; + let marketplace: Marketplace; + + let token: MorpheusToken; + + const modelId = getHex(Buffer.from('1')); + const ipfsCID = getHex(Buffer.from('ipfs://ipfsaddress')); + + before(async () => { + [OWNER, SECOND] = await ethers.getSigners(); + + [diamond, token] = await Promise.all([deployLumerinDiamond(), deployMORToken()]); + + [providerRegistry, modelRegistry, , marketplace] = await Promise.all([ + deployFacetProviderRegistry(diamond), + deployFacetModelRegistry(diamond), + deployFacetSessionRouter(diamond, OWNER), + deployFacetMarketplace(diamond, token, wei(0.0001), wei(900)), + ]); + + await token.transfer(SECOND, wei(1000)); + await token.connect(SECOND).approve(providerRegistry, wei(1000)); + await token.approve(providerRegistry, wei(1000)); + await token.connect(SECOND).approve(modelRegistry, wei(1000)); + await token.approve(modelRegistry, wei(1000)); + await token.connect(SECOND).approve(marketplace, wei(1000)); + await token.approve(marketplace, wei(1000)); + + await reverter.snapshot(); + }); + + afterEach(reverter.revert); + + describe('#__ModelRegistry_init', () => { + it('should revert if try to call init function twice', async () => { + await expect(modelRegistry.__ModelRegistry_init()).to.be.rejectedWith( + 'Initializable: contract is already initialized', + ); + }); + }); + + describe('#modelSetMinStake', async () => { + it('should set min stake', async () => { + const minStake = wei(100); + + await expect(modelRegistry.modelSetMinStake(minStake)) + .to.emit(modelRegistry, 'ModelMinimumStakeUpdated') + .withArgs(minStake); + + expect(await modelRegistry.getModelMinimumStake()).eq(minStake); + }); + + it('should throw error when caller is not an owner', async () => { + await expect(modelRegistry.connect(SECOND).modelSetMinStake(100)).to.be.revertedWithCustomError( + diamond, + 'OwnableUnauthorizedAccount', + ); + }); + }); + + describe('#getModelIds', async () => { + it('should set min stake', async () => { + await setNextTime(300); + await modelRegistry + .connect(SECOND) + .modelRegister(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']); + + const modelIds = await modelRegistry.getModelIds(0, 10); + expect(modelIds.length).to.eq(2); + }); + + it('should throw error when caller is not an owner', async () => { + await expect(modelRegistry.connect(SECOND).modelSetMinStake(100)).to.be.revertedWithCustomError( + diamond, + 'OwnableUnauthorizedAccount', + ); + }); + }); + + 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']); + + 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]); + + await modelRegistry.connect(SECOND).modelRegister(modelId, 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']); + + const data = await modelRegistry.getModel(modelId); + expect(data.ipfsCID).to.eq(ipfsCID2); + expect(data.fee).to.eq(1); + expect(data.stake).to.eq(wei(400)); + expect(data.owner).to.eq(SECOND); + expect(data.name).to.eq('name2'); + expect(data.tags).deep.eq(['tag_1', 'tag_2']); + 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(400)); + expect(await token.balanceOf(SECOND)).to.eq(wei(600)); + }); + 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).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']); + + data = await modelRegistry.getModel(modelId); + expect(data.ipfsCID).to.eq(ipfsCID); + expect(data.fee).to.eq(4); + expect(data.stake).to.eq(wei(200)); + expect(data.owner).to.eq(SECOND); + expect(data.name).to.eq('name3'); + expect(data.tags).deep.eq(['tag_3']); + expect(data.createdAt).to.eq(300); + 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']), + ).to.be.revertedWithCustomError(modelRegistry, 'ModelStakeTooLow'); + }); + }); + + 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).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([]); + }); + 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', + ); + }); + 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 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).modelDeregister(modelId); + await expect(modelRegistry.connect(SECOND).modelDeregister(modelId)).to.be.revertedWithCustomError( + modelRegistry, + 'ModelHasAlreadyDeregistered', + ); + }); + }); +}); + +// npm run generate-types && npx hardhat test "test/diamond/facets/ModelRegistry.test.ts" +// npx hardhat coverage --solcoverjs ./.solcover.ts --testfiles "test/diamond/facets/ModelRegistry.test.ts" diff --git a/smart-contracts/test/diamond/facets/ProviderRegistry.test.ts b/smart-contracts/test/diamond/facets/ProviderRegistry.test.ts new file mode 100644 index 00000000..9a392db2 --- /dev/null +++ b/smart-contracts/test/diamond/facets/ProviderRegistry.test.ts @@ -0,0 +1,206 @@ +import { 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 { + deployFacetMarketplace, + deployFacetModelRegistry, + deployFacetProviderRegistry, + deployFacetSessionRouter, + deployLumerinDiamond, + deployMORToken, +} from '@/test/helpers/deployers'; +import { Reverter } from '@/test/helpers/reverter'; +import { setNextTime } from '@/utils/block-helper'; +import { YEAR } from '@/utils/time'; + +describe('ProviderRegistry', () => { + const reverter = new Reverter(); + + let OWNER: SignerWithAddress; + let PROVIDER: SignerWithAddress; + + let diamond: LumerinDiamond; + let providerRegistry: ProviderRegistry; + let modelRegistry: ModelRegistry; + let marketplace: Marketplace; + + let token: MorpheusToken; + + const modelId = getHex(Buffer.from('1')); + const ipfsCID = getHex(Buffer.from('ipfs://ipfsaddress')); + + before(async () => { + [OWNER, PROVIDER] = await ethers.getSigners(); + + [diamond, token] = await Promise.all([deployLumerinDiamond(), deployMORToken()]); + + [providerRegistry, modelRegistry, , marketplace] = await Promise.all([ + deployFacetProviderRegistry(diamond), + deployFacetModelRegistry(diamond), + deployFacetSessionRouter(diamond, OWNER), + deployFacetMarketplace(diamond, token, wei(0.0001), wei(900)), + ]); + + await token.transfer(PROVIDER, wei(1000)); + await token.connect(PROVIDER).approve(providerRegistry, wei(1000)); + await token.approve(providerRegistry, wei(1000)); + + await reverter.snapshot(); + }); + + afterEach(reverter.revert); + + describe('#__ProviderRegistry_init', () => { + it('should revert if try to call init function twice', async () => { + await expect(providerRegistry.__ProviderRegistry_init()).to.be.rejectedWith( + 'Initializable: contract is already initialized', + ); + }); + }); + + describe('#providerSetMinStake', async () => { + it('should set min stake', async () => { + const minStake = wei(100); + + await expect(providerRegistry.providerSetMinStake(minStake)) + .to.emit(providerRegistry, 'ProviderMinimumStakeUpdated') + .withArgs(minStake); + + expect(await providerRegistry.getProviderMinimumStake()).eq(minStake); + }); + + it('should throw error when caller is not an owner', async () => { + await expect(providerRegistry.connect(PROVIDER).providerSetMinStake(100)).to.be.revertedWithCustomError( + diamond, + 'OwnableUnauthorizedAccount', + ); + }); + }); + + describe('#providerRegister', async () => { + it('should register a new provider', async () => { + await setNextTime(300); + await providerRegistry.connect(PROVIDER).providerRegister(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]); + + await providerRegistry.connect(PROVIDER).providerRegister(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'); + + const data = await providerRegistry.getProvider(PROVIDER); + + expect(data.endpoint).to.eq('test2'); + expect(data.stake).to.eq(wei(400)); + 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(400)); + expect(await token.balanceOf(PROVIDER)).to.eq(wei(600)); + }); + it('should activate deregistered provider', async () => { + await setNextTime(300); + await providerRegistry.connect(PROVIDER).providerRegister(wei(100), 'test'); + await setNextTime(301 + YEAR); + await providerRegistry.connect(PROVIDER).providerDeregister(); + + 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'); + data = await providerRegistry.getProvider(PROVIDER); + + expect(data.endpoint).to.eq('test2'); + expect(data.stake).to.eq(wei(1)); + 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); + }); + 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', + ); + }); + }); + + describe('#providerDeregister', async () => { + it('should deregister the provider', async () => { + await setNextTime(300); + await providerRegistry.connect(PROVIDER).providerRegister(wei(100), 'test'); + await setNextTime(301 + YEAR); + await providerRegistry.connect(PROVIDER).providerDeregister(); + + 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([]); + }); + it('should deregister the provider without transfer', async () => { + await providerRegistry.providerSetMinStake(0); + await setNextTime(300); + await providerRegistry.connect(PROVIDER).providerRegister(wei(0), 'test'); + await setNextTime(301 + YEAR); + await providerRegistry.connect(PROVIDER).providerDeregister(); + + 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)); + }); + it('should throw error when provider is not found', async () => { + await expect(providerRegistry.connect(OWNER).providerDeregister()).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( + 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( + providerRegistry, + 'ProviderHasAlreadyDeregistered', + ); + }); + }); +}); + +// npm run generate-types && npx hardhat test "test/diamond/facets/ProviderRegistry.test.ts" +// npx hardhat coverage --solcoverjs ./.solcover.ts --testfiles "test/diamond/facets/ProviderRegistry.test.ts" diff --git a/smart-contracts/test/diamond/facets/SessionRouter.test.ts b/smart-contracts/test/diamond/facets/SessionRouter.test.ts new file mode 100644 index 00000000..2ceba527 --- /dev/null +++ b/smart-contracts/test/diamond/facets/SessionRouter.test.ts @@ -0,0 +1,911 @@ +import { 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 { + deployFacetMarketplace, + deployFacetModelRegistry, + deployFacetProviderRegistry, + deployFacetSessionRouter, + deployLumerinDiamond, + deployMORToken, +} from '@/test/helpers/deployers'; +import { payoutStart } from '@/test/helpers/pool-helper'; +import { Reverter } from '@/test/helpers/reverter'; +import { setTime } from '@/utils/block-helper'; +import { getProviderApproval, getReceipt } from '@/utils/provider-helper'; +import { DAY } from '@/utils/time'; + +describe('SessionRouter', () => { + const reverter = new Reverter(); + + let OWNER: SignerWithAddress; + let SECOND: SignerWithAddress; + let FUNDING: SignerWithAddress; + let PROVIDER: SignerWithAddress; + + let diamond: LumerinDiamond; + let marketplace: Marketplace; + let modelRegistry: ModelRegistry; + let providerRegistry: ProviderRegistry; + let sessionRouter: SessionRouter; + + let token: MorpheusToken; + + let bidId = ''; + const modelId = getHex(Buffer.from('1')); + const bidPricePerSecond = wei(0.0001); + + before(async () => { + [OWNER, SECOND, FUNDING, PROVIDER] = await ethers.getSigners(); + + [diamond, token] = await Promise.all([deployLumerinDiamond(), deployMORToken()]); + + [providerRegistry, modelRegistry, sessionRouter, marketplace] = await Promise.all([ + deployFacetProviderRegistry(diamond), + deployFacetModelRegistry(diamond), + deployFacetSessionRouter(diamond, FUNDING), + deployFacetMarketplace(diamond, token, wei(0.0001), wei(900)), + ]); + + await token.transfer(SECOND, wei(10000)); + await token.transfer(PROVIDER, wei(10000)); + await token.transfer(FUNDING, wei(10000)); + await token.connect(PROVIDER).approve(providerRegistry, wei(10000)); + await token.connect(PROVIDER).approve(modelRegistry, wei(10000)); + await token.connect(PROVIDER).approve(marketplace, wei(10000)); + await token.connect(SECOND).approve(sessionRouter, wei(10000)); + 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 marketplace.connect(PROVIDER).postModelBid(modelId, bidPricePerSecond); + bidId = await marketplace.getBidId(PROVIDER, modelId, 0); + + await reverter.snapshot(); + }); + + afterEach(reverter.revert); + + describe('#__SessionRouter_init', () => { + it('should set correct data after creation', async () => { + expect(await sessionRouter.getFundingAccount()).to.eq(FUNDING); + expect((await sessionRouter.getPools()).length).to.eq(5); + }); + it('should revert if try to call init function twice', async () => { + await expect(sessionRouter.__SessionRouter_init(FUNDING, DAY, [])).to.be.rejectedWith( + 'Initializable: contract is already initialized', + ); + }); + }); + + describe('#getTodaysBudget', () => { + it('should return not zero amount', async () => { + expect(await sessionRouter.getTodaysBudget(payoutStart)).to.eq(0); + expect(await sessionRouter.getTodaysBudget(payoutStart + 10 * DAY)).to.greaterThan(0); + }); + }); + + describe('#setPoolConfig', () => { + it('should reset pool', async () => { + await sessionRouter.setPoolConfig(0, { + payoutStart: 0, + decreaseInterval: DAY, + initialReward: wei(1000), + rewardDecrease: wei(10), + }); + + const pool = await sessionRouter.getPool(0); + expect(pool.payoutStart).to.eq(0); + expect(pool.decreaseInterval).to.eq(DAY); + expect(pool.initialReward).to.eq(wei(1000)); + expect(pool.rewardDecrease).to.eq(wei(10)); + }); + it('should throw error when the pool index is invalid', async () => { + await expect( + sessionRouter.setPoolConfig(100, { + payoutStart: 0, + decreaseInterval: DAY, + initialReward: wei(1000), + rewardDecrease: wei(10), + }), + ).to.be.revertedWithCustomError(sessionRouter, 'SessionPoolIndexOutOfBounds'); + }); + it('should throw error when the caller is invalid', async () => { + await expect( + sessionRouter.connect(SECOND).setPoolConfig(0, { + payoutStart: 0, + decreaseInterval: DAY, + initialReward: wei(1000), + rewardDecrease: wei(10), + }), + ).to.be.revertedWithCustomError(sessionRouter, 'OwnableUnauthorizedAccount'); + }); + }); + + describe('#setMaxSessionDuration', () => { + it('should set max session duration', async () => { + await sessionRouter.setMaxSessionDuration(7 * DAY); + expect(await sessionRouter.getMaxSessionDuration()).to.eq(7 * DAY); + + await sessionRouter.setMaxSessionDuration(8 * DAY); + expect(await sessionRouter.getMaxSessionDuration()).to.eq(8 * DAY); + }); + it('should throw error when max session duration too low', async () => { + await expect(sessionRouter.setMaxSessionDuration(1)).to.be.revertedWithCustomError( + sessionRouter, + 'SessionMaxDurationTooShort', + ); + }); + it('should throw error when the caller is invalid', async () => { + await expect(sessionRouter.connect(SECOND).setMaxSessionDuration(1)).to.be.revertedWithCustomError( + sessionRouter, + 'OwnableUnauthorizedAccount', + ); + }); + }); + + describe('#openSession', () => { + let tokenBalBefore = 0n; + let secondBalBefore = 0n; + + beforeEach(async () => { + tokenBalBefore = await token.balanceOf(sessionRouter); + secondBalBefore = await token.balanceOf(SECOND); + }); + it('should open 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); + + 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]); + expect(await sessionRouter.getProviderSessions(PROVIDER, 0, 10)).to.deep.eq([sessionId]); + expect(await sessionRouter.getModelSessions(modelId, 0, 10)).to.deep.eq([sessionId]); + }); + it('should open two different session 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); + + const sessionId1 = await sessionRouter.getSessionId(SECOND, PROVIDER, bidId, 0); + const sessionId2 = await sessionRouter.getSessionId(SECOND, PROVIDER, bidId, 1); + + const tokenBalAfter = await token.balanceOf(sessionRouter); + expect(tokenBalAfter - tokenBalBefore).to.eq(wei(100)); + const secondBalAfter = await token.balanceOf(SECOND); + expect(secondBalBefore - secondBalAfter).to.eq(wei(100)); + + 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.getTotalSessions(PROVIDER)).to.eq(2); + }); + it('should open 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); + + 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 () => { + await setTime(payoutStart + 10 * DAY); + const { msg, signature } = await getProviderApproval(PROVIDER, SECOND, bidId); + await sessionRouter.connect(SECOND).openSession(wei(50), true, 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(true); + + 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]); + expect(await sessionRouter.getProviderSessions(PROVIDER, 0, 10)).to.deep.eq([sessionId]); + expect(await sessionRouter.getModelSessions(modelId, 0, 10)).to.deep.eq([sessionId]); + }); + 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), + ).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), + ).to.be.revertedWithCustomError(sessionRouter, 'SesssionApprovedForAnotherChainId'); + }); + it('should throw error when an aprrove expired', async () => { + await setTime(payoutStart); + const { msg, signature } = await getProviderApproval(PROVIDER, SECOND, bidId); + await setTime(payoutStart + 600); + await expect( + sessionRouter.connect(SECOND).openSession(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), + ).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), + ).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 expect( + sessionRouter.connect(SECOND).openSession(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), + ).to.be.revertedWithCustomError(sessionRouter, 'SessionTooShort'); + }); + }); + + describe('#closeSession', () => { + it('should close session and send rewards for the provider, late closure', async () => { + const { sessionId, openedAt } = await _createSession(); + + const providerBalBefore = await token.balanceOf(PROVIDER); + const fundingBalBefore = await token.balanceOf(FUNDING); + + 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(SECOND).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); + + const fundingBalBefore = await token.balanceOf(FUNDING); + await setTime(openedAt + 200); + const { msg: receiptMsg, signature: receiptSig } = await getReceipt(PROVIDER, sessionId, 0, 0); + await sessionRouter.connect(SECOND).closeSession(receiptMsg, receiptSig); + + const session = await sessionRouter.getSession(sessionId); + const duration = session.closedAt - session.openedAt; + + expect(session.closedAt).to.eq(openedAt + 201); + 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, late closure before end', async () => { + const { sessionId, secondsToDayEnd, openedAt } = await _createSession(); + + const providerBalBefore = await token.balanceOf(PROVIDER); + const fundingBalBefore = await token.balanceOf(FUNDING); + + 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); + + 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, same day closure', async () => { + const { sessionId, secondsToDayEnd, openedAt } = await _createSession(); + + const providerBalBefore = await token.balanceOf(PROVIDER); + const fundingBalBefore = await token.balanceOf(FUNDING); + + await setTime(openedAt + secondsToDayEnd - 50); + 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); + + const session = await sessionRouter.getSession(sessionId); + + const duration = 0n; + expect(session.closedAt).to.eq(openedAt + secondsToDayEnd - 49); + 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, early closure', async () => { + const { sessionId, openedAt, secondsToDayEnd } = await _createSession(true); + + const providerBalBefore = await token.balanceOf(PROVIDER); + const fundingBalBefore = await token.balanceOf(FUNDING); + const contractBalBefore = await token.balanceOf(sessionRouter); + const secondBalBefore = await token.balanceOf(SECOND); + + await setTime(openedAt + secondsToDayEnd + 100); + 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); + + const session = await sessionRouter.getSession(sessionId); + const duration = BigInt(secondsToDayEnd); + + expect(session.closedAt).to.eq(openedAt + secondsToDayEnd + 100 + 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(0); + const contractBalAfter = await token.balanceOf(sessionRouter); + const secondBalAfter = await token.balanceOf(SECOND); + expect(contractBalBefore - contractBalAfter).to.eq( + bidPricePerSecond * duration + secondBalAfter - secondBalBefore, + ); + }); + it('should close session and send rewards for the user, late closure', async () => { + const { sessionId, openedAt } = await _createSession(); + + const userBalBefore = await token.balanceOf(SECOND); + const contractBalBefore = await token.balanceOf(sessionRouter); + + await setTime(openedAt + 5 * DAY); + const { msg: receiptMsg, signature: receiptSig } = await getReceipt(PROVIDER, sessionId, 0, 0); + await sessionRouter.connect(SECOND).closeSession(receiptMsg, receiptSig); + + const stakesOnHold = await sessionRouter.getUserStakesOnHold(SECOND, 20); + expect(stakesOnHold[0]).to.eq(0); + expect(stakesOnHold[1]).to.eq(0); + + const userBalAfter = await token.balanceOf(SECOND); + expect(userBalAfter - userBalBefore).to.eq(wei(50)); + const contractBalAfter = await token.balanceOf(sessionRouter); + expect(contractBalBefore - contractBalAfter).to.eq(wei(50)); + }); + it('should close session and send rewards for the user, early closure', async () => { + const { sessionId, openedAt, secondsToDayEnd } = await _createSession(); + + const userBalBefore = await token.balanceOf(SECOND); + const contractBalBefore = await token.balanceOf(sessionRouter); + + await setTime(openedAt + secondsToDayEnd + 1); + const { msg: receiptMsg, signature: receiptSig } = await getReceipt(PROVIDER, sessionId, 0, 0); + await sessionRouter.connect(SECOND).closeSession(receiptMsg, receiptSig); + + const stakesOnHold = await sessionRouter.getUserStakesOnHold(SECOND, 1); + expect(stakesOnHold[0]).to.eq(0); + expect(stakesOnHold[1]).to.greaterThan(0); + + const userBalAfter = await token.balanceOf(SECOND); + expect(userBalAfter - userBalBefore).to.lessThan(wei(50)); + const contractBalAfter = await token.balanceOf(sessionRouter); + expect(contractBalBefore - contractBalAfter).to.lessThan(wei(50)); + + await sessionRouter.getProviderModelStats(modelId, PROVIDER); + await sessionRouter.getModelStats(modelId); + }); + it('should claim provider rewards and close session, late closure', async () => { + const { sessionId, openedAt } = await _createSession(true); + + let userBalBefore = await token.balanceOf(SECOND); + let providerBalBefore = await token.balanceOf(PROVIDER); + let contractBalBefore = await token.balanceOf(sessionRouter); + + // Claim for Provider + await setTime(openedAt + 5 * DAY); + await sessionRouter.connect(PROVIDER).claimForProvider(sessionId); + + let session = await sessionRouter.getSession(sessionId); + const duration = session.endsAt - session.openedAt; + + 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 userBalAfter = await token.balanceOf(SECOND); + expect(userBalAfter - userBalBefore).to.eq(0); + const providerBalAfter = await token.balanceOf(PROVIDER); + expect(providerBalAfter - providerBalBefore).to.eq(bidPricePerSecond * duration); + const contractBalAfter = await token.balanceOf(sessionRouter); + expect(contractBalBefore - contractBalAfter).to.eq(bidPricePerSecond * duration); + + // Close session + userBalBefore = userBalAfter; + providerBalBefore = providerBalAfter; + contractBalBefore = contractBalAfter; + + await setTime(openedAt + 6 * DAY); + const { msg: receiptMsg, signature: receiptSig } = await getReceipt(PROVIDER, sessionId, 0, 0); + await sessionRouter.connect(SECOND).closeSession(receiptMsg, receiptSig); + + const userBalAfterClose = await token.balanceOf(SECOND); + expect(userBalAfterClose - userBalBefore).to.eq(wei(50) - bidPricePerSecond * duration); + const providerBalAfterClose = await token.balanceOf(PROVIDER); + expect(providerBalAfterClose - providerBalBefore).to.eq(0); + const contractBalAfterClose = await token.balanceOf(sessionRouter); + expect(contractBalBefore - contractBalAfterClose).to.eq(wei(50) - bidPricePerSecond * duration); + + session = await sessionRouter.getSession(sessionId); + expect(session.closedAt).to.eq(openedAt + 6 * DAY + 1); + expect(session.isActive).to.eq(false); + expect(session.closeoutReceipt).to.eq(receiptMsg); + expect(session.providerWithdrawnAmount).to.eq(bidPricePerSecond * duration); + }); + it('should throw error when the caller is invalid', async () => { + 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', + ); + }); + it('should throw error when the session already closed', async () => { + const { sessionId, openedAt, secondsToDayEnd } = await _createSession(); + + await setTime(openedAt + secondsToDayEnd + 1); + const { msg: receiptMsg, signature: receiptSig } = await getReceipt(PROVIDER, sessionId, 0, 0); + await sessionRouter.connect(SECOND).closeSession(receiptMsg, receiptSig); + + await expect(sessionRouter.connect(SECOND).closeSession(receiptMsg, receiptSig)).to.be.revertedWithCustomError( + sessionRouter, + 'SessionAlreadyClosed', + ); + }); + it('should throw error when the provider receipt for another chain', async () => { + const { sessionId } = await _createSession(); + + const { msg: receiptMsg, signature: receiptSig } = await getReceipt(PROVIDER, sessionId, 0, 0, 1n); + await expect(sessionRouter.connect(SECOND).closeSession(receiptMsg, receiptSig)).to.be.revertedWithCustomError( + sessionRouter, + 'SesssionReceiptForAnotherChainId', + ); + }); + it('should throw error when the provider receipt expired', async () => { + const { sessionId, openedAt } = await _createSession(); + + await setTime(openedAt + 100); + const { msg: receiptMsg, signature: receiptSig } = await getReceipt(PROVIDER, sessionId, 0, 0); + + await setTime(openedAt + 10000); + await expect(sessionRouter.connect(SECOND).closeSession(receiptMsg, receiptSig)).to.be.revertedWithCustomError( + sessionRouter, + 'SesssionReceiptExpired', + ); + }); + }); + + describe('#claimForProvider', () => { + it('should claim provider rewards, remainder, session closed with dispute', 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 sessionRouter.connect(PROVIDER).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 claim provider rewards, full', async () => { + const { sessionId, openedAt } = await _createSession(); + + let session = await sessionRouter.getSession(sessionId); + const duration = session.endsAt - session.openedAt; + + const providerBalBefore = await token.balanceOf(PROVIDER); + const fundingBalBefore = await token.balanceOf(FUNDING); + + await setTime(openedAt + 5 * DAY + 1); + 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(bidPricePerSecond * duration); + const fundingBalAfter = await token.balanceOf(FUNDING); + expect(fundingBalBefore - fundingBalAfter).to.eq(bidPricePerSecond * duration); + }); + it('should claim provider rewards with reward limiter amount for the period', async () => { + const providerBalBefore = await token.balanceOf(PROVIDER); + const fundingBalBefore = await token.balanceOf(FUNDING); + + 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); + + const sessionId1 = await sessionRouter.getSessionId(SECOND, PROVIDER, bidId, 0); + await setTime(payoutStart + 20 * DAY); + await sessionRouter.connect(PROVIDER).claimForProvider(sessionId1); + + 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); + + const sessionId2 = await sessionRouter.getSessionId(SECOND, PROVIDER, bidId, 1); + await setTime(payoutStart + 40 * DAY); + await sessionRouter.connect(PROVIDER).claimForProvider(sessionId2); + + expect(await sessionRouter.getProvidersTotalClaimed()).to.eq(wei(0.2)); + expect((await sessionRouter.getProvider(PROVIDER)).limitPeriodEarned).to.eq(wei(0.2)); + + const providerBalAfter = await token.balanceOf(PROVIDER); + expect(providerBalAfter - providerBalBefore).to.eq(wei(0.2)); + const fundingBalAfter = await token.balanceOf(FUNDING); + expect(fundingBalBefore - fundingBalAfter).to.eq(wei(0.2)); + }); + it('should claim zero when session is not end', async () => { + const { sessionId, openedAt } = await _createSession(); + + const providerBalBefore = await token.balanceOf(PROVIDER); + const fundingBalBefore = await token.balanceOf(FUNDING); + + await setTime(openedAt + 10); + await sessionRouter.connect(PROVIDER).claimForProvider(sessionId); + + 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 throw error when caller is not the session provider', async () => { + const { sessionId } = await _createSession(); + + await expect(sessionRouter.connect(SECOND).claimForProvider(sessionId)).to.be.revertedWithCustomError( + sessionRouter, + 'OwnableUnauthorizedAccount', + ); + }); + }); + + describe('#withdrawUserStakes', () => { + it('should withdraw the user stake on hold, 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(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 setTime(openedAt + 3 * DAY + 2); + await sessionRouter.connect(SECOND).withdrawUserStakes(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, few entities, with on hold', async () => { + const openedAt = payoutStart + (payoutStart % DAY) + 10 * DAY - 201; + + 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); + const sessionId1 = await sessionRouter.getSessionId(SECOND, PROVIDER, bidId, 0); + + await setTime(openedAt + 1 * DAY + 500); + const { msg: receiptMsg1, signature: receiptSig1 } = await getReceipt(PROVIDER, sessionId1, 0, 0); + await sessionRouter.connect(SECOND).closeSession(receiptMsg1, receiptSig1); + + 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); + const sessionId2 = await sessionRouter.getSessionId(SECOND, PROVIDER, bidId, 1); + + await setTime(openedAt + 3 * DAY + 500); + const { msg: receiptMsg2, signature: receiptSig2 } = await getReceipt(PROVIDER, sessionId2, 0, 0); + await sessionRouter.connect(SECOND).closeSession(receiptMsg2, receiptSig2); + + const stakesOnHold = await sessionRouter.getUserStakesOnHold(SECOND, 20); + expect(stakesOnHold[0]).to.greaterThan(0); + expect(stakesOnHold[1]).to.greaterThan(0); + + const userBalBefore = await token.balanceOf(SECOND); + const contractBalBefore = await token.balanceOf(sessionRouter); + + await setTime(openedAt + 4 * DAY); + await sessionRouter.connect(SECOND).withdrawUserStakes(20); + + const userBalAfter = await token.balanceOf(SECOND); + expect(userBalAfter - userBalBefore).to.eq(stakesOnHold[0]); + const contractBalAfter = await token.balanceOf(sessionRouter); + expect(contractBalBefore - contractBalAfter).to.eq(stakesOnHold[0]); + }); + it('should withdraw the user stake on hold, few entities, with on hold, partial withdraw', async () => { + const openedAt = payoutStart + (payoutStart % DAY) + 10 * DAY - 201; + + // 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); + const sessionId1 = await sessionRouter.getSessionId(SECOND, PROVIDER, bidId, 0); + + await setTime(openedAt + 1 * DAY + 500); + const { msg: receiptMsg1, signature: receiptSig1 } = await getReceipt(PROVIDER, sessionId1, 0, 0); + await sessionRouter.connect(SECOND).closeSession(receiptMsg1, receiptSig1); + + let stakesOnHold = await sessionRouter.getUserStakesOnHold(SECOND, 10); + const onHoldAfterSession1 = stakesOnHold[1]; + + // 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); + const sessionId2 = await sessionRouter.getSessionId(SECOND, PROVIDER, bidId, 1); + + await setTime(openedAt + 3 * DAY + 500); + const { msg: receiptMsg2, signature: receiptSig2 } = await getReceipt(PROVIDER, sessionId2, 0, 0); + await sessionRouter.connect(SECOND).closeSession(receiptMsg2, receiptSig2); + + stakesOnHold = await sessionRouter.getUserStakesOnHold(SECOND, 10); + const onHoldAfterSession2 = stakesOnHold[1]; + + // 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); + const sessionId3 = await sessionRouter.getSessionId(SECOND, PROVIDER, bidId, 2); + + await setTime(openedAt + 5 * DAY + 500); + const { msg: receiptMsg3, signature: receiptSig3 } = await getReceipt(PROVIDER, sessionId3, 0, 0); + await sessionRouter.connect(SECOND).closeSession(receiptMsg3, receiptSig3); + + stakesOnHold = await sessionRouter.getUserStakesOnHold(SECOND, 10); + const onHoldAfterSession3 = stakesOnHold[1]; + + // First withdraw + await setTime(openedAt + 99 * DAY); + stakesOnHold = await sessionRouter.getUserStakesOnHold(SECOND, 10); + expect(stakesOnHold[0]).to.greaterThan(0); + expect(stakesOnHold[1]).to.eq(0); + + let userBalBefore = await token.balanceOf(SECOND); + let contractBalBefore = await token.balanceOf(sessionRouter); + + await sessionRouter.connect(SECOND).withdrawUserStakes(1); + + let userBalAfter = await token.balanceOf(SECOND); + expect(userBalAfter - userBalBefore).to.eq(onHoldAfterSession3); + let contractBalAfter = await token.balanceOf(sessionRouter); + expect(contractBalBefore - contractBalAfter).to.eq(onHoldAfterSession3); + + // Second withdraw + stakesOnHold = await sessionRouter.getUserStakesOnHold(SECOND, 1); + expect(stakesOnHold[0]).to.greaterThan(0); + expect(stakesOnHold[1]).to.eq(0); + + userBalBefore = await token.balanceOf(SECOND); + contractBalBefore = await token.balanceOf(sessionRouter); + + await sessionRouter.connect(SECOND).withdrawUserStakes(1); + + userBalAfter = await token.balanceOf(SECOND); + expect(userBalAfter - userBalBefore).to.eq(onHoldAfterSession2); + contractBalAfter = await token.balanceOf(sessionRouter); + expect(contractBalBefore - contractBalAfter).to.eq(onHoldAfterSession2); + + // Third withdraw + stakesOnHold = await sessionRouter.getUserStakesOnHold(SECOND, 1); + expect(stakesOnHold[0]).to.greaterThan(0); + expect(stakesOnHold[1]).to.eq(0); + + userBalBefore = await token.balanceOf(SECOND); + contractBalBefore = await token.balanceOf(sessionRouter); + + await sessionRouter.connect(SECOND).withdrawUserStakes(1); + + userBalAfter = await token.balanceOf(SECOND); + expect(userBalAfter - userBalBefore).to.eq(onHoldAfterSession1); + contractBalAfter = await token.balanceOf(sessionRouter); + expect(contractBalBefore - contractBalAfter).to.eq(onHoldAfterSession1); + }); + it('should withdraw the user stake on hold, few entities, without on hold', async () => { + const openedAt = payoutStart + (payoutStart % DAY) + 10 * DAY - 201; + + 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); + const sessionId1 = await sessionRouter.getSessionId(SECOND, PROVIDER, bidId, 0); + + await setTime(openedAt + 1 * DAY + 500); + const { msg: receiptMsg1, signature: receiptSig1 } = await getReceipt(PROVIDER, sessionId1, 0, 0); + await sessionRouter.connect(SECOND).closeSession(receiptMsg1, receiptSig1); + + 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); + const sessionId2 = await sessionRouter.getSessionId(SECOND, PROVIDER, bidId, 1); + + await setTime(openedAt + 3 * DAY + 500); + const { msg: receiptMsg2, signature: receiptSig2 } = await getReceipt(PROVIDER, sessionId2, 0, 0); + await sessionRouter.connect(SECOND).closeSession(receiptMsg2, receiptSig2); + + await setTime(openedAt + 10 * DAY); + const stakesOnHold = await sessionRouter.getUserStakesOnHold(SECOND, 20); + expect(stakesOnHold[0]).to.greaterThan(0); + expect(stakesOnHold[1]).to.eq(0); + + const userBalBefore = await token.balanceOf(SECOND); + const contractBalBefore = await token.balanceOf(sessionRouter); + + await sessionRouter.connect(SECOND).withdrawUserStakes(20); + + const userBalAfter = await token.balanceOf(SECOND); + expect(userBalAfter - userBalBefore).to.eq(stakesOnHold[0]); + const contractBalAfter = await token.balanceOf(sessionRouter); + expect(contractBalBefore - contractBalAfter).to.eq(stakesOnHold[0]); + }); + it('should throw error when withdraw amount is zero', async () => { + const openedAt = payoutStart + (payoutStart % DAY) + 10 * DAY - 201; + + 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); + 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); + const sessionId2 = await sessionRouter.getSessionId(SECOND, PROVIDER, bidId, 1); + + await setTime(openedAt + 1 * DAY + 500); + const { msg: receiptMsg1, signature: receiptSig1 } = await getReceipt(PROVIDER, sessionId1, 0, 0); + await sessionRouter.connect(SECOND).closeSession(receiptMsg1, receiptSig1); + + await setTime(openedAt + 1 * DAY + 550); + 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( + sessionRouter, + 'SessionUserAmountToWithdrawIsZero', + ); + }); + it('should throw error when amount of itterations are zero', async () => { + await expect(sessionRouter.connect(SECOND).withdrawUserStakes(0)).to.be.revertedWithCustomError( + sessionRouter, + 'SessionUserAmountToWithdrawIsZero', + ); + }); + }); + + describe('#stipendToStake', () => { + it('should return zero if compute balance is zero', async () => { + expect(await sessionRouter.connect(SECOND).stipendToStake(0, 0)).to.eq(0); + }); + }); + + const _createSession = async (isDirectPaymentFromUser = false) => { + const secondsToDayEnd = 600n; + const openedAt = payoutStart + (payoutStart % DAY) + 10 * DAY - Number(secondsToDayEnd) - 1; + + await setTime(openedAt); + const { msg, signature } = await getProviderApproval(PROVIDER, SECOND, bidId); + await sessionRouter.connect(SECOND).openSession(wei(50), isDirectPaymentFromUser, msg, signature); + + return { + sessionId: await sessionRouter.getSessionId(SECOND, PROVIDER, bidId, 0), + secondsToDayEnd: Number(secondsToDayEnd), + openedAt, + }; + }; +}); + +// npm run generate-types && npx hardhat test "test/diamond/facets/SessionRouter.test.ts" +// npx hardhat coverage --solcoverjs ./.solcover.ts --testfiles "test/diamond/facets/SessionRouter.test.ts" diff --git a/smart-contracts/test/helpers/deployers/diamond/facets/marketplace.ts b/smart-contracts/test/helpers/deployers/diamond/facets/marketplace.ts new file mode 100644 index 00000000..33229561 --- /dev/null +++ b/smart-contracts/test/helpers/deployers/diamond/facets/marketplace.ts @@ -0,0 +1,45 @@ +import { Fragment } from 'ethers'; +import { ethers } from 'hardhat'; + +import { + IBidStorage__factory, + IMarketplace__factory, + LumerinDiamond, + Marketplace, + MorpheusToken, +} from '@/generated-types/ethers'; +import { FacetAction } from '@/test/helpers/deployers/diamond/lumerin-diamond'; + +export const deployFacetMarketplace = async ( + diamond: LumerinDiamond, + token: MorpheusToken, + bidMinPrice: bigint, + bidMaxPrice: bigint, +): Promise => { + let facet: Marketplace; + + const factory = await ethers.getContractFactory('Marketplace'); + facet = await factory.deploy(); + + await diamond['diamondCut((address,uint8,bytes4[])[])']([ + { + facetAddress: facet, + action: FacetAction.Add, + functionSelectors: IMarketplace__factory.createInterface() + .fragments.filter(Fragment.isFunction) + .map((f) => f.selector), + }, + { + facetAddress: facet, + action: FacetAction.Add, + functionSelectors: IBidStorage__factory.createInterface() + .fragments.filter(Fragment.isFunction) + .map((f) => f.selector), + }, + ]); + + facet = facet.attach(diamond.target) as Marketplace; + await facet.__Marketplace_init(token, bidMinPrice, bidMaxPrice); + + return facet; +}; diff --git a/smart-contracts/test/helpers/deployers/diamond/facets/model-registry.ts b/smart-contracts/test/helpers/deployers/diamond/facets/model-registry.ts new file mode 100644 index 00000000..aa198cc7 --- /dev/null +++ b/smart-contracts/test/helpers/deployers/diamond/facets/model-registry.ts @@ -0,0 +1,27 @@ +import { Fragment } from 'ethers'; +import { ethers } from 'hardhat'; + +import { IModelRegistry__factory, LumerinDiamond, ModelRegistry } from '@/generated-types/ethers'; +import { FacetAction } from '@/test/helpers/deployers/diamond/lumerin-diamond'; + +export const deployFacetModelRegistry = async (diamond: LumerinDiamond): Promise => { + let facet: ModelRegistry; + + const factory = await ethers.getContractFactory('ModelRegistry'); + facet = await factory.deploy(); + + await diamond['diamondCut((address,uint8,bytes4[])[])']([ + { + facetAddress: facet, + action: FacetAction.Add, + functionSelectors: IModelRegistry__factory.createInterface() + .fragments.filter(Fragment.isFunction) + .map((f) => f.selector), + }, + ]); + + facet = facet.attach(diamond.target) as ModelRegistry; + await facet.__ModelRegistry_init(); + + return facet; +}; diff --git a/smart-contracts/test/helpers/deployers/diamond/facets/provider-registry.ts b/smart-contracts/test/helpers/deployers/diamond/facets/provider-registry.ts new file mode 100644 index 00000000..12ee4165 --- /dev/null +++ b/smart-contracts/test/helpers/deployers/diamond/facets/provider-registry.ts @@ -0,0 +1,27 @@ +import { Fragment } from 'ethers'; +import { ethers } from 'hardhat'; + +import { IProviderRegistry__factory, LumerinDiamond, ProviderRegistry } from '@/generated-types/ethers'; +import { FacetAction } from '@/test/helpers/deployers/diamond/lumerin-diamond'; + +export const deployFacetProviderRegistry = async (diamond: LumerinDiamond): Promise => { + let facet: ProviderRegistry; + + const factory = await ethers.getContractFactory('ProviderRegistry'); + facet = await factory.deploy(); + + await diamond['diamondCut((address,uint8,bytes4[])[])']([ + { + facetAddress: facet, + action: FacetAction.Add, + functionSelectors: IProviderRegistry__factory.createInterface() + .fragments.filter(Fragment.isFunction) + .map((f) => f.selector), + }, + ]); + + facet = facet.attach(diamond.target) as ProviderRegistry; + await facet.__ProviderRegistry_init(); + + return facet; +}; diff --git a/smart-contracts/test/helpers/deployers/diamond/facets/session-router.ts b/smart-contracts/test/helpers/deployers/diamond/facets/session-router.ts new file mode 100644 index 00000000..39f63f5f --- /dev/null +++ b/smart-contracts/test/helpers/deployers/diamond/facets/session-router.ts @@ -0,0 +1,52 @@ +import { SignerWithAddress } from '@nomicfoundation/hardhat-ethers/signers'; +import { Fragment } from 'ethers'; +import { ethers } from 'hardhat'; + +import { + ISessionRouter__factory, + IStatsStorage__factory, + LumerinDiamond, + SessionRouter, +} from '@/generated-types/ethers'; +import { FacetAction } from '@/test/helpers/deployers/diamond/lumerin-diamond'; +import { getDefaultPools } from '@/test/helpers/pool-helper'; +import { DAY } from '@/utils/time'; + +export const deployFacetSessionRouter = async ( + diamond: LumerinDiamond, + fundingAccount: SignerWithAddress, +): Promise => { + let facet: SessionRouter; + + const LDIDFactory = await ethers.getContractFactory('LinearDistributionIntervalDecrease'); + const LDID = await LDIDFactory.deploy(); + + const factory = await ethers.getContractFactory('SessionRouter', { + libraries: { + LinearDistributionIntervalDecrease: LDID, + }, + }); + facet = await factory.deploy(); + + await diamond['diamondCut((address,uint8,bytes4[])[])']([ + { + facetAddress: facet, + action: FacetAction.Add, + functionSelectors: ISessionRouter__factory.createInterface() + .fragments.filter(Fragment.isFunction) + .map((f) => f.selector), + }, + { + facetAddress: facet, + action: FacetAction.Add, + functionSelectors: IStatsStorage__factory.createInterface() + .fragments.filter(Fragment.isFunction) + .map((f) => f.selector), + }, + ]); + + facet = facet.attach(diamond.target) as SessionRouter; + await facet.__SessionRouter_init(fundingAccount, DAY, getDefaultPools()); + + return facet; +}; diff --git a/smart-contracts/test/helpers/deployers/diamond/index.ts b/smart-contracts/test/helpers/deployers/diamond/index.ts new file mode 100644 index 00000000..36c74670 --- /dev/null +++ b/smart-contracts/test/helpers/deployers/diamond/index.ts @@ -0,0 +1,5 @@ +export * from './facets/model-registry'; +export * from './facets/marketplace'; +export * from './facets/provider-registry'; +export * from './facets/session-router'; +export * from './lumerin-diamond'; diff --git a/smart-contracts/test/helpers/deployers/diamond/lumerin-diamond.ts b/smart-contracts/test/helpers/deployers/diamond/lumerin-diamond.ts new file mode 100644 index 00000000..f2220ca2 --- /dev/null +++ b/smart-contracts/test/helpers/deployers/diamond/lumerin-diamond.ts @@ -0,0 +1,17 @@ +import { ethers } from 'hardhat'; + +import { LumerinDiamond } from '@/generated-types/ethers'; + +export enum FacetAction { + Add = 0, + Replace = 1, + Remove = 2, +} + +export const deployLumerinDiamond = async (): Promise => { + const factory = await ethers.getContractFactory('LumerinDiamond'); + const contract = await factory.deploy(); + await contract.__LumerinDiamond_init(); + + return contract; +}; diff --git a/smart-contracts/test/helpers/deployers/index.ts b/smart-contracts/test/helpers/deployers/index.ts new file mode 100644 index 00000000..6d1b8c98 --- /dev/null +++ b/smart-contracts/test/helpers/deployers/index.ts @@ -0,0 +1,2 @@ +export * from './diamond'; +export * from './mock'; diff --git a/smart-contracts/test/helpers/deployers/mock/index.ts b/smart-contracts/test/helpers/deployers/mock/index.ts new file mode 100644 index 00000000..cfcb186e --- /dev/null +++ b/smart-contracts/test/helpers/deployers/mock/index.ts @@ -0,0 +1 @@ +export * from './tokens/morpheus-token'; diff --git a/smart-contracts/test/helpers/deployers/mock/tokens/morpheus-token.ts b/smart-contracts/test/helpers/deployers/mock/tokens/morpheus-token.ts new file mode 100644 index 00000000..8ff21270 --- /dev/null +++ b/smart-contracts/test/helpers/deployers/mock/tokens/morpheus-token.ts @@ -0,0 +1,10 @@ +import { ethers } from 'hardhat'; + +import { MorpheusToken } from '@/generated-types/ethers'; + +export const deployMORToken = async (): Promise => { + const factory = await ethers.getContractFactory('MorpheusToken'); + const contract = await factory.deploy(); + + return contract; +}; diff --git a/smart-contracts/test/helpers/enums.ts b/smart-contracts/test/helpers/enums.ts deleted file mode 100644 index 89962ab6..00000000 --- a/smart-contracts/test/helpers/enums.ts +++ /dev/null @@ -1,5 +0,0 @@ -export enum FacetAction { - Add = 0, - Replace = 1, - Remove = 2, -} diff --git a/smart-contracts/test/helpers/pool-helper.ts b/smart-contracts/test/helpers/pool-helper.ts index c5117be6..914c3538 100644 --- a/smart-contracts/test/helpers/pool-helper.ts +++ b/smart-contracts/test/helpers/pool-helper.ts @@ -1,9 +1,11 @@ import { ISessionStorage } from '../../generated-types/ethers/contracts/interfaces/facets/ISessionRouter'; +export const payoutStart = 1707393600; + export function getDefaultPools(): ISessionStorage.PoolStruct[] { return [ { - payoutStart: 1707393600n, + payoutStart: payoutStart, decreaseInterval: 86400n, initialReward: 3456000000000000000000n, rewardDecrease: 592558728240000000n, @@ -15,19 +17,19 @@ export function getDefaultPools(): ISessionStorage.PoolStruct[] { rewardDecrease: 592558728240000000n, }, { - payoutStart: 1707393600n, + payoutStart: payoutStart, decreaseInterval: 86400n, initialReward: 3456000000000000000000n, rewardDecrease: 592558728240000000n, }, { - payoutStart: 1707393600n, + payoutStart: payoutStart, decreaseInterval: 86400n, initialReward: 3456000000000000000000n, rewardDecrease: 592558728240000000n, }, { - payoutStart: 1707393600n, + payoutStart: payoutStart, decreaseInterval: 86400n, initialReward: 576000000000000000000n, rewardDecrease: 98759788040000000n, diff --git a/smart-contracts/test/helpers/reverter.ts b/smart-contracts/test/helpers/reverter.ts index 207c36b5..c2ff7420 100644 --- a/smart-contracts/test/helpers/reverter.ts +++ b/smart-contracts/test/helpers/reverter.ts @@ -1,6 +1,7 @@ import { network } from 'hardhat'; export class Reverter { + // eslint-disable-next-line @typescript-eslint/no-explicit-any private snapshotId: any; revert = async () => { diff --git a/smart-contracts/utils/provider-helper.ts b/smart-contracts/utils/provider-helper.ts index 46d2bca5..ccfe5cd1 100644 --- a/smart-contracts/utils/provider-helper.ts +++ b/smart-contracts/utils/provider-helper.ts @@ -3,13 +3,20 @@ import { AbiCoder, getBytes, keccak256 } from 'ethers'; import { getChainId, getCurrentBlockTime } from './block-helper'; -export const getProviderApproval = async (provider: SignerWithAddress, user: string, bidId: string, chainId = 0n) => { +export const getProviderApproval = async ( + provider: SignerWithAddress, + user: SignerWithAddress, + bidId: string, + chainId = 0n, +) => { chainId = chainId || (await getChainId()); const timestamp = await getCurrentBlockTime(); + const msg = AbiCoder.defaultAbiCoder().encode( ['bytes32', 'uint256', 'address', 'uint128'], - [bidId, chainId, user, timestamp], + [bidId, chainId, user.address, timestamp], ); + const signature = await provider.signMessage(getBytes(keccak256(msg))); return { @@ -18,11 +25,19 @@ export const getProviderApproval = async (provider: SignerWithAddress, user: str }; }; -export const getReport = async (reporter: SignerWithAddress, sessionId: string, tps: number, ttftMs: number) => { +export const getReceipt = async ( + reporter: SignerWithAddress, + sessionId: string, + tps: number, + ttftMs: number, + chainId = 0n, +) => { + chainId = chainId || (await getChainId()); const timestamp = await getCurrentBlockTime(); + const msg = AbiCoder.defaultAbiCoder().encode( ['bytes32', 'uint256', 'uint128', 'uint32', 'uint32'], - [sessionId, await getChainId(), timestamp, tps * 1000, ttftMs], + [sessionId, chainId, timestamp, tps * 1000, ttftMs], ); const signature = await reporter.signMessage(getBytes(keccak256(msg))); diff --git a/smart-contracts/utils/time.ts b/smart-contracts/utils/time.ts index 79742b5d..c55ce8d7 100644 --- a/smart-contracts/utils/time.ts +++ b/smart-contracts/utils/time.ts @@ -1,5 +1,5 @@ -export const SECOND = 1n; -export const MINUTE = 60n * SECOND; -export const HOUR = 60n * MINUTE; -export const DAY = 24n * HOUR; -export const YEAR = 365n * DAY; +export const SECOND = 1; +export const MINUTE = 60 * SECOND; +export const HOUR = 60 * MINUTE; +export const DAY = 24 * HOUR; +export const YEAR = 365 * DAY; diff --git a/smart-contracts/wagmi.config.ts b/smart-contracts/wagmi.config.ts index a4838e9d..2f9ea2ce 100644 --- a/smart-contracts/wagmi.config.ts +++ b/smart-contracts/wagmi.config.ts @@ -1,16 +1,12 @@ -import { defineConfig } from "@wagmi/cli"; -import { hardhat } from "@wagmi/cli/plugins"; +import { defineConfig } from '@wagmi/cli'; +import { hardhat } from '@wagmi/cli/plugins'; export default defineConfig({ - out: "bindings/ts/abi.ts", + out: 'bindings/ts/abi.ts', plugins: [ hardhat({ - project: ".", - include: [ - "facets/**/*.json", - "MorpheusToken.sol/*.json", - "ERC20.sol/*.json", - ], + project: '.', + include: ['facets/**/*.json', 'MorpheusToken.sol/*.json', 'ERC20.sol/*.json'], }), ], }); diff --git a/ui-desktop/.env.example b/ui-desktop/.env.example index fecc58ca..9fc0168d 100644 --- a/ui-desktop/.env.example +++ b/ui-desktop/.env.example @@ -3,7 +3,7 @@ CHAIN_ID=421614 DEBUG=false DEFAULT_SELLER_CURRENCY=BTC DEV_TOOLS=true -DIAMOND_ADDRESS=0x8e19288d908b2d9f8d7c539c74c899808ac3de45 +DIAMOND_ADDRESS=0x10777866547c53cbd69b02c5c76369d7e24e7b10 DISPLAY_NAME=Sepolia Arbitrum EXPLORER_URL=https://sepolia.arbiscan.io/tx/{{hash}} IGNORE_DEBUG_LOGS=false @@ -11,5 +11,5 @@ PROXY_WEB_DEFAULT_PORT=8082 SENTRY_DSN= SYMBOL_ETH=saETH SYMBOL_LMR=saMOR -TOKEN_ADDRESS=0xc1664f994fd3991f98ae944bc16b9aed673ef5fd +TOKEN_ADDRESS=0x34a285a1b1c166420df5b6630132542923b5b27e TRACKING_ID= 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/src/main/src/client/apiGateway.js b/ui-desktop/src/main/src/client/apiGateway.js index e438e766..2728519e 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,108 @@ 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; + } + } + export default { getAllModels, getBalances, @@ -122,5 +224,9 @@ export default { getTransactions, getMorRate, getTodaysBudget, - getTokenSupply + getTokenSupply, + getChatHistoryTitles, + getChatHistory, + updateChatHistoryTitle, + deleteChatHistory, } \ 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..676df241 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,11 @@ import { getDefaultCurrencySetting, setDefaultCurrencySetting, getKey, - setKey + setKey, + getFailoverSetting, + setFailoverSetting } from '../settings' import apiGateway from '../apiGateway'; -import chatHistory from '../history/chat-history'; const validatePassword = (data) => auth.isValidPassword(data) @@ -115,6 +116,7 @@ export default { setProfitSettings, getAutoAdjustPriceData, setAutoAdjustPriceData, + getFailoverSetting, + 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..f88d8a0f 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,13 @@ 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.getFailoverSetting, + "set-failover-setting": handlers.setFailoverSetting } // 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/client/index.jsx b/ui-desktop/src/renderer/src/client/index.jsx index c92c6a57..d966bbe2 100644 --- a/ui-desktop/src/renderer/src/client/index.jsx +++ b/ui-desktop/src/renderer/src/client/index.jsx @@ -93,7 +93,7 @@ const createClient = function (createStore) { refreshAllTransactions: utils.forwardToMainProcess('refresh-all-transactions', 120000), refreshAllContracts: utils.forwardToMainProcess('refresh-all-contracts', 120000), onOnboardingCompleted: utils.forwardToMainProcess('onboarding-completed'), - recoverFromMnemonic: utils.forwardToMainProcess('recover-from-mnemonic'), + suggestAddresses: utils.forwardToMainProcess('suggest-addresses'), getTokenGasLimit: utils.forwardToMainProcess('get-token-gas-limit'), validatePassword: utils.forwardToMainProcess('validate-password'), changePassword: utils.forwardToMainProcess('change-password'), @@ -115,9 +115,7 @@ const createClient = function (createStore) { logout: utils.forwardToMainProcess('logout'), getLocalIp: utils.forwardToMainProcess('get-local-ip'), getPoolAddress: utils.forwardToMainProcess('get-pool-address'), - revealSecretPhrase: utils.forwardToMainProcess('reveal-secret-phrase'), getPrivateKey: utils.forwardToMainProcess('get-private-key'), - hasStoredSecretPhrase: utils.forwardToMainProcess('has-stored-secret-phrase'), getProxyRouterSettings: utils.forwardToMainProcess('get-proxy-router-settings'), getDefaultCurrencySetting: utils.forwardToMainProcess('get-default-currency-settings'), setDefaultCurrencySetting: utils.forwardToMainProcess('set-default-currency-settings'), @@ -140,12 +138,13 @@ const createClient = function (createStore) { getTodaysBudget: utils.forwardToMainProcess('get-todays-budget'), getTokenSupply: utils.forwardToMainProcess('get-supply'), // Chat History + getChatHistoryTitles: utils.forwardToMainProcess('get-chat-history-titles'), getChatHistory: utils.forwardToMainProcess('get-chat-history', 750000), - saveChatHistory: utils.forwardToMainProcess('save-chat-history', 750000), - getTitles: utils.forwardToMainProcess('get-chat-titles', 750000), - saveTitle: utils.forwardToMainProcess('save-chat-title', 750000), - deleteTitle: utils.forwardToMainProcess('delete-chat-title', 750000), - updateChatTitle: utils.forwardToMainProcess("update-chat-title", 750000), + deleteChatHistory: utils.forwardToMainProcess('delete-chat-history', 750000), + updateChatHistoryTitle: utils.forwardToMainProcess('update-chat-history-title', 750000), + // Failover + getFailoverSetting: utils.forwardToMainProcess('get-failover-setting', 750000), + setFailoverSetting: utils.forwardToMainProcess('set-failover-setting', 750000), } const api = { diff --git a/ui-desktop/src/renderer/src/components/chat/Chat.tsx b/ui-desktop/src/renderer/src/components/chat/Chat.tsx index 32c20237..58ff8e9a 100644 --- a/ui-desktop/src/renderer/src/components/chat/Chat.tsx +++ b/ui-desktop/src/renderer/src/components/chat/Chat.tsx @@ -31,11 +31,13 @@ import './Chat.css' import { ChatHistory } from './ChatHistory'; import Spinner from 'react-bootstrap/Spinner'; import ModelSelectionModal from './modals/ModelSelectionModal'; -import { parseDataChunk, makeId, getColor, isClosed } from './utils'; +import { parseDataChunk, makeId, getColor, isClosed, generateHashId } from './utils'; import { Cooldown } from './Cooldown'; import ImageViewer from "react-simple-image-viewer"; import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter' import { coldarkDark } from 'react-syntax-highlighter/dist/esm/styles/prism' +import { ChatData, ChatHistoryInterface, ChatTitle, HistoryMessage } from './interfaces'; + let abort = false; let cancelScroll = false; const userMessage = { user: 'Me', role: "user", icon: "M", color: "#20dc8e" }; @@ -56,7 +58,7 @@ const Chat = (props) => { const [activeSession, setActiveSession] = useState(undefined); const [chainData, setChainData] = useState(null); - const [sessionTitles, setSessionTitles] = useState<{ sessionId: string, title: string, createdAt: any }[]>([]); + const [chatData, setChatsData] = useState([]); const [openChangeModal, setOpenChangeModal] = useState(false); const [isReadonly, setIsReadonly] = useState(false); @@ -66,7 +68,7 @@ const Chat = (props) => { const [requiredStake, setRequiredStake] = useState<{ min: Number, max: number }>({ min: 0, max: 0 }) const [balances, setBalances] = useState<{ eth: Number, mor: number }>({ eth: 0, mor: 0 }); - const [chat, setChat] = useState(undefined); + const [chat, setChat] = useState(undefined); const modelName = selectedModel?.Name || "Model"; const isLocal = chat?.isLocal; @@ -78,31 +80,44 @@ const Chat = (props) => { useEffect(() => { (async () => { - const [meta, chainData, titles, userBalances] = await Promise.all([ + const [meta, chainData, chats, userBalances] = await Promise.all([ props.getMetaInfo(), props.getModelsData(), - props.client.getTitles(), + props.client.getChatHistoryTitles() as Promise, props.getBalances()]); setBalances(userBalances) setMeta(meta); setChainData(chainData) - setSessionTitles(titles.map(t => ({ ...t, title: t.title, sessionId: t._id }))); - const sessions = await props.getSessionsByUser(props.address); - const openSessions = sessions.filter(s => !isClosed(s)); + const mappedChatData = chats.reduce((res, item) => { + const chatModel = chainData.models.find(x => x.Id == item.modelId); + if (chatModel) { + res.push({ + id: item.chatId, + title: item.title, + createdAt: new Date(item.createdAt * 1000), + modelId: item.modelId, + isLocal: item.isLocal, + }) + } + return res; + }, [] as ChatData[]) + setChatsData(mappedChatData); - setSessions(sessions); + const sessions = await refreshSessions(chainData?.models); + + const openSessions = sessions.filter(s => !isClosed(s)); const useLocalModelChat = () => { - const localModel = (chainData?.models?.find((m: any) => m.hasLocal)); + const localModel = (chainData?.models?.find((m: any) => m.isLocal)); if (localModel) { setSelectedModel(localModel); - setChat({ id: makeId(16), createdAt: new Date(), modelId: localModel.Id, isLocal: true }); + setChat({ id: generateHashId(), createdAt: new Date(), modelId: localModel.Id, isLocal: true }); } } - if(!openSessions.length) { + if (!openSessions.length) { useLocalModelChat(); return; } @@ -110,27 +125,32 @@ const Chat = (props) => { const latestSession = openSessions[0]; const latestSessionModel = (chainData.models.find((m: any) => m.Id == latestSession.ModelAgentId)); - if(!latestSessionModel) { + if (!latestSessionModel) { useLocalModelChat(); return; } const openBid = latestSessionModel?.bids?.find(b => b.Id == latestSession.BidID); - if(!openBid) { + if (!openBid) { useLocalModelChat(); } setSelectedModel(latestSessionModel); setSelectedBid(openBid); setActiveSession(latestSession); - setChat({ id: makeId(16), createdAt: new Date(), modelId: latestSessionModel.ModelAgentId }); + setChat({ id: generateHashId(), createdAt: new Date(), modelId: latestSessionModel.ModelAgentId }); })().then(() => { setIsLoading(false); }) }, []) - const toggleDrawer = () => { + const toggleDrawer = async () => { + if (!isOpen) { + setIsLoading(true); + await refreshSessions() + setIsLoading(false); + } setIsOpen((prevState) => !prevState) } @@ -156,14 +176,23 @@ const Chat = (props) => { return (targetDuration - (targetDuration % 60)) - delta; } + const setSessionData = async (sessionId) => { + const allSessions = await refreshSessions(); + const targetSessionData = allSessions.find(x => x.Id == sessionId); + setActiveSession({ ...targetSessionData, sessionId }); + const targetModel = chainData.models.find(x => x.Id == targetSessionData.ModelAgentId) + const targetBid = targetModel.bids.find(x => x.Id == targetSessionData.BidID); + setSelectedBid(targetBid); + } + const onOpenSession = async (isReopen) => { setIsLoading(true); - if(!isReopen) { - setChat({ id: makeId(16), createdAt: new Date(), modelId: selectedModel.Id }); + if (!isReopen) { + setChat({ id: generateHashId(), createdAt: new Date(), modelId: selectedModel.Id }); } - const prices = selectedModel.bids.map(x => x.PricePerSecond); - const maxPrice = Math.max(prices); + const prices = selectedModel.bids.map(x => Number(x.PricePerSecond)); + const maxPrice = Math.max(...prices); const duration = calculateAcceptableDuration(maxPrice, Number(balances.mor), meta); console.log("open-session", duration); @@ -173,12 +202,7 @@ const Chat = (props) => { if (!openedSession) { return; } - const allSessions = await refreshSessions(); - const targetSessionData = allSessions.find(x => x.Id == openedSession); - setActiveSession({ ...targetSessionData, sessionId: openedSession }); - const targetModel = chainData.models.find(x => x.Id == targetSessionData.ModelAgentId) - const targetBid = targetModel.bids.find(x => x.Id == targetSessionData.BidID); - setSelectedBid(targetBid); + await setSessionData(openedSession); return openedSession; } finally { @@ -186,60 +210,87 @@ const Chat = (props) => { } } - const loadHistory = async (id) => { + const loadChatHistory = async (chatId: string) => { try { - const history = await props.client.getChatHistory(id); - setMessages(history.length ? (history[0].messages || []) : []); + const history: ChatHistoryInterface = await props.client.getChatHistory(chatId); + const messages: HistoryMessage[] = []; + + const model = chainData.models.find((m) => m.Id == history.modelId); + history.messages.forEach((m) => { + const modelName = model.Name || "Model"; + + const aiIcon = modelName.toUpperCase()[0]; + const aiColor = getColor(aiIcon); + + messages.push({ id: makeId(16), text: m.prompt.messages[0].content, user: userMessage.user, role: userMessage.role, icon: userMessage.icon, color: userMessage.color }); + messages.push({ id: makeId(16), text: m.response, user: modelName, role: "assistant", icon: aiIcon, color: aiColor, isImageContent: m.isImageContent }); + }); + setMessages(messages); } catch (e) { props.toasts.toast('error', 'Failed to load chat history'); } } - const refreshSessions = async () => { - const sessions = await props.getSessionsByUser(props.address); + const refreshSessions = async (models = null) => { + const sessions = (await props.getSessionsByUser(props.address)).reduce((res, item) => { + const sessionModel = (models || chainData.models).find(x => x.Id == item.ModelAgentId); + if (sessionModel) { + item.ModelName = sessionModel.Name; + res.push(item); + } + return res; + }, []); + setSessions(sessions); + return sessions; } const closeSession = async (sessionId: string) => { + setIsLoading(true); await props.closeSession(sessionId); await refreshSessions(); + setIsLoading(false); if (activeSession.Id == sessionId) { - const localModel = (chainData?.models?.find((m: any) => m.hasLocal)); + const localModel = (chainData?.models?.find((m: any) => m.isLocal)); if (localModel) { setSelectedModel(localModel); - setChat({ id: makeId(16), createdAt: new Date(), modelId: localModel.Id, isLocal: true }); + setChat({ id: generateHashId(), createdAt: new Date(), modelId: localModel.Id, isLocal: true }); } setMessages([]); } } - const selectSession = async (sessionData) => { - console.log("select-session", sessionData) + const selectChat = async (chatData: ChatData) => { + console.log("select-session", chatData) - if(!sessionData.modelId) { + const modelId = chatData.modelId; + if (!modelId) { + console.warn("Model ID is missed"); return; } + + const selectedModel = chainData.models.find((m: any) => m.Id == modelId); + setSelectedModel(selectedModel); + setIsReadonly(false); + // toggleDrawer(); - setChat({ ...sessionData}) + setChat({ ...chatData }) - if(sessionData.isLocal) { - await loadHistory(sessionData.id); - return + if (chatData.isLocal) { + await loadChatHistory(chatData.id); + return; } const openSessions = sessions.filter(s => !isClosed(s)); // search open session by model ID - const openSession = openSessions.find(s => s.ModelAgentId == sessionData.modelId); + const openSession = openSessions.find(s => s.ModelAgentId == modelId); setIsReadonly(!openSession); - const selectedModel = chainData.models.find((m: any) => m.Id == sessionData.modelId); - setSelectedModel(selectedModel); - - if(openSession) { + if (openSession) { setActiveSession(openSession); const activeBid = selectedModel.bids.find((b) => b.Id == openSession.BidID); setSelectedBid(activeBid); @@ -249,7 +300,7 @@ const Chat = (props) => { setSelectedBid(undefined); } - await loadHistory(sessionData.id); + await loadChatHistory(chatData.id); setTimeout(() => scrollToBottom("smooth"), 400); } @@ -287,8 +338,6 @@ const Chat = (props) => { } const call = async (message) => { - const chatHistory = messages.map(m => ({ role: m.role, content: m.text, isImageContent: m.isImageContent })) - let memoState = [...messages, { id: makeId(16), text: value, ...userMessage }]; setMessages(memoState); scrollToBottom(); @@ -301,12 +350,12 @@ const Chat = (props) => { } else { headers["session_id"] = activeSession.Id; } + headers["chat_id"] = chat?.id; - const hasImageHistory = chatHistory.some(x => x.isImageContent); const incommingMessage = { role: "user", content: message }; const payload = { stream: true, - messages: hasImageHistory ? [incommingMessage] : [...chatHistory, incommingMessage] + messages: [incommingMessage] }; // If image take only last message @@ -339,7 +388,8 @@ const Chat = (props) => { const reader = response.body.getReader() registerScrollEvent(true); - const iconProps = { icon: modelName.toUpperCase()[0], color: getColor(modelName.toUpperCase()[0]) }; + const icon = modelName.toUpperCase()[0]; + const iconProps = { icon, color: getColor(icon) }; try { while (true) { if (abort) { @@ -356,10 +406,20 @@ const Chat = (props) => { const decodedString = textDecoder.decode(value, { stream: true }); const parts = parseDataChunk(decodedString); parts.forEach(part => { + if (!part) { + return; + } + if (part.error) { console.warn(part.error); return; } + + if (typeof part === 'string') { + handleSystemMessage(part); + return; + } + const imageContent = part.imageUrl; if (!part?.id && !imageContent) { @@ -383,17 +443,38 @@ const Chat = (props) => { } } catch (e) { + props.toasts.toast('error', 'Something goes wrong. Try later.'); console.error(e); } - console.log("Flush to storage"); - await props.client.saveChatHistory({ sessionId: chat?.id, messages: memoState }); - console.log("Stored succesfully"); - registerScrollEvent(false); return memoState; } + const handleSystemMessage = (message) => { + const openSessionEventMessage = "new session opened"; + const failoverTurnOnMessage = "provider failed, failover enabled" + + const renderMessage = (value) => { + props.toasts.toast('info', value, { + autoClose: 1500 + }); + } + + if (message.includes(openSessionEventMessage)) { + const sessionId = message.split(":")[1].trim(); // new session opened: 0x123456 + setSessionData(sessionId).catch((err) => renderMessage(`Failed to load session data: ${err.message}`)); + renderMessage("Opening session with available provider..."); + return; + } + if (message.includes(failoverTurnOnMessage)) { + renderMessage("Target provider unavailable. Applying failover policy..."); + return; + } + renderMessage(message); + return; + } + const handleSubmit = () => { if (abort) { abort = false; @@ -409,11 +490,9 @@ const Chat = (props) => { return; } - if (messages.length === 0) { - const title = { ...chat, sessionId: chat?.id, title: value }; - props.client.saveTitle(title).then(() => { - setSessionTitles([...sessionTitles, title]); - }).catch(console.error); + if (messages.length === 0 && chat) { + const title = { ...chat, title: value }; + setChatsData([...chatData, title]); } setIsSpinning(true); @@ -421,10 +500,10 @@ const Chat = (props) => { setValue(""); } - const deleteChatEntry = (id) => { - props.client.deleteTitle(id).then(() => { - const newSessions = sessionTitles.filter(x => x.sessionId != id); - setSessionTitles(newSessions); + const deleteChatEntry = (id: string) => { + props.client.deleteChatHistory(id).then(() => { + const newChats = chatData.filter(x => x.id != id); + setChatsData(newChats); }).catch(console.error); } @@ -440,7 +519,7 @@ const Chat = (props) => { setActiveSession(undefined); setSelectedBid(undefined); setIsReadonly(false); - setChat({ id: makeId(16), createdAt: new Date(), modelId, isLocal }); + setChat({ id: generateHashId(), createdAt: new Date(), modelId, isLocal }); const selectedModel = chainData.models.find((m: any) => m.Id == modelId); setSelectedModel(selectedModel); @@ -463,14 +542,14 @@ const Chat = (props) => { return; } - const prices = selectedModel.bids.map(x => x.PricePerSecond); - const maxPrice = Math.max(prices); + const prices = selectedModel.bids.map(x => Number(x.PricePerSecond)); + const maxPrice = Math.max(...prices); setRequiredStake({ min: calculateStake(maxPrice, 5), max: calculateStake(maxPrice, 24 * 60) }) } const wrapChangeTitle = async (data: { id, title }) => { - await props.client.updateChatTitle(data); + await props.client.updateChatHistoryTitle(data); } return ( @@ -490,11 +569,11 @@ const Chat = (props) => { @@ -531,7 +610,7 @@ const Chat = (props) => { } - setOpenChangeModal(true)}> New chat @@ -617,15 +696,15 @@ const Chat = (props) => { minRows={1} maxRows={6} /> { - isReadonly - ? ( - {isSpinning ? : Reopen} - ) - : ( - { - isSpinning ? : - } - ) + isReadonly + ? ( + {isSpinning ? : Reopen} + ) + : ( + { + isSpinning ? : + } + ) } 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..2a544a82 100644 --- a/ui-desktop/src/renderer/src/components/chat/ChatHistory.styles.tsx +++ b/ui-desktop/src/renderer/src/components/chat/ChatHistory.styles.tsx @@ -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; diff --git a/ui-desktop/src/renderer/src/components/chat/ChatHistory.tsx b/ui-desktop/src/renderer/src/components/chat/ChatHistory.tsx index a2f41f3e..3a06773f 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; + onCloseSession: (id: string) => void; + onSelectChat: (chat: ChatData) => void; refreshSessions: () => void; - deleteHistory: (string) => void - onChangeTitle: (data: { id, title }) => 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,14 +33,14 @@ 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 ? ( @@ -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(); @@ -92,26 +93,31 @@ export const ChatHistory = (props: ChatHistoryProps) => { 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,8 +143,8 @@ 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 filterdModels = props.chatData && search ? props.chatData.filter(m => m.title?.includes(search)) : (props.chatData || []); + const groupedItems = getGroupHistory(filterdModels); return ( @@ -146,7 +152,7 @@ export const ChatHistory = (props: ChatHistoryProps) => { @@ -199,23 +205,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 +228,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..e8d31bb0 --- /dev/null +++ b/ui-desktop/src/renderer/src/components/chat/interfaces.tsx @@ -0,0 +1,48 @@ +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; +} + +export interface ChatHistoryInterface { + title: string; + modelId: string; + messages: ChatMessage[]; +} + +export interface ChatMessage { + response: string; + prompt: ChatPrompt; + promptAt: number; + responseAt: number; + isImageContent?: 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..c03543a2 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,8 +98,13 @@ 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 = (() => { + if(!bids?.length) { + return new Date(); + } + return bids.map(b => new Date(b.ProviderData?.availabilityUpdatedAt ?? new Date()))[0]; + })(); const [selected, changeSelected] = useState(); const [useSelect, setUseSelect] = useState(); @@ -121,13 +132,13 @@ function ModelRow(props) { return `${formatSmallNumber(targetBid?.PricePerSecond / (10 ** 18))} MOR`; } - 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`; } - 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` } @@ -135,9 +146,13 @@ function ModelRow(props) { return ( - {props?.model?.Name} + { props?.model?.Name } + { + !props?.model?.isOnline && + + } - + { useSelect ?
@@ -158,32 +173,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..171bc148 100644 --- a/ui-desktop/src/renderer/src/components/chat/modals/ModelSelectionModal.tsx +++ b/ui-desktop/src/renderer/src/components/chat/modals/ModelSelectionModal.tsx @@ -47,7 +47,11 @@ const ModelSelectionModal = ({ isActive, handleClose, models, onChangeModel }) = handleClose(); } - const filterdModels = search ? models.filter(m => m.Name.includes(search)) : models; + const sortedModels = models + .map(m => ({ ...m, isOnline: m.isLocal || m.bids.some(b => b.ProviderData?.availabilityStatus != "disconnected") })) + .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 diff --git a/ui-desktop/src/renderer/src/components/chat/utils.js b/ui-desktop/src/renderer/src/components/chat/utils.js index f9958281..2d426041 100644 --- a/ui-desktop/src/renderer/src/components/chat/utils.js +++ b/ui-desktop/src/renderer/src/components/chat/utils.js @@ -12,6 +12,11 @@ export const makeId = (length) => { 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/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..16ecfb23 100644 --- a/ui-desktop/src/renderer/src/components/dashboard/Dashboard.jsx +++ b/ui-desktop/src/renderer/src/components/dashboard/Dashboard.jsx @@ -9,13 +9,40 @@ import TransactionModal from './tx-modal' import TxList from './tx-list/TxList' import { View } from '../common/View' import { toUSD } from '../../store/utils/syncAmounts'; +import { + BtnAccent, -const Container = styled.div` - background-color: ${(p) => p.theme.colors.light}; - height: 100vh; - max-width: 100vw; - position: relative; - padding: 0 2.4rem; +} from './BalanceBlock.styles'; + +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; + background-color: #fff; + padding: 1.6rem 3.2rem; + border-radius: 0.375rem; + color: white; + max-width: 720px; + background: rgba(255,255,255,0.04); + border-width: 1px; + border: 1px solid rgba(255,255,255,0.04); + color: white; +` + +const StakingWidjet = styled(WidjetItem)` + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; ` const Dashboard = ({ @@ -29,6 +56,7 @@ const Dashboard = ({ getBalances, ethCoinPrice, loadTransactions, + getStakedFunds, ...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...") @@ -134,10 +166,35 @@ const Dashboard = ({ onTabSwitch={onTabSwitch} /> + + +
+ Staked Balance +
+
{staked} MOR
+
+ + window.openLink(`https://sepolia.arbiscan.io/address/${address}`)} + 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/models/FileSelectionModal.tsx b/ui-desktop/src/renderer/src/components/models/FileSelectionModal.tsx new file mode 100644 index 00000000..126ffff2 --- /dev/null +++ b/ui-desktop/src/renderer/src/components/models/FileSelectionModal.tsx @@ -0,0 +1,105 @@ +//import Modal from '../../contracts/modals/Modal'; +import { List as RVList } from 'react-virtualized'; +import Modal from '../contracts/modals/Modal'; +import styled from 'styled-components'; +import { + TitleWrapper, + Title, + RightBtn +} from '../contracts/modals/CreateContractModal.styles'; +import { useState } from 'react'; +import Form from 'react-bootstrap/Form'; +import { Sp } from '../common' + +const bodyProps = { + height: '750px', + width: '70%', + maxWidth: '100%', + overflow: 'hidden', + onClick: e => e.stopPropagation() +} +const RVContainer = styled(RVList)` + .ReactVirtualized__Grid__innerScrollContainer { + overflow: visible !important; + }` + +const RowContainer = styled.div` + padding: 1rem; + border: 1px solid; + background-color: rgba(0,0,0,0.4); + margin-bottom: 1rem; + ` + +const FileSelectionModal = ({ isActive, handleClose }) => { + + if (!isActive) { + return <>; + } + + const [files, setFiles] = useState([]); + + const openSelectionModal = () => { + return new Promise(resolve => { + let input = document.createElement('input'); + input.type = 'file'; + input.multiple = true; + + input.onchange = () => { + const files = Array.from(input.files as any); + setFiles(files) + ; + }; + + input.click(); + }); + } + + + return ( + { + handleClose(); + }} + bodyProps={bodyProps} + > + + Select Files + + + + + Set desired model name + + + + + + Select files required to run model (including .gguf) + { + setFiles(Object.values((e.currentTarget as any).files)) + })} /> + + + + { + !files.length ? null : + ( + files.map(f => { + return +
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..4ee05a83 100644 --- a/ui-desktop/src/renderer/src/components/models/Models.tsx +++ b/ui-desktop/src/renderer/src/components/models/Models.tsx @@ -1,11 +1,55 @@ +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'; + + +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); + } +` export const Models = () => { - return ( - - - - ) -} \ No newline at end of file + + const [openChangeModal, setOpenChangeModal] = useState(false); + + return ( + + + setOpenChangeModal(true)}>Pin Model + + + + + + + + + + + + + setOpenChangeModal(false)} /> + ) + +} 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/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/tools/common.jsx b/ui-desktop/src/renderer/src/components/tools/common.jsx index 73a094df..bfd2fd3f 100644 --- a/ui-desktop/src/renderer/src/components/tools/common.jsx +++ b/ui-desktop/src/renderer/src/components/tools/common.jsx @@ -49,9 +49,9 @@ export const StyledParagraph = styled.p` export const Input = styled(TextInput)` outline: 0; - border: 0px; - background: #eaf7fc; - border-radius: 15px; + border: 1px solid ${p => p.theme.colors.morMain}; + background: transparent; + border-radius: 5px; padding: 1.2rem 1.2rem; margin-top: 0.25rem; `; diff --git a/ui-desktop/src/renderer/src/store/hocs/withChatState.jsx b/ui-desktop/src/renderer/src/store/hocs/withChatState.jsx index 8aca8bc3..0d321385 100644 --- a/ui-desktop/src/renderer/src/store/hocs/withChatState.jsx +++ b/ui-desktop/src/renderer/src/store/hocs/withChatState.jsx @@ -1,11 +1,16 @@ -import * as validators from '../validators'; import { withClient } from './clientContext'; -import * as utils from '../utils'; import { connect } from 'react-redux'; -import PropTypes from 'prop-types'; import React from 'react'; import { ToastsContext } from '../../components/toasts'; import selectors from '../selectors'; +import axios from 'axios'; +import { getSessionsByUser } from '../utils/apiCallsHelper'; + +const AvailabilityStatus = { + available: "available", + unknown: "unknown", + disconnected: "disconnected" +} const withChatState = WrappedComponent => { class Container extends React.Component { @@ -129,6 +134,17 @@ const withChatState = WrappedComponent => { const models = modelsResp.filter(m => !m.IsDeleted); const providers = providersResp.filter(m => !m.IsDeleted); + + const availabilityResults = await this.getProvidersAvailability(providers); + availabilityResults.forEach(ar => { + const provider = providers.find(p => p.Address == ar.id); + if(!provider) + return; + + provider.availabilityStatus = ar.status; + provider.availabilityUpdatedAt = ar.time; + }); + const providersMap = providers.reduce((a, b) => ({ ...a, [b.Address.toLowerCase()]: b }), {}); const responses = (await Promise.all( @@ -136,23 +152,59 @@ const withChatState = WrappedComponent => { const id = m.Id; const bids = (await this.getBidsByModels(id)) .filter(b => +b.DeletedAt === 0) - .map(b => ({ ...b, ProviderData: providersMap[b.Provider.toLowerCase()], Model: m })); + .map(b => ({ ...b, ProviderData: providersMap[b.Provider.toLowerCase()], Model: m })) + .filter(b => b.ProviderData); return { id, bids } }) )).reduce((a,b) => ({...a, [b.id]: b.bids}), {}); - const result = []; + const result = [...localModels.map(m => ({...m, isLocal: true }))]; for (const model of models) { const id = model.Id; const bids = responses[id]; - const localModel = localModels.find(lm => lm.Id == id); + if(!bids.length) { + continue; + } - result.push({ ...model, bids, hasLocal: Boolean(localModel) }) + result.push({ ...model, bids }) } - return { models: result.filter(r => r.bids.length || r.hasLocal), providers } + return { models: result, providers } + } + + getProvidersAvailability = async (providers) => { + const availabilityResults = await Promise.all(providers.map(async p => { + try { + const storedRecord = JSON.parse(localStorage.getItem(p.Address)); + if(storedRecord && storedRecord.status == AvailabilityStatus.available) { + const lastUpdatedAt = new Date(storedRecord.time); + const cacheMinutes = 15; + const timestampBefore = new Date(new Date().getTime() - (cacheMinutes * 60 * 1000)); + + if(lastUpdatedAt > timestampBefore) { + return ({...storedRecord, id: p.Address}); + } + } + + const endpoint = p.Endpoint; + const [domain, port] = endpoint.split(":"); + const { data } = await axios.post("https://portchecker.io/api/v1/query", { + host: domain, + ports: [port], + }); + + const isValid = !!data.check?.find((c) => c.port == port && c.status == true); + const record = ({id: p.Address, status: isValid ? AvailabilityStatus.available : AvailabilityStatus.disconnected, time: new Date() }); + localStorage.setItem(record.id, JSON.stringify({ status: record.status, time: record.time })); + return record; + } + catch(e) { + return ({id: p.Address, status: AvailabilityStatus.unknown, time: new Date() }) + } + })); + return availabilityResults; } getMetaInfo = async () => { @@ -166,23 +218,18 @@ const withChatState = WrappedComponent => { if(!user) { return; } - try { - const path = `${this.props.config.chain.localProxyRouterUrl}/blockchain/sessions?user=${user}`; - const response = await fetch(path); - const data = await response.json(); - return data.sessions; - } - catch (e) { - console.log("Error", e) - return []; - } + + return await getSessionsByUser(this.props.config.chain.localProxyRouterUrl, user); } onOpenSession = async ({ modelId, duration }) => { this.context.toast('info', 'Processing...'); try { + const failoverSettings = await this.props.client.getFailoverSetting(); + const path = `${this.props.config.chain.localProxyRouterUrl}/blockchain/models/${modelId}/session`; const body = { + failover: failoverSettings?.isEnabled || false, sessionDuration: +duration // convert to seconds }; const response = await fetch(path, { diff --git a/ui-desktop/src/renderer/src/store/hocs/withDashboardState.jsx b/ui-desktop/src/renderer/src/store/hocs/withDashboardState.jsx index 3ef96655..5f8d58d5 100644 --- a/ui-desktop/src/renderer/src/store/hocs/withDashboardState.jsx +++ b/ui-desktop/src/renderer/src/store/hocs/withDashboardState.jsx @@ -4,6 +4,7 @@ import selectors from '../selectors'; import { connect } from 'react-redux'; import PropTypes from 'prop-types'; import { ToastsContext } from '../../components/toasts'; +import { getSessionsByUser } from '../utils/apiCallsHelper'; const withDashboardState = WrappedComponent => { class Container extends React.Component { @@ -45,9 +46,9 @@ const withDashboardState = WrappedComponent => { }); }; - loadTransactions = async (page = 0, pageSize = 15) => { + loadTransactions = async (page = 1, pageSize = 15) => { this.setState({ refreshStatus: 'pending', refreshError: null }); - const transactions = await this.props.client.getTransactions(page, pageSize); + const transactions = await this.props.client.getTransactions({ page, pageSize }); this.setState({ refreshStatus: 'success' }) // if (page && pageSize) { @@ -60,6 +61,26 @@ const withDashboardState = WrappedComponent => { return transactions; } + getStakedFunds = async (user) => { + const isClosed = (item) => item.ClosedAt || (new Date().getTime() > item.EndsAt * 1000); + + if(!user) { + return; + } + + const sessions = await getSessionsByUser(this.props.config.chain.localProxyRouterUrl, user); + + try { + const openSessions = sessions.filter(s => !isClosed(s)); + const sum = openSessions.reduce((curr, next) => curr + next.Stake, 0); + return (sum / 10 ** 18).toFixed(2); + } + catch (e) { + console.log("Error", e) + return 0; + } + } + getBalances = async () => { const balances = await this.props.client.getBalances(); const rate = await this.props.client.getRates(); @@ -84,6 +105,7 @@ const withDashboardState = WrappedComponent => { getBalances={this.getBalances} sendDisabled={sendLmrFeatureStatus !== 'ok'} loadTransactions={this.loadTransactions} + getStakedFunds={this.getStakedFunds} {...this.props} {...this.state} /> @@ -92,6 +114,7 @@ const withDashboardState = WrappedComponent => { } const mapStateToProps = state => ({ + config: state.config, syncStatus: selectors.getTxSyncStatus(state), sendLmrFeatureStatus: selectors.sendLmrFeatureStatus(state), hasTransactions: selectors.hasTransactions(state), diff --git a/ui-desktop/src/renderer/src/store/hocs/withOnboardingState.jsx b/ui-desktop/src/renderer/src/store/hocs/withOnboardingState.jsx index ef7a9881..c4c02b43 100644 --- a/ui-desktop/src/renderer/src/store/hocs/withOnboardingState.jsx +++ b/ui-desktop/src/renderer/src/store/hocs/withOnboardingState.jsx @@ -7,6 +7,7 @@ import * as utils from '../utils'; import { toRfc2396, generatePoolUrl } from '../../utils'; const EMAIL_REGEX = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/; +const UrlRegex = /\b(?:http|ws)s?:\/\/\S*[^\s."]/g; const withOnboardingState = WrappedComponent => { class Container extends React.Component { @@ -36,11 +37,13 @@ const withOnboardingState = WrappedComponent => { passwordAgain: null, mnemonicAgain: null, userMnemonic: null, + userPrivateKey: null, + derivationPath: null, + customEthNode: null, password: null, mnemonic: null, - proxyDefaultPool: null, - lightningAddress: null, - isTitanLightning: true, + useImportFlow: false, + useEthStep: false, errors: {} }; @@ -58,7 +61,7 @@ const withOnboardingState = WrappedComponent => { } }; - onPasswordSubmit = ({ clearOnError = false }) => { + onPasswordSubmit = ({ clearOnError = false, useImportFlow = false }) => { const { password, passwordAgain } = this.state; const errors = validators.validatePasswordCreation( @@ -82,7 +85,7 @@ const withOnboardingState = WrappedComponent => { }); return; } - this.setState({ isPasswordDefined: true }); + this.setState({ isPasswordDefined: true, useImportFlow }); }; onUseUserMnemonicToggled = () => { @@ -130,6 +133,13 @@ const withOnboardingState = WrappedComponent => { this.onFinishOnboarding(); }; + onPrivateKeyAccepted = e => { + if (e && e.preventDefault) e.preventDefault(); + + this.setState({ isMnemonicVerified: true, useEthStep: true }); + } + + validateDefaultPoolAddress() { const errors = validators.validatePoolAddress( this.state.proxyDefaultPool @@ -142,16 +152,26 @@ const withOnboardingState = WrappedComponent => { return true; } - // HERE - onFinishOnboarding = e => { + onFinishOnboarding = async (e) => { if (e && e.preventDefault) e.preventDefault(); - - return this.props.onOnboardingCompleted({ + + const payload = { password: this.state.password, - mnemonic: this.state.useUserMnemonic - ? utils.sanitizeMnemonic(this.state.userMnemonic) - : this.state.mnemonic - }); + ethNode: this.state.customEthNode || '', + derivationPath: this.state.derivationPath || "0", + privateKey: '' + }; + + if(this.state.userPrivateKey) { + payload.privateKey = this.state.userPrivateKey; + } + else { + payload.mnemonic = this.state.useUserMnemonic + ? utils.sanitizeMnemonic(this.state.userMnemonic) + : this.state.mnemonic; + } + + await this.props.onOnboardingCompleted(payload); }; onRunWithoutProxyRouter = e => { @@ -166,6 +186,28 @@ const withOnboardingState = WrappedComponent => { }); }; + onSuggestAddress = async () => { + const addrs = await this.props.client.suggestAddresses(this.state.userMnemonic); + return addrs; + } + + onMnemonicSet = async (e, path) => { + if (e && e.preventDefault) e.preventDefault(); + + this.setState({...this.state, useUserMnemonic: true, derivationPath: path, useEthStep: true }) + } + + onEthNodeSet = async (e) => { + if(this.state.customEthNode && !UrlRegex.test(this.state.customEthNode)) { + const errors = this.state.errors; + errors.customEthNode = "Url format is not valid" + this.setState({ errors }); + } + else { + await this.onFinishOnboarding(e); + } + } + onInputChange = ({ id, value }) => { this.setState(state => ({ ...state, @@ -180,9 +222,11 @@ const withOnboardingState = WrappedComponent => { getCurrentStep() { if (!this.state.areTermsAccepted) return 'ask-for-terms'; if (!this.state.isPasswordDefined) return 'define-password'; + if (this.state.useEthStep) return 'set-custom-eth'; if (this.state.isMnemonicVerified) return 'config-proxy-router'; if (this.state.useUserMnemonic) return 'recover-from-mnemonic'; if (this.state.isMnemonicCopied) return 'verify-mnemonic'; + if (this.state.useImportFlow) return 'import-flow'; return 'copy-mnemonic'; } @@ -210,7 +254,11 @@ const withOnboardingState = WrappedComponent => { shouldSubmit={shouldSubmit} currentStep={this.getCurrentStep()} getTooltip={getTooltip} + onSuggestAddress={this.onSuggestAddress} onRunWithoutProxyRouter={this.onRunWithoutProxyRouter} + onPrivateKeyAccepted={this.onPrivateKeyAccepted} + onMnemonicSet={this.onMnemonicSet} + onEthNodeSet={this.onEthNodeSet} {...this.state} /> ); diff --git a/ui-desktop/src/renderer/src/store/hocs/withProvidersState.jsx b/ui-desktop/src/renderer/src/store/hocs/withProvidersState.jsx index fc9029a2..3fba485d 100644 --- a/ui-desktop/src/renderer/src/store/hocs/withProvidersState.jsx +++ b/ui-desktop/src/renderer/src/store/hocs/withProvidersState.jsx @@ -35,7 +35,7 @@ const withProvidersState = WrappedComponent => { getSessionsByProvider = async (provider) => { try { - const path = `${this.props.config.chain.localProxyRouterUrl}/blockchain/sessions?provider=${provider}`; + const path = `${this.props.config.chain.localProxyRouterUrl}/blockchain/sessions/provider?provider=${provider}`; const response = await fetch(path); const data = await response.json(); return data.sessions; diff --git a/ui-desktop/src/renderer/src/store/hocs/withSettingsState.jsx b/ui-desktop/src/renderer/src/store/hocs/withSettingsState.jsx index 06fb1c09..57d2a7c9 100644 --- a/ui-desktop/src/renderer/src/store/hocs/withSettingsState.jsx +++ b/ui-desktop/src/renderer/src/store/hocs/withSettingsState.jsx @@ -19,11 +19,56 @@ const withSettingsState = WrappedComponent => { return this.props.client.logout(); }; + getConfig = async () => { + try { + const path = `${this.props.config.chain.localProxyRouterUrl}/config`; + const response = await fetch(path); + const data = await response.json(); + return data; + } + catch (e) { + console.log("Error", e) + return []; + } + } + + updateEthNodeUrl = async (value) => { + if(!value) + return; + + if(!/\b(?:http|ws)s?:\/\/\S*[^\s."]/g.test(value)) { + this.context.toast('error', "Invalid format"); + return; + } + + const ethNodeResult = await fetch(`${this.props.config.chain.localProxyRouterUrl}/config/ethNode`, { + method: 'POST', + body: JSON.stringify({ urls: [value] }) + }) + + const dataResponse = await ethNodeResult.json(); + if (dataResponse.error) { + this.context.toast('error', dataResponse.error); + return; + } + + this.context.toast('success', "Changed"); + } + + updateFailoverSetting = async (value) => { + await this.props.client.setFailoverSetting(value); + this.context.toast('success', "Setting changed") + } + + render() { return ( diff --git a/ui-desktop/src/renderer/src/store/utils/apiCallsHelper.tsx b/ui-desktop/src/renderer/src/store/utils/apiCallsHelper.tsx new file mode 100644 index 00000000..f2c71265 --- /dev/null +++ b/ui-desktop/src/renderer/src/store/utils/apiCallsHelper.tsx @@ -0,0 +1,39 @@ +export const getSessionsByUser = async (url, user) => { + if(!user || !url) { + return; + } + + const getSessions = async (user, offset, limit) => { + try { + const path = `${url}/blockchain/sessions/user?user=${user}&offset=${offset}&limit=${limit}`; + const response = await fetch(path); + const data = await response.json(); + return data.sessions; + } + catch (e) { + console.log("Error", e) + return []; + } + } + + + const limit = 50; + let offset = 0; + let sessions: any[] = []; + let all = false; + + while (!all) { + console.log("Getting session for user: ", user, offset, limit) + const sessionsRes = await getSessions(user, offset, limit); + sessions.push(...sessionsRes); + + if(sessionsRes.length != limit) { + all = true; + } + else { + offset++; + } + } + + return sessions; + } \ No newline at end of file diff --git a/ui-desktop/src/renderer/src/termsAndConditions.md b/ui-desktop/src/renderer/src/termsAndConditions.md index b266e3a6..010c4794 100644 --- a/ui-desktop/src/renderer/src/termsAndConditions.md +++ b/ui-desktop/src/renderer/src/termsAndConditions.md @@ -1,4 +1,4 @@ -# Lumerin Terms of Use +# Morpheus Terms of Use Last Updated Date: March 16, 2023