From 365a6f53fc587bf624f3768e71ef15f7d14e4c0b Mon Sep 17 00:00:00 2001
From: Iulian Pascalau
Date: Sun, 1 Feb 2026 19:23:54 +0200
Subject: [PATCH 1/8] - removed contract, adjusted code changes to integrate
the contract
---
.github/workflows/check-contract-build.yml | 34 -
.github/workflows/rs-tests.yml | 36 -
integrationTests/go/cryptoPayment_test.go | 4 +-
integrationTests/go/framework/common.go | 2 +-
.../go/framework/cryptoPaymentService.go | 2 +-
requests-contract/.gitignore | 18 -
requests-contract/AUDIT_AND_SPECS.md | 106 --
requests-contract/Cargo.lock | 1187 -----------------
requests-contract/Cargo.toml | 15 -
requests-contract/build_reproducible.sh | 28 -
requests-contract/build_with_docker.py | 120 --
requests-contract/meta/Cargo.lock | 785 -----------
requests-contract/meta/Cargo.toml | 12 -
requests-contract/meta/src/main.rs | 3 -
requests-contract/multiversx.json | 3 -
requests-contract/mxsc-template.toml | 25 -
requests-contract/output/artifacts.json | 26 -
.../requests/requests-0.0.0.source.json | 106 --
.../output/requests/requests.abi.json | 230 ----
.../output/requests/requests.codehash.txt | 1 -
.../output/requests/requests.imports.json | 36 -
.../output/requests/requests.mxsc.json | 282 ----
.../output/requests/requests.wasm | Bin 4009 -> 0 bytes
requests-contract/sc-config.toml | 4 -
.../add_requests_accumulation.scen.json | 107 --
.../scenarios/add_requests_multiple.scen.json | 111 --
.../scenarios/add_requests_single.scen.json | 86 --
.../add_requests_when_paused.scen.json | 73 -
.../scenarios/change_rate_non_owner.scen.json | 57 -
.../scenarios/change_rate_valid.scen.json | 94 --
.../scenarios/change_rate_zero.scen.json | 53 -
.../scenarios/full_workflow.scen.json | 177 ---
.../scenarios/get_requests_existing.scen.json | 73 -
.../get_requests_nonexistent.scen.json | 51 -
.../scenarios/init_valid.scen.json | 42 -
.../scenarios/init_zero.scen.json | 40 -
.../scenarios/pause_already_paused.scen.json | 66 -
.../scenarios/pause_non_owner.scen.json | 55 -
.../scenarios/pause_success.scen.json | 61 -
.../pause_unpause_workflow.scen.json | 151 ---
.../rate_change_affects_future.scen.json | 124 --
.../scenarios/unpause_non_owner.scen.json | 70 -
.../scenarios/unpause_not_paused.scen.json | 51 -
.../scenarios/unpause_success.scen.json | 76 --
.../scenarios/withdraw_empty.scen.json | 51 -
.../scenarios/withdraw_non_owner.scen.json | 77 --
.../scenarios/withdraw_success.scen.json | 72 -
requests-contract/scripts/change-price.sh | 8 -
requests-contract/scripts/config.cfg | 15 -
requests-contract/scripts/contract-deploy.sh | 10 -
requests-contract/scripts/pause-contract.sh | 7 -
requests-contract/scripts/unpause-contract.sh | 7 -
requests-contract/scripts/withdraw-all.sh | 7 -
requests-contract/src/lib.rs | 181 ---
requests-contract/tests/scenarios_rs_test.rs | 124 --
requests-contract/wasm/Cargo.lock | 223 ----
requests-contract/wasm/Cargo.toml | 34 -
requests-contract/wasm/src/lib.rs | 28 -
.../crypto-payment/process/accountHandler.go | 4 +-
.../process/accountHandler_test.go | 20 +-
.../crypto-payment/process/configHandler.go | 4 +-
.../process/configHandler_test.go | 6 +-
.../process/contractQueryHandler.go | 30 +-
.../process/contractQueryHandler_test.go | 24 +-
services/crypto-payment/process/interface.go | 4 +-
.../testsCommon/contractHandlerStub.go | 22 +-
66 files changed, 61 insertions(+), 5580 deletions(-)
delete mode 100644 .github/workflows/check-contract-build.yml
delete mode 100644 .github/workflows/rs-tests.yml
delete mode 100644 requests-contract/.gitignore
delete mode 100644 requests-contract/AUDIT_AND_SPECS.md
delete mode 100644 requests-contract/Cargo.lock
delete mode 100644 requests-contract/Cargo.toml
delete mode 100755 requests-contract/build_reproducible.sh
delete mode 100644 requests-contract/build_with_docker.py
delete mode 100644 requests-contract/meta/Cargo.lock
delete mode 100644 requests-contract/meta/Cargo.toml
delete mode 100644 requests-contract/meta/src/main.rs
delete mode 100644 requests-contract/multiversx.json
delete mode 100644 requests-contract/mxsc-template.toml
delete mode 100644 requests-contract/output/artifacts.json
delete mode 100644 requests-contract/output/requests/requests-0.0.0.source.json
delete mode 100644 requests-contract/output/requests/requests.abi.json
delete mode 100644 requests-contract/output/requests/requests.codehash.txt
delete mode 100644 requests-contract/output/requests/requests.imports.json
delete mode 100644 requests-contract/output/requests/requests.mxsc.json
delete mode 100755 requests-contract/output/requests/requests.wasm
delete mode 100644 requests-contract/sc-config.toml
delete mode 100644 requests-contract/scenarios/add_requests_accumulation.scen.json
delete mode 100644 requests-contract/scenarios/add_requests_multiple.scen.json
delete mode 100644 requests-contract/scenarios/add_requests_single.scen.json
delete mode 100644 requests-contract/scenarios/add_requests_when_paused.scen.json
delete mode 100644 requests-contract/scenarios/change_rate_non_owner.scen.json
delete mode 100644 requests-contract/scenarios/change_rate_valid.scen.json
delete mode 100644 requests-contract/scenarios/change_rate_zero.scen.json
delete mode 100644 requests-contract/scenarios/full_workflow.scen.json
delete mode 100644 requests-contract/scenarios/get_requests_existing.scen.json
delete mode 100644 requests-contract/scenarios/get_requests_nonexistent.scen.json
delete mode 100644 requests-contract/scenarios/init_valid.scen.json
delete mode 100644 requests-contract/scenarios/init_zero.scen.json
delete mode 100644 requests-contract/scenarios/pause_already_paused.scen.json
delete mode 100644 requests-contract/scenarios/pause_non_owner.scen.json
delete mode 100644 requests-contract/scenarios/pause_success.scen.json
delete mode 100644 requests-contract/scenarios/pause_unpause_workflow.scen.json
delete mode 100644 requests-contract/scenarios/rate_change_affects_future.scen.json
delete mode 100644 requests-contract/scenarios/unpause_non_owner.scen.json
delete mode 100644 requests-contract/scenarios/unpause_not_paused.scen.json
delete mode 100644 requests-contract/scenarios/unpause_success.scen.json
delete mode 100644 requests-contract/scenarios/withdraw_empty.scen.json
delete mode 100644 requests-contract/scenarios/withdraw_non_owner.scen.json
delete mode 100644 requests-contract/scenarios/withdraw_success.scen.json
delete mode 100755 requests-contract/scripts/change-price.sh
delete mode 100644 requests-contract/scripts/config.cfg
delete mode 100755 requests-contract/scripts/contract-deploy.sh
delete mode 100755 requests-contract/scripts/pause-contract.sh
delete mode 100755 requests-contract/scripts/unpause-contract.sh
delete mode 100755 requests-contract/scripts/withdraw-all.sh
delete mode 100644 requests-contract/src/lib.rs
delete mode 100644 requests-contract/tests/scenarios_rs_test.rs
delete mode 100644 requests-contract/wasm/Cargo.lock
delete mode 100644 requests-contract/wasm/Cargo.toml
delete mode 100644 requests-contract/wasm/src/lib.rs
diff --git a/.github/workflows/check-contract-build.yml b/.github/workflows/check-contract-build.yml
deleted file mode 100644
index 16a3ca6..0000000
--- a/.github/workflows/check-contract-build.yml
+++ /dev/null
@@ -1,34 +0,0 @@
-name: Check Contract Build
-
-on:
- push:
- branches: [ main, rc/*, feat/* ]
- pull_request:
- branches: [ main, rc/*, feat/* ]
-
-jobs:
- check-build:
- name: Check Reproducible Build
- runs-on: ubuntu-latest
- defaults:
- run:
- working-directory: requests-contract
-
- steps:
- - name: Checkout code
- uses: actions/checkout@v4
-
- - name: Build Contract
- run: |
- chmod +x build_reproducible.sh
- ./build_reproducible.sh
-
- - name: Check for changes
- run: |
- git status --porcelain
- if [ -n "$(git status --porcelain)" ]; then
- echo "Error: The requests-contract/output directory is not up to date."
- echo "Please run ./build_reproducible.sh locally and commit the changes."
- git diff
- exit 1
- fi
diff --git a/.github/workflows/rs-tests.yml b/.github/workflows/rs-tests.yml
deleted file mode 100644
index 39dbc4c..0000000
--- a/.github/workflows/rs-tests.yml
+++ /dev/null
@@ -1,36 +0,0 @@
-name: Rust Tests
-
-on:
- push:
- branches: [ main, rc/*, feat/* ]
- pull_request:
- branches: [ main, rc/*, feat/* ]
-
-jobs:
- test:
- name: Rust Automated Tests
- runs-on: ubuntu-latest
- defaults:
- run:
- working-directory: requests-contract
-
- steps:
- - name: Checkout code
- uses: actions/checkout@v4
-
- - name: Install Rust
- uses: dtolnay/rust-toolchain@stable
-
- - name: Cargo Cache
- uses: actions/cache@v3
- with:
- path: |
- ~/.cargo/bin/
- ~/.cargo/registry/index/
- ~/.cargo/registry/cache/
- ~/.cargo/git/db/
- requests-contract/target/
- key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
-
- - name: Run Tests
- run: cargo test
diff --git a/integrationTests/go/cryptoPayment_test.go b/integrationTests/go/cryptoPayment_test.go
index 2726365..70e208d 100644
--- a/integrationTests/go/cryptoPayment_test.go
+++ b/integrationTests/go/cryptoPayment_test.go
@@ -11,7 +11,7 @@ import (
"github.com/stretchr/testify/require"
)
-const functionGetRequests = "getRequests"
+const functionGetCredits = "getCredits"
var log = logger.GetOrCreate("integrationTests")
@@ -293,7 +293,7 @@ func checkCredits(ctx context.Context, service *framework.CryptoPaymentService,
result := service.ChainSimulator.ExecuteVMQuery(
ctx,
service.ContractAddress,
- functionGetRequests,
+ functionGetCredits,
[]string{
hex.EncodeToString(big.NewInt(int64(id)).Bytes()),
},
diff --git a/integrationTests/go/framework/common.go b/integrationTests/go/framework/common.go
index 3dde0f2..19c8326 100644
--- a/integrationTests/go/framework/common.go
+++ b/integrationTests/go/framework/common.go
@@ -15,7 +15,7 @@ const CallGasLimit = 3000000
func GetContractPath(contractName string) string {
currentDir := traverse("integrationTests")
- return filepath.Join(currentDir, "requests-contract", "output", contractName, contractName+".wasm")
+ return filepath.Join(currentDir, "contracts", contractName, contractName+".wasm")
}
// GetProxyRootPath returns the absolute path to the proxy service root path
diff --git a/integrationTests/go/framework/cryptoPaymentService.go b/integrationTests/go/framework/cryptoPaymentService.go
index ea51327..a105c5c 100644
--- a/integrationTests/go/framework/cryptoPaymentService.go
+++ b/integrationTests/go/framework/cryptoPaymentService.go
@@ -54,7 +54,7 @@ func (crs *CryptoPaymentService) Setup(ctx context.Context, numRequestsPerEGLD i
log.Info("deploying contract")
address, _, txOnNetwork := crs.ChainSimulator.DeploySC(
ctx,
- GetContractPath("requests"),
+ GetContractPath("credits"),
crs.Keys.OwnerKeys.MvxSk,
deployGasLimit,
[]string{
diff --git a/requests-contract/.gitignore b/requests-contract/.gitignore
deleted file mode 100644
index 4d2dff6..0000000
--- a/requests-contract/.gitignore
+++ /dev/null
@@ -1,18 +0,0 @@
-# Rust
-/target/
-
-**/*.rs.bk
-
-# IDE
-.vscode/
-.idea/
-*.swp
-*.swo
-*~
-.DS_Store
-
-# Environment
-.env
-.env.local
-wallet.pem
-*.key
\ No newline at end of file
diff --git a/requests-contract/AUDIT_AND_SPECS.md b/requests-contract/AUDIT_AND_SPECS.md
deleted file mode 100644
index fa3c6cc..0000000
--- a/requests-contract/AUDIT_AND_SPECS.md
+++ /dev/null
@@ -1,106 +0,0 @@
-This document details the specifications and audit results for the `RequestsContract` smart contract designed for the MultiversX blockchain.
-
-## 1. Contract Overview
-
-**Name:** Requests Contract
-**Purpose:** To allow users to purchase "acquired requests" using EGLD based on a configurable exchange rate.
-**Platform:** MultiversX (Rust Framework)
-**Roles:**
-* **Owner:** Has exclusive rights to change the exchange rate, pause/unpause the contract, and withdraw funds.
-* **User:** Can purchase requests by sending EGLD to the `addRequests` endpoint.
-
-## 2. Technical Specifications
-
-### 2.1 Storage Mappers
-* `numRequestsPerEgld` (`SingleValueMapper`): Stores the current exchange rate (requests per 1 EGLD).
-* `acquiredRequests` (`SingleValueMapper`): Map storing the total requests purchased for a specific `id` (u64).
-* `isPaused` (`SingleValueMapper`): Boolean flag indicating if the contract is currently paused.
-
-### 2.2 Endpoints
-
-#### `init`
-* **Input:** `num_requests_per_egld` (BigUint)
-* **Logic:**
- * Sets the initial exchange rate.
- * Initializes `isPaused` to `false`.
- * **Constraint:** `num_requests_per_egld` must be > 0.
-
-#### `upgrade`
-* **Input:** `num_requests_per_egld` (BigUint)
-* **Logic:**
- * Updates the exchange rate.
- * Preserves the existing `isPaused` state if set; otherwise defaults to `false`.
- * **Constraint:** `num_requests_per_egld` must be > 0.
-
-#### `addRequests` (Payable)
-* **Input:** `id` (u64)
-* **Payment:** EGLD
-* **Logic:**
- * Checks if contract is paused.
- * Calculates requests: `(payment_wei * rate) / 10^18`.
- * Updates `acquiredRequests` for the given `id`.
- * Emits `addRequests` event.
- * **Constraints:**
- * Contract must not be paused.
- * Payment > 0.
-
-#### `changeNumRequestsPerEGLD`
-* **Input:** `new_num_requests_per_egld` (BigUint)
-* **Logic:**
- * Updates the exchange rate.
- * Emits `changeNumRequestsPerEGLD` event.
- * **Constraints:**
- * Caller must be Owner.
- * New rate must be > 0.
-
-#### `pause` / `unpause`
-* **Logic:** Toggles the `isPaused` storage.
-* **Constraints:**
- * Caller must be Owner.
- * Cannot pause if already paused (and vice versa).
-
-#### `withdrawAll`
-* **Logic:** Sends entire EGLD balance to the Owner.
-* **Constraints:**
- * Caller must be Owner.
- * Balance > 0.
-
-#### `getRequests` (View)
-* **Input:** `id` (u64)
-* **Output:** Returns the count of requests for the ID.
-
-## 3. Security Audit & Findings
-
-### 3.1 Arithmetic Precision
-* **Status:** **SECURE** (Fixed)
-* **Details:** The contract originally calculated requests as `(amount / 10^18) * rate`, which caused significant precision loss for fractional EGLD amounts. This was patched to `(amount * rate) / 10^18`.
-* **Recommendation:** No further action.
-
-### 3.2 Access Control
-* **Status:** **SECURE**
-* **Details:** Critical functions (`changeNumRequestsPerEGLD`, `pause`, `unpause`, `withdrawAll`) properly enforce `require!(caller == owner)`.
-
-### 3.3 Re-entrancy
-* **Status:** **SECURE**
-* **Details:** The only external call is the EGLD transfer in `withdrawAll` to the owner. Since this is the final step and state variables are not modified after the transfer, re-entrancy risks are minimal.
-
-### 3.4 Logic Constraints
-* **Status:** **SECURE**
-* **Details:**
- * `init` and `upgrade` enforce non-zero rates to prevent division/logic errors.
- * `addRequests` enforces non-zero payments.
- * `pause` mechanism correctly blocks deposits.
-
-### 3.5 Upgrade Safety
-* **Status:** **NOTE**
-* **Details:** The `upgrade` function resets the rate. Owners must be careful to pass the correct (current or new) rate during upgrades to avoid accidental rate changes. It safely handles the `isPaused` flag initialization for older versions of the contract state.
-
-## 4. Recommendations and Improvements
-
-1. **Rate Limiting / Caps (Optional):** Currently, there is no upper limit on the number of requests a single ID can accumulate. If `requests` represent a resource liability, consider adding a cap.
-2. **Event Data:** The `addRequests` event indexes `id` and `egld_amount`. This is good practice. The `requests_added` is also included, allowing full off-chain reconstruction of the state.
-
-## 5. Conclusion
-The `RequestsContract` contains robust logic with appropriate access controls and safeguards. The identification and repair of the arithmetic precision bug was the primary critical finding, which has been resolved and verified via tests.
-
-**Verdict:** The contract is structurally sound and ready for deployment.
diff --git a/requests-contract/Cargo.lock b/requests-contract/Cargo.lock
deleted file mode 100644
index 668b64c..0000000
--- a/requests-contract/Cargo.lock
+++ /dev/null
@@ -1,1187 +0,0 @@
-# This file is automatically @generated by Cargo.
-# It is not intended for manual editing.
-version = 4
-
-[[package]]
-name = "anstream"
-version = "0.6.21"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "43d5b281e737544384e969a5ccad3f1cdd24b48086a0fc1b2a5262a26b8f4f4a"
-dependencies = [
- "anstyle",
- "anstyle-parse",
- "anstyle-query",
- "anstyle-wincon",
- "colorchoice",
- "is_terminal_polyfill",
- "utf8parse",
-]
-
-[[package]]
-name = "anstyle"
-version = "1.0.13"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5192cca8006f1fd4f7237516f40fa183bb07f8fbdfedaa0036de5ea9b0b45e78"
-
-[[package]]
-name = "anstyle-parse"
-version = "0.2.7"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2"
-dependencies = [
- "utf8parse",
-]
-
-[[package]]
-name = "anstyle-query"
-version = "1.1.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc"
-dependencies = [
- "windows-sys 0.61.2",
-]
-
-[[package]]
-name = "anstyle-wincon"
-version = "3.0.11"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d"
-dependencies = [
- "anstyle",
- "once_cell_polyfill",
- "windows-sys 0.61.2",
-]
-
-[[package]]
-name = "anyhow"
-version = "1.0.100"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61"
-
-[[package]]
-name = "arrayvec"
-version = "0.7.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50"
-
-[[package]]
-name = "autocfg"
-version = "1.5.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8"
-
-[[package]]
-name = "base64"
-version = "0.22.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
-
-[[package]]
-name = "base64ct"
-version = "1.8.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2af50177e190e07a26ab74f8b1efbfe2ef87da2116221318cb1c2e82baf7de06"
-
-[[package]]
-name = "bech32"
-version = "0.11.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "32637268377fc7b10a8c6d51de3e7fba1ce5dd371a96e342b34e6078db558e7f"
-
-[[package]]
-name = "bitflags"
-version = "2.9.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd"
-
-[[package]]
-name = "block-buffer"
-version = "0.10.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71"
-dependencies = [
- "generic-array 0.14.7",
-]
-
-[[package]]
-name = "bumpalo"
-version = "3.19.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5dd9dc738b7a8311c7ade152424974d8115f2cdad61e8dab8dac9f2362298510"
-
-[[package]]
-name = "cfg-if"
-version = "1.0.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
-
-[[package]]
-name = "clap"
-version = "4.5.54"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c6e6ff9dcd79cff5cd969a17a545d79e84ab086e444102a591e288a8aa3ce394"
-dependencies = [
- "clap_builder",
- "clap_derive",
-]
-
-[[package]]
-name = "clap_builder"
-version = "4.5.54"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fa42cf4d2b7a41bc8f663a7cab4031ebafa1bf3875705bfaf8466dc60ab52c00"
-dependencies = [
- "anstream",
- "anstyle",
- "clap_lex",
- "strsim",
-]
-
-[[package]]
-name = "clap_derive"
-version = "4.5.49"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2a0b5487afeab2deb2ff4e03a807ad1a03ac532ff5a2cee5d86884440c7f7671"
-dependencies = [
- "heck",
- "proc-macro2",
- "quote",
- "syn",
-]
-
-[[package]]
-name = "clap_lex"
-version = "0.7.7"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c3e64b0cc0439b12df2fa678eae89a1c56a529fd067a9115f7827f1fffd22b32"
-
-[[package]]
-name = "colorchoice"
-version = "1.0.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75"
-
-[[package]]
-name = "colored"
-version = "3.0.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fde0e0ec90c9dfb3b4b1a0891a7dcd0e2bffde2f7efed5fe7c9bb00e5bfb915e"
-dependencies = [
- "windows-sys 0.59.0",
-]
-
-[[package]]
-name = "const-oid"
-version = "0.9.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8"
-
-[[package]]
-name = "convert_case"
-version = "0.8.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "baaaa0ecca5b51987b9423ccdc971514dd8b0bb7b4060b983d3664dad3f1f89f"
-dependencies = [
- "unicode-segmentation",
-]
-
-[[package]]
-name = "cpufeatures"
-version = "0.2.17"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280"
-dependencies = [
- "libc",
-]
-
-[[package]]
-name = "crypto-common"
-version = "0.1.7"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a"
-dependencies = [
- "generic-array 0.14.7",
- "typenum",
-]
-
-[[package]]
-name = "curve25519-dalek"
-version = "4.1.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "97fb8b7c4503de7d6ae7b42ab72a5a59857b4c937ec27a3d4539dba95b5ab2be"
-dependencies = [
- "cfg-if",
- "cpufeatures",
- "curve25519-dalek-derive",
- "digest",
- "fiat-crypto",
- "rustc_version",
- "subtle",
- "zeroize",
-]
-
-[[package]]
-name = "curve25519-dalek-derive"
-version = "0.1.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn",
-]
-
-[[package]]
-name = "der"
-version = "0.7.10"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e7c1832837b905bbfb5101e07cc24c8deddf52f93225eee6ead5f4d63d53ddcb"
-dependencies = [
- "const-oid",
- "zeroize",
-]
-
-[[package]]
-name = "digest"
-version = "0.10.7"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
-dependencies = [
- "block-buffer",
- "crypto-common",
-]
-
-[[package]]
-name = "ed25519"
-version = "2.2.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "115531babc129696a58c64a4fef0a8bf9e9698629fb97e9e40767d235cfbcd53"
-dependencies = [
- "pkcs8",
- "signature",
-]
-
-[[package]]
-name = "ed25519-dalek"
-version = "2.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "70e796c081cee67dc755e1a36a0a172b897fab85fc3f6bc48307991f64e4eca9"
-dependencies = [
- "curve25519-dalek",
- "ed25519",
- "serde",
- "sha2",
- "subtle",
- "zeroize",
-]
-
-[[package]]
-name = "either"
-version = "1.15.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719"
-
-[[package]]
-name = "endian-type"
-version = "0.1.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c34f04666d835ff5d62e058c3995147c06f42fe86ff053337632bca83e42702d"
-
-[[package]]
-name = "equivalent"
-version = "1.0.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
-
-[[package]]
-name = "fiat-crypto"
-version = "0.2.9"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d"
-
-[[package]]
-name = "foldhash"
-version = "0.1.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2"
-
-[[package]]
-name = "generic-array"
-version = "0.14.7"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"
-dependencies = [
- "typenum",
- "version_check",
-]
-
-[[package]]
-name = "generic-array"
-version = "1.3.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "eaf57c49a95fd1fe24b90b3033bee6dc7e8f1288d51494cb44e627c295e38542"
-dependencies = [
- "rustversion",
- "typenum",
-]
-
-[[package]]
-name = "getrandom"
-version = "0.2.17"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0"
-dependencies = [
- "cfg-if",
- "libc",
- "wasi",
-]
-
-[[package]]
-name = "hashbrown"
-version = "0.15.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1"
-dependencies = [
- "foldhash",
- "serde",
-]
-
-[[package]]
-name = "hashbrown"
-version = "0.16.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100"
-
-[[package]]
-name = "heck"
-version = "0.5.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
-
-[[package]]
-name = "hex"
-version = "0.4.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
-
-[[package]]
-name = "hex-literal"
-version = "0.4.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46"
-
-[[package]]
-name = "indexmap"
-version = "2.13.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017"
-dependencies = [
- "equivalent",
- "hashbrown 0.16.1",
- "serde",
- "serde_core",
-]
-
-[[package]]
-name = "is_terminal_polyfill"
-version = "1.70.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695"
-
-[[package]]
-name = "itertools"
-version = "0.14.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285"
-dependencies = [
- "either",
-]
-
-[[package]]
-name = "itoa"
-version = "1.0.17"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2"
-
-[[package]]
-name = "keccak"
-version = "0.1.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ecc2af9a1119c51f12a14607e783cb977bde58bc069ff0c3da1095e635d70654"
-dependencies = [
- "cpufeatures",
-]
-
-[[package]]
-name = "lazy_static"
-version = "1.5.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
-
-[[package]]
-name = "leb128fmt"
-version = "0.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2"
-
-[[package]]
-name = "libc"
-version = "0.2.180"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bcc35a38544a891a5f7c865aca548a982ccb3b8650a5b06d0fd33a10283c56fc"
-
-[[package]]
-name = "log"
-version = "0.4.29"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897"
-
-[[package]]
-name = "memchr"
-version = "2.7.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273"
-
-[[package]]
-name = "multiversx-chain-core"
-version = "0.14.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "73f1f0526ca094185847776c2c03de97ea082743ee4e6f799860ad67e7d78250"
-dependencies = [
- "bitflags",
- "multiversx-sc-codec",
-]
-
-[[package]]
-name = "multiversx-chain-scenario-format"
-version = "0.23.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e688a0d32a5873871cd19224186ecbfaa0b26f7c8ec62f0ca35d7ee9d4616b40"
-dependencies = [
- "bech32",
- "hex",
- "num-bigint",
- "num-traits",
- "serde",
- "serde_json",
- "sha3",
-]
-
-[[package]]
-name = "multiversx-chain-vm"
-version = "0.14.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6d9e0408c341bbd1d73365b2dd8a96b0c2a41f9458d3dc3519f64275754e7971"
-dependencies = [
- "bitflags",
- "colored",
- "ed25519-dalek",
- "hex",
- "hex-literal",
- "itertools",
- "multiversx-chain-core",
- "multiversx-chain-vm-executor",
- "num-bigint",
- "num-traits",
- "rand",
- "rand_seeder",
- "sha2",
- "sha3",
-]
-
-[[package]]
-name = "multiversx-chain-vm-executor"
-version = "0.3.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "51cce7ae386960fbf5e85afe40ca16d63f926f0620ed1a36b019212b28e17219"
-
-[[package]]
-name = "multiversx-sc"
-version = "0.57.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "20602d4fc336092faadc03b6b445c4bb5e4dbc4c86fb53726e46eca67070813a"
-dependencies = [
- "bitflags",
- "generic-array 1.3.5",
- "hex-literal",
- "multiversx-chain-core",
- "multiversx-sc-codec",
- "multiversx-sc-derive",
- "num-traits",
- "unwrap-infallible",
-]
-
-[[package]]
-name = "multiversx-sc-codec"
-version = "0.22.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "43e0f24a020adf32faffae1c57475c6b7285a3216d1a36e4a73617639721c2e0"
-dependencies = [
- "arrayvec",
- "bitflags",
- "multiversx-sc-codec-derive",
- "num-bigint",
- "unwrap-infallible",
-]
-
-[[package]]
-name = "multiversx-sc-codec-derive"
-version = "0.22.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7c5f17d5ee23657d5cddc7f4471925b5a49f7e25306f8bba656ea6917acc629d"
-dependencies = [
- "hex",
- "proc-macro2",
- "quote",
- "syn",
-]
-
-[[package]]
-name = "multiversx-sc-derive"
-version = "0.57.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0d44d08d3376c199e8c391cc07752d2822cd289693da5319d7905599501e557f"
-dependencies = [
- "hex",
- "proc-macro2",
- "quote",
- "radix_trie",
- "syn",
-]
-
-[[package]]
-name = "multiversx-sc-meta-lib"
-version = "0.57.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "438149f455382e64d1d383b2cb5bee144c215d2943d6a0ae06a50d3225680fbb"
-dependencies = [
- "clap",
- "colored",
- "convert_case",
- "hex",
- "lazy_static",
- "multiversx-sc",
- "rustc_version",
- "semver",
- "serde",
- "serde_json",
- "toml",
- "wasmparser 0.227.1",
- "wasmprinter",
- "wat",
-]
-
-[[package]]
-name = "multiversx-sc-scenario"
-version = "0.57.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2a96dfc78030fec0f05928d2fa0334d1eeaaac2df3b819182876e402461e8c7e"
-dependencies = [
- "base64",
- "bech32",
- "colored",
- "hex",
- "itertools",
- "log",
- "multiversx-chain-scenario-format",
- "multiversx-chain-vm",
- "multiversx-chain-vm-executor",
- "multiversx-sc",
- "multiversx-sc-meta-lib",
- "num-bigint",
- "num-traits",
- "pathdiff",
- "serde",
- "serde_json",
- "sha2",
- "unwrap-infallible",
-]
-
-[[package]]
-name = "nibble_vec"
-version = "0.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "77a5d83df9f36fe23f0c3648c6bbb8b0298bb5f1939c8f2704431371f4b84d43"
-dependencies = [
- "smallvec",
-]
-
-[[package]]
-name = "num-bigint"
-version = "0.4.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9"
-dependencies = [
- "num-integer",
- "num-traits",
-]
-
-[[package]]
-name = "num-integer"
-version = "0.1.46"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f"
-dependencies = [
- "num-traits",
-]
-
-[[package]]
-name = "num-traits"
-version = "0.2.19"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
-dependencies = [
- "autocfg",
-]
-
-[[package]]
-name = "once_cell_polyfill"
-version = "1.70.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe"
-
-[[package]]
-name = "pathdiff"
-version = "0.2.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "df94ce210e5bc13cb6651479fa48d14f601d9858cfe0467f43ae157023b938d3"
-
-[[package]]
-name = "pkcs8"
-version = "0.10.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7"
-dependencies = [
- "der",
- "spki",
-]
-
-[[package]]
-name = "ppv-lite86"
-version = "0.2.21"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9"
-dependencies = [
- "zerocopy",
-]
-
-[[package]]
-name = "proc-macro2"
-version = "1.0.94"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a31971752e70b8b2686d7e46ec17fb38dad4051d94024c88df49b667caea9c84"
-dependencies = [
- "unicode-ident",
-]
-
-[[package]]
-name = "quote"
-version = "1.0.39"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c1f1914ce909e1658d9907913b4b91947430c7d9be598b15a1912935b8c04801"
-dependencies = [
- "proc-macro2",
-]
-
-[[package]]
-name = "radix_trie"
-version = "0.2.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c069c179fcdc6a2fe24d8d18305cf085fdbd4f922c041943e203685d6a1c58fd"
-dependencies = [
- "endian-type",
- "nibble_vec",
-]
-
-[[package]]
-name = "rand"
-version = "0.8.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
-dependencies = [
- "libc",
- "rand_chacha",
- "rand_core",
-]
-
-[[package]]
-name = "rand_chacha"
-version = "0.3.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
-dependencies = [
- "ppv-lite86",
- "rand_core",
-]
-
-[[package]]
-name = "rand_core"
-version = "0.6.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
-dependencies = [
- "getrandom",
-]
-
-[[package]]
-name = "rand_seeder"
-version = "0.3.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4a9febe641d2842ffc76ee962668a17578767c4e01735e4802b21ed9a24b2e4e"
-dependencies = [
- "rand_core",
-]
-
-[[package]]
-name = "requests"
-version = "0.0.0"
-dependencies = [
- "multiversx-sc",
- "multiversx-sc-scenario",
-]
-
-[[package]]
-name = "rustc_version"
-version = "0.4.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92"
-dependencies = [
- "semver",
-]
-
-[[package]]
-name = "rustversion"
-version = "1.0.22"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d"
-
-[[package]]
-name = "semver"
-version = "1.0.27"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2"
-
-[[package]]
-name = "serde"
-version = "1.0.228"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e"
-dependencies = [
- "serde_core",
- "serde_derive",
-]
-
-[[package]]
-name = "serde_core"
-version = "1.0.228"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad"
-dependencies = [
- "serde_derive",
-]
-
-[[package]]
-name = "serde_derive"
-version = "1.0.228"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn",
-]
-
-[[package]]
-name = "serde_json"
-version = "1.0.149"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86"
-dependencies = [
- "itoa",
- "memchr",
- "serde",
- "serde_core",
- "zmij",
-]
-
-[[package]]
-name = "serde_spanned"
-version = "0.6.9"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bf41e0cfaf7226dca15e8197172c295a782857fcb97fad1808a166870dee75a3"
-dependencies = [
- "serde",
-]
-
-[[package]]
-name = "sha2"
-version = "0.10.9"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283"
-dependencies = [
- "cfg-if",
- "cpufeatures",
- "digest",
-]
-
-[[package]]
-name = "sha3"
-version = "0.10.8"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "75872d278a8f37ef87fa0ddbda7802605cb18344497949862c0d4dcb291eba60"
-dependencies = [
- "digest",
- "keccak",
-]
-
-[[package]]
-name = "signature"
-version = "2.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de"
-dependencies = [
- "rand_core",
-]
-
-[[package]]
-name = "smallvec"
-version = "1.15.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03"
-
-[[package]]
-name = "spki"
-version = "0.7.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d"
-dependencies = [
- "base64ct",
- "der",
-]
-
-[[package]]
-name = "strsim"
-version = "0.11.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
-
-[[package]]
-name = "subtle"
-version = "2.6.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292"
-
-[[package]]
-name = "syn"
-version = "2.0.100"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b09a44accad81e1ba1cd74a32461ba89dee89095ba17b32f5d03683b1b1fc2a0"
-dependencies = [
- "proc-macro2",
- "quote",
- "unicode-ident",
-]
-
-[[package]]
-name = "termcolor"
-version = "1.4.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755"
-dependencies = [
- "winapi-util",
-]
-
-[[package]]
-name = "toml"
-version = "0.8.23"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dc1beb996b9d83529a9e75c17a1686767d148d70663143c7854d8b4a09ced362"
-dependencies = [
- "indexmap",
- "serde",
- "serde_spanned",
- "toml_datetime",
- "toml_edit",
-]
-
-[[package]]
-name = "toml_datetime"
-version = "0.6.11"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c"
-dependencies = [
- "serde",
-]
-
-[[package]]
-name = "toml_edit"
-version = "0.22.27"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a"
-dependencies = [
- "indexmap",
- "serde",
- "serde_spanned",
- "toml_datetime",
- "toml_write",
- "winnow",
-]
-
-[[package]]
-name = "toml_write"
-version = "0.1.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5d99f8c9a7727884afe522e9bd5edbfc91a3312b36a77b5fb8926e4c31a41801"
-
-[[package]]
-name = "typenum"
-version = "1.19.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb"
-
-[[package]]
-name = "unicode-ident"
-version = "1.0.22"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5"
-
-[[package]]
-name = "unicode-segmentation"
-version = "1.12.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493"
-
-[[package]]
-name = "unicode-width"
-version = "0.2.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b4ac048d71ede7ee76d585517add45da530660ef4390e49b098733c6e897f254"
-
-[[package]]
-name = "unwrap-infallible"
-version = "0.1.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "151ac09978d3c2862c4e39b557f4eceee2cc72150bc4cb4f16abf061b6e381fb"
-
-[[package]]
-name = "utf8parse"
-version = "0.2.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
-
-[[package]]
-name = "version_check"
-version = "0.9.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
-
-[[package]]
-name = "wasi"
-version = "0.11.1+wasi-snapshot-preview1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b"
-
-[[package]]
-name = "wasm-encoder"
-version = "0.244.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "990065f2fe63003fe337b932cfb5e3b80e0b4d0f5ff650e6985b1048f62c8319"
-dependencies = [
- "leb128fmt",
- "wasmparser 0.244.0",
-]
-
-[[package]]
-name = "wasmparser"
-version = "0.227.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0f51cad774fb3c9461ab9bccc9c62dfb7388397b5deda31bf40e8108ccd678b2"
-dependencies = [
- "bitflags",
- "hashbrown 0.15.5",
- "indexmap",
- "semver",
- "serde",
-]
-
-[[package]]
-name = "wasmparser"
-version = "0.244.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe"
-dependencies = [
- "bitflags",
- "indexmap",
- "semver",
-]
-
-[[package]]
-name = "wasmprinter"
-version = "0.227.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "32475a0459db5639e989206dd8833fb07110ec092a7cb3468c82341989cac4d3"
-dependencies = [
- "anyhow",
- "termcolor",
- "wasmparser 0.227.1",
-]
-
-[[package]]
-name = "wast"
-version = "244.0.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b2e7b9f9e23311275920e3d6b56d64137c160cf8af4f84a7283b36cfecbf4acb"
-dependencies = [
- "bumpalo",
- "leb128fmt",
- "memchr",
- "unicode-width",
- "wasm-encoder",
-]
-
-[[package]]
-name = "wat"
-version = "1.244.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bbf35b87ed352f9ab6cd0732abde5a67dd6153dfd02c493e61459218b19456fa"
-dependencies = [
- "wast",
-]
-
-[[package]]
-name = "winapi-util"
-version = "0.1.11"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22"
-dependencies = [
- "windows-sys 0.61.2",
-]
-
-[[package]]
-name = "windows-link"
-version = "0.2.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
-
-[[package]]
-name = "windows-sys"
-version = "0.59.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
-dependencies = [
- "windows-targets",
-]
-
-[[package]]
-name = "windows-sys"
-version = "0.61.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc"
-dependencies = [
- "windows-link",
-]
-
-[[package]]
-name = "windows-targets"
-version = "0.52.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
-dependencies = [
- "windows_aarch64_gnullvm",
- "windows_aarch64_msvc",
- "windows_i686_gnu",
- "windows_i686_gnullvm",
- "windows_i686_msvc",
- "windows_x86_64_gnu",
- "windows_x86_64_gnullvm",
- "windows_x86_64_msvc",
-]
-
-[[package]]
-name = "windows_aarch64_gnullvm"
-version = "0.52.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
-
-[[package]]
-name = "windows_aarch64_msvc"
-version = "0.52.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
-
-[[package]]
-name = "windows_i686_gnu"
-version = "0.52.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
-
-[[package]]
-name = "windows_i686_gnullvm"
-version = "0.52.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
-
-[[package]]
-name = "windows_i686_msvc"
-version = "0.52.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
-
-[[package]]
-name = "windows_x86_64_gnu"
-version = "0.52.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
-
-[[package]]
-name = "windows_x86_64_gnullvm"
-version = "0.52.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
-
-[[package]]
-name = "windows_x86_64_msvc"
-version = "0.52.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
-
-[[package]]
-name = "winnow"
-version = "0.7.14"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5a5364e9d77fcdeeaa6062ced926ee3381faa2ee02d3eb83a5c27a8825540829"
-dependencies = [
- "memchr",
-]
-
-[[package]]
-name = "zerocopy"
-version = "0.8.27"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0894878a5fa3edfd6da3f88c4805f4c8558e2b996227a3d864f47fe11e38282c"
-dependencies = [
- "zerocopy-derive",
-]
-
-[[package]]
-name = "zerocopy-derive"
-version = "0.8.27"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "88d2b8d9c68ad2b9e4340d7832716a4d21a22a1154777ad56ea55c51a9cf3831"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn",
-]
-
-[[package]]
-name = "zeroize"
-version = "1.8.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0"
-
-[[package]]
-name = "zmij"
-version = "1.0.14"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bd8f3f50b848df28f887acb68e41201b5aea6bc8a8dacc00fb40635ff9a72fea"
diff --git a/requests-contract/Cargo.toml b/requests-contract/Cargo.toml
deleted file mode 100644
index a15bbc5..0000000
--- a/requests-contract/Cargo.toml
+++ /dev/null
@@ -1,15 +0,0 @@
-[package]
-name = "requests"
-version = "0.0.0"
-authors = ["Andrei Marinica "]
-edition = "2021"
-publish = false
-
-[lib]
-path = "src/lib.rs"
-
-[dependencies.multiversx-sc]
-version = "0.57.1"
-
-[dev-dependencies.multiversx-sc-scenario]
-version = "0.57.1"
diff --git a/requests-contract/build_reproducible.sh b/requests-contract/build_reproducible.sh
deleted file mode 100755
index 703732c..0000000
--- a/requests-contract/build_reproducible.sh
+++ /dev/null
@@ -1,28 +0,0 @@
-#!/bin/bash
-set -e
-
-# Ensure we are in the script's directory
-cd "$(dirname "$0")"
-
-BUILDER_TAG="v10.0.0"
-SCRIPT_URL="https://raw.githubusercontent.com/multiversx/mx-sdk-rust-contract-builder/${BUILDER_TAG}/build_with_docker.py"
-SCRIPT_NAME="build_with_docker.py"
-
-# Download the build script
-echo "Downloading build script from ${SCRIPT_URL}..."
-curl -s -o "${SCRIPT_NAME}" "${SCRIPT_URL}"
-
-# Clean and create output directory
-rm -rf output
-mkdir -p output
-
-# Run the build
-echo "Starting reproducible build using Docker image multiversx/sdk-rust-contract-builder:${BUILDER_TAG}..."
-python3 "${SCRIPT_NAME}" \
- --image="multiversx/sdk-rust-contract-builder:${BUILDER_TAG}" \
- --project="$(pwd)" \
- --output="$(pwd)/output" \
- --no-docker-interactive \
- --contract=requests
-
-echo "Build complete. Artifacts are in $(pwd)/output"
diff --git a/requests-contract/build_with_docker.py b/requests-contract/build_with_docker.py
deleted file mode 100644
index 83ebc2b..0000000
--- a/requests-contract/build_with_docker.py
+++ /dev/null
@@ -1,120 +0,0 @@
-import logging
-import os
-import subprocess
-import sys
-from argparse import ArgumentParser
-from pathlib import Path
-from typing import List
-
-logger = logging.getLogger("build-with-docker")
-
-
-def main(cli_args: List[str]):
- logging.basicConfig(level=logging.DEBUG)
-
- parser = ArgumentParser()
- parser.add_argument("--image", type=str, required=True)
- parser.add_argument("--no-docker-interactive", action="store_true", default=False)
- parser.add_argument("--no-docker-tty", action="store_true", default=False)
- parser.add_argument("--project", type=str, help="source code folder (project)")
- parser.add_argument("--packaged-src", type=str, help="source code packaged in a JSON file")
- parser.add_argument("--contract", type=str, help="contract to build (contract name, as found in Cargo.toml)")
- parser.add_argument("--output", type=str, default=Path(os.getcwd()) / "output")
- parser.add_argument("--package-whole-project-src", action="store_true", default=False, help="deprecated parameter, not used anymore")
- parser.add_argument("--cargo-target-dir", help="deprecated parameter, not used anymore")
- parser.add_argument("--no-wasm-opt", action="store_true", default=False, help="do not optimize wasm files after the build (default: %(default)s)")
- parser.add_argument("--build-root", type=str, required=False, help="root path (within container) for the build (default: %(default)s)")
- parser.add_argument("--cargo-verbose", action="store_true", default=False, help="set 'CARGO_TERM_VERBOSE' environment variable (default: %(default)s)")
-
- # Handle CLI arguments
- parsed_args = parser.parse_args(cli_args)
- image = parsed_args.image
- docker_interactive = not parsed_args.no_docker_interactive
- docker_tty = not parsed_args.no_docker_tty
- project_path = Path(parsed_args.project).expanduser().resolve() if parsed_args.project else None
- packaged_src_path = Path(parsed_args.packaged_src).expanduser().resolve() if parsed_args.packaged_src else None
- contract_path = parsed_args.contract
- output_path = Path(parsed_args.output).expanduser().resolve()
- no_wasm_opt = parsed_args.no_wasm_opt
- build_root = Path(parsed_args.build_root) if parsed_args.build_root else None
- cargo_verbose = parsed_args.cargo_verbose
-
- # Prepare (and check) output folder
- output_path.mkdir(parents=True, exist_ok=True)
- ensure_output_folder_is_empty(output_path)
-
- # Prepare general docker arguments
- docker_general_args = ["docker", "run"]
-
- if docker_interactive:
- docker_general_args += ["--interactive"]
- if docker_tty:
- docker_general_args += ["--tty"]
-
- docker_general_args += ["--user", f"{str(os.getuid())}:{str(os.getgid())}"]
- docker_general_args += ["--rm"]
-
- # Prepare docker arguments related to mounting volumes
- docker_mount_args: List[str] = ["--volume", f"{output_path}:/output"]
-
- if project_path:
- docker_mount_args.extend(["--volume", f"{project_path}:/project"])
-
- if packaged_src_path:
- docker_mount_args.extend(["--volume", f"{packaged_src_path}:/packaged-src.json"])
-
- mounted_temporary_root = Path("/tmp/multiversx_sdk_rust_contract_builder")
- mounted_cargo_target_dir = mounted_temporary_root / "cargo-target-dir"
- mounted_cargo_registry = mounted_temporary_root / "cargo-registry"
- mounted_cargo_git = mounted_temporary_root / "cargo-git"
-
- mounted_cargo_target_dir.mkdir(parents=True, exist_ok=True)
- mounted_cargo_registry.mkdir(parents=True, exist_ok=True)
- mounted_cargo_git.mkdir(parents=True, exist_ok=True)
-
- docker_mount_args += ["--volume", f"{mounted_cargo_target_dir}:/rust/cargo-target-dir"]
- docker_mount_args += ["--volume", f"{mounted_cargo_registry}:/rust/registry"]
- docker_mount_args += ["--volume", f"{mounted_cargo_git}:/rust/git"]
-
- docker_env_args = ["--env", f"CARGO_TERM_VERBOSE={str(cargo_verbose).lower()}"]
-
- # Prepare entrypoint arguments
- entrypoint_args: List[str] = []
-
- if project_path:
- entrypoint_args.extend(["--project", "project"])
-
- if packaged_src_path:
- entrypoint_args.extend(["--packaged-src", "packaged-src.json"])
-
- if no_wasm_opt:
- entrypoint_args.append("--no-wasm-opt")
-
- if contract_path:
- entrypoint_args.extend(["--contract", contract_path])
-
- if build_root:
- entrypoint_args.extend(["--build-root", str(build_root)])
-
- # Run docker container
- args = docker_general_args + docker_mount_args + docker_env_args + [image] + entrypoint_args
- logger.info(f"Running docker: {args}")
-
- result = subprocess.run(args)
- return result.returncode
-
-
-def ensure_output_folder_is_empty(parent_output_folder: Path):
- is_empty = len(os.listdir(parent_output_folder)) == 0
- if not is_empty:
- raise Exception(f"Output folder must be empty: {parent_output_folder}")
-
-
-if __name__ == "__main__":
- try:
- return_code = main(sys.argv[1:])
- exit(return_code)
- except Exception as err:
- print("An error occurred.")
- print(err)
- exit(1)
diff --git a/requests-contract/meta/Cargo.lock b/requests-contract/meta/Cargo.lock
deleted file mode 100644
index b53ce30..0000000
--- a/requests-contract/meta/Cargo.lock
+++ /dev/null
@@ -1,785 +0,0 @@
-# This file is automatically @generated by Cargo.
-# It is not intended for manual editing.
-version = 4
-
-[[package]]
-name = "anstream"
-version = "0.6.21"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "43d5b281e737544384e969a5ccad3f1cdd24b48086a0fc1b2a5262a26b8f4f4a"
-dependencies = [
- "anstyle",
- "anstyle-parse",
- "anstyle-query",
- "anstyle-wincon",
- "colorchoice",
- "is_terminal_polyfill",
- "utf8parse",
-]
-
-[[package]]
-name = "anstyle"
-version = "1.0.13"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5192cca8006f1fd4f7237516f40fa183bb07f8fbdfedaa0036de5ea9b0b45e78"
-
-[[package]]
-name = "anstyle-parse"
-version = "0.2.7"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2"
-dependencies = [
- "utf8parse",
-]
-
-[[package]]
-name = "anstyle-query"
-version = "1.1.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc"
-dependencies = [
- "windows-sys 0.61.2",
-]
-
-[[package]]
-name = "anstyle-wincon"
-version = "3.0.11"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d"
-dependencies = [
- "anstyle",
- "once_cell_polyfill",
- "windows-sys 0.61.2",
-]
-
-[[package]]
-name = "anyhow"
-version = "1.0.100"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61"
-
-[[package]]
-name = "arrayvec"
-version = "0.7.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50"
-
-[[package]]
-name = "autocfg"
-version = "1.5.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8"
-
-[[package]]
-name = "bitflags"
-version = "2.9.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd"
-
-[[package]]
-name = "bumpalo"
-version = "3.19.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5dd9dc738b7a8311c7ade152424974d8115f2cdad61e8dab8dac9f2362298510"
-
-[[package]]
-name = "clap"
-version = "4.5.54"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c6e6ff9dcd79cff5cd969a17a545d79e84ab086e444102a591e288a8aa3ce394"
-dependencies = [
- "clap_builder",
- "clap_derive",
-]
-
-[[package]]
-name = "clap_builder"
-version = "4.5.54"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fa42cf4d2b7a41bc8f663a7cab4031ebafa1bf3875705bfaf8466dc60ab52c00"
-dependencies = [
- "anstream",
- "anstyle",
- "clap_lex",
- "strsim",
-]
-
-[[package]]
-name = "clap_derive"
-version = "4.5.49"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2a0b5487afeab2deb2ff4e03a807ad1a03ac532ff5a2cee5d86884440c7f7671"
-dependencies = [
- "heck",
- "proc-macro2",
- "quote",
- "syn",
-]
-
-[[package]]
-name = "clap_lex"
-version = "0.7.7"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c3e64b0cc0439b12df2fa678eae89a1c56a529fd067a9115f7827f1fffd22b32"
-
-[[package]]
-name = "colorchoice"
-version = "1.0.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75"
-
-[[package]]
-name = "colored"
-version = "3.0.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fde0e0ec90c9dfb3b4b1a0891a7dcd0e2bffde2f7efed5fe7c9bb00e5bfb915e"
-dependencies = [
- "windows-sys 0.59.0",
-]
-
-[[package]]
-name = "convert_case"
-version = "0.8.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "baaaa0ecca5b51987b9423ccdc971514dd8b0bb7b4060b983d3664dad3f1f89f"
-dependencies = [
- "unicode-segmentation",
-]
-
-[[package]]
-name = "endian-type"
-version = "0.1.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c34f04666d835ff5d62e058c3995147c06f42fe86ff053337632bca83e42702d"
-
-[[package]]
-name = "equivalent"
-version = "1.0.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
-
-[[package]]
-name = "foldhash"
-version = "0.1.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2"
-
-[[package]]
-name = "generic-array"
-version = "1.3.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "eaf57c49a95fd1fe24b90b3033bee6dc7e8f1288d51494cb44e627c295e38542"
-dependencies = [
- "rustversion",
- "typenum",
-]
-
-[[package]]
-name = "hashbrown"
-version = "0.15.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1"
-dependencies = [
- "foldhash",
- "serde",
-]
-
-[[package]]
-name = "hashbrown"
-version = "0.16.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100"
-
-[[package]]
-name = "heck"
-version = "0.5.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
-
-[[package]]
-name = "hex"
-version = "0.4.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
-
-[[package]]
-name = "hex-literal"
-version = "0.4.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46"
-
-[[package]]
-name = "indexmap"
-version = "2.13.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017"
-dependencies = [
- "equivalent",
- "hashbrown 0.16.1",
- "serde",
- "serde_core",
-]
-
-[[package]]
-name = "is_terminal_polyfill"
-version = "1.70.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695"
-
-[[package]]
-name = "itoa"
-version = "1.0.17"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2"
-
-[[package]]
-name = "lazy_static"
-version = "1.5.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
-
-[[package]]
-name = "leb128fmt"
-version = "0.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2"
-
-[[package]]
-name = "memchr"
-version = "2.7.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273"
-
-[[package]]
-name = "multiversx-chain-core"
-version = "0.14.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "73f1f0526ca094185847776c2c03de97ea082743ee4e6f799860ad67e7d78250"
-dependencies = [
- "bitflags",
- "multiversx-sc-codec",
-]
-
-[[package]]
-name = "multiversx-sc"
-version = "0.57.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "20602d4fc336092faadc03b6b445c4bb5e4dbc4c86fb53726e46eca67070813a"
-dependencies = [
- "bitflags",
- "generic-array",
- "hex-literal",
- "multiversx-chain-core",
- "multiversx-sc-codec",
- "multiversx-sc-derive",
- "num-traits",
- "unwrap-infallible",
-]
-
-[[package]]
-name = "multiversx-sc-codec"
-version = "0.22.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "43e0f24a020adf32faffae1c57475c6b7285a3216d1a36e4a73617639721c2e0"
-dependencies = [
- "arrayvec",
- "bitflags",
- "multiversx-sc-codec-derive",
- "num-bigint",
- "unwrap-infallible",
-]
-
-[[package]]
-name = "multiversx-sc-codec-derive"
-version = "0.22.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7c5f17d5ee23657d5cddc7f4471925b5a49f7e25306f8bba656ea6917acc629d"
-dependencies = [
- "hex",
- "proc-macro2",
- "quote",
- "syn",
-]
-
-[[package]]
-name = "multiversx-sc-derive"
-version = "0.57.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0d44d08d3376c199e8c391cc07752d2822cd289693da5319d7905599501e557f"
-dependencies = [
- "hex",
- "proc-macro2",
- "quote",
- "radix_trie",
- "syn",
-]
-
-[[package]]
-name = "multiversx-sc-meta-lib"
-version = "0.57.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "438149f455382e64d1d383b2cb5bee144c215d2943d6a0ae06a50d3225680fbb"
-dependencies = [
- "clap",
- "colored",
- "convert_case",
- "hex",
- "lazy_static",
- "multiversx-sc",
- "rustc_version",
- "semver",
- "serde",
- "serde_json",
- "toml",
- "wasmparser 0.227.1",
- "wasmprinter",
- "wat",
-]
-
-[[package]]
-name = "nibble_vec"
-version = "0.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "77a5d83df9f36fe23f0c3648c6bbb8b0298bb5f1939c8f2704431371f4b84d43"
-dependencies = [
- "smallvec",
-]
-
-[[package]]
-name = "num-bigint"
-version = "0.4.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9"
-dependencies = [
- "num-integer",
- "num-traits",
-]
-
-[[package]]
-name = "num-integer"
-version = "0.1.46"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f"
-dependencies = [
- "num-traits",
-]
-
-[[package]]
-name = "num-traits"
-version = "0.2.19"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
-dependencies = [
- "autocfg",
-]
-
-[[package]]
-name = "once_cell_polyfill"
-version = "1.70.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe"
-
-[[package]]
-name = "proc-macro2"
-version = "1.0.94"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a31971752e70b8b2686d7e46ec17fb38dad4051d94024c88df49b667caea9c84"
-dependencies = [
- "unicode-ident",
-]
-
-[[package]]
-name = "quote"
-version = "1.0.39"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c1f1914ce909e1658d9907913b4b91947430c7d9be598b15a1912935b8c04801"
-dependencies = [
- "proc-macro2",
-]
-
-[[package]]
-name = "radix_trie"
-version = "0.2.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c069c179fcdc6a2fe24d8d18305cf085fdbd4f922c041943e203685d6a1c58fd"
-dependencies = [
- "endian-type",
- "nibble_vec",
-]
-
-[[package]]
-name = "requests"
-version = "0.0.0"
-dependencies = [
- "multiversx-sc",
-]
-
-[[package]]
-name = "requests-meta"
-version = "0.0.0"
-dependencies = [
- "multiversx-sc-meta-lib",
- "requests",
-]
-
-[[package]]
-name = "rustc_version"
-version = "0.4.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92"
-dependencies = [
- "semver",
-]
-
-[[package]]
-name = "rustversion"
-version = "1.0.22"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d"
-
-[[package]]
-name = "semver"
-version = "1.0.27"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2"
-
-[[package]]
-name = "serde"
-version = "1.0.228"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e"
-dependencies = [
- "serde_core",
- "serde_derive",
-]
-
-[[package]]
-name = "serde_core"
-version = "1.0.228"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad"
-dependencies = [
- "serde_derive",
-]
-
-[[package]]
-name = "serde_derive"
-version = "1.0.228"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn",
-]
-
-[[package]]
-name = "serde_json"
-version = "1.0.149"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86"
-dependencies = [
- "itoa",
- "memchr",
- "serde",
- "serde_core",
- "zmij",
-]
-
-[[package]]
-name = "serde_spanned"
-version = "0.6.9"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bf41e0cfaf7226dca15e8197172c295a782857fcb97fad1808a166870dee75a3"
-dependencies = [
- "serde",
-]
-
-[[package]]
-name = "smallvec"
-version = "1.15.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03"
-
-[[package]]
-name = "strsim"
-version = "0.11.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
-
-[[package]]
-name = "syn"
-version = "2.0.100"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b09a44accad81e1ba1cd74a32461ba89dee89095ba17b32f5d03683b1b1fc2a0"
-dependencies = [
- "proc-macro2",
- "quote",
- "unicode-ident",
-]
-
-[[package]]
-name = "termcolor"
-version = "1.4.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755"
-dependencies = [
- "winapi-util",
-]
-
-[[package]]
-name = "toml"
-version = "0.8.23"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dc1beb996b9d83529a9e75c17a1686767d148d70663143c7854d8b4a09ced362"
-dependencies = [
- "indexmap",
- "serde",
- "serde_spanned",
- "toml_datetime",
- "toml_edit",
-]
-
-[[package]]
-name = "toml_datetime"
-version = "0.6.11"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c"
-dependencies = [
- "serde",
-]
-
-[[package]]
-name = "toml_edit"
-version = "0.22.27"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a"
-dependencies = [
- "indexmap",
- "serde",
- "serde_spanned",
- "toml_datetime",
- "toml_write",
- "winnow",
-]
-
-[[package]]
-name = "toml_write"
-version = "0.1.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5d99f8c9a7727884afe522e9bd5edbfc91a3312b36a77b5fb8926e4c31a41801"
-
-[[package]]
-name = "typenum"
-version = "1.19.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb"
-
-[[package]]
-name = "unicode-ident"
-version = "1.0.22"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5"
-
-[[package]]
-name = "unicode-segmentation"
-version = "1.12.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493"
-
-[[package]]
-name = "unicode-width"
-version = "0.2.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b4ac048d71ede7ee76d585517add45da530660ef4390e49b098733c6e897f254"
-
-[[package]]
-name = "unwrap-infallible"
-version = "0.1.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "151ac09978d3c2862c4e39b557f4eceee2cc72150bc4cb4f16abf061b6e381fb"
-
-[[package]]
-name = "utf8parse"
-version = "0.2.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
-
-[[package]]
-name = "wasm-encoder"
-version = "0.244.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "990065f2fe63003fe337b932cfb5e3b80e0b4d0f5ff650e6985b1048f62c8319"
-dependencies = [
- "leb128fmt",
- "wasmparser 0.244.0",
-]
-
-[[package]]
-name = "wasmparser"
-version = "0.227.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0f51cad774fb3c9461ab9bccc9c62dfb7388397b5deda31bf40e8108ccd678b2"
-dependencies = [
- "bitflags",
- "hashbrown 0.15.5",
- "indexmap",
- "semver",
- "serde",
-]
-
-[[package]]
-name = "wasmparser"
-version = "0.244.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe"
-dependencies = [
- "bitflags",
- "indexmap",
- "semver",
-]
-
-[[package]]
-name = "wasmprinter"
-version = "0.227.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "32475a0459db5639e989206dd8833fb07110ec092a7cb3468c82341989cac4d3"
-dependencies = [
- "anyhow",
- "termcolor",
- "wasmparser 0.227.1",
-]
-
-[[package]]
-name = "wast"
-version = "244.0.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b2e7b9f9e23311275920e3d6b56d64137c160cf8af4f84a7283b36cfecbf4acb"
-dependencies = [
- "bumpalo",
- "leb128fmt",
- "memchr",
- "unicode-width",
- "wasm-encoder",
-]
-
-[[package]]
-name = "wat"
-version = "1.244.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bbf35b87ed352f9ab6cd0732abde5a67dd6153dfd02c493e61459218b19456fa"
-dependencies = [
- "wast",
-]
-
-[[package]]
-name = "winapi-util"
-version = "0.1.11"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22"
-dependencies = [
- "windows-sys 0.61.2",
-]
-
-[[package]]
-name = "windows-link"
-version = "0.2.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
-
-[[package]]
-name = "windows-sys"
-version = "0.59.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
-dependencies = [
- "windows-targets",
-]
-
-[[package]]
-name = "windows-sys"
-version = "0.61.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc"
-dependencies = [
- "windows-link",
-]
-
-[[package]]
-name = "windows-targets"
-version = "0.52.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
-dependencies = [
- "windows_aarch64_gnullvm",
- "windows_aarch64_msvc",
- "windows_i686_gnu",
- "windows_i686_gnullvm",
- "windows_i686_msvc",
- "windows_x86_64_gnu",
- "windows_x86_64_gnullvm",
- "windows_x86_64_msvc",
-]
-
-[[package]]
-name = "windows_aarch64_gnullvm"
-version = "0.52.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
-
-[[package]]
-name = "windows_aarch64_msvc"
-version = "0.52.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
-
-[[package]]
-name = "windows_i686_gnu"
-version = "0.52.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
-
-[[package]]
-name = "windows_i686_gnullvm"
-version = "0.52.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
-
-[[package]]
-name = "windows_i686_msvc"
-version = "0.52.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
-
-[[package]]
-name = "windows_x86_64_gnu"
-version = "0.52.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
-
-[[package]]
-name = "windows_x86_64_gnullvm"
-version = "0.52.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
-
-[[package]]
-name = "windows_x86_64_msvc"
-version = "0.52.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
-
-[[package]]
-name = "winnow"
-version = "0.7.14"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5a5364e9d77fcdeeaa6062ced926ee3381faa2ee02d3eb83a5c27a8825540829"
-dependencies = [
- "memchr",
-]
-
-[[package]]
-name = "zmij"
-version = "1.0.14"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bd8f3f50b848df28f887acb68e41201b5aea6bc8a8dacc00fb40635ff9a72fea"
diff --git a/requests-contract/meta/Cargo.toml b/requests-contract/meta/Cargo.toml
deleted file mode 100644
index 83f38a8..0000000
--- a/requests-contract/meta/Cargo.toml
+++ /dev/null
@@ -1,12 +0,0 @@
-[package]
-name = "requests-meta"
-version = "0.0.0"
-edition = "2021"
-publish = false
-
-[dependencies.requests]
-path = ".."
-
-[dependencies.multiversx-sc-meta-lib]
-version = "0.57.1"
-default-features = false
diff --git a/requests-contract/meta/src/main.rs b/requests-contract/meta/src/main.rs
deleted file mode 100644
index 3f71a26..0000000
--- a/requests-contract/meta/src/main.rs
+++ /dev/null
@@ -1,3 +0,0 @@
-fn main() {
- multiversx_sc_meta_lib::cli_main::();
-}
diff --git a/requests-contract/multiversx.json b/requests-contract/multiversx.json
deleted file mode 100644
index 7365539..0000000
--- a/requests-contract/multiversx.json
+++ /dev/null
@@ -1,3 +0,0 @@
-{
- "language": "rust"
-}
\ No newline at end of file
diff --git a/requests-contract/mxsc-template.toml b/requests-contract/mxsc-template.toml
deleted file mode 100644
index f6a6bb7..0000000
--- a/requests-contract/mxsc-template.toml
+++ /dev/null
@@ -1,25 +0,0 @@
-name = "adder"
-contract_trait = "Adder"
-src_file = "adder.rs"
-rename_pairs = [
- [
- "blockchain.set_current_dir_from_workspace(\"contracts/examples/adder\");",
- "// blockchain.set_current_dir_from_workspace(\"relative path to your workspace, if applicable\");",
- ],
-]
-files_include = [
- "meta",
- "scenarios",
- "src",
- "tests",
- "Cargo.toml",
- "README.md",
- "sc-config.toml",
- "multiversx.json",
- "interactor/Cargo.toml",
- "interactor/config.toml",
- "interactor/.gitignore",
- "interactor/src",
- "interactor/tests",
-]
-has_interactor = true
diff --git a/requests-contract/output/artifacts.json b/requests-contract/output/artifacts.json
deleted file mode 100644
index 9100616..0000000
--- a/requests-contract/output/artifacts.json
+++ /dev/null
@@ -1,26 +0,0 @@
-{
- "buildMetadata": {
- "versionRust": "1.86.0",
- "versionScTool": "0.57.1",
- "versionWasmOpt": "0.116.1",
- "targetPlatform": "linux/amd64"
- },
- "buildOptions": {
- "packageWholeProjectSrc": true,
- "specificContract": "requests",
- "cargoTargetDir": "/rust/cargo-target-dir",
- "noWasmOpt": false,
- "buildRootFolder": "/tmp/project"
- },
- "contracts": {
- "requests": {
- "version": "0.0.0",
- "codehash": "1e8c9ef47f3f3f00b58b48075411edab699126c8ee9ff69f53827dfcf2eecf0a",
- "artifacts": {
- "bytecode": "requests.wasm",
- "abi": "requests.abi.json",
- "srcPackage": "requests-0.0.0.source.json"
- }
- }
- }
-}
\ No newline at end of file
diff --git a/requests-contract/output/requests/requests-0.0.0.source.json b/requests-contract/output/requests/requests-0.0.0.source.json
deleted file mode 100644
index c4f29d6..0000000
--- a/requests-contract/output/requests/requests-0.0.0.source.json
+++ /dev/null
@@ -1,106 +0,0 @@
-{
- "schemaVersion": "2.0.0",
- "metadata": {
- "contractName": "requests",
- "contractVersion": "0.0.0",
- "buildMetadata": {
- "versionRust": "1.86.0",
- "versionScTool": "0.57.1",
- "versionWasmOpt": "0.116.1",
- "targetPlatform": "linux/amd64"
- },
- "buildOptions": {
- "packageWholeProjectSrc": true,
- "specificContract": "requests",
- "cargoTargetDir": "/rust/cargo-target-dir",
- "noWasmOpt": false,
- "buildRootFolder": "/tmp/project"
- }
- },
- "entries": [
- {
- "path": "Cargo.lock",
- "content": "IyBUaGlzIGZpbGUgaXMgYXV0b21hdGljYWxseSBAZ2VuZXJhdGVkIGJ5IENhcmdvLgojIEl0IGlzIG5vdCBpbnRlbmRlZCBmb3IgbWFudWFsIGVkaXRpbmcuCnZlcnNpb24gPSA0CgpbW3BhY2thZ2VdXQpuYW1lID0gImFuc3RyZWFtIgp2ZXJzaW9uID0gIjAuNi4yMSIKc291cmNlID0gInJlZ2lzdHJ5K2h0dHBzOi8vZ2l0aHViLmNvbS9ydXN0LWxhbmcvY3JhdGVzLmlvLWluZGV4IgpjaGVja3N1bSA9ICI0M2Q1YjI4MWU3Mzc1NDQzODRlOTY5YTVjY2FkM2YxY2RkMjRiNDgwODZhMGZjMWIyYTUyNjJhMjZiOGY0ZjRhIgpkZXBlbmRlbmNpZXMgPSBbCiAiYW5zdHlsZSIsCiAiYW5zdHlsZS1wYXJzZSIsCiAiYW5zdHlsZS1xdWVyeSIsCiAiYW5zdHlsZS13aW5jb24iLAogImNvbG9yY2hvaWNlIiwKICJpc190ZXJtaW5hbF9wb2x5ZmlsbCIsCiAidXRmOHBhcnNlIiwKXQoKW1twYWNrYWdlXV0KbmFtZSA9ICJhbnN0eWxlIgp2ZXJzaW9uID0gIjEuMC4xMyIKc291cmNlID0gInJlZ2lzdHJ5K2h0dHBzOi8vZ2l0aHViLmNvbS9ydXN0LWxhbmcvY3JhdGVzLmlvLWluZGV4IgpjaGVja3N1bSA9ICI1MTkyY2NhODAwNmYxZmQ0ZjcyMzc1MTZmNDBmYTE4M2JiMDdmOGZiZGZlZGFhMDAzNmRlNWVhOWIwYjQ1ZTc4IgoKW1twYWNrYWdlXV0KbmFtZSA9ICJhbnN0eWxlLXBhcnNlIgp2ZXJzaW9uID0gIjAuMi43Igpzb3VyY2UgPSAicmVnaXN0cnkraHR0cHM6Ly9naXRodWIuY29tL3J1c3QtbGFuZy9jcmF0ZXMuaW8taW5kZXgiCmNoZWNrc3VtID0gIjRlNzY0NDgyNGYwYWEyYzdiOTM4NDU3OTIzNGVmMTBlYjdlZmI2YTBkZWI4M2Y5NjMwYTQ5NTk0ZGQ5YzE1YzIiCmRlcGVuZGVuY2llcyA9IFsKICJ1dGY4cGFyc2UiLApdCgpbW3BhY2thZ2VdXQpuYW1lID0gImFuc3R5bGUtcXVlcnkiCnZlcnNpb24gPSAiMS4xLjUiCnNvdXJjZSA9ICJyZWdpc3RyeStodHRwczovL2dpdGh1Yi5jb20vcnVzdC1sYW5nL2NyYXRlcy5pby1pbmRleCIKY2hlY2tzdW0gPSAiNDBjNDhmNzJmZDUzY2QyODkxMDRmYzY0MDk5YWJjYTczZGI0MTY2YWQ4NmVhMGI0MzQxYWJlNjVhZjgzZGFkYyIKZGVwZW5kZW5jaWVzID0gWwogIndpbmRvd3Mtc3lzIDAuNjEuMiIsCl0KCltbcGFja2FnZV1dCm5hbWUgPSAiYW5zdHlsZS13aW5jb24iCnZlcnNpb24gPSAiMy4wLjExIgpzb3VyY2UgPSAicmVnaXN0cnkraHR0cHM6Ly9naXRodWIuY29tL3J1c3QtbGFuZy9jcmF0ZXMuaW8taW5kZXgiCmNoZWNrc3VtID0gIjI5MWU2YTI1MGZmODZjZDRhODIwMTEyZmI4ODk4ODA4YTM2NmQ4ZjlmNThjZTE2ZDFmNTM4MzUzYWQ1NTc0N2QiCmRlcGVuZGVuY2llcyA9IFsKICJhbnN0eWxlIiwKICJvbmNlX2NlbGxfcG9seWZpbGwiLAogIndpbmRvd3Mtc3lzIDAuNjEuMiIsCl0KCltbcGFja2FnZV1dCm5hbWUgPSAiYW55aG93Igp2ZXJzaW9uID0gIjEuMC4xMDAiCnNvdXJjZSA9ICJyZWdpc3RyeStodHRwczovL2dpdGh1Yi5jb20vcnVzdC1sYW5nL2NyYXRlcy5pby1pbmRleCIKY2hlY2tzdW0gPSAiYTIzZWI2YjE2MTQzMThhODA3MWM5YjI1MjFmMzZiNDI0YjJjODNkYjVlYjNhMGZlYWQ0YTZjMDgwOWFmNmU2MSIKCltbcGFja2FnZV1dCm5hbWUgPSAiYXJyYXl2ZWMiCnZlcnNpb24gPSAiMC43LjYiCnNvdXJjZSA9ICJyZWdpc3RyeStodHRwczovL2dpdGh1Yi5jb20vcnVzdC1sYW5nL2NyYXRlcy5pby1pbmRleCIKY2hlY2tzdW0gPSAiN2MwMmQxMjNkZjAxN2VmY2RmYmQ3MzllZjgxNzM1YjM2YzViYTgzZWMzYzU5YzgwYTlkN2VjYzcxOGY5MmU1MCIKCltbcGFja2FnZV1dCm5hbWUgPSAiYXV0b2NmZyIKdmVyc2lvbiA9ICIxLjUuMCIKc291cmNlID0gInJlZ2lzdHJ5K2h0dHBzOi8vZ2l0aHViLmNvbS9ydXN0LWxhbmcvY3JhdGVzLmlvLWluZGV4IgpjaGVja3N1bSA9ICJjMDg2MDZmOGMzY2JmNGNlNmVjOGUyOGZiMDAxNGEyYzA4NjcwOGZlOTU0ZWFhODg1Mzg0YTYxNjUxNzJlN2U4IgoKW1twYWNrYWdlXV0KbmFtZSA9ICJiYXNlNjQiCnZlcnNpb24gPSAiMC4yMi4xIgpzb3VyY2UgPSAicmVnaXN0cnkraHR0cHM6Ly9naXRodWIuY29tL3J1c3QtbGFuZy9jcmF0ZXMuaW8taW5kZXgiCmNoZWNrc3VtID0gIjcyYjMyNTRmMTYyNTFhODM4MWFhMTJlNDBlM2M0ZDJmMDE5OWY4YzY1MDhmYmVjYjlkOTFmNTc1ZTBmYmI4YzYiCgpbW3BhY2thZ2VdXQpuYW1lID0gImJhc2U2NGN0Igp2ZXJzaW9uID0gIjEuOC4zIgpzb3VyY2UgPSAicmVnaXN0cnkraHR0cHM6Ly9naXRodWIuY29tL3J1c3QtbGFuZy9jcmF0ZXMuaW8taW5kZXgiCmNoZWNrc3VtID0gIjJhZjUwMTc3ZTE5MGUwN2EyNmFiNzRmOGIxZWZiZmUyZWY4N2RhMjExNjIyMTMxOGNiMWMyZTgyYmFmN2RlMDYiCgpbW3BhY2thZ2VdXQpuYW1lID0gImJlY2gzMiIKdmVyc2lvbiA9ICIwLjExLjEiCnNvdXJjZSA9ICJyZWdpc3RyeStodHRwczovL2dpdGh1Yi5jb20vcnVzdC1sYW5nL2NyYXRlcy5pby1pbmRleCIKY2hlY2tzdW0gPSAiMzI2MzcyNjgzNzdmYzdiMTBhOGM2ZDUxZGUzZTdmYmExY2U1ZGQzNzFhOTZlMzQyYjM0ZTYwNzhkYjU1OGU3ZiIKCltbcGFja2FnZV1dCm5hbWUgPSAiYml0ZmxhZ3MiCnZlcnNpb24gPSAiMi45LjAiCnNvdXJjZSA9ICJyZWdpc3RyeStodHRwczovL2dpdGh1Yi5jb20vcnVzdC1sYW5nL2NyYXRlcy5pby1pbmRleCIKY2hlY2tzdW0gPSAiNWM4MjE0MTE1YjdiZjg0MDk5ZjEzMDkzMjRlNjMxNDFkNGM1ZDdjYzI2ODYyZjk3YTBhODU3ZGJlZmUxNjViZCIKCltbcGFja2FnZV1dCm5hbWUgPSAiYmxvY2stYnVmZmVyIgp2ZXJzaW9uID0gIjAuMTAuNCIKc291cmNlID0gInJlZ2lzdHJ5K2h0dHBzOi8vZ2l0aHViLmNvbS9ydXN0LWxhbmcvY3JhdGVzLmlvLWluZGV4IgpjaGVja3N1bSA9ICIzMDc4Yzc2MjliNjJkM2YwNDM5NTE3ZmEzOTQ5OTZhY2FjYzVjYmM5MWM1YTIwZDhjNjU4ZTc3YWJkNTAzYTcxIgpkZXBlbmRlbmNpZXMgPSBbCiAiZ2VuZXJpYy1hcnJheSAwLjE0LjciLApdCgpbW3BhY2thZ2VdXQpuYW1lID0gImJ1bXBhbG8iCnZlcnNpb24gPSAiMy4xOS4xIgpzb3VyY2UgPSAicmVnaXN0cnkraHR0cHM6Ly9naXRodWIuY29tL3J1c3QtbGFuZy9jcmF0ZXMuaW8taW5kZXgiCmNoZWNrc3VtID0gIjVkZDlkYzczOGI3YTgzMTFjN2FkZTE1MjQyNDk3NGQ4MTE1ZjJjZGFkNjFlOGRhYjhkYWM5ZjIzNjIyOTg1MTAiCgpbW3BhY2thZ2VdXQpuYW1lID0gImNmZy1pZiIKdmVyc2lvbiA9ICIxLjAuNCIKc291cmNlID0gInJlZ2lzdHJ5K2h0dHBzOi8vZ2l0aHViLmNvbS9ydXN0LWxhbmcvY3JhdGVzLmlvLWluZGV4IgpjaGVja3N1bSA9ICI5MzMwZjhiMmZmMTNmMzQ1NDBiNDRlOTQ2ZWYzNTExMTgyNTcyN2IzOGQzMzI4NmVmOTg2MTQyNjE1MTIxODAxIgoKW1twYWNrYWdlXV0KbmFtZSA9ICJjbGFwIgp2ZXJzaW9uID0gIjQuNS41NCIKc291cmNlID0gInJlZ2lzdHJ5K2h0dHBzOi8vZ2l0aHViLmNvbS9ydXN0LWxhbmcvY3JhdGVzLmlvLWluZGV4IgpjaGVja3N1bSA9ICJjNmU2ZmY5ZGNkNzljZmY1Y2Q5NjlhMTdhNTQ1ZDc5ZTg0YWIwODZlNDQ0MTAyYTU5MWUyODhhOGFhM2NlMzk0IgpkZXBlbmRlbmNpZXMgPSBbCiAiY2xhcF9idWlsZGVyIiwKICJjbGFwX2Rlcml2ZSIsCl0KCltbcGFja2FnZV1dCm5hbWUgPSAiY2xhcF9idWlsZGVyIgp2ZXJzaW9uID0gIjQuNS41NCIKc291cmNlID0gInJlZ2lzdHJ5K2h0dHBzOi8vZ2l0aHViLmNvbS9ydXN0LWxhbmcvY3JhdGVzLmlvLWluZGV4IgpjaGVja3N1bSA9ICJmYTQyY2Y0ZDJiN2E0MWJjOGY2NjNhN2NhYjQwMzFlYmFmYTFiZjM4NzU3MDViZmFmODQ2NmRjNjBhYjUyYzAwIgpkZXBlbmRlbmNpZXMgPSBbCiAiYW5zdHJlYW0iLAogImFuc3R5bGUiLAogImNsYXBfbGV4IiwKICJzdHJzaW0iLApdCgpbW3BhY2thZ2VdXQpuYW1lID0gImNsYXBfZGVyaXZlIgp2ZXJzaW9uID0gIjQuNS40OSIKc291cmNlID0gInJlZ2lzdHJ5K2h0dHBzOi8vZ2l0aHViLmNvbS9ydXN0LWxhbmcvY3JhdGVzLmlvLWluZGV4IgpjaGVja3N1bSA9ICIyYTBiNTQ4N2FmZWFiMmRlYjJmZjRlMDNhODA3YWQxYTAzYWM1MzJmZjVhMmNlZTVkODY4ODQ0NDBjN2Y3NjcxIgpkZXBlbmRlbmNpZXMgPSBbCiAiaGVjayIsCiAicHJvYy1tYWNybzIiLAogInF1b3RlIiwKICJzeW4iLApdCgpbW3BhY2thZ2VdXQpuYW1lID0gImNsYXBfbGV4Igp2ZXJzaW9uID0gIjAuNy43Igpzb3VyY2UgPSAicmVnaXN0cnkraHR0cHM6Ly9naXRodWIuY29tL3J1c3QtbGFuZy9jcmF0ZXMuaW8taW5kZXgiCmNoZWNrc3VtID0gImMzZTY0YjBjYzA0MzliMTJkZjJmYTY3OGVhZTg5YTFjNTZhNTI5ZmQwNjdhOTExNWY3ODI3ZjFmZmZkMjJiMzIiCgpbW3BhY2thZ2VdXQpuYW1lID0gImNvbG9yY2hvaWNlIgp2ZXJzaW9uID0gIjEuMC40Igpzb3VyY2UgPSAicmVnaXN0cnkraHR0cHM6Ly9naXRodWIuY29tL3J1c3QtbGFuZy9jcmF0ZXMuaW8taW5kZXgiCmNoZWNrc3VtID0gImIwNWI2MWRjNTExMmNiYjE3ZTRiNmNkNjE3OTBkOTg0NWQxMzg4ODM1NjM5MTYyNGNiZTdlNDFlZmVhYzFlNzUiCgpbW3BhY2thZ2VdXQpuYW1lID0gImNvbG9yZWQiCnZlcnNpb24gPSAiMy4wLjAiCnNvdXJjZSA9ICJyZWdpc3RyeStodHRwczovL2dpdGh1Yi5jb20vcnVzdC1sYW5nL2NyYXRlcy5pby1pbmRleCIKY2hlY2tzdW0gPSAiZmRlMGUwZWM5MGM5ZGZiM2I0YjFhMDg5MWE3ZGNkMGUyYmZmZGUyZjdlZmVkNWZlN2M5YmIwMGU1YmZiOTE1ZSIKZGVwZW5kZW5jaWVzID0gWwogIndpbmRvd3Mtc3lzIDAuNTkuMCIsCl0KCltbcGFja2FnZV1dCm5hbWUgPSAiY29uc3Qtb2lkIgp2ZXJzaW9uID0gIjAuOS42Igpzb3VyY2UgPSAicmVnaXN0cnkraHR0cHM6Ly9naXRodWIuY29tL3J1c3QtbGFuZy9jcmF0ZXMuaW8taW5kZXgiCmNoZWNrc3VtID0gImMyNDU5Mzc3Mjg1YWQ4NzQwNTRkNzk3ZjNjY2ViZjk4NDk3OGFhMzkxMjlmNmVhZmRlNWNkYzgzMTViNjEyZjgiCgpbW3BhY2thZ2VdXQpuYW1lID0gImNvbnZlcnRfY2FzZSIKdmVyc2lvbiA9ICIwLjguMCIKc291cmNlID0gInJlZ2lzdHJ5K2h0dHBzOi8vZ2l0aHViLmNvbS9ydXN0LWxhbmcvY3JhdGVzLmlvLWluZGV4IgpjaGVja3N1bSA9ICJiYWFhYTBlY2NhNWI1MTk4N2I5NDIzY2NkYzk3MTUxNGRkOGIwYmI3YjQwNjBiOTgzZDM2NjRkYWQzZjFmODlmIgpkZXBlbmRlbmNpZXMgPSBbCiAidW5pY29kZS1zZWdtZW50YXRpb24iLApdCgpbW3BhY2thZ2VdXQpuYW1lID0gImNwdWZlYXR1cmVzIgp2ZXJzaW9uID0gIjAuMi4xNyIKc291cmNlID0gInJlZ2lzdHJ5K2h0dHBzOi8vZ2l0aHViLmNvbS9ydXN0LWxhbmcvY3JhdGVzLmlvLWluZGV4IgpjaGVja3N1bSA9ICI1OWVkNTgzOGVlYmIyNmEyYmIyZTU4ZjZkNWI1MzE2OTg5YWU5ZDA4YmFiMTBlMGU2ZDEwM2U2NTZkMWIwMjgwIgpkZXBlbmRlbmNpZXMgPSBbCiAibGliYyIsCl0KCltbcGFja2FnZV1dCm5hbWUgPSAiY3J5cHRvLWNvbW1vbiIKdmVyc2lvbiA9ICIwLjEuNyIKc291cmNlID0gInJlZ2lzdHJ5K2h0dHBzOi8vZ2l0aHViLmNvbS9ydXN0LWxhbmcvY3JhdGVzLmlvLWluZGV4IgpjaGVja3N1bSA9ICI3OGM4MjkyMDU1ZDFjMWRmMGNjZTVkMTgwMzkzZGM4Y2NlMGFiZWMwYTcxMDJhZGI2YzdiMWVlZjYwMTZkNjBhIgpkZXBlbmRlbmNpZXMgPSBbCiAiZ2VuZXJpYy1hcnJheSAwLjE0LjciLAogInR5cGVudW0iLApdCgpbW3BhY2thZ2VdXQpuYW1lID0gImN1cnZlMjU1MTktZGFsZWsiCnZlcnNpb24gPSAiNC4xLjMiCnNvdXJjZSA9ICJyZWdpc3RyeStodHRwczovL2dpdGh1Yi5jb20vcnVzdC1sYW5nL2NyYXRlcy5pby1pbmRleCIKY2hlY2tzdW0gPSAiOTdmYjhiN2M0NTAzZGU3ZDZhZTdiNDJhYjcyYTVhNTk4NTdiNGM5MzdlYzI3YTNkNDUzOWRiYTk1YjVhYjJiZSIKZGVwZW5kZW5jaWVzID0gWwogImNmZy1pZiIsCiAiY3B1ZmVhdHVyZXMiLAogImN1cnZlMjU1MTktZGFsZWstZGVyaXZlIiwKICJkaWdlc3QiLAogImZpYXQtY3J5cHRvIiwKICJydXN0Y192ZXJzaW9uIiwKICJzdWJ0bGUiLAogInplcm9pemUiLApdCgpbW3BhY2thZ2VdXQpuYW1lID0gImN1cnZlMjU1MTktZGFsZWstZGVyaXZlIgp2ZXJzaW9uID0gIjAuMS4xIgpzb3VyY2UgPSAicmVnaXN0cnkraHR0cHM6Ly9naXRodWIuY29tL3J1c3QtbGFuZy9jcmF0ZXMuaW8taW5kZXgiCmNoZWNrc3VtID0gImY0Njg4MmUxNzk5OWM2Y2M1OTBhZjU5MjI5MDQzMmJlM2JjZTA0MjhjYjBkNWY4YjY3MTVlNGRjN2IzODNlYjMiCmRlcGVuZGVuY2llcyA9IFsKICJwcm9jLW1hY3JvMiIsCiAicXVvdGUiLAogInN5biIsCl0KCltbcGFja2FnZV1dCm5hbWUgPSAiZGVyIgp2ZXJzaW9uID0gIjAuNy4xMCIKc291cmNlID0gInJlZ2lzdHJ5K2h0dHBzOi8vZ2l0aHViLmNvbS9ydXN0LWxhbmcvY3JhdGVzLmlvLWluZGV4IgpjaGVja3N1bSA9ICJlN2MxODMyODM3YjkwNWJiZmI1MTAxZTA3Y2MyNGM4ZGVkZGY1MmY5MzIyNWVlZTZlYWQ1ZjRkNjNkNTNkZGNiIgpkZXBlbmRlbmNpZXMgPSBbCiAiY29uc3Qtb2lkIiwKICJ6ZXJvaXplIiwKXQoKW1twYWNrYWdlXV0KbmFtZSA9ICJkaWdlc3QiCnZlcnNpb24gPSAiMC4xMC43Igpzb3VyY2UgPSAicmVnaXN0cnkraHR0cHM6Ly9naXRodWIuY29tL3J1c3QtbGFuZy9jcmF0ZXMuaW8taW5kZXgiCmNoZWNrc3VtID0gIjllZDlhMjgxZjdiYzliNzU3NmU2MTQ2OGJhNjE1YTY2YTVjOGNmZGZmNDI0MjBhNzBhYTgyNzAxYTNiMWUyOTIiCmRlcGVuZGVuY2llcyA9IFsKICJibG9jay1idWZmZXIiLAogImNyeXB0by1jb21tb24iLApdCgpbW3BhY2thZ2VdXQpuYW1lID0gImVkMjU1MTkiCnZlcnNpb24gPSAiMi4yLjMiCnNvdXJjZSA9ICJyZWdpc3RyeStodHRwczovL2dpdGh1Yi5jb20vcnVzdC1sYW5nL2NyYXRlcy5pby1pbmRleCIKY2hlY2tzdW0gPSAiMTE1NTMxYmFiYzEyOTY5NmE1OGM2NGE0ZmVmMGE4YmY5ZTk2OTg2MjlmYjk3ZTllNDA3NjdkMjM1Y2ZiY2Q1MyIKZGVwZW5kZW5jaWVzID0gWwogInBrY3M4IiwKICJzaWduYXR1cmUiLApdCgpbW3BhY2thZ2VdXQpuYW1lID0gImVkMjU1MTktZGFsZWsiCnZlcnNpb24gPSAiMi4yLjAiCnNvdXJjZSA9ICJyZWdpc3RyeStodHRwczovL2dpdGh1Yi5jb20vcnVzdC1sYW5nL2NyYXRlcy5pby1pbmRleCIKY2hlY2tzdW0gPSAiNzBlNzk2YzA4MWNlZTY3ZGM3NTVlMWEzNmEwYTE3MmI4OTdmYWI4NWZjM2Y2YmM0ODMwNzk5MWY2NGU0ZWNhOSIKZGVwZW5kZW5jaWVzID0gWwogImN1cnZlMjU1MTktZGFsZWsiLAogImVkMjU1MTkiLAogInNlcmRlIiwKICJzaGEyIiwKICJzdWJ0bGUiLAogInplcm9pemUiLApdCgpbW3BhY2thZ2VdXQpuYW1lID0gImVpdGhlciIKdmVyc2lvbiA9ICIxLjE1LjAiCnNvdXJjZSA9ICJyZWdpc3RyeStodHRwczovL2dpdGh1Yi5jb20vcnVzdC1sYW5nL2NyYXRlcy5pby1pbmRleCIKY2hlY2tzdW0gPSAiNDhjNzU3OTQ4YzVlZGUwZTQ2MTc3YjdhZGQyZTY3MTU1ZjcwZTMzYzA3ZmVhODI4NGRmNjU3NmRhNzBiMzcxOSIKCltbcGFja2FnZV1dCm5hbWUgPSAiZW5kaWFuLXR5cGUiCnZlcnNpb24gPSAiMC4xLjIiCnNvdXJjZSA9ICJyZWdpc3RyeStodHRwczovL2dpdGh1Yi5jb20vcnVzdC1sYW5nL2NyYXRlcy5pby1pbmRleCIKY2hlY2tzdW0gPSAiYzM0ZjA0NjY2ZDgzNWZmNWQ2MmUwNThjMzk5NTE0N2MwNmY0MmZlODZmZjA1MzMzNzYzMmJjYTgzZTQyNzAyZCIKCltbcGFja2FnZV1dCm5hbWUgPSAiZXF1aXZhbGVudCIKdmVyc2lvbiA9ICIxLjAuMiIKc291cmNlID0gInJlZ2lzdHJ5K2h0dHBzOi8vZ2l0aHViLmNvbS9ydXN0LWxhbmcvY3JhdGVzLmlvLWluZGV4IgpjaGVja3N1bSA9ICI4NzdhNGFjZTg3MTNiMGJjZjJhNGU3ZWVjODI1MjljMDI5ZjFkMDYxOTg4NmQxODE0NWZlYTk2YzNmZmU1YzBmIgoKW1twYWNrYWdlXV0KbmFtZSA9ICJmaWF0LWNyeXB0byIKdmVyc2lvbiA9ICIwLjIuOSIKc291cmNlID0gInJlZ2lzdHJ5K2h0dHBzOi8vZ2l0aHViLmNvbS9ydXN0LWxhbmcvY3JhdGVzLmlvLWluZGV4IgpjaGVja3N1bSA9ICIyOGRlYTUxOWE5Njk1Yjk5NzcyMTY4NzlhM2ViZmRkZjkyZjFjMDhjMDVkOTg0Zjg5OTZhZWNkNmVjZGM4MTFkIgoKW1twYWNrYWdlXV0KbmFtZSA9ICJmb2xkaGFzaCIKdmVyc2lvbiA9ICIwLjEuNSIKc291cmNlID0gInJlZ2lzdHJ5K2h0dHBzOi8vZ2l0aHViLmNvbS9ydXN0LWxhbmcvY3JhdGVzLmlvLWluZGV4IgpjaGVja3N1bSA9ICJkOWM0ZjVkYWM1ZTE1YzI0ZWI5OTljMjYxODFhNmNhNDBiMzlmZTk0NmNiZTRjMjYzYzcyMDk0NjdiYzgzYWYyIgoKW1twYWNrYWdlXV0KbmFtZSA9ICJnZW5lcmljLWFycmF5Igp2ZXJzaW9uID0gIjAuMTQuNyIKc291cmNlID0gInJlZ2lzdHJ5K2h0dHBzOi8vZ2l0aHViLmNvbS9ydXN0LWxhbmcvY3JhdGVzLmlvLWluZGV4IgpjaGVja3N1bSA9ICI4NTY0OWNhNTFmZDcyMjcyZDc4MjFhZGFmMjc0YWQ5MWMyODgyNzc3MTNkOWMxODgyMGQ4NDk5YTdmZjY5ZTlhIgpkZXBlbmRlbmNpZXMgPSBbCiAidHlwZW51bSIsCiAidmVyc2lvbl9jaGVjayIsCl0KCltbcGFja2FnZV1dCm5hbWUgPSAiZ2VuZXJpYy1hcnJheSIKdmVyc2lvbiA9ICIxLjMuNSIKc291cmNlID0gInJlZ2lzdHJ5K2h0dHBzOi8vZ2l0aHViLmNvbS9ydXN0LWxhbmcvY3JhdGVzLmlvLWluZGV4IgpjaGVja3N1bSA9ICJlYWY1N2M0OWE5NWZkMWZlMjRiOTBiMzAzM2JlZTZkYzdlOGYxMjg4ZDUxNDk0Y2I0NGU2MjdjMjk1ZTM4NTQyIgpkZXBlbmRlbmNpZXMgPSBbCiAicnVzdHZlcnNpb24iLAogInR5cGVudW0iLApdCgpbW3BhY2thZ2VdXQpuYW1lID0gImdldHJhbmRvbSIKdmVyc2lvbiA9ICIwLjIuMTciCnNvdXJjZSA9ICJyZWdpc3RyeStodHRwczovL2dpdGh1Yi5jb20vcnVzdC1sYW5nL2NyYXRlcy5pby1pbmRleCIKY2hlY2tzdW0gPSAiZmYyYWJjMDBiZTdmY2E2ZWJjNDc0NTI0Njk3YWUyNzZhZDg0N2FkMGE2YjNmYWE0YmNiMDI3ZTlhNDYxNGFkMCIKZGVwZW5kZW5jaWVzID0gWwogImNmZy1pZiIsCiAibGliYyIsCiAid2FzaSIsCl0KCltbcGFja2FnZV1dCm5hbWUgPSAiaGFzaGJyb3duIgp2ZXJzaW9uID0gIjAuMTUuNSIKc291cmNlID0gInJlZ2lzdHJ5K2h0dHBzOi8vZ2l0aHViLmNvbS9ydXN0LWxhbmcvY3JhdGVzLmlvLWluZGV4IgpjaGVja3N1bSA9ICI5MjI5Y2ZlNTNkZmQ2OWYwNjA5YTQ5ZjY1NDYxYmQ5MzAwMWVhMWVmODg5Y2Q1NTI5ZGQxNzY1OTNmNTMzOGExIgpkZXBlbmRlbmNpZXMgPSBbCiAiZm9sZGhhc2giLAogInNlcmRlIiwKXQoKW1twYWNrYWdlXV0KbmFtZSA9ICJoYXNoYnJvd24iCnZlcnNpb24gPSAiMC4xNi4xIgpzb3VyY2UgPSAicmVnaXN0cnkraHR0cHM6Ly9naXRodWIuY29tL3J1c3QtbGFuZy9jcmF0ZXMuaW8taW5kZXgiCmNoZWNrc3VtID0gIjg0MWQxY2M5YmVkN2Y5MjM2ZjMyMWRmOTc3MDMwMzczZjRhNDE2M2FlMWE3ZGJmZTFhNTFhMmMxYTUxZDkxMDAiCgpbW3BhY2thZ2VdXQpuYW1lID0gImhlY2siCnZlcnNpb24gPSAiMC41LjAiCnNvdXJjZSA9ICJyZWdpc3RyeStodHRwczovL2dpdGh1Yi5jb20vcnVzdC1sYW5nL2NyYXRlcy5pby1pbmRleCIKY2hlY2tzdW0gPSAiMjMwNGUwMDk4M2Y4N2ZmYjM4YjU1YjQ0NGI1ZTNiNjBhODg0YjVkMzBjMGZjYTdkODJmZTMzNDQ5YmJlNTVlYSIKCltbcGFja2FnZV1dCm5hbWUgPSAiaGV4Igp2ZXJzaW9uID0gIjAuNC4zIgpzb3VyY2UgPSAicmVnaXN0cnkraHR0cHM6Ly9naXRodWIuY29tL3J1c3QtbGFuZy9jcmF0ZXMuaW8taW5kZXgiCmNoZWNrc3VtID0gIjdmMjQyNTRhYTlhNTRiNWM4NThlYWVlMmY1YmNjZGI0NmFhZjBlNDg2YTU5NWVkNWZkOGY4NmJhNTUyMzJhNzAiCgpbW3BhY2thZ2VdXQpuYW1lID0gImhleC1saXRlcmFsIgp2ZXJzaW9uID0gIjAuNC4xIgpzb3VyY2UgPSAicmVnaXN0cnkraHR0cHM6Ly9naXRodWIuY29tL3J1c3QtbGFuZy9jcmF0ZXMuaW8taW5kZXgiCmNoZWNrc3VtID0gIjZmZTIyNjdkNGVkNDliYzA3YjYzODAxNTU5YmUyOGM3MThlYTA2YzQ3MzhiN2EwM2M5NGRmNzM4NmQyY2RlNDYiCgpbW3BhY2thZ2VdXQpuYW1lID0gImluZGV4bWFwIgp2ZXJzaW9uID0gIjIuMTMuMCIKc291cmNlID0gInJlZ2lzdHJ5K2h0dHBzOi8vZ2l0aHViLmNvbS9ydXN0LWxhbmcvY3JhdGVzLmlvLWluZGV4IgpjaGVja3N1bSA9ICI3NzE0ZTcwNDM3YTdkYzNhYzhlYjdlNmY4ZGY3NWZkOGViNDIyNjc1ZmM3Njc4YWZmNzM2NDMwMTA5MmIxMDE3IgpkZXBlbmRlbmNpZXMgPSBbCiAiZXF1aXZhbGVudCIsCiAiaGFzaGJyb3duIDAuMTYuMSIsCiAic2VyZGUiLAogInNlcmRlX2NvcmUiLApdCgpbW3BhY2thZ2VdXQpuYW1lID0gImlzX3Rlcm1pbmFsX3BvbHlmaWxsIgp2ZXJzaW9uID0gIjEuNzAuMiIKc291cmNlID0gInJlZ2lzdHJ5K2h0dHBzOi8vZ2l0aHViLmNvbS9ydXN0LWxhbmcvY3JhdGVzLmlvLWluZGV4IgpjaGVja3N1bSA9ICJhNmNiMTM4YmI3OWExNDZjMWJkNDYwMDA1NjIzZTE0MmVmMDE4MWUzZDAyMTljYjQ5M2UwMmY3ZDA4YTM1Njk1IgoKW1twYWNrYWdlXV0KbmFtZSA9ICJpdGVydG9vbHMiCnZlcnNpb24gPSAiMC4xNC4wIgpzb3VyY2UgPSAicmVnaXN0cnkraHR0cHM6Ly9naXRodWIuY29tL3J1c3QtbGFuZy9jcmF0ZXMuaW8taW5kZXgiCmNoZWNrc3VtID0gIjJiMTkyYzc4MjAzN2ZhZGQ5Y2ZhNzU1NDgzMTA0ODhhYWJkYmYzZDJkYTczODg1YjMxYmQwYWJkMDMzNTEyODUiCmRlcGVuZGVuY2llcyA9IFsKICJlaXRoZXIiLApdCgpbW3BhY2thZ2VdXQpuYW1lID0gIml0b2EiCnZlcnNpb24gPSAiMS4wLjE3Igpzb3VyY2UgPSAicmVnaXN0cnkraHR0cHM6Ly9naXRodWIuY29tL3J1c3QtbGFuZy9jcmF0ZXMuaW8taW5kZXgiCmNoZWNrc3VtID0gIjkyZWNjNjYxODE4MWRlZjA0NTczOTJjY2QwZWU1MTE5OGUwNjVlMDE2ZDFkNTI3YTdhYzFiNmRjN2MxZjA5ZDIiCgpbW3BhY2thZ2VdXQpuYW1lID0gImtlY2NhayIKdmVyc2lvbiA9ICIwLjEuNSIKc291cmNlID0gInJlZ2lzdHJ5K2h0dHBzOi8vZ2l0aHViLmNvbS9ydXN0LWxhbmcvY3JhdGVzLmlvLWluZGV4IgpjaGVja3N1bSA9ICJlY2MyYWY5YTExMTljNTFmMTJhMTQ2MDdlNzgzY2I5NzdiZGU1OGJjMDY5ZmYwYzNkYTEwOTVlNjM1ZDcwNjU0IgpkZXBlbmRlbmNpZXMgPSBbCiAiY3B1ZmVhdHVyZXMiLApdCgpbW3BhY2thZ2VdXQpuYW1lID0gImxhenlfc3RhdGljIgp2ZXJzaW9uID0gIjEuNS4wIgpzb3VyY2UgPSAicmVnaXN0cnkraHR0cHM6Ly9naXRodWIuY29tL3J1c3QtbGFuZy9jcmF0ZXMuaW8taW5kZXgiCmNoZWNrc3VtID0gImJiZDJiY2I0Yzk2M2YyZGRhZTA2YTJlZmM3ZTlmMzU5MTMxMjQ3M2M1MGM2Njg1ZTFmMjk4MDY4MzE2ZTY2ZmUiCgpbW3BhY2thZ2VdXQpuYW1lID0gImxlYjEyOGZtdCIKdmVyc2lvbiA9ICIwLjEuMCIKc291cmNlID0gInJlZ2lzdHJ5K2h0dHBzOi8vZ2l0aHViLmNvbS9ydXN0LWxhbmcvY3JhdGVzLmlvLWluZGV4IgpjaGVja3N1bSA9ICIwOWVkZDllOGI1NGU0OWU1ODdlNGY2Mjk1YTdkMjljM2VhOTRkNDY5Y2I0MGFiOGNhNzBiMjg4MjQ4YTgxZGIyIgoKW1twYWNrYWdlXV0KbmFtZSA9ICJsaWJjIgp2ZXJzaW9uID0gIjAuMi4xODAiCnNvdXJjZSA9ICJyZWdpc3RyeStodHRwczovL2dpdGh1Yi5jb20vcnVzdC1sYW5nL2NyYXRlcy5pby1pbmRleCIKY2hlY2tzdW0gPSAiYmNjMzVhMzg1NDRhODkxYTVmN2M4NjVhY2E1NDhhOTgyY2NiM2I4NjUwYTViMDZkMGZkMzNhMTAyODNjNTZmYyIKCltbcGFja2FnZV1dCm5hbWUgPSAibG9nIgp2ZXJzaW9uID0gIjAuNC4yOSIKc291cmNlID0gInJlZ2lzdHJ5K2h0dHBzOi8vZ2l0aHViLmNvbS9ydXN0LWxhbmcvY3JhdGVzLmlvLWluZGV4IgpjaGVja3N1bSA9ICI1ZTUwMzJlMjQwMTkwNDVjNzYyZDNjMGYyOGY1YjZiOGJiZjM4NTYzYTY1OTA4Mzg5YmY3OTc4NzU4OTIwODk3IgoKW1twYWNrYWdlXV0KbmFtZSA9ICJtZW1jaHIiCnZlcnNpb24gPSAiMi43LjYiCnNvdXJjZSA9ICJyZWdpc3RyeStodHRwczovL2dpdGh1Yi5jb20vcnVzdC1sYW5nL2NyYXRlcy5pby1pbmRleCIKY2hlY2tzdW0gPSAiZjUyYjAwZDM5OTYxZmM1YjI3MzZlYTg1M2M5Y2M4NjIzOGUxNjUwMTdhNDkzZDFkNWM4ZWFjNmJkYzRjYzI3MyIKCltbcGFja2FnZV1dCm5hbWUgPSAibXVsdGl2ZXJzeC1jaGFpbi1jb3JlIgp2ZXJzaW9uID0gIjAuMTQuMCIKc291cmNlID0gInJlZ2lzdHJ5K2h0dHBzOi8vZ2l0aHViLmNvbS9ydXN0LWxhbmcvY3JhdGVzLmlvLWluZGV4IgpjaGVja3N1bSA9ICI3M2YxZjA1MjZjYTA5NDE4NTg0Nzc3NmMyYzAzZGU5N2VhMDgyNzQzZWU0ZTZmNzk5ODYwYWQ2N2U3ZDc4MjUwIgpkZXBlbmRlbmNpZXMgPSBbCiAiYml0ZmxhZ3MiLAogIm11bHRpdmVyc3gtc2MtY29kZWMiLApdCgpbW3BhY2thZ2VdXQpuYW1lID0gIm11bHRpdmVyc3gtY2hhaW4tc2NlbmFyaW8tZm9ybWF0Igp2ZXJzaW9uID0gIjAuMjMuMSIKc291cmNlID0gInJlZ2lzdHJ5K2h0dHBzOi8vZ2l0aHViLmNvbS9ydXN0LWxhbmcvY3JhdGVzLmlvLWluZGV4IgpjaGVja3N1bSA9ICJlNjg4YTBkMzJhNTg3Mzg3MWNkMTkyMjQxODZlY2JmYWEwYjI2ZjdjOGVjNjJmMGNhMzVkN2VlOWQ0NjE2YjQwIgpkZXBlbmRlbmNpZXMgPSBbCiAiYmVjaDMyIiwKICJoZXgiLAogIm51bS1iaWdpbnQiLAogIm51bS10cmFpdHMiLAogInNlcmRlIiwKICJzZXJkZV9qc29uIiwKICJzaGEzIiwKXQoKW1twYWNrYWdlXV0KbmFtZSA9ICJtdWx0aXZlcnN4LWNoYWluLXZtIgp2ZXJzaW9uID0gIjAuMTQuMCIKc291cmNlID0gInJlZ2lzdHJ5K2h0dHBzOi8vZ2l0aHViLmNvbS9ydXN0LWxhbmcvY3JhdGVzLmlvLWluZGV4IgpjaGVja3N1bSA9ICI2ZDllMDQwOGMzNDFiYmQxZDczMzY1YjJkZDhhOTZiMGMyYTQxZjk0NThkM2RjMzUxOWY2NDI3NTc1NGU3OTcxIgpkZXBlbmRlbmNpZXMgPSBbCiAiYml0ZmxhZ3MiLAogImNvbG9yZWQiLAogImVkMjU1MTktZGFsZWsiLAogImhleCIsCiAiaGV4LWxpdGVyYWwiLAogIml0ZXJ0b29scyIsCiAibXVsdGl2ZXJzeC1jaGFpbi1jb3JlIiwKICJtdWx0aXZlcnN4LWNoYWluLXZtLWV4ZWN1dG9yIiwKICJudW0tYmlnaW50IiwKICJudW0tdHJhaXRzIiwKICJyYW5kIiwKICJyYW5kX3NlZWRlciIsCiAic2hhMiIsCiAic2hhMyIsCl0KCltbcGFja2FnZV1dCm5hbWUgPSAibXVsdGl2ZXJzeC1jaGFpbi12bS1leGVjdXRvciIKdmVyc2lvbiA9ICIwLjMuMCIKc291cmNlID0gInJlZ2lzdHJ5K2h0dHBzOi8vZ2l0aHViLmNvbS9ydXN0LWxhbmcvY3JhdGVzLmlvLWluZGV4IgpjaGVja3N1bSA9ICI1MWNjZTdhZTM4Njk2MGZiZjVlODVhZmU0MGNhMTZkNjNmOTI2ZjA2MjBlZDFhMzZiMDE5MjEyYjI4ZTE3MjE5IgoKW1twYWNrYWdlXV0KbmFtZSA9ICJtdWx0aXZlcnN4LXNjIgp2ZXJzaW9uID0gIjAuNTcuMSIKc291cmNlID0gInJlZ2lzdHJ5K2h0dHBzOi8vZ2l0aHViLmNvbS9ydXN0LWxhbmcvY3JhdGVzLmlvLWluZGV4IgpjaGVja3N1bSA9ICIyMDYwMmQ0ZmMzMzYwOTJmYWFkYzAzYjZiNDQ1YzRiYjVlNGRiYzRjODZmYjUzNzI2ZTQ2ZWNhNjcwNzA4MTNhIgpkZXBlbmRlbmNpZXMgPSBbCiAiYml0ZmxhZ3MiLAogImdlbmVyaWMtYXJyYXkgMS4zLjUiLAogImhleC1saXRlcmFsIiwKICJtdWx0aXZlcnN4LWNoYWluLWNvcmUiLAogIm11bHRpdmVyc3gtc2MtY29kZWMiLAogIm11bHRpdmVyc3gtc2MtZGVyaXZlIiwKICJudW0tdHJhaXRzIiwKICJ1bndyYXAtaW5mYWxsaWJsZSIsCl0KCltbcGFja2FnZV1dCm5hbWUgPSAibXVsdGl2ZXJzeC1zYy1jb2RlYyIKdmVyc2lvbiA9ICIwLjIyLjAiCnNvdXJjZSA9ICJyZWdpc3RyeStodHRwczovL2dpdGh1Yi5jb20vcnVzdC1sYW5nL2NyYXRlcy5pby1pbmRleCIKY2hlY2tzdW0gPSAiNDNlMGYyNGEwMjBhZGYzMmZhZmZhZTFjNTc0NzVjNmI3Mjg1YTMyMTZkMWEzNmU0YTczNjE3NjM5NzIxYzJlMCIKZGVwZW5kZW5jaWVzID0gWwogImFycmF5dmVjIiwKICJiaXRmbGFncyIsCiAibXVsdGl2ZXJzeC1zYy1jb2RlYy1kZXJpdmUiLAogIm51bS1iaWdpbnQiLAogInVud3JhcC1pbmZhbGxpYmxlIiwKXQoKW1twYWNrYWdlXV0KbmFtZSA9ICJtdWx0aXZlcnN4LXNjLWNvZGVjLWRlcml2ZSIKdmVyc2lvbiA9ICIwLjIyLjAiCnNvdXJjZSA9ICJyZWdpc3RyeStodHRwczovL2dpdGh1Yi5jb20vcnVzdC1sYW5nL2NyYXRlcy5pby1pbmRleCIKY2hlY2tzdW0gPSAiN2M1ZjE3ZDVlZTIzNjU3ZDVjZGRjN2Y0NDcxOTI1YjVhNDlmN2UyNTMwNmY4YmJhNjU2ZWE2OTE3YWNjNjI5ZCIKZGVwZW5kZW5jaWVzID0gWwogImhleCIsCiAicHJvYy1tYWNybzIiLAogInF1b3RlIiwKICJzeW4iLApdCgpbW3BhY2thZ2VdXQpuYW1lID0gIm11bHRpdmVyc3gtc2MtZGVyaXZlIgp2ZXJzaW9uID0gIjAuNTcuMSIKc291cmNlID0gInJlZ2lzdHJ5K2h0dHBzOi8vZ2l0aHViLmNvbS9ydXN0LWxhbmcvY3JhdGVzLmlvLWluZGV4IgpjaGVja3N1bSA9ICIwZDQ0ZDA4ZDMzNzZjMTk5ZThjMzkxY2MwNzc1MmQyODIyY2QyODk2OTNkYTUzMTlkNzkwNTU5OTUwMWU1NTdmIgpkZXBlbmRlbmNpZXMgPSBbCiAiaGV4IiwKICJwcm9jLW1hY3JvMiIsCiAicXVvdGUiLAogInJhZGl4X3RyaWUiLAogInN5biIsCl0KCltbcGFja2FnZV1dCm5hbWUgPSAibXVsdGl2ZXJzeC1zYy1tZXRhLWxpYiIKdmVyc2lvbiA9ICIwLjU3LjEiCnNvdXJjZSA9ICJyZWdpc3RyeStodHRwczovL2dpdGh1Yi5jb20vcnVzdC1sYW5nL2NyYXRlcy5pby1pbmRleCIKY2hlY2tzdW0gPSAiNDM4MTQ5ZjQ1NTM4MmU2NGQxZDM4M2IyY2I1YmVlMTQ0YzIxNWQyOTQzZDZhMGFlMDZhNTBkMzIyNTY4MGZiYiIKZGVwZW5kZW5jaWVzID0gWwogImNsYXAiLAogImNvbG9yZWQiLAogImNvbnZlcnRfY2FzZSIsCiAiaGV4IiwKICJsYXp5X3N0YXRpYyIsCiAibXVsdGl2ZXJzeC1zYyIsCiAicnVzdGNfdmVyc2lvbiIsCiAic2VtdmVyIiwKICJzZXJkZSIsCiAic2VyZGVfanNvbiIsCiAidG9tbCIsCiAid2FzbXBhcnNlciAwLjIyNy4xIiwKICJ3YXNtcHJpbnRlciIsCiAid2F0IiwKXQoKW1twYWNrYWdlXV0KbmFtZSA9ICJtdWx0aXZlcnN4LXNjLXNjZW5hcmlvIgp2ZXJzaW9uID0gIjAuNTcuMSIKc291cmNlID0gInJlZ2lzdHJ5K2h0dHBzOi8vZ2l0aHViLmNvbS9ydXN0LWxhbmcvY3JhdGVzLmlvLWluZGV4IgpjaGVja3N1bSA9ICIyYTk2ZGZjNzgwMzBmZWMwZjA1OTI4ZDJmYTAzMzRkMWVlYWFhYzJkZjNiODE5MTgyODc2ZTQwMjQ2MWU4YzdlIgpkZXBlbmRlbmNpZXMgPSBbCiAiYmFzZTY0IiwKICJiZWNoMzIiLAogImNvbG9yZWQiLAogImhleCIsCiAiaXRlcnRvb2xzIiwKICJsb2ciLAogIm11bHRpdmVyc3gtY2hhaW4tc2NlbmFyaW8tZm9ybWF0IiwKICJtdWx0aXZlcnN4LWNoYWluLXZtIiwKICJtdWx0aXZlcnN4LWNoYWluLXZtLWV4ZWN1dG9yIiwKICJtdWx0aXZlcnN4LXNjIiwKICJtdWx0aXZlcnN4LXNjLW1ldGEtbGliIiwKICJudW0tYmlnaW50IiwKICJudW0tdHJhaXRzIiwKICJwYXRoZGlmZiIsCiAic2VyZGUiLAogInNlcmRlX2pzb24iLAogInNoYTIiLAogInVud3JhcC1pbmZhbGxpYmxlIiwKXQoKW1twYWNrYWdlXV0KbmFtZSA9ICJuaWJibGVfdmVjIgp2ZXJzaW9uID0gIjAuMS4wIgpzb3VyY2UgPSAicmVnaXN0cnkraHR0cHM6Ly9naXRodWIuY29tL3J1c3QtbGFuZy9jcmF0ZXMuaW8taW5kZXgiCmNoZWNrc3VtID0gIjc3YTVkODNkZjlmMzZmZTIzZjBjMzY0OGM2YmJiOGIwMjk4YmI1ZjE5MzljOGYyNzA0NDMxMzcxZjRiODRkNDMiCmRlcGVuZGVuY2llcyA9IFsKICJzbWFsbHZlYyIsCl0KCltbcGFja2FnZV1dCm5hbWUgPSAibnVtLWJpZ2ludCIKdmVyc2lvbiA9ICIwLjQuNiIKc291cmNlID0gInJlZ2lzdHJ5K2h0dHBzOi8vZ2l0aHViLmNvbS9ydXN0LWxhbmcvY3JhdGVzLmlvLWluZGV4IgpjaGVja3N1bSA9ICJhNWU0NGY3MjNmMTEzM2M5ZGVhYzY0Njc2MzU3OWZkYjNhYzc0NWU0MThmMmE3YWY5Y2QwYzQzMWRhMWYyMGI5IgpkZXBlbmRlbmNpZXMgPSBbCiAibnVtLWludGVnZXIiLAogIm51bS10cmFpdHMiLApdCgpbW3BhY2thZ2VdXQpuYW1lID0gIm51bS1pbnRlZ2VyIgp2ZXJzaW9uID0gIjAuMS40NiIKc291cmNlID0gInJlZ2lzdHJ5K2h0dHBzOi8vZ2l0aHViLmNvbS9ydXN0LWxhbmcvY3JhdGVzLmlvLWluZGV4IgpjaGVja3N1bSA9ICI3OTY5NjYxZmQyOTU4YTVjYjA5NmU1NmM4ZTFhZDA0NDRhYzJiYmNkMDA2MWJkMjg2NjA0ODVhNDQ4Nzk4NThmIgpkZXBlbmRlbmNpZXMgPSBbCiAibnVtLXRyYWl0cyIsCl0KCltbcGFja2FnZV1dCm5hbWUgPSAibnVtLXRyYWl0cyIKdmVyc2lvbiA9ICIwLjIuMTkiCnNvdXJjZSA9ICJyZWdpc3RyeStodHRwczovL2dpdGh1Yi5jb20vcnVzdC1sYW5nL2NyYXRlcy5pby1pbmRleCIKY2hlY2tzdW0gPSAiMDcxZGZjMDYyNjkwZTkwYjczNGMwYjIyNzNjZTcyYWQwZmZhOTVmMGM3NDU5NmJjMjUwZGNmZDk2MDI2Mjg0MSIKZGVwZW5kZW5jaWVzID0gWwogImF1dG9jZmciLApdCgpbW3BhY2thZ2VdXQpuYW1lID0gIm9uY2VfY2VsbF9wb2x5ZmlsbCIKdmVyc2lvbiA9ICIxLjcwLjIiCnNvdXJjZSA9ICJyZWdpc3RyeStodHRwczovL2dpdGh1Yi5jb20vcnVzdC1sYW5nL2NyYXRlcy5pby1pbmRleCIKY2hlY2tzdW0gPSAiMzg0YjhhYjZkMzcyMTVmM2M1MzAxYTk1YTRhY2NiNWQ2NGFhNjA3ZjFmY2IyNmExMWI1MzAzODc4NDUxYjRmZSIKCltbcGFja2FnZV1dCm5hbWUgPSAicGF0aGRpZmYiCnZlcnNpb24gPSAiMC4yLjMiCnNvdXJjZSA9ICJyZWdpc3RyeStodHRwczovL2dpdGh1Yi5jb20vcnVzdC1sYW5nL2NyYXRlcy5pby1pbmRleCIKY2hlY2tzdW0gPSAiZGY5NGNlMjEwZTViYzEzY2I2NjUxNDc5ZmE0OGQxNGY2MDFkOTg1OGNmZTA0NjdmNDNhZTE1NzAyM2I5MzhkMyIKCltbcGFja2FnZV1dCm5hbWUgPSAicGtjczgiCnZlcnNpb24gPSAiMC4xMC4yIgpzb3VyY2UgPSAicmVnaXN0cnkraHR0cHM6Ly9naXRodWIuY29tL3J1c3QtbGFuZy9jcmF0ZXMuaW8taW5kZXgiCmNoZWNrc3VtID0gImY5NTBiMjM3Nzg0NWNlYmU1Y2Y4YjUxNjVjYjNjYzFhNWUwZmE1Y2ZhM2UxZjdmNTU3MDdkOGZkODJlMGE3YjciCmRlcGVuZGVuY2llcyA9IFsKICJkZXIiLAogInNwa2kiLApdCgpbW3BhY2thZ2VdXQpuYW1lID0gInBwdi1saXRlODYiCnZlcnNpb24gPSAiMC4yLjIxIgpzb3VyY2UgPSAicmVnaXN0cnkraHR0cHM6Ly9naXRodWIuY29tL3J1c3QtbGFuZy9jcmF0ZXMuaW8taW5kZXgiCmNoZWNrc3VtID0gIjg1ZWFlM2M0ZWQyZjUwZGNmZTcyNjQzZGE0YmVmYzMwZGVhZGI0NThhOWI1OTBkNzIwY2RlMmYyYjFlOTdkYTkiCmRlcGVuZGVuY2llcyA9IFsKICJ6ZXJvY29weSIsCl0KCltbcGFja2FnZV1dCm5hbWUgPSAicHJvYy1tYWNybzIiCnZlcnNpb24gPSAiMS4wLjk0Igpzb3VyY2UgPSAicmVnaXN0cnkraHR0cHM6Ly9naXRodWIuY29tL3J1c3QtbGFuZy9jcmF0ZXMuaW8taW5kZXgiCmNoZWNrc3VtID0gImEzMTk3MTc1MmU3MGI4YjI2ODZkN2U0NmVjMTdmYjM4ZGFkNDA1MWQ5NDAyNGM4OGRmNDliNjY3Y2FlYTljODQiCmRlcGVuZGVuY2llcyA9IFsKICJ1bmljb2RlLWlkZW50IiwKXQoKW1twYWNrYWdlXV0KbmFtZSA9ICJxdW90ZSIKdmVyc2lvbiA9ICIxLjAuMzkiCnNvdXJjZSA9ICJyZWdpc3RyeStodHRwczovL2dpdGh1Yi5jb20vcnVzdC1sYW5nL2NyYXRlcy5pby1pbmRleCIKY2hlY2tzdW0gPSAiYzFmMTkxNGNlOTA5ZTE2NThkOTkwNzkxM2I0YjkxOTQ3NDMwYzdkOWJlNTk4YjE1YTE5MTI5MzViOGMwNDgwMSIKZGVwZW5kZW5jaWVzID0gWwogInByb2MtbWFjcm8yIiwKXQoKW1twYWNrYWdlXV0KbmFtZSA9ICJyYWRpeF90cmllIgp2ZXJzaW9uID0gIjAuMi4xIgpzb3VyY2UgPSAicmVnaXN0cnkraHR0cHM6Ly9naXRodWIuY29tL3J1c3QtbGFuZy9jcmF0ZXMuaW8taW5kZXgiCmNoZWNrc3VtID0gImMwNjljMTc5ZmNkYzZhMmZlMjRkOGQxODMwNWNmMDg1ZmRiZDRmOTIyYzA0MTk0M2UyMDM2ODVkNmExYzU4ZmQiCmRlcGVuZGVuY2llcyA9IFsKICJlbmRpYW4tdHlwZSIsCiAibmliYmxlX3ZlYyIsCl0KCltbcGFja2FnZV1dCm5hbWUgPSAicmFuZCIKdmVyc2lvbiA9ICIwLjguNSIKc291cmNlID0gInJlZ2lzdHJ5K2h0dHBzOi8vZ2l0aHViLmNvbS9ydXN0LWxhbmcvY3JhdGVzLmlvLWluZGV4IgpjaGVja3N1bSA9ICIzNGFmOGQxYTBlMjU5MjRiYzViN2M0M2MwNzljOTQyMzM5ZDhmMGE4YjU3YzM5MDQ5YmVmNTgxYjQ2MzI3NDA0IgpkZXBlbmRlbmNpZXMgPSBbCiAibGliYyIsCiAicmFuZF9jaGFjaGEiLAogInJhbmRfY29yZSIsCl0KCltbcGFja2FnZV1dCm5hbWUgPSAicmFuZF9jaGFjaGEiCnZlcnNpb24gPSAiMC4zLjEiCnNvdXJjZSA9ICJyZWdpc3RyeStodHRwczovL2dpdGh1Yi5jb20vcnVzdC1sYW5nL2NyYXRlcy5pby1pbmRleCIKY2hlY2tzdW0gPSAiZTZjMTBhNjNhMGZhMzIyNTJiZTQ5ZDIxZTc3MDlkNGQ0YmFmOGQyMzFjMmRiY2UxZWFhODE0MWI5YjEyN2Q4OCIKZGVwZW5kZW5jaWVzID0gWwogInBwdi1saXRlODYiLAogInJhbmRfY29yZSIsCl0KCltbcGFja2FnZV1dCm5hbWUgPSAicmFuZF9jb3JlIgp2ZXJzaW9uID0gIjAuNi40Igpzb3VyY2UgPSAicmVnaXN0cnkraHR0cHM6Ly9naXRodWIuY29tL3J1c3QtbGFuZy9jcmF0ZXMuaW8taW5kZXgiCmNoZWNrc3VtID0gImVjMGJlNDc5NWUyZjZhMjgwNjliZWMwYjVmZjNlMmFjOWJhZmM5OWU2YTlhN2RjMzU0Nzk5NmM1YzgxNjkyMmMiCmRlcGVuZGVuY2llcyA9IFsKICJnZXRyYW5kb20iLApdCgpbW3BhY2thZ2VdXQpuYW1lID0gInJhbmRfc2VlZGVyIgp2ZXJzaW9uID0gIjAuMy4wIgpzb3VyY2UgPSAicmVnaXN0cnkraHR0cHM6Ly9naXRodWIuY29tL3J1c3QtbGFuZy9jcmF0ZXMuaW8taW5kZXgiCmNoZWNrc3VtID0gIjRhOWZlYmU2NDFkMjg0MmZmYzc2ZWU5NjI2NjhhMTc1Nzg3NjdjNGUwMTczNWU0ODAyYjIxZWQ5YTI0YjJlNGUiCmRlcGVuZGVuY2llcyA9IFsKICJyYW5kX2NvcmUiLApdCgpbW3BhY2thZ2VdXQpuYW1lID0gInJlcXVlc3RzIgp2ZXJzaW9uID0gIjAuMC4wIgpkZXBlbmRlbmNpZXMgPSBbCiAibXVsdGl2ZXJzeC1zYyIsCiAibXVsdGl2ZXJzeC1zYy1zY2VuYXJpbyIsCl0KCltbcGFja2FnZV1dCm5hbWUgPSAicnVzdGNfdmVyc2lvbiIKdmVyc2lvbiA9ICIwLjQuMSIKc291cmNlID0gInJlZ2lzdHJ5K2h0dHBzOi8vZ2l0aHViLmNvbS9ydXN0LWxhbmcvY3JhdGVzLmlvLWluZGV4IgpjaGVja3N1bSA9ICJjZmNiM2EyMmVmNDZlODViNDVkZTZlZTdlNzlkMDYzMzE5ZWJiNjU5NGZhYWZjZjFjMjI1ZWE5MmFiNmU5YjkyIgpkZXBlbmRlbmNpZXMgPSBbCiAic2VtdmVyIiwKXQoKW1twYWNrYWdlXV0KbmFtZSA9ICJydXN0dmVyc2lvbiIKdmVyc2lvbiA9ICIxLjAuMjIiCnNvdXJjZSA9ICJyZWdpc3RyeStodHRwczovL2dpdGh1Yi5jb20vcnVzdC1sYW5nL2NyYXRlcy5pby1pbmRleCIKY2hlY2tzdW0gPSAiYjM5Y2RlZjBmYTgwMGZjNDQ1MjVjODRjY2I1NGEwMjk5NjFhODIxNWY5NjE5NzUzNjM1YTljMGQyNTM4ZDQ2ZCIKCltbcGFja2FnZV1dCm5hbWUgPSAic2VtdmVyIgp2ZXJzaW9uID0gIjEuMC4yNyIKc291cmNlID0gInJlZ2lzdHJ5K2h0dHBzOi8vZ2l0aHViLmNvbS9ydXN0LWxhbmcvY3JhdGVzLmlvLWluZGV4IgpjaGVja3N1bSA9ICJkNzY3ZWIwYWFiYzg4MGIyOTk1NmMzNTczNDE3MGYyNmVkNTUxYTg1OWRiZDM2MWQxNDBjZGJlY2E2MWFiMWUyIgoKW1twYWNrYWdlXV0KbmFtZSA9ICJzZXJkZSIKdmVyc2lvbiA9ICIxLjAuMjI4Igpzb3VyY2UgPSAicmVnaXN0cnkraHR0cHM6Ly9naXRodWIuY29tL3J1c3QtbGFuZy9jcmF0ZXMuaW8taW5kZXgiCmNoZWNrc3VtID0gIjlhOGU5NGVhN2YzNzhiZDMyY2JiZDM3MTk4YTRhOTE0MzYxODBjNWJiNDcyNDExZTQ4YjVlYzJlMjEyNGFlOWUiCmRlcGVuZGVuY2llcyA9IFsKICJzZXJkZV9jb3JlIiwKICJzZXJkZV9kZXJpdmUiLApdCgpbW3BhY2thZ2VdXQpuYW1lID0gInNlcmRlX2NvcmUiCnZlcnNpb24gPSAiMS4wLjIyOCIKc291cmNlID0gInJlZ2lzdHJ5K2h0dHBzOi8vZ2l0aHViLmNvbS9ydXN0LWxhbmcvY3JhdGVzLmlvLWluZGV4IgpjaGVja3N1bSA9ICI0MWQzODVjN2Q0Y2E1OGU1OWZjNzMyYWYyNWMzOTgzYjY3YWM4NTJjMWEyNTAwMGFmZTExNzVkZTQ1OGI2N2FkIgpkZXBlbmRlbmNpZXMgPSBbCiAic2VyZGVfZGVyaXZlIiwKXQoKW1twYWNrYWdlXV0KbmFtZSA9ICJzZXJkZV9kZXJpdmUiCnZlcnNpb24gPSAiMS4wLjIyOCIKc291cmNlID0gInJlZ2lzdHJ5K2h0dHBzOi8vZ2l0aHViLmNvbS9ydXN0LWxhbmcvY3JhdGVzLmlvLWluZGV4IgpjaGVja3N1bSA9ICJkNTQwZjIyMGQzMTg3MTczZGEyMjBmODg1YWI2NjYwODM2N2I2NTc0ZTkyNTAxMWE5MzUzZTRiYWRkYTkxZDc5IgpkZXBlbmRlbmNpZXMgPSBbCiAicHJvYy1tYWNybzIiLAogInF1b3RlIiwKICJzeW4iLApdCgpbW3BhY2thZ2VdXQpuYW1lID0gInNlcmRlX2pzb24iCnZlcnNpb24gPSAiMS4wLjE0OSIKc291cmNlID0gInJlZ2lzdHJ5K2h0dHBzOi8vZ2l0aHViLmNvbS9ydXN0LWxhbmcvY3JhdGVzLmlvLWluZGV4IgpjaGVja3N1bSA9ICI4M2ZjMDM5NDczYzU1OTVhY2U4NjBkOGM0ZmFmYTIyMGZmNDc0YjNmYzZiZmRiNDI5MzMyN2YxYTM3ZTk0ZDg2IgpkZXBlbmRlbmNpZXMgPSBbCiAiaXRvYSIsCiAibWVtY2hyIiwKICJzZXJkZSIsCiAic2VyZGVfY29yZSIsCiAiem1paiIsCl0KCltbcGFja2FnZV1dCm5hbWUgPSAic2VyZGVfc3Bhbm5lZCIKdmVyc2lvbiA9ICIwLjYuOSIKc291cmNlID0gInJlZ2lzdHJ5K2h0dHBzOi8vZ2l0aHViLmNvbS9ydXN0LWxhbmcvY3JhdGVzLmlvLWluZGV4IgpjaGVja3N1bSA9ICJiZjQxZTBjZmFmNzIyNmRjYTE1ZTgxOTcxNzJjMjk1YTc4Mjg1N2ZjYjk3ZmFkMTgwOGExNjY4NzBkZWU3NWEzIgpkZXBlbmRlbmNpZXMgPSBbCiAic2VyZGUiLApdCgpbW3BhY2thZ2VdXQpuYW1lID0gInNoYTIiCnZlcnNpb24gPSAiMC4xMC45Igpzb3VyY2UgPSAicmVnaXN0cnkraHR0cHM6Ly9naXRodWIuY29tL3J1c3QtbGFuZy9jcmF0ZXMuaW8taW5kZXgiCmNoZWNrc3VtID0gImE3NTA3ZDgxOTc2OWQwMWEzNjVhYjcwNzc5NGE0MDg0MzkyYzgyNGY1NGE3YTZhNzg2MmY4YzNkMDg5MmIyODMiCmRlcGVuZGVuY2llcyA9IFsKICJjZmctaWYiLAogImNwdWZlYXR1cmVzIiwKICJkaWdlc3QiLApdCgpbW3BhY2thZ2VdXQpuYW1lID0gInNoYTMiCnZlcnNpb24gPSAiMC4xMC44Igpzb3VyY2UgPSAicmVnaXN0cnkraHR0cHM6Ly9naXRodWIuY29tL3J1c3QtbGFuZy9jcmF0ZXMuaW8taW5kZXgiCmNoZWNrc3VtID0gIjc1ODcyZDI3OGE4ZjM3ZWY4N2ZhMGRkYmRhNzgwMjYwNWNiMTgzNDQ0OTc5NDk4NjJjMGQ0ZGNiMjkxZWJhNjAiCmRlcGVuZGVuY2llcyA9IFsKICJkaWdlc3QiLAogImtlY2NhayIsCl0KCltbcGFja2FnZV1dCm5hbWUgPSAic2lnbmF0dXJlIgp2ZXJzaW9uID0gIjIuMi4wIgpzb3VyY2UgPSAicmVnaXN0cnkraHR0cHM6Ly9naXRodWIuY29tL3J1c3QtbGFuZy9jcmF0ZXMuaW8taW5kZXgiCmNoZWNrc3VtID0gIjc3NTQ5Mzk5NTUyZGU0NWE4OThhNTgwYzFiNDFkNDQ1YmY3MzBkZjg2N2NjNDRlNmMwMjMzYmJjNGI4MzI5ZGUiCmRlcGVuZGVuY2llcyA9IFsKICJyYW5kX2NvcmUiLApdCgpbW3BhY2thZ2VdXQpuYW1lID0gInNtYWxsdmVjIgp2ZXJzaW9uID0gIjEuMTUuMSIKc291cmNlID0gInJlZ2lzdHJ5K2h0dHBzOi8vZ2l0aHViLmNvbS9ydXN0LWxhbmcvY3JhdGVzLmlvLWluZGV4IgpjaGVja3N1bSA9ICI2N2IxYjdhM2I1ZmU0ZjEzNzY4ODcxODQwNDVmY2Y0NWM2OWU5MmFmNzM0YjdhYWRkYzA1ZmI3NzdiNmZiZDAzIgoKW1twYWNrYWdlXV0KbmFtZSA9ICJzcGtpIgp2ZXJzaW9uID0gIjAuNy4zIgpzb3VyY2UgPSAicmVnaXN0cnkraHR0cHM6Ly9naXRodWIuY29tL3J1c3QtbGFuZy9jcmF0ZXMuaW8taW5kZXgiCmNoZWNrc3VtID0gImQ5MWVkNmM4NThiMDFmOTQyY2Q1NmIzN2E5NGIzZTBhMTc5ODI5MDMyN2QxMjM2ZTRkOWNmNGVhY2E0NGQyOWQiCmRlcGVuZGVuY2llcyA9IFsKICJiYXNlNjRjdCIsCiAiZGVyIiwKXQoKW1twYWNrYWdlXV0KbmFtZSA9ICJzdHJzaW0iCnZlcnNpb24gPSAiMC4xMS4xIgpzb3VyY2UgPSAicmVnaXN0cnkraHR0cHM6Ly9naXRodWIuY29tL3J1c3QtbGFuZy9jcmF0ZXMuaW8taW5kZXgiCmNoZWNrc3VtID0gIjdkYThiNTczNjg0NWQ5ZjJmY2I4MzdlYTVkOWUyNjI4NTY0YjNiMDQzYTcwOTQ4YTNmMGI3Nzg4MzhjNWZiNGYiCgpbW3BhY2thZ2VdXQpuYW1lID0gInN1YnRsZSIKdmVyc2lvbiA9ICIyLjYuMSIKc291cmNlID0gInJlZ2lzdHJ5K2h0dHBzOi8vZ2l0aHViLmNvbS9ydXN0LWxhbmcvY3JhdGVzLmlvLWluZGV4IgpjaGVja3N1bSA9ICIxM2MyYmRkZWNjNTdiMzg0ZGVlMTg2NTIzNThmYjIzMTcyZmFjYjhhMmM1MWNjYzEwZDc0YzE1N2JkZWEzMjkyIgoKW1twYWNrYWdlXV0KbmFtZSA9ICJzeW4iCnZlcnNpb24gPSAiMi4wLjEwMCIKc291cmNlID0gInJlZ2lzdHJ5K2h0dHBzOi8vZ2l0aHViLmNvbS9ydXN0LWxhbmcvY3JhdGVzLmlvLWluZGV4IgpjaGVja3N1bSA9ICJiMDlhNDRhY2NhZDgxZTFiYTFjZDc0YTMyNDYxYmE4OWRlZTg5MDk1YmExN2IzMmY1ZDAzNjgzYjFiMWZjMmEwIgpkZXBlbmRlbmNpZXMgPSBbCiAicHJvYy1tYWNybzIiLAogInF1b3RlIiwKICJ1bmljb2RlLWlkZW50IiwKXQoKW1twYWNrYWdlXV0KbmFtZSA9ICJ0ZXJtY29sb3IiCnZlcnNpb24gPSAiMS40LjEiCnNvdXJjZSA9ICJyZWdpc3RyeStodHRwczovL2dpdGh1Yi5jb20vcnVzdC1sYW5nL2NyYXRlcy5pby1pbmRleCIKY2hlY2tzdW0gPSAiMDY3OTRmOGY2YzVjODk4YjMyNzVhZWJlZmE2YjhhMWNiMjRjZDJjNmM3OTM5N2FiMTU3NzQ4MzdhMGJjNTc1NSIKZGVwZW5kZW5jaWVzID0gWwogIndpbmFwaS11dGlsIiwKXQoKW1twYWNrYWdlXV0KbmFtZSA9ICJ0b21sIgp2ZXJzaW9uID0gIjAuOC4yMyIKc291cmNlID0gInJlZ2lzdHJ5K2h0dHBzOi8vZ2l0aHViLmNvbS9ydXN0LWxhbmcvY3JhdGVzLmlvLWluZGV4IgpjaGVja3N1bSA9ICJkYzFiZWI5OTZiOWQ4MzUyOWE5ZTc1YzE3YTE2ODY3NjdkMTQ4ZDcwNjYzMTQzYzc4NTRkOGI0YTA5Y2VkMzYyIgpkZXBlbmRlbmNpZXMgPSBbCiAiaW5kZXhtYXAiLAogInNlcmRlIiwKICJzZXJkZV9zcGFubmVkIiwKICJ0b21sX2RhdGV0aW1lIiwKICJ0b21sX2VkaXQiLApdCgpbW3BhY2thZ2VdXQpuYW1lID0gInRvbWxfZGF0ZXRpbWUiCnZlcnNpb24gPSAiMC42LjExIgpzb3VyY2UgPSAicmVnaXN0cnkraHR0cHM6Ly9naXRodWIuY29tL3J1c3QtbGFuZy9jcmF0ZXMuaW8taW5kZXgiCmNoZWNrc3VtID0gIjIyY2RkYWY4OGY0ZmJjMTNjNTFhZWJiZjVmOGVjZWI1YzdjNWE5ZGEyYWM0MGExMzUxOWViNWIwYTBlOGYxMWMiCmRlcGVuZGVuY2llcyA9IFsKICJzZXJkZSIsCl0KCltbcGFja2FnZV1dCm5hbWUgPSAidG9tbF9lZGl0Igp2ZXJzaW9uID0gIjAuMjIuMjciCnNvdXJjZSA9ICJyZWdpc3RyeStodHRwczovL2dpdGh1Yi5jb20vcnVzdC1sYW5nL2NyYXRlcy5pby1pbmRleCIKY2hlY2tzdW0gPSAiNDFmZThjNjYwYWU0MjU3ODg3Y2Y2NjM5NDg2MmQyMWRiY2E0YTZkZGQyNmYwNGEzNTYwNDEwNDA2YTJmODE5YSIKZGVwZW5kZW5jaWVzID0gWwogImluZGV4bWFwIiwKICJzZXJkZSIsCiAic2VyZGVfc3Bhbm5lZCIsCiAidG9tbF9kYXRldGltZSIsCiAidG9tbF93cml0ZSIsCiAid2lubm93IiwKXQoKW1twYWNrYWdlXV0KbmFtZSA9ICJ0b21sX3dyaXRlIgp2ZXJzaW9uID0gIjAuMS4yIgpzb3VyY2UgPSAicmVnaXN0cnkraHR0cHM6Ly9naXRodWIuY29tL3J1c3QtbGFuZy9jcmF0ZXMuaW8taW5kZXgiCmNoZWNrc3VtID0gIjVkOTlmOGM5YTc3Mjc4ODRhZmU1MjJlOWJkNWVkYmZjOTFhMzMxMmIzNmE3N2I1ZmI4OTI2ZTRjMzFhNDE4MDEiCgpbW3BhY2thZ2VdXQpuYW1lID0gInR5cGVudW0iCnZlcnNpb24gPSAiMS4xOS4wIgpzb3VyY2UgPSAicmVnaXN0cnkraHR0cHM6Ly9naXRodWIuY29tL3J1c3QtbGFuZy9jcmF0ZXMuaW8taW5kZXgiCmNoZWNrc3VtID0gIjU2MmQ0ODEwNjZiZGUwNjU4Mjc2YTM1NDY3YzRhZjAwYmRjNmVlNzI2MzA1Njk4YTU1Yjg2ZTYxZDdhZDgyYmIiCgpbW3BhY2thZ2VdXQpuYW1lID0gInVuaWNvZGUtaWRlbnQiCnZlcnNpb24gPSAiMS4wLjIyIgpzb3VyY2UgPSAicmVnaXN0cnkraHR0cHM6Ly9naXRodWIuY29tL3J1c3QtbGFuZy9jcmF0ZXMuaW8taW5kZXgiCmNoZWNrc3VtID0gIjkzMTJmN2M0ZjZmZjkwNjliMTY1NDk4MjM0Y2U4YmU2NTgwNTljNjcyODYzMzY2N2M1MjZlMjdkYzJjZjFkZjUiCgpbW3BhY2thZ2VdXQpuYW1lID0gInVuaWNvZGUtc2VnbWVudGF0aW9uIgp2ZXJzaW9uID0gIjEuMTIuMCIKc291cmNlID0gInJlZ2lzdHJ5K2h0dHBzOi8vZ2l0aHViLmNvbS9ydXN0LWxhbmcvY3JhdGVzLmlvLWluZGV4IgpjaGVja3N1bSA9ICJmNmNjZjI1MTIxMjExNGI1NDQzM2VjOTQ5ZmQ2YTc4NDEyNzVmOWFkYTIwZGRkZDJmMjllOWNlZWE0NTAxNDkzIgoKW1twYWNrYWdlXV0KbmFtZSA9ICJ1bmljb2RlLXdpZHRoIgp2ZXJzaW9uID0gIjAuMi4yIgpzb3VyY2UgPSAicmVnaXN0cnkraHR0cHM6Ly9naXRodWIuY29tL3J1c3QtbGFuZy9jcmF0ZXMuaW8taW5kZXgiCmNoZWNrc3VtID0gImI0YWMwNDhkNzFlZGU3ZWU3NmQ1ODU1MTdhZGQ0NWRhNTMwNjYwZWY0MzkwZTQ5YjA5ODczM2M2ZTg5N2YyNTQiCgpbW3BhY2thZ2VdXQpuYW1lID0gInVud3JhcC1pbmZhbGxpYmxlIgp2ZXJzaW9uID0gIjAuMS41Igpzb3VyY2UgPSAicmVnaXN0cnkraHR0cHM6Ly9naXRodWIuY29tL3J1c3QtbGFuZy9jcmF0ZXMuaW8taW5kZXgiCmNoZWNrc3VtID0gIjE1MWFjMDk5NzhkM2MyODYyYzRlMzliNTU3ZjRlY2VlZTJjYzcyMTUwYmM0Y2I0ZjE2YWJmMDYxYjZlMzgxZmIiCgpbW3BhY2thZ2VdXQpuYW1lID0gInV0ZjhwYXJzZSIKdmVyc2lvbiA9ICIwLjIuMiIKc291cmNlID0gInJlZ2lzdHJ5K2h0dHBzOi8vZ2l0aHViLmNvbS9ydXN0LWxhbmcvY3JhdGVzLmlvLWluZGV4IgpjaGVja3N1bSA9ICIwNmFiZGUzNjExNjU3YWRmNjZkMzgzZjAwYjA5M2Q3ZmFlY2M3ZmE1NzA3MWNjZTI1Nzg2NjBjOWYxMDEwODIxIgoKW1twYWNrYWdlXV0KbmFtZSA9ICJ2ZXJzaW9uX2NoZWNrIgp2ZXJzaW9uID0gIjAuOS41Igpzb3VyY2UgPSAicmVnaXN0cnkraHR0cHM6Ly9naXRodWIuY29tL3J1c3QtbGFuZy9jcmF0ZXMuaW8taW5kZXgiCmNoZWNrc3VtID0gIjBiOTI4ZjMzZDk3NWZjNmFkOWY4NmM4ZjI4Mzg1M2FkMjZiZGQ1YjEwYjdmMTU0MmFhMmZhMTVlMjI4OTEwNWEiCgpbW3BhY2thZ2VdXQpuYW1lID0gIndhc2kiCnZlcnNpb24gPSAiMC4xMS4xK3dhc2ktc25hcHNob3QtcHJldmlldzEiCnNvdXJjZSA9ICJyZWdpc3RyeStodHRwczovL2dpdGh1Yi5jb20vcnVzdC1sYW5nL2NyYXRlcy5pby1pbmRleCIKY2hlY2tzdW0gPSAiY2NmM2VjNjUxYTg0N2ViMDFkZTczY2NhZDE1ZWI3ZDk5ZjgwNDg1ZGUwNDNlZmIyZjM3MGNkNjU0ZjRlYTQ0YiIKCltbcGFja2FnZV1dCm5hbWUgPSAid2FzbS1lbmNvZGVyIgp2ZXJzaW9uID0gIjAuMjQ0LjAiCnNvdXJjZSA9ICJyZWdpc3RyeStodHRwczovL2dpdGh1Yi5jb20vcnVzdC1sYW5nL2NyYXRlcy5pby1pbmRleCIKY2hlY2tzdW0gPSAiOTkwMDY1ZjJmZTYzMDAzZmUzMzdiOTMyY2ZiNWUzYjgwZTBiNGQwZjVmZjY1MGU2OTg1YjEwNDhmNjJjODMxOSIKZGVwZW5kZW5jaWVzID0gWwogImxlYjEyOGZtdCIsCiAid2FzbXBhcnNlciAwLjI0NC4wIiwKXQoKW1twYWNrYWdlXV0KbmFtZSA9ICJ3YXNtcGFyc2VyIgp2ZXJzaW9uID0gIjAuMjI3LjEiCnNvdXJjZSA9ICJyZWdpc3RyeStodHRwczovL2dpdGh1Yi5jb20vcnVzdC1sYW5nL2NyYXRlcy5pby1pbmRleCIKY2hlY2tzdW0gPSAiMGY1MWNhZDc3NGZiM2M5NDYxYWI5YmNjYzljNjJkZmI3Mzg4Mzk3YjVkZWRhMzFiZjQwZTgxMDhjY2Q2NzhiMiIKZGVwZW5kZW5jaWVzID0gWwogImJpdGZsYWdzIiwKICJoYXNoYnJvd24gMC4xNS41IiwKICJpbmRleG1hcCIsCiAic2VtdmVyIiwKICJzZXJkZSIsCl0KCltbcGFja2FnZV1dCm5hbWUgPSAid2FzbXBhcnNlciIKdmVyc2lvbiA9ICIwLjI0NC4wIgpzb3VyY2UgPSAicmVnaXN0cnkraHR0cHM6Ly9naXRodWIuY29tL3J1c3QtbGFuZy9jcmF0ZXMuaW8taW5kZXgiCmNoZWNrc3VtID0gIjQ3YjgwN2M3MmUxYmFjNjkzODJiM2E2ZmIzZGJlOGVhNGMwZWQ4N2ZmNTYyOWI4Njg1YWU2YjlhNjExMDI4ZmUiCmRlcGVuZGVuY2llcyA9IFsKICJiaXRmbGFncyIsCiAiaW5kZXhtYXAiLAogInNlbXZlciIsCl0KCltbcGFja2FnZV1dCm5hbWUgPSAid2FzbXByaW50ZXIiCnZlcnNpb24gPSAiMC4yMjcuMSIKc291cmNlID0gInJlZ2lzdHJ5K2h0dHBzOi8vZ2l0aHViLmNvbS9ydXN0LWxhbmcvY3JhdGVzLmlvLWluZGV4IgpjaGVja3N1bSA9ICIzMjQ3NWEwNDU5ZGI1NjM5ZTk4OTIwNmRkODgzM2ZiMDcxMTBlYzA5MmE3Y2IzNDY4YzgyMzQxOTg5Y2FjNGQzIgpkZXBlbmRlbmNpZXMgPSBbCiAiYW55aG93IiwKICJ0ZXJtY29sb3IiLAogIndhc21wYXJzZXIgMC4yMjcuMSIsCl0KCltbcGFja2FnZV1dCm5hbWUgPSAid2FzdCIKdmVyc2lvbiA9ICIyNDQuMC4wIgpzb3VyY2UgPSAicmVnaXN0cnkraHR0cHM6Ly9naXRodWIuY29tL3J1c3QtbGFuZy9jcmF0ZXMuaW8taW5kZXgiCmNoZWNrc3VtID0gImIyZTdiOWY5ZTIzMzExMjc1OTIwZTNkNmI1NmQ2NDEzN2MxNjBjZjhhZjRmODRhNzI4M2IzNmNmZWNiZjRhY2IiCmRlcGVuZGVuY2llcyA9IFsKICJidW1wYWxvIiwKICJsZWIxMjhmbXQiLAogIm1lbWNociIsCiAidW5pY29kZS13aWR0aCIsCiAid2FzbS1lbmNvZGVyIiwKXQoKW1twYWNrYWdlXV0KbmFtZSA9ICJ3YXQiCnZlcnNpb24gPSAiMS4yNDQuMCIKc291cmNlID0gInJlZ2lzdHJ5K2h0dHBzOi8vZ2l0aHViLmNvbS9ydXN0LWxhbmcvY3JhdGVzLmlvLWluZGV4IgpjaGVja3N1bSA9ICJiYmYzNWI4N2VkMzUyZjlhYjZjZDA3MzJhYmRlNWE2N2RkNjE1M2RmZDAyYzQ5M2U2MTQ1OTIxOGIxOTQ1NmZhIgpkZXBlbmRlbmNpZXMgPSBbCiAid2FzdCIsCl0KCltbcGFja2FnZV1dCm5hbWUgPSAid2luYXBpLXV0aWwiCnZlcnNpb24gPSAiMC4xLjExIgpzb3VyY2UgPSAicmVnaXN0cnkraHR0cHM6Ly9naXRodWIuY29tL3J1c3QtbGFuZy9jcmF0ZXMuaW8taW5kZXgiCmNoZWNrc3VtID0gImMyYTdiMWMwM2M4NzYxMjJhYTQzZjMwMjBlNmMzYzNlZTVjMDUwODFjOWEwMDczOWZhZjc1MDNhZWJhMTBkMjIiCmRlcGVuZGVuY2llcyA9IFsKICJ3aW5kb3dzLXN5cyAwLjYxLjIiLApdCgpbW3BhY2thZ2VdXQpuYW1lID0gIndpbmRvd3MtbGluayIKdmVyc2lvbiA9ICIwLjIuMSIKc291cmNlID0gInJlZ2lzdHJ5K2h0dHBzOi8vZ2l0aHViLmNvbS9ydXN0LWxhbmcvY3JhdGVzLmlvLWluZGV4IgpjaGVja3N1bSA9ICJmMDgwNTIyMmU1N2Y3NTIxZDZhNjJlMzZmYTkxNjNiYzg5MWFjZDQyMmY5NzFkZWZlOTdkNjRlNzBkMGE0ZmU1IgoKW1twYWNrYWdlXV0KbmFtZSA9ICJ3aW5kb3dzLXN5cyIKdmVyc2lvbiA9ICIwLjU5LjAiCnNvdXJjZSA9ICJyZWdpc3RyeStodHRwczovL2dpdGh1Yi5jb20vcnVzdC1sYW5nL2NyYXRlcy5pby1pbmRleCIKY2hlY2tzdW0gPSAiMWUzOGJjNGQ3OWVkNjdmZDA3NWJjYzI1MWExYzM5YjMyYTE3NzZiYmU5MmU1YmVmMWYwYmYxZjhjNTMxODUzYiIKZGVwZW5kZW5jaWVzID0gWwogIndpbmRvd3MtdGFyZ2V0cyIsCl0KCltbcGFja2FnZV1dCm5hbWUgPSAid2luZG93cy1zeXMiCnZlcnNpb24gPSAiMC42MS4yIgpzb3VyY2UgPSAicmVnaXN0cnkraHR0cHM6Ly9naXRodWIuY29tL3J1c3QtbGFuZy9jcmF0ZXMuaW8taW5kZXgiCmNoZWNrc3VtID0gImFlMTM3MjI5YmNiZDZjZGYwZjdiODBhMzFkZjYxNzY2MTQ1MDc3ZGRmNDk0MTZhNzI4YjAyY2IzOTIxZmYzZmMiCmRlcGVuZGVuY2llcyA9IFsKICJ3aW5kb3dzLWxpbmsiLApdCgpbW3BhY2thZ2VdXQpuYW1lID0gIndpbmRvd3MtdGFyZ2V0cyIKdmVyc2lvbiA9ICIwLjUyLjYiCnNvdXJjZSA9ICJyZWdpc3RyeStodHRwczovL2dpdGh1Yi5jb20vcnVzdC1sYW5nL2NyYXRlcy5pby1pbmRleCIKY2hlY2tzdW0gPSAiOWI3MjRmNzI3OTZlMDM2YWI5MGMxMDIxZDQ3ODBkNGQzZDY0OGFjYTU5ZTQ5MWU2Yjk4ZTcyNWI4NGU5OTk3MyIKZGVwZW5kZW5jaWVzID0gWwogIndpbmRvd3NfYWFyY2g2NF9nbnVsbHZtIiwKICJ3aW5kb3dzX2FhcmNoNjRfbXN2YyIsCiAid2luZG93c19pNjg2X2dudSIsCiAid2luZG93c19pNjg2X2dudWxsdm0iLAogIndpbmRvd3NfaTY4Nl9tc3ZjIiwKICJ3aW5kb3dzX3g4Nl82NF9nbnUiLAogIndpbmRvd3NfeDg2XzY0X2dudWxsdm0iLAogIndpbmRvd3NfeDg2XzY0X21zdmMiLApdCgpbW3BhY2thZ2VdXQpuYW1lID0gIndpbmRvd3NfYWFyY2g2NF9nbnVsbHZtIgp2ZXJzaW9uID0gIjAuNTIuNiIKc291cmNlID0gInJlZ2lzdHJ5K2h0dHBzOi8vZ2l0aHViLmNvbS9ydXN0LWxhbmcvY3JhdGVzLmlvLWluZGV4IgpjaGVja3N1bSA9ICIzMmE0NjIyMTgwZTdhMGVjMDQ0YmI1NTU0MDRjODAwYmM5ZmQ5ZWMyNjJlYzE0N2VkZDU5ODljY2QwYzAyY2QzIgoKW1twYWNrYWdlXV0KbmFtZSA9ICJ3aW5kb3dzX2FhcmNoNjRfbXN2YyIKdmVyc2lvbiA9ICIwLjUyLjYiCnNvdXJjZSA9ICJyZWdpc3RyeStodHRwczovL2dpdGh1Yi5jb20vcnVzdC1sYW5nL2NyYXRlcy5pby1pbmRleCIKY2hlY2tzdW0gPSAiMDllYzJhN2JiMTUyZTIyNTJiNTNmYTc4MDMxNTAwMDc4Nzk1NDhiYzcwOWMwMzlkZjc2MjdjYWJiZDA1ZDQ2OSIKCltbcGFja2FnZV1dCm5hbWUgPSAid2luZG93c19pNjg2X2dudSIKdmVyc2lvbiA9ICIwLjUyLjYiCnNvdXJjZSA9ICJyZWdpc3RyeStodHRwczovL2dpdGh1Yi5jb20vcnVzdC1sYW5nL2NyYXRlcy5pby1pbmRleCIKY2hlY2tzdW0gPSAiOGU5YjVhZDVhYjgwMmU5N2ViOGUyOTVhYzY3MjBlNTA5ZWU0YzI0M2Y2OWQ3ODEzOTQwMTRlYmZlOGJiZmEwYiIKCltbcGFja2FnZV1dCm5hbWUgPSAid2luZG93c19pNjg2X2dudWxsdm0iCnZlcnNpb24gPSAiMC41Mi42Igpzb3VyY2UgPSAicmVnaXN0cnkraHR0cHM6Ly9naXRodWIuY29tL3J1c3QtbGFuZy9jcmF0ZXMuaW8taW5kZXgiCmNoZWNrc3VtID0gIjBlZWU1MmQzOGMwOTBiM2NhYTc2YzU2M2I4NmMzYTRiZDcxZWYxYTgxOTI4N2MxOWQ1ODZkNzMzNGFlOGVkNjYiCgpbW3BhY2thZ2VdXQpuYW1lID0gIndpbmRvd3NfaTY4Nl9tc3ZjIgp2ZXJzaW9uID0gIjAuNTIuNiIKc291cmNlID0gInJlZ2lzdHJ5K2h0dHBzOi8vZ2l0aHViLmNvbS9ydXN0LWxhbmcvY3JhdGVzLmlvLWluZGV4IgpjaGVja3N1bSA9ICIyNDA5NDhiYzA1YzVlN2M2ZGFiYmEyOGJmODlkODlmZmNlM2UzMDMwMjI4MDllNzNkZWFlZmU0ZjZlYzU2YzY2IgoKW1twYWNrYWdlXV0KbmFtZSA9ICJ3aW5kb3dzX3g4Nl82NF9nbnUiCnZlcnNpb24gPSAiMC41Mi42Igpzb3VyY2UgPSAicmVnaXN0cnkraHR0cHM6Ly9naXRodWIuY29tL3J1c3QtbGFuZy9jcmF0ZXMuaW8taW5kZXgiCmNoZWNrc3VtID0gIjE0N2E1YzgwYWFiZmJmMGM3ZDkwMWNiNTg5NWQxZGUzMGVmMjkwN2ViMjFmYmJhYjI5Y2E5NGM1YjA4YjFhNzgiCgpbW3BhY2thZ2VdXQpuYW1lID0gIndpbmRvd3NfeDg2XzY0X2dudWxsdm0iCnZlcnNpb24gPSAiMC41Mi42Igpzb3VyY2UgPSAicmVnaXN0cnkraHR0cHM6Ly9naXRodWIuY29tL3J1c3QtbGFuZy9jcmF0ZXMuaW8taW5kZXgiCmNoZWNrc3VtID0gIjI0ZDViMjNkYzQxNzQxMjY3OTY4MTM5NmYyYjQ5ZjNkZThjMTQ3M2RlYjUxNmJkMzQ0MTA4NzJlZmY1MWVkMGQiCgpbW3BhY2thZ2VdXQpuYW1lID0gIndpbmRvd3NfeDg2XzY0X21zdmMiCnZlcnNpb24gPSAiMC41Mi42Igpzb3VyY2UgPSAicmVnaXN0cnkraHR0cHM6Ly9naXRodWIuY29tL3J1c3QtbGFuZy9jcmF0ZXMuaW8taW5kZXgiCmNoZWNrc3VtID0gIjU4OWY2ZGE4NGM2NDYyMDQ3NDdkMTI3MGEyYTU2NjFlYTY2ZWQxY2NlZDI2MzFkNTQ2ZmRmYjE1NTk1OWY5ZWMiCgpbW3BhY2thZ2VdXQpuYW1lID0gIndpbm5vdyIKdmVyc2lvbiA9ICIwLjcuMTQiCnNvdXJjZSA9ICJyZWdpc3RyeStodHRwczovL2dpdGh1Yi5jb20vcnVzdC1sYW5nL2NyYXRlcy5pby1pbmRleCIKY2hlY2tzdW0gPSAiNWE1MzY0ZTlkNzdmY2RlZWFhNjA2MmNlZDkyNmVlMzM4MWZhYTJlZTAyZDNlYjgzYTVjMjdhODgyNTU0MDgyOSIKZGVwZW5kZW5jaWVzID0gWwogIm1lbWNociIsCl0KCltbcGFja2FnZV1dCm5hbWUgPSAiemVyb2NvcHkiCnZlcnNpb24gPSAiMC44LjI3Igpzb3VyY2UgPSAicmVnaXN0cnkraHR0cHM6Ly9naXRodWIuY29tL3J1c3QtbGFuZy9jcmF0ZXMuaW8taW5kZXgiCmNoZWNrc3VtID0gIjA4OTQ4NzhhNWZhM2VkZmQ2ZGEzZjg4YzQ4MDVmNGM4NTU4ZTJiOTk2MjI3YTNkODY0ZjQ3ZmUxMWUzODI4MmMiCmRlcGVuZGVuY2llcyA9IFsKICJ6ZXJvY29weS1kZXJpdmUiLApdCgpbW3BhY2thZ2VdXQpuYW1lID0gInplcm9jb3B5LWRlcml2ZSIKdmVyc2lvbiA9ICIwLjguMjciCnNvdXJjZSA9ICJyZWdpc3RyeStodHRwczovL2dpdGh1Yi5jb20vcnVzdC1sYW5nL2NyYXRlcy5pby1pbmRleCIKY2hlY2tzdW0gPSAiODhkMmI4ZDljNjhhZDJiOWU0MzQwZDc4MzI3MTZhNGQyMWEyMmExMTU0Nzc3YWQ1NmVhNTVjNTFhOWNmMzgzMSIKZGVwZW5kZW5jaWVzID0gWwogInByb2MtbWFjcm8yIiwKICJxdW90ZSIsCiAic3luIiwKXQoKW1twYWNrYWdlXV0KbmFtZSA9ICJ6ZXJvaXplIgp2ZXJzaW9uID0gIjEuOC4yIgpzb3VyY2UgPSAicmVnaXN0cnkraHR0cHM6Ly9naXRodWIuY29tL3J1c3QtbGFuZy9jcmF0ZXMuaW8taW5kZXgiCmNoZWNrc3VtID0gImI5NzE1NGU2N2UzMmM4NTQ2NTgyNmU4YmNjMWM1OTQyOWFhYWYxMDdjMWU0YTllNTNjOGQ4Y2NkNWVmZjg4ZDAiCgpbW3BhY2thZ2VdXQpuYW1lID0gInptaWoiCnZlcnNpb24gPSAiMS4wLjE0Igpzb3VyY2UgPSAicmVnaXN0cnkraHR0cHM6Ly9naXRodWIuY29tL3J1c3QtbGFuZy9jcmF0ZXMuaW8taW5kZXgiCmNoZWNrc3VtID0gImJkOGYzZjUwYjg0OGRmMjhmODg3YWNiNjhlNDEyMDFiNWFlYTZiYzhhOGRhY2MwMGZiNDA2MzVmZjlhNzJmZWEiCg==",
- "module": ".",
- "dependencyDepth": 0,
- "isTestFile": false
- },
- {
- "path": "Cargo.toml",
- "content": "W3BhY2thZ2VdCm5hbWUgPSAicmVxdWVzdHMiCnZlcnNpb24gPSAiMC4wLjAiCmF1dGhvcnMgPSBbIkFuZHJlaSBNYXJpbmljYSA8YW5kcmVpLm1hcmluaWNhQG11bHRpdmVyc3guY29tPiJdCmVkaXRpb24gPSAiMjAyMSIKcHVibGlzaCA9IGZhbHNlCgpbbGliXQpwYXRoID0gInNyYy9saWIucnMiCgpbZGVwZW5kZW5jaWVzLm11bHRpdmVyc3gtc2NdCnZlcnNpb24gPSAiMC41Ny4xIgoKW2Rldi1kZXBlbmRlbmNpZXMubXVsdGl2ZXJzeC1zYy1zY2VuYXJpb10KdmVyc2lvbiA9ICIwLjU3LjEiCg==",
- "module": ".",
- "dependencyDepth": 0,
- "isTestFile": false
- },
- {
- "path": "meta/Cargo.lock",
- "content": "IyBUaGlzIGZpbGUgaXMgYXV0b21hdGljYWxseSBAZ2VuZXJhdGVkIGJ5IENhcmdvLgojIEl0IGlzIG5vdCBpbnRlbmRlZCBmb3IgbWFudWFsIGVkaXRpbmcuCnZlcnNpb24gPSA0CgpbW3BhY2thZ2VdXQpuYW1lID0gImFuc3RyZWFtIgp2ZXJzaW9uID0gIjAuNi4yMSIKc291cmNlID0gInJlZ2lzdHJ5K2h0dHBzOi8vZ2l0aHViLmNvbS9ydXN0LWxhbmcvY3JhdGVzLmlvLWluZGV4IgpjaGVja3N1bSA9ICI0M2Q1YjI4MWU3Mzc1NDQzODRlOTY5YTVjY2FkM2YxY2RkMjRiNDgwODZhMGZjMWIyYTUyNjJhMjZiOGY0ZjRhIgpkZXBlbmRlbmNpZXMgPSBbCiAiYW5zdHlsZSIsCiAiYW5zdHlsZS1wYXJzZSIsCiAiYW5zdHlsZS1xdWVyeSIsCiAiYW5zdHlsZS13aW5jb24iLAogImNvbG9yY2hvaWNlIiwKICJpc190ZXJtaW5hbF9wb2x5ZmlsbCIsCiAidXRmOHBhcnNlIiwKXQoKW1twYWNrYWdlXV0KbmFtZSA9ICJhbnN0eWxlIgp2ZXJzaW9uID0gIjEuMC4xMyIKc291cmNlID0gInJlZ2lzdHJ5K2h0dHBzOi8vZ2l0aHViLmNvbS9ydXN0LWxhbmcvY3JhdGVzLmlvLWluZGV4IgpjaGVja3N1bSA9ICI1MTkyY2NhODAwNmYxZmQ0ZjcyMzc1MTZmNDBmYTE4M2JiMDdmOGZiZGZlZGFhMDAzNmRlNWVhOWIwYjQ1ZTc4IgoKW1twYWNrYWdlXV0KbmFtZSA9ICJhbnN0eWxlLXBhcnNlIgp2ZXJzaW9uID0gIjAuMi43Igpzb3VyY2UgPSAicmVnaXN0cnkraHR0cHM6Ly9naXRodWIuY29tL3J1c3QtbGFuZy9jcmF0ZXMuaW8taW5kZXgiCmNoZWNrc3VtID0gIjRlNzY0NDgyNGYwYWEyYzdiOTM4NDU3OTIzNGVmMTBlYjdlZmI2YTBkZWI4M2Y5NjMwYTQ5NTk0ZGQ5YzE1YzIiCmRlcGVuZGVuY2llcyA9IFsKICJ1dGY4cGFyc2UiLApdCgpbW3BhY2thZ2VdXQpuYW1lID0gImFuc3R5bGUtcXVlcnkiCnZlcnNpb24gPSAiMS4xLjUiCnNvdXJjZSA9ICJyZWdpc3RyeStodHRwczovL2dpdGh1Yi5jb20vcnVzdC1sYW5nL2NyYXRlcy5pby1pbmRleCIKY2hlY2tzdW0gPSAiNDBjNDhmNzJmZDUzY2QyODkxMDRmYzY0MDk5YWJjYTczZGI0MTY2YWQ4NmVhMGI0MzQxYWJlNjVhZjgzZGFkYyIKZGVwZW5kZW5jaWVzID0gWwogIndpbmRvd3Mtc3lzIDAuNjEuMiIsCl0KCltbcGFja2FnZV1dCm5hbWUgPSAiYW5zdHlsZS13aW5jb24iCnZlcnNpb24gPSAiMy4wLjExIgpzb3VyY2UgPSAicmVnaXN0cnkraHR0cHM6Ly9naXRodWIuY29tL3J1c3QtbGFuZy9jcmF0ZXMuaW8taW5kZXgiCmNoZWNrc3VtID0gIjI5MWU2YTI1MGZmODZjZDRhODIwMTEyZmI4ODk4ODA4YTM2NmQ4ZjlmNThjZTE2ZDFmNTM4MzUzYWQ1NTc0N2QiCmRlcGVuZGVuY2llcyA9IFsKICJhbnN0eWxlIiwKICJvbmNlX2NlbGxfcG9seWZpbGwiLAogIndpbmRvd3Mtc3lzIDAuNjEuMiIsCl0KCltbcGFja2FnZV1dCm5hbWUgPSAiYW55aG93Igp2ZXJzaW9uID0gIjEuMC4xMDAiCnNvdXJjZSA9ICJyZWdpc3RyeStodHRwczovL2dpdGh1Yi5jb20vcnVzdC1sYW5nL2NyYXRlcy5pby1pbmRleCIKY2hlY2tzdW0gPSAiYTIzZWI2YjE2MTQzMThhODA3MWM5YjI1MjFmMzZiNDI0YjJjODNkYjVlYjNhMGZlYWQ0YTZjMDgwOWFmNmU2MSIKCltbcGFja2FnZV1dCm5hbWUgPSAiYXJyYXl2ZWMiCnZlcnNpb24gPSAiMC43LjYiCnNvdXJjZSA9ICJyZWdpc3RyeStodHRwczovL2dpdGh1Yi5jb20vcnVzdC1sYW5nL2NyYXRlcy5pby1pbmRleCIKY2hlY2tzdW0gPSAiN2MwMmQxMjNkZjAxN2VmY2RmYmQ3MzllZjgxNzM1YjM2YzViYTgzZWMzYzU5YzgwYTlkN2VjYzcxOGY5MmU1MCIKCltbcGFja2FnZV1dCm5hbWUgPSAiYXV0b2NmZyIKdmVyc2lvbiA9ICIxLjUuMCIKc291cmNlID0gInJlZ2lzdHJ5K2h0dHBzOi8vZ2l0aHViLmNvbS9ydXN0LWxhbmcvY3JhdGVzLmlvLWluZGV4IgpjaGVja3N1bSA9ICJjMDg2MDZmOGMzY2JmNGNlNmVjOGUyOGZiMDAxNGEyYzA4NjcwOGZlOTU0ZWFhODg1Mzg0YTYxNjUxNzJlN2U4IgoKW1twYWNrYWdlXV0KbmFtZSA9ICJiaXRmbGFncyIKdmVyc2lvbiA9ICIyLjkuMCIKc291cmNlID0gInJlZ2lzdHJ5K2h0dHBzOi8vZ2l0aHViLmNvbS9ydXN0LWxhbmcvY3JhdGVzLmlvLWluZGV4IgpjaGVja3N1bSA9ICI1YzgyMTQxMTViN2JmODQwOTlmMTMwOTMyNGU2MzE0MWQ0YzVkN2NjMjY4NjJmOTdhMGE4NTdkYmVmZTE2NWJkIgoKW1twYWNrYWdlXV0KbmFtZSA9ICJidW1wYWxvIgp2ZXJzaW9uID0gIjMuMTkuMSIKc291cmNlID0gInJlZ2lzdHJ5K2h0dHBzOi8vZ2l0aHViLmNvbS9ydXN0LWxhbmcvY3JhdGVzLmlvLWluZGV4IgpjaGVja3N1bSA9ICI1ZGQ5ZGM3MzhiN2E4MzExYzdhZGUxNTI0MjQ5NzRkODExNWYyY2RhZDYxZThkYWI4ZGFjOWYyMzYyMjk4NTEwIgoKW1twYWNrYWdlXV0KbmFtZSA9ICJjbGFwIgp2ZXJzaW9uID0gIjQuNS41NCIKc291cmNlID0gInJlZ2lzdHJ5K2h0dHBzOi8vZ2l0aHViLmNvbS9ydXN0LWxhbmcvY3JhdGVzLmlvLWluZGV4IgpjaGVja3N1bSA9ICJjNmU2ZmY5ZGNkNzljZmY1Y2Q5NjlhMTdhNTQ1ZDc5ZTg0YWIwODZlNDQ0MTAyYTU5MWUyODhhOGFhM2NlMzk0IgpkZXBlbmRlbmNpZXMgPSBbCiAiY2xhcF9idWlsZGVyIiwKICJjbGFwX2Rlcml2ZSIsCl0KCltbcGFja2FnZV1dCm5hbWUgPSAiY2xhcF9idWlsZGVyIgp2ZXJzaW9uID0gIjQuNS41NCIKc291cmNlID0gInJlZ2lzdHJ5K2h0dHBzOi8vZ2l0aHViLmNvbS9ydXN0LWxhbmcvY3JhdGVzLmlvLWluZGV4IgpjaGVja3N1bSA9ICJmYTQyY2Y0ZDJiN2E0MWJjOGY2NjNhN2NhYjQwMzFlYmFmYTFiZjM4NzU3MDViZmFmODQ2NmRjNjBhYjUyYzAwIgpkZXBlbmRlbmNpZXMgPSBbCiAiYW5zdHJlYW0iLAogImFuc3R5bGUiLAogImNsYXBfbGV4IiwKICJzdHJzaW0iLApdCgpbW3BhY2thZ2VdXQpuYW1lID0gImNsYXBfZGVyaXZlIgp2ZXJzaW9uID0gIjQuNS40OSIKc291cmNlID0gInJlZ2lzdHJ5K2h0dHBzOi8vZ2l0aHViLmNvbS9ydXN0LWxhbmcvY3JhdGVzLmlvLWluZGV4IgpjaGVja3N1bSA9ICIyYTBiNTQ4N2FmZWFiMmRlYjJmZjRlMDNhODA3YWQxYTAzYWM1MzJmZjVhMmNlZTVkODY4ODQ0NDBjN2Y3NjcxIgpkZXBlbmRlbmNpZXMgPSBbCiAiaGVjayIsCiAicHJvYy1tYWNybzIiLAogInF1b3RlIiwKICJzeW4iLApdCgpbW3BhY2thZ2VdXQpuYW1lID0gImNsYXBfbGV4Igp2ZXJzaW9uID0gIjAuNy43Igpzb3VyY2UgPSAicmVnaXN0cnkraHR0cHM6Ly9naXRodWIuY29tL3J1c3QtbGFuZy9jcmF0ZXMuaW8taW5kZXgiCmNoZWNrc3VtID0gImMzZTY0YjBjYzA0MzliMTJkZjJmYTY3OGVhZTg5YTFjNTZhNTI5ZmQwNjdhOTExNWY3ODI3ZjFmZmZkMjJiMzIiCgpbW3BhY2thZ2VdXQpuYW1lID0gImNvbG9yY2hvaWNlIgp2ZXJzaW9uID0gIjEuMC40Igpzb3VyY2UgPSAicmVnaXN0cnkraHR0cHM6Ly9naXRodWIuY29tL3J1c3QtbGFuZy9jcmF0ZXMuaW8taW5kZXgiCmNoZWNrc3VtID0gImIwNWI2MWRjNTExMmNiYjE3ZTRiNmNkNjE3OTBkOTg0NWQxMzg4ODM1NjM5MTYyNGNiZTdlNDFlZmVhYzFlNzUiCgpbW3BhY2thZ2VdXQpuYW1lID0gImNvbG9yZWQiCnZlcnNpb24gPSAiMy4wLjAiCnNvdXJjZSA9ICJyZWdpc3RyeStodHRwczovL2dpdGh1Yi5jb20vcnVzdC1sYW5nL2NyYXRlcy5pby1pbmRleCIKY2hlY2tzdW0gPSAiZmRlMGUwZWM5MGM5ZGZiM2I0YjFhMDg5MWE3ZGNkMGUyYmZmZGUyZjdlZmVkNWZlN2M5YmIwMGU1YmZiOTE1ZSIKZGVwZW5kZW5jaWVzID0gWwogIndpbmRvd3Mtc3lzIDAuNTkuMCIsCl0KCltbcGFja2FnZV1dCm5hbWUgPSAiY29udmVydF9jYXNlIgp2ZXJzaW9uID0gIjAuOC4wIgpzb3VyY2UgPSAicmVnaXN0cnkraHR0cHM6Ly9naXRodWIuY29tL3J1c3QtbGFuZy9jcmF0ZXMuaW8taW5kZXgiCmNoZWNrc3VtID0gImJhYWFhMGVjY2E1YjUxOTg3Yjk0MjNjY2RjOTcxNTE0ZGQ4YjBiYjdiNDA2MGI5ODNkMzY2NGRhZDNmMWY4OWYiCmRlcGVuZGVuY2llcyA9IFsKICJ1bmljb2RlLXNlZ21lbnRhdGlvbiIsCl0KCltbcGFja2FnZV1dCm5hbWUgPSAiZW5kaWFuLXR5cGUiCnZlcnNpb24gPSAiMC4xLjIiCnNvdXJjZSA9ICJyZWdpc3RyeStodHRwczovL2dpdGh1Yi5jb20vcnVzdC1sYW5nL2NyYXRlcy5pby1pbmRleCIKY2hlY2tzdW0gPSAiYzM0ZjA0NjY2ZDgzNWZmNWQ2MmUwNThjMzk5NTE0N2MwNmY0MmZlODZmZjA1MzMzNzYzMmJjYTgzZTQyNzAyZCIKCltbcGFja2FnZV1dCm5hbWUgPSAiZXF1aXZhbGVudCIKdmVyc2lvbiA9ICIxLjAuMiIKc291cmNlID0gInJlZ2lzdHJ5K2h0dHBzOi8vZ2l0aHViLmNvbS9ydXN0LWxhbmcvY3JhdGVzLmlvLWluZGV4IgpjaGVja3N1bSA9ICI4NzdhNGFjZTg3MTNiMGJjZjJhNGU3ZWVjODI1MjljMDI5ZjFkMDYxOTg4NmQxODE0NWZlYTk2YzNmZmU1YzBmIgoKW1twYWNrYWdlXV0KbmFtZSA9ICJmb2xkaGFzaCIKdmVyc2lvbiA9ICIwLjEuNSIKc291cmNlID0gInJlZ2lzdHJ5K2h0dHBzOi8vZ2l0aHViLmNvbS9ydXN0LWxhbmcvY3JhdGVzLmlvLWluZGV4IgpjaGVja3N1bSA9ICJkOWM0ZjVkYWM1ZTE1YzI0ZWI5OTljMjYxODFhNmNhNDBiMzlmZTk0NmNiZTRjMjYzYzcyMDk0NjdiYzgzYWYyIgoKW1twYWNrYWdlXV0KbmFtZSA9ICJnZW5lcmljLWFycmF5Igp2ZXJzaW9uID0gIjEuMy41Igpzb3VyY2UgPSAicmVnaXN0cnkraHR0cHM6Ly9naXRodWIuY29tL3J1c3QtbGFuZy9jcmF0ZXMuaW8taW5kZXgiCmNoZWNrc3VtID0gImVhZjU3YzQ5YTk1ZmQxZmUyNGI5MGIzMDMzYmVlNmRjN2U4ZjEyODhkNTE0OTRjYjQ0ZTYyN2MyOTVlMzg1NDIiCmRlcGVuZGVuY2llcyA9IFsKICJydXN0dmVyc2lvbiIsCiAidHlwZW51bSIsCl0KCltbcGFja2FnZV1dCm5hbWUgPSAiaGFzaGJyb3duIgp2ZXJzaW9uID0gIjAuMTUuNSIKc291cmNlID0gInJlZ2lzdHJ5K2h0dHBzOi8vZ2l0aHViLmNvbS9ydXN0LWxhbmcvY3JhdGVzLmlvLWluZGV4IgpjaGVja3N1bSA9ICI5MjI5Y2ZlNTNkZmQ2OWYwNjA5YTQ5ZjY1NDYxYmQ5MzAwMWVhMWVmODg5Y2Q1NTI5ZGQxNzY1OTNmNTMzOGExIgpkZXBlbmRlbmNpZXMgPSBbCiAiZm9sZGhhc2giLAogInNlcmRlIiwKXQoKW1twYWNrYWdlXV0KbmFtZSA9ICJoYXNoYnJvd24iCnZlcnNpb24gPSAiMC4xNi4xIgpzb3VyY2UgPSAicmVnaXN0cnkraHR0cHM6Ly9naXRodWIuY29tL3J1c3QtbGFuZy9jcmF0ZXMuaW8taW5kZXgiCmNoZWNrc3VtID0gIjg0MWQxY2M5YmVkN2Y5MjM2ZjMyMWRmOTc3MDMwMzczZjRhNDE2M2FlMWE3ZGJmZTFhNTFhMmMxYTUxZDkxMDAiCgpbW3BhY2thZ2VdXQpuYW1lID0gImhlY2siCnZlcnNpb24gPSAiMC41LjAiCnNvdXJjZSA9ICJyZWdpc3RyeStodHRwczovL2dpdGh1Yi5jb20vcnVzdC1sYW5nL2NyYXRlcy5pby1pbmRleCIKY2hlY2tzdW0gPSAiMjMwNGUwMDk4M2Y4N2ZmYjM4YjU1YjQ0NGI1ZTNiNjBhODg0YjVkMzBjMGZjYTdkODJmZTMzNDQ5YmJlNTVlYSIKCltbcGFja2FnZV1dCm5hbWUgPSAiaGV4Igp2ZXJzaW9uID0gIjAuNC4zIgpzb3VyY2UgPSAicmVnaXN0cnkraHR0cHM6Ly9naXRodWIuY29tL3J1c3QtbGFuZy9jcmF0ZXMuaW8taW5kZXgiCmNoZWNrc3VtID0gIjdmMjQyNTRhYTlhNTRiNWM4NThlYWVlMmY1YmNjZGI0NmFhZjBlNDg2YTU5NWVkNWZkOGY4NmJhNTUyMzJhNzAiCgpbW3BhY2thZ2VdXQpuYW1lID0gImhleC1saXRlcmFsIgp2ZXJzaW9uID0gIjAuNC4xIgpzb3VyY2UgPSAicmVnaXN0cnkraHR0cHM6Ly9naXRodWIuY29tL3J1c3QtbGFuZy9jcmF0ZXMuaW8taW5kZXgiCmNoZWNrc3VtID0gIjZmZTIyNjdkNGVkNDliYzA3YjYzODAxNTU5YmUyOGM3MThlYTA2YzQ3MzhiN2EwM2M5NGRmNzM4NmQyY2RlNDYiCgpbW3BhY2thZ2VdXQpuYW1lID0gImluZGV4bWFwIgp2ZXJzaW9uID0gIjIuMTMuMCIKc291cmNlID0gInJlZ2lzdHJ5K2h0dHBzOi8vZ2l0aHViLmNvbS9ydXN0LWxhbmcvY3JhdGVzLmlvLWluZGV4IgpjaGVja3N1bSA9ICI3NzE0ZTcwNDM3YTdkYzNhYzhlYjdlNmY4ZGY3NWZkOGViNDIyNjc1ZmM3Njc4YWZmNzM2NDMwMTA5MmIxMDE3IgpkZXBlbmRlbmNpZXMgPSBbCiAiZXF1aXZhbGVudCIsCiAiaGFzaGJyb3duIDAuMTYuMSIsCiAic2VyZGUiLAogInNlcmRlX2NvcmUiLApdCgpbW3BhY2thZ2VdXQpuYW1lID0gImlzX3Rlcm1pbmFsX3BvbHlmaWxsIgp2ZXJzaW9uID0gIjEuNzAuMiIKc291cmNlID0gInJlZ2lzdHJ5K2h0dHBzOi8vZ2l0aHViLmNvbS9ydXN0LWxhbmcvY3JhdGVzLmlvLWluZGV4IgpjaGVja3N1bSA9ICJhNmNiMTM4YmI3OWExNDZjMWJkNDYwMDA1NjIzZTE0MmVmMDE4MWUzZDAyMTljYjQ5M2UwMmY3ZDA4YTM1Njk1IgoKW1twYWNrYWdlXV0KbmFtZSA9ICJpdG9hIgp2ZXJzaW9uID0gIjEuMC4xNyIKc291cmNlID0gInJlZ2lzdHJ5K2h0dHBzOi8vZ2l0aHViLmNvbS9ydXN0LWxhbmcvY3JhdGVzLmlvLWluZGV4IgpjaGVja3N1bSA9ICI5MmVjYzY2MTgxODFkZWYwNDU3MzkyY2NkMGVlNTExOThlMDY1ZTAxNmQxZDUyN2E3YWMxYjZkYzdjMWYwOWQyIgoKW1twYWNrYWdlXV0KbmFtZSA9ICJsYXp5X3N0YXRpYyIKdmVyc2lvbiA9ICIxLjUuMCIKc291cmNlID0gInJlZ2lzdHJ5K2h0dHBzOi8vZ2l0aHViLmNvbS9ydXN0LWxhbmcvY3JhdGVzLmlvLWluZGV4IgpjaGVja3N1bSA9ICJiYmQyYmNiNGM5NjNmMmRkYWUwNmEyZWZjN2U5ZjM1OTEzMTI0NzNjNTBjNjY4NWUxZjI5ODA2ODMxNmU2NmZlIgoKW1twYWNrYWdlXV0KbmFtZSA9ICJsZWIxMjhmbXQiCnZlcnNpb24gPSAiMC4xLjAiCnNvdXJjZSA9ICJyZWdpc3RyeStodHRwczovL2dpdGh1Yi5jb20vcnVzdC1sYW5nL2NyYXRlcy5pby1pbmRleCIKY2hlY2tzdW0gPSAiMDllZGQ5ZThiNTRlNDllNTg3ZTRmNjI5NWE3ZDI5YzNlYTk0ZDQ2OWNiNDBhYjhjYTcwYjI4ODI0OGE4MWRiMiIKCltbcGFja2FnZV1dCm5hbWUgPSAibWVtY2hyIgp2ZXJzaW9uID0gIjIuNy42Igpzb3VyY2UgPSAicmVnaXN0cnkraHR0cHM6Ly9naXRodWIuY29tL3J1c3QtbGFuZy9jcmF0ZXMuaW8taW5kZXgiCmNoZWNrc3VtID0gImY1MmIwMGQzOTk2MWZjNWIyNzM2ZWE4NTNjOWNjODYyMzhlMTY1MDE3YTQ5M2QxZDVjOGVhYzZiZGM0Y2MyNzMiCgpbW3BhY2thZ2VdXQpuYW1lID0gIm11bHRpdmVyc3gtY2hhaW4tY29yZSIKdmVyc2lvbiA9ICIwLjE0LjAiCnNvdXJjZSA9ICJyZWdpc3RyeStodHRwczovL2dpdGh1Yi5jb20vcnVzdC1sYW5nL2NyYXRlcy5pby1pbmRleCIKY2hlY2tzdW0gPSAiNzNmMWYwNTI2Y2EwOTQxODU4NDc3NzZjMmMwM2RlOTdlYTA4Mjc0M2VlNGU2Zjc5OTg2MGFkNjdlN2Q3ODI1MCIKZGVwZW5kZW5jaWVzID0gWwogImJpdGZsYWdzIiwKICJtdWx0aXZlcnN4LXNjLWNvZGVjIiwKXQoKW1twYWNrYWdlXV0KbmFtZSA9ICJtdWx0aXZlcnN4LXNjIgp2ZXJzaW9uID0gIjAuNTcuMSIKc291cmNlID0gInJlZ2lzdHJ5K2h0dHBzOi8vZ2l0aHViLmNvbS9ydXN0LWxhbmcvY3JhdGVzLmlvLWluZGV4IgpjaGVja3N1bSA9ICIyMDYwMmQ0ZmMzMzYwOTJmYWFkYzAzYjZiNDQ1YzRiYjVlNGRiYzRjODZmYjUzNzI2ZTQ2ZWNhNjcwNzA4MTNhIgpkZXBlbmRlbmNpZXMgPSBbCiAiYml0ZmxhZ3MiLAogImdlbmVyaWMtYXJyYXkiLAogImhleC1saXRlcmFsIiwKICJtdWx0aXZlcnN4LWNoYWluLWNvcmUiLAogIm11bHRpdmVyc3gtc2MtY29kZWMiLAogIm11bHRpdmVyc3gtc2MtZGVyaXZlIiwKICJudW0tdHJhaXRzIiwKICJ1bndyYXAtaW5mYWxsaWJsZSIsCl0KCltbcGFja2FnZV1dCm5hbWUgPSAibXVsdGl2ZXJzeC1zYy1jb2RlYyIKdmVyc2lvbiA9ICIwLjIyLjAiCnNvdXJjZSA9ICJyZWdpc3RyeStodHRwczovL2dpdGh1Yi5jb20vcnVzdC1sYW5nL2NyYXRlcy5pby1pbmRleCIKY2hlY2tzdW0gPSAiNDNlMGYyNGEwMjBhZGYzMmZhZmZhZTFjNTc0NzVjNmI3Mjg1YTMyMTZkMWEzNmU0YTczNjE3NjM5NzIxYzJlMCIKZGVwZW5kZW5jaWVzID0gWwogImFycmF5dmVjIiwKICJiaXRmbGFncyIsCiAibXVsdGl2ZXJzeC1zYy1jb2RlYy1kZXJpdmUiLAogIm51bS1iaWdpbnQiLAogInVud3JhcC1pbmZhbGxpYmxlIiwKXQoKW1twYWNrYWdlXV0KbmFtZSA9ICJtdWx0aXZlcnN4LXNjLWNvZGVjLWRlcml2ZSIKdmVyc2lvbiA9ICIwLjIyLjAiCnNvdXJjZSA9ICJyZWdpc3RyeStodHRwczovL2dpdGh1Yi5jb20vcnVzdC1sYW5nL2NyYXRlcy5pby1pbmRleCIKY2hlY2tzdW0gPSAiN2M1ZjE3ZDVlZTIzNjU3ZDVjZGRjN2Y0NDcxOTI1YjVhNDlmN2UyNTMwNmY4YmJhNjU2ZWE2OTE3YWNjNjI5ZCIKZGVwZW5kZW5jaWVzID0gWwogImhleCIsCiAicHJvYy1tYWNybzIiLAogInF1b3RlIiwKICJzeW4iLApdCgpbW3BhY2thZ2VdXQpuYW1lID0gIm11bHRpdmVyc3gtc2MtZGVyaXZlIgp2ZXJzaW9uID0gIjAuNTcuMSIKc291cmNlID0gInJlZ2lzdHJ5K2h0dHBzOi8vZ2l0aHViLmNvbS9ydXN0LWxhbmcvY3JhdGVzLmlvLWluZGV4IgpjaGVja3N1bSA9ICIwZDQ0ZDA4ZDMzNzZjMTk5ZThjMzkxY2MwNzc1MmQyODIyY2QyODk2OTNkYTUzMTlkNzkwNTU5OTUwMWU1NTdmIgpkZXBlbmRlbmNpZXMgPSBbCiAiaGV4IiwKICJwcm9jLW1hY3JvMiIsCiAicXVvdGUiLAogInJhZGl4X3RyaWUiLAogInN5biIsCl0KCltbcGFja2FnZV1dCm5hbWUgPSAibXVsdGl2ZXJzeC1zYy1tZXRhLWxpYiIKdmVyc2lvbiA9ICIwLjU3LjEiCnNvdXJjZSA9ICJyZWdpc3RyeStodHRwczovL2dpdGh1Yi5jb20vcnVzdC1sYW5nL2NyYXRlcy5pby1pbmRleCIKY2hlY2tzdW0gPSAiNDM4MTQ5ZjQ1NTM4MmU2NGQxZDM4M2IyY2I1YmVlMTQ0YzIxNWQyOTQzZDZhMGFlMDZhNTBkMzIyNTY4MGZiYiIKZGVwZW5kZW5jaWVzID0gWwogImNsYXAiLAogImNvbG9yZWQiLAogImNvbnZlcnRfY2FzZSIsCiAiaGV4IiwKICJsYXp5X3N0YXRpYyIsCiAibXVsdGl2ZXJzeC1zYyIsCiAicnVzdGNfdmVyc2lvbiIsCiAic2VtdmVyIiwKICJzZXJkZSIsCiAic2VyZGVfanNvbiIsCiAidG9tbCIsCiAid2FzbXBhcnNlciAwLjIyNy4xIiwKICJ3YXNtcHJpbnRlciIsCiAid2F0IiwKXQoKW1twYWNrYWdlXV0KbmFtZSA9ICJuaWJibGVfdmVjIgp2ZXJzaW9uID0gIjAuMS4wIgpzb3VyY2UgPSAicmVnaXN0cnkraHR0cHM6Ly9naXRodWIuY29tL3J1c3QtbGFuZy9jcmF0ZXMuaW8taW5kZXgiCmNoZWNrc3VtID0gIjc3YTVkODNkZjlmMzZmZTIzZjBjMzY0OGM2YmJiOGIwMjk4YmI1ZjE5MzljOGYyNzA0NDMxMzcxZjRiODRkNDMiCmRlcGVuZGVuY2llcyA9IFsKICJzbWFsbHZlYyIsCl0KCltbcGFja2FnZV1dCm5hbWUgPSAibnVtLWJpZ2ludCIKdmVyc2lvbiA9ICIwLjQuNiIKc291cmNlID0gInJlZ2lzdHJ5K2h0dHBzOi8vZ2l0aHViLmNvbS9ydXN0LWxhbmcvY3JhdGVzLmlvLWluZGV4IgpjaGVja3N1bSA9ICJhNWU0NGY3MjNmMTEzM2M5ZGVhYzY0Njc2MzU3OWZkYjNhYzc0NWU0MThmMmE3YWY5Y2QwYzQzMWRhMWYyMGI5IgpkZXBlbmRlbmNpZXMgPSBbCiAibnVtLWludGVnZXIiLAogIm51bS10cmFpdHMiLApdCgpbW3BhY2thZ2VdXQpuYW1lID0gIm51bS1pbnRlZ2VyIgp2ZXJzaW9uID0gIjAuMS40NiIKc291cmNlID0gInJlZ2lzdHJ5K2h0dHBzOi8vZ2l0aHViLmNvbS9ydXN0LWxhbmcvY3JhdGVzLmlvLWluZGV4IgpjaGVja3N1bSA9ICI3OTY5NjYxZmQyOTU4YTVjYjA5NmU1NmM4ZTFhZDA0NDRhYzJiYmNkMDA2MWJkMjg2NjA0ODVhNDQ4Nzk4NThmIgpkZXBlbmRlbmNpZXMgPSBbCiAibnVtLXRyYWl0cyIsCl0KCltbcGFja2FnZV1dCm5hbWUgPSAibnVtLXRyYWl0cyIKdmVyc2lvbiA9ICIwLjIuMTkiCnNvdXJjZSA9ICJyZWdpc3RyeStodHRwczovL2dpdGh1Yi5jb20vcnVzdC1sYW5nL2NyYXRlcy5pby1pbmRleCIKY2hlY2tzdW0gPSAiMDcxZGZjMDYyNjkwZTkwYjczNGMwYjIyNzNjZTcyYWQwZmZhOTVmMGM3NDU5NmJjMjUwZGNmZDk2MDI2Mjg0MSIKZGVwZW5kZW5jaWVzID0gWwogImF1dG9jZmciLApdCgpbW3BhY2thZ2VdXQpuYW1lID0gIm9uY2VfY2VsbF9wb2x5ZmlsbCIKdmVyc2lvbiA9ICIxLjcwLjIiCnNvdXJjZSA9ICJyZWdpc3RyeStodHRwczovL2dpdGh1Yi5jb20vcnVzdC1sYW5nL2NyYXRlcy5pby1pbmRleCIKY2hlY2tzdW0gPSAiMzg0YjhhYjZkMzcyMTVmM2M1MzAxYTk1YTRhY2NiNWQ2NGFhNjA3ZjFmY2IyNmExMWI1MzAzODc4NDUxYjRmZSIKCltbcGFja2FnZV1dCm5hbWUgPSAicHJvYy1tYWNybzIiCnZlcnNpb24gPSAiMS4wLjk0Igpzb3VyY2UgPSAicmVnaXN0cnkraHR0cHM6Ly9naXRodWIuY29tL3J1c3QtbGFuZy9jcmF0ZXMuaW8taW5kZXgiCmNoZWNrc3VtID0gImEzMTk3MTc1MmU3MGI4YjI2ODZkN2U0NmVjMTdmYjM4ZGFkNDA1MWQ5NDAyNGM4OGRmNDliNjY3Y2FlYTljODQiCmRlcGVuZGVuY2llcyA9IFsKICJ1bmljb2RlLWlkZW50IiwKXQoKW1twYWNrYWdlXV0KbmFtZSA9ICJxdW90ZSIKdmVyc2lvbiA9ICIxLjAuMzkiCnNvdXJjZSA9ICJyZWdpc3RyeStodHRwczovL2dpdGh1Yi5jb20vcnVzdC1sYW5nL2NyYXRlcy5pby1pbmRleCIKY2hlY2tzdW0gPSAiYzFmMTkxNGNlOTA5ZTE2NThkOTkwNzkxM2I0YjkxOTQ3NDMwYzdkOWJlNTk4YjE1YTE5MTI5MzViOGMwNDgwMSIKZGVwZW5kZW5jaWVzID0gWwogInByb2MtbWFjcm8yIiwKXQoKW1twYWNrYWdlXV0KbmFtZSA9ICJyYWRpeF90cmllIgp2ZXJzaW9uID0gIjAuMi4xIgpzb3VyY2UgPSAicmVnaXN0cnkraHR0cHM6Ly9naXRodWIuY29tL3J1c3QtbGFuZy9jcmF0ZXMuaW8taW5kZXgiCmNoZWNrc3VtID0gImMwNjljMTc5ZmNkYzZhMmZlMjRkOGQxODMwNWNmMDg1ZmRiZDRmOTIyYzA0MTk0M2UyMDM2ODVkNmExYzU4ZmQiCmRlcGVuZGVuY2llcyA9IFsKICJlbmRpYW4tdHlwZSIsCiAibmliYmxlX3ZlYyIsCl0KCltbcGFja2FnZV1dCm5hbWUgPSAicmVxdWVzdHMiCnZlcnNpb24gPSAiMC4wLjAiCmRlcGVuZGVuY2llcyA9IFsKICJtdWx0aXZlcnN4LXNjIiwKXQoKW1twYWNrYWdlXV0KbmFtZSA9ICJyZXF1ZXN0cy1tZXRhIgp2ZXJzaW9uID0gIjAuMC4wIgpkZXBlbmRlbmNpZXMgPSBbCiAibXVsdGl2ZXJzeC1zYy1tZXRhLWxpYiIsCiAicmVxdWVzdHMiLApdCgpbW3BhY2thZ2VdXQpuYW1lID0gInJ1c3RjX3ZlcnNpb24iCnZlcnNpb24gPSAiMC40LjEiCnNvdXJjZSA9ICJyZWdpc3RyeStodHRwczovL2dpdGh1Yi5jb20vcnVzdC1sYW5nL2NyYXRlcy5pby1pbmRleCIKY2hlY2tzdW0gPSAiY2ZjYjNhMjJlZjQ2ZTg1YjQ1ZGU2ZWU3ZTc5ZDA2MzMxOWViYjY1OTRmYWFmY2YxYzIyNWVhOTJhYjZlOWI5MiIKZGVwZW5kZW5jaWVzID0gWwogInNlbXZlciIsCl0KCltbcGFja2FnZV1dCm5hbWUgPSAicnVzdHZlcnNpb24iCnZlcnNpb24gPSAiMS4wLjIyIgpzb3VyY2UgPSAicmVnaXN0cnkraHR0cHM6Ly9naXRodWIuY29tL3J1c3QtbGFuZy9jcmF0ZXMuaW8taW5kZXgiCmNoZWNrc3VtID0gImIzOWNkZWYwZmE4MDBmYzQ0NTI1Yzg0Y2NiNTRhMDI5OTYxYTgyMTVmOTYxOTc1MzYzNWE5YzBkMjUzOGQ0NmQiCgpbW3BhY2thZ2VdXQpuYW1lID0gInNlbXZlciIKdmVyc2lvbiA9ICIxLjAuMjciCnNvdXJjZSA9ICJyZWdpc3RyeStodHRwczovL2dpdGh1Yi5jb20vcnVzdC1sYW5nL2NyYXRlcy5pby1pbmRleCIKY2hlY2tzdW0gPSAiZDc2N2ViMGFhYmM4ODBiMjk5NTZjMzU3MzQxNzBmMjZlZDU1MWE4NTlkYmQzNjFkMTQwY2RiZWNhNjFhYjFlMiIKCltbcGFja2FnZV1dCm5hbWUgPSAic2VyZGUiCnZlcnNpb24gPSAiMS4wLjIyOCIKc291cmNlID0gInJlZ2lzdHJ5K2h0dHBzOi8vZ2l0aHViLmNvbS9ydXN0LWxhbmcvY3JhdGVzLmlvLWluZGV4IgpjaGVja3N1bSA9ICI5YThlOTRlYTdmMzc4YmQzMmNiYmQzNzE5OGE0YTkxNDM2MTgwYzViYjQ3MjQxMWU0OGI1ZWMyZTIxMjRhZTllIgpkZXBlbmRlbmNpZXMgPSBbCiAic2VyZGVfY29yZSIsCiAic2VyZGVfZGVyaXZlIiwKXQoKW1twYWNrYWdlXV0KbmFtZSA9ICJzZXJkZV9jb3JlIgp2ZXJzaW9uID0gIjEuMC4yMjgiCnNvdXJjZSA9ICJyZWdpc3RyeStodHRwczovL2dpdGh1Yi5jb20vcnVzdC1sYW5nL2NyYXRlcy5pby1pbmRleCIKY2hlY2tzdW0gPSAiNDFkMzg1YzdkNGNhNThlNTlmYzczMmFmMjVjMzk4M2I2N2FjODUyYzFhMjUwMDBhZmUxMTc1ZGU0NThiNjdhZCIKZGVwZW5kZW5jaWVzID0gWwogInNlcmRlX2Rlcml2ZSIsCl0KCltbcGFja2FnZV1dCm5hbWUgPSAic2VyZGVfZGVyaXZlIgp2ZXJzaW9uID0gIjEuMC4yMjgiCnNvdXJjZSA9ICJyZWdpc3RyeStodHRwczovL2dpdGh1Yi5jb20vcnVzdC1sYW5nL2NyYXRlcy5pby1pbmRleCIKY2hlY2tzdW0gPSAiZDU0MGYyMjBkMzE4NzE3M2RhMjIwZjg4NWFiNjY2MDgzNjdiNjU3NGU5MjUwMTFhOTM1M2U0YmFkZGE5MWQ3OSIKZGVwZW5kZW5jaWVzID0gWwogInByb2MtbWFjcm8yIiwKICJxdW90ZSIsCiAic3luIiwKXQoKW1twYWNrYWdlXV0KbmFtZSA9ICJzZXJkZV9qc29uIgp2ZXJzaW9uID0gIjEuMC4xNDkiCnNvdXJjZSA9ICJyZWdpc3RyeStodHRwczovL2dpdGh1Yi5jb20vcnVzdC1sYW5nL2NyYXRlcy5pby1pbmRleCIKY2hlY2tzdW0gPSAiODNmYzAzOTQ3M2M1NTk1YWNlODYwZDhjNGZhZmEyMjBmZjQ3NGIzZmM2YmZkYjQyOTMzMjdmMWEzN2U5NGQ4NiIKZGVwZW5kZW5jaWVzID0gWwogIml0b2EiLAogIm1lbWNociIsCiAic2VyZGUiLAogInNlcmRlX2NvcmUiLAogInptaWoiLApdCgpbW3BhY2thZ2VdXQpuYW1lID0gInNlcmRlX3NwYW5uZWQiCnZlcnNpb24gPSAiMC42LjkiCnNvdXJjZSA9ICJyZWdpc3RyeStodHRwczovL2dpdGh1Yi5jb20vcnVzdC1sYW5nL2NyYXRlcy5pby1pbmRleCIKY2hlY2tzdW0gPSAiYmY0MWUwY2ZhZjcyMjZkY2ExNWU4MTk3MTcyYzI5NWE3ODI4NTdmY2I5N2ZhZDE4MDhhMTY2ODcwZGVlNzVhMyIKZGVwZW5kZW5jaWVzID0gWwogInNlcmRlIiwKXQoKW1twYWNrYWdlXV0KbmFtZSA9ICJzbWFsbHZlYyIKdmVyc2lvbiA9ICIxLjE1LjEiCnNvdXJjZSA9ICJyZWdpc3RyeStodHRwczovL2dpdGh1Yi5jb20vcnVzdC1sYW5nL2NyYXRlcy5pby1pbmRleCIKY2hlY2tzdW0gPSAiNjdiMWI3YTNiNWZlNGYxMzc2ODg3MTg0MDQ1ZmNmNDVjNjllOTJhZjczNGI3YWFkZGMwNWZiNzc3YjZmYmQwMyIKCltbcGFja2FnZV1dCm5hbWUgPSAic3Ryc2ltIgp2ZXJzaW9uID0gIjAuMTEuMSIKc291cmNlID0gInJlZ2lzdHJ5K2h0dHBzOi8vZ2l0aHViLmNvbS9ydXN0LWxhbmcvY3JhdGVzLmlvLWluZGV4IgpjaGVja3N1bSA9ICI3ZGE4YjU3MzY4NDVkOWYyZmNiODM3ZWE1ZDllMjYyODU2NGIzYjA0M2E3MDk0OGEzZjBiNzc4ODM4YzVmYjRmIgoKW1twYWNrYWdlXV0KbmFtZSA9ICJzeW4iCnZlcnNpb24gPSAiMi4wLjEwMCIKc291cmNlID0gInJlZ2lzdHJ5K2h0dHBzOi8vZ2l0aHViLmNvbS9ydXN0LWxhbmcvY3JhdGVzLmlvLWluZGV4IgpjaGVja3N1bSA9ICJiMDlhNDRhY2NhZDgxZTFiYTFjZDc0YTMyNDYxYmE4OWRlZTg5MDk1YmExN2IzMmY1ZDAzNjgzYjFiMWZjMmEwIgpkZXBlbmRlbmNpZXMgPSBbCiAicHJvYy1tYWNybzIiLAogInF1b3RlIiwKICJ1bmljb2RlLWlkZW50IiwKXQoKW1twYWNrYWdlXV0KbmFtZSA9ICJ0ZXJtY29sb3IiCnZlcnNpb24gPSAiMS40LjEiCnNvdXJjZSA9ICJyZWdpc3RyeStodHRwczovL2dpdGh1Yi5jb20vcnVzdC1sYW5nL2NyYXRlcy5pby1pbmRleCIKY2hlY2tzdW0gPSAiMDY3OTRmOGY2YzVjODk4YjMyNzVhZWJlZmE2YjhhMWNiMjRjZDJjNmM3OTM5N2FiMTU3NzQ4MzdhMGJjNTc1NSIKZGVwZW5kZW5jaWVzID0gWwogIndpbmFwaS11dGlsIiwKXQoKW1twYWNrYWdlXV0KbmFtZSA9ICJ0b21sIgp2ZXJzaW9uID0gIjAuOC4yMyIKc291cmNlID0gInJlZ2lzdHJ5K2h0dHBzOi8vZ2l0aHViLmNvbS9ydXN0LWxhbmcvY3JhdGVzLmlvLWluZGV4IgpjaGVja3N1bSA9ICJkYzFiZWI5OTZiOWQ4MzUyOWE5ZTc1YzE3YTE2ODY3NjdkMTQ4ZDcwNjYzMTQzYzc4NTRkOGI0YTA5Y2VkMzYyIgpkZXBlbmRlbmNpZXMgPSBbCiAiaW5kZXhtYXAiLAogInNlcmRlIiwKICJzZXJkZV9zcGFubmVkIiwKICJ0b21sX2RhdGV0aW1lIiwKICJ0b21sX2VkaXQiLApdCgpbW3BhY2thZ2VdXQpuYW1lID0gInRvbWxfZGF0ZXRpbWUiCnZlcnNpb24gPSAiMC42LjExIgpzb3VyY2UgPSAicmVnaXN0cnkraHR0cHM6Ly9naXRodWIuY29tL3J1c3QtbGFuZy9jcmF0ZXMuaW8taW5kZXgiCmNoZWNrc3VtID0gIjIyY2RkYWY4OGY0ZmJjMTNjNTFhZWJiZjVmOGVjZWI1YzdjNWE5ZGEyYWM0MGExMzUxOWViNWIwYTBlOGYxMWMiCmRlcGVuZGVuY2llcyA9IFsKICJzZXJkZSIsCl0KCltbcGFja2FnZV1dCm5hbWUgPSAidG9tbF9lZGl0Igp2ZXJzaW9uID0gIjAuMjIuMjciCnNvdXJjZSA9ICJyZWdpc3RyeStodHRwczovL2dpdGh1Yi5jb20vcnVzdC1sYW5nL2NyYXRlcy5pby1pbmRleCIKY2hlY2tzdW0gPSAiNDFmZThjNjYwYWU0MjU3ODg3Y2Y2NjM5NDg2MmQyMWRiY2E0YTZkZGQyNmYwNGEzNTYwNDEwNDA2YTJmODE5YSIKZGVwZW5kZW5jaWVzID0gWwogImluZGV4bWFwIiwKICJzZXJkZSIsCiAic2VyZGVfc3Bhbm5lZCIsCiAidG9tbF9kYXRldGltZSIsCiAidG9tbF93cml0ZSIsCiAid2lubm93IiwKXQoKW1twYWNrYWdlXV0KbmFtZSA9ICJ0b21sX3dyaXRlIgp2ZXJzaW9uID0gIjAuMS4yIgpzb3VyY2UgPSAicmVnaXN0cnkraHR0cHM6Ly9naXRodWIuY29tL3J1c3QtbGFuZy9jcmF0ZXMuaW8taW5kZXgiCmNoZWNrc3VtID0gIjVkOTlmOGM5YTc3Mjc4ODRhZmU1MjJlOWJkNWVkYmZjOTFhMzMxMmIzNmE3N2I1ZmI4OTI2ZTRjMzFhNDE4MDEiCgpbW3BhY2thZ2VdXQpuYW1lID0gInR5cGVudW0iCnZlcnNpb24gPSAiMS4xOS4wIgpzb3VyY2UgPSAicmVnaXN0cnkraHR0cHM6Ly9naXRodWIuY29tL3J1c3QtbGFuZy9jcmF0ZXMuaW8taW5kZXgiCmNoZWNrc3VtID0gIjU2MmQ0ODEwNjZiZGUwNjU4Mjc2YTM1NDY3YzRhZjAwYmRjNmVlNzI2MzA1Njk4YTU1Yjg2ZTYxZDdhZDgyYmIiCgpbW3BhY2thZ2VdXQpuYW1lID0gInVuaWNvZGUtaWRlbnQiCnZlcnNpb24gPSAiMS4wLjIyIgpzb3VyY2UgPSAicmVnaXN0cnkraHR0cHM6Ly9naXRodWIuY29tL3J1c3QtbGFuZy9jcmF0ZXMuaW8taW5kZXgiCmNoZWNrc3VtID0gIjkzMTJmN2M0ZjZmZjkwNjliMTY1NDk4MjM0Y2U4YmU2NTgwNTljNjcyODYzMzY2N2M1MjZlMjdkYzJjZjFkZjUiCgpbW3BhY2thZ2VdXQpuYW1lID0gInVuaWNvZGUtc2VnbWVudGF0aW9uIgp2ZXJzaW9uID0gIjEuMTIuMCIKc291cmNlID0gInJlZ2lzdHJ5K2h0dHBzOi8vZ2l0aHViLmNvbS9ydXN0LWxhbmcvY3JhdGVzLmlvLWluZGV4IgpjaGVja3N1bSA9ICJmNmNjZjI1MTIxMjExNGI1NDQzM2VjOTQ5ZmQ2YTc4NDEyNzVmOWFkYTIwZGRkZDJmMjllOWNlZWE0NTAxNDkzIgoKW1twYWNrYWdlXV0KbmFtZSA9ICJ1bmljb2RlLXdpZHRoIgp2ZXJzaW9uID0gIjAuMi4yIgpzb3VyY2UgPSAicmVnaXN0cnkraHR0cHM6Ly9naXRodWIuY29tL3J1c3QtbGFuZy9jcmF0ZXMuaW8taW5kZXgiCmNoZWNrc3VtID0gImI0YWMwNDhkNzFlZGU3ZWU3NmQ1ODU1MTdhZGQ0NWRhNTMwNjYwZWY0MzkwZTQ5YjA5ODczM2M2ZTg5N2YyNTQiCgpbW3BhY2thZ2VdXQpuYW1lID0gInVud3JhcC1pbmZhbGxpYmxlIgp2ZXJzaW9uID0gIjAuMS41Igpzb3VyY2UgPSAicmVnaXN0cnkraHR0cHM6Ly9naXRodWIuY29tL3J1c3QtbGFuZy9jcmF0ZXMuaW8taW5kZXgiCmNoZWNrc3VtID0gIjE1MWFjMDk5NzhkM2MyODYyYzRlMzliNTU3ZjRlY2VlZTJjYzcyMTUwYmM0Y2I0ZjE2YWJmMDYxYjZlMzgxZmIiCgpbW3BhY2thZ2VdXQpuYW1lID0gInV0ZjhwYXJzZSIKdmVyc2lvbiA9ICIwLjIuMiIKc291cmNlID0gInJlZ2lzdHJ5K2h0dHBzOi8vZ2l0aHViLmNvbS9ydXN0LWxhbmcvY3JhdGVzLmlvLWluZGV4IgpjaGVja3N1bSA9ICIwNmFiZGUzNjExNjU3YWRmNjZkMzgzZjAwYjA5M2Q3ZmFlY2M3ZmE1NzA3MWNjZTI1Nzg2NjBjOWYxMDEwODIxIgoKW1twYWNrYWdlXV0KbmFtZSA9ICJ3YXNtLWVuY29kZXIiCnZlcnNpb24gPSAiMC4yNDQuMCIKc291cmNlID0gInJlZ2lzdHJ5K2h0dHBzOi8vZ2l0aHViLmNvbS9ydXN0LWxhbmcvY3JhdGVzLmlvLWluZGV4IgpjaGVja3N1bSA9ICI5OTAwNjVmMmZlNjMwMDNmZTMzN2I5MzJjZmI1ZTNiODBlMGI0ZDBmNWZmNjUwZTY5ODViMTA0OGY2MmM4MzE5IgpkZXBlbmRlbmNpZXMgPSBbCiAibGViMTI4Zm10IiwKICJ3YXNtcGFyc2VyIDAuMjQ0LjAiLApdCgpbW3BhY2thZ2VdXQpuYW1lID0gIndhc21wYXJzZXIiCnZlcnNpb24gPSAiMC4yMjcuMSIKc291cmNlID0gInJlZ2lzdHJ5K2h0dHBzOi8vZ2l0aHViLmNvbS9ydXN0LWxhbmcvY3JhdGVzLmlvLWluZGV4IgpjaGVja3N1bSA9ICIwZjUxY2FkNzc0ZmIzYzk0NjFhYjliY2NjOWM2MmRmYjczODgzOTdiNWRlZGEzMWJmNDBlODEwOGNjZDY3OGIyIgpkZXBlbmRlbmNpZXMgPSBbCiAiYml0ZmxhZ3MiLAogImhhc2hicm93biAwLjE1LjUiLAogImluZGV4bWFwIiwKICJzZW12ZXIiLAogInNlcmRlIiwKXQoKW1twYWNrYWdlXV0KbmFtZSA9ICJ3YXNtcGFyc2VyIgp2ZXJzaW9uID0gIjAuMjQ0LjAiCnNvdXJjZSA9ICJyZWdpc3RyeStodHRwczovL2dpdGh1Yi5jb20vcnVzdC1sYW5nL2NyYXRlcy5pby1pbmRleCIKY2hlY2tzdW0gPSAiNDdiODA3YzcyZTFiYWM2OTM4MmIzYTZmYjNkYmU4ZWE0YzBlZDg3ZmY1NjI5Yjg2ODVhZTZiOWE2MTEwMjhmZSIKZGVwZW5kZW5jaWVzID0gWwogImJpdGZsYWdzIiwKICJpbmRleG1hcCIsCiAic2VtdmVyIiwKXQoKW1twYWNrYWdlXV0KbmFtZSA9ICJ3YXNtcHJpbnRlciIKdmVyc2lvbiA9ICIwLjIyNy4xIgpzb3VyY2UgPSAicmVnaXN0cnkraHR0cHM6Ly9naXRodWIuY29tL3J1c3QtbGFuZy9jcmF0ZXMuaW8taW5kZXgiCmNoZWNrc3VtID0gIjMyNDc1YTA0NTlkYjU2MzllOTg5MjA2ZGQ4ODMzZmIwNzExMGVjMDkyYTdjYjM0NjhjODIzNDE5ODljYWM0ZDMiCmRlcGVuZGVuY2llcyA9IFsKICJhbnlob3ciLAogInRlcm1jb2xvciIsCiAid2FzbXBhcnNlciAwLjIyNy4xIiwKXQoKW1twYWNrYWdlXV0KbmFtZSA9ICJ3YXN0Igp2ZXJzaW9uID0gIjI0NC4wLjAiCnNvdXJjZSA9ICJyZWdpc3RyeStodHRwczovL2dpdGh1Yi5jb20vcnVzdC1sYW5nL2NyYXRlcy5pby1pbmRleCIKY2hlY2tzdW0gPSAiYjJlN2I5ZjllMjMzMTEyNzU5MjBlM2Q2YjU2ZDY0MTM3YzE2MGNmOGFmNGY4NGE3MjgzYjM2Y2ZlY2JmNGFjYiIKZGVwZW5kZW5jaWVzID0gWwogImJ1bXBhbG8iLAogImxlYjEyOGZtdCIsCiAibWVtY2hyIiwKICJ1bmljb2RlLXdpZHRoIiwKICJ3YXNtLWVuY29kZXIiLApdCgpbW3BhY2thZ2VdXQpuYW1lID0gIndhdCIKdmVyc2lvbiA9ICIxLjI0NC4wIgpzb3VyY2UgPSAicmVnaXN0cnkraHR0cHM6Ly9naXRodWIuY29tL3J1c3QtbGFuZy9jcmF0ZXMuaW8taW5kZXgiCmNoZWNrc3VtID0gImJiZjM1Yjg3ZWQzNTJmOWFiNmNkMDczMmFiZGU1YTY3ZGQ2MTUzZGZkMDJjNDkzZTYxNDU5MjE4YjE5NDU2ZmEiCmRlcGVuZGVuY2llcyA9IFsKICJ3YXN0IiwKXQoKW1twYWNrYWdlXV0KbmFtZSA9ICJ3aW5hcGktdXRpbCIKdmVyc2lvbiA9ICIwLjEuMTEiCnNvdXJjZSA9ICJyZWdpc3RyeStodHRwczovL2dpdGh1Yi5jb20vcnVzdC1sYW5nL2NyYXRlcy5pby1pbmRleCIKY2hlY2tzdW0gPSAiYzJhN2IxYzAzYzg3NjEyMmFhNDNmMzAyMGU2YzNjM2VlNWMwNTA4MWM5YTAwNzM5ZmFmNzUwM2FlYmExMGQyMiIKZGVwZW5kZW5jaWVzID0gWwogIndpbmRvd3Mtc3lzIDAuNjEuMiIsCl0KCltbcGFja2FnZV1dCm5hbWUgPSAid2luZG93cy1saW5rIgp2ZXJzaW9uID0gIjAuMi4xIgpzb3VyY2UgPSAicmVnaXN0cnkraHR0cHM6Ly9naXRodWIuY29tL3J1c3QtbGFuZy9jcmF0ZXMuaW8taW5kZXgiCmNoZWNrc3VtID0gImYwODA1MjIyZTU3Zjc1MjFkNmE2MmUzNmZhOTE2M2JjODkxYWNkNDIyZjk3MWRlZmU5N2Q2NGU3MGQwYTRmZTUiCgpbW3BhY2thZ2VdXQpuYW1lID0gIndpbmRvd3Mtc3lzIgp2ZXJzaW9uID0gIjAuNTkuMCIKc291cmNlID0gInJlZ2lzdHJ5K2h0dHBzOi8vZ2l0aHViLmNvbS9ydXN0LWxhbmcvY3JhdGVzLmlvLWluZGV4IgpjaGVja3N1bSA9ICIxZTM4YmM0ZDc5ZWQ2N2ZkMDc1YmNjMjUxYTFjMzliMzJhMTc3NmJiZTkyZTViZWYxZjBiZjFmOGM1MzE4NTNiIgpkZXBlbmRlbmNpZXMgPSBbCiAid2luZG93cy10YXJnZXRzIiwKXQoKW1twYWNrYWdlXV0KbmFtZSA9ICJ3aW5kb3dzLXN5cyIKdmVyc2lvbiA9ICIwLjYxLjIiCnNvdXJjZSA9ICJyZWdpc3RyeStodHRwczovL2dpdGh1Yi5jb20vcnVzdC1sYW5nL2NyYXRlcy5pby1pbmRleCIKY2hlY2tzdW0gPSAiYWUxMzcyMjliY2JkNmNkZjBmN2I4MGEzMWRmNjE3NjYxNDUwNzdkZGY0OTQxNmE3MjhiMDJjYjM5MjFmZjNmYyIKZGVwZW5kZW5jaWVzID0gWwogIndpbmRvd3MtbGluayIsCl0KCltbcGFja2FnZV1dCm5hbWUgPSAid2luZG93cy10YXJnZXRzIgp2ZXJzaW9uID0gIjAuNTIuNiIKc291cmNlID0gInJlZ2lzdHJ5K2h0dHBzOi8vZ2l0aHViLmNvbS9ydXN0LWxhbmcvY3JhdGVzLmlvLWluZGV4IgpjaGVja3N1bSA9ICI5YjcyNGY3Mjc5NmUwMzZhYjkwYzEwMjFkNDc4MGQ0ZDNkNjQ4YWNhNTllNDkxZTZiOThlNzI1Yjg0ZTk5OTczIgpkZXBlbmRlbmNpZXMgPSBbCiAid2luZG93c19hYXJjaDY0X2dudWxsdm0iLAogIndpbmRvd3NfYWFyY2g2NF9tc3ZjIiwKICJ3aW5kb3dzX2k2ODZfZ251IiwKICJ3aW5kb3dzX2k2ODZfZ251bGx2bSIsCiAid2luZG93c19pNjg2X21zdmMiLAogIndpbmRvd3NfeDg2XzY0X2dudSIsCiAid2luZG93c194ODZfNjRfZ251bGx2bSIsCiAid2luZG93c194ODZfNjRfbXN2YyIsCl0KCltbcGFja2FnZV1dCm5hbWUgPSAid2luZG93c19hYXJjaDY0X2dudWxsdm0iCnZlcnNpb24gPSAiMC41Mi42Igpzb3VyY2UgPSAicmVnaXN0cnkraHR0cHM6Ly9naXRodWIuY29tL3J1c3QtbGFuZy9jcmF0ZXMuaW8taW5kZXgiCmNoZWNrc3VtID0gIjMyYTQ2MjIxODBlN2EwZWMwNDRiYjU1NTQwNGM4MDBiYzlmZDllYzI2MmVjMTQ3ZWRkNTk4OWNjZDBjMDJjZDMiCgpbW3BhY2thZ2VdXQpuYW1lID0gIndpbmRvd3NfYWFyY2g2NF9tc3ZjIgp2ZXJzaW9uID0gIjAuNTIuNiIKc291cmNlID0gInJlZ2lzdHJ5K2h0dHBzOi8vZ2l0aHViLmNvbS9ydXN0LWxhbmcvY3JhdGVzLmlvLWluZGV4IgpjaGVja3N1bSA9ICIwOWVjMmE3YmIxNTJlMjI1MmI1M2ZhNzgwMzE1MDAwNzg3OTU0OGJjNzA5YzAzOWRmNzYyN2NhYmJkMDVkNDY5IgoKW1twYWNrYWdlXV0KbmFtZSA9ICJ3aW5kb3dzX2k2ODZfZ251Igp2ZXJzaW9uID0gIjAuNTIuNiIKc291cmNlID0gInJlZ2lzdHJ5K2h0dHBzOi8vZ2l0aHViLmNvbS9ydXN0LWxhbmcvY3JhdGVzLmlvLWluZGV4IgpjaGVja3N1bSA9ICI4ZTliNWFkNWFiODAyZTk3ZWI4ZTI5NWFjNjcyMGU1MDllZTRjMjQzZjY5ZDc4MTM5NDAxNGViZmU4YmJmYTBiIgoKW1twYWNrYWdlXV0KbmFtZSA9ICJ3aW5kb3dzX2k2ODZfZ251bGx2bSIKdmVyc2lvbiA9ICIwLjUyLjYiCnNvdXJjZSA9ICJyZWdpc3RyeStodHRwczovL2dpdGh1Yi5jb20vcnVzdC1sYW5nL2NyYXRlcy5pby1pbmRleCIKY2hlY2tzdW0gPSAiMGVlZTUyZDM4YzA5MGIzY2FhNzZjNTYzYjg2YzNhNGJkNzFlZjFhODE5Mjg3YzE5ZDU4NmQ3MzM0YWU4ZWQ2NiIKCltbcGFja2FnZV1dCm5hbWUgPSAid2luZG93c19pNjg2X21zdmMiCnZlcnNpb24gPSAiMC41Mi42Igpzb3VyY2UgPSAicmVnaXN0cnkraHR0cHM6Ly9naXRodWIuY29tL3J1c3QtbGFuZy9jcmF0ZXMuaW8taW5kZXgiCmNoZWNrc3VtID0gIjI0MDk0OGJjMDVjNWU3YzZkYWJiYTI4YmY4OWQ4OWZmY2UzZTMwMzAyMjgwOWU3M2RlYWVmZTRmNmVjNTZjNjYiCgpbW3BhY2thZ2VdXQpuYW1lID0gIndpbmRvd3NfeDg2XzY0X2dudSIKdmVyc2lvbiA9ICIwLjUyLjYiCnNvdXJjZSA9ICJyZWdpc3RyeStodHRwczovL2dpdGh1Yi5jb20vcnVzdC1sYW5nL2NyYXRlcy5pby1pbmRleCIKY2hlY2tzdW0gPSAiMTQ3YTVjODBhYWJmYmYwYzdkOTAxY2I1ODk1ZDFkZTMwZWYyOTA3ZWIyMWZiYmFiMjljYTk0YzViMDhiMWE3OCIKCltbcGFja2FnZV1dCm5hbWUgPSAid2luZG93c194ODZfNjRfZ251bGx2bSIKdmVyc2lvbiA9ICIwLjUyLjYiCnNvdXJjZSA9ICJyZWdpc3RyeStodHRwczovL2dpdGh1Yi5jb20vcnVzdC1sYW5nL2NyYXRlcy5pby1pbmRleCIKY2hlY2tzdW0gPSAiMjRkNWIyM2RjNDE3NDEyNjc5NjgxMzk2ZjJiNDlmM2RlOGMxNDczZGViNTE2YmQzNDQxMDg3MmVmZjUxZWQwZCIKCltbcGFja2FnZV1dCm5hbWUgPSAid2luZG93c194ODZfNjRfbXN2YyIKdmVyc2lvbiA9ICIwLjUyLjYiCnNvdXJjZSA9ICJyZWdpc3RyeStodHRwczovL2dpdGh1Yi5jb20vcnVzdC1sYW5nL2NyYXRlcy5pby1pbmRleCIKY2hlY2tzdW0gPSAiNTg5ZjZkYTg0YzY0NjIwNDc0N2QxMjcwYTJhNTY2MWVhNjZlZDFjY2VkMjYzMWQ1NDZmZGZiMTU1OTU5ZjllYyIKCltbcGFja2FnZV1dCm5hbWUgPSAid2lubm93Igp2ZXJzaW9uID0gIjAuNy4xNCIKc291cmNlID0gInJlZ2lzdHJ5K2h0dHBzOi8vZ2l0aHViLmNvbS9ydXN0LWxhbmcvY3JhdGVzLmlvLWluZGV4IgpjaGVja3N1bSA9ICI1YTUzNjRlOWQ3N2ZjZGVlYWE2MDYyY2VkOTI2ZWUzMzgxZmFhMmVlMDJkM2ViODNhNWMyN2E4ODI1NTQwODI5IgpkZXBlbmRlbmNpZXMgPSBbCiAibWVtY2hyIiwKXQoKW1twYWNrYWdlXV0KbmFtZSA9ICJ6bWlqIgp2ZXJzaW9uID0gIjEuMC4xNCIKc291cmNlID0gInJlZ2lzdHJ5K2h0dHBzOi8vZ2l0aHViLmNvbS9ydXN0LWxhbmcvY3JhdGVzLmlvLWluZGV4IgpjaGVja3N1bSA9ICJiZDhmM2Y1MGI4NDhkZjI4Zjg4N2FjYjY4ZTQxMjAxYjVhZWE2YmM4YThkYWNjMDBmYjQwNjM1ZmY5YTcyZmVhIgo=",
- "module": ".",
- "dependencyDepth": 0,
- "isTestFile": false
- },
- {
- "path": "meta/Cargo.toml",
- "content": "W3BhY2thZ2VdCm5hbWUgPSAicmVxdWVzdHMtbWV0YSIKdmVyc2lvbiA9ICIwLjAuMCIKZWRpdGlvbiA9ICIyMDIxIgpwdWJsaXNoID0gZmFsc2UKCltkZXBlbmRlbmNpZXMucmVxdWVzdHNdCnBhdGggPSAiLi4iCgpbZGVwZW5kZW5jaWVzLm11bHRpdmVyc3gtc2MtbWV0YS1saWJdCnZlcnNpb24gPSAiMC41Ny4xIgpkZWZhdWx0LWZlYXR1cmVzID0gZmFsc2UK",
- "module": ".",
- "dependencyDepth": 0,
- "isTestFile": false
- },
- {
- "path": "meta/src/main.rs",
- "content": "Zm4gbWFpbigpIHsKICAgIG11bHRpdmVyc3hfc2NfbWV0YV9saWI6OmNsaV9tYWluOjo8cmVxdWVzdHM6OkFiaVByb3ZpZGVyPigpOwp9Cg==",
- "module": ".",
- "dependencyDepth": 0,
- "isTestFile": false
- },
- {
- "path": "multiversx.json",
- "content": "ewogICAgImxhbmd1YWdlIjogInJ1c3QiCn0=",
- "module": ".",
- "dependencyDepth": 0,
- "isTestFile": false
- },
- {
- "path": "sc-config.toml",
- "content": "W3NldHRpbmdzXQoKW1twcm94eV1dCnBhdGggPSAic3JjL3JlcXVlc3RzX3Byb3h5LnJzIgo=",
- "module": ".",
- "dependencyDepth": 0,
- "isTestFile": false
- },
- {
- "path": "src/lib.rs",
- "content": "IyFbbm9fc3RkXQoKdXNlIG11bHRpdmVyc3hfc2M6OmltcG9ydHM6Oio7CgojW211bHRpdmVyc3hfc2M6OmNvbnRyYWN0XQpwdWIgdHJhaXQgUmVxdWVzdHNDb250cmFjdCB7CiAgICAvLy8gQ29uc3RydWN0b3IgLSBpbml0aWFsaXplcyB0aGUgY29udHJhY3Qgd2l0aCB0aGUgbnVtYmVyIG9mIHJlcXVlc3RzIHBlciBFR0xECiAgICAjW2luaXRdCiAgICBmbiBpbml0KCZzZWxmLCBudW1fcmVxdWVzdHNfcGVyX2VnbGQ6IEJpZ1VpbnQpIHsKICAgICAgICByZXF1aXJlIShudW1fcmVxdWVzdHNfcGVyX2VnbGQgPiAwLCAiTnVtYmVyIG9mIHJlcXVlc3RzIHBlciBFR0xEIG11c3QgYmUgbm9uLXplcm8iKTsKICAgICAgICBzZWxmLm51bV9yZXF1ZXN0c19wZXJfZWdsZCgpLnNldChudW1fcmVxdWVzdHNfcGVyX2VnbGQpOwogICAgICAgIHNlbGYuaXNfcGF1c2VkKCkuc2V0KGZhbHNlKTsKICAgIH0KCiAgICAvLy8gVXBncmFkZSBmdW5jdGlvbiAtIGNhbGxlZCB3aGVuIGNvbnRyYWN0IGlzIHVwZ3JhZGVkCiAgICAjW3VwZ3JhZGVdCiAgICBmbiB1cGdyYWRlKCZzZWxmLCBudW1fcmVxdWVzdHNfcGVyX2VnbGQ6IEJpZ1VpbnQpIHsKICAgICAgICByZXF1aXJlIShudW1fcmVxdWVzdHNfcGVyX2VnbGQgPiAwLCAiTnVtYmVyIG9mIHJlcXVlc3RzIHBlciBFR0xEIG11c3QgYmUgbm9uLXplcm8iKTsKICAgICAgICBzZWxmLm51bV9yZXF1ZXN0c19wZXJfZWdsZCgpLnNldChudW1fcmVxdWVzdHNfcGVyX2VnbGQpOwogICAgICAgIGlmICFzZWxmLmlzX3BhdXNlZCgpLmlzX2VtcHR5KCkgewogICAgICAgICAgICAvLyBpc19wYXVzZWQgYWxyZWFkeSBleGlzdHMsIGtlZXAgY3VycmVudCB2YWx1ZQogICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgIC8vIEZpcnN0IHVwZ3JhZGUsIGluaXRpYWxpemUgcGF1c2Ugc3RhdGUKICAgICAgICAgICAgc2VsZi5pc19wYXVzZWQoKS5zZXQoZmFsc2UpOwogICAgICAgIH0KICAgIH0KCiAgICAvLy8gQWRkIGFjcXVpcmVkIHJlcXVlc3RzIGZvciBhIGdpdmVuIElEIC0gcGF5YWJsZSBvbmx5IGluIEVHTEQKICAgIC8vLyBUaGUgbnVtYmVyIG9mIGFjcXVpcmVkIHJlcXVlc3RzIGFkZGVkID0gKEVHTEQgYW1vdW50IHRyYW5zZmVycmVkIGluIHJlZ3VsYXIgdW5pdHMpICogbnVtX3JlcXVlc3RzX3Blcl9lZ2xkCiAgICAvLy8gRXhhbXBsZTogMi41IEVHTEQgKiAxMDAgcmF0ZSA9IDI1MCBhY3F1aXJlZCByZXF1ZXN0cwogICAgI1twYXlhYmxlKCJFR0xEIildCiAgICAjW2VuZHBvaW50KGFkZFJlcXVlc3RzKV0KICAgIGZuIGFkZF9yZXF1ZXN0cygmc2VsZiwgaWQ6IHU2NCkgewogICAgICAgIHJlcXVpcmUhKCFzZWxmLmlzX3BhdXNlZCgpLmdldCgpLCAiQ29udHJhY3QgaXMgcGF1c2VkIik7CgogICAgICAgIGxldCBwYXltZW50ID0gc2VsZi5jYWxsX3ZhbHVlKCkuZWdsZCgpOwogICAgICAgIGxldCBhbW91bnRfd2VpID0gcGF5bWVudC5jbG9uZV92YWx1ZSgpOwoKICAgICAgICByZXF1aXJlIShhbW91bnRfd2VpID4gMCwgIlBheW1lbnQgYW1vdW50IG11c3QgYmUgZ3JlYXRlciB0aGFuIDAiKTsKCiAgICAgICAgLy8gQ29udmVydCBmcm9tIHdlaSB0byBFR0xEICgxIEVHTEQgPSAxMF4xOCB3ZWkpCiAgICAgICAgbGV0IG9uZV9lZ2xkID0gQmlnVWludDo6ZnJvbSgxXzAwMF8wMDBfMDAwXzAwMF8wMDBfMDAwdTY0KTsKCiAgICAgICAgbGV0IG51bV9yZXF1ZXN0c19wZXJfZWdsZCA9IHNlbGYubnVtX3JlcXVlc3RzX3Blcl9lZ2xkKCkuZ2V0KCk7CiAgICAgICAgbGV0IHJlcXVlc3RzX3RvX2FkZCA9IChhbW91bnRfd2VpLmNsb25lKCkgKiAmbnVtX3JlcXVlc3RzX3Blcl9lZ2xkKSAvIG9uZV9lZ2xkOwoKICAgICAgICBzZWxmLmFjcXVpcmVkX3JlcXVlc3RzKCZpZCkudXBkYXRlKHxyZXF1ZXN0c3wgKnJlcXVlc3RzICs9IHJlcXVlc3RzX3RvX2FkZC5jbG9uZSgpKTsKCiAgICAgICAgc2VsZi5hZGRfcmVxdWVzdHNfZXZlbnQoJmlkLCAmYW1vdW50X3dlaSwgJnJlcXVlc3RzX3RvX2FkZCk7CiAgICB9CgoKICAgIC8vLyBHZXQgdGhlIG51bWJlciBvZiBhY3F1aXJlZCByZXF1ZXN0cyBmb3IgYSBnaXZlbiBJRAogICAgLy8vIFJldHVybnMgMCBpZiB0aGUgSUQgd2FzIG5vdCBjcmVkaXRlZAogICAgI1t2aWV3KGdldFJlcXVlc3RzKV0KICAgIGZuIGdldF9yZXF1ZXN0cygmc2VsZiwgaWQ6IHU2NCkgLT4gQmlnVWludCB7CiAgICAgICAgc2VsZi5hY3F1aXJlZF9yZXF1ZXN0cygmaWQpLmdldCgpCiAgICB9CgogICAgLy8vIENoZWNrIGlmIHRoZSBjb250cmFjdCBpcyBwYXVzZWQKICAgICNbdmlldyhpc1BhdXNlZCldCiAgICBmbiBnZXRfaXNfcGF1c2VkKCZzZWxmKSAtPiBib29sIHsKICAgICAgICBzZWxmLmlzX3BhdXNlZCgpLmdldCgpCiAgICB9CgogICAgLy8vIEdldCB0aGUgbnVtYmVyIG9mIHJlcXVlc3RzIHBlciBFR0xECiAgICAjW3ZpZXcoZ2V0UmVxdWVzdHNQZXJFZ2xkKV0KICAgIGZuIGdldF9yZXF1ZXN0c19wZXJfZWdsZCgmc2VsZikgLT4gQmlnVWludCB7CiAgICAgICAgc2VsZi5udW1fcmVxdWVzdHNfcGVyX2VnbGQoKS5nZXQoKQogICAgfQoKCiAgICAvLy8gQ2hhbmdlIHRoZSBudW1iZXIgb2YgcmVxdWVzdHMgcGVyIEVHTEQKICAgIC8vLyBDYW4gb25seSBiZSBjYWxsZWQgYnkgdGhlIG93bmVyCiAgICAjW2VuZHBvaW50KGNoYW5nZU51bVJlcXVlc3RzUGVyRUdMRCldCiAgICBmbiBjaGFuZ2VfbnVtX3JlcXVlc3RzX3Blcl9lZ2xkKCZzZWxmLCBuZXdfbnVtX3JlcXVlc3RzX3Blcl9lZ2xkOiBCaWdVaW50KSB7CiAgICAgICAgbGV0IGNhbGxlciA9IHNlbGYuYmxvY2tjaGFpbigpLmdldF9jYWxsZXIoKTsKICAgICAgICBsZXQgb3duZXIgPSBzZWxmLmJsb2NrY2hhaW4oKS5nZXRfb3duZXJfYWRkcmVzcygpOwoKICAgICAgICByZXF1aXJlIShjYWxsZXIgPT0gb3duZXIsICJPbmx5IHRoZSBvd25lciBjYW4gY2hhbmdlIHRoZSBleGNoYW5nZSByYXRlIik7CiAgICAgICAgcmVxdWlyZSEobmV3X251bV9yZXF1ZXN0c19wZXJfZWdsZCA+IDAsICJOdW1iZXIgb2YgcmVxdWVzdHMgcGVyIEVHTEQgbXVzdCBiZSBub24temVybyIpOwoKICAgICAgICBsZXQgb2xkX3ZhbHVlID0gc2VsZi5udW1fcmVxdWVzdHNfcGVyX2VnbGQoKS5nZXQoKTsKICAgICAgICBzZWxmLm51bV9yZXF1ZXN0c19wZXJfZWdsZCgpLnNldChuZXdfbnVtX3JlcXVlc3RzX3Blcl9lZ2xkLmNsb25lKCkpOwoKICAgICAgICBzZWxmLmNoYW5nZV9udW1fcmVxdWVzdHNfcGVyX2VnbGRfZXZlbnQoJm9sZF92YWx1ZSwgJm5ld19udW1fcmVxdWVzdHNfcGVyX2VnbGQpOwogICAgfQoKICAgIC8vLyBQYXVzZSB0aGUgY29udHJhY3QgLSBwcmV2ZW50cyBuZXcgcmVxdWVzdHMgZnJvbSBiZWluZyBhZGRlZAogICAgLy8vIENhbiBvbmx5IGJlIGNhbGxlZCBieSB0aGUgb3duZXIKICAgICNbZW5kcG9pbnQocGF1c2UpXQogICAgZm4gcGF1c2UoJnNlbGYpIHsKICAgICAgICBsZXQgY2FsbGVyID0gc2VsZi5ibG9ja2NoYWluKCkuZ2V0X2NhbGxlcigpOwogICAgICAgIGxldCBvd25lciA9IHNlbGYuYmxvY2tjaGFpbigpLmdldF9vd25lcl9hZGRyZXNzKCk7CgogICAgICAgIHJlcXVpcmUhKGNhbGxlciA9PSBvd25lciwgIk9ubHkgdGhlIG93bmVyIGNhbiBwYXVzZSB0aGUgY29udHJhY3QiKTsKICAgICAgICByZXF1aXJlISghc2VsZi5pc19wYXVzZWQoKS5nZXQoKSwgIkNvbnRyYWN0IGlzIGFscmVhZHkgcGF1c2VkIik7CgogICAgICAgIHNlbGYuaXNfcGF1c2VkKCkuc2V0KHRydWUpOwogICAgICAgIHNlbGYucGF1c2VfZXZlbnQoKTsKICAgIH0KCiAgICAvLy8gVW5wYXVzZSB0aGUgY29udHJhY3QgLSBhbGxvd3MgbmV3IHJlcXVlc3RzIHRvIGJlIGFkZGVkIGFnYWluCiAgICAvLy8gQ2FuIG9ubHkgYmUgY2FsbGVkIGJ5IHRoZSBvd25lcgogICAgI1tlbmRwb2ludCh1bnBhdXNlKV0KICAgIGZuIHVucGF1c2UoJnNlbGYpIHsKICAgICAgICBsZXQgY2FsbGVyID0gc2VsZi5ibG9ja2NoYWluKCkuZ2V0X2NhbGxlcigpOwogICAgICAgIGxldCBvd25lciA9IHNlbGYuYmxvY2tjaGFpbigpLmdldF9vd25lcl9hZGRyZXNzKCk7CgogICAgICAgIHJlcXVpcmUhKGNhbGxlciA9PSBvd25lciwgIk9ubHkgdGhlIG93bmVyIGNhbiB1bnBhdXNlIHRoZSBjb250cmFjdCIpOwogICAgICAgIHJlcXVpcmUhKHNlbGYuaXNfcGF1c2VkKCkuZ2V0KCksICJDb250cmFjdCBpcyBub3QgcGF1c2VkIik7CgogICAgICAgIHNlbGYuaXNfcGF1c2VkKCkuc2V0KGZhbHNlKTsKICAgICAgICBzZWxmLnVucGF1c2VfZXZlbnQoKTsKICAgIH0KCiAgICAvLy8gV2l0aGRyYXcgYWxsIGF2YWlsYWJsZSBFR0xEIGluIHRoZSBjb250cmFjdCB0byB0aGUgb3duZXIncyBhZGRyZXNzCiAgICAvLy8gQ2FuIG9ubHkgYmUgY2FsbGVkIGJ5IHRoZSBvd25lcgogICAgI1tlbmRwb2ludCh3aXRoZHJhd0FsbCldCiAgICBmbiB3aXRoZHJhd19hbGwoJnNlbGYpIHsKICAgICAgICBsZXQgY2FsbGVyID0gc2VsZi5ibG9ja2NoYWluKCkuZ2V0X2NhbGxlcigpOwogICAgICAgIGxldCBvd25lciA9IHNlbGYuYmxvY2tjaGFpbigpLmdldF9vd25lcl9hZGRyZXNzKCk7CgogICAgICAgIHJlcXVpcmUhKGNhbGxlciA9PSBvd25lciwgIk9ubHkgdGhlIG93bmVyIGNhbiB3aXRoZHJhdyIpOwoKICAgICAgICBsZXQgY29udHJhY3RfYmFsYW5jZSA9IHNlbGYuYmxvY2tjaGFpbigpLmdldF9zY19iYWxhbmNlKCZFZ2xkT3JFc2R0VG9rZW5JZGVudGlmaWVyOjplZ2xkKCksIDApOwogICAgICAgIHJlcXVpcmUhKGNvbnRyYWN0X2JhbGFuY2UgPiAwLCAiTm8gRUdMRCB0byB3aXRoZHJhdyIpOwoKICAgICAgICBzZWxmLnR4KCkKICAgICAgICAgICAgLnRvKCZvd25lcikKICAgICAgICAgICAgLmVnbGQoJmNvbnRyYWN0X2JhbGFuY2UpCiAgICAgICAgICAgIC50cmFuc2ZlcigpOwoKICAgICAgICBzZWxmLndpdGhkcmF3X2V2ZW50KCZvd25lciwgJmNvbnRyYWN0X2JhbGFuY2UpOwogICAgfQoKICAgIC8vLyBFdmVudCBlbWl0dGVkIHdoZW4gcmVxdWVzdHMgYXJlIGFkZGVkCiAgICAjW2V2ZW50KCJhZGRSZXF1ZXN0cyIpXQogICAgZm4gYWRkX3JlcXVlc3RzX2V2ZW50KAogICAgICAgICZzZWxmLAogICAgICAgICNbaW5kZXhlZF0gaWQ6ICZ1NjQsCiAgICAgICAgI1tpbmRleGVkXSBlZ2xkX2Ftb3VudDogJkJpZ1VpbnQsCiAgICAgICAgcmVxdWVzdHNfYWRkZWQ6ICZCaWdVaW50LAogICAgKTsKCiAgICAvLy8gRXZlbnQgZW1pdHRlZCB3aGVuIHRoZSBleGNoYW5nZSByYXRlIGlzIGNoYW5nZWQKICAgICNbZXZlbnQoImNoYW5nZU51bVJlcXVlc3RzUGVyRUdMRCIpXQogICAgZm4gY2hhbmdlX251bV9yZXF1ZXN0c19wZXJfZWdsZF9ldmVudCgKICAgICAgICAmc2VsZiwKICAgICAgICAjW2luZGV4ZWRdIG9sZF92YWx1ZTogJkJpZ1VpbnQsCiAgICAgICAgbmV3X3ZhbHVlOiAmQmlnVWludCwKICAgICk7CgogICAgLy8vIEV2ZW50IGVtaXR0ZWQgd2hlbiB0aGUgY29udHJhY3QgaXMgcGF1c2VkCiAgICAjW2V2ZW50KCJwYXVzZSIpXQogICAgZm4gcGF1c2VfZXZlbnQoJnNlbGYpOwoKICAgIC8vLyBFdmVudCBlbWl0dGVkIHdoZW4gdGhlIGNvbnRyYWN0IGlzIHVucGF1c2VkCiAgICAjW2V2ZW50KCJ1bnBhdXNlIildCiAgICBmbiB1bnBhdXNlX2V2ZW50KCZzZWxmKTsKCiAgICAvLy8gRXZlbnQgZW1pdHRlZCB3aGVuIEVHTEQgaXMgd2l0aGRyYXduCiAgICAjW2V2ZW50KCJ3aXRoZHJhdyIpXQogICAgZm4gd2l0aGRyYXdfZXZlbnQoCiAgICAgICAgJnNlbGYsCiAgICAgICAgI1tpbmRleGVkXSByZWNpcGllbnQ6ICZNYW5hZ2VkQWRkcmVzcywKICAgICAgICBhbW91bnQ6ICZCaWdVaW50LAogICAgKTsKCiAgICAvLy8gU3RvcmFnZSBtYXBwZXIgZm9yIHRoZSBudW1iZXIgb2YgcmVxdWVzdHMgcGVyIEVHTEQKICAgICNbc3RvcmFnZV9tYXBwZXIoIm51bVJlcXVlc3RzUGVyRWdsZCIpXQogICAgZm4gbnVtX3JlcXVlc3RzX3Blcl9lZ2xkKCZzZWxmKSAtPiBTaW5nbGVWYWx1ZU1hcHBlcjxCaWdVaW50PjsKCiAgICAvLy8gU3RvcmFnZSBtYXBwZXIgZm9yIGFjcXVpcmVkIHJlcXVlc3RzIGNvdW50IHBlciBJRAogICAgI1tzdG9yYWdlX21hcHBlcigiYWNxdWlyZWRSZXF1ZXN0cyIpXQogICAgZm4gYWNxdWlyZWRfcmVxdWVzdHMoJnNlbGYsIGlkOiAmdTY0KSAtPiBTaW5nbGVWYWx1ZU1hcHBlcjxCaWdVaW50PjsKCiAgICAvLy8gU3RvcmFnZSBtYXBwZXIgZm9yIHBhdXNlIHN0YXRlCiAgICAjW3N0b3JhZ2VfbWFwcGVyKCJpc1BhdXNlZCIpXQogICAgZm4gaXNfcGF1c2VkKCZzZWxmKSAtPiBTaW5nbGVWYWx1ZU1hcHBlcjxib29sPjsKfQo=",
- "module": ".",
- "dependencyDepth": 0,
- "isTestFile": false
- },
- {
- "path": "tests/scenarios_rs_test.rs",
- "content": "dXNlIG11bHRpdmVyc3hfc2Nfc2NlbmFyaW86Oio7CgpmbiB3b3JsZCgpIC0+IFNjZW5hcmlvV29ybGQgewogICAgbGV0IG11dCBibG9ja2NoYWluID0gU2NlbmFyaW9Xb3JsZDo6bmV3KCk7CgogICAgYmxvY2tjaGFpbi5zZXRfY3VycmVudF9kaXJfZnJvbV93b3Jrc3BhY2UoIiIpOwogICAgYmxvY2tjaGFpbi5yZWdpc3Rlcl9jb250cmFjdCgibXhzYzpvdXRwdXQvcmVxdWVzdHMubXhzYy5qc29uIiwgcmVxdWVzdHM6OkNvbnRyYWN0QnVpbGRlcik7CiAgICBibG9ja2NoYWluCn0KCiNbdGVzdF0KZm4gYWRkX3JlcXVlc3RzX2FjY3VtdWxhdGlvbl9ycygpIHsKICAgIHdvcmxkKCkucnVuKCJzY2VuYXJpb3MvYWRkX3JlcXVlc3RzX2FjY3VtdWxhdGlvbi5zY2VuLmpzb24iKTsKfQoKI1t0ZXN0XQpmbiBhZGRfcmVxdWVzdHNfbXVsdGlwbGVfcnMoKSB7CiAgICB3b3JsZCgpLnJ1bigic2NlbmFyaW9zL2FkZF9yZXF1ZXN0c19tdWx0aXBsZS5zY2VuLmpzb24iKTsKfQoKI1t0ZXN0XQpmbiBhZGRfcmVxdWVzdHNfc2luZ2xlX3JzKCkgewogICAgd29ybGQoKS5ydW4oInNjZW5hcmlvcy9hZGRfcmVxdWVzdHNfc2luZ2xlLnNjZW4uanNvbiIpOwp9CgojW3Rlc3RdCmZuIGFkZF9yZXF1ZXN0c193aGVuX3BhdXNlZF9ycygpIHsKICAgIHdvcmxkKCkucnVuKCJzY2VuYXJpb3MvYWRkX3JlcXVlc3RzX3doZW5fcGF1c2VkLnNjZW4uanNvbiIpOwp9CgojW3Rlc3RdCmZuIGNoYW5nZV9yYXRlX25vbl9vd25lcl9ycygpIHsKICAgIHdvcmxkKCkucnVuKCJzY2VuYXJpb3MvY2hhbmdlX3JhdGVfbm9uX293bmVyLnNjZW4uanNvbiIpOwp9CgojW3Rlc3RdCmZuIGNoYW5nZV9yYXRlX3ZhbGlkX3JzKCkgewogICAgd29ybGQoKS5ydW4oInNjZW5hcmlvcy9jaGFuZ2VfcmF0ZV92YWxpZC5zY2VuLmpzb24iKTsKfQoKI1t0ZXN0XQpmbiBjaGFuZ2VfcmF0ZV96ZXJvX3JzKCkgewogICAgd29ybGQoKS5ydW4oInNjZW5hcmlvcy9jaGFuZ2VfcmF0ZV96ZXJvLnNjZW4uanNvbiIpOwp9CgojW3Rlc3RdCmZuIGZ1bGxfd29ya2Zsb3dfcnMoKSB7CiAgICB3b3JsZCgpLnJ1bigic2NlbmFyaW9zL2Z1bGxfd29ya2Zsb3cuc2Nlbi5qc29uIik7Cn0KCiNbdGVzdF0KZm4gZ2V0X3JlcXVlc3RzX2V4aXN0aW5nX3JzKCkgewogICAgd29ybGQoKS5ydW4oInNjZW5hcmlvcy9nZXRfcmVxdWVzdHNfZXhpc3Rpbmcuc2Nlbi5qc29uIik7Cn0KCiNbdGVzdF0KZm4gZ2V0X3JlcXVlc3RzX25vbmV4aXN0ZW50X3JzKCkgewogICAgd29ybGQoKS5ydW4oInNjZW5hcmlvcy9nZXRfcmVxdWVzdHNfbm9uZXhpc3RlbnQuc2Nlbi5qc29uIik7Cn0KCiNbdGVzdF0KZm4gaW5pdF92YWxpZF9ycygpIHsKICAgIHdvcmxkKCkucnVuKCJzY2VuYXJpb3MvaW5pdF92YWxpZC5zY2VuLmpzb24iKTsKfQoKI1t0ZXN0XQpmbiBpbml0X3plcm9fcnMoKSB7CiAgICB3b3JsZCgpLnJ1bigic2NlbmFyaW9zL2luaXRfemVyby5zY2VuLmpzb24iKTsKfQoKI1t0ZXN0XQpmbiBwYXVzZV9hbHJlYWR5X3BhdXNlZF9ycygpIHsKICAgIHdvcmxkKCkucnVuKCJzY2VuYXJpb3MvcGF1c2VfYWxyZWFkeV9wYXVzZWQuc2Nlbi5qc29uIik7Cn0KCiNbdGVzdF0KZm4gcGF1c2Vfbm9uX293bmVyX3JzKCkgewogICAgd29ybGQoKS5ydW4oInNjZW5hcmlvcy9wYXVzZV9ub25fb3duZXIuc2Nlbi5qc29uIik7Cn0KCiNbdGVzdF0KZm4gcGF1c2Vfc3VjY2Vzc19ycygpIHsKICAgIHdvcmxkKCkucnVuKCJzY2VuYXJpb3MvcGF1c2Vfc3VjY2Vzcy5zY2VuLmpzb24iKTsKfQoKI1t0ZXN0XQpmbiBwYXVzZV91bnBhdXNlX3dvcmtmbG93X3JzKCkgewogICAgd29ybGQoKS5ydW4oInNjZW5hcmlvcy9wYXVzZV91bnBhdXNlX3dvcmtmbG93LnNjZW4uanNvbiIpOwp9CgojW3Rlc3RdCmZuIHJhdGVfY2hhbmdlX2FmZmVjdHNfZnV0dXJlX3JzKCkgewogICAgd29ybGQoKS5ydW4oInNjZW5hcmlvcy9yYXRlX2NoYW5nZV9hZmZlY3RzX2Z1dHVyZS5zY2VuLmpzb24iKTsKfQoKI1t0ZXN0XQpmbiB1bnBhdXNlX25vbl9vd25lcl9ycygpIHsKICAgIHdvcmxkKCkucnVuKCJzY2VuYXJpb3MvdW5wYXVzZV9ub25fb3duZXIuc2Nlbi5qc29uIik7Cn0KCiNbdGVzdF0KZm4gdW5wYXVzZV9ub3RfcGF1c2VkX3JzKCkgewogICAgd29ybGQoKS5ydW4oInNjZW5hcmlvcy91bnBhdXNlX25vdF9wYXVzZWQuc2Nlbi5qc29uIik7Cn0KCiNbdGVzdF0KZm4gdW5wYXVzZV9zdWNjZXNzX3JzKCkgewogICAgd29ybGQoKS5ydW4oInNjZW5hcmlvcy91bnBhdXNlX3N1Y2Nlc3Muc2Nlbi5qc29uIik7Cn0KCiNbdGVzdF0KZm4gd2l0aGRyYXdfZW1wdHlfcnMoKSB7CiAgICB3b3JsZCgpLnJ1bigic2NlbmFyaW9zL3dpdGhkcmF3X2VtcHR5LnNjZW4uanNvbiIpOwp9CgojW3Rlc3RdCmZuIHdpdGhkcmF3X25vbl9vd25lcl9ycygpIHsKICAgIHdvcmxkKCkucnVuKCJzY2VuYXJpb3Mvd2l0aGRyYXdfbm9uX293bmVyLnNjZW4uanNvbiIpOwp9CgojW3Rlc3RdCmZuIHdpdGhkcmF3X3N1Y2Nlc3NfcnMoKSB7CiAgICB3b3JsZCgpLnJ1bigic2NlbmFyaW9zL3dpdGhkcmF3X3N1Y2Nlc3Muc2Nlbi5qc29uIik7Cn0K",
- "module": ".",
- "dependencyDepth": 0,
- "isTestFile": true
- },
- {
- "path": "wasm/Cargo.lock",
- "content": "IyBUaGlzIGZpbGUgaXMgYXV0b21hdGljYWxseSBAZ2VuZXJhdGVkIGJ5IENhcmdvLgojIEl0IGlzIG5vdCBpbnRlbmRlZCBmb3IgbWFudWFsIGVkaXRpbmcuCnZlcnNpb24gPSA0CgpbW3BhY2thZ2VdXQpuYW1lID0gImFycmF5dmVjIgp2ZXJzaW9uID0gIjAuNy42Igpzb3VyY2UgPSAicmVnaXN0cnkraHR0cHM6Ly9naXRodWIuY29tL3J1c3QtbGFuZy9jcmF0ZXMuaW8taW5kZXgiCmNoZWNrc3VtID0gIjdjMDJkMTIzZGYwMTdlZmNkZmJkNzM5ZWY4MTczNWIzNmM1YmE4M2VjM2M1OWM4MGE5ZDdlY2M3MThmOTJlNTAiCgpbW3BhY2thZ2VdXQpuYW1lID0gImF1dG9jZmciCnZlcnNpb24gPSAiMS41LjAiCnNvdXJjZSA9ICJyZWdpc3RyeStodHRwczovL2dpdGh1Yi5jb20vcnVzdC1sYW5nL2NyYXRlcy5pby1pbmRleCIKY2hlY2tzdW0gPSAiYzA4NjA2ZjhjM2NiZjRjZTZlYzhlMjhmYjAwMTRhMmMwODY3MDhmZTk1NGVhYTg4NTM4NGE2MTY1MTcyZTdlOCIKCltbcGFja2FnZV1dCm5hbWUgPSAiYml0ZmxhZ3MiCnZlcnNpb24gPSAiMi45LjAiCnNvdXJjZSA9ICJyZWdpc3RyeStodHRwczovL2dpdGh1Yi5jb20vcnVzdC1sYW5nL2NyYXRlcy5pby1pbmRleCIKY2hlY2tzdW0gPSAiNWM4MjE0MTE1YjdiZjg0MDk5ZjEzMDkzMjRlNjMxNDFkNGM1ZDdjYzI2ODYyZjk3YTBhODU3ZGJlZmUxNjViZCIKCltbcGFja2FnZV1dCm5hbWUgPSAiZW5kaWFuLXR5cGUiCnZlcnNpb24gPSAiMC4xLjIiCnNvdXJjZSA9ICJyZWdpc3RyeStodHRwczovL2dpdGh1Yi5jb20vcnVzdC1sYW5nL2NyYXRlcy5pby1pbmRleCIKY2hlY2tzdW0gPSAiYzM0ZjA0NjY2ZDgzNWZmNWQ2MmUwNThjMzk5NTE0N2MwNmY0MmZlODZmZjA1MzMzNzYzMmJjYTgzZTQyNzAyZCIKCltbcGFja2FnZV1dCm5hbWUgPSAiZ2VuZXJpYy1hcnJheSIKdmVyc2lvbiA9ICIxLjMuNSIKc291cmNlID0gInJlZ2lzdHJ5K2h0dHBzOi8vZ2l0aHViLmNvbS9ydXN0LWxhbmcvY3JhdGVzLmlvLWluZGV4IgpjaGVja3N1bSA9ICJlYWY1N2M0OWE5NWZkMWZlMjRiOTBiMzAzM2JlZTZkYzdlOGYxMjg4ZDUxNDk0Y2I0NGU2MjdjMjk1ZTM4NTQyIgpkZXBlbmRlbmNpZXMgPSBbCiAicnVzdHZlcnNpb24iLAogInR5cGVudW0iLApdCgpbW3BhY2thZ2VdXQpuYW1lID0gImhleCIKdmVyc2lvbiA9ICIwLjQuMyIKc291cmNlID0gInJlZ2lzdHJ5K2h0dHBzOi8vZ2l0aHViLmNvbS9ydXN0LWxhbmcvY3JhdGVzLmlvLWluZGV4IgpjaGVja3N1bSA9ICI3ZjI0MjU0YWE5YTU0YjVjODU4ZWFlZTJmNWJjY2RiNDZhYWYwZTQ4NmE1OTVlZDVmZDhmODZiYTU1MjMyYTcwIgoKW1twYWNrYWdlXV0KbmFtZSA9ICJoZXgtbGl0ZXJhbCIKdmVyc2lvbiA9ICIwLjQuMSIKc291cmNlID0gInJlZ2lzdHJ5K2h0dHBzOi8vZ2l0aHViLmNvbS9ydXN0LWxhbmcvY3JhdGVzLmlvLWluZGV4IgpjaGVja3N1bSA9ICI2ZmUyMjY3ZDRlZDQ5YmMwN2I2MzgwMTU1OWJlMjhjNzE4ZWEwNmM0NzM4YjdhMDNjOTRkZjczODZkMmNkZTQ2IgoKW1twYWNrYWdlXV0KbmFtZSA9ICJtdWx0aXZlcnN4LWNoYWluLWNvcmUiCnZlcnNpb24gPSAiMC4xNC4wIgpzb3VyY2UgPSAicmVnaXN0cnkraHR0cHM6Ly9naXRodWIuY29tL3J1c3QtbGFuZy9jcmF0ZXMuaW8taW5kZXgiCmNoZWNrc3VtID0gIjczZjFmMDUyNmNhMDk0MTg1ODQ3Nzc2YzJjMDNkZTk3ZWEwODI3NDNlZTRlNmY3OTk4NjBhZDY3ZTdkNzgyNTAiCmRlcGVuZGVuY2llcyA9IFsKICJiaXRmbGFncyIsCiAibXVsdGl2ZXJzeC1zYy1jb2RlYyIsCl0KCltbcGFja2FnZV1dCm5hbWUgPSAibXVsdGl2ZXJzeC1zYyIKdmVyc2lvbiA9ICIwLjU3LjEiCnNvdXJjZSA9ICJyZWdpc3RyeStodHRwczovL2dpdGh1Yi5jb20vcnVzdC1sYW5nL2NyYXRlcy5pby1pbmRleCIKY2hlY2tzdW0gPSAiMjA2MDJkNGZjMzM2MDkyZmFhZGMwM2I2YjQ0NWM0YmI1ZTRkYmM0Yzg2ZmI1MzcyNmU0NmVjYTY3MDcwODEzYSIKZGVwZW5kZW5jaWVzID0gWwogImJpdGZsYWdzIiwKICJnZW5lcmljLWFycmF5IiwKICJoZXgtbGl0ZXJhbCIsCiAibXVsdGl2ZXJzeC1jaGFpbi1jb3JlIiwKICJtdWx0aXZlcnN4LXNjLWNvZGVjIiwKICJtdWx0aXZlcnN4LXNjLWRlcml2ZSIsCiAibnVtLXRyYWl0cyIsCiAidW53cmFwLWluZmFsbGlibGUiLApdCgpbW3BhY2thZ2VdXQpuYW1lID0gIm11bHRpdmVyc3gtc2MtY29kZWMiCnZlcnNpb24gPSAiMC4yMi4wIgpzb3VyY2UgPSAicmVnaXN0cnkraHR0cHM6Ly9naXRodWIuY29tL3J1c3QtbGFuZy9jcmF0ZXMuaW8taW5kZXgiCmNoZWNrc3VtID0gIjQzZTBmMjRhMDIwYWRmMzJmYWZmYWUxYzU3NDc1YzZiNzI4NWEzMjE2ZDFhMzZlNGE3MzYxNzYzOTcyMWMyZTAiCmRlcGVuZGVuY2llcyA9IFsKICJhcnJheXZlYyIsCiAiYml0ZmxhZ3MiLAogIm11bHRpdmVyc3gtc2MtY29kZWMtZGVyaXZlIiwKICJ1bndyYXAtaW5mYWxsaWJsZSIsCl0KCltbcGFja2FnZV1dCm5hbWUgPSAibXVsdGl2ZXJzeC1zYy1jb2RlYy1kZXJpdmUiCnZlcnNpb24gPSAiMC4yMi4wIgpzb3VyY2UgPSAicmVnaXN0cnkraHR0cHM6Ly9naXRodWIuY29tL3J1c3QtbGFuZy9jcmF0ZXMuaW8taW5kZXgiCmNoZWNrc3VtID0gIjdjNWYxN2Q1ZWUyMzY1N2Q1Y2RkYzdmNDQ3MTkyNWI1YTQ5ZjdlMjUzMDZmOGJiYTY1NmVhNjkxN2FjYzYyOWQiCmRlcGVuZGVuY2llcyA9IFsKICJoZXgiLAogInByb2MtbWFjcm8yIiwKICJxdW90ZSIsCiAic3luIiwKXQoKW1twYWNrYWdlXV0KbmFtZSA9ICJtdWx0aXZlcnN4LXNjLWRlcml2ZSIKdmVyc2lvbiA9ICIwLjU3LjEiCnNvdXJjZSA9ICJyZWdpc3RyeStodHRwczovL2dpdGh1Yi5jb20vcnVzdC1sYW5nL2NyYXRlcy5pby1pbmRleCIKY2hlY2tzdW0gPSAiMGQ0NGQwOGQzMzc2YzE5OWU4YzM5MWNjMDc3NTJkMjgyMmNkMjg5NjkzZGE1MzE5ZDc5MDU1OTk1MDFlNTU3ZiIKZGVwZW5kZW5jaWVzID0gWwogImhleCIsCiAicHJvYy1tYWNybzIiLAogInF1b3RlIiwKICJyYWRpeF90cmllIiwKICJzeW4iLApdCgpbW3BhY2thZ2VdXQpuYW1lID0gIm11bHRpdmVyc3gtc2Mtd2FzbS1hZGFwdGVyIgp2ZXJzaW9uID0gIjAuNTcuMSIKc291cmNlID0gInJlZ2lzdHJ5K2h0dHBzOi8vZ2l0aHViLmNvbS9ydXN0LWxhbmcvY3JhdGVzLmlvLWluZGV4IgpjaGVja3N1bSA9ICJlZTgyNTNiODQ2MDA1NTRmYmUxNmVhMGEyMzRiMDA5ODU0MzQ4ZGM5NWNlMTc0YmE2ZWJhMDQ2ZGM1OTE4ZjhmIgpkZXBlbmRlbmNpZXMgPSBbCiAibXVsdGl2ZXJzeC1zYyIsCl0KCltbcGFja2FnZV1dCm5hbWUgPSAibmliYmxlX3ZlYyIKdmVyc2lvbiA9ICIwLjEuMCIKc291cmNlID0gInJlZ2lzdHJ5K2h0dHBzOi8vZ2l0aHViLmNvbS9ydXN0LWxhbmcvY3JhdGVzLmlvLWluZGV4IgpjaGVja3N1bSA9ICI3N2E1ZDgzZGY5ZjM2ZmUyM2YwYzM2NDhjNmJiYjhiMDI5OGJiNWYxOTM5YzhmMjcwNDQzMTM3MWY0Yjg0ZDQzIgpkZXBlbmRlbmNpZXMgPSBbCiAic21hbGx2ZWMiLApdCgpbW3BhY2thZ2VdXQpuYW1lID0gIm51bS10cmFpdHMiCnZlcnNpb24gPSAiMC4yLjE5Igpzb3VyY2UgPSAicmVnaXN0cnkraHR0cHM6Ly9naXRodWIuY29tL3J1c3QtbGFuZy9jcmF0ZXMuaW8taW5kZXgiCmNoZWNrc3VtID0gIjA3MWRmYzA2MjY5MGU5MGI3MzRjMGIyMjczY2U3MmFkMGZmYTk1ZjBjNzQ1OTZiYzI1MGRjZmQ5NjAyNjI4NDEiCmRlcGVuZGVuY2llcyA9IFsKICJhdXRvY2ZnIiwKXQoKW1twYWNrYWdlXV0KbmFtZSA9ICJwcm9jLW1hY3JvMiIKdmVyc2lvbiA9ICIxLjAuOTQiCnNvdXJjZSA9ICJyZWdpc3RyeStodHRwczovL2dpdGh1Yi5jb20vcnVzdC1sYW5nL2NyYXRlcy5pby1pbmRleCIKY2hlY2tzdW0gPSAiYTMxOTcxNzUyZTcwYjhiMjY4NmQ3ZTQ2ZWMxN2ZiMzhkYWQ0MDUxZDk0MDI0Yzg4ZGY0OWI2NjdjYWVhOWM4NCIKZGVwZW5kZW5jaWVzID0gWwogInVuaWNvZGUtaWRlbnQiLApdCgpbW3BhY2thZ2VdXQpuYW1lID0gInF1b3RlIgp2ZXJzaW9uID0gIjEuMC4zOSIKc291cmNlID0gInJlZ2lzdHJ5K2h0dHBzOi8vZ2l0aHViLmNvbS9ydXN0LWxhbmcvY3JhdGVzLmlvLWluZGV4IgpjaGVja3N1bSA9ICJjMWYxOTE0Y2U5MDllMTY1OGQ5OTA3OTEzYjRiOTE5NDc0MzBjN2Q5YmU1OThiMTVhMTkxMjkzNWI4YzA0ODAxIgpkZXBlbmRlbmNpZXMgPSBbCiAicHJvYy1tYWNybzIiLApdCgpbW3BhY2thZ2VdXQpuYW1lID0gInJhZGl4X3RyaWUiCnZlcnNpb24gPSAiMC4yLjEiCnNvdXJjZSA9ICJyZWdpc3RyeStodHRwczovL2dpdGh1Yi5jb20vcnVzdC1sYW5nL2NyYXRlcy5pby1pbmRleCIKY2hlY2tzdW0gPSAiYzA2OWMxNzlmY2RjNmEyZmUyNGQ4ZDE4MzA1Y2YwODVmZGJkNGY5MjJjMDQxOTQzZTIwMzY4NWQ2YTFjNThmZCIKZGVwZW5kZW5jaWVzID0gWwogImVuZGlhbi10eXBlIiwKICJuaWJibGVfdmVjIiwKXQoKW1twYWNrYWdlXV0KbmFtZSA9ICJyZXF1ZXN0cyIKdmVyc2lvbiA9ICIwLjAuMCIKZGVwZW5kZW5jaWVzID0gWwogIm11bHRpdmVyc3gtc2MiLApdCgpbW3BhY2thZ2VdXQpuYW1lID0gInJlcXVlc3RzLXdhc20iCnZlcnNpb24gPSAiMC4wLjAiCmRlcGVuZGVuY2llcyA9IFsKICJtdWx0aXZlcnN4LXNjLXdhc20tYWRhcHRlciIsCiAicmVxdWVzdHMiLApdCgpbW3BhY2thZ2VdXQpuYW1lID0gInJ1c3R2ZXJzaW9uIgp2ZXJzaW9uID0gIjEuMC4yMiIKc291cmNlID0gInJlZ2lzdHJ5K2h0dHBzOi8vZ2l0aHViLmNvbS9ydXN0LWxhbmcvY3JhdGVzLmlvLWluZGV4IgpjaGVja3N1bSA9ICJiMzljZGVmMGZhODAwZmM0NDUyNWM4NGNjYjU0YTAyOTk2MWE4MjE1Zjk2MTk3NTM2MzVhOWMwZDI1MzhkNDZkIgoKW1twYWNrYWdlXV0KbmFtZSA9ICJzbWFsbHZlYyIKdmVyc2lvbiA9ICIxLjE1LjEiCnNvdXJjZSA9ICJyZWdpc3RyeStodHRwczovL2dpdGh1Yi5jb20vcnVzdC1sYW5nL2NyYXRlcy5pby1pbmRleCIKY2hlY2tzdW0gPSAiNjdiMWI3YTNiNWZlNGYxMzc2ODg3MTg0MDQ1ZmNmNDVjNjllOTJhZjczNGI3YWFkZGMwNWZiNzc3YjZmYmQwMyIKCltbcGFja2FnZV1dCm5hbWUgPSAic3luIgp2ZXJzaW9uID0gIjIuMC4xMDAiCnNvdXJjZSA9ICJyZWdpc3RyeStodHRwczovL2dpdGh1Yi5jb20vcnVzdC1sYW5nL2NyYXRlcy5pby1pbmRleCIKY2hlY2tzdW0gPSAiYjA5YTQ0YWNjYWQ4MWUxYmExY2Q3NGEzMjQ2MWJhODlkZWU4OTA5NWJhMTdiMzJmNWQwMzY4M2IxYjFmYzJhMCIKZGVwZW5kZW5jaWVzID0gWwogInByb2MtbWFjcm8yIiwKICJxdW90ZSIsCiAidW5pY29kZS1pZGVudCIsCl0KCltbcGFja2FnZV1dCm5hbWUgPSAidHlwZW51bSIKdmVyc2lvbiA9ICIxLjE5LjAiCnNvdXJjZSA9ICJyZWdpc3RyeStodHRwczovL2dpdGh1Yi5jb20vcnVzdC1sYW5nL2NyYXRlcy5pby1pbmRleCIKY2hlY2tzdW0gPSAiNTYyZDQ4MTA2NmJkZTA2NTgyNzZhMzU0NjdjNGFmMDBiZGM2ZWU3MjYzMDU2OThhNTViODZlNjFkN2FkODJiYiIKCltbcGFja2FnZV1dCm5hbWUgPSAidW5pY29kZS1pZGVudCIKdmVyc2lvbiA9ICIxLjAuMjIiCnNvdXJjZSA9ICJyZWdpc3RyeStodHRwczovL2dpdGh1Yi5jb20vcnVzdC1sYW5nL2NyYXRlcy5pby1pbmRleCIKY2hlY2tzdW0gPSAiOTMxMmY3YzRmNmZmOTA2OWIxNjU0OTgyMzRjZThiZTY1ODA1OWM2NzI4NjMzNjY3YzUyNmUyN2RjMmNmMWRmNSIKCltbcGFja2FnZV1dCm5hbWUgPSAidW53cmFwLWluZmFsbGlibGUiCnZlcnNpb24gPSAiMC4xLjUiCnNvdXJjZSA9ICJyZWdpc3RyeStodHRwczovL2dpdGh1Yi5jb20vcnVzdC1sYW5nL2NyYXRlcy5pby1pbmRleCIKY2hlY2tzdW0gPSAiMTUxYWMwOTk3OGQzYzI4NjJjNGUzOWI1NTdmNGVjZWVlMmNjNzIxNTBiYzRjYjRmMTZhYmYwNjFiNmUzODFmYiIK",
- "module": ".",
- "dependencyDepth": 0,
- "isTestFile": false
- },
- {
- "path": "wasm/Cargo.toml",
- "content": "IyBDb2RlIGdlbmVyYXRlZCBieSB0aGUgbXVsdGl2ZXJzeC1zYyBidWlsZCBzeXN0ZW0uIERPIE5PVCBFRElULgoKIyAjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKIyAjIyMjIyMjIyMjIyMjIyBBVVRPLUdFTkVSQVRFRCAjIyMjIyMjIyMjIyMjCiMgIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCgpbcGFja2FnZV0KbmFtZSA9ICJyZXF1ZXN0cy13YXNtIgp2ZXJzaW9uID0gIjAuMC4wIgplZGl0aW9uID0gIjIwMjEiCnB1Ymxpc2ggPSBmYWxzZQoKW2xpYl0KY3JhdGUtdHlwZSA9IFsiY2R5bGliIl0KCltwcm9maWxlLnJlbGVhc2VdCmNvZGVnZW4tdW5pdHMgPSAxCm9wdC1sZXZlbCA9ICJ6IgpsdG8gPSB0cnVlCmRlYnVnID0gZmFsc2UKcGFuaWMgPSAiYWJvcnQiCm92ZXJmbG93LWNoZWNrcyA9IGZhbHNlCgpbcHJvZmlsZS5kZXZdCnBhbmljID0gImFib3J0IgoKW2RlcGVuZGVuY2llcy5yZXF1ZXN0c10KcGF0aCA9ICIuLiIKCltkZXBlbmRlbmNpZXMubXVsdGl2ZXJzeC1zYy13YXNtLWFkYXB0ZXJdCnZlcnNpb24gPSAiMC41Ny4xIgoKW3dvcmtzcGFjZV0KbWVtYmVycyA9IFsiLiJdCg==",
- "module": ".",
- "dependencyDepth": 0,
- "isTestFile": false
- },
- {
- "path": "wasm/src/lib.rs",
- "content": "Ly8gQ29kZSBnZW5lcmF0ZWQgYnkgdGhlIG11bHRpdmVyc3gtc2MgYnVpbGQgc3lzdGVtLiBETyBOT1QgRURJVC4KCi8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8KLy8vLy8vLy8vLy8vLy8vLy8vIEFVVE8tR0VORVJBVEVEIC8vLy8vLy8vLy8vLy8vLy8vLwovLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vCgovLyBJbml0OiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDEKLy8gVXBncmFkZTogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAxCi8vIEVuZHBvaW50czogICAgICAgICAgICAgICAgICAgICAgICAgICAgOAovLyBBc3luYyBDYWxsYmFjayAoZW1wdHkpOiAgICAgICAgICAgICAgIDEKLy8gVG90YWwgbnVtYmVyIG9mIGV4cG9ydGVkIGZ1bmN0aW9uczogIDExCgojIVtub19zdGRdCgptdWx0aXZlcnN4X3NjX3dhc21fYWRhcHRlcjo6YWxsb2NhdG9yISgpOwptdWx0aXZlcnN4X3NjX3dhc21fYWRhcHRlcjo6cGFuaWNfaGFuZGxlciEoKTsKCm11bHRpdmVyc3hfc2Nfd2FzbV9hZGFwdGVyOjplbmRwb2ludHMhIHsKICAgIHJlcXVlc3RzCiAgICAoCiAgICAgICAgaW5pdCA9PiBpbml0CiAgICAgICAgdXBncmFkZSA9PiB1cGdyYWRlCiAgICAgICAgYWRkUmVxdWVzdHMgPT4gYWRkX3JlcXVlc3RzCiAgICAgICAgZ2V0UmVxdWVzdHMgPT4gZ2V0X3JlcXVlc3RzCiAgICAgICAgaXNQYXVzZWQgPT4gZ2V0X2lzX3BhdXNlZAogICAgICAgIGdldFJlcXVlc3RzUGVyRWdsZCA9PiBnZXRfcmVxdWVzdHNfcGVyX2VnbGQKICAgICAgICBjaGFuZ2VOdW1SZXF1ZXN0c1BlckVHTEQgPT4gY2hhbmdlX251bV9yZXF1ZXN0c19wZXJfZWdsZAogICAgICAgIHBhdXNlID0+IHBhdXNlCiAgICAgICAgdW5wYXVzZSA9PiB1bnBhdXNlCiAgICAgICAgd2l0aGRyYXdBbGwgPT4gd2l0aGRyYXdfYWxsCiAgICApCn0KCm11bHRpdmVyc3hfc2Nfd2FzbV9hZGFwdGVyOjphc3luY19jYWxsYmFja19lbXB0eSEge30K",
- "module": ".",
- "dependencyDepth": 0,
- "isTestFile": false
- }
- ]
-}
\ No newline at end of file
diff --git a/requests-contract/output/requests/requests.abi.json b/requests-contract/output/requests/requests.abi.json
deleted file mode 100644
index 2944ba8..0000000
--- a/requests-contract/output/requests/requests.abi.json
+++ /dev/null
@@ -1,230 +0,0 @@
-{
- "buildInfo": {
- "rustc": {
- "version": "1.86.0",
- "commitHash": "05f9846f893b09a1be1fc8560e33fc3c815cfecb",
- "commitDate": "2025-03-31",
- "channel": "Stable",
- "short": "rustc 1.86.0 (05f9846f8 2025-03-31)"
- },
- "contractCrate": {
- "name": "requests",
- "version": "0.0.0"
- },
- "framework": {
- "name": "multiversx-sc",
- "version": "0.57.1"
- }
- },
- "name": "RequestsContract",
- "constructor": {
- "docs": [
- "Constructor - initializes the contract with the number of requests per EGLD"
- ],
- "inputs": [
- {
- "name": "num_requests_per_egld",
- "type": "BigUint"
- }
- ],
- "outputs": []
- },
- "upgradeConstructor": {
- "docs": [
- "Upgrade function - called when contract is upgraded"
- ],
- "inputs": [
- {
- "name": "num_requests_per_egld",
- "type": "BigUint"
- }
- ],
- "outputs": []
- },
- "endpoints": [
- {
- "docs": [
- "Add acquired requests for a given ID - payable only in EGLD",
- "The number of acquired requests added = (EGLD amount transferred in regular units) * num_requests_per_egld",
- "Example: 2.5 EGLD * 100 rate = 250 acquired requests"
- ],
- "name": "addRequests",
- "mutability": "mutable",
- "payableInTokens": [
- "EGLD"
- ],
- "inputs": [
- {
- "name": "id",
- "type": "u64"
- }
- ],
- "outputs": []
- },
- {
- "docs": [
- "Get the number of acquired requests for a given ID",
- "Returns 0 if the ID was not credited"
- ],
- "name": "getRequests",
- "mutability": "readonly",
- "inputs": [
- {
- "name": "id",
- "type": "u64"
- }
- ],
- "outputs": [
- {
- "type": "BigUint"
- }
- ]
- },
- {
- "docs": [
- "Check if the contract is paused"
- ],
- "name": "isPaused",
- "mutability": "readonly",
- "inputs": [],
- "outputs": [
- {
- "type": "bool"
- }
- ]
- },
- {
- "docs": [
- "Get the number of requests per EGLD"
- ],
- "name": "getRequestsPerEgld",
- "mutability": "readonly",
- "inputs": [],
- "outputs": [
- {
- "type": "BigUint"
- }
- ]
- },
- {
- "docs": [
- "Change the number of requests per EGLD",
- "Can only be called by the owner"
- ],
- "name": "changeNumRequestsPerEGLD",
- "mutability": "mutable",
- "inputs": [
- {
- "name": "new_num_requests_per_egld",
- "type": "BigUint"
- }
- ],
- "outputs": []
- },
- {
- "docs": [
- "Pause the contract - prevents new requests from being added",
- "Can only be called by the owner"
- ],
- "name": "pause",
- "mutability": "mutable",
- "inputs": [],
- "outputs": []
- },
- {
- "docs": [
- "Unpause the contract - allows new requests to be added again",
- "Can only be called by the owner"
- ],
- "name": "unpause",
- "mutability": "mutable",
- "inputs": [],
- "outputs": []
- },
- {
- "docs": [
- "Withdraw all available EGLD in the contract to the owner's address",
- "Can only be called by the owner"
- ],
- "name": "withdrawAll",
- "mutability": "mutable",
- "inputs": [],
- "outputs": []
- }
- ],
- "events": [
- {
- "docs": [
- "Event emitted when requests are added"
- ],
- "identifier": "addRequests",
- "inputs": [
- {
- "name": "id",
- "type": "u64",
- "indexed": true
- },
- {
- "name": "egld_amount",
- "type": "BigUint",
- "indexed": true
- },
- {
- "name": "requests_added",
- "type": "BigUint"
- }
- ]
- },
- {
- "docs": [
- "Event emitted when the exchange rate is changed"
- ],
- "identifier": "changeNumRequestsPerEGLD",
- "inputs": [
- {
- "name": "old_value",
- "type": "BigUint",
- "indexed": true
- },
- {
- "name": "new_value",
- "type": "BigUint"
- }
- ]
- },
- {
- "docs": [
- "Event emitted when the contract is paused"
- ],
- "identifier": "pause",
- "inputs": []
- },
- {
- "docs": [
- "Event emitted when the contract is unpaused"
- ],
- "identifier": "unpause",
- "inputs": []
- },
- {
- "docs": [
- "Event emitted when EGLD is withdrawn"
- ],
- "identifier": "withdraw",
- "inputs": [
- {
- "name": "recipient",
- "type": "Address",
- "indexed": true
- },
- {
- "name": "amount",
- "type": "BigUint"
- }
- ]
- }
- ],
- "esdtAttributes": [],
- "hasCallback": false,
- "types": {}
-}
diff --git a/requests-contract/output/requests/requests.codehash.txt b/requests-contract/output/requests/requests.codehash.txt
deleted file mode 100644
index 8a5cfdb..0000000
--- a/requests-contract/output/requests/requests.codehash.txt
+++ /dev/null
@@ -1 +0,0 @@
-1e8c9ef47f3f3f00b58b48075411edab699126c8ee9ff69f53827dfcf2eecf0a
\ No newline at end of file
diff --git a/requests-contract/output/requests/requests.imports.json b/requests-contract/output/requests/requests.imports.json
deleted file mode 100644
index 3bee223..0000000
--- a/requests-contract/output/requests/requests.imports.json
+++ /dev/null
@@ -1,36 +0,0 @@
-[
- "bigIntAdd",
- "bigIntFinishUnsigned",
- "bigIntGetCallValue",
- "bigIntGetESDTExternalBalance",
- "bigIntGetExternalBalance",
- "bigIntGetUnsignedArgument",
- "bigIntMul",
- "bigIntSetInt64",
- "bigIntSign",
- "bigIntTDiv",
- "checkNoPayment",
- "getNumArguments",
- "mBufferAppend",
- "mBufferAppendBytes",
- "mBufferEq",
- "mBufferFromBigIntUnsigned",
- "mBufferGetByteSlice",
- "mBufferGetBytes",
- "mBufferGetLength",
- "mBufferNew",
- "mBufferSetBytes",
- "mBufferStorageLoad",
- "mBufferStorageStore",
- "mBufferToBigIntUnsigned",
- "managedCaller",
- "managedGetMultiESDTCallValue",
- "managedOwnerAddress",
- "managedSCAddress",
- "managedSignalError",
- "managedTransferValueExecute",
- "managedWriteLog",
- "signalError",
- "smallIntFinishSigned",
- "smallIntGetUnsignedArgument"
-]
\ No newline at end of file
diff --git a/requests-contract/output/requests/requests.mxsc.json b/requests-contract/output/requests/requests.mxsc.json
deleted file mode 100644
index 77a95f9..0000000
--- a/requests-contract/output/requests/requests.mxsc.json
+++ /dev/null
@@ -1,282 +0,0 @@
-{
- "buildInfo": {
- "rustc": {
- "version": "1.86.0",
- "commitHash": "05f9846f893b09a1be1fc8560e33fc3c815cfecb",
- "commitDate": "2025-03-31",
- "channel": "Stable",
- "short": "rustc 1.86.0 (05f9846f8 2025-03-31)"
- },
- "contractCrate": {
- "name": "requests",
- "version": "0.0.0"
- },
- "framework": {
- "name": "multiversx-sc",
- "version": "0.57.1"
- }
- },
- "abi": {
- "name": "RequestsContract",
- "constructor": {
- "docs": [
- "Constructor - initializes the contract with the number of requests per EGLD"
- ],
- "inputs": [
- {
- "name": "num_requests_per_egld",
- "type": "BigUint"
- }
- ],
- "outputs": []
- },
- "upgradeConstructor": {
- "docs": [
- "Upgrade function - called when contract is upgraded"
- ],
- "inputs": [
- {
- "name": "num_requests_per_egld",
- "type": "BigUint"
- }
- ],
- "outputs": []
- },
- "endpoints": [
- {
- "docs": [
- "Add acquired requests for a given ID - payable only in EGLD",
- "The number of acquired requests added = (EGLD amount transferred in regular units) * num_requests_per_egld",
- "Example: 2.5 EGLD * 100 rate = 250 acquired requests"
- ],
- "name": "addRequests",
- "mutability": "mutable",
- "payableInTokens": [
- "EGLD"
- ],
- "inputs": [
- {
- "name": "id",
- "type": "u64"
- }
- ],
- "outputs": []
- },
- {
- "docs": [
- "Get the number of acquired requests for a given ID",
- "Returns 0 if the ID was not credited"
- ],
- "name": "getRequests",
- "mutability": "readonly",
- "inputs": [
- {
- "name": "id",
- "type": "u64"
- }
- ],
- "outputs": [
- {
- "type": "BigUint"
- }
- ]
- },
- {
- "docs": [
- "Check if the contract is paused"
- ],
- "name": "isPaused",
- "mutability": "readonly",
- "inputs": [],
- "outputs": [
- {
- "type": "bool"
- }
- ]
- },
- {
- "docs": [
- "Get the number of requests per EGLD"
- ],
- "name": "getRequestsPerEgld",
- "mutability": "readonly",
- "inputs": [],
- "outputs": [
- {
- "type": "BigUint"
- }
- ]
- },
- {
- "docs": [
- "Change the number of requests per EGLD",
- "Can only be called by the owner"
- ],
- "name": "changeNumRequestsPerEGLD",
- "mutability": "mutable",
- "inputs": [
- {
- "name": "new_num_requests_per_egld",
- "type": "BigUint"
- }
- ],
- "outputs": []
- },
- {
- "docs": [
- "Pause the contract - prevents new requests from being added",
- "Can only be called by the owner"
- ],
- "name": "pause",
- "mutability": "mutable",
- "inputs": [],
- "outputs": []
- },
- {
- "docs": [
- "Unpause the contract - allows new requests to be added again",
- "Can only be called by the owner"
- ],
- "name": "unpause",
- "mutability": "mutable",
- "inputs": [],
- "outputs": []
- },
- {
- "docs": [
- "Withdraw all available EGLD in the contract to the owner's address",
- "Can only be called by the owner"
- ],
- "name": "withdrawAll",
- "mutability": "mutable",
- "inputs": [],
- "outputs": []
- }
- ],
- "events": [
- {
- "docs": [
- "Event emitted when requests are added"
- ],
- "identifier": "addRequests",
- "inputs": [
- {
- "name": "id",
- "type": "u64",
- "indexed": true
- },
- {
- "name": "egld_amount",
- "type": "BigUint",
- "indexed": true
- },
- {
- "name": "requests_added",
- "type": "BigUint"
- }
- ]
- },
- {
- "docs": [
- "Event emitted when the exchange rate is changed"
- ],
- "identifier": "changeNumRequestsPerEGLD",
- "inputs": [
- {
- "name": "old_value",
- "type": "BigUint",
- "indexed": true
- },
- {
- "name": "new_value",
- "type": "BigUint"
- }
- ]
- },
- {
- "docs": [
- "Event emitted when the contract is paused"
- ],
- "identifier": "pause",
- "inputs": []
- },
- {
- "docs": [
- "Event emitted when the contract is unpaused"
- ],
- "identifier": "unpause",
- "inputs": []
- },
- {
- "docs": [
- "Event emitted when EGLD is withdrawn"
- ],
- "identifier": "withdraw",
- "inputs": [
- {
- "name": "recipient",
- "type": "Address",
- "indexed": true
- },
- {
- "name": "amount",
- "type": "BigUint"
- }
- ]
- }
- ],
- "esdtAttributes": [],
- "hasCallback": false,
- "types": {}
- },
- "code": "0061736d01000000015c1060000060017f017f6000017f60027f7f017f60027f7f0060017f0060037f7f7f0060037f7f7f017f60027f7e0060017f017e60047f7f7f7f017f60017e0060057f7f7f7e7f0060057f7f7e7f7f017f60047f7e7f7f0060017e017f02bd062203656e760e626967496e74536574496e743634000803656e7609626967496e74416464000603656e760b7369676e616c4572726f72000403656e760d6d616e6167656443616c6c6572000503656e76106d616e61676564534341646472657373000503656e76136d616e616765644f776e657241646472657373000503656e761c6d616e616765644765744d756c74694553445443616c6c56616c7565000503656e76106d4275666665724765744c656e677468000103656e7612626967496e7447657443616c6c56616c7565000503656e761b736d616c6c496e74476574556e7369676e6564417267756d656e74000903656e7619626967496e74476574556e7369676e6564417267756d656e74000403656e760f6765744e756d417267756d656e7473000203656e76136d42756666657247657442797465536c696365000a03656e760f6d4275666665725365744279746573000703656e76126d427566666572417070656e644279746573000703656e76196d42756666657246726f6d426967496e74556e7369676e6564000303656e76126d42756666657253746f726167654c6f6164000303656e76136d42756666657253746f7261676553746f7265000303656e76176d427566666572546f426967496e74556e7369676e6564000303656e760d6d427566666572417070656e64000303656e76126d616e616765645369676e616c4572726f72000503656e760a626967496e745369676e000103656e760e636865636b4e6f5061796d656e74000003656e7609626967496e744d756c000603656e760a626967496e7454446976000603656e760f6d616e6167656457726974654c6f67000403656e7614626967496e7446696e697368556e7369676e6564000503656e7614736d616c6c496e7446696e6973685369676e6564000b03656e760f6d4275666665724765744279746573000303656e761c626967496e744765744553445445787465726e616c42616c616e6365000c03656e7618626967496e7447657445787465726e616c42616c616e6365000403656e761b6d616e616765645472616e7366657256616c756545786563757465000d03656e760a6d4275666665724e6577000203656e76096d42756666657245710003032b2a0102040202020107010205030204030101040e040106010104030f02020100000000000000000000050005030100030616037f01418080080b7f0041a185080b7f0041b085080b07b8010e066d656d6f7279020004696e69740040077570677261646500410b616464526571756573747300420b67657452657175657374730043086973506175736564004412676574526571756573747350657245676c640045186368616e67654e756d526571756573747350657245474c440046057061757365004707756e706175736500480b7769746864726177416c6c00490863616c6c4261636b004b0a5f5f646174615f656e6403010b5f5f686561705f6261736503020a8a112a1601017f1023220142001000200120012000100120010b1901017f41dc840841dc840828020041016b220036020020000b0900200020011002000b0c01017f10232200100320000b0c01017f10232200100520000bd90101037f230041106b2200240041021028450440415a10060b02400240027f024002400240415a10074104760e020102000b41a58008411d1002000b415d410110280d011a415d1008415d0c010b200041086a420037030020004200370300415a2000411010290d01200028020c21012000280200220241187420024180fe03714108747220024108764180fe037120024118767272102a450d02200141187420014180fe03714108747220014108764180fe0371200141187672720b200041106a24000f0b41ec8008411d1002000b4180800841251002000b2b01027f200041e084082d0000220171200041ff017146220245044041e0840820002001723a00000b20020b0f002000410020022001100c4100470b1300415841898108410b100d1a4158200010300b0e01017f410010232200100a20000b1400100b20004604400f0b41c5800841191002000b1101017f1023220220002001100d1a20020b080041014100102d0b4601017f230041106b220224002002200141187420014180fe03714108747220014108764180fe03712001411876727236020c20002002410c6a4104100e1a200241106a24000b0b0020002001102141004a0b0f01017f102322012000100f1a20010b0d0020001023220010101a20000b3a01017f230041106b220224002002420037030820022001ad4101200241086a1034200020022802002002280204102d10111a200241106a24000baa0202047f027e2003200142388620014280fe0383422886842001428080fc0783421886200142808080f80f834208868484200142088842808080f80f832001421888428080fc07838420014238882208200142288822094280fe0383848484370000200041084100200142005322072002716b41ff017122042008a746220520042001423088a741ff01714671220620056a2006410020042009a741ff0171461b22056a2005410020042001422088a741ff0171461b22056a2005410020042001a72205411876461b22066a200641002004200541107641ff0171461b22066a200641002004200541087641ff0171461b22046a200441002001501b6a22042007200320044107716a2c0000410048732004410047712002716b22026b3602042000200220036a3602000b0b0020002001103110111a0bc80102017e037f230041106b22022400200242003703082000103222041007220341094904402004200220036b41106a200310291a027f02402002290308220142388620014280fe0383422886842001428080fc0783421886200142808080f80f834208868484200142088842808080f80f832001421888428080fc07838420014228884280fe038320014238888484220184420158044041002001a741016b0d021a0c010b200041af810841121037000b41010b200241106a24000f0b200041de8008410e1037000b2c01017f41948108411b102d2203200010131a200341c280084103100e1a200320012002100e1a20031014000b0f00200010321023220010121a20000b0900102e1a200010310b0d00102e1a200020011031102f0b1201017f102e220220002001102d102f20020b840101027f230041106b2201240041d581084110102d21022001200042388620004280fe0383422886842000428080fc0783421886200042808080f80f834208868484200042088842808080f80f832000421888428080fc07838420004228884280fe038320004238888484843703082002200141086a4108100e1a200141106a240020020b0a0041f081084112102d0b0a00419a82084108102d0b09002000101541004a0b2901017f10164101102c102b2200103f45044041b28308412c1024000b103d20001035103e410010330b3801017f10164101102c102b2200103f0440103d20001035103e416710101a41671007450440103e410010330b0f0b41b28308412c1024000bd30102057f017e230041106b2201240010271a4101102c4100100921050240103e1036450440102710222204103f450d011023220042808090bbbad6adf00d1000103d1038210220041022220320032002101720032003200010182005103c220210382200200020031022100120022000103541e58108410b103b2100102e210220014200370308200120054100200141086a1034200220012802002001280204100d1a20002002102f20002004103a2000200310391019200141106a24000f0b41c7820841121024000b41a2820841251024000b120010164101102c41001009103c1038101a0b0f0010164100102c103e1036ad101b0b0e0010164100102c103d1038101a0b5801037f10164101102c102b2100024010251026103004402000103f450d01103d10382101103d200010221035418282084118103b22022001103a20022000103910190f0b41878308412b1024000b41b28308412c1024000b3f0010164100102c02401025102610300440103e10360d01103e4101103341c181084105103b102e10190f0b41de830841251024000b41838408411a1024000b400010164100102c02401025102610300440103e1036450d01103e4100103341c681084107103b102e10190f0b419d840841271024000b41c4840841161024000bb90101057f10164100102c02401025102622041030044041898108410b102d2201102a21031023220010042000210210232100024020034504402001100721032002104a200141818508101c1a41e1840841818508200342002000101d0c010b2002104a41e184082000101e0b2000103f450d01200420004200102e102e101f1a41cd81084108103b2101102e1a10202202200410131a20012002102f20012000103910190f0b41d98208411b1024000b41f4820841131024000b0b00200041e18408101c1a0b02000b0bee040200418080080bda0466756e6374696f6e20646f6573206e6f74206163636570742045534454207061796d656e74696e636f7272656374206e756d626572206f66207472616e7366657273293a2077726f6e67206e756d626572206f6620617267756d656e7473696e70757420746f6f206c6f6e674d616e6167656456656320696e646578206f7574206f662072616e676545474c442d30303030303073746f72616765206465636f6465206572726f7220286b65793a20696e707574206f7574206f662072616e67657061757365756e706175736577697468647261776163717569726564526571756573747361646452657175657374736e756d526571756573747350657245676c646368616e67654e756d526571756573747350657245474c4469735061757365645061796d656e7420616d6f756e74206d7573742062652067726561746572207468616e2030436f6e7472616374206973207061757365644f6e6c7920746865206f776e65722063616e2077697468647261774e6f2045474c4420746f2077697468647261774f6e6c7920746865206f776e65722063616e206368616e6765207468652065786368616e676520726174654e756d626572206f66207265717565737473207065722045474c44206d757374206265206e6f6e2d7a65726f4f6e6c7920746865206f776e65722063616e2070617573652074686520636f6e7472616374436f6e747261637420697320616c7265616479207061757365644f6e6c7920746865206f776e65722063616e20756e70617573652074686520636f6e7472616374436f6e7472616374206973206e6f74207061757365640041dc84080b0438ffffff",
- "report": {
- "imports": [
- "bigIntAdd",
- "bigIntFinishUnsigned",
- "bigIntGetCallValue",
- "bigIntGetESDTExternalBalance",
- "bigIntGetExternalBalance",
- "bigIntGetUnsignedArgument",
- "bigIntMul",
- "bigIntSetInt64",
- "bigIntSign",
- "bigIntTDiv",
- "checkNoPayment",
- "getNumArguments",
- "mBufferAppend",
- "mBufferAppendBytes",
- "mBufferEq",
- "mBufferFromBigIntUnsigned",
- "mBufferGetByteSlice",
- "mBufferGetBytes",
- "mBufferGetLength",
- "mBufferNew",
- "mBufferSetBytes",
- "mBufferStorageLoad",
- "mBufferStorageStore",
- "mBufferToBigIntUnsigned",
- "managedCaller",
- "managedGetMultiESDTCallValue",
- "managedOwnerAddress",
- "managedSCAddress",
- "managedSignalError",
- "managedTransferValueExecute",
- "managedWriteLog",
- "signalError",
- "smallIntFinishSigned",
- "smallIntGetUnsignedArgument"
- ],
- "isMemGrow": false,
- "eiCheck": {
- "eiVersion": "1.3",
- "ok": true
- },
- "codeReport": {
- "path": "../output/requests.wasm",
- "size": 4009,
- "hasAllocator": false,
- "hasPanic": "None"
- }
- }
-}
diff --git a/requests-contract/output/requests/requests.wasm b/requests-contract/output/requests/requests.wasm
deleted file mode 100755
index 54ad16c749262061e41df6642d2b50270fdc09a4..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001
literal 4009
zcmbtXO>7)V6|U;;@wD9@yW)hbGtNS}lMv@;^0PmQNp?4`N$hNvY&ODSiB?2TXQnb9
zd#2m&>2YEX9`D8*0w)ffR@wtdC=yZx;>3?QfcU#`LLe!gNXb&7XAj0>mdnS{R
zhyxzEy869(f8Tqr<_!y4P0kqOUl!LHyUshjbDiPe>d+1=(b#pnLpxdxb;F$8xbA>J
z6b?cT+YKDTbHflFdg9;)?^r(_@NFHgjohf$E`-UvPOzSMiMd1^Oo^&mWdro?wd%Dn
zXw1fO6f=h?g=P>2HC;U$G#WZ)IiiV-Hh&g^v2L|e^7f4U)~!&-k8yTqobx()v)xGQ
zv-9V!kixfvMq77vmfJUP>KI2Z>adn9GESz(QU^hO;`~Ib2?YoRtS^S-wyvtU)^6%B
zVS^;Pt0($jd=uGdO(&Py&8|?3StPZ++4G~kp6K~Ty`tF=aYi!^5F}2E<&A?GRjsV(
zu-eDil`-bxs9849cimuizu0N95jLui5Vur@kd9V
zV4FNoWIkSrgRq4PGetLhTUXkNW(86(lp%LX-%5*MFeA*a0>(oJx#d`v#q-?C*_LB-
z?u
zuhin8s+sbFYV`|xwXIu8i#mtM?8evPSR9-!Sd!BzWU_mT_fCO>Q)Eso?Pa5$`diN@kLe09#ZC_+#PocI)Dp0vDC_^X(NNinS0d2c&YSJl_vb(JRyMRgTWAM-{CXod_h
zF$CmxFai5>&J3*o5;k{{&21^rmI1y{gk~2RfmF$x11kmE+G{NRkKj&N!_Z=>;U(pW
z5vVeudS05;NyXmqMpJ8438O`nLIFJEpD4n?Q;!>@bhs4Z1H}pNCGisJN6FCQh?3aW
zGxA-_ayr(Av?VW3-^GFy+$m4p-JuUYM%G=(pp`n40(U-hGp>RewO{mgE3V
zJ903kP57YX4273vcCep#-_M~$<|h1su4GP$HKXq_8p@7}V#0Tpq(lB(o>+nxd4%q$
z{OZzShPrsYMZEK?-w}D=R)ZIu
z8H54hW#m)Z;y{s_Oj-wQ7p?t&gFOY{kt+lH)|St=%KR$I9f94)%}}t4X_I~rr9CE2
zqJ`13X=RO4H+_sk9wGW+6p#8QPEClCk6S}*FG^ee9BiA45rrWwvk^O(=^pWdsk||&
zyg??8;3{2msCC{3bFae)90_Ner*
z?Uo*GAC(^KD?Qd%dJHv}q5)O+sO-`PK`4tw(#+_ffR_B)n5^_Cr(cyNrZS>tK9Szu3EYvK&1-;
zi-U`hsvcQGABs~()#t>n3`B(TYrr-}fT(X{w~uyXEJcl?5U+@7QADkP!~i4$dLSme
zk?uR(2m30%j=D%sGQ_=4d{!Jo&k*Venu5fNS04eq2SelHG%AY2BMJ&0!IiHfH;0TX
zJ$%n(b{?rD51{ci!2F{68KB6C)8dGc{}}Qn0CfjntVPl^^Hh0q$s}I=3JUT)1s_6e
zzj5Ff*zKg&Z;(6+7@QIAqPotF$T)1f%#)TvJe5R;=3m09ao1-U%1ZWO*H8t{4
ztX=Fr0;Utj^?zWuop$t{L#koeqZ{w<4(1G+um0%VY=@Pk9)+?R>6Q$mL~oH
zep^>$J*?{6G6EB-psA*5+A1A0f30+)msMSfs#{yzqSkn4v{o{o`+W}@2&=mO>=-hnpQ(T 0, "Number of requests per EGLD must be non-zero");
- self.num_requests_per_egld().set(num_requests_per_egld);
- self.is_paused().set(false);
- }
-
- /// Upgrade function - called when contract is upgraded
- #[upgrade]
- fn upgrade(&self, num_requests_per_egld: BigUint) {
- require!(num_requests_per_egld > 0, "Number of requests per EGLD must be non-zero");
- self.num_requests_per_egld().set(num_requests_per_egld);
- if !self.is_paused().is_empty() {
- // is_paused already exists, keep current value
- } else {
- // First upgrade, initialize pause state
- self.is_paused().set(false);
- }
- }
-
- /// Add acquired requests for a given ID - payable only in EGLD
- /// The number of acquired requests added = (EGLD amount transferred in regular units) * num_requests_per_egld
- /// Example: 2.5 EGLD * 100 rate = 250 acquired requests
- #[payable("EGLD")]
- #[endpoint(addRequests)]
- fn add_requests(&self, id: u64) {
- require!(!self.is_paused().get(), "Contract is paused");
-
- let payment = self.call_value().egld();
- let amount_wei = payment.clone_value();
-
- require!(amount_wei > 0, "Payment amount must be greater than 0");
-
- // Convert from wei to EGLD (1 EGLD = 10^18 wei)
- let one_egld = BigUint::from(1_000_000_000_000_000_000u64);
-
- let num_requests_per_egld = self.num_requests_per_egld().get();
- let requests_to_add = (amount_wei.clone() * &num_requests_per_egld) / one_egld;
-
- self.acquired_requests(&id).update(|requests| *requests += requests_to_add.clone());
-
- self.add_requests_event(&id, &amount_wei, &requests_to_add);
- }
-
-
- /// Get the number of acquired requests for a given ID
- /// Returns 0 if the ID was not credited
- #[view(getRequests)]
- fn get_requests(&self, id: u64) -> BigUint {
- self.acquired_requests(&id).get()
- }
-
- /// Check if the contract is paused
- #[view(isPaused)]
- fn get_is_paused(&self) -> bool {
- self.is_paused().get()
- }
-
- /// Get the number of requests per EGLD
- #[view(getRequestsPerEgld)]
- fn get_requests_per_egld(&self) -> BigUint {
- self.num_requests_per_egld().get()
- }
-
-
- /// Change the number of requests per EGLD
- /// Can only be called by the owner
- #[endpoint(changeNumRequestsPerEGLD)]
- fn change_num_requests_per_egld(&self, new_num_requests_per_egld: BigUint) {
- let caller = self.blockchain().get_caller();
- let owner = self.blockchain().get_owner_address();
-
- require!(caller == owner, "Only the owner can change the exchange rate");
- require!(new_num_requests_per_egld > 0, "Number of requests per EGLD must be non-zero");
-
- let old_value = self.num_requests_per_egld().get();
- self.num_requests_per_egld().set(new_num_requests_per_egld.clone());
-
- self.change_num_requests_per_egld_event(&old_value, &new_num_requests_per_egld);
- }
-
- /// Pause the contract - prevents new requests from being added
- /// Can only be called by the owner
- #[endpoint(pause)]
- fn pause(&self) {
- let caller = self.blockchain().get_caller();
- let owner = self.blockchain().get_owner_address();
-
- require!(caller == owner, "Only the owner can pause the contract");
- require!(!self.is_paused().get(), "Contract is already paused");
-
- self.is_paused().set(true);
- self.pause_event();
- }
-
- /// Unpause the contract - allows new requests to be added again
- /// Can only be called by the owner
- #[endpoint(unpause)]
- fn unpause(&self) {
- let caller = self.blockchain().get_caller();
- let owner = self.blockchain().get_owner_address();
-
- require!(caller == owner, "Only the owner can unpause the contract");
- require!(self.is_paused().get(), "Contract is not paused");
-
- self.is_paused().set(false);
- self.unpause_event();
- }
-
- /// Withdraw all available EGLD in the contract to the owner's address
- /// Can only be called by the owner
- #[endpoint(withdrawAll)]
- fn withdraw_all(&self) {
- let caller = self.blockchain().get_caller();
- let owner = self.blockchain().get_owner_address();
-
- require!(caller == owner, "Only the owner can withdraw");
-
- let contract_balance = self.blockchain().get_sc_balance(&EgldOrEsdtTokenIdentifier::egld(), 0);
- require!(contract_balance > 0, "No EGLD to withdraw");
-
- self.tx()
- .to(&owner)
- .egld(&contract_balance)
- .transfer();
-
- self.withdraw_event(&owner, &contract_balance);
- }
-
- /// Event emitted when requests are added
- #[event("addRequests")]
- fn add_requests_event(
- &self,
- #[indexed] id: &u64,
- #[indexed] egld_amount: &BigUint,
- requests_added: &BigUint,
- );
-
- /// Event emitted when the exchange rate is changed
- #[event("changeNumRequestsPerEGLD")]
- fn change_num_requests_per_egld_event(
- &self,
- #[indexed] old_value: &BigUint,
- new_value: &BigUint,
- );
-
- /// Event emitted when the contract is paused
- #[event("pause")]
- fn pause_event(&self);
-
- /// Event emitted when the contract is unpaused
- #[event("unpause")]
- fn unpause_event(&self);
-
- /// Event emitted when EGLD is withdrawn
- #[event("withdraw")]
- fn withdraw_event(
- &self,
- #[indexed] recipient: &ManagedAddress,
- amount: &BigUint,
- );
-
- /// Storage mapper for the number of requests per EGLD
- #[storage_mapper("numRequestsPerEgld")]
- fn num_requests_per_egld(&self) -> SingleValueMapper;
-
- /// Storage mapper for acquired requests count per ID
- #[storage_mapper("acquiredRequests")]
- fn acquired_requests(&self, id: &u64) -> SingleValueMapper;
-
- /// Storage mapper for pause state
- #[storage_mapper("isPaused")]
- fn is_paused(&self) -> SingleValueMapper;
-}
diff --git a/requests-contract/tests/scenarios_rs_test.rs b/requests-contract/tests/scenarios_rs_test.rs
deleted file mode 100644
index 23732be..0000000
--- a/requests-contract/tests/scenarios_rs_test.rs
+++ /dev/null
@@ -1,124 +0,0 @@
-use multiversx_sc_scenario::*;
-
-fn world() -> ScenarioWorld {
- let mut blockchain = ScenarioWorld::new();
-
- blockchain.set_current_dir_from_workspace("");
- blockchain.register_contract("mxsc:output/requests.mxsc.json", requests::ContractBuilder);
- blockchain
-}
-
-#[test]
-fn add_requests_accumulation_rs() {
- world().run("scenarios/add_requests_accumulation.scen.json");
-}
-
-#[test]
-fn add_requests_multiple_rs() {
- world().run("scenarios/add_requests_multiple.scen.json");
-}
-
-#[test]
-fn add_requests_single_rs() {
- world().run("scenarios/add_requests_single.scen.json");
-}
-
-#[test]
-fn add_requests_when_paused_rs() {
- world().run("scenarios/add_requests_when_paused.scen.json");
-}
-
-#[test]
-fn change_rate_non_owner_rs() {
- world().run("scenarios/change_rate_non_owner.scen.json");
-}
-
-#[test]
-fn change_rate_valid_rs() {
- world().run("scenarios/change_rate_valid.scen.json");
-}
-
-#[test]
-fn change_rate_zero_rs() {
- world().run("scenarios/change_rate_zero.scen.json");
-}
-
-#[test]
-fn full_workflow_rs() {
- world().run("scenarios/full_workflow.scen.json");
-}
-
-#[test]
-fn get_requests_existing_rs() {
- world().run("scenarios/get_requests_existing.scen.json");
-}
-
-#[test]
-fn get_requests_nonexistent_rs() {
- world().run("scenarios/get_requests_nonexistent.scen.json");
-}
-
-#[test]
-fn init_valid_rs() {
- world().run("scenarios/init_valid.scen.json");
-}
-
-#[test]
-fn init_zero_rs() {
- world().run("scenarios/init_zero.scen.json");
-}
-
-#[test]
-fn pause_already_paused_rs() {
- world().run("scenarios/pause_already_paused.scen.json");
-}
-
-#[test]
-fn pause_non_owner_rs() {
- world().run("scenarios/pause_non_owner.scen.json");
-}
-
-#[test]
-fn pause_success_rs() {
- world().run("scenarios/pause_success.scen.json");
-}
-
-#[test]
-fn pause_unpause_workflow_rs() {
- world().run("scenarios/pause_unpause_workflow.scen.json");
-}
-
-#[test]
-fn rate_change_affects_future_rs() {
- world().run("scenarios/rate_change_affects_future.scen.json");
-}
-
-#[test]
-fn unpause_non_owner_rs() {
- world().run("scenarios/unpause_non_owner.scen.json");
-}
-
-#[test]
-fn unpause_not_paused_rs() {
- world().run("scenarios/unpause_not_paused.scen.json");
-}
-
-#[test]
-fn unpause_success_rs() {
- world().run("scenarios/unpause_success.scen.json");
-}
-
-#[test]
-fn withdraw_empty_rs() {
- world().run("scenarios/withdraw_empty.scen.json");
-}
-
-#[test]
-fn withdraw_non_owner_rs() {
- world().run("scenarios/withdraw_non_owner.scen.json");
-}
-
-#[test]
-fn withdraw_success_rs() {
- world().run("scenarios/withdraw_success.scen.json");
-}
diff --git a/requests-contract/wasm/Cargo.lock b/requests-contract/wasm/Cargo.lock
deleted file mode 100644
index 3ec1460..0000000
--- a/requests-contract/wasm/Cargo.lock
+++ /dev/null
@@ -1,223 +0,0 @@
-# This file is automatically @generated by Cargo.
-# It is not intended for manual editing.
-version = 4
-
-[[package]]
-name = "arrayvec"
-version = "0.7.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50"
-
-[[package]]
-name = "autocfg"
-version = "1.5.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8"
-
-[[package]]
-name = "bitflags"
-version = "2.9.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd"
-
-[[package]]
-name = "endian-type"
-version = "0.1.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c34f04666d835ff5d62e058c3995147c06f42fe86ff053337632bca83e42702d"
-
-[[package]]
-name = "generic-array"
-version = "1.3.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "eaf57c49a95fd1fe24b90b3033bee6dc7e8f1288d51494cb44e627c295e38542"
-dependencies = [
- "rustversion",
- "typenum",
-]
-
-[[package]]
-name = "hex"
-version = "0.4.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
-
-[[package]]
-name = "hex-literal"
-version = "0.4.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46"
-
-[[package]]
-name = "multiversx-chain-core"
-version = "0.14.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "73f1f0526ca094185847776c2c03de97ea082743ee4e6f799860ad67e7d78250"
-dependencies = [
- "bitflags",
- "multiversx-sc-codec",
-]
-
-[[package]]
-name = "multiversx-sc"
-version = "0.57.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "20602d4fc336092faadc03b6b445c4bb5e4dbc4c86fb53726e46eca67070813a"
-dependencies = [
- "bitflags",
- "generic-array",
- "hex-literal",
- "multiversx-chain-core",
- "multiversx-sc-codec",
- "multiversx-sc-derive",
- "num-traits",
- "unwrap-infallible",
-]
-
-[[package]]
-name = "multiversx-sc-codec"
-version = "0.22.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "43e0f24a020adf32faffae1c57475c6b7285a3216d1a36e4a73617639721c2e0"
-dependencies = [
- "arrayvec",
- "bitflags",
- "multiversx-sc-codec-derive",
- "unwrap-infallible",
-]
-
-[[package]]
-name = "multiversx-sc-codec-derive"
-version = "0.22.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7c5f17d5ee23657d5cddc7f4471925b5a49f7e25306f8bba656ea6917acc629d"
-dependencies = [
- "hex",
- "proc-macro2",
- "quote",
- "syn",
-]
-
-[[package]]
-name = "multiversx-sc-derive"
-version = "0.57.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0d44d08d3376c199e8c391cc07752d2822cd289693da5319d7905599501e557f"
-dependencies = [
- "hex",
- "proc-macro2",
- "quote",
- "radix_trie",
- "syn",
-]
-
-[[package]]
-name = "multiversx-sc-wasm-adapter"
-version = "0.57.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ee8253b84600554fbe16ea0a234b009854348dc95ce174ba6eba046dc5918f8f"
-dependencies = [
- "multiversx-sc",
-]
-
-[[package]]
-name = "nibble_vec"
-version = "0.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "77a5d83df9f36fe23f0c3648c6bbb8b0298bb5f1939c8f2704431371f4b84d43"
-dependencies = [
- "smallvec",
-]
-
-[[package]]
-name = "num-traits"
-version = "0.2.19"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
-dependencies = [
- "autocfg",
-]
-
-[[package]]
-name = "proc-macro2"
-version = "1.0.94"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a31971752e70b8b2686d7e46ec17fb38dad4051d94024c88df49b667caea9c84"
-dependencies = [
- "unicode-ident",
-]
-
-[[package]]
-name = "quote"
-version = "1.0.39"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c1f1914ce909e1658d9907913b4b91947430c7d9be598b15a1912935b8c04801"
-dependencies = [
- "proc-macro2",
-]
-
-[[package]]
-name = "radix_trie"
-version = "0.2.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c069c179fcdc6a2fe24d8d18305cf085fdbd4f922c041943e203685d6a1c58fd"
-dependencies = [
- "endian-type",
- "nibble_vec",
-]
-
-[[package]]
-name = "requests"
-version = "0.0.0"
-dependencies = [
- "multiversx-sc",
-]
-
-[[package]]
-name = "requests-wasm"
-version = "0.0.0"
-dependencies = [
- "multiversx-sc-wasm-adapter",
- "requests",
-]
-
-[[package]]
-name = "rustversion"
-version = "1.0.22"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d"
-
-[[package]]
-name = "smallvec"
-version = "1.15.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03"
-
-[[package]]
-name = "syn"
-version = "2.0.100"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b09a44accad81e1ba1cd74a32461ba89dee89095ba17b32f5d03683b1b1fc2a0"
-dependencies = [
- "proc-macro2",
- "quote",
- "unicode-ident",
-]
-
-[[package]]
-name = "typenum"
-version = "1.19.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb"
-
-[[package]]
-name = "unicode-ident"
-version = "1.0.22"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5"
-
-[[package]]
-name = "unwrap-infallible"
-version = "0.1.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "151ac09978d3c2862c4e39b557f4eceee2cc72150bc4cb4f16abf061b6e381fb"
diff --git a/requests-contract/wasm/Cargo.toml b/requests-contract/wasm/Cargo.toml
deleted file mode 100644
index a0d90e1..0000000
--- a/requests-contract/wasm/Cargo.toml
+++ /dev/null
@@ -1,34 +0,0 @@
-# Code generated by the multiversx-sc build system. DO NOT EDIT.
-
-# ##########################################
-# ############## AUTO-GENERATED #############
-# ##########################################
-
-[package]
-name = "requests-wasm"
-version = "0.0.0"
-edition = "2021"
-publish = false
-
-[lib]
-crate-type = ["cdylib"]
-
-[profile.release]
-codegen-units = 1
-opt-level = "z"
-lto = true
-debug = false
-panic = "abort"
-overflow-checks = false
-
-[profile.dev]
-panic = "abort"
-
-[dependencies.requests]
-path = ".."
-
-[dependencies.multiversx-sc-wasm-adapter]
-version = "0.57.1"
-
-[workspace]
-members = ["."]
diff --git a/requests-contract/wasm/src/lib.rs b/requests-contract/wasm/src/lib.rs
deleted file mode 100644
index 19ea33c..0000000
--- a/requests-contract/wasm/src/lib.rs
+++ /dev/null
@@ -1,28 +0,0 @@
-// Code generated by the multiversx-sc build system. DO NOT EDIT.
-
-////////////////////////////////////////////////////
-////////////////// AUTO-GENERATED //////////////////
-////////////////////////////////////////////////////
-
-// Init: 1
-// Upgrade: 1
-// Endpoints: 2
-// Async Callback (empty): 1
-// Total number of exported functions: 5
-
-#![no_std]
-
-multiversx_sc_wasm_adapter::allocator!();
-multiversx_sc_wasm_adapter::panic_handler!();
-
-multiversx_sc_wasm_adapter::endpoints! {
- adder
- (
- init => init
- upgrade => upgrade
- getSum => sum
- add => add
- )
-}
-
-multiversx_sc_wasm_adapter::async_callback_empty! {}
diff --git a/services/crypto-payment/process/accountHandler.go b/services/crypto-payment/process/accountHandler.go
index 7bf8894..abd1807 100644
--- a/services/crypto-payment/process/accountHandler.go
+++ b/services/crypto-payment/process/accountHandler.go
@@ -34,12 +34,12 @@ func (ah *accountHandler) GetAccount(ctx context.Context, id uint64) (string, ui
return "", 0, err
}
- requests, err := ah.contractHandler.GetRequests(ctx, id)
+ credits, err := ah.contractHandler.GetCredits(ctx, id)
if err != nil {
return "", 0, err
}
- return entry.Address, requests, nil
+ return entry.Address, credits, nil
}
// IsInterfaceNil returns true if the value under the interface is nil
diff --git a/services/crypto-payment/process/accountHandler_test.go b/services/crypto-payment/process/accountHandler_test.go
index e2b7f10..f2ec797 100644
--- a/services/crypto-payment/process/accountHandler_test.go
+++ b/services/crypto-payment/process/accountHandler_test.go
@@ -44,15 +44,15 @@ func TestAccountHandler_GetAccount(t *testing.T) {
expectedID := uint64(123)
expectedAddress := "erd1test"
- expectedRequests := uint64(50)
+ expectedCredits := uint64(50)
t.Run("success", func(t *testing.T) {
t.Parallel()
contractStub := &testsCommon.ContractHandlerStub{
- GetRequestsHandler: func(ctx context.Context, id uint64) (uint64, error) {
+ GetCreditsHandler: func(ctx context.Context, id uint64) (uint64, error) {
require.Equal(t, expectedID, id)
- return expectedRequests, nil
+ return expectedCredits, nil
},
}
@@ -67,10 +67,10 @@ func TestAccountHandler_GetAccount(t *testing.T) {
}
ah, _ := NewAccountHandler(contractStub, dataStub)
- address, requests, err := ah.GetAccount(context.Background(), expectedID)
+ address, credits, err := ah.GetAccount(context.Background(), expectedID)
require.NoError(t, err)
require.Equal(t, expectedAddress, address)
- require.Equal(t, expectedRequests, requests)
+ require.Equal(t, expectedCredits, credits)
})
t.Run("data provider error", func(t *testing.T) {
@@ -85,10 +85,10 @@ func TestAccountHandler_GetAccount(t *testing.T) {
contractStub := &testsCommon.ContractHandlerStub{}
ah, _ := NewAccountHandler(contractStub, dataStub)
- address, requests, err := ah.GetAccount(context.Background(), expectedID)
+ address, credits, err := ah.GetAccount(context.Background(), expectedID)
require.Equal(t, expectedErr, err)
require.Empty(t, address)
- require.Zero(t, requests)
+ require.Zero(t, credits)
})
t.Run("contract handler error", func(t *testing.T) {
@@ -101,15 +101,15 @@ func TestAccountHandler_GetAccount(t *testing.T) {
},
}
contractStub := &testsCommon.ContractHandlerStub{
- GetRequestsHandler: func(ctx context.Context, id uint64) (uint64, error) {
+ GetCreditsHandler: func(ctx context.Context, id uint64) (uint64, error) {
return 0, expectedErr
},
}
ah, _ := NewAccountHandler(contractStub, dataStub)
- address, requests, err := ah.GetAccount(context.Background(), expectedID)
+ address, credits, err := ah.GetAccount(context.Background(), expectedID)
require.Equal(t, expectedErr, err)
require.Empty(t, address)
- require.Zero(t, requests)
+ require.Zero(t, credits)
})
}
diff --git a/services/crypto-payment/process/configHandler.go b/services/crypto-payment/process/configHandler.go
index 488a9ea..7ec47ba 100644
--- a/services/crypto-payment/process/configHandler.go
+++ b/services/crypto-payment/process/configHandler.go
@@ -40,7 +40,7 @@ func (ch *configHandler) GetConfig(ctx context.Context) (map[string]interface{},
return nil, err
}
- requestsPerEgld, err := ch.contractHandler.GetRequestsPerEGLD(ctx)
+ creditsPerEgld, err := ch.contractHandler.GetCreditsPerEGLD(ctx)
if err != nil {
return nil, err
}
@@ -49,7 +49,7 @@ func (ch *configHandler) GetConfig(ctx context.Context) (map[string]interface{},
"isContractPaused": isPaused,
"walletURL": ch.walletURL,
"explorerURL": ch.explorerURL,
- "requestsPerEGLD": requestsPerEgld,
+ "creditsPerEGLD": creditsPerEgld,
"minimumBalance": ch.minimumBalance,
}, nil
}
diff --git a/services/crypto-payment/process/configHandler_test.go b/services/crypto-payment/process/configHandler_test.go
index 65cdd9c..454155d 100644
--- a/services/crypto-payment/process/configHandler_test.go
+++ b/services/crypto-payment/process/configHandler_test.go
@@ -61,7 +61,7 @@ func TestConfigHandler_GetConfig(t *testing.T) {
IsContractPausedHandler: func(ctx context.Context) (bool, error) {
return false, nil
},
- GetRequestsPerEGLDHandler: func(ctx context.Context) (uint64, error) {
+ GetCreditsPerEGLDHandler: func(ctx context.Context) (uint64, error) {
return 0, expectedErr
},
}
@@ -81,7 +81,7 @@ func TestConfigHandler_GetConfig(t *testing.T) {
IsContractPausedHandler: func(ctx context.Context) (bool, error) {
return true, nil
},
- GetRequestsPerEGLDHandler: func(ctx context.Context) (uint64, error) {
+ GetCreditsPerEGLDHandler: func(ctx context.Context) (uint64, error) {
return expectedRate, nil
},
}
@@ -93,7 +93,7 @@ func TestConfigHandler_GetConfig(t *testing.T) {
require.NotNil(t, config)
assert.True(t, config["isContractPaused"].(bool))
- assert.Equal(t, expectedRate, config["requestsPerEGLD"])
+ assert.Equal(t, expectedRate, config["creditsPerEGLD"])
assert.Equal(t, expectedWallet, config["walletURL"])
assert.Equal(t, expectedExplorer, config["explorerURL"])
assert.Equal(t, expectedMinBalance, config["minimumBalance"])
diff --git a/services/crypto-payment/process/contractQueryHandler.go b/services/crypto-payment/process/contractQueryHandler.go
index 72680c6..e884373 100644
--- a/services/crypto-payment/process/contractQueryHandler.go
+++ b/services/crypto-payment/process/contractQueryHandler.go
@@ -10,11 +10,11 @@ import (
)
const (
- isPausedFunc = "isPaused"
- requestsPerEgldFunc = "getRequestsPerEgld"
+ isPausedFunc = "isPaused"
+ creditsPerEgldFunc = "getCreditsPerEgld"
- keyIsPaused = "isPaused"
- keyRequestsPerEgld = "requestsPerEgld"
+ keyIsPaused = "isPaused"
+ keyCreditsPerEgld = "creditsPerEgld"
contractNotFoundStatus = "contract not found"
)
@@ -82,16 +82,16 @@ func (cqh *contractQueryHandler) IsContractPaused(ctx context.Context) (bool, er
return isPaused, nil
}
-// GetRequestsPerEGLD returns the number of requests per EGLD
-func (cqh *contractQueryHandler) GetRequestsPerEGLD(ctx context.Context) (uint64, error) {
- requestsPerEgldCachedValue, found := cqh.cacher.Get(keyRequestsPerEgld)
+// GetCreditsPerEGLD returns the number of credits per EGLD
+func (cqh *contractQueryHandler) GetCreditsPerEGLD(ctx context.Context) (uint64, error) {
+ creditsPerEgldCachedValue, found := cqh.cacher.Get(keyCreditsPerEgld)
if found {
- return requestsPerEgldCachedValue.(uint64), nil
+ return creditsPerEgldCachedValue.(uint64), nil
}
res, err := cqh.blockchainDataProvider.ExecuteVMQuery(ctx, &data.VmValueRequest{
Address: cqh.contractBech32Address,
- FuncName: requestsPerEgldFunc,
+ FuncName: creditsPerEgldFunc,
CallValue: "0",
CallerAddr: cqh.contractBech32Address,
})
@@ -99,14 +99,14 @@ func (cqh *contractQueryHandler) GetRequestsPerEGLD(ctx context.Context) (uint64
return 0, err
}
- requestsPerEgld, err := vmValueToUint64Decoder(res.Data.ReturnData)
+ creditsPerEgld, err := vmValueToUint64Decoder(res.Data.ReturnData)
if err != nil {
return 0, err
}
- cqh.cacher.Set(keyRequestsPerEgld, requestsPerEgld)
+ cqh.cacher.Set(keyCreditsPerEgld, creditsPerEgld)
- return requestsPerEgld, nil
+ return creditsPerEgld, nil
}
func vmValueToUint64Decoder(buff [][]byte) (uint64, error) {
@@ -123,11 +123,11 @@ func vmValueToUint64Decoder(buff [][]byte) (uint64, error) {
return val.Uint64(), nil
}
-// GetRequests returns the number of requests for a specific ID
-func (cqh *contractQueryHandler) GetRequests(ctx context.Context, id uint64) (uint64, error) {
+// GetCredits returns the number of credits for a specific ID
+func (cqh *contractQueryHandler) GetCredits(ctx context.Context, id uint64) (uint64, error) {
res, err := cqh.blockchainDataProvider.ExecuteVMQuery(ctx, &data.VmValueRequest{
Address: cqh.contractBech32Address,
- FuncName: "getRequests",
+ FuncName: "getCredits",
Args: []string{ensureEvenHex(fmt.Sprintf("%x", id))}, // hex encoded id
CallValue: "0",
CallerAddr: cqh.contractBech32Address,
diff --git a/services/crypto-payment/process/contractQueryHandler_test.go b/services/crypto-payment/process/contractQueryHandler_test.go
index 9ae4293..85e38a5 100644
--- a/services/crypto-payment/process/contractQueryHandler_test.go
+++ b/services/crypto-payment/process/contractQueryHandler_test.go
@@ -208,7 +208,7 @@ func TestContractQueryHandler_IsContractPaused(t *testing.T) {
})
}
-func TestContractQueryHandler_GetRequestsPerEGLD(t *testing.T) {
+func TestContractQueryHandler_GetCreditsPerEGLD(t *testing.T) {
t.Parallel()
t.Run("proxy error", func(t *testing.T) {
@@ -222,7 +222,7 @@ func TestContractQueryHandler_GetRequestsPerEGLD(t *testing.T) {
}
handler, _ := NewContractQueryHandler(proxy, "erd1test", &testsCommon.CacherStub{})
- val, err := handler.GetRequestsPerEGLD(context.Background())
+ val, err := handler.GetCreditsPerEGLD(context.Background())
require.Equal(t, uint64(0), val)
require.Equal(t, expectedErr, err)
})
@@ -239,7 +239,7 @@ func TestContractQueryHandler_GetRequestsPerEGLD(t *testing.T) {
}
handler, _ := NewContractQueryHandler(proxy, "erd1test", &testsCommon.CacherStub{})
- val, err := handler.GetRequestsPerEGLD(context.Background())
+ val, err := handler.GetCreditsPerEGLD(context.Background())
require.NoError(t, err)
require.Equal(t, uint64(0), val)
})
@@ -249,7 +249,7 @@ func TestContractQueryHandler_GetRequestsPerEGLD(t *testing.T) {
proxy := &testsCommon.BlockchainDataProviderStub{
ExecuteVMQueryHandler: func(ctx context.Context, vmRequest *data.VmValueRequest) (*data.VmValuesResponseData, error) {
- assert.Equal(t, "getRequestsPerEgld", vmRequest.FuncName)
+ assert.Equal(t, "getCreditsPerEgld", vmRequest.FuncName)
return &data.VmValuesResponseData{
Data: &vm.VMOutputApi{ReturnData: [][]byte{{10}}},
}, nil
@@ -257,7 +257,7 @@ func TestContractQueryHandler_GetRequestsPerEGLD(t *testing.T) {
}
handler, _ := NewContractQueryHandler(proxy, "erd1test", &testsCommon.CacherStub{})
- val, err := handler.GetRequestsPerEGLD(context.Background())
+ val, err := handler.GetCreditsPerEGLD(context.Background())
require.NoError(t, err)
require.Equal(t, uint64(10), val)
})
@@ -277,14 +277,14 @@ func TestContractQueryHandler_GetRequestsPerEGLD(t *testing.T) {
}
handler, _ := NewContractQueryHandler(proxy, "erd1test", &testsCommon.CacherStub{})
- val, err := handler.GetRequestsPerEGLD(context.Background())
+ val, err := handler.GetCreditsPerEGLD(context.Background())
require.Error(t, err)
require.True(t, strings.Contains(err.Error(), "is not a uint64"))
require.Equal(t, uint64(0), val)
})
}
-func TestContractQueryHandler_GetRequests(t *testing.T) {
+func TestContractQueryHandler_GetCredits(t *testing.T) {
t.Parallel()
t.Run("proxy error", func(t *testing.T) {
@@ -298,7 +298,7 @@ func TestContractQueryHandler_GetRequests(t *testing.T) {
}
handler, _ := NewContractQueryHandler(proxy, "erd1test", &testsCommon.CacherStub{})
- val, err := handler.GetRequests(context.Background(), 1)
+ val, err := handler.GetCredits(context.Background(), 1)
require.Equal(t, uint64(0), val)
require.Equal(t, expectedErr, err)
})
@@ -315,7 +315,7 @@ func TestContractQueryHandler_GetRequests(t *testing.T) {
}
handler, _ := NewContractQueryHandler(proxy, "erd1test", &testsCommon.CacherStub{})
- val, err := handler.GetRequests(context.Background(), 1)
+ val, err := handler.GetCredits(context.Background(), 1)
require.NoError(t, err)
require.Equal(t, uint64(0), val)
})
@@ -326,7 +326,7 @@ func TestContractQueryHandler_GetRequests(t *testing.T) {
id := uint64(123)
proxy := &testsCommon.BlockchainDataProviderStub{
ExecuteVMQueryHandler: func(ctx context.Context, vmRequest *data.VmValueRequest) (*data.VmValuesResponseData, error) {
- assert.Equal(t, "getRequests", vmRequest.FuncName)
+ assert.Equal(t, "getCredits", vmRequest.FuncName)
assert.Equal(t, "7b", vmRequest.Args[0]) // 123 in hex
return &data.VmValuesResponseData{
Data: &vm.VMOutputApi{ReturnData: [][]byte{{10}}},
@@ -335,7 +335,7 @@ func TestContractQueryHandler_GetRequests(t *testing.T) {
}
handler, _ := NewContractQueryHandler(proxy, "erd1test", &testsCommon.CacherStub{})
- val, err := handler.GetRequests(context.Background(), id)
+ val, err := handler.GetCredits(context.Background(), id)
require.NoError(t, err)
require.Equal(t, uint64(10), val)
})
@@ -353,7 +353,7 @@ func TestContractQueryHandler_GetRequests(t *testing.T) {
}
handler, _ := NewContractQueryHandler(proxy, "erd1test", &testsCommon.CacherStub{})
- val, err := handler.GetRequests(context.Background(), 1)
+ val, err := handler.GetCredits(context.Background(), 1)
require.Error(t, err)
require.True(t, strings.Contains(err.Error(), "is not a uint64"))
require.Equal(t, uint64(0), val)
diff --git a/services/crypto-payment/process/interface.go b/services/crypto-payment/process/interface.go
index bcb99c0..52b42d0 100644
--- a/services/crypto-payment/process/interface.go
+++ b/services/crypto-payment/process/interface.go
@@ -58,8 +58,8 @@ type NonceTransactionsHandler interface {
// ContractHandler defines the operations to query the contract state
type ContractHandler interface {
IsContractPaused(ctx context.Context) (bool, error)
- GetRequestsPerEGLD(ctx context.Context) (uint64, error)
- GetRequests(ctx context.Context, id uint64) (uint64, error)
+ GetCreditsPerEGLD(ctx context.Context) (uint64, error)
+ GetCredits(ctx context.Context, id uint64) (uint64, error)
IsInterfaceNil() bool
}
diff --git a/services/crypto-payment/testsCommon/contractHandlerStub.go b/services/crypto-payment/testsCommon/contractHandlerStub.go
index 1b10bf6..04aab9c 100644
--- a/services/crypto-payment/testsCommon/contractHandlerStub.go
+++ b/services/crypto-payment/testsCommon/contractHandlerStub.go
@@ -4,9 +4,9 @@ import "context"
// ContractHandlerStub -
type ContractHandlerStub struct {
- IsContractPausedHandler func(ctx context.Context) (bool, error)
- GetRequestsPerEGLDHandler func(ctx context.Context) (uint64, error)
- GetRequestsHandler func(ctx context.Context, id uint64) (uint64, error)
+ IsContractPausedHandler func(ctx context.Context) (bool, error)
+ GetCreditsPerEGLDHandler func(ctx context.Context) (uint64, error)
+ GetCreditsHandler func(ctx context.Context, id uint64) (uint64, error)
}
// IsContractPaused -
@@ -17,18 +17,18 @@ func (stub *ContractHandlerStub) IsContractPaused(ctx context.Context) (bool, er
return false, nil
}
-// GetRequestsPerEGLD -
-func (stub *ContractHandlerStub) GetRequestsPerEGLD(ctx context.Context) (uint64, error) {
- if stub.GetRequestsPerEGLDHandler != nil {
- return stub.GetRequestsPerEGLDHandler(ctx)
+// GetCreditsPerEGLD -
+func (stub *ContractHandlerStub) GetCreditsPerEGLD(ctx context.Context) (uint64, error) {
+ if stub.GetCreditsPerEGLDHandler != nil {
+ return stub.GetCreditsPerEGLDHandler(ctx)
}
return 0, nil
}
-// GetRequests -
-func (stub *ContractHandlerStub) GetRequests(ctx context.Context, id uint64) (uint64, error) {
- if stub.GetRequestsHandler != nil {
- return stub.GetRequestsHandler(ctx, id)
+// GetCredits -
+func (stub *ContractHandlerStub) GetCredits(ctx context.Context, id uint64) (uint64, error) {
+ if stub.GetCreditsHandler != nil {
+ return stub.GetCreditsHandler(ctx, id)
}
return 0, nil
}
From f00093325a896f340228a8a94fd5ec53eae880b2 Mon Sep 17 00:00:00 2001
From: Iulian Pascalau
Date: Sun, 1 Feb 2026 19:43:27 +0200
Subject: [PATCH 2/8] - added contracts downloader, completed the renaming from
requests to credits
---
.gitignore | 1 +
frontend/src/Dashboard.tsx | 22 +--
integrationTests/go/e2e_test.go | 2 +-
.../go/framework/cryptoPaymentService.go | 6 +-
integrationTests/go/framework/downloader.go | 130 ++++++++++++++++++
integrationTests/go/framework/testSession.go | 9 +-
services/crypto-payment/api/handler.go | 6 +-
services/crypto-payment/api/handler_test.go | 20 +--
.../process/relayedTxProcessor.go | 4 +-
.../process/relayedTxProcessor_test.go | 2 +-
services/proxy/api/cryptoPaymentHandler.go | 24 ++--
.../proxy/api/cryptoPaymentHandler_test.go | 10 +-
services/proxy/common/servicesDTOs.go | 8 +-
.../proxy/process/requestsSynchronizer.go | 6 +-
.../process/requestsSynchronizer_test.go | 12 +-
.../cryptoPaymentClient_test.go | 6 +-
16 files changed, 200 insertions(+), 68 deletions(-)
create mode 100644 integrationTests/go/framework/downloader.go
diff --git a/.gitignore b/.gitignore
index 689cd91..aa4827d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -31,3 +31,4 @@ data/
logs/
.idea/
epoch-proxy-server
+contracts/
diff --git a/frontend/src/Dashboard.tsx b/frontend/src/Dashboard.tsx
index 1838aa4..0cfd422 100644
--- a/frontend/src/Dashboard.tsx
+++ b/frontend/src/Dashboard.tsx
@@ -29,7 +29,7 @@ interface UserDetails {
interface CryptoPaymentState {
isServiceAvailable: boolean;
isPaused: boolean;
- requestsPerEGLD: number;
+ creditsPerEGLD: number;
walletURL: string;
explorerURL: string;
contractAddress: string;
@@ -37,7 +37,7 @@ interface CryptoPaymentState {
paymentId: number | null;
depositAddress: string | null;
- numberOfRequests: number;
+ credits: number;
isLoading: boolean;
error: string | null;
@@ -111,14 +111,14 @@ export const Dashboard = () => {
const [cryptoState, setCryptoState] = useState({
isServiceAvailable: false,
isPaused: false,
- requestsPerEGLD: 10000,
+ creditsPerEGLD: 10000,
walletURL: 'https://devnet-wallet.multiversx.com',
explorerURL: 'https://devnet-explorer.multiversx.com',
contractAddress: 'erd1qqqqqqqqqqqqqpgqc6u0p4kfkr5ekcrae86m6knx46gr36khrqqqhf96zw',
minimumBalance: 0,
paymentId: null,
depositAddress: null,
- numberOfRequests: 0,
+ credits: 0,
isLoading: false,
error: null
});
@@ -141,7 +141,7 @@ export const Dashboard = () => {
const newState = {
isServiceAvailable: config.isAvailable,
isPaused: config.isPaused,
- requestsPerEGLD: config.requestsPerEGLD,
+ creditsPerEGLD: config.creditsPerEGLD,
walletURL: ensureProtocol(config.walletURL),
explorerURL: ensureProtocol(config.explorerURL),
contractAddress: config.contractAddress,
@@ -164,7 +164,7 @@ export const Dashboard = () => {
...prev,
paymentId: accountRes.data.paymentId,
depositAddress: accountRes.data.address,
- numberOfRequests: accountRes.data.numberOfRequests
+ credits: accountRes.data.credits
}));
}
} catch (accErr: any) {
@@ -177,7 +177,7 @@ export const Dashboard = () => {
...prev,
paymentId: null,
depositAddress: null,
- numberOfRequests: 0
+ credits: 0
}));
}
}
@@ -191,7 +191,7 @@ export const Dashboard = () => {
isServiceAvailable: false,
isPaused: false, // Ensure paused state is cleared if service is down
isLoading: false,
- requestsPerEGLD: 0, // Reset rate
+ creditsPerEGLD: 0, // Reset rate
error: err.response?.data?.error || "Crypto service unavailable"
}));
}
@@ -217,7 +217,7 @@ export const Dashboard = () => {
...prev,
paymentId: accountRes.data.paymentId,
depositAddress: accountRes.data.address,
- numberOfRequests: accountRes.data.numberOfRequests,
+ credits: accountRes.data.credits,
isLoading: false
}));
// Also refresh the main user data to ensure all views are in sync
@@ -636,7 +636,7 @@ export const Dashboard = () => {
- Rate: {cryptoState.requestsPerEGLD ? cryptoState.requestsPerEGLD.toLocaleString() : '-'} req / 1 EGLD
+ Rate: {cryptoState.creditsPerEGLD ? cryptoState.creditsPerEGLD.toLocaleString() : '-'} credits / 1 EGLD
Activation: under 3 minutes
@@ -727,7 +727,7 @@ export const Dashboard = () => {
-
{cryptoState.requestsPerEGLD ? cryptoState.requestsPerEGLD.toLocaleString() : '-'} req/EGLD
+
{cryptoState.creditsPerEGLD ? cryptoState.creditsPerEGLD.toLocaleString() : '-'} credits/EGLD
diff --git a/integrationTests/go/e2e_test.go b/integrationTests/go/e2e_test.go
index 85677d2..f0c5a13 100644
--- a/integrationTests/go/e2e_test.go
+++ b/integrationTests/go/e2e_test.go
@@ -103,7 +103,7 @@ func TestCreateFreeUserAndCreateKeyAndTestRequestsAreThrottledThenSwitchToPremiu
// Generate a block to ensure any pending txs (from balanceProcessor) are processed
cryptoPaymentService.ChainSimulator.GenerateBlocks(ctx, 1)
- reqs := session.GetNumberOfRequests()
+ reqs := session.GetCredits()
return reqs >= 50
}, 2*time.Minute, 1*time.Second)
log.Info("Done ✓")
diff --git a/integrationTests/go/framework/cryptoPaymentService.go b/integrationTests/go/framework/cryptoPaymentService.go
index a105c5c..80e9c36 100644
--- a/integrationTests/go/framework/cryptoPaymentService.go
+++ b/integrationTests/go/framework/cryptoPaymentService.go
@@ -47,7 +47,7 @@ func NewCryptoPaymentService(tb testing.TB) *CryptoPaymentService {
}
// Setup prepares the environment
-func (crs *CryptoPaymentService) Setup(ctx context.Context, numRequestsPerEGLD int64) {
+func (crs *CryptoPaymentService) Setup(ctx context.Context, creditsPerEGLD int64) {
log.Info("minting tokens to the users")
crs.ChainSimulator.FundWallets(ctx, crs.Keys.WalletsToFundOnMultiversX())
@@ -58,11 +58,11 @@ func (crs *CryptoPaymentService) Setup(ctx context.Context, numRequestsPerEGLD i
crs.Keys.OwnerKeys.MvxSk,
deployGasLimit,
[]string{
- hex.EncodeToString(big.NewInt(numRequestsPerEGLD).Bytes()),
+ hex.EncodeToString(big.NewInt(creditsPerEGLD).Bytes()),
},
)
- log.Info("deployed the requests contract", "address", address.Bech32(), "txHash", txOnNetwork.Hash)
+ log.Info("deployed the credits contract", "address", address.Bech32(), "txHash", txOnNetwork.Hash)
crs.ContractAddress = address
}
diff --git a/integrationTests/go/framework/downloader.go b/integrationTests/go/framework/downloader.go
new file mode 100644
index 0000000..e927cdd
--- /dev/null
+++ b/integrationTests/go/framework/downloader.go
@@ -0,0 +1,130 @@
+package framework
+
+import (
+ "archive/zip"
+ "fmt"
+ "io"
+ "net/http"
+ "os"
+ "path/filepath"
+ "strings"
+)
+
+const (
+ contractCreditsVersionTag = "v1.0.0"
+ contractCreditsURL = "https://github.com/iulianpascalau/credits-contract-rs/releases/download/" + contractCreditsVersionTag + "/credits-contract.zip"
+)
+
+func init() {
+ if !IsChainSimulatorIsRunning() {
+ return
+ }
+ err := ensureContractCredits()
+ if err != nil {
+ fmt.Printf("WARNING: Failed to ensure credits contract: %v\n", err)
+ // We deliberately panic here because if we can't get the contract, tests will fail anyway
+ panic(err)
+ }
+}
+
+func ensureContractCredits() error {
+ root := traverse("integrationTests")
+ extractTarget := filepath.Join(root, "contracts")
+ contractDir := filepath.Join(extractTarget, "credits")
+ contractPath := filepath.Join(contractDir, "credits.wasm")
+
+ if _, err := os.Stat(contractPath); err == nil {
+ // Contract exists. We could check versioning (e.g. hash) but for now existence matches intent.
+ return nil
+ }
+
+ fmt.Printf("Downloading credits contract from %s...\n", contractCreditsURL)
+ resp, err := http.Get(contractCreditsURL)
+ if err != nil {
+ return fmt.Errorf("failed to download contract: %w", err)
+ }
+ defer func() {
+ _ = resp.Body.Close()
+ }()
+
+ if resp.StatusCode != http.StatusOK {
+ return fmt.Errorf("bad status: %s", resp.Status)
+ }
+
+ // Create temp file
+ tmpFile, err := os.CreateTemp("", "credits-contract-*.zip")
+ if err != nil {
+ return fmt.Errorf("failed to create temp file: %w", err)
+ }
+ defer func() {
+ _ = os.Remove(tmpFile.Name())
+ }()
+
+ _, err = io.Copy(tmpFile, resp.Body)
+ if err != nil {
+ return fmt.Errorf("failed to write temp file: %w", err)
+ }
+ _ = tmpFile.Close()
+
+ // Unzip
+ r, err := zip.OpenReader(tmpFile.Name())
+ if err != nil {
+ return fmt.Errorf("failed to open zip reader: %w", err)
+ }
+ defer func() {
+ _ = r.Close()
+ }()
+
+ err = os.MkdirAll(extractTarget, 0755)
+
+ if err != nil {
+ return fmt.Errorf("failed to create target dir: %w", err)
+ }
+
+ for _, f := range r.File {
+ fpath := filepath.Join(extractTarget, f.Name)
+
+ // ZipSlip check
+ if !strings.HasPrefix(fpath, filepath.Clean(extractTarget)+string(os.PathSeparator)) {
+ return fmt.Errorf("illegal file path: %s", fpath)
+ }
+
+ if f.FileInfo().IsDir() {
+ err = os.MkdirAll(fpath, os.ModePerm)
+ if err != nil {
+ return err
+ }
+ continue
+ }
+
+ err = os.MkdirAll(filepath.Dir(fpath), os.ModePerm)
+ if err != nil {
+ return err
+ }
+
+ var outFile *os.File
+ outFile, err = os.OpenFile(fpath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, f.Mode())
+ if err != nil {
+ return err
+ }
+
+ var rc io.ReadCloser
+ rc, err = f.Open()
+ if err != nil {
+ _ = outFile.Close()
+ return err
+ }
+
+ _, err = io.Copy(outFile, rc)
+
+ _ = outFile.Close()
+ _ = rc.Close()
+
+ if err != nil {
+ return err
+ }
+ }
+
+ fmt.Println("Successfully downloaded and extracted credits contract.")
+ return nil
+}
diff --git a/integrationTests/go/framework/testSession.go b/integrationTests/go/framework/testSession.go
index d6fd63f..f6a1743 100644
--- a/integrationTests/go/framework/testSession.go
+++ b/integrationTests/go/framework/testSession.go
@@ -180,7 +180,8 @@ func (session *testSession) GetDepositAddress() string {
return session.depositAddress
}
-func (session *testSession) GetNumberOfRequests() int {
+// GetCredits returns the number of credits
+func (session *testSession) GetCredits() int {
req, _ := http.NewRequest(http.MethodGet, session.baseAddress+api.EndpointApiCryptoPaymentAccount, nil)
req.Header.Set("Authorization", "Bearer "+session.jwtToken)
client := &http.Client{}
@@ -197,11 +198,11 @@ func (session *testSession) GetNumberOfRequests() int {
var acc map[string]interface{}
_ = json.NewDecoder(resp.Body).Decode(&acc)
- // Check numberOfRequests. Should be around 50 (0.5 EGLD * 100 requests/EGLD)
- reqs, ok := acc["numberOfRequests"].(float64)
+ // Check credits
+ credits, ok := acc["credits"].(float64)
if !ok {
return -1
}
- return int(reqs)
+ return int(credits)
}
diff --git a/services/crypto-payment/api/handler.go b/services/crypto-payment/api/handler.go
index 76841f3..ccbddfd 100644
--- a/services/crypto-payment/api/handler.go
+++ b/services/crypto-payment/api/handler.go
@@ -64,14 +64,14 @@ func (h *Handler) GetAccount(c *gin.Context) {
return
}
- address, requests, err := h.accountHandler.GetAccount(c.Request.Context(), request.ID)
+ address, credits, err := h.accountHandler.GetAccount(c.Request.Context(), request.ID)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
c.JSON(http.StatusOK, gin.H{
- "address": address,
- "numberOfRequests": requests,
+ "address": address,
+ "credits": credits,
})
}
diff --git a/services/crypto-payment/api/handler_test.go b/services/crypto-payment/api/handler_test.go
index 454f362..6ce98b1 100644
--- a/services/crypto-payment/api/handler_test.go
+++ b/services/crypto-payment/api/handler_test.go
@@ -43,17 +43,17 @@ func (m *mockConfigProvider) IsInterfaceNil() bool {
}
type mockAccountHandler struct {
- getAccountCalled int
- getAccountID uint64
- getAccountAddr string
- getAccountRequests uint64
- getAccountErr error
+ getAccountCalled int
+ getAccountID uint64
+ getAccountAddr string
+ getAccountCredits uint64
+ getAccountErr error
}
func (m *mockAccountHandler) GetAccount(_ context.Context, id uint64) (string, uint64, error) {
m.getAccountCalled++
m.getAccountID = id
- return m.getAccountAddr, m.getAccountRequests, m.getAccountErr
+ return m.getAccountAddr, m.getAccountCredits, m.getAccountErr
}
func (m *mockAccountHandler) IsInterfaceNil() bool {
@@ -168,11 +168,11 @@ func TestHandler_GetAccount(t *testing.T) {
t.Run("success", func(t *testing.T) {
expectedID := uint64(123)
expectedAddr := "erd1test"
- expectedRequests := uint64(10)
+ expectedCredits := uint64(10)
accountHandler := &mockAccountHandler{
- getAccountAddr: expectedAddr,
- getAccountRequests: expectedRequests,
+ getAccountAddr: expectedAddr,
+ getAccountCredits: expectedCredits,
}
h, _ := NewHandler(&mockStorage{}, &mockConfigProvider{}, accountHandler)
@@ -191,7 +191,7 @@ func TestHandler_GetAccount(t *testing.T) {
err := json.Unmarshal(w.Body.Bytes(), &response)
require.NoError(t, err)
require.Equal(t, expectedAddr, response["address"])
- require.Equal(t, float64(expectedRequests), response["numberOfRequests"])
+ require.Equal(t, float64(expectedCredits), response["credits"])
})
t.Run("invalid id", func(t *testing.T) {
diff --git a/services/crypto-payment/process/relayedTxProcessor.go b/services/crypto-payment/process/relayedTxProcessor.go
index 87b6f63..ecb09ba 100644
--- a/services/crypto-payment/process/relayedTxProcessor.go
+++ b/services/crypto-payment/process/relayedTxProcessor.go
@@ -17,7 +17,7 @@ import (
"github.com/multiversx/mx-sdk-go/interactors/nonceHandlerV2"
)
-const requestsAddEndpoint = "addRequests"
+const creditsAddEndpoint = "addCredits"
const intervalToResendTxs = time.Minute
var hashSigningTxHasher = keccak.NewKeccak()
@@ -127,7 +127,7 @@ func (processor *relayedTxProcessor) Process(ctx context.Context, id uint64, sen
// 1. Prepare the data field
dataFieldBuilder := builders.NewTxDataBuilder()
- dataField, err := dataFieldBuilder.Function(requestsAddEndpoint).ArgInt64(int64(id)).ToDataBytes()
+ dataField, err := dataFieldBuilder.Function(creditsAddEndpoint).ArgInt64(int64(id)).ToDataBytes()
if err != nil {
return fmt.Errorf("failed to build data field: %w", err)
}
diff --git a/services/crypto-payment/process/relayedTxProcessor_test.go b/services/crypto-payment/process/relayedTxProcessor_test.go
index 57c6fd2..d02701c 100644
--- a/services/crypto-payment/process/relayedTxProcessor_test.go
+++ b/services/crypto-payment/process/relayedTxProcessor_test.go
@@ -550,7 +550,7 @@ func TestRelayedTxProcessor_Process(t *testing.T) {
assert.Equal(t, senderBech32, tx.Sender)
assert.Equal(t, uint64(1000000000), tx.GasPrice)
assert.Equal(t, gasLimit, tx.GasLimit)
- assert.Equal(t, []byte("addRequests@05"), tx.Data)
+ assert.Equal(t, []byte("addCredits@05"), tx.Data)
assert.Equal(t, "T", tx.ChainID)
assert.Equal(t, uint32(1), tx.Version)
assert.Equal(t, hex.EncodeToString([]byte("userSig")), tx.Signature)
diff --git a/services/proxy/api/cryptoPaymentHandler.go b/services/proxy/api/cryptoPaymentHandler.go
index df2f57b..b614e7e 100644
--- a/services/proxy/api/cryptoPaymentHandler.go
+++ b/services/proxy/api/cryptoPaymentHandler.go
@@ -106,7 +106,7 @@ func (h *cryptoPaymentHandler) handleConfig(w http.ResponseWriter, r *http.Reque
response := map[string]interface{}{
"isAvailable": true,
"isPaused": cfg.IsContractPaused,
- "requestsPerEGLD": cfg.RequestsPerEGLD,
+ "creditsPerEGLD": cfg.CreditsPerEGLD,
"walletURL": cfg.WalletURL,
"explorerURL": cfg.ExplorerURL,
"contractAddress": cfg.ContractAddress,
@@ -204,9 +204,9 @@ func (h *cryptoPaymentHandler) handleGetAccount(w http.ResponseWriter, r *http.R
w.Header().Set("Content-Type", "application/json")
_ = json.NewEncoder(w).Encode(map[string]interface{}{
- "paymentId": info.PaymentID,
- "address": info.Address,
- "numberOfRequests": info.NumberOfRequests,
+ "paymentId": info.PaymentID,
+ "address": info.Address,
+ "credits": info.Credits,
})
}
@@ -246,10 +246,10 @@ func (h *cryptoPaymentHandler) handleAdmin(w http.ResponseWriter, r *http.Reques
// I'll return a special JSON indicating no payment info.
w.Header().Set("Content-Type", "application/json")
_ = json.NewEncoder(w).Encode(map[string]interface{}{
- "username": user.Username,
- "paymentId": nil,
- "address": nil,
- "numberOfRequests": 0,
+ "username": user.Username,
+ "paymentId": nil,
+ "address": nil,
+ "credits": 0,
})
return
}
@@ -263,9 +263,9 @@ func (h *cryptoPaymentHandler) handleAdmin(w http.ResponseWriter, r *http.Reques
w.Header().Set("Content-Type", "application/json")
_ = json.NewEncoder(w).Encode(map[string]interface{}{
- "username": user.Username,
- "paymentId": info.PaymentID,
- "address": info.Address,
- "numberOfRequests": info.NumberOfRequests,
+ "username": user.Username,
+ "paymentId": info.PaymentID,
+ "address": info.Address,
+ "credits": info.Credits,
})
}
diff --git a/services/proxy/api/cryptoPaymentHandler_test.go b/services/proxy/api/cryptoPaymentHandler_test.go
index e000db1..13e60c0 100644
--- a/services/proxy/api/cryptoPaymentHandler_test.go
+++ b/services/proxy/api/cryptoPaymentHandler_test.go
@@ -68,8 +68,8 @@ func TestCryptoPaymentHandler_HandleConfig(t *testing.T) {
t.Run("success", func(t *testing.T) {
expectedConfig := &common.CryptoPaymentConfig{
- RequestsPerEGLD: 100,
- WalletURL: "https://wallet.com",
+ CreditsPerEGLD: 100,
+ WalletURL: "https://wallet.com",
}
clientStub.GetConfigHandler = func() (*common.CryptoPaymentConfig, error) {
return expectedConfig, nil
@@ -219,7 +219,7 @@ func TestCryptoPaymentHandler_HandleGetAccount(t *testing.T) {
}
clientStub.GetAccountHandler = func(paymentID uint64) (*common.AccountInfo, error) {
assert.Equal(t, uint64(100), paymentID)
- return &common.AccountInfo{PaymentID: 100, NumberOfRequests: 50}, nil
+ return &common.AccountInfo{PaymentID: 100, Credits: 50}, nil
}
w := httptest.NewRecorder()
@@ -278,7 +278,7 @@ func TestCryptoPaymentHandler_HandleAdmin(t *testing.T) {
return &common.UsersDetails{Username: "target", CryptoPaymentID: 100}, nil
}
clientStub.GetAccountHandler = func(paymentID uint64) (*common.AccountInfo, error) {
- return &common.AccountInfo{PaymentID: 100, NumberOfRequests: 50}, nil
+ return &common.AccountInfo{PaymentID: 100, Credits: 50}, nil
}
w := httptest.NewRecorder()
@@ -329,6 +329,6 @@ func TestCryptoPaymentHandler_HandleAdmin(t *testing.T) {
var resp map[string]interface{}
_ = json.NewDecoder(w.Body).Decode(&resp)
assert.Nil(t, resp["paymentId"])
- assert.Equal(t, float64(0), resp["numberOfRequests"])
+ assert.Equal(t, float64(0), resp["credits"])
})
}
diff --git a/services/proxy/common/servicesDTOs.go b/services/proxy/common/servicesDTOs.go
index d9bb5b3..7f7e1f5 100644
--- a/services/proxy/common/servicesDTOs.go
+++ b/services/proxy/common/servicesDTOs.go
@@ -3,7 +3,7 @@ package common
// CryptoPaymentConfig response from crypto-payment service
type CryptoPaymentConfig struct {
IsContractPaused bool `json:"isContractPaused"`
- RequestsPerEGLD uint64 `json:"requestsPerEGLD"`
+ CreditsPerEGLD uint64 `json:"creditsPerEGLD"`
WalletURL string `json:"walletURL"`
ExplorerURL string `json:"explorerURL"`
ContractAddress string `json:"contractAddress"`
@@ -17,7 +17,7 @@ type CreateAddressResponse struct {
// AccountInfo response from account endpoint
type AccountInfo struct {
- PaymentID uint64 `json:"paymentID"`
- Address string `json:"address"`
- NumberOfRequests uint64 `json:"numberOfRequests"`
+ PaymentID uint64 `json:"paymentID"`
+ Address string `json:"address"`
+ Credits uint64 `json:"credits"`
}
diff --git a/services/proxy/process/requestsSynchronizer.go b/services/proxy/process/requestsSynchronizer.go
index f47e9a7..a592095 100644
--- a/services/proxy/process/requestsSynchronizer.go
+++ b/services/proxy/process/requestsSynchronizer.go
@@ -47,10 +47,10 @@ func (rs *requestsSynchronizer) Process() {
}
// The DB should be updated if the contract's value exceeds what we have in the DB for the contract
- if accountInfo.NumberOfRequests > user.SCMaxRequests {
- log.Info("updating user max requests from contract", "user", user.Username, "old_sc", user.SCMaxRequests, "new_sc", accountInfo.NumberOfRequests)
+ if accountInfo.Credits > user.SCMaxRequests {
+ log.Info("updating user max requests from contract", "user", user.Username, "old_sc", user.SCMaxRequests, "new_sc", accountInfo.Credits)
- errUpdate := rs.store.UpdateUserMaxRequestsFromContract(user.Username, accountInfo.NumberOfRequests)
+ errUpdate := rs.store.UpdateUserMaxRequestsFromContract(user.Username, accountInfo.Credits)
if errUpdate != nil {
log.Error("failed to update user max requests", "user", user.Username, "error", errUpdate)
}
diff --git a/services/proxy/process/requestsSynchronizer_test.go b/services/proxy/process/requestsSynchronizer_test.go
index 3dd153a..abc934a 100644
--- a/services/proxy/process/requestsSynchronizer_test.go
+++ b/services/proxy/process/requestsSynchronizer_test.go
@@ -122,8 +122,8 @@ func TestRequestsSynchronizer_Process(t *testing.T) {
crypto := &testscommon.CryptoPaymentClientStub{
GetAccountHandler: func(paymentID uint64) (*common.AccountInfo, error) {
return &common.AccountInfo{
- PaymentID: 1,
- NumberOfRequests: 100,
+ PaymentID: 1,
+ Credits: 100,
}, nil
},
}
@@ -157,8 +157,8 @@ func TestRequestsSynchronizer_Process(t *testing.T) {
crypto := &testscommon.CryptoPaymentClientStub{
GetAccountHandler: func(paymentID uint64) (*common.AccountInfo, error) {
return &common.AccountInfo{
- PaymentID: 1,
- NumberOfRequests: 100,
+ PaymentID: 1,
+ Credits: 100,
}, nil
},
}
@@ -190,8 +190,8 @@ func TestRequestsSynchronizer_Process(t *testing.T) {
crypto := &testscommon.CryptoPaymentClientStub{
GetAccountHandler: func(paymentID uint64) (*common.AccountInfo, error) {
return &common.AccountInfo{
- PaymentID: 1,
- NumberOfRequests: 100,
+ PaymentID: 1,
+ Credits: 100,
}, nil
},
}
diff --git a/services/proxy/serviceWrappers/cryptoPaymentClient_test.go b/services/proxy/serviceWrappers/cryptoPaymentClient_test.go
index 559be32..1640526 100644
--- a/services/proxy/serviceWrappers/cryptoPaymentClient_test.go
+++ b/services/proxy/serviceWrappers/cryptoPaymentClient_test.go
@@ -64,8 +64,8 @@ func TestCryptoPaymentClient_GetConfig(t *testing.T) {
t.Parallel()
expectedConfig := common.CryptoPaymentConfig{
- RequestsPerEGLD: 100,
- WalletURL: "https://wallet.com",
+ CreditsPerEGLD: 100,
+ WalletURL: "https://wallet.com",
}
stub := &testscommon.HttpRequesterStub{
@@ -172,7 +172,7 @@ func TestCryptoPaymentClient_GetAccount(t *testing.T) {
t.Run("success", func(t *testing.T) {
t.Parallel()
- expectedInfo := common.AccountInfo{PaymentID: 1, Address: "addr", NumberOfRequests: 50}
+ expectedInfo := common.AccountInfo{PaymentID: 1, Address: "addr", Credits: 50}
stub := &testscommon.HttpRequesterStub{
DoRequestHandler: func(method string, url string, apiKey string, result any) error {
assert.Equal(t, http.MethodGet, method)
From 522cc4175227c88152ea0e13df8e9ee2cd990313 Mon Sep 17 00:00:00 2001
From: Iulian Pascalau
Date: Sun, 1 Feb 2026 21:01:40 +0200
Subject: [PATCH 3/8] - added query contract error treated as paused
---
.../process/contractQueryHandler.go | 9 ++++-
.../process/contractQueryHandler_test.go | 35 +++++++++++++++----
2 files changed, 36 insertions(+), 8 deletions(-)
diff --git a/services/crypto-payment/process/contractQueryHandler.go b/services/crypto-payment/process/contractQueryHandler.go
index e884373..31fa1a1 100644
--- a/services/crypto-payment/process/contractQueryHandler.go
+++ b/services/crypto-payment/process/contractQueryHandler.go
@@ -17,6 +17,7 @@ const (
keyCreditsPerEgld = "creditsPerEgld"
contractNotFoundStatus = "contract not found"
+ returnCodeOk = "ok"
)
type contractQueryHandler struct {
@@ -63,7 +64,7 @@ func (cqh *contractQueryHandler) IsContractPaused(ctx context.Context) (bool, er
CallerAddr: cqh.contractBech32Address, // Caller can be the contract itself for views usually, or random
})
if err != nil {
- return false, err
+ return true, err
}
if res.Data == nil || res.Data.ReturnCode == contractNotFoundStatus {
@@ -71,6 +72,12 @@ func (cqh *contractQueryHandler) IsContractPaused(ctx context.Context) (bool, er
return true, nil
}
+ // If the return code is not "ok", something went wrong (e.g. function not found, execution failed).
+ // We should treat this as the contract being paused/unavailable for safety.
+ if res.Data.ReturnCode != returnCodeOk {
+ return true, nil
+ }
+
if len(res.Data.ReturnData) == 0 || len(res.Data.ReturnData[0]) == 0 {
isPaused = false
} else {
diff --git a/services/crypto-payment/process/contractQueryHandler_test.go b/services/crypto-payment/process/contractQueryHandler_test.go
index 85e38a5..faaf138 100644
--- a/services/crypto-payment/process/contractQueryHandler_test.go
+++ b/services/crypto-payment/process/contractQueryHandler_test.go
@@ -58,7 +58,7 @@ func TestContractQueryHandler_IsContractPaused(t *testing.T) {
handler, _ := NewContractQueryHandler(proxy, "erd1test", &testsCommon.CacherStub{})
paused, err := handler.IsContractPaused(context.Background())
- require.False(t, paused)
+ require.True(t, paused)
require.Equal(t, expectedErr, err)
})
@@ -74,6 +74,7 @@ func TestContractQueryHandler_IsContractPaused(t *testing.T) {
handler, _ := NewContractQueryHandler(proxy, "erd1test", &testsCommon.CacherStub{})
paused, err := handler.IsContractPaused(context.Background())
require.NoError(t, err)
+ // Data nil -> Paused
require.True(t, paused)
})
@@ -83,7 +84,7 @@ func TestContractQueryHandler_IsContractPaused(t *testing.T) {
proxy := &testsCommon.BlockchainDataProviderStub{
ExecuteVMQueryHandler: func(ctx context.Context, vmRequest *data.VmValueRequest) (*data.VmValuesResponseData, error) {
return &data.VmValuesResponseData{
- Data: &vm.VMOutputApi{ReturnData: nil},
+ Data: &vm.VMOutputApi{ReturnData: nil, ReturnCode: "ok"},
}, nil
},
}
@@ -100,7 +101,7 @@ func TestContractQueryHandler_IsContractPaused(t *testing.T) {
proxy := &testsCommon.BlockchainDataProviderStub{
ExecuteVMQueryHandler: func(ctx context.Context, vmRequest *data.VmValueRequest) (*data.VmValuesResponseData, error) {
return &data.VmValuesResponseData{
- Data: &vm.VMOutputApi{ReturnData: make([][]byte, 0)},
+ Data: &vm.VMOutputApi{ReturnData: make([][]byte, 0), ReturnCode: "ok"},
}, nil
},
}
@@ -117,7 +118,7 @@ func TestContractQueryHandler_IsContractPaused(t *testing.T) {
proxy := &testsCommon.BlockchainDataProviderStub{
ExecuteVMQueryHandler: func(ctx context.Context, vmRequest *data.VmValueRequest) (*data.VmValuesResponseData, error) {
return &data.VmValuesResponseData{
- Data: &vm.VMOutputApi{ReturnData: [][]byte{{}}},
+ Data: &vm.VMOutputApi{ReturnData: [][]byte{{}}, ReturnCode: "ok"},
}, nil
},
}
@@ -147,13 +148,33 @@ func TestContractQueryHandler_IsContractPaused(t *testing.T) {
require.True(t, paused)
})
+ t.Run("execution failed", func(t *testing.T) {
+ t.Parallel()
+
+ proxy := &testsCommon.BlockchainDataProviderStub{
+ ExecuteVMQueryHandler: func(ctx context.Context, vmRequest *data.VmValueRequest) (*data.VmValuesResponseData, error) {
+ return &data.VmValuesResponseData{
+ Data: &vm.VMOutputApi{
+ ReturnCode: "execution failed",
+ ReturnData: nil,
+ },
+ }, nil
+ },
+ }
+
+ handler, _ := NewContractQueryHandler(proxy, "erd1test", &testsCommon.CacherStub{})
+ paused, err := handler.IsContractPaused(context.Background())
+ require.NoError(t, err)
+ require.True(t, paused)
+ })
+
t.Run("paused", func(t *testing.T) {
t.Parallel()
proxy := &testsCommon.BlockchainDataProviderStub{
ExecuteVMQueryHandler: func(ctx context.Context, vmRequest *data.VmValueRequest) (*data.VmValuesResponseData, error) {
return &data.VmValuesResponseData{
- Data: &vm.VMOutputApi{ReturnData: [][]byte{{1}}},
+ Data: &vm.VMOutputApi{ReturnData: [][]byte{{1}}, ReturnCode: "ok"},
}, nil
},
}
@@ -170,7 +191,7 @@ func TestContractQueryHandler_IsContractPaused(t *testing.T) {
proxy := &testsCommon.BlockchainDataProviderStub{
ExecuteVMQueryHandler: func(ctx context.Context, vmRequest *data.VmValueRequest) (*data.VmValuesResponseData, error) {
return &data.VmValuesResponseData{
- Data: &vm.VMOutputApi{ReturnData: [][]byte{{0}}},
+ Data: &vm.VMOutputApi{ReturnData: [][]byte{{0}}, ReturnCode: "ok"},
}, nil
},
}
@@ -189,7 +210,7 @@ func TestContractQueryHandler_IsContractPaused(t *testing.T) {
ExecuteVMQueryHandler: func(ctx context.Context, vmRequest *data.VmValueRequest) (*data.VmValuesResponseData, error) {
calls++
return &data.VmValuesResponseData{
- Data: &vm.VMOutputApi{ReturnData: [][]byte{{1}}},
+ Data: &vm.VMOutputApi{ReturnData: [][]byte{{1}}, ReturnCode: "ok"},
}, nil
},
}
From b58f96c02f664925f6e14c1a1d25604afc39b7da Mon Sep 17 00:00:00 2001
From: Iulian Pascalau
Date: Sun, 1 Feb 2026 23:19:31 +0200
Subject: [PATCH 4/8] - removed the crypto payments service
---
Jenkinsfile-crypto-prod | 24 -
Jenkinsfile-crypto-staging | 24 -
Jenkinsfile-proxy-prod => Jenkinsfile-prod | 0
...sfile-proxy-staging => Jenkinsfile-staging | 0
go.mod | 3 +-
go.sum | 2 +
integrationTests/{go => }/e2e_test.go | 17 +-
.../framework/chainSimulatorWrapper.go | 28 +-
integrationTests/{go => }/framework/common.go | 23 +-
.../{go => }/framework/interface.go | 4 +-
.../{go => }/framework/mockCaptchaWrapper.go | 0
.../{go => }/framework/mockEmailSender.go | 0
.../{go => }/framework/proxyService.go | 0
.../{go => }/framework/testSession.go | 0
integrationTests/go/cryptoPayment_test.go | 314 --------
integrationTests/go/framework/address.go | 72 --
.../go/framework/cryptoPaymentService.go | 141 ----
integrationTests/go/framework/downloader.go | 130 ----
integrationTests/go/framework/keys.go | 119 ----
integrationTests/{go => }/interface.go | 4 +-
.../{go => }/manual_flows_test.go | 11 +-
integrationTests/{go => }/proxy_test.go | 4 +-
scripts/create_crypto_payment_service.sh | 46 --
scripts/deploy_crypto.sh | 78 --
services/crypto-payment/.env.example | 1 -
services/crypto-payment/SPECS.md | 141 ----
services/crypto-payment/api/handler.go | 77 --
services/crypto-payment/api/handler_test.go | 227 ------
services/crypto-payment/api/httpServer.go | 76 --
.../crypto-payment/api/httpServer_test.go | 57 --
services/crypto-payment/api/interface.go | 32 -
services/crypto-payment/api/middleware.go | 41 --
.../crypto-payment/api/middleware_test.go | 53 --
services/crypto-payment/common/dtos.go | 7 -
services/crypto-payment/config.toml.example | 23 -
services/crypto-payment/config/config.go | 15 -
.../crypto-payment/config/tomlConfig_test.go | 53 --
services/crypto-payment/crypto/errors.go | 6 -
services/crypto-payment/crypto/interface.go | 12 -
.../crypto/multipleKeysHandler.go | 70 --
.../crypto/multipleKeysHandler_test.go | 214 ------
.../crypto-payment/crypto/singleKeyHandler.go | 61 --
.../crypto/singleKeyHandler_test.go | 83 ---
.../factory/componentsHandler.go | 196 -----
.../factory/componentsHandler_test.go | 141 ----
services/crypto-payment/factory/errors.go | 5 -
services/crypto-payment/factory/interface.go | 37 -
services/crypto-payment/main.go | 265 -------
.../crypto-payment/process/accountHandler.go | 48 --
.../process/accountHandler_test.go | 115 ---
.../process/balanceProcessor.go | 126 ----
.../process/balanceProcessor_test.go | 669 ------------------
.../crypto-payment/process/configHandler.go | 60 --
.../process/configHandler_test.go | 101 ---
.../process/contractQueryHandler.go | 152 ----
.../process/contractQueryHandler_test.go | 361 ----------
services/crypto-payment/process/errors.go | 15 -
services/crypto-payment/process/interface.go | 72 --
.../process/relayedTxProcessor.go | 236 ------
.../process/relayedTxProcessor_test.go | 573 ---------------
services/crypto-payment/storage/cacher.go | 76 --
.../crypto-payment/storage/cacher_test.go | 98 ---
services/crypto-payment/storage/errors.go | 5 -
services/crypto-payment/storage/interface.go | 7 -
.../crypto-payment/storage/sqliteWrapper.go | 164 -----
.../storage/sqliteWrapper_test.go | 145 ----
.../testsCommon/balanceOperatorStub.go | 36 -
.../testsCommon/blockchainDataProviderStub.go | 66 --
.../crypto-payment/testsCommon/cacherStub.go | 36 -
.../testsCommon/contractHandlerStub.go | 39 -
.../testsCommon/dataProviderStub.go | 32 -
.../multipleAddressesHandlerStub.go | 30 -
.../testsCommon/singleKeyHandler.go | 42 --
.../crypto-payment/testsCommon/walletStub.go | 29 -
services/proxy/SPECS.md | 21 +-
75 files changed, 78 insertions(+), 6213 deletions(-)
delete mode 100644 Jenkinsfile-crypto-prod
delete mode 100644 Jenkinsfile-crypto-staging
rename Jenkinsfile-proxy-prod => Jenkinsfile-prod (100%)
rename Jenkinsfile-proxy-staging => Jenkinsfile-staging (100%)
rename integrationTests/{go => }/e2e_test.go (87%)
rename integrationTests/{go => }/framework/chainSimulatorWrapper.go (90%)
rename integrationTests/{go => }/framework/common.go (67%)
rename integrationTests/{go => }/framework/interface.go (93%)
rename integrationTests/{go => }/framework/mockCaptchaWrapper.go (100%)
rename integrationTests/{go => }/framework/mockEmailSender.go (100%)
rename integrationTests/{go => }/framework/proxyService.go (100%)
rename integrationTests/{go => }/framework/testSession.go (100%)
delete mode 100644 integrationTests/go/cryptoPayment_test.go
delete mode 100644 integrationTests/go/framework/address.go
delete mode 100644 integrationTests/go/framework/cryptoPaymentService.go
delete mode 100644 integrationTests/go/framework/downloader.go
delete mode 100644 integrationTests/go/framework/keys.go
rename integrationTests/{go => }/interface.go (86%)
rename integrationTests/{go => }/manual_flows_test.go (93%)
rename integrationTests/{go => }/proxy_test.go (94%)
delete mode 100755 scripts/create_crypto_payment_service.sh
delete mode 100755 scripts/deploy_crypto.sh
delete mode 100644 services/crypto-payment/.env.example
delete mode 100644 services/crypto-payment/SPECS.md
delete mode 100644 services/crypto-payment/api/handler.go
delete mode 100644 services/crypto-payment/api/handler_test.go
delete mode 100644 services/crypto-payment/api/httpServer.go
delete mode 100644 services/crypto-payment/api/httpServer_test.go
delete mode 100644 services/crypto-payment/api/interface.go
delete mode 100644 services/crypto-payment/api/middleware.go
delete mode 100644 services/crypto-payment/api/middleware_test.go
delete mode 100644 services/crypto-payment/common/dtos.go
delete mode 100644 services/crypto-payment/config.toml.example
delete mode 100644 services/crypto-payment/config/config.go
delete mode 100644 services/crypto-payment/config/tomlConfig_test.go
delete mode 100644 services/crypto-payment/crypto/errors.go
delete mode 100644 services/crypto-payment/crypto/interface.go
delete mode 100644 services/crypto-payment/crypto/multipleKeysHandler.go
delete mode 100644 services/crypto-payment/crypto/multipleKeysHandler_test.go
delete mode 100644 services/crypto-payment/crypto/singleKeyHandler.go
delete mode 100644 services/crypto-payment/crypto/singleKeyHandler_test.go
delete mode 100644 services/crypto-payment/factory/componentsHandler.go
delete mode 100644 services/crypto-payment/factory/componentsHandler_test.go
delete mode 100644 services/crypto-payment/factory/errors.go
delete mode 100644 services/crypto-payment/factory/interface.go
delete mode 100644 services/crypto-payment/main.go
delete mode 100644 services/crypto-payment/process/accountHandler.go
delete mode 100644 services/crypto-payment/process/accountHandler_test.go
delete mode 100644 services/crypto-payment/process/balanceProcessor.go
delete mode 100644 services/crypto-payment/process/balanceProcessor_test.go
delete mode 100644 services/crypto-payment/process/configHandler.go
delete mode 100644 services/crypto-payment/process/configHandler_test.go
delete mode 100644 services/crypto-payment/process/contractQueryHandler.go
delete mode 100644 services/crypto-payment/process/contractQueryHandler_test.go
delete mode 100644 services/crypto-payment/process/errors.go
delete mode 100644 services/crypto-payment/process/interface.go
delete mode 100644 services/crypto-payment/process/relayedTxProcessor.go
delete mode 100644 services/crypto-payment/process/relayedTxProcessor_test.go
delete mode 100644 services/crypto-payment/storage/cacher.go
delete mode 100644 services/crypto-payment/storage/cacher_test.go
delete mode 100644 services/crypto-payment/storage/errors.go
delete mode 100644 services/crypto-payment/storage/interface.go
delete mode 100644 services/crypto-payment/storage/sqliteWrapper.go
delete mode 100644 services/crypto-payment/storage/sqliteWrapper_test.go
delete mode 100644 services/crypto-payment/testsCommon/balanceOperatorStub.go
delete mode 100644 services/crypto-payment/testsCommon/blockchainDataProviderStub.go
delete mode 100644 services/crypto-payment/testsCommon/cacherStub.go
delete mode 100644 services/crypto-payment/testsCommon/contractHandlerStub.go
delete mode 100644 services/crypto-payment/testsCommon/dataProviderStub.go
delete mode 100644 services/crypto-payment/testsCommon/multipleAddressesHandlerStub.go
delete mode 100644 services/crypto-payment/testsCommon/singleKeyHandler.go
delete mode 100644 services/crypto-payment/testsCommon/walletStub.go
diff --git a/Jenkinsfile-crypto-prod b/Jenkinsfile-crypto-prod
deleted file mode 100644
index 1a7e84a..0000000
--- a/Jenkinsfile-crypto-prod
+++ /dev/null
@@ -1,24 +0,0 @@
-pipeline {
- agent any
-
- parameters {
- string(name: 'BRANCH_OR_TAG', defaultValue: 'main', description: 'Branch or Tag to deploy (e.g., main, v1.0.0)')
- }
-
- environment {
- PROD_VM_USER = 'ubuntu'
- // You will need to add this credential in Jenkins
- PROD_VM_HOST = credentials('crypto-payment-prod-vm-ip')
- PROJECT_PATH = '/home/ubuntu/epoch-proxy'
- }
-
- stages {
- stage('Deploy') {
- steps {
- sshagent(['prod-vm-ssh-key']) {
- sh "ssh -o StrictHostKeyChecking=no ${PROD_VM_USER}@${PROD_VM_HOST} 'cd ${PROJECT_PATH} && ./scripts/deploy_crypto.sh ${params.BRANCH_OR_TAG}'"
- }
- }
- }
- }
-}
diff --git a/Jenkinsfile-crypto-staging b/Jenkinsfile-crypto-staging
deleted file mode 100644
index 334b9be..0000000
--- a/Jenkinsfile-crypto-staging
+++ /dev/null
@@ -1,24 +0,0 @@
-pipeline {
- agent any
-
- parameters {
- string(name: 'BRANCH_OR_TAG', defaultValue: 'main', description: 'Branch or Tag to deploy (e.g., main, v1.0.0)')
- }
-
- environment {
- STAGING_VM_USER = 'ubuntu'
- // You will need to add this credential in Jenkins
- STAGING_VM_HOST = credentials('crypto-payment-staging-vm-ip')
- PROJECT_PATH = '/home/ubuntu/epoch-proxy'
- }
-
- stages {
- stage('Deploy') {
- steps {
- sshagent(['prod-vm-ssh-key']) {
- sh "ssh -o StrictHostKeyChecking=no ${STAGING_VM_USER}@${STAGING_VM_HOST} 'cd ${PROJECT_PATH} && ./scripts/deploy_crypto.sh ${params.BRANCH_OR_TAG}'"
- }
- }
- }
- }
-}
diff --git a/Jenkinsfile-proxy-prod b/Jenkinsfile-prod
similarity index 100%
rename from Jenkinsfile-proxy-prod
rename to Jenkinsfile-prod
diff --git a/Jenkinsfile-proxy-staging b/Jenkinsfile-staging
similarity index 100%
rename from Jenkinsfile-proxy-staging
rename to Jenkinsfile-staging
diff --git a/go.mod b/go.mod
index f653440..a5adad7 100644
--- a/go.mod
+++ b/go.mod
@@ -6,8 +6,8 @@ toolchain go1.24.11
require (
github.com/dchest/captcha v1.1.0
- github.com/gin-gonic/gin v1.10.0
github.com/golang-jwt/jwt/v5 v5.3.0
+ github.com/iulianpascalau/mx-crypto-payments v1.0.4
github.com/joho/godotenv v1.5.1
github.com/mattn/go-sqlite3 v1.14.33
github.com/multiversx/mx-chain-core-go v1.4.1
@@ -50,6 +50,7 @@ require (
github.com/gin-contrib/cors v1.6.0 // indirect
github.com/gin-contrib/pprof v1.4.0 // indirect
github.com/gin-contrib/sse v0.1.0 // indirect
+ github.com/gin-gonic/gin v1.10.0 // indirect
github.com/go-logr/logr v1.4.2 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/go-ole/go-ole v1.2.6 // indirect
diff --git a/go.sum b/go.sum
index d030fb3..32926ba 100644
--- a/go.sum
+++ b/go.sum
@@ -268,6 +268,8 @@ github.com/ipfs/go-test v0.0.4 h1:DKT66T6GBB6PsDFLoO56QZPrOmzJkqU1FZH5C9ySkew=
github.com/ipfs/go-test v0.0.4/go.mod h1:qhIM1EluEfElKKM6fnWxGn822/z9knUGM1+I/OAQNKI=
github.com/ipld/go-ipld-prime v0.21.0 h1:n4JmcpOlPDIxBcY037SVfpd1G+Sj1nKZah0m6QH9C2E=
github.com/ipld/go-ipld-prime v0.21.0/go.mod h1:3RLqy//ERg/y5oShXXdx5YIp50cFGOanyMctpPjsvxQ=
+github.com/iulianpascalau/mx-crypto-payments v1.0.4 h1:mHsP6s+OpOYhK+a3v/F4SV44SQfxYKN8idDS/FKV5Go=
+github.com/iulianpascalau/mx-crypto-payments v1.0.4/go.mod h1:4/NVijzrXB9NswwfiG8QSV4KkolilWOCjcxIhpVFSUw=
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/jbenet/go-cienv v0.1.0/go.mod h1:TqNnHUmJgXau0nCzC7kXWeotg3J9W34CUv5Djy1+FlA=
diff --git a/integrationTests/go/e2e_test.go b/integrationTests/e2e_test.go
similarity index 87%
rename from integrationTests/go/e2e_test.go
rename to integrationTests/e2e_test.go
index f0c5a13..9f3687a 100644
--- a/integrationTests/go/e2e_test.go
+++ b/integrationTests/e2e_test.go
@@ -1,4 +1,4 @@
-package _go
+package integrationTests
import (
"context"
@@ -8,23 +8,30 @@ import (
"testing"
"time"
- "github.com/iulianpascalau/mx-epoch-proxy-go/integrationTests/go/framework"
+ cryptoPaymentsFramework "github.com/iulianpascalau/mx-crypto-payments/integrationTests/framework"
+ "github.com/iulianpascalau/mx-epoch-proxy-go/integrationTests/framework"
"github.com/multiversx/mx-chain-core-go/data/transaction"
+ logger "github.com/multiversx/mx-chain-logger-go"
"github.com/stretchr/testify/require"
)
+var log = logger.GetOrCreate("integrationTests")
+
func TestCreateFreeUserAndCreateKeyAndTestRequestsAreThrottledThenSwitchToPremium(t *testing.T) {
if !framework.IsChainSimulatorIsRunning() {
t.Skip("No chain simulator instance running found. Skipping slow test")
}
+
+ framework.EnsureTestContracts(t)
+
proxyService := framework.NewProxyService(t)
- cryptoPaymentService := framework.NewCryptoPaymentService(t)
+ cryptoPaymentService := cryptoPaymentsFramework.NewCryptoPaymentService(t)
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
proxyService.Setup(ctx)
- cryptoPaymentService.Setup(ctx, 100)
+ cryptoPaymentService.Setup(ctx, 100, framework.GetContractPath("credits"))
defer proxyService.TearDown()
defer cryptoPaymentService.TearDown()
@@ -87,7 +94,7 @@ func TestCreateFreeUserAndCreateKeyAndTestRequestsAreThrottledThenSwitchToPremiu
// Value: 0.5 EGLD = 0.5 * 10^18 = 500000000000000000
value := "500000000000000000"
- receiverAddr := framework.NewMvxAddressFromBech32(t, session.GetDepositAddress())
+ receiverAddr := cryptoPaymentsFramework.NewMvxAddressFromBech32(t, session.GetDepositAddress())
// Send Tx
hash, _, status := cryptoPaymentService.ChainSimulator.SendTx(ctx, senderSk, receiverAddr, value, 500000, []byte{})
diff --git a/integrationTests/go/framework/chainSimulatorWrapper.go b/integrationTests/framework/chainSimulatorWrapper.go
similarity index 90%
rename from integrationTests/go/framework/chainSimulatorWrapper.go
rename to integrationTests/framework/chainSimulatorWrapper.go
index bad9328..c3b356d 100644
--- a/integrationTests/go/framework/chainSimulatorWrapper.go
+++ b/integrationTests/framework/chainSimulatorWrapper.go
@@ -10,6 +10,7 @@ import (
"testing"
"time"
+ cryptoPaymentsFramework "github.com/iulianpascalau/mx-crypto-payments/integrationTests/framework"
"github.com/multiversx/mx-chain-core-go/core"
"github.com/multiversx/mx-chain-core-go/core/pubkeyConverter"
apiCore "github.com/multiversx/mx-chain-core-go/data/api"
@@ -44,9 +45,10 @@ const (
)
var (
- log = logger.GetOrCreate("integrationTests")
- signer = &singlesig.Ed25519Signer{}
- keyGenerator = signing.NewKeyGenerator(ed25519.NewEd25519())
+ log = logger.GetOrCreate("integrationTests")
+ signer = &singlesig.Ed25519Signer{}
+ keyGenerator = signing.NewKeyGenerator(ed25519.NewEd25519())
+ addressPubkeyConverter, _ = pubkeyConverter.NewBech32PubkeyConverter(32, "erd")
)
// ESDTSupply represents the DTO that holds the supply values for a token
@@ -132,7 +134,7 @@ func (instance *chainSimulatorWrapper) GetNetworkAddress() string {
}
// DeploySC will deploy the provided smart contract and return its address
-func (instance *chainSimulatorWrapper) DeploySC(ctx context.Context, wasmFilePath string, ownerSK []byte, gasLimit uint64, parameters []string) (*MvxAddress, string, *data.TransactionOnNetwork) {
+func (instance *chainSimulatorWrapper) DeploySC(ctx context.Context, wasmFilePath string, ownerSK []byte, gasLimit uint64, parameters []string) (*cryptoPaymentsFramework.MvxAddress, string, *data.TransactionOnNetwork) {
networkConfig, err := instance.proxyInstance.GetNetworkConfig(ctx)
require.Nil(instance.TB, err)
@@ -164,11 +166,11 @@ func (instance *chainSimulatorWrapper) DeploySC(ctx context.Context, wasmFilePat
require.Nil(instance, err)
require.Equal(instance, transaction.TxStatusSuccess, txStatus, fmt.Sprintf("tx hash: %s,\n tx: %s", hash, string(jsonData)))
- return NewMvxAddressFromBech32(instance.TB, txResult.Logs.Events[0].Address), hash, txResult
+ return cryptoPaymentsFramework.NewMvxAddressFromBech32(instance.TB, txResult.Logs.Events[0].Address), hash, txResult
}
// UpgradeSC will upgrade the provided smart contract
-func (instance *chainSimulatorWrapper) UpgradeSC(ctx context.Context, scAddress *MvxAddress, wasmFilePath string, ownerSK []byte, gasLimit uint64, parameters []string) (string, *data.TransactionOnNetwork) {
+func (instance *chainSimulatorWrapper) UpgradeSC(ctx context.Context, scAddress *cryptoPaymentsFramework.MvxAddress, wasmFilePath string, ownerSK []byte, gasLimit uint64, parameters []string) (string, *data.TransactionOnNetwork) {
networkConfig, err := instance.proxyInstance.GetNetworkConfig(ctx)
require.Nil(instance.TB, err)
@@ -253,12 +255,12 @@ func (instance *chainSimulatorWrapper) GenerateBlocksUntilTxProcessed(ctx contex
}
// ScCall will make the provided sc call
-func (instance *chainSimulatorWrapper) ScCall(ctx context.Context, senderSK []byte, contract *MvxAddress, value string, gasLimit uint64, function string, parameters []string) (string, *data.TransactionOnNetwork, transaction.TxStatus) {
+func (instance *chainSimulatorWrapper) ScCall(ctx context.Context, senderSK []byte, contract *cryptoPaymentsFramework.MvxAddress, value string, gasLimit uint64, function string, parameters []string) (string, *data.TransactionOnNetwork, transaction.TxStatus) {
return instance.SendTx(ctx, senderSK, contract, value, gasLimit, createTxData(function, parameters))
}
// ScCallWithoutGenerateBlocks will make the provided sc call and do not trigger the generate blocks command
-func (instance *chainSimulatorWrapper) ScCallWithoutGenerateBlocks(ctx context.Context, senderSK []byte, contract *MvxAddress, value string, gasLimit uint64, function string, parameters []string) string {
+func (instance *chainSimulatorWrapper) ScCallWithoutGenerateBlocks(ctx context.Context, senderSK []byte, contract *cryptoPaymentsFramework.MvxAddress, value string, gasLimit uint64, function string, parameters []string) string {
return instance.SendTxWithoutGenerateBlocks(ctx, senderSK, contract, value, gasLimit, createTxData(function, parameters))
}
@@ -271,7 +273,7 @@ func createTxData(function string, parameters []string) []byte {
}
// SendTx will build and send a transaction
-func (instance *chainSimulatorWrapper) SendTx(ctx context.Context, senderSK []byte, receiver *MvxAddress, value string, gasLimit uint64, dataField []byte) (string, *data.TransactionOnNetwork, transaction.TxStatus) {
+func (instance *chainSimulatorWrapper) SendTx(ctx context.Context, senderSK []byte, receiver *cryptoPaymentsFramework.MvxAddress, value string, gasLimit uint64, dataField []byte) (string, *data.TransactionOnNetwork, transaction.TxStatus) {
hash := instance.SendTxWithoutGenerateBlocks(ctx, senderSK, receiver, value, gasLimit, dataField)
instance.GenerateBlocks(ctx, 1)
txResult, txStatus := instance.GetTransactionResult(ctx, hash)
@@ -280,7 +282,7 @@ func (instance *chainSimulatorWrapper) SendTx(ctx context.Context, senderSK []by
}
// SendTxWithoutGenerateBlocks will build and send a transaction without generating blocks
-func (instance *chainSimulatorWrapper) SendTxWithoutGenerateBlocks(ctx context.Context, senderSK []byte, receiver *MvxAddress, value string, gasLimit uint64, dataField []byte) string {
+func (instance *chainSimulatorWrapper) SendTxWithoutGenerateBlocks(ctx context.Context, senderSK []byte, receiver *cryptoPaymentsFramework.MvxAddress, value string, gasLimit uint64, dataField []byte) string {
senderPK := instance.getPublicKey(senderSK)
nonce, err := instance.getNonce(ctx, senderPK)
require.Nil(instance, err)
@@ -289,7 +291,7 @@ func (instance *chainSimulatorWrapper) SendTxWithoutGenerateBlocks(ctx context.C
}
// SendTxWithNonceWithoutGenerateBlocks will build a transaction with given nonce and send it without generating blocks
-func (instance *chainSimulatorWrapper) SendTxWithNonceWithoutGenerateBlocks(ctx context.Context, senderSK []byte, receiver *MvxAddress, nonce uint64, value string, gasLimit uint64, dataField []byte) string {
+func (instance *chainSimulatorWrapper) SendTxWithNonceWithoutGenerateBlocks(ctx context.Context, senderSK []byte, receiver *cryptoPaymentsFramework.MvxAddress, nonce uint64, value string, gasLimit uint64, dataField []byte) string {
networkConfig, err := instance.proxyInstance.GetNetworkConfig(ctx)
require.Nil(instance, err)
@@ -337,7 +339,7 @@ func (instance *chainSimulatorWrapper) FundWallets(ctx context.Context, wallets
}
// GetESDTBalance returns the balance of the esdt token for the provided address
-func (instance *chainSimulatorWrapper) GetESDTBalance(ctx context.Context, address *MvxAddress, token string) string {
+func (instance *chainSimulatorWrapper) GetESDTBalance(ctx context.Context, address *cryptoPaymentsFramework.MvxAddress, token string) string {
tokenData, err := instance.proxyInstance.GetESDTTokenData(ctx, address, token, apiCore.AccountQueryOptions{
OnFinalBlock: true,
})
@@ -426,7 +428,7 @@ func computeTransactionSignature(senderSk []byte, tx *transaction.FrontendTransa
// ExecuteVMQuery will try to execute a VM query and return the results
func (instance *chainSimulatorWrapper) ExecuteVMQuery(
ctx context.Context,
- scAddress *MvxAddress,
+ scAddress *cryptoPaymentsFramework.MvxAddress,
function string,
hexParams []string,
) [][]byte {
diff --git a/integrationTests/go/framework/common.go b/integrationTests/framework/common.go
similarity index 67%
rename from integrationTests/go/framework/common.go
rename to integrationTests/framework/common.go
index 19c8326..9971b1a 100644
--- a/integrationTests/go/framework/common.go
+++ b/integrationTests/framework/common.go
@@ -3,13 +3,18 @@ package framework
import (
"path/filepath"
"runtime"
+ "testing"
+
+ cryptoPaymentsFramework "github.com/iulianpascalau/mx-crypto-payments/integrationTests/framework"
+ "github.com/stretchr/testify/require"
)
-// PaymentGasLimit is the gas limit for the payment transaction
-const PaymentGasLimit = 50000
+// GetProxyRootPath returns the absolute path to the proxy service root path
+func GetProxyRootPath(templateFile string) string {
+ currentDir := traverse("integrationTests")
-// CallGasLimit is the gas limit for a SC call
-const CallGasLimit = 3000000
+ return filepath.Join(currentDir, "services", "proxy", templateFile)
+}
// GetContractPath returns the absolute path to the wasm file
func GetContractPath(contractName string) string {
@@ -18,11 +23,13 @@ func GetContractPath(contractName string) string {
return filepath.Join(currentDir, "contracts", contractName, contractName+".wasm")
}
-// GetProxyRootPath returns the absolute path to the proxy service root path
-func GetProxyRootPath(templateFile string) string {
- currentDir := traverse("integrationTests")
+// EnsureTestContracts test if the contracts are present in the project, if not, download them
+func EnsureTestContracts(tb testing.TB) {
+ root := traverse("integrationTests")
+ extractTarget := filepath.Join(root, "contracts")
- return filepath.Join(currentDir, "services", "proxy", templateFile)
+ err := cryptoPaymentsFramework.EnsureContractCredits(cryptoPaymentsFramework.ContractCreditsURL, extractTarget)
+ require.NoError(tb, err)
}
func traverse(upToDir string) string {
diff --git a/integrationTests/go/framework/interface.go b/integrationTests/framework/interface.go
similarity index 93%
rename from integrationTests/go/framework/interface.go
rename to integrationTests/framework/interface.go
index 22cc730..31be288 100644
--- a/integrationTests/go/framework/interface.go
+++ b/integrationTests/framework/interface.go
@@ -3,8 +3,8 @@ package framework
import (
"context"
- "github.com/iulianpascalau/mx-epoch-proxy-go/services/crypto-payment/factory"
- "github.com/iulianpascalau/mx-epoch-proxy-go/services/crypto-payment/process"
+ "github.com/iulianpascalau/mx-crypto-payments/factory"
+ "github.com/iulianpascalau/mx-crypto-payments/process"
proxyApi "github.com/iulianpascalau/mx-epoch-proxy-go/services/proxy/api"
proxyFactory "github.com/iulianpascalau/mx-epoch-proxy-go/services/proxy/factory"
"github.com/multiversx/mx-chain-core-go/data/api"
diff --git a/integrationTests/go/framework/mockCaptchaWrapper.go b/integrationTests/framework/mockCaptchaWrapper.go
similarity index 100%
rename from integrationTests/go/framework/mockCaptchaWrapper.go
rename to integrationTests/framework/mockCaptchaWrapper.go
diff --git a/integrationTests/go/framework/mockEmailSender.go b/integrationTests/framework/mockEmailSender.go
similarity index 100%
rename from integrationTests/go/framework/mockEmailSender.go
rename to integrationTests/framework/mockEmailSender.go
diff --git a/integrationTests/go/framework/proxyService.go b/integrationTests/framework/proxyService.go
similarity index 100%
rename from integrationTests/go/framework/proxyService.go
rename to integrationTests/framework/proxyService.go
diff --git a/integrationTests/go/framework/testSession.go b/integrationTests/framework/testSession.go
similarity index 100%
rename from integrationTests/go/framework/testSession.go
rename to integrationTests/framework/testSession.go
diff --git a/integrationTests/go/cryptoPayment_test.go b/integrationTests/go/cryptoPayment_test.go
deleted file mode 100644
index 70e208d..0000000
--- a/integrationTests/go/cryptoPayment_test.go
+++ /dev/null
@@ -1,314 +0,0 @@
-package _go
-
-import (
- "context"
- "encoding/hex"
- "math/big"
- "testing"
-
- "github.com/iulianpascalau/mx-epoch-proxy-go/integrationTests/go/framework"
- logger "github.com/multiversx/mx-chain-logger-go"
- "github.com/stretchr/testify/require"
-)
-
-const functionGetCredits = "getCredits"
-
-var log = logger.GetOrCreate("integrationTests")
-
-func TestPauseUnpause(t *testing.T) {
- if !framework.IsChainSimulatorIsRunning() {
- t.Skip("No chain simulator instance running found. Skipping slow test")
- }
- cryptoService := framework.NewCryptoPaymentService(t)
-
- ctx, cancel := context.WithCancel(context.Background())
- defer cancel()
-
- cryptoService.Setup(ctx, 500000)
- defer cryptoService.TearDown()
-
- cryptoService.CreateService()
- balanceProcessor := cryptoService.Components.GetBalanceProcessor()
-
- log.Info("======== 1. Check that the contract is not paused after deployment")
- checkIsPaused(ctx, cryptoService, false)
- log.Info("Done ✓")
-
- log.Info("======== 2. Pausing contract")
- _, _, txStatus := cryptoService.ChainSimulator.ScCall(
- ctx,
- cryptoService.Keys.OwnerKeys.MvxSk,
- cryptoService.ContractAddress,
- "0",
- framework.CallGasLimit,
- "pause",
- make([]string, 0),
- )
- require.Equal(t, "success", string(txStatus))
- log.Info("Done ✓")
-
- log.Info("======== 3. Check that the contract is paused")
- checkIsPaused(ctx, cryptoService, true)
- log.Info("Done ✓")
-
- log.Info("======== 4. All credit operations should not happen")
- txHash1 := cryptoService.ChainSimulator.SendTxWithoutGenerateBlocks(
- ctx,
- cryptoService.Keys.UserAKeys.MvxSk,
- cryptoService.Keys.UserAKeys.PayAddress,
- "1010000000000000000", // 1.01 EGLD
- framework.PaymentGasLimit,
- make([]byte, 0),
- )
- log.Info("sent payment tx from user A", "txHash", txHash1)
- cryptoService.ChainSimulator.GenerateBlocksUntilTxProcessed(ctx, txHash1)
-
- log.Info(" ===== 4a. Check payment addresses to have EGLD")
- checkEGLD(ctx, cryptoService, cryptoService.Keys.UserAKeys.PayAddress, "1010000000000000000") // 1.01 EGLD
- log.Info(" Done ✓")
-
- log.Info(" ===== 4b. Trying to process payments")
- err := balanceProcessor.ProcessAll(ctx)
- require.NotNil(t, err)
- log.Error("Error processing payments", "error", err)
- log.Info(" Done ✓")
-
- log.Info(" ===== 4c. Generate blocks until the payments are completed")
- cryptoService.ChainSimulator.GenerateBlocks(ctx, 12)
- log.Info(" Done ✓")
-
- log.Info(" ===== 4d. Check payment addresses to have the same amount of EGLD")
- checkEGLD(ctx, cryptoService, cryptoService.Keys.UserAKeys.PayAddress, "1010000000000000000") // 1.01 EGLD
- log.Info(" Done ✓")
-
- log.Info(" ===== 4e. Credits should not change")
- checkCredits(ctx, cryptoService, cryptoService.Keys.UserAKeys.ID, 0)
- log.Info(" Done ✓")
- log.Info("Done ✓")
-
- log.Info("======== 5. Unpausing contract")
- _, _, txStatus = cryptoService.ChainSimulator.ScCall(
- ctx,
- cryptoService.Keys.OwnerKeys.MvxSk,
- cryptoService.ContractAddress,
- "0",
- framework.CallGasLimit,
- "unpause",
- make([]string, 0),
- )
- require.Equal(t, "success", string(txStatus))
- log.Info("Done ✓")
-
- log.Info("======== 6. Check that the contract is unpaused")
- checkIsPaused(ctx, cryptoService, false)
- log.Info("Done ✓")
-
- log.Info("======== 7. All credit operations should happen")
- log.Info(" ===== 7a. Check payment addresses to have EGLD")
- checkEGLD(ctx, cryptoService, cryptoService.Keys.UserAKeys.PayAddress, "1010000000000000000") // 1.01 EGLD
- log.Info(" Done ✓")
-
- log.Info(" ===== 7b. Trying to process payments")
- err = balanceProcessor.ProcessAll(ctx)
- require.Nil(t, err)
- log.Info(" Done ✓")
-
- log.Info(" ===== 7c. Generate blocks until the payments are completed")
- cryptoService.ChainSimulator.GenerateBlocks(ctx, 12)
- log.Info(" Done ✓")
-
- log.Info(" ===== 7d. Check payment addresses to be empty")
- checkEGLD(ctx, cryptoService, cryptoService.Keys.UserAKeys.PayAddress, "0")
- log.Info(" Done ✓")
-
- log.Info(" ===== 4e. Credits should change")
- checkCredits(ctx, cryptoService, cryptoService.Keys.UserAKeys.ID, 505000) // 500000 * 1.01
- log.Info(" Done ✓")
- log.Info("Done ✓")
-}
-
-func TestCallingSCWhenBalanceIsAvailableInSync(t *testing.T) {
- if !framework.IsChainSimulatorIsRunning() {
- t.Skip("No chain simulator instance running found. Skipping slow test")
- }
- cryptoService := framework.NewCryptoPaymentService(t)
-
- ctx, cancel := context.WithCancel(context.Background())
- defer cancel()
-
- cryptoService.Setup(ctx, 500000)
- defer cryptoService.TearDown()
-
- cryptoService.CreateService()
- balanceProcessor := cryptoService.Components.GetBalanceProcessor()
-
- log.Info("======== 1. All users initiate some payments")
- txHash1 := cryptoService.ChainSimulator.SendTxWithoutGenerateBlocks(
- ctx,
- cryptoService.Keys.UserAKeys.MvxSk,
- cryptoService.Keys.UserAKeys.PayAddress,
- "1010000000000000000", // 1.01 EGLD
- framework.PaymentGasLimit,
- make([]byte, 0),
- )
- log.Info("sent payment tx from user A", "txHash", txHash1)
-
- txHash2 := cryptoService.ChainSimulator.SendTxWithoutGenerateBlocks(
- ctx,
- cryptoService.Keys.UserBKeys.MvxSk,
- cryptoService.Keys.UserBKeys.PayAddress,
- "1999999900000000000", // 1.9999999 EGLD
- framework.PaymentGasLimit,
- make([]byte, 0),
- )
- log.Info("sent payment tx from user B", "txHash", txHash2)
-
- txHash3 := cryptoService.ChainSimulator.SendTxWithoutGenerateBlocks(
- ctx,
- cryptoService.Keys.UserCKeys.MvxSk,
- cryptoService.Keys.UserCKeys.PayAddress,
- "3000000000000000000", // 3 EGLD
- framework.PaymentGasLimit,
- make([]byte, 0),
- )
- log.Info("sent payment tx from user C", "txHash", txHash3)
-
- log.Info("======== 2. The payments are not completed yet, all contract credits should be 0")
- checkCredits(ctx, cryptoService, cryptoService.Keys.UserAKeys.ID, 0)
- checkCredits(ctx, cryptoService, cryptoService.Keys.UserBKeys.ID, 0)
- checkCredits(ctx, cryptoService, cryptoService.Keys.UserCKeys.ID, 0)
- log.Info("Done ✓")
-
- log.Info("======== 3. Generate blocks until the payments are completed")
- cryptoService.ChainSimulator.GenerateBlocksUntilTxProcessed(ctx, txHash1)
- cryptoService.ChainSimulator.GenerateBlocksUntilTxProcessed(ctx, txHash2)
- cryptoService.ChainSimulator.GenerateBlocksUntilTxProcessed(ctx, txHash3)
- log.Info("Done ✓")
-
- log.Info("======== 4. Check payment addresses to have EGLD")
- checkEGLD(ctx, cryptoService, cryptoService.Keys.UserAKeys.PayAddress, "1010000000000000000") // 1.01 EGLD
- checkEGLD(ctx, cryptoService, cryptoService.Keys.UserBKeys.PayAddress, "1999999900000000000") // 1.9999999 EGLD
- checkEGLD(ctx, cryptoService, cryptoService.Keys.UserCKeys.PayAddress, "3000000000000000000") // 3 EGLD
- log.Info("Done ✓")
-
- log.Info("======== 5. The SC call is not done, all contract credits should be 0")
- checkCredits(ctx, cryptoService, cryptoService.Keys.UserAKeys.ID, 0)
- checkCredits(ctx, cryptoService, cryptoService.Keys.UserBKeys.ID, 0)
- checkCredits(ctx, cryptoService, cryptoService.Keys.UserCKeys.ID, 0)
- log.Info("Done ✓")
-
- log.Info("======== 6. The balance processor checks & process all addresses")
- err := balanceProcessor.ProcessAll(ctx)
- require.Nil(t, err)
-
- log.Info("======== 7. Generate blocks until the payments are completed")
- cryptoService.ChainSimulator.GenerateBlocks(ctx, 12)
- log.Info("Done ✓")
-
- log.Info("======== 8. Check payment addresses to have 0 EGLD")
- checkEGLD(ctx, cryptoService, cryptoService.Keys.UserAKeys.PayAddress, "0")
- checkEGLD(ctx, cryptoService, cryptoService.Keys.UserBKeys.PayAddress, "0")
- checkEGLD(ctx, cryptoService, cryptoService.Keys.UserCKeys.PayAddress, "0")
- log.Info("Done ✓")
-
- log.Info("======== 9. The payments are completed yet, check credits")
- checkCredits(ctx, cryptoService, cryptoService.Keys.UserAKeys.ID, 505000) // 500000 * 1.01
- checkCredits(ctx, cryptoService, cryptoService.Keys.UserBKeys.ID, 999999) // 500000 * 1.9999999
- checkCredits(ctx, cryptoService, cryptoService.Keys.UserCKeys.ID, 1500000) // 500000 * 3
- log.Info("Done ✓")
-
- log.Info("======== 10. Another round of payments")
- txHash1 = cryptoService.ChainSimulator.SendTxWithoutGenerateBlocks(
- ctx,
- cryptoService.Keys.UserAKeys.MvxSk,
- cryptoService.Keys.UserAKeys.PayAddress,
- "950000000000000000", // 0.95 EGLD
- framework.PaymentGasLimit,
- make([]byte, 0),
- )
- log.Info("sent payment tx from user A", "txHash", txHash1)
-
- txHash2 = cryptoService.ChainSimulator.SendTxWithoutGenerateBlocks(
- ctx,
- cryptoService.Keys.UserBKeys.MvxSk,
- cryptoService.Keys.UserBKeys.PayAddress,
- "009999999000000000", // 0.009999999 EGLD
- framework.PaymentGasLimit,
- make([]byte, 0),
- )
- log.Info("sent payment tx from user B", "txHash", txHash2)
-
- txHash3 = cryptoService.ChainSimulator.SendTxWithoutGenerateBlocks(
- ctx,
- cryptoService.Keys.UserCKeys.MvxSk,
- cryptoService.Keys.UserCKeys.PayAddress,
- "10000000000000000", // 0.01 EGLD
- framework.PaymentGasLimit,
- make([]byte, 0),
- )
- log.Info("sent payment tx from user C", "txHash", txHash3)
-
- log.Info("======== 11. Generate blocks until the payments are completed")
- cryptoService.ChainSimulator.GenerateBlocksUntilTxProcessed(ctx, txHash1)
- cryptoService.ChainSimulator.GenerateBlocksUntilTxProcessed(ctx, txHash2)
- cryptoService.ChainSimulator.GenerateBlocksUntilTxProcessed(ctx, txHash3)
- log.Info("Done ✓")
-
- log.Info("======== 12. Check payment addresses to have EGLD")
- checkEGLD(ctx, cryptoService, cryptoService.Keys.UserAKeys.PayAddress, "950000000000000000") // 0.95 EGLD
- checkEGLD(ctx, cryptoService, cryptoService.Keys.UserBKeys.PayAddress, "9999999000000000") // 0.009999999 EGLD
- checkEGLD(ctx, cryptoService, cryptoService.Keys.UserCKeys.PayAddress, "10000000000000000") // 0.01 EGLD
- log.Info("Done ✓")
-
- log.Info("======== 13. The balance processor checks & process all addresses")
- err = balanceProcessor.ProcessAll(ctx)
- require.Nil(t, err)
-
- log.Info("======== 14. Generate blocks until the payments are completed")
- cryptoService.ChainSimulator.GenerateBlocks(ctx, 12)
- log.Info("Done ✓")
-
- log.Info("======== 15. Check payment addresses to have 0 EGLD except user B's address")
- checkEGLD(ctx, cryptoService, cryptoService.Keys.UserAKeys.PayAddress, "0")
- checkEGLD(ctx, cryptoService, cryptoService.Keys.UserBKeys.PayAddress, "9999999000000000")
- checkEGLD(ctx, cryptoService, cryptoService.Keys.UserCKeys.PayAddress, "0")
- log.Info("Done ✓")
-
- log.Info("======== 16. The payments are completed yet, check credits")
- checkCredits(ctx, cryptoService, cryptoService.Keys.UserAKeys.ID, 980000) // 500000 * 1.01 + 500000 * 0.95
- checkCredits(ctx, cryptoService, cryptoService.Keys.UserBKeys.ID, 999999) // 500000 * 1.9999999 + 0
- checkCredits(ctx, cryptoService, cryptoService.Keys.UserCKeys.ID, 1505000) // 500000 * 3 + 500000 * 0.01
- log.Info("Done ✓")
-}
-
-func checkIsPaused(ctx context.Context, service *framework.CryptoPaymentService, expected bool) {
- contractHandler := service.Components.GetContractHandler()
- isPaused, err := contractHandler.IsContractPaused(ctx)
- require.Nil(service, err)
-
- require.Equal(service, expected, isPaused)
-}
-
-func checkCredits(ctx context.Context, service *framework.CryptoPaymentService, id uint64, expectedCredits uint64) {
- result := service.ChainSimulator.ExecuteVMQuery(
- ctx,
- service.ContractAddress,
- functionGetCredits,
- []string{
- hex.EncodeToString(big.NewInt(int64(id)).Bytes()),
- },
- )
- require.NotNil(service, result)
- require.Equal(service, 1, len(result))
-
- valueAsBytes := result[0]
- credits := big.NewInt(0).SetBytes(valueAsBytes)
- require.Equal(service, expectedCredits, credits.Uint64())
-}
-
-func checkEGLD(ctx context.Context, service *framework.CryptoPaymentService, address *framework.MvxAddress, expectedEGLD string) {
- account, err := service.ChainSimulator.Proxy().GetAccount(ctx, address)
- require.Nil(service, err)
-
- require.Equal(service, expectedEGLD, account.Balance)
-}
diff --git a/integrationTests/go/framework/address.go b/integrationTests/go/framework/address.go
deleted file mode 100644
index 49ab92b..0000000
--- a/integrationTests/go/framework/address.go
+++ /dev/null
@@ -1,72 +0,0 @@
-package framework
-
-import (
- "encoding/hex"
- "testing"
-
- "github.com/multiversx/mx-chain-core-go/core/pubkeyConverter"
- sdkCore "github.com/multiversx/mx-sdk-go/core"
- "github.com/multiversx/mx-sdk-go/data"
- "github.com/stretchr/testify/require"
-)
-
-var (
- addressPubkeyConverter, _ = pubkeyConverter.NewBech32PubkeyConverter(32, "erd")
-)
-
-// MvxAddress holds the different forms a MultiversX address might have
-type MvxAddress struct {
- sdkCore.AddressHandler
- bytes []byte
- bech32 string
- hex string
-}
-
-// NewMvxAddressFromBytes return a new instance of MvxAddress from bytes
-func NewMvxAddressFromBytes(tb testing.TB, bytes []byte) *MvxAddress {
- address := &MvxAddress{
- bytes: make([]byte, len(bytes)),
- hex: hex.EncodeToString(bytes),
- AddressHandler: data.NewAddressFromBytes(bytes),
- }
-
- var err error
- copy(address.bytes, bytes)
- address.bech32, err = addressPubkeyConverter.Encode(bytes)
- require.Nil(tb, err)
-
- return address
-}
-
-// NewMvxAddressFromBech32 return a new instance of MvxAddress from the bech32 string
-func NewMvxAddressFromBech32(tb testing.TB, bech32 string) *MvxAddress {
- addressHandler, err := data.NewAddressFromBech32String(bech32)
- require.Nil(tb, err)
-
- return &MvxAddress{
- bytes: addressHandler.AddressBytes(),
- hex: hex.EncodeToString(addressHandler.AddressBytes()),
- bech32: bech32,
- AddressHandler: addressHandler,
- }
-}
-
-// Bytes returns the bytes format address
-func (address *MvxAddress) Bytes() []byte {
- return address.bytes
-}
-
-// Bech32 returns the bech32 string format address
-func (address *MvxAddress) Bech32() string {
- return address.bech32
-}
-
-// Hex returns the hex string format address
-func (address *MvxAddress) Hex() string {
- return address.hex
-}
-
-// String returns the address in bech32 format
-func (address *MvxAddress) String() string {
- return address.bech32
-}
diff --git a/integrationTests/go/framework/cryptoPaymentService.go b/integrationTests/go/framework/cryptoPaymentService.go
deleted file mode 100644
index 80e9c36..0000000
--- a/integrationTests/go/framework/cryptoPaymentService.go
+++ /dev/null
@@ -1,141 +0,0 @@
-package framework
-
-import (
- "context"
- "encoding/hex"
- "math/big"
- "path"
- "testing"
-
- "github.com/iulianpascalau/mx-epoch-proxy-go/services/crypto-payment/config"
- "github.com/iulianpascalau/mx-epoch-proxy-go/services/crypto-payment/factory"
- "github.com/multiversx/mx-sdk-go/interactors"
- "github.com/stretchr/testify/require"
-)
-
-const deployGasLimit = 20_000_000
-const callGasLimit = 40_000_000
-const minimumBalanceToCall = 0.01 // 0.01 EGLD
-
-// CryptoPaymentService will hold all elements used by the crypto-payment service
-type CryptoPaymentService struct {
- testing.TB
- Keys *KeysStore
- ChainSimulator *chainSimulatorWrapper
-
- ContractAddress *MvxAddress
- Components CryptoPaymentComponentsHandler
-}
-
-// NewCryptoPaymentService creates a new CryptoPaymentService instance
-func NewCryptoPaymentService(tb testing.TB) *CryptoPaymentService {
- args := ArgChainSimulatorWrapper{
- TB: tb,
- ProxyCacherExpirationSeconds: 600,
- ProxyMaxNoncesDelta: 7,
- }
- chainSimulator := CreateChainSimulatorWrapper(args)
- chainSimulator.GenerateBlocksUntilEpochReached(context.Background(), 1)
- cfg, err := chainSimulator.Proxy().GetNetworkConfig(context.Background())
- require.Nil(tb, err)
-
- return &CryptoPaymentService{
- TB: tb,
- Keys: NewKeysStore(tb, cfg.NumShardsWithoutMeta),
- ChainSimulator: chainSimulator,
- }
-}
-
-// Setup prepares the environment
-func (crs *CryptoPaymentService) Setup(ctx context.Context, creditsPerEGLD int64) {
- log.Info("minting tokens to the users")
- crs.ChainSimulator.FundWallets(ctx, crs.Keys.WalletsToFundOnMultiversX())
-
- log.Info("deploying contract")
- address, _, txOnNetwork := crs.ChainSimulator.DeploySC(
- ctx,
- GetContractPath("credits"),
- crs.Keys.OwnerKeys.MvxSk,
- deployGasLimit,
- []string{
- hex.EncodeToString(big.NewInt(creditsPerEGLD).Bytes()),
- },
- )
-
- log.Info("deployed the credits contract", "address", address.Bech32(), "txHash", txOnNetwork.Hash)
- crs.ContractAddress = address
-}
-
-// TearDown cleans up the test environment
-func (crs *CryptoPaymentService) TearDown() {
- crs.Components.Close()
-}
-
-// CreateService will assemble all the service processing components
-func (crs *CryptoPaymentService) CreateService() {
- w := interactors.NewWallet()
- mnemonic, err := w.GenerateMnemonic()
- require.Nil(crs, err)
-
- log.Info("generated mnemonic", "mnemonic", mnemonic)
-
- cfg := config.Config{
- Port: 0,
- WalletURL: "https://wallet",
- ExplorerURL: "https://explorer",
- ProxyURL: "",
- ContractAddress: crs.ContractAddress.Bech32(),
- CallSCGasLimit: callGasLimit,
- SCSettingsCacheInMillis: 1,
- MinimumBalanceToProcess: minimumBalanceToCall,
- TimeToProcessAddressesInSeconds: 5,
- ServiceApiKey: "service-api-key",
- }
-
- dbPath := path.Join(crs.TempDir(), "test.db")
-
- relayersKeys := make([][]byte, 0, len(crs.Keys.RelayersKeys))
- for _, relayerKey := range crs.Keys.RelayersKeys {
- relayersKeys = append(relayersKeys, relayerKey.MvxSk)
- }
-
- crs.Components, err = factory.NewComponentsHandler(
- string(mnemonic),
- dbPath,
- crs.ChainSimulator.Proxy(),
- cfg,
- relayersKeys,
- )
- require.Nil(crs, err)
-
- // Add users to DB
- var bech32Address string
-
- sqliteWrapper := crs.Components.GetSQLiteWrapper()
- crs.Keys.UserAKeys.ID, err = sqliteWrapper.Add()
- require.Nil(crs, err)
- entryA, err := sqliteWrapper.Get(crs.Keys.UserAKeys.ID)
- require.Nil(crs, err)
- bech32Address = entryA.Address
- crs.Keys.UserAKeys.PayAddress = NewMvxAddressFromBech32(crs, bech32Address)
- log.Info("registered user A", "UserA address", crs.Keys.UserAKeys.MvxAddress.Bech32(),
- "payment address", bech32Address, "contract ID", crs.Keys.UserAKeys.ID)
-
- crs.Keys.UserBKeys.ID, err = sqliteWrapper.Add()
- require.Nil(crs, err)
- entryB, err := sqliteWrapper.Get(crs.Keys.UserBKeys.ID)
- require.Nil(crs, err)
- bech32Address = entryB.Address
- crs.Keys.UserBKeys.PayAddress = NewMvxAddressFromBech32(crs, bech32Address)
- log.Info("registered user B", "UserB address", crs.Keys.UserBKeys.MvxAddress.Bech32(),
- "payment address", bech32Address, "contract ID", crs.Keys.UserBKeys.ID)
-
- crs.Keys.UserCKeys.ID, err = sqliteWrapper.Add()
- require.Nil(crs, err)
- entryC, err := sqliteWrapper.Get(crs.Keys.UserCKeys.ID)
- require.Nil(crs, err)
- bech32Address = entryC.Address
- crs.Keys.UserCKeys.PayAddress = NewMvxAddressFromBech32(crs, bech32Address)
- log.Info("registered user C", "UserC address", crs.Keys.UserCKeys.MvxAddress.Bech32(),
- "payment address", bech32Address, "contract ID", crs.Keys.UserCKeys.ID)
-}
diff --git a/integrationTests/go/framework/downloader.go b/integrationTests/go/framework/downloader.go
deleted file mode 100644
index e927cdd..0000000
--- a/integrationTests/go/framework/downloader.go
+++ /dev/null
@@ -1,130 +0,0 @@
-package framework
-
-import (
- "archive/zip"
- "fmt"
- "io"
- "net/http"
- "os"
- "path/filepath"
- "strings"
-)
-
-const (
- contractCreditsVersionTag = "v1.0.0"
- contractCreditsURL = "https://github.com/iulianpascalau/credits-contract-rs/releases/download/" + contractCreditsVersionTag + "/credits-contract.zip"
-)
-
-func init() {
- if !IsChainSimulatorIsRunning() {
- return
- }
- err := ensureContractCredits()
- if err != nil {
- fmt.Printf("WARNING: Failed to ensure credits contract: %v\n", err)
- // We deliberately panic here because if we can't get the contract, tests will fail anyway
- panic(err)
- }
-}
-
-func ensureContractCredits() error {
- root := traverse("integrationTests")
- extractTarget := filepath.Join(root, "contracts")
- contractDir := filepath.Join(extractTarget, "credits")
- contractPath := filepath.Join(contractDir, "credits.wasm")
-
- if _, err := os.Stat(contractPath); err == nil {
- // Contract exists. We could check versioning (e.g. hash) but for now existence matches intent.
- return nil
- }
-
- fmt.Printf("Downloading credits contract from %s...\n", contractCreditsURL)
- resp, err := http.Get(contractCreditsURL)
- if err != nil {
- return fmt.Errorf("failed to download contract: %w", err)
- }
- defer func() {
- _ = resp.Body.Close()
- }()
-
- if resp.StatusCode != http.StatusOK {
- return fmt.Errorf("bad status: %s", resp.Status)
- }
-
- // Create temp file
- tmpFile, err := os.CreateTemp("", "credits-contract-*.zip")
- if err != nil {
- return fmt.Errorf("failed to create temp file: %w", err)
- }
- defer func() {
- _ = os.Remove(tmpFile.Name())
- }()
-
- _, err = io.Copy(tmpFile, resp.Body)
- if err != nil {
- return fmt.Errorf("failed to write temp file: %w", err)
- }
- _ = tmpFile.Close()
-
- // Unzip
- r, err := zip.OpenReader(tmpFile.Name())
- if err != nil {
- return fmt.Errorf("failed to open zip reader: %w", err)
- }
- defer func() {
- _ = r.Close()
- }()
-
- err = os.MkdirAll(extractTarget, 0755)
-
- if err != nil {
- return fmt.Errorf("failed to create target dir: %w", err)
- }
-
- for _, f := range r.File {
- fpath := filepath.Join(extractTarget, f.Name)
-
- // ZipSlip check
- if !strings.HasPrefix(fpath, filepath.Clean(extractTarget)+string(os.PathSeparator)) {
- return fmt.Errorf("illegal file path: %s", fpath)
- }
-
- if f.FileInfo().IsDir() {
- err = os.MkdirAll(fpath, os.ModePerm)
- if err != nil {
- return err
- }
- continue
- }
-
- err = os.MkdirAll(filepath.Dir(fpath), os.ModePerm)
- if err != nil {
- return err
- }
-
- var outFile *os.File
- outFile, err = os.OpenFile(fpath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, f.Mode())
- if err != nil {
- return err
- }
-
- var rc io.ReadCloser
- rc, err = f.Open()
- if err != nil {
- _ = outFile.Close()
- return err
- }
-
- _, err = io.Copy(outFile, rc)
-
- _ = outFile.Close()
- _ = rc.Close()
-
- if err != nil {
- return err
- }
- }
-
- fmt.Println("Successfully downloaded and extracted credits contract.")
- return nil
-}
diff --git a/integrationTests/go/framework/keys.go b/integrationTests/go/framework/keys.go
deleted file mode 100644
index 9876102..0000000
--- a/integrationTests/go/framework/keys.go
+++ /dev/null
@@ -1,119 +0,0 @@
-package framework
-
-import (
- "testing"
-
- mxCrypto "github.com/multiversx/mx-chain-crypto-go"
- "github.com/stretchr/testify/require"
-)
-
-// KeysHolder holds a 2 pk-sk pairs for Mvx chain
-type KeysHolder struct {
- MvxAddress *MvxAddress
- MvxSk []byte
- ID uint64
- PayAddress *MvxAddress
-}
-
-// KeysStore will hold all the keys used in the test
-type KeysStore struct {
- testing.TB
- OwnerKeys KeysHolder
- RelayersKeys []KeysHolder
- UserAKeys KeysHolder
- UserBKeys KeysHolder
- UserCKeys KeysHolder
-}
-
-// NewKeysStore will create a KeysStore instance and generate all keys
-func NewKeysStore(
- tb testing.TB,
- numShards uint32,
-) *KeysStore {
- keysStore := &KeysStore{
- TB: tb,
- }
-
- keysStore.OwnerKeys = keysStore.generateKey(0)
- log.Info("generated owner",
- "MvX address", keysStore.OwnerKeys.MvxAddress.Bech32())
-
- for i := 0; i < int(numShards); i++ {
- relayer := keysStore.generateKey(byte(i))
- keysStore.RelayersKeys = append(keysStore.RelayersKeys, relayer)
- log.Info("generated relayer", "shard", i,
- "MvX address", relayer.MvxAddress.Bech32())
- }
-
- keysStore.UserAKeys = keysStore.generateKey(2)
- log.Info("generated user A",
- "MvX address", keysStore.UserAKeys.MvxAddress.Bech32())
-
- keysStore.UserBKeys = keysStore.generateKey(0)
- log.Info("generated user B",
- "MvX address", keysStore.UserBKeys.MvxAddress.Bech32())
-
- keysStore.UserCKeys = keysStore.generateKey(2)
- log.Info("generated user C",
- "MvX address", keysStore.UserCKeys.MvxAddress.Bech32())
-
- return keysStore
-}
-
-func (keyStore *KeysStore) getAllKeys() []KeysHolder {
- allKeys := make([]KeysHolder, 0, 100)
- allKeys = append(allKeys, keyStore.OwnerKeys)
- allKeys = append(allKeys, keyStore.RelayersKeys...)
- allKeys = append(allKeys, keyStore.UserAKeys)
- allKeys = append(allKeys, keyStore.UserBKeys)
- allKeys = append(allKeys, keyStore.UserCKeys)
-
- return allKeys
-}
-
-func (keyStore *KeysStore) generateKey(projectedShard byte) KeysHolder {
- keys := GenerateMvxPrivatePublicKey(keyStore, projectedShard)
-
- return keys
-}
-
-// WalletsToFundOnMultiversX will return the wallets to fund on MultiversX
-func (keyStore *KeysStore) WalletsToFundOnMultiversX() []string {
- allKeys := keyStore.getAllKeys()
- walletsToFund := make([]string, 0, len(allKeys))
-
- for _, key := range allKeys {
- walletsToFund = append(walletsToFund, key.MvxAddress.Bech32())
- }
-
- return walletsToFund
-}
-
-// GenerateMvxPrivatePublicKey will generate a new keys holder instance that will hold only the MultiversX generated keys
-func GenerateMvxPrivatePublicKey(tb testing.TB, projectedShard byte) KeysHolder {
- sk, pkBytes := generateSkPkInShard(tb, projectedShard)
-
- skBytes, err := sk.ToByteArray()
- require.Nil(tb, err)
-
- return KeysHolder{
- MvxSk: skBytes,
- MvxAddress: NewMvxAddressFromBytes(tb, pkBytes),
- }
-}
-
-func generateSkPkInShard(tb testing.TB, projectedShard byte) (mxCrypto.PrivateKey, []byte) {
- var sk mxCrypto.PrivateKey
- var pk mxCrypto.PublicKey
-
- for {
- sk, pk = keyGenerator.GeneratePair()
-
- pkBytes, err := pk.ToByteArray()
- require.Nil(tb, err)
-
- if pkBytes[len(pkBytes)-1] == projectedShard {
- return sk, pkBytes
- }
- }
-}
diff --git a/integrationTests/go/interface.go b/integrationTests/interface.go
similarity index 86%
rename from integrationTests/go/interface.go
rename to integrationTests/interface.go
index 1e55f25..ff67ad5 100644
--- a/integrationTests/go/interface.go
+++ b/integrationTests/interface.go
@@ -1,10 +1,10 @@
-package _go
+package integrationTests
import (
"net/http"
"testing"
- "github.com/iulianpascalau/mx-epoch-proxy-go/integrationTests/go/framework"
+ "github.com/iulianpascalau/mx-epoch-proxy-go/integrationTests/framework"
)
// SessionHandler defines the supported operations of a Session object
diff --git a/integrationTests/go/manual_flows_test.go b/integrationTests/manual_flows_test.go
similarity index 93%
rename from integrationTests/go/manual_flows_test.go
rename to integrationTests/manual_flows_test.go
index 2ab0db5..070f858 100644
--- a/integrationTests/go/manual_flows_test.go
+++ b/integrationTests/manual_flows_test.go
@@ -1,4 +1,4 @@
-package _go
+package integrationTests
import (
"context"
@@ -7,7 +7,8 @@ import (
"testing"
"time"
- "github.com/iulianpascalau/mx-epoch-proxy-go/integrationTests/go/framework"
+ cryptoPaymentsFramework "github.com/iulianpascalau/mx-crypto-payments/integrationTests/framework"
+ "github.com/iulianpascalau/mx-epoch-proxy-go/integrationTests/framework"
logger "github.com/multiversx/mx-chain-logger-go"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
@@ -20,16 +21,18 @@ func TestManualFlowsIsolation(t *testing.T) {
t.Skip("No chain simulator instance running found. Skipping slow test")
}
+ framework.EnsureTestContracts(t)
+
// 1. Setup Environment
proxyService := framework.NewProxyService(t)
- cryptoPaymentService := framework.NewCryptoPaymentService(t)
+ cryptoPaymentService := cryptoPaymentsFramework.NewCryptoPaymentService(t)
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
proxyService.Setup(ctx)
// High rate to avoid throttle issues during setup
- cryptoPaymentService.Setup(ctx, 1000)
+ cryptoPaymentService.Setup(ctx, 1000, framework.GetContractPath("credits"))
defer proxyService.TearDown()
defer cryptoPaymentService.TearDown()
diff --git a/integrationTests/go/proxy_test.go b/integrationTests/proxy_test.go
similarity index 94%
rename from integrationTests/go/proxy_test.go
rename to integrationTests/proxy_test.go
index 3e90399..dcd63de 100644
--- a/integrationTests/go/proxy_test.go
+++ b/integrationTests/proxy_test.go
@@ -1,4 +1,4 @@
-package _go
+package integrationTests
import (
"context"
@@ -6,7 +6,7 @@ import (
"net/http"
"testing"
- "github.com/iulianpascalau/mx-epoch-proxy-go/integrationTests/go/framework"
+ "github.com/iulianpascalau/mx-epoch-proxy-go/integrationTests/framework"
"github.com/stretchr/testify/require"
)
diff --git a/scripts/create_crypto_payment_service.sh b/scripts/create_crypto_payment_service.sh
deleted file mode 100755
index 5f05eb2..0000000
--- a/scripts/create_crypto_payment_service.sh
+++ /dev/null
@@ -1,46 +0,0 @@
-#!/bin/bash
-
-# Configuration
-USER_NAME="ubuntu"
-APP_NAME="crypto-payment-service"
-APP_DIR="/home/${USER_NAME}/epoch-proxy/services/crypto-payment"
-EXEC_PATH="${APP_DIR}/crypto-payment-server"
-
-# Create the service file content
-SERVICE_CONTENT="[Unit]
-Description=Mvx Crypto Payment Service Go Backend
-After=network-online.target
-
-[Service]
-User=${USER_NAME}
-WorkingDirectory=${APP_DIR}
-ExecStart=${EXEC_PATH} -log-save -log-level *:DEBUG
-Restart=always
-RestartSec=3
-
-[Install]
-WantedBy=multi-user.target
-"
-
-# Path to the systemd service file
-SERVICE_FILE="/etc/systemd/system/${APP_NAME}.service"
-
-# Write the service file
-echo "Creating systemd service file at ${SERVICE_FILE}..."
-sudo bash -c "echo '${SERVICE_CONTENT}' > ${SERVICE_FILE}"
-
-# Reload systemd daemon
-echo "Reloading systemd daemon..."
-sudo systemctl daemon-reload
-
-# Enable the service
-echo "Enabling ${APP_NAME} service..."
-sudo systemctl enable ${APP_NAME}
-
-# Start the service
-echo "Starting ${APP_NAME} service..."
-sudo systemctl start ${APP_NAME}
-
-# Show status
-echo "Service status:"
-sudo systemctl status ${APP_NAME} --no-pager
diff --git a/scripts/deploy_crypto.sh b/scripts/deploy_crypto.sh
deleted file mode 100755
index 2878fc4..0000000
--- a/scripts/deploy_crypto.sh
+++ /dev/null
@@ -1,78 +0,0 @@
-#!/bin/bash
-set -e
-
-# Configuration
-PROJECT_DIR="/home/ubuntu/epoch-proxy"
-SERVICE_NAME="crypto-payment-service"
-
-# Check argument
-BRANCH=$1
-if [ -z "$BRANCH" ]; then
- echo "Usage: $0 "
- echo "Example: $0 main"
- exit 1
-fi
-
-echo "=========================================="
-echo "Starting Crypto Payment deployment for branch: $BRANCH"
-echo "=========================================="
-
-# Navigate to project directory
-if [ ! -d "$PROJECT_DIR" ]; then
- echo "Error: Project directory $PROJECT_DIR does not exist."
- exit 1
-fi
-cd "$PROJECT_DIR"
-
-# 1. Stop Service
-echo "Step 1: Stopping service..."
-sudo systemctl stop $SERVICE_NAME || echo "Service $SERVICE_NAME not found or not running, skipping stop."
-
-# 2. Checkout Code
-echo "Step 2: Checking out code..."
-git fetch --all
-git checkout "$BRANCH"
-git pull origin "$BRANCH"
-
-# 3. Recompile Backend
-echo "Step 3: Recompiling Crypto Payment Service..."
-# Load common functions
-source ./scripts/common.sh
-
-# Ensure Go is installed
-ensure_go_installed
-GO_CMD="go"
-
-cd ./services/crypto-payment
-$GO_CMD build -v -ldflags="-X main.appVersion=$(git describe --tags --long --dirty)" -o crypto-payment-server main.go
-if [ $? -ne 0 ]; then
- echo "Build failed!"
- exit 1
-fi
-echo "Build successful."
-
-# 4. Restart Service
-echo "Step 4: Restarting service..."
-if systemctl cat $SERVICE_NAME > /dev/null 2>&1; then
- sudo systemctl start $SERVICE_NAME
-else
- echo "Service $SERVICE_NAME not found. Creating it..."
- chmod +x "$PROJECT_DIR/scripts/create_crypto_payment_service.sh"
- "$PROJECT_DIR/scripts/create_crypto_payment_service.sh"
-fi
-
-# 5. Monitor
-echo "Step 5: Monitoring status..."
-sleep 5
-
-if systemctl is-active --quiet $SERVICE_NAME; then
- echo "✅ $SERVICE_NAME is active."
-else
- echo "❌ $SERVICE_NAME failed to start."
- sudo journalctl -u $SERVICE_NAME -n 20 --no-pager
- exit 1
-fi
-
-echo "=========================================="
-echo "Deployment Finished Successfully!"
-echo "=========================================="
diff --git a/services/crypto-payment/.env.example b/services/crypto-payment/.env.example
deleted file mode 100644
index 6bde943..0000000
--- a/services/crypto-payment/.env.example
+++ /dev/null
@@ -1 +0,0 @@
-MNEMONICS=segment seed puzzle pair wear already claw course oyster melody road original vault basket chest champion dune busy police genius piece rally chalk airport
diff --git a/services/crypto-payment/SPECS.md b/services/crypto-payment/SPECS.md
deleted file mode 100644
index 4239aa8..0000000
--- a/services/crypto-payment/SPECS.md
+++ /dev/null
@@ -1,141 +0,0 @@
-# Crypto Payment Service - Feature Specification
-
-## 1. Overview
-This feature allows users of the **Mx Epoch Proxy** to upgrade their accounts from "Free" to "Premium" by making a cryptocurrency payment in eGLD on the MultiversX blockchain.
-
-The system utilizes a secure, segregated microservice (`crypto-payment`) to manage deposit addresses and relay funds to a licensing Smart Contract. This ensures that the main Proxy service never handles private keys and that the user experience is seamless (no gas required for the user's deposit transaction).
-
-## 2. Architecture
-
-The solution consists of three main components interacting asynchronously:
-
-1. **Epoch Proxy Service** (Existing): Handles the user UI and final entitlement (premium status).
-2. **Crypto Payment Service** (New Microservice):
- - **Responsibility**: Secure key management, address generation, blockchain monitoring, and transaction relaying.
- - **Security**: Runs in a restricted environment (separate VM); holds the master mnemonic.
-3. **Licensing Smart Contract**:
- - **Responsibility**: Receives funds, calculates entitlement (e.g., 1 eGLD = 1M requests), and stores the "Allowed Requests" quota for each Payment ID.
-
-## 3. Detailed Data Flow
-
-### Phase 1: Initiation
-1. **User Action**: User clicks "Upgrade to Premium" on the Proxy Dashboard.
-2. **Proxy Request**: The Proxy Backend requests a new `Payment ID` and `Address` from the internal `crypto-payment` API.
-3. **Address Generation**:
- - The `crypto-payment` service increments its internal index counter.
- - It derives a new public key/address from its master mnemonic using the HD path (e.g., `m/44'/508'/0'/0/index`).
- - It stores the `{index, address}` tuple in its local database.
- - It returns the `index` (Payment ID) to the Proxy.
-4. **Display**:
- - The Proxy links this `Payment ID` to the User in its database.
- - The Proxy calls `GET /account?id=` to retrieve the address to display to the User.
- - The Proxy displays the `address` and `numberOfRequests` to the User.
-
-### Phase 2: Payment & Monitoring
-5. **User Payment**: The user sends eGLD to the displayed unique address.
-6. **Monitoring**: The `crypto-payment` service monitors the blockchain (via Observer Nodes) for any incoming transactions to its known generated addresses.
-
-### Phase 3: Sweeping (Relayed Transaction)
-7. **Detection**: When a balance > 0 is detected on a generated address:
-8. **Construction**: The `crypto-payment` service constructs a **Relayed Transaction v3**:
- - **Inner Transaction**:
- - **Sender**: The generated deposit address.
- - **Receiver**: The Licensing Smart Contract address.
- - **Value**: The entire balance of the deposit address.
- - **Data**: `buy_credits` endpoint call, passing the `Payment ID` as an argument (e.g., `buy_credits@`).
- - **Gas Limit**: Sufficient for SC execution.
- - **Signature**: Signed by the derived private key of the deposit address.
- - **Relayer**:
- - **Sender**: The `crypto-payment` service's "Hot Wallet" (Gas Payer).
- - **Signature**: Signed by the Hot Wallet's private key.
-9. **Submission**: The transaction is broadcast to the network. The Hot Wallet pays the gas fees; the User's deposit is forwarded intact.
-
-### Phase 4: Entitlement & Sync
-10. **Smart Contract**: Executes `buy_credits`. It calculates the credit amount based on the `Value` transferred and updates its storage: `storage[payment_id] = new_total_credits`.
-11. **Synchronization**:
- - *Option A (Polling)*: The Proxy Service periodically queries the Smart Contract for the credit balance of its users' `Payment IDs`.
- - *Option B (Trigger)*: The `crypto-payment` service notifies the Proxy Service via web-hook upon successful relay.
-12. **Update**: When the Proxy Service detects an increase in credits on the SC, it updates the local `users` table:
- - `max_requests` updated to the new limit.
- - `account_type` set to `premium`.
-
-## 4. API Endpoints
-
-### 4.1. `POST /create-address`
-Generates a new deposit address.
-
-**Request:** Empty body.
-
-**Response:**
-```json
-{
- "id": 123
-}
-```
-
-### 4.2. `GET /account`
-Retrieves account details for a payment ID.
-
-**Query Parameters:**
-- `id` (required): The Payment ID (uint64).
-
-**Response:**
-```json
-{
- "address": "erd1...",
- "numberOfRequests": 1500000
-}
-```
-
-### 4.3. `GET /config`
-Retrieves public configuration required by the client/proxy.
-
-**Response:**
-```json
-{
- "walletUrl": "https://devnet-wallet.multiversx.com",
- "explorerUrl": "https://devnet-explorer.multiversx.com",
- "contractAddress": "erd1...",
- "requestsPerEGLD": 1000000,
- "isContractPaused": false
-}
-```
-
-## 5. Data Models
-
-### Proxy Database (`sqlite.db`)
-Changes to `users` table:
-- `payment_id` (Integer, Nullable): Links the user to the crypto-payment system.
-
-### Crypto Payment Database (`crypto-payment.db`)
-New SQLite database for the microservice.
-**Table: `payment_address`** (Created by `sqliteWrapper`)
-- `id` (Integer, Primary Key): The derivation index (Payment ID).
-- `address` (Text, Unique): The derived Bech32 address.
-
-## 6. Implementation Details
-- **Balance Processor**: A background process (`BalanceProcessor`) periodically scans all generated addresses for balances.
-- **Relayed Transactions**: If a balance is found, a relayed transaction is constructed and sent to the network to sweep funds to the contract.
-- **Contract Query**: The service caches (`timeCacher`) contract query results (`isPaused`, `requestsPerEgld`) to ensure performance and reduce network load.
-- **Caching**: A simple in-memory cache with a global flush strategy is used to store high-frequency data (like contract config values).
-
-## 7. Security Considerations
-- **Isolation**: The `crypto-payment` service contains the "Crown Jewels" (the Mnemonic). It must be isolated.
-- **Relayer Wallet**: The Hot Wallet key is also sensitive as it holds gas funds.
-- **Input Validation**: The Proxy must validate that the `crypto-payment` service is the only one calling its internal webhooks (if used).
-
-## 8. Configuration
-
-### Crypto Payment Service
-- `MNEMONIC` (Env variable): 24-word secret phrase for user address derivation.
-- `config.toml`:
- - `Port`: API Port (default 8080).
- - `WalletURL`: URL of the Web Wallet (e.g., `devnet-wallet.multiversx.com`).
- - `ExplorerURL`: URL of the Explorer (e.g., `devnet-explorer.multiversx.com`).
- - `ProxyURL`: URL of the MultiversX Proxy/Gateway.
- - `ContractAddress`: Address of the Licensing Smart Contract.
- - `CallSCGasLimit`: Gas limit for the relayed transaction (default 40,000,000).
- - `SCSettingsCacheInSeconds`: Cache TTL for contract queries (e.g., 60s).
- - `MinimumBalanceToProcess`: Minimum eGLD balance to trigger a sweep (e.g., 0.01).
- - `TimeToProcessAddressesInSeconds`: Interval for the Balance Processor cron job.
-- `*.pem` files in working directory: Loaded as Relayer Sk(s) for paying gas.
diff --git a/services/crypto-payment/api/handler.go b/services/crypto-payment/api/handler.go
deleted file mode 100644
index ccbddfd..0000000
--- a/services/crypto-payment/api/handler.go
+++ /dev/null
@@ -1,77 +0,0 @@
-package api
-
-import (
- "fmt"
- "net/http"
-
- "github.com/gin-gonic/gin"
- "github.com/multiversx/mx-chain-core-go/core/check"
-)
-
-// Handler holds the dependencies for the API handlers
-type Handler struct {
- storage Storage
- configProvider ConfigProvider
- accountHandler AccountHandler
-}
-
-// NewHandler creates a new Handler instance
-func NewHandler(storage Storage, configProvider ConfigProvider, accountHandler AccountHandler) (*Handler, error) {
- if check.IfNil(storage) {
- return nil, fmt.Errorf("nil storage")
- }
- if check.IfNil(configProvider) {
- return nil, fmt.Errorf("nil config provider")
- }
- if check.IfNil(accountHandler) {
- return nil, fmt.Errorf("nil account handler")
- }
- return &Handler{
- storage: storage,
- configProvider: configProvider,
- accountHandler: accountHandler,
- }, nil
-}
-
-// GetConfig returns the configuration
-func (h *Handler) GetConfig(c *gin.Context) {
- config, err := h.configProvider.GetConfig(c.Request.Context())
- if err != nil {
- c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
- return
- }
- c.JSON(http.StatusOK, config)
-}
-
-// CreateAddress generates a new address and returns its details
-func (h *Handler) CreateAddress(c *gin.Context) {
- id, err := h.storage.Add()
- if err != nil {
- c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
- return
- }
- c.JSON(http.StatusOK, gin.H{"paymentID": id})
-}
-
-// GetAccount returns the account details including address and number of requests
-func (h *Handler) GetAccount(c *gin.Context) {
- var request struct {
- ID uint64 `form:"id" binding:"required"`
- }
-
- if err := c.ShouldBindQuery(&request); err != nil {
- c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
- return
- }
-
- address, credits, err := h.accountHandler.GetAccount(c.Request.Context(), request.ID)
- if err != nil {
- c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
- return
- }
-
- c.JSON(http.StatusOK, gin.H{
- "address": address,
- "credits": credits,
- })
-}
diff --git a/services/crypto-payment/api/handler_test.go b/services/crypto-payment/api/handler_test.go
deleted file mode 100644
index 6ce98b1..0000000
--- a/services/crypto-payment/api/handler_test.go
+++ /dev/null
@@ -1,227 +0,0 @@
-package api
-
-import (
- "context"
- "encoding/json"
- "errors"
- "net/http"
- "net/http/httptest"
- "testing"
-
- "github.com/gin-gonic/gin"
- "github.com/stretchr/testify/require"
-)
-
-// mockStorage is a mock implementation of the Storage interface
-type mockStorage struct {
- addCalled int
- addID uint64
- addAddr string
- addErr error
-}
-
-func (m *mockStorage) Add() (uint64, error) {
- m.addCalled++
- return m.addID, m.addErr
-}
-
-func (m *mockStorage) IsInterfaceNil() bool {
- return m == nil
-}
-
-type mockConfigProvider struct {
- config map[string]interface{}
- err error
-}
-
-func (m *mockConfigProvider) GetConfig(_ context.Context) (map[string]interface{}, error) {
- return m.config, m.err
-}
-
-func (m *mockConfigProvider) IsInterfaceNil() bool {
- return m == nil
-}
-
-type mockAccountHandler struct {
- getAccountCalled int
- getAccountID uint64
- getAccountAddr string
- getAccountCredits uint64
- getAccountErr error
-}
-
-func (m *mockAccountHandler) GetAccount(_ context.Context, id uint64) (string, uint64, error) {
- m.getAccountCalled++
- m.getAccountID = id
- return m.getAccountAddr, m.getAccountCredits, m.getAccountErr
-}
-
-func (m *mockAccountHandler) IsInterfaceNil() bool {
- return m == nil
-}
-
-func TestNewHandler(t *testing.T) {
- t.Parallel()
-
- t.Run("nil storage", func(t *testing.T) {
- h, err := NewHandler(nil, &mockConfigProvider{}, &mockAccountHandler{})
- require.EqualError(t, err, "nil storage")
- require.Nil(t, h)
- })
-
- t.Run("nil config provider", func(t *testing.T) {
- h, err := NewHandler(&mockStorage{}, nil, &mockAccountHandler{})
- require.EqualError(t, err, "nil config provider")
- require.Nil(t, h)
- })
-
- t.Run("nil account handler", func(t *testing.T) {
- h, err := NewHandler(&mockStorage{}, &mockConfigProvider{}, nil)
- require.EqualError(t, err, "nil account handler")
- require.Nil(t, h)
- })
-
- t.Run("success", func(t *testing.T) {
- h, err := NewHandler(&mockStorage{}, &mockConfigProvider{}, &mockAccountHandler{})
- require.NoError(t, err)
- require.NotNil(t, h)
- })
-}
-
-func TestHandler_GetConfig(t *testing.T) {
- t.Parallel()
-
- storage := &mockStorage{}
- expectedConfig := map[string]interface{}{"key": "value"}
- configProvider := &mockConfigProvider{config: expectedConfig}
- h, _ := NewHandler(storage, configProvider, &mockAccountHandler{})
-
- gin.SetMode(gin.TestMode)
- w := httptest.NewRecorder()
- c, _ := gin.CreateTestContext(w)
- c.Request, _ = http.NewRequest("GET", "/config", nil)
-
- h.GetConfig(c)
-
- require.Equal(t, http.StatusOK, w.Code)
-
- var response map[string]interface{}
- err := json.Unmarshal(w.Body.Bytes(), &response)
- require.NoError(t, err)
- require.Equal(t, "value", response["key"])
-}
-
-func TestHandler_CreateAddress(t *testing.T) {
- t.Parallel()
-
- t.Run("success", func(t *testing.T) {
- expectedID := uint64(123)
- expectedAddr := "erd1test"
- storage := &mockStorage{
- addID: expectedID,
- addAddr: expectedAddr,
- }
- h, _ := NewHandler(storage, &mockConfigProvider{}, &mockAccountHandler{})
-
- gin.SetMode(gin.TestMode)
- w := httptest.NewRecorder()
- c, _ := gin.CreateTestContext(w)
-
- h.CreateAddress(c)
-
- require.Equal(t, http.StatusOK, w.Code)
-
- var response map[string]interface{}
- err := json.Unmarshal(w.Body.Bytes(), &response)
- require.NoError(t, err)
- require.Equal(t, float64(expectedID), response["paymentID"]) // json unmarshal numbers as float64
- require.Nil(t, response["address"])
- require.Equal(t, 1, storage.addCalled)
- })
-
- t.Run("storage error", func(t *testing.T) {
- expectedErr := errors.New("storage fail")
- storage := &mockStorage{
- addErr: expectedErr,
- }
- h, _ := NewHandler(storage, &mockConfigProvider{}, &mockAccountHandler{})
-
- gin.SetMode(gin.TestMode)
- w := httptest.NewRecorder()
- c, _ := gin.CreateTestContext(w)
-
- h.CreateAddress(c)
-
- require.Equal(t, http.StatusInternalServerError, w.Code)
-
- var response map[string]string
- err := json.Unmarshal(w.Body.Bytes(), &response)
- require.NoError(t, err)
- require.Equal(t, expectedErr.Error(), response["error"])
- require.Equal(t, 1, storage.addCalled)
- })
-}
-
-func TestHandler_GetAccount(t *testing.T) {
- t.Parallel()
-
- t.Run("success", func(t *testing.T) {
- expectedID := uint64(123)
- expectedAddr := "erd1test"
- expectedCredits := uint64(10)
-
- accountHandler := &mockAccountHandler{
- getAccountAddr: expectedAddr,
- getAccountCredits: expectedCredits,
- }
-
- h, _ := NewHandler(&mockStorage{}, &mockConfigProvider{}, accountHandler)
-
- gin.SetMode(gin.TestMode)
- w := httptest.NewRecorder()
- c, _ := gin.CreateTestContext(w)
- c.Request, _ = http.NewRequest("GET", "/account?id=123", nil)
-
- h.GetAccount(c)
-
- require.Equal(t, http.StatusOK, w.Code)
- require.Equal(t, expectedID, accountHandler.getAccountID)
-
- var response map[string]interface{}
- err := json.Unmarshal(w.Body.Bytes(), &response)
- require.NoError(t, err)
- require.Equal(t, expectedAddr, response["address"])
- require.Equal(t, float64(expectedCredits), response["credits"])
- })
-
- t.Run("invalid id", func(t *testing.T) {
- h, _ := NewHandler(&mockStorage{}, &mockConfigProvider{}, &mockAccountHandler{})
-
- gin.SetMode(gin.TestMode)
- w := httptest.NewRecorder()
- c, _ := gin.CreateTestContext(w)
- c.Request, _ = http.NewRequest("GET", "/account", nil)
-
- h.GetAccount(c)
-
- require.Equal(t, http.StatusBadRequest, w.Code)
- })
-
- t.Run("account handler error", func(t *testing.T) {
- expectedErr := errors.New("fail")
- accountHandler := &mockAccountHandler{
- getAccountErr: expectedErr,
- }
-
- h, _ := NewHandler(&mockStorage{}, &mockConfigProvider{}, accountHandler)
-
- gin.SetMode(gin.TestMode)
- w := httptest.NewRecorder()
- c, _ := gin.CreateTestContext(w)
- c.Request, _ = http.NewRequest("GET", "/account?id=123", nil)
-
- h.GetAccount(c)
-
- require.Equal(t, http.StatusInternalServerError, w.Code)
- })
-}
diff --git a/services/crypto-payment/api/httpServer.go b/services/crypto-payment/api/httpServer.go
deleted file mode 100644
index 4180560..0000000
--- a/services/crypto-payment/api/httpServer.go
+++ /dev/null
@@ -1,76 +0,0 @@
-package api
-
-import (
- "context"
- "fmt"
- "net"
- "net/http"
- "time"
-
- "github.com/gin-gonic/gin"
- logger "github.com/multiversx/mx-chain-logger-go"
-)
-
-var log = logger.GetOrCreate("api")
-
-// HTTPServer defines the specific implementation for the HTTP server
-type httpServer struct {
- server *http.Server
-}
-
-// NewHTTPServer creates a new instance of httpServer
-func NewHTTPServer(handler APIHandler, port int, serviceApiKey string) *httpServer {
- router := gin.Default()
-
- // Public endpoints
- router.GET("/config", handler.GetConfig)
-
- // Protected endpoints
- protected := router.Group("/")
- if len(serviceApiKey) > 0 {
- middleware := NewAuthenticationMiddleware(serviceApiKey)
- protected.Use(middleware.Middleware())
- }
- protected.POST("/create-address", handler.CreateAddress)
- protected.GET("/account", handler.GetAccount)
-
- server := &http.Server{
- Addr: fmt.Sprintf(":%d", port),
- Handler: router,
- }
-
- return &httpServer{server: server}
-}
-
-// Start launches the HTTP server in a separate goroutine
-func (s *httpServer) Start() error {
- listener, err := net.Listen("tcp", s.server.Addr)
- if err != nil {
- return err
- }
-
- // Update the server address to reflect the actual port (useful if port was 0)
- s.server.Addr = listener.Addr().String()
-
- go func() {
- log.Info("starting HTTP server", "address", s.server.Addr)
- errServe := s.server.Serve(listener)
- if errServe != nil && errServe != http.ErrServerClosed {
- log.Error("HTTP server stopped unexpectedly", "error", errServe)
- }
- }()
-
- return nil
-}
-
-// GetAddress returns the address of the HTTP server
-func (s *httpServer) GetAddress() string {
- return s.server.Addr
-}
-
-// Close gracefully shuts down the HTTP server
-func (s *httpServer) Close() error {
- ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
- defer cancel()
- return s.server.Shutdown(ctx)
-}
diff --git a/services/crypto-payment/api/httpServer_test.go b/services/crypto-payment/api/httpServer_test.go
deleted file mode 100644
index 69c7131..0000000
--- a/services/crypto-payment/api/httpServer_test.go
+++ /dev/null
@@ -1,57 +0,0 @@
-package api
-
-import (
- "net/http"
- "strings"
- "testing"
- "time"
-
- "github.com/stretchr/testify/require"
-)
-
-func TestHTTPServer_StartAndClose(t *testing.T) {
- t.Parallel()
-
- storage := &mockStorage{}
- h, _ := NewHandler(storage, &mockConfigProvider{config: map[string]interface{}{"key": "value"}}, &mockAccountHandler{})
-
- // Use port 0 to let the OS assign a free port
- server := NewHTTPServer(h, 0, "test-api-key")
-
- // Start the server
- err := server.Start()
- require.NoError(t, err)
-
- // The address should now be updated with the actual port
- addr := server.GetAddress()
- require.NotEmpty(t, addr)
- require.False(t, strings.HasSuffix(addr, ":0"))
-
- // Create a request to the ping endpoint
- client := &http.Client{}
-
- // Wait a bit for goroutine to pick up
- time.Sleep(100 * time.Millisecond)
-
- url := "http://" + addr + "/config"
- if strings.HasPrefix(addr, ":") {
- url = "http://localhost" + addr + "/config"
- } else if strings.HasPrefix(addr, "0.0.0.0") {
- url = strings.Replace(url, "0.0.0.0", "localhost", 1)
- }
-
- req, err := http.NewRequest("GET", url, nil)
- require.NoError(t, err)
-
- resp, err := client.Do(req)
- require.NoError(t, err)
- defer func() {
- _ = resp.Body.Close()
- }()
-
- require.Equal(t, http.StatusOK, resp.StatusCode)
-
- // Close the server
- err = server.Close()
- require.NoError(t, err)
-}
diff --git a/services/crypto-payment/api/interface.go b/services/crypto-payment/api/interface.go
deleted file mode 100644
index e4c033a..0000000
--- a/services/crypto-payment/api/interface.go
+++ /dev/null
@@ -1,32 +0,0 @@
-package api
-
-import (
- "context"
-
- "github.com/gin-gonic/gin"
-)
-
-// Storage defines the operations required from the storage layer
-type Storage interface {
- Add() (uint64, error)
- IsInterfaceNil() bool
-}
-
-// ConfigProvider defines the operations required to fetch configuration
-type ConfigProvider interface {
- GetConfig(ctx context.Context) (map[string]interface{}, error)
- IsInterfaceNil() bool
-}
-
-// AccountHandler acts as a middleman between the API and the data/contract layers
-type AccountHandler interface {
- GetAccount(ctx context.Context, id uint64) (string, uint64, error)
- IsInterfaceNil() bool
-}
-
-// APIHandler defines the operations supported by the API
-type APIHandler interface {
- GetConfig(c *gin.Context)
- CreateAddress(c *gin.Context)
- GetAccount(c *gin.Context)
-}
diff --git a/services/crypto-payment/api/middleware.go b/services/crypto-payment/api/middleware.go
deleted file mode 100644
index f489a10..0000000
--- a/services/crypto-payment/api/middleware.go
+++ /dev/null
@@ -1,41 +0,0 @@
-package api
-
-import (
- "crypto/subtle"
- "net/http"
-
- "github.com/gin-gonic/gin"
-)
-
-const serviceApiKeyHeader = "X-Service-Api-Key"
-
-// AuthenticationMiddleware handles the authentication for the API
-type AuthenticationMiddleware struct {
- expectedApiKey string
-}
-
-// NewAuthenticationMiddleware creates a new AuthenticationMiddleware instance
-func NewAuthenticationMiddleware(expectedApiKey string) *AuthenticationMiddleware {
- return &AuthenticationMiddleware{
- expectedApiKey: expectedApiKey,
- }
-}
-
-// Middleware returns the gin middleware function
-func (am *AuthenticationMiddleware) Middleware() gin.HandlerFunc {
- return func(c *gin.Context) {
- apiKey := c.GetHeader(serviceApiKeyHeader)
- if len(apiKey) == 0 {
- c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"error": "missing API key"})
- return
- }
-
- // Constant time comparison to prevent timing attacks
- if subtle.ConstantTimeCompare([]byte(apiKey), []byte(am.expectedApiKey)) != 1 {
- c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"error": "invalid API key"})
- return
- }
-
- c.Next()
- }
-}
diff --git a/services/crypto-payment/api/middleware_test.go b/services/crypto-payment/api/middleware_test.go
deleted file mode 100644
index ba601da..0000000
--- a/services/crypto-payment/api/middleware_test.go
+++ /dev/null
@@ -1,53 +0,0 @@
-package api
-
-import (
- "net/http"
- "net/http/httptest"
- "testing"
-
- "github.com/gin-gonic/gin"
- "github.com/stretchr/testify/require"
-)
-
-func TestAuthenticationMiddleware(t *testing.T) {
- t.Parallel()
-
- expectedKey := "test-key"
- middleware := NewAuthenticationMiddleware(expectedKey)
-
- setupRouter := func() *gin.Engine {
- gin.SetMode(gin.TestMode)
- r := gin.New()
- r.Use(middleware.Middleware())
- r.GET("/test", func(c *gin.Context) {
- c.Status(http.StatusOK)
- })
- return r
- }
-
- t.Run("missing key", func(t *testing.T) {
- r := setupRouter()
- w := httptest.NewRecorder()
- req, _ := http.NewRequest("GET", "/test", nil)
- r.ServeHTTP(w, req)
- require.Equal(t, http.StatusUnauthorized, w.Code)
- })
-
- t.Run("invalid key", func(t *testing.T) {
- r := setupRouter()
- w := httptest.NewRecorder()
- req, _ := http.NewRequest("GET", "/test", nil)
- req.Header.Set("X-Service-Api-Key", "wrong-key")
- r.ServeHTTP(w, req)
- require.Equal(t, http.StatusUnauthorized, w.Code)
- })
-
- t.Run("valid key", func(t *testing.T) {
- r := setupRouter()
- w := httptest.NewRecorder()
- req, _ := http.NewRequest("GET", "/test", nil)
- req.Header.Set("X-Service-Api-Key", expectedKey)
- r.ServeHTTP(w, req)
- require.Equal(t, http.StatusOK, w.Code)
- })
-}
diff --git a/services/crypto-payment/common/dtos.go b/services/crypto-payment/common/dtos.go
deleted file mode 100644
index 0acbe9a..0000000
--- a/services/crypto-payment/common/dtos.go
+++ /dev/null
@@ -1,7 +0,0 @@
-package common
-
-// BalanceEntry represents a record for a certain ID with an addres
-type BalanceEntry struct {
- ID uint64
- Address string
-}
diff --git a/services/crypto-payment/config.toml.example b/services/crypto-payment/config.toml.example
deleted file mode 100644
index afc481e..0000000
--- a/services/crypto-payment/config.toml.example
+++ /dev/null
@@ -1,23 +0,0 @@
-Port = 8081
-
-# WalletURL represents the wallet HTTP address
-WalletURL = "devnet-wallet.multiversx.com"
-
-# ExplorerURL represents the explorer HTTP address
-ExplorerURL = "devnet-explorer.multiversx.com"
-
-# ProxyURL represents the proxy URL for the API
-ProxyURL = "https://devnet-gateway.multiversx.com"
-
-ContractAddress = "erd1qqqqqqqqqqqqqpgqc6u0p4kfkr5ekcrae86m6knx46gr36khrqqqhf96zw"
-
-CallSCGasLimit = 40000000
-
-SCSettingsCacheInMillis = 60000
-
-MinimumBalanceToProcess = 0.01
-
-TimeToProcessAddressesInSeconds = 60
-
-# ServiceApiKey represents the shared secret for API authentication
-ServiceApiKey = "secure-random-key"
\ No newline at end of file
diff --git a/services/crypto-payment/config/config.go b/services/crypto-payment/config/config.go
deleted file mode 100644
index 9cdcf7d..0000000
--- a/services/crypto-payment/config/config.go
+++ /dev/null
@@ -1,15 +0,0 @@
-package config
-
-// Config specify all config options this service will use
-type Config struct {
- Port uint64
- WalletURL string
- ExplorerURL string
- ProxyURL string
- ContractAddress string
- CallSCGasLimit uint64
- SCSettingsCacheInMillis uint32
- MinimumBalanceToProcess float64
- TimeToProcessAddressesInSeconds uint32
- ServiceApiKey string
-}
diff --git a/services/crypto-payment/config/tomlConfig_test.go b/services/crypto-payment/config/tomlConfig_test.go
deleted file mode 100644
index c8653da..0000000
--- a/services/crypto-payment/config/tomlConfig_test.go
+++ /dev/null
@@ -1,53 +0,0 @@
-package config
-
-import (
- "testing"
-
- "github.com/pelletier/go-toml"
- "github.com/stretchr/testify/assert"
-)
-
-func TestConfig(t *testing.T) {
- t.Parallel()
-
- testString := `
-Port = 8080
-
-# WalletURL represents the wallet HTTP address
-WalletURL = "devnet-wallet.multiversx.com"
-
-# ExplorerURL represents the explorer HTTP address
-ExplorerURL = "devnet-explorer.multiversx.com"
-
-# ProxyURL represents the proxy URL for the API
-ProxyURL = "https://devnet-gateway.multiversx.com"
-
-ContractAddress = "erd1qqqqqqqqqqqqqpgqc6u0p4kfkr5ekcrae86m6knx46gr36khrqqqhf96zw"
-
-CallSCGasLimit = 40000000
-
-SCSettingsCacheInMillis = 60000
-
-MinimumBalanceToProcess = 0.01
-
-TimeToProcessAddressesInSeconds = 60
-`
-
- expectedCfg := Config{
- Port: 8080,
- WalletURL: "devnet-wallet.multiversx.com",
- ExplorerURL: "devnet-explorer.multiversx.com",
- ProxyURL: "https://devnet-gateway.multiversx.com",
- ContractAddress: "erd1qqqqqqqqqqqqqpgqc6u0p4kfkr5ekcrae86m6knx46gr36khrqqqhf96zw",
- CallSCGasLimit: 40000000,
- SCSettingsCacheInMillis: 60000,
- MinimumBalanceToProcess: 0.01,
- TimeToProcessAddressesInSeconds: 60,
- }
-
- cfg := Config{}
-
- err := toml.Unmarshal([]byte(testString), &cfg)
- assert.Nil(t, err)
- assert.Equal(t, expectedCfg, cfg)
-}
diff --git a/services/crypto-payment/crypto/errors.go b/services/crypto-payment/crypto/errors.go
deleted file mode 100644
index ec4d9d9..0000000
--- a/services/crypto-payment/crypto/errors.go
+++ /dev/null
@@ -1,6 +0,0 @@
-package crypto
-
-import "errors"
-
-var errNilWallet = errors.New("nil wallet")
-var errEmptyMnemonic = errors.New("empty mnemonic")
diff --git a/services/crypto-payment/crypto/interface.go b/services/crypto-payment/crypto/interface.go
deleted file mode 100644
index 78dff3d..0000000
--- a/services/crypto-payment/crypto/interface.go
+++ /dev/null
@@ -1,12 +0,0 @@
-package crypto
-
-import (
- "github.com/multiversx/mx-sdk-go/core"
- "github.com/multiversx/mx-sdk-go/data"
-)
-
-// Wallet defines the operations of an entity able to manipulate wallet-sensitive data
-type Wallet interface {
- GetPrivateKeyFromMnemonic(mnemonic data.Mnemonic, account, addressIndex uint32) []byte
- GetAddressFromPrivateKey(privateKeyBytes []byte) (core.AddressHandler, error)
-}
diff --git a/services/crypto-payment/crypto/multipleKeysHandler.go b/services/crypto-payment/crypto/multipleKeysHandler.go
deleted file mode 100644
index 7a9bc84..0000000
--- a/services/crypto-payment/crypto/multipleKeysHandler.go
+++ /dev/null
@@ -1,70 +0,0 @@
-package crypto
-
-import (
- "fmt"
-
- "github.com/multiversx/mx-chain-core-go/core/check"
- "github.com/multiversx/mx-chain-crypto-go/signing"
- "github.com/multiversx/mx-chain-crypto-go/signing/ed25519"
- "github.com/multiversx/mx-chain-crypto-go/signing/ed25519/singlesig"
- "github.com/multiversx/mx-sdk-go/data"
-)
-
-const account uint32 = 0
-
-var singleSigner = &singlesig.Ed25519Signer{}
-var suite = ed25519.NewEd25519()
-var keyGenerator = signing.NewKeyGenerator(suite)
-
-type multipleKeysHandler struct {
- mnemonics data.Mnemonic
- wallet Wallet
-}
-
-// NewMultipleKeysHandler creates a new instance of multipleKeysHandler able to manage multiple (private, public) keys
-func NewMultipleKeysHandler(wallet Wallet, mnemonic string) (*multipleKeysHandler, error) {
- if check.IfNilReflect(wallet) {
- return nil, errNilWallet
- }
- if len(mnemonic) == 0 {
- return nil, errEmptyMnemonic
- }
-
- return &multipleKeysHandler{
- wallet: wallet,
- mnemonics: data.Mnemonic(mnemonic),
- }, nil
-}
-
-// GetBech32AddressAtIndex returns the address at the given index in bech32 format
-func (handler *multipleKeysHandler) GetBech32AddressAtIndex(index uint32) (string, error) {
-
- privateKey := handler.wallet.GetPrivateKeyFromMnemonic(handler.mnemonics, account, index)
- address, err := handler.wallet.GetAddressFromPrivateKey(privateKey)
- if err != nil {
- return "", fmt.Errorf("failed to get address from private key: %w", err)
- }
-
- bechAddress, err := address.AddressAsBech32String()
- if err != nil {
- return "", fmt.Errorf("failed to convert address to bech32 string: %w", err)
- }
-
- return bechAddress, nil
-}
-
-// Sign signs the given data with the private key at index
-func (handler *multipleKeysHandler) Sign(index uint32, msg []byte) ([]byte, error) {
- privateKeyBytes := handler.wallet.GetPrivateKeyFromMnemonic(handler.mnemonics, account, index)
- privateKey, err := keyGenerator.PrivateKeyFromByteArray(privateKeyBytes)
- if err != nil {
- return nil, err
- }
-
- return singleSigner.Sign(privateKey, msg)
-}
-
-// IsInterfaceNil returns true if the value under the interface is nil
-func (handler *multipleKeysHandler) IsInterfaceNil() bool {
- return handler == nil
-}
diff --git a/services/crypto-payment/crypto/multipleKeysHandler_test.go b/services/crypto-payment/crypto/multipleKeysHandler_test.go
deleted file mode 100644
index 2343aba..0000000
--- a/services/crypto-payment/crypto/multipleKeysHandler_test.go
+++ /dev/null
@@ -1,214 +0,0 @@
-package crypto
-
-import (
- "bytes"
- "errors"
- "testing"
-
- "github.com/iulianpascalau/mx-epoch-proxy-go/services/crypto-payment/testsCommon"
- logger "github.com/multiversx/mx-chain-logger-go"
- "github.com/multiversx/mx-sdk-go/core"
- "github.com/multiversx/mx-sdk-go/data"
- "github.com/stretchr/testify/assert"
- "github.com/stretchr/testify/require"
-)
-
-var log = logger.GetOrCreate("test")
-
-// mockAddress is a mock implementation of core.AddressHandler
-type mockAddress struct {
- addressAsBech32String func() (string, error)
- addressBytes func() []byte
- addressSlice func() [32]byte
- isValid func() bool
- pretty func() string
- isInterfaceNil func() bool
-}
-
-func (m *mockAddress) AddressAsBech32String() (string, error) {
- return m.addressAsBech32String()
-}
-
-func (m *mockAddress) AddressBytes() []byte {
- if m.addressBytes != nil {
- return m.addressBytes()
- }
- return nil
-}
-
-func (m *mockAddress) AddressSlice() [32]byte {
- if m.addressSlice != nil {
- return m.addressSlice()
- }
- return [32]byte{}
-}
-
-func (m *mockAddress) IsValid() bool {
- if m.isValid != nil {
- return m.isValid()
- }
- return true
-}
-
-func (m *mockAddress) Pretty() string {
- if m.pretty != nil {
- return m.pretty()
- }
- return ""
-}
-
-func (m *mockAddress) IsInterfaceNil() bool {
- if m.isInterfaceNil != nil {
- return m.isInterfaceNil()
- }
- return false
-}
-
-func TestNewMultipleKeysHandler(t *testing.T) {
- t.Parallel()
-
- t.Run("nil wallet", func(t *testing.T) {
- ah, err := NewMultipleKeysHandler(nil, "mnemonic")
- require.Nil(t, ah)
- require.Equal(t, errNilWallet, err)
- require.True(t, ah.IsInterfaceNil())
- })
-
- t.Run("empty mnemonic", func(t *testing.T) {
- ah, err := NewMultipleKeysHandler(&testsCommon.WalletStub{}, "")
- require.Nil(t, ah)
- require.Equal(t, errEmptyMnemonic, err)
- require.True(t, ah.IsInterfaceNil())
- })
-
- t.Run("success", func(t *testing.T) {
- ah, err := NewMultipleKeysHandler(&testsCommon.WalletStub{}, "mnemonic")
- require.NotNil(t, ah)
- require.NoError(t, err)
- require.False(t, ah.IsInterfaceNil())
- })
-}
-
-func TestMultipleKeysHandler_GetAddressAtIndex(t *testing.T) {
- t.Parallel()
-
- expectedMnemonic := data.Mnemonic("mnemonic")
- expectedIndex := uint32(5)
- expectedProdKey := []byte("privKey")
-
- t.Run("success", func(t *testing.T) {
- mw := &testsCommon.WalletStub{
- GetPrivateKeyFromMnemonicHandler: func(mnemonic data.Mnemonic, account, addressIndex uint32) []byte {
- assert.Equal(t, expectedMnemonic, mnemonic)
- assert.Equal(t, uint32(0), account)
- assert.Equal(t, expectedIndex, addressIndex)
- return expectedProdKey
- },
- GetAddressFromPrivateKeyHandler: func(privateKeyBytes []byte) (core.AddressHandler, error) {
- assert.Equal(t, expectedProdKey, privateKeyBytes)
- return &mockAddress{
- addressAsBech32String: func() (string, error) {
- return "erd1test", nil
- },
- }, nil
- },
- }
-
- ah, err := NewMultipleKeysHandler(mw, string(expectedMnemonic))
- require.NoError(t, err)
-
- addr, err := ah.GetBech32AddressAtIndex(expectedIndex)
- require.NoError(t, err)
- require.Equal(t, "erd1test", addr)
- })
-
- t.Run("error getting address from private key", func(t *testing.T) {
- expectedErr := errors.New("conversion error")
- mw := &testsCommon.WalletStub{
- GetPrivateKeyFromMnemonicHandler: func(mnemonic data.Mnemonic, account, addressIndex uint32) []byte {
- return expectedProdKey
- },
- GetAddressFromPrivateKeyHandler: func(privateKeyBytes []byte) (core.AddressHandler, error) {
- return nil, expectedErr
- },
- }
-
- ah, err := NewMultipleKeysHandler(mw, string(expectedMnemonic))
- require.NoError(t, err)
-
- addr, err := ah.GetBech32AddressAtIndex(expectedIndex)
- require.Error(t, err)
- require.Contains(t, err.Error(), "failed to get address from private key")
- require.Contains(t, err.Error(), expectedErr.Error())
- require.Empty(t, addr)
- })
-
- t.Run("error converting to bech32", func(t *testing.T) {
- expectedErr := errors.New("bech32 error")
- mw := &testsCommon.WalletStub{
- GetPrivateKeyFromMnemonicHandler: func(mnemonic data.Mnemonic, account, addressIndex uint32) []byte {
- return expectedProdKey
- },
- GetAddressFromPrivateKeyHandler: func(privateKeyBytes []byte) (core.AddressHandler, error) {
- return &mockAddress{
- addressAsBech32String: func() (string, error) {
- return "", expectedErr
- },
- }, nil
- },
- }
-
- ah, err := NewMultipleKeysHandler(mw, string(expectedMnemonic))
- require.NoError(t, err)
-
- addr, err := ah.GetBech32AddressAtIndex(expectedIndex)
- require.Error(t, err)
- require.Contains(t, err.Error(), "failed to convert address to bech32 string")
- require.Contains(t, err.Error(), expectedErr.Error())
- require.Empty(t, addr)
- })
-}
-
-func TestMultipleKeysHandler_Sign(t *testing.T) {
- t.Parallel()
-
- expectedMnemonic := data.Mnemonic("mnemonic")
- expectedIndex := uint32(5)
- privateKeyBytes := bytes.Repeat([]byte{1}, 32)
- privateKey, err := keyGenerator.PrivateKeyFromByteArray(privateKeyBytes)
- require.Nil(t, err)
-
- publicKey := privateKey.GeneratePublic()
- publicKeyBytes, err := publicKey.ToByteArray()
- require.Nil(t, err)
-
- address := data.NewAddressFromBytes(publicKeyBytes)
-
- mw := &testsCommon.WalletStub{
- GetPrivateKeyFromMnemonicHandler: func(mnemonic data.Mnemonic, account, addressIndex uint32) []byte {
- assert.Equal(t, expectedMnemonic, mnemonic)
- assert.Equal(t, uint32(0), account)
- assert.Equal(t, expectedIndex, addressIndex)
- return privateKeyBytes
- },
- GetAddressFromPrivateKeyHandler: func(privateKeyBytes []byte) (core.AddressHandler, error) {
- assert.Equal(t, privateKeyBytes, privateKeyBytes)
- return address, nil
- },
- }
-
- ah, err := NewMultipleKeysHandler(mw, string(expectedMnemonic))
- require.NoError(t, err)
-
- message := []byte("test")
-
- sig, err := ah.Sign(5, message)
- require.Nil(t, err)
-
- addr, _ := address.AddressAsBech32String()
-
- log.Info("Signature generated", "message", message, "signature", sig, "address", addr)
-
- err = singleSigner.Verify(publicKey, message, sig)
- assert.Nil(t, err)
-}
diff --git a/services/crypto-payment/crypto/singleKeyHandler.go b/services/crypto-payment/crypto/singleKeyHandler.go
deleted file mode 100644
index b414b44..0000000
--- a/services/crypto-payment/crypto/singleKeyHandler.go
+++ /dev/null
@@ -1,61 +0,0 @@
-package crypto
-
-import (
- mxCrypto "github.com/multiversx/mx-chain-crypto-go"
- "github.com/multiversx/mx-sdk-go/core"
- "github.com/multiversx/mx-sdk-go/data"
-)
-
-type singleKeyHandler struct {
- privateKey mxCrypto.PrivateKey
- publicKey mxCrypto.PublicKey
- bech32Address string
- address core.AddressHandler
-}
-
-// NewSingleKeyHandler creates an instance able to manage a single (private, public) key pair
-func NewSingleKeyHandler(privKeyBytes []byte) (*singleKeyHandler, error) {
- privKey, err := keyGenerator.PrivateKeyFromByteArray(privKeyBytes)
- if err != nil {
- return nil, err
- }
-
- publicKey := privKey.GeneratePublic()
- publicKeyBytes, err := publicKey.ToByteArray()
- if err != nil {
- return nil, err
- }
-
- address := data.NewAddressFromBytes(publicKeyBytes)
- bech32Address, err := address.AddressAsBech32String()
- if err != nil {
- return nil, err
- }
-
- return &singleKeyHandler{
- privateKey: privKey,
- publicKey: publicKey,
- bech32Address: bech32Address,
- address: address,
- }, nil
-}
-
-// Sign signs the given data with the inner private key
-func (handler *singleKeyHandler) Sign(msg []byte) ([]byte, error) {
- return singleSigner.Sign(handler.privateKey, msg)
-}
-
-// GetBech32Address returns the address of the inner public key in bech32 format
-func (handler *singleKeyHandler) GetBech32Address() string {
- return handler.bech32Address
-}
-
-// GetAddress returns the address of the inner public key
-func (handler *singleKeyHandler) GetAddress() core.AddressHandler {
- return handler.address
-}
-
-// IsInterfaceNil returns true if the value under the interface is nil
-func (handler *singleKeyHandler) IsInterfaceNil() bool {
- return handler == nil
-}
diff --git a/services/crypto-payment/crypto/singleKeyHandler_test.go b/services/crypto-payment/crypto/singleKeyHandler_test.go
deleted file mode 100644
index f50e5aa..0000000
--- a/services/crypto-payment/crypto/singleKeyHandler_test.go
+++ /dev/null
@@ -1,83 +0,0 @@
-package crypto
-
-import (
- "bytes"
- "testing"
-
- "github.com/multiversx/mx-sdk-go/data"
- "github.com/stretchr/testify/assert"
- "github.com/stretchr/testify/require"
-)
-
-func TestNewSingleKeyHandler(t *testing.T) {
- t.Parallel()
-
- t.Run("invalid private key", func(t *testing.T) {
- skh, err := NewSingleKeyHandler([]byte("invalid"))
- require.Nil(t, skh)
- require.Error(t, err)
- require.True(t, skh.IsInterfaceNil())
- })
-
- t.Run("success", func(t *testing.T) {
- privKeyBytes := bytes.Repeat([]byte{1}, 32)
- skh, err := NewSingleKeyHandler(privKeyBytes)
- require.NotNil(t, skh)
- require.NoError(t, err)
- require.False(t, skh.IsInterfaceNil())
- })
-}
-
-func TestSingleKeyHandler_Sign(t *testing.T) {
- t.Parallel()
-
- privateKeyBytes := bytes.Repeat([]byte{1}, 32)
- skh, err := NewSingleKeyHandler(privateKeyBytes)
- require.NoError(t, err)
-
- privateKey, err := keyGenerator.PrivateKeyFromByteArray(privateKeyBytes)
- require.NoError(t, err)
- publicKey := privateKey.GeneratePublic()
-
- msg := []byte("test message")
- signature, err := skh.Sign(msg)
- require.NoError(t, err)
- require.NotEmpty(t, signature)
-
- log.Info("Signature generated", "message", msg, "signature", signature)
-
- err = singleSigner.Verify(publicKey, msg, signature)
- assert.Nil(t, err)
-}
-
-func TestSingleKeyHandler_GetBech32Address(t *testing.T) {
- t.Parallel()
-
- privateKeyBytes := bytes.Repeat([]byte{1}, 32)
- skh, err := NewSingleKeyHandler(privateKeyBytes)
- require.NoError(t, err)
-
- // Calculate expected address
- privateKey, _ := keyGenerator.PrivateKeyFromByteArray(privateKeyBytes)
- publicKey := privateKey.GeneratePublic()
- publicKeyBytes, _ := publicKey.ToByteArray()
- address := data.NewAddressFromBytes(publicKeyBytes)
- expectedAddress, _ := address.AddressAsBech32String()
-
- assert.Equal(t, expectedAddress, skh.GetBech32Address())
-}
-
-func TestSingleKeyHandler_GetAddress(t *testing.T) {
- t.Parallel()
-
- privateKeyBytes := bytes.Repeat([]byte{1}, 32)
- skh, err := NewSingleKeyHandler(privateKeyBytes)
- require.NoError(t, err)
-
- // Calculate expected address
- privateKey, _ := keyGenerator.PrivateKeyFromByteArray(privateKeyBytes)
- publicKey := privateKey.GeneratePublic()
- publicKeyBytes, _ := publicKey.ToByteArray()
-
- assert.Equal(t, publicKeyBytes, skh.GetAddress().AddressBytes())
-}
diff --git a/services/crypto-payment/factory/componentsHandler.go b/services/crypto-payment/factory/componentsHandler.go
deleted file mode 100644
index 02e166c..0000000
--- a/services/crypto-payment/factory/componentsHandler.go
+++ /dev/null
@@ -1,196 +0,0 @@
-package factory
-
-import (
- "context"
- "fmt"
- "time"
-
- "github.com/iulianpascalau/mx-epoch-proxy-go/services/crypto-payment/api"
- "github.com/iulianpascalau/mx-epoch-proxy-go/services/crypto-payment/config"
- "github.com/iulianpascalau/mx-epoch-proxy-go/services/crypto-payment/crypto"
- "github.com/iulianpascalau/mx-epoch-proxy-go/services/crypto-payment/process"
- "github.com/iulianpascalau/mx-epoch-proxy-go/services/crypto-payment/storage"
- "github.com/iulianpascalau/mx-epoch-proxy-go/services/proxy/common"
- "github.com/multiversx/mx-chain-core-go/core/check"
- logger "github.com/multiversx/mx-chain-logger-go"
- "github.com/multiversx/mx-sdk-go/interactors"
-)
-
-var log = logger.GetOrCreate("factory")
-
-type componentsHandler struct {
- config config.Config
- wallet crypto.Wallet
- multipleKeysHandler process.MultipleKeysHandler
- sqliteWrapper SQLiteWrapper
- proxy process.BlockchainDataProvider
- timeCacher process.Cacher
- contractHandler process.ContractHandler
- configProvider api.ConfigProvider
- accountHandler api.AccountHandler
- apiHandler APIHandler
- httpServer HTTPServer
- relayersHandlers []process.SingleKeyHandler
- balanceOperator process.BalanceOperator
- balanceProcessor BalanceProcessor
-}
-
-// NewComponentsHandler creates a new instance of the components handler holding all high-level components
-func NewComponentsHandler(
- mnemonics string,
- sqlitePath string,
- proxy process.BlockchainDataProvider,
- cfg config.Config,
- relayersKeys [][]byte,
-) (*componentsHandler, error) {
- if check.IfNil(proxy) {
- return nil, errNilBlockchainDataProvider
- }
-
- ch := &componentsHandler{
- config: cfg,
- proxy: proxy,
- }
- var err error
- defer func() {
- if err != nil {
- ch.Close()
- }
- }()
-
- ch.wallet = interactors.NewWallet()
- ch.multipleKeysHandler, err = crypto.NewMultipleKeysHandler(ch.wallet, mnemonics)
- if err != nil {
- return nil, err
- }
-
- ch.sqliteWrapper, err = storage.NewSQLiteWrapper(sqlitePath, ch.multipleKeysHandler)
- if err != nil {
- return nil, err
- }
-
- ch.timeCacher = storage.NewTimeCacher(time.Duration(cfg.SCSettingsCacheInMillis) * time.Millisecond)
- ch.contractHandler, err = process.NewContractQueryHandler(
- ch.proxy,
- cfg.ContractAddress,
- ch.timeCacher,
- )
- if err != nil {
- return nil, err
- }
-
- ch.configProvider, err = process.NewConfigHandler(
- cfg.WalletURL,
- cfg.ExplorerURL,
- ch.contractHandler,
- cfg.MinimumBalanceToProcess,
- )
- if err != nil {
- return nil, err
- }
-
- ch.accountHandler, err = process.NewAccountHandler(ch.contractHandler, ch.sqliteWrapper)
- if err != nil {
- return nil, err
- }
-
- ch.apiHandler, err = api.NewHandler(ch.sqliteWrapper, ch.configProvider, ch.accountHandler)
- if err != nil {
- return nil, err
- }
-
- ch.httpServer = api.NewHTTPServer(ch.apiHandler, int(cfg.Port), cfg.ServiceApiKey)
- err = ch.httpServer.Start()
- if err != nil {
- return nil, err
- }
-
- ch.relayersHandlers = make([]process.SingleKeyHandler, 0, len(relayersKeys))
- for _, relayerKey := range relayersKeys {
- relayerHandler, errCreate := crypto.NewSingleKeyHandler(relayerKey)
- if errCreate != nil {
- return nil, errCreate
- }
- ch.relayersHandlers = append(ch.relayersHandlers, relayerHandler)
- }
-
- ch.balanceOperator, err = process.NewRelayedTxProcessor(
- proxy,
- ch.multipleKeysHandler,
- ch.relayersHandlers,
- cfg.CallSCGasLimit,
- cfg.ContractAddress,
- )
- if err != nil {
- return nil, fmt.Errorf("%w while initializing the relayedTxProcessor", err)
- }
-
- ch.balanceProcessor, err = process.NewBalanceProcessor(
- ch.sqliteWrapper,
- ch.proxy,
- ch.balanceOperator,
- ch.contractHandler,
- cfg.MinimumBalanceToProcess,
- )
- if err != nil {
- return nil, err
- }
-
- return ch, nil
-}
-
-// StartCronJobs starts all defined cron jobs
-func (ch *componentsHandler) StartCronJobs(ctx context.Context) {
- if ch == nil {
- return
- }
-
- common.CronJobStarter(ctx, func() {
- errRun := ch.balanceProcessor.ProcessAll(ctx)
- log.LogIfError(errRun)
- }, time.Duration(ch.config.TimeToProcessAddressesInSeconds)*time.Second)
-}
-
-// GetSQLiteWrapper returns the SQLiteWrapper instance
-func (ch *componentsHandler) GetSQLiteWrapper() SQLiteWrapper {
- return ch.sqliteWrapper
-}
-
-// GetBalanceProcessor returns the BalanceProcessor instance
-func (ch *componentsHandler) GetBalanceProcessor() BalanceProcessor {
- return ch.balanceProcessor
-}
-
-// GetHTTPServer returns the HTTPServer instance
-func (ch *componentsHandler) GetHTTPServer() HTTPServer {
- return ch.httpServer
-}
-
-// GetContractHandler returns the ContractHandler instance
-func (ch *componentsHandler) GetContractHandler() process.ContractHandler {
- return ch.contractHandler
-}
-
-// Close closes all the components held by the handler
-func (ch *componentsHandler) Close() {
- if ch == nil {
- return
- }
-
- if !check.IfNil(ch.sqliteWrapper) {
- err := ch.sqliteWrapper.Close()
- log.LogIfError(err)
- }
-
- if !check.IfNil(ch.timeCacher) {
- ch.timeCacher.Close()
- }
-
- if !check.IfNilReflect(ch.httpServer) {
- _ = ch.httpServer.Close()
- }
-
- if !check.IfNil(ch.balanceOperator) {
- _ = ch.balanceOperator.Close()
- }
-}
diff --git a/services/crypto-payment/factory/componentsHandler_test.go b/services/crypto-payment/factory/componentsHandler_test.go
deleted file mode 100644
index 7b8d8ba..0000000
--- a/services/crypto-payment/factory/componentsHandler_test.go
+++ /dev/null
@@ -1,141 +0,0 @@
-package factory
-
-import (
- "bytes"
- "context"
- "fmt"
- "path"
- "testing"
-
- "github.com/iulianpascalau/mx-epoch-proxy-go/services/crypto-payment/config"
- "github.com/iulianpascalau/mx-epoch-proxy-go/services/crypto-payment/testsCommon"
- "github.com/multiversx/mx-chain-core-go/core/check"
- "github.com/multiversx/mx-sdk-go/data"
- "github.com/stretchr/testify/assert"
-)
-
-func TestNewComponentsHandler(t *testing.T) {
- t.Parallel()
-
- testConfig := config.Config{
- Port: 0,
- WalletURL: "https://wallet",
- ExplorerURL: "https://explorer",
- ProxyURL: "proxy URL",
- ContractAddress: "er1test",
- CallSCGasLimit: 100,
- SCSettingsCacheInMillis: 1,
- MinimumBalanceToProcess: 0.01,
- TimeToProcessAddressesInSeconds: 1,
- ServiceApiKey: "service-api-key",
- }
- relayersKeys := [][]byte{
- bytes.Repeat([]byte{1}, 32),
- bytes.Repeat([]byte{2}, 32),
- }
-
- proxy := &testsCommon.BlockchainDataProviderStub{
- GetNetworkConfigHandler: func(ctx context.Context) (*data.NetworkConfig, error) {
- return &data.NetworkConfig{
- NumShardsWithoutMeta: 1,
- }, nil
- },
- }
-
- t.Run("nil proxy should error and close & start cron jobs should not panic", func(t *testing.T) {
- defer func() {
- r := recover()
- if r != nil {
- assert.Fail(t, fmt.Sprintf("panic: %v", r))
- }
- }()
-
- dbPath := path.Join(t.TempDir(), "data.db")
- components, err := NewComponentsHandler(
- "mnemonics",
- dbPath,
- nil,
- testConfig,
- relayersKeys,
- )
-
- assert.Nil(t, components)
- assert.Equal(t, err, errNilBlockchainDataProvider)
-
- components.StartCronJobs(context.Background())
- components.Close()
- })
- t.Run("should work", func(t *testing.T) {
- defer func() {
- r := recover()
- if r != nil {
- assert.Fail(t, fmt.Sprintf("panic: %v", r))
- }
- }()
-
- dbPath := path.Join(t.TempDir(), "data.db")
- components, err := NewComponentsHandler(
- "mnemonics",
- dbPath,
- proxy,
- testConfig,
- relayersKeys,
- )
-
- assert.NotNil(t, components)
- assert.Nil(t, err)
-
- components.StartCronJobs(context.Background())
- components.Close()
- })
-}
-
-func TestNewComponentsHandler_Getters(t *testing.T) {
- t.Parallel()
-
- testConfig := config.Config{
- Port: 0,
- WalletURL: "https://wallet",
- ExplorerURL: "https://explorer",
- ProxyURL: "proxy URL",
- ContractAddress: "er1test",
- CallSCGasLimit: 100,
- SCSettingsCacheInMillis: 1,
- MinimumBalanceToProcess: 0.01,
- TimeToProcessAddressesInSeconds: 1,
- ServiceApiKey: "service-api-key",
- }
- relayersKeys := [][]byte{
- bytes.Repeat([]byte{1}, 32),
- bytes.Repeat([]byte{2}, 32),
- }
-
- proxy := &testsCommon.BlockchainDataProviderStub{
- GetNetworkConfigHandler: func(ctx context.Context) (*data.NetworkConfig, error) {
- return &data.NetworkConfig{
- NumShardsWithoutMeta: 1,
- }, nil
- },
- }
-
- dbPath := path.Join(t.TempDir(), "data.db")
- components, _ := NewComponentsHandler(
- "mnemonics",
- dbPath,
- proxy,
- testConfig,
- relayersKeys,
- )
-
- assert.False(t, check.IfNil(components.GetSQLiteWrapper()))
- assert.Equal(t, "*storage.sqliteWrapper", fmt.Sprintf("%T", components.GetSQLiteWrapper()))
-
- assert.False(t, check.IfNil(components.GetBalanceProcessor()))
- assert.Equal(t, "*process.balanceProcessor", fmt.Sprintf("%T", components.GetBalanceProcessor()))
-
- assert.False(t, check.IfNil(components.GetContractHandler()))
- assert.Equal(t, "*process.contractQueryHandler", fmt.Sprintf("%T", components.GetContractHandler()))
-
- assert.False(t, check.IfNilReflect(components.GetHTTPServer()))
- assert.Equal(t, "*api.httpServer", fmt.Sprintf("%T", components.GetHTTPServer()))
-}
diff --git a/services/crypto-payment/factory/errors.go b/services/crypto-payment/factory/errors.go
deleted file mode 100644
index 374dcb1..0000000
--- a/services/crypto-payment/factory/errors.go
+++ /dev/null
@@ -1,5 +0,0 @@
-package factory
-
-import "errors"
-
-var errNilBlockchainDataProvider = errors.New("nil blockchain data provider")
diff --git a/services/crypto-payment/factory/interface.go b/services/crypto-payment/factory/interface.go
deleted file mode 100644
index fb2980c..0000000
--- a/services/crypto-payment/factory/interface.go
+++ /dev/null
@@ -1,37 +0,0 @@
-package factory
-
-import (
- "context"
-
- "github.com/gin-gonic/gin"
- "github.com/iulianpascalau/mx-epoch-proxy-go/services/crypto-payment/common"
-)
-
-// SQLiteWrapper defines the behavior of a SQLite database wrapper
-type SQLiteWrapper interface {
- Get(id uint64) (*common.BalanceEntry, error)
- Add() (uint64, error)
- GetAll() ([]*common.BalanceEntry, error)
- Close() error
- IsInterfaceNil() bool
-}
-
-// APIHandler defines the operations supported by the API
-type APIHandler interface {
- GetConfig(c *gin.Context)
- CreateAddress(c *gin.Context)
- GetAccount(c *gin.Context)
-}
-
-// HTTPServer defines the operations supported by the HTTP server
-type HTTPServer interface {
- Start() error
- GetAddress() string
- Close() error
-}
-
-// BalanceProcessor defines the operations supported by a component able to process balance changes
-type BalanceProcessor interface {
- ProcessAll(ctx context.Context) error
- IsInterfaceNil() bool
-}
diff --git a/services/crypto-payment/main.go b/services/crypto-payment/main.go
deleted file mode 100644
index 622d715..0000000
--- a/services/crypto-payment/main.go
+++ /dev/null
@@ -1,265 +0,0 @@
-package main
-
-import (
- "context"
- "fmt"
- "os"
- "os/signal"
- "path"
- "path/filepath"
- "runtime"
- "syscall"
- "time"
-
- "github.com/iulianpascalau/mx-epoch-proxy-go/services/crypto-payment/config"
- "github.com/iulianpascalau/mx-epoch-proxy-go/services/crypto-payment/factory"
- "github.com/joho/godotenv"
- logger "github.com/multiversx/mx-chain-logger-go"
- "github.com/multiversx/mx-chain-logger-go/file"
- "github.com/multiversx/mx-sdk-go/blockchain"
- sdkCore "github.com/multiversx/mx-sdk-go/core"
- "github.com/multiversx/mx-sdk-go/interactors"
- "github.com/pelletier/go-toml"
- "github.com/urfave/cli"
-)
-
-const (
- defaultLogsPath = "logs"
- defaultDataPath = "data"
- dbFile = "sqlite.db"
- logFilePrefix = "crypto-payment"
- logFileLifeSpanInSec = 86400 // 24h
- logFileLifeSpanInMB = 1024 // 1GB
- envFile = "./.env"
- pemFilesSearchPattern = "*.pem"
-)
-
-// appVersion should be populated at build time using ldflags
-var appVersion = "undefined"
-var fileLogging FileLoggingHandler
-
-var (
- helpTemplate = `NAME:
- {{.Name}} - {{.Usage}}
-USAGE:
- {{.HelpName}} {{if .VisibleFlags}}[global options]{{end}}
- {{if len .Authors}}
-AUTHOR:
- {{range .Authors}}{{ . }}{{end}}
- {{end}}{{if .Commands}}
-GLOBAL OPTIONS:
- {{range .VisibleFlags}}{{.}}
- {{end}}
-VERSION:
- {{.Version}}
- {{end}}
-`
-
- log = logger.GetOrCreate("crypto-payment")
-
- // logLevel defines the logger level
- logLevel = cli.StringFlag{
- Name: "log-level",
- Usage: "This flag specifies the logger `level(s)`. It can contain multiple comma-separated value. For example" +
- ", if set to *:INFO the logs for all packages will have the INFO level.",
- Value: "*:" + logger.LogInfo.String(),
- }
- // logFile is used when the log output needs to be logged in a file
- logSaveFile = cli.BoolFlag{
- Name: "log-save",
- Usage: "Boolean option for enabling log saving. If set, it will automatically save all the logs into a file.",
- }
- // workingDirectory defines a flag for the path for the working directory.
- workingDirectory = cli.StringFlag{
- Name: "working-directory",
- Usage: "This flag specifies the `directory` where the node will store databases and logs.",
- Value: "",
- }
-)
-
-func main() {
- app := cli.NewApp()
- cli.AppHelpTemplate = helpTemplate
- app.Name = "Crypto Payment Service"
- app.Version = fmt.Sprintf("%s/%s/%s-%s", appVersion, runtime.Version(), runtime.GOOS, runtime.GOARCH)
- app.Usage = "Entry point for the Crypto Payment Service"
- app.Flags = []cli.Flag{
- logLevel,
- logSaveFile,
- workingDirectory,
- }
- app.Authors = []cli.Author{
- {
- Name: "Iulian Pascalau",
- Email: "iulian.pascalau@gmail.com",
- },
- }
-
- app.Action = run
-
- defer func() {
- if fileLogging != nil {
- _ = fileLogging.Close()
- }
- }()
-
- err := app.Run(os.Args)
- if err != nil {
- log.Error(err.Error())
- os.Exit(1)
- }
-}
-
-func run(ctx *cli.Context) error {
- saveLogFile := ctx.GlobalBool(logSaveFile.Name)
- workingDir := ctx.GlobalString(workingDirectory.Name)
-
- err := logger.SetLogLevel(ctx.GlobalString(logLevel.Name))
- if err != nil {
- return err
- }
-
- err = attachFileLogger(log, saveLogFile, workingDir)
- if err != nil {
- return err
- }
-
- if fileLogging != nil {
- timeLogLifeSpan := time.Second * time.Duration(logFileLifeSpanInSec)
- sizeLogLifeSpanInMB := uint64(logFileLifeSpanInMB)
- err = fileLogging.ChangeFileLifeSpan(timeLogLifeSpan, sizeLogLifeSpanInMB)
- if err != nil {
- return err
- }
- }
-
- log.Info("starting crypto-payment service", "version", appVersion, "pid", os.Getpid())
-
- err = godotenv.Load(envFile)
- if err != nil {
- log.Warn("load env file", "error", err)
- }
-
- mnemonics := os.Getenv("MNEMONICS")
- if len(mnemonics) == 0 {
- return fmt.Errorf("missing MNEMONICS environment variable")
- }
-
- sqlitePath := path.Join(workingDir, defaultDataPath, dbFile)
-
- cfg, err := loadConfig(workingDir)
- if err != nil {
- return err
- }
-
- proxyArgs := blockchain.ArgsProxy{
- ProxyURL: cfg.ProxyURL,
- SameScState: false,
- ShouldBeSynced: false,
- FinalityCheck: true,
- AllowedDeltaToFinal: 7,
- CacheExpirationTime: time.Second * 600,
- EntityType: sdkCore.Proxy,
- }
- proxy, err := blockchain.NewProxy(proxyArgs)
- if err != nil {
- return err
- }
-
- relayersKeys, err := loadPemFiles(workingDir)
- if err != nil {
- return err
- }
-
- components, err := factory.NewComponentsHandler(mnemonics, sqlitePath, proxy, *cfg, relayersKeys)
- if err != nil {
- return err
- }
- defer components.Close()
-
- time.Sleep(time.Second)
-
- ctxRun, cancel := context.WithCancel(context.Background())
- defer cancel()
-
- components.StartCronJobs(ctxRun)
-
- log.Info("Service is running... Press Ctrl+C to stop")
-
- sigs := make(chan os.Signal, 1)
- signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)
-
- <-sigs
-
- log.Info("application closing")
-
- return nil
-}
-
-// FileLoggingHandler interface for the logger
-type FileLoggingHandler interface {
- ChangeFileLifeSpan(newDuration time.Duration, newSizeInMB uint64) error
- Close() error
-}
-
-func attachFileLogger(log logger.Logger, saveLogFile bool, workingDir string) error {
- var err error
- if saveLogFile {
- argsFileLogging := file.ArgsFileLogging{
- WorkingDir: workingDir,
- DefaultLogsPath: defaultLogsPath,
- LogFilePrefix: logFilePrefix,
- }
- fileLogging, err = file.NewFileLogging(argsFileLogging)
- if err != nil {
- return fmt.Errorf("%w creating a log file", err)
- }
- }
-
- err = logger.SetDisplayByteSlice(logger.ToHex)
- log.LogIfError(err)
-
- return nil
-}
-
-func loadConfig(workingDir string) (*config.Config, error) {
- configFile := filepath.Join(workingDir, "config.toml")
- _, err := os.Stat(configFile)
- if os.IsNotExist(err) {
- return nil, fmt.Errorf("config file not found: %s", configFile)
- }
-
- var cfg config.Config
- tree, err := toml.LoadFile(configFile)
- if err != nil {
- return nil, err
- }
- err = tree.Unmarshal(&cfg)
- if err != nil {
- return nil, err
- }
-
- return &cfg, nil
-}
-
-func loadPemFiles(workingDir string) ([][]byte, error) {
- pemFiles, err := filepath.Glob(filepath.Join(workingDir, pemFilesSearchPattern))
- if err != nil {
- return nil, err
- }
-
- allPemBytes := make([][]byte, 0, len(pemFiles))
- wallet := interactors.NewWallet()
- for _, pemFile := range pemFiles {
- pemBytes, errRead := wallet.LoadPrivateKeyFromPemFile(pemFile)
- if errRead != nil {
- return nil, fmt.Errorf("%w for file %s", errRead, pemFile)
- }
-
- log.Info("loaded pem file", "filename", pemFile)
-
- allPemBytes = append(allPemBytes, pemBytes)
- }
-
- return allPemBytes, nil
-}
diff --git a/services/crypto-payment/process/accountHandler.go b/services/crypto-payment/process/accountHandler.go
deleted file mode 100644
index abd1807..0000000
--- a/services/crypto-payment/process/accountHandler.go
+++ /dev/null
@@ -1,48 +0,0 @@
-package process
-
-import (
- "context"
- "fmt"
-
- "github.com/multiversx/mx-chain-core-go/core/check"
-)
-
-type accountHandler struct {
- contractHandler ContractHandler
- dataProvider DataProvider
-}
-
-// NewAccountHandler creates a new instance of accountHandler
-func NewAccountHandler(contractHandler ContractHandler, dataProvider DataProvider) (*accountHandler, error) {
- if check.IfNil(contractHandler) {
- return nil, fmt.Errorf("nil contract handler")
- }
- if check.IfNil(dataProvider) {
- return nil, fmt.Errorf("nil data provider")
- }
-
- return &accountHandler{
- contractHandler: contractHandler,
- dataProvider: dataProvider,
- }, nil
-}
-
-// GetAccount returns the address and the number of requests for a specific ID
-func (ah *accountHandler) GetAccount(ctx context.Context, id uint64) (string, uint64, error) {
- entry, err := ah.dataProvider.Get(id)
- if err != nil {
- return "", 0, err
- }
-
- credits, err := ah.contractHandler.GetCredits(ctx, id)
- if err != nil {
- return "", 0, err
- }
-
- return entry.Address, credits, nil
-}
-
-// IsInterfaceNil returns true if the value under the interface is nil
-func (ah *accountHandler) IsInterfaceNil() bool {
- return ah == nil
-}
diff --git a/services/crypto-payment/process/accountHandler_test.go b/services/crypto-payment/process/accountHandler_test.go
deleted file mode 100644
index f2ec797..0000000
--- a/services/crypto-payment/process/accountHandler_test.go
+++ /dev/null
@@ -1,115 +0,0 @@
-package process
-
-import (
- "context"
- "errors"
- "testing"
-
- "github.com/iulianpascalau/mx-epoch-proxy-go/services/crypto-payment/common"
- "github.com/iulianpascalau/mx-epoch-proxy-go/services/crypto-payment/testsCommon"
- "github.com/stretchr/testify/require"
-)
-
-func TestNewAccountHandler(t *testing.T) {
- t.Parallel()
-
- contractStub := &testsCommon.ContractHandlerStub{}
- dataStub := &testsCommon.DataProviderStub{}
-
- t.Run("nil contract handler should error", func(t *testing.T) {
- t.Parallel()
- ah, err := NewAccountHandler(nil, dataStub)
- require.Nil(t, ah)
- require.EqualError(t, err, "nil contract handler")
- })
-
- t.Run("nil data provider should error", func(t *testing.T) {
- t.Parallel()
- ah, err := NewAccountHandler(contractStub, nil)
- require.Nil(t, ah)
- require.EqualError(t, err, "nil data provider")
- })
-
- t.Run("success", func(t *testing.T) {
- t.Parallel()
- ah, err := NewAccountHandler(contractStub, dataStub)
- require.NotNil(t, ah)
- require.NoError(t, err)
- require.False(t, ah.IsInterfaceNil())
- })
-}
-
-func TestAccountHandler_GetAccount(t *testing.T) {
- t.Parallel()
-
- expectedID := uint64(123)
- expectedAddress := "erd1test"
- expectedCredits := uint64(50)
-
- t.Run("success", func(t *testing.T) {
- t.Parallel()
-
- contractStub := &testsCommon.ContractHandlerStub{
- GetCreditsHandler: func(ctx context.Context, id uint64) (uint64, error) {
- require.Equal(t, expectedID, id)
- return expectedCredits, nil
- },
- }
-
- dataStub := &testsCommon.DataProviderStub{
- GetHandler: func(id uint64) (*common.BalanceEntry, error) {
- require.Equal(t, expectedID, id)
- return &common.BalanceEntry{
- ID: id,
- Address: expectedAddress,
- }, nil
- },
- }
-
- ah, _ := NewAccountHandler(contractStub, dataStub)
- address, credits, err := ah.GetAccount(context.Background(), expectedID)
- require.NoError(t, err)
- require.Equal(t, expectedAddress, address)
- require.Equal(t, expectedCredits, credits)
- })
-
- t.Run("data provider error", func(t *testing.T) {
- t.Parallel()
-
- expectedErr := errors.New("db error")
- dataStub := &testsCommon.DataProviderStub{
- GetHandler: func(id uint64) (*common.BalanceEntry, error) {
- return nil, expectedErr
- },
- }
- contractStub := &testsCommon.ContractHandlerStub{}
-
- ah, _ := NewAccountHandler(contractStub, dataStub)
- address, credits, err := ah.GetAccount(context.Background(), expectedID)
- require.Equal(t, expectedErr, err)
- require.Empty(t, address)
- require.Zero(t, credits)
- })
-
- t.Run("contract handler error", func(t *testing.T) {
- t.Parallel()
-
- expectedErr := errors.New("contract error")
- dataStub := &testsCommon.DataProviderStub{
- GetHandler: func(id uint64) (*common.BalanceEntry, error) {
- return &common.BalanceEntry{Address: expectedAddress}, nil
- },
- }
- contractStub := &testsCommon.ContractHandlerStub{
- GetCreditsHandler: func(ctx context.Context, id uint64) (uint64, error) {
- return 0, expectedErr
- },
- }
-
- ah, _ := NewAccountHandler(contractStub, dataStub)
- address, credits, err := ah.GetAccount(context.Background(), expectedID)
- require.Equal(t, expectedErr, err)
- require.Empty(t, address)
- require.Zero(t, credits)
- })
-}
diff --git a/services/crypto-payment/process/balanceProcessor.go b/services/crypto-payment/process/balanceProcessor.go
deleted file mode 100644
index cccc2d8..0000000
--- a/services/crypto-payment/process/balanceProcessor.go
+++ /dev/null
@@ -1,126 +0,0 @@
-package process
-
-import (
- "context"
- "fmt"
-
- "github.com/iulianpascalau/mx-epoch-proxy-go/services/crypto-payment/common"
- "github.com/multiversx/mx-chain-core-go/core/check"
- logger "github.com/multiversx/mx-chain-logger-go"
- "github.com/multiversx/mx-sdk-go/data"
-)
-
-var log = logger.GetOrCreate("process")
-
-type balanceProcessor struct {
- dataProvider DataProvider
- blockchainDataProvider BlockchainDataProvider
- balanceOperator BalanceOperator
- contractHandler ContractHandler
- minimumBalanceToCall float64
-}
-
-// NewBalanceProcessor creates a new instance of balanceProcessor
-// NewBalanceProcessor creates a new instance of balanceProcessor
-func NewBalanceProcessor(
- dataProvider DataProvider,
- blockchainDataProvider BlockchainDataProvider,
- balanceOperator BalanceOperator,
- contractHandler ContractHandler,
- minimumBalanceToCall float64,
-) (*balanceProcessor, error) {
- if check.IfNil(dataProvider) {
- return nil, errNilDataProvider
- }
- if check.IfNil(blockchainDataProvider) {
- return nil, errNilBlockchainDataProvider
- }
- if check.IfNil(balanceOperator) {
- return nil, errNilBalanceOperator
- }
- if check.IfNil(contractHandler) {
- return nil, fmt.Errorf("nil contract handler")
- }
- if minimumBalanceToCall <= 0 {
- return nil, errInvalidMinimumBalanceToCall
- }
-
- return &balanceProcessor{
- dataProvider: dataProvider,
- blockchainDataProvider: blockchainDataProvider,
- balanceOperator: balanceOperator,
- contractHandler: contractHandler,
- minimumBalanceToCall: minimumBalanceToCall,
- }, nil
-}
-
-// ProcessAll will update the inner data provider state based on the accounts balances changes for all registered payment addresses
-func (processor *balanceProcessor) ProcessAll(ctx context.Context) error {
- isPaused, err := processor.contractHandler.IsContractPaused(ctx)
- if err != nil {
- return fmt.Errorf("%w while processing payment addresses", err)
- }
- if isPaused {
- return errContractIsPaused
- }
-
- allRows, err := processor.dataProvider.GetAll()
- if err != nil {
- return fmt.Errorf("%w when getting all records", err)
- }
-
- for _, row := range allRows {
- processor.processRecord(ctx, row)
- }
- return nil
-}
-
-func (processor *balanceProcessor) processRecord(ctx context.Context, row *common.BalanceEntry) {
- select {
- case <-ctx.Done():
- log.Debug("context done", "id", row.ID, "address", row.Address)
- return
- default:
- }
-
- addressHandler, err := data.NewAddressFromBech32String(row.Address)
- if err != nil {
- log.Trace("error converting address to AddressHandler instance", "id", row.ID, "address", row.Address, "error", err)
- return
- }
-
- accountData, err := processor.blockchainDataProvider.GetAccount(ctx, addressHandler)
- if err != nil {
- log.Debug("error fetching account data", "id", row.ID, "address", row.Address, "error", err)
- return
- }
-
- networkConfig, err := processor.blockchainDataProvider.GetNetworkConfig(ctx)
- if err != nil {
- log.Debug("error getting the network configs", "error", err)
- return
- }
-
- blockchainBalance, err := accountData.GetBalance(networkConfig.Denomination)
- if err != nil {
- log.Debug("error getting the balance", "id", row.ID, "address", row.Address, "blockchain balance", accountData.Balance, "error", err)
- return
- }
-
- if blockchainBalance < processor.minimumBalanceToCall {
- log.Trace("balance is too low", "id", row.ID, "address", row.Address, "blockchain balance", accountData.Balance)
- return
- }
-
- err = processor.balanceOperator.Process(ctx, row.ID, addressHandler, accountData.Balance, accountData.Nonce)
- if err != nil {
- log.Error("error processing balance",
- "id", row.ID, "address", row.Address, "balance", accountData.Balance,
- "nonce", accountData.Nonce, "error", err)
- }
-}
-
-// IsInterfaceNil returns true if the value under the interface is nil
-func (processor *balanceProcessor) IsInterfaceNil() bool {
- return processor == nil
-}
diff --git a/services/crypto-payment/process/balanceProcessor_test.go b/services/crypto-payment/process/balanceProcessor_test.go
deleted file mode 100644
index 0afbfd5..0000000
--- a/services/crypto-payment/process/balanceProcessor_test.go
+++ /dev/null
@@ -1,669 +0,0 @@
-package process
-
-import (
- "context"
- "errors"
- "testing"
-
- "github.com/iulianpascalau/mx-epoch-proxy-go/services/crypto-payment/common"
- "github.com/iulianpascalau/mx-epoch-proxy-go/services/crypto-payment/testsCommon"
- "github.com/multiversx/mx-chain-core-go/data/vm"
- "github.com/multiversx/mx-sdk-go/core"
- "github.com/multiversx/mx-sdk-go/data"
- "github.com/stretchr/testify/assert"
- "github.com/stretchr/testify/require"
-)
-
-func TestNewBalanceProcessor(t *testing.T) {
- t.Parallel()
-
- t.Run("nil data provider should error", func(t *testing.T) {
- t.Parallel()
-
- instance, err := NewBalanceProcessor(
- nil,
- &testsCommon.BlockchainDataProviderStub{},
- &testsCommon.BalanceOperatorStub{},
- &testsCommon.ContractHandlerStub{},
- 0.01,
- )
- assert.Nil(t, instance)
- assert.True(t, instance.IsInterfaceNil())
- assert.Equal(t, errNilDataProvider, err)
- })
- t.Run("nil blockchain data provider should error", func(t *testing.T) {
- t.Parallel()
-
- instance, err := NewBalanceProcessor(
- &testsCommon.DataProviderStub{},
- nil,
- &testsCommon.BalanceOperatorStub{},
- &testsCommon.ContractHandlerStub{},
- 0.01,
- )
- assert.Nil(t, instance)
- assert.True(t, instance.IsInterfaceNil())
- assert.Equal(t, errNilBlockchainDataProvider, err)
- })
- t.Run("nil balance operator should error", func(t *testing.T) {
- t.Parallel()
-
- instance, err := NewBalanceProcessor(
- &testsCommon.DataProviderStub{},
- &testsCommon.BlockchainDataProviderStub{},
- nil,
- &testsCommon.ContractHandlerStub{},
- 0.01,
- )
- assert.Nil(t, instance)
- assert.True(t, instance.IsInterfaceNil())
- assert.Equal(t, errNilBalanceOperator, err)
- })
- t.Run("invalid minimum balance to call should error", func(t *testing.T) {
- t.Parallel()
-
- instance, err := NewBalanceProcessor(
- &testsCommon.DataProviderStub{},
- &testsCommon.BlockchainDataProviderStub{},
- &testsCommon.BalanceOperatorStub{},
- &testsCommon.ContractHandlerStub{},
- 0,
- )
- assert.Nil(t, instance)
- assert.True(t, instance.IsInterfaceNil())
- assert.Equal(t, errInvalidMinimumBalanceToCall, err)
-
- instance, err = NewBalanceProcessor(
- &testsCommon.DataProviderStub{},
- &testsCommon.BlockchainDataProviderStub{},
- &testsCommon.BalanceOperatorStub{},
- &testsCommon.ContractHandlerStub{},
- -0.0001,
- )
- assert.Nil(t, instance)
- assert.True(t, instance.IsInterfaceNil())
- assert.Equal(t, errInvalidMinimumBalanceToCall, err)
- })
- t.Run("nil contract handler should error", func(t *testing.T) {
- t.Parallel()
-
- instance, err := NewBalanceProcessor(
- &testsCommon.DataProviderStub{},
- &testsCommon.BlockchainDataProviderStub{},
- &testsCommon.BalanceOperatorStub{},
- nil,
- 0.01,
- )
- assert.Nil(t, instance)
- assert.True(t, instance.IsInterfaceNil())
- assert.Equal(t, "nil contract handler", err.Error())
- })
- t.Run("should work", func(t *testing.T) {
- t.Parallel()
-
- instance, err := NewBalanceProcessor(
- &testsCommon.DataProviderStub{},
- &testsCommon.BlockchainDataProviderStub{},
- &testsCommon.BalanceOperatorStub{},
- &testsCommon.ContractHandlerStub{},
- 0.01,
- )
- assert.NotNil(t, instance)
- assert.False(t, instance.IsInterfaceNil())
- assert.Nil(t, err)
- })
-}
-
-func TestBalanceProcessor_ProcessAll(t *testing.T) {
- t.Parallel()
-
- expectedErr := errors.New("expected error")
-
- t.Run("contract paused should error", func(t *testing.T) {
- t.Parallel()
-
- dataProvider := &testsCommon.DataProviderStub{
- GetAllHandler: func() ([]*common.BalanceEntry, error) {
- assert.Fail(t, "should not be called")
- return nil, nil
- },
- }
-
- blockchainDataProvider := &testsCommon.BlockchainDataProviderStub{
- GetAccountHandler: func(ctx context.Context, address core.AddressHandler) (*data.Account, error) {
- assert.Fail(t, "should not be called")
-
- return &data.Account{}, nil
- },
- ExecuteVMQueryHandler: func(ctx context.Context, vmRequest *data.VmValueRequest) (*data.VmValuesResponseData, error) {
- return &data.VmValuesResponseData{
- Data: &vm.VMOutputApi{
- ReturnData: [][]byte{{1}},
- },
- }, nil
- },
- }
-
- balanceOperator := &testsCommon.BalanceOperatorStub{
- ProcessHandler: func(ctx context.Context, id uint64, sender core.AddressHandler, value string, nonce uint64) error {
- assert.Fail(t, "should not be called")
-
- return nil
- },
- }
-
- contractHandler := &testsCommon.ContractHandlerStub{
- IsContractPausedHandler: func(ctx context.Context) (bool, error) {
- return true, nil
- },
- }
-
- bp, _ := NewBalanceProcessor(
- dataProvider,
- blockchainDataProvider,
- balanceOperator,
- contractHandler,
- 0.01,
- )
-
- err := bp.ProcessAll(context.Background())
- require.Error(t, err)
- require.ErrorIs(t, err, errContractIsPaused)
- })
-
- t.Run("check paused returns error", func(t *testing.T) {
- contractHandler := &testsCommon.ContractHandlerStub{
- IsContractPausedHandler: func(ctx context.Context) (bool, error) {
- return false, expectedErr
- },
- }
-
- dataProvider := &testsCommon.DataProviderStub{}
- blockchainDataProvider := &testsCommon.BlockchainDataProviderStub{}
- balanceOperator := &testsCommon.BalanceOperatorStub{}
-
- bp, _ := NewBalanceProcessor(
- dataProvider,
- blockchainDataProvider,
- balanceOperator,
- contractHandler,
- 0.01,
- )
-
- err := bp.ProcessAll(context.Background())
- require.Error(t, err)
- require.ErrorIs(t, err, expectedErr)
- })
-
- t.Run("get all errors should error", func(t *testing.T) {
- t.Parallel()
-
- dataProvider := &testsCommon.DataProviderStub{
- GetAllHandler: func() ([]*common.BalanceEntry, error) {
- return nil, expectedErr
- },
- }
-
- blockchainDataProvider := &testsCommon.BlockchainDataProviderStub{
- GetAccountHandler: func(ctx context.Context, address core.AddressHandler) (*data.Account, error) {
- assert.Fail(t, "should not be called")
-
- return &data.Account{}, nil
- },
- ExecuteVMQueryHandler: func(ctx context.Context, vmRequest *data.VmValueRequest) (*data.VmValuesResponseData, error) {
- return &data.VmValuesResponseData{
- Data: &vm.VMOutputApi{
- ReturnData: make([][]byte, 0),
- },
- }, nil
- },
- }
-
- balanceOperator := &testsCommon.BalanceOperatorStub{
- ProcessHandler: func(ctx context.Context, id uint64, sender core.AddressHandler, value string, nonce uint64) error {
- assert.Fail(t, "should not be called")
-
- return nil
- },
- }
-
- bp, _ := NewBalanceProcessor(
- dataProvider,
- blockchainDataProvider,
- balanceOperator,
- &testsCommon.ContractHandlerStub{},
- 0.01,
- )
-
- err := bp.ProcessAll(context.Background())
- require.Error(t, err)
- require.ErrorIs(t, err, expectedErr)
- })
-
- t.Run("no rows should not process anything", func(t *testing.T) {
- t.Parallel()
-
- dataProvider := &testsCommon.DataProviderStub{
- GetAllHandler: func() ([]*common.BalanceEntry, error) {
- return make([]*common.BalanceEntry, 0), nil
- },
- }
-
- blockchainDataProvider := &testsCommon.BlockchainDataProviderStub{
- GetAccountHandler: func(ctx context.Context, address core.AddressHandler) (*data.Account, error) {
- assert.Fail(t, "should not be called")
-
- return &data.Account{}, nil
- },
- ExecuteVMQueryHandler: func(ctx context.Context, vmRequest *data.VmValueRequest) (*data.VmValuesResponseData, error) {
- return &data.VmValuesResponseData{
- Data: &vm.VMOutputApi{
- ReturnData: make([][]byte, 0),
- },
- }, nil
- },
- }
-
- balanceOperator := &testsCommon.BalanceOperatorStub{
- ProcessHandler: func(ctx context.Context, id uint64, sender core.AddressHandler, value string, nonce uint64) error {
- assert.Fail(t, "should not be called")
-
- return nil
- },
- }
-
- bp, _ := NewBalanceProcessor(
- dataProvider,
- blockchainDataProvider,
- balanceOperator,
- &testsCommon.ContractHandlerStub{},
- 0.01,
- )
-
- err := bp.ProcessAll(context.Background())
- require.NoError(t, err)
- })
-
- t.Run("context done should stop the processing", func(t *testing.T) {
- t.Parallel()
-
- dataProvider := &testsCommon.DataProviderStub{
- GetAllHandler: func() ([]*common.BalanceEntry, error) {
- return []*common.BalanceEntry{
- {
- ID: 0,
- Address: "erd19x6dfsupwtsl46nmgpxw30xcka72e4z0x3ngh6h0yjy6zwtrgh5q8px2wc",
- },
- }, nil
- },
- }
-
- blockchainDataProvider := &testsCommon.BlockchainDataProviderStub{
- GetAccountHandler: func(ctx context.Context, address core.AddressHandler) (*data.Account, error) {
- assert.Fail(t, "should not be called")
-
- return &data.Account{}, nil
- },
- ExecuteVMQueryHandler: func(ctx context.Context, vmRequest *data.VmValueRequest) (*data.VmValuesResponseData, error) {
- return &data.VmValuesResponseData{
- Data: &vm.VMOutputApi{
- ReturnData: make([][]byte, 0),
- },
- }, nil
- },
- }
-
- balanceOperator := &testsCommon.BalanceOperatorStub{
- ProcessHandler: func(ctx context.Context, id uint64, sender core.AddressHandler, value string, nonce uint64) error {
- assert.Fail(t, "should not be called")
-
- return nil
- },
- }
-
- bp, _ := NewBalanceProcessor(
- dataProvider,
- blockchainDataProvider,
- balanceOperator,
- &testsCommon.ContractHandlerStub{},
- 0.01,
- )
-
- ctx, cancelFunc := context.WithCancel(context.Background())
- cancelFunc()
- err := bp.ProcessAll(ctx)
- require.NoError(t, err)
- })
-
- t.Run("invalid bech32 address string should not process", func(t *testing.T) {
- t.Parallel()
-
- dataProvider := &testsCommon.DataProviderStub{
- GetAllHandler: func() ([]*common.BalanceEntry, error) {
- return []*common.BalanceEntry{
- {
- ID: 0,
- Address: "erd1invalid",
- },
- }, nil
- },
- }
-
- blockchainDataProvider := &testsCommon.BlockchainDataProviderStub{
- GetAccountHandler: func(ctx context.Context, address core.AddressHandler) (*data.Account, error) {
- assert.Fail(t, "should not be called")
-
- return &data.Account{}, nil
- },
- ExecuteVMQueryHandler: func(ctx context.Context, vmRequest *data.VmValueRequest) (*data.VmValuesResponseData, error) {
- return &data.VmValuesResponseData{
- Data: &vm.VMOutputApi{
- ReturnData: make([][]byte, 0),
- },
- }, nil
- },
- }
-
- balanceOperator := &testsCommon.BalanceOperatorStub{
- ProcessHandler: func(ctx context.Context, id uint64, sender core.AddressHandler, value string, nonce uint64) error {
- assert.Fail(t, "should not be called")
-
- return nil
- },
- }
-
- bp, _ := NewBalanceProcessor(
- dataProvider,
- blockchainDataProvider,
- balanceOperator,
- &testsCommon.ContractHandlerStub{},
- 0.01,
- )
-
- err := bp.ProcessAll(context.Background())
- require.NoError(t, err)
- })
-
- t.Run("get account errors should not process", func(t *testing.T) {
- t.Parallel()
-
- dataProvider := &testsCommon.DataProviderStub{
- GetAllHandler: func() ([]*common.BalanceEntry, error) {
- return []*common.BalanceEntry{
- {
- ID: 0,
- Address: "erd19x6dfsupwtsl46nmgpxw30xcka72e4z0x3ngh6h0yjy6zwtrgh5q8px2wc",
- },
- }, nil
- },
- }
-
- blockchainDataProvider := &testsCommon.BlockchainDataProviderStub{
- GetAccountHandler: func(ctx context.Context, address core.AddressHandler) (*data.Account, error) {
- return nil, expectedErr
- },
- ExecuteVMQueryHandler: func(ctx context.Context, vmRequest *data.VmValueRequest) (*data.VmValuesResponseData, error) {
- return &data.VmValuesResponseData{
- Data: &vm.VMOutputApi{
- ReturnData: make([][]byte, 0),
- },
- }, nil
- },
- }
-
- balanceOperator := &testsCommon.BalanceOperatorStub{
- ProcessHandler: func(ctx context.Context, id uint64, sender core.AddressHandler, value string, nonce uint64) error {
- assert.Fail(t, "should not be called")
-
- return nil
- },
- }
-
- bp, _ := NewBalanceProcessor(
- dataProvider,
- blockchainDataProvider,
- balanceOperator,
- &testsCommon.ContractHandlerStub{},
- 0.01,
- )
-
- err := bp.ProcessAll(context.Background())
- require.NoError(t, err)
- })
-
- t.Run("get balance errors should not process", func(t *testing.T) {
- t.Parallel()
-
- dataProvider := &testsCommon.DataProviderStub{
- GetAllHandler: func() ([]*common.BalanceEntry, error) {
- return []*common.BalanceEntry{
- {
- ID: 0,
- Address: "erd19x6dfsupwtsl46nmgpxw30xcka72e4z0x3ngh6h0yjy6zwtrgh5q8px2wc",
- },
- }, nil
- },
- }
-
- blockchainDataProvider := &testsCommon.BlockchainDataProviderStub{
- GetAccountHandler: func(ctx context.Context, address core.AddressHandler) (*data.Account, error) {
- return &data.Account{
- Balance: "not-a-balance",
- }, nil
- },
- ExecuteVMQueryHandler: func(ctx context.Context, vmRequest *data.VmValueRequest) (*data.VmValuesResponseData, error) {
- return &data.VmValuesResponseData{
- Data: &vm.VMOutputApi{
- ReturnData: make([][]byte, 0),
- },
- }, nil
- },
- }
-
- balanceOperator := &testsCommon.BalanceOperatorStub{
- ProcessHandler: func(ctx context.Context, id uint64, sender core.AddressHandler, value string, nonce uint64) error {
- assert.Fail(t, "should not be called")
-
- return nil
- },
- }
-
- bp, _ := NewBalanceProcessor(
- dataProvider,
- blockchainDataProvider,
- balanceOperator,
- &testsCommon.ContractHandlerStub{},
- 0.01,
- )
-
- err := bp.ProcessAll(context.Background())
- require.NoError(t, err)
- })
-
- t.Run("under the minimum value should not process", func(t *testing.T) {
- t.Parallel()
-
- dataProvider := &testsCommon.DataProviderStub{
- GetAllHandler: func() ([]*common.BalanceEntry, error) {
- return []*common.BalanceEntry{
- {
- ID: 0,
- Address: "erd19x6dfsupwtsl46nmgpxw30xcka72e4z0x3ngh6h0yjy6zwtrgh5q8px2wc",
- },
- }, nil
- },
- }
-
- blockchainDataProvider := &testsCommon.BlockchainDataProviderStub{
- GetAccountHandler: func(ctx context.Context, address core.AddressHandler) (*data.Account, error) {
- return &data.Account{
- Balance: "9000000000000000",
- }, nil
- },
- GetNetworkConfigHandler: func(ctx context.Context) (*data.NetworkConfig, error) {
- return &data.NetworkConfig{
- Denomination: 18,
- }, nil
- },
- ExecuteVMQueryHandler: func(ctx context.Context, vmRequest *data.VmValueRequest) (*data.VmValuesResponseData, error) {
- return &data.VmValuesResponseData{
- Data: &vm.VMOutputApi{
- ReturnData: make([][]byte, 0),
- },
- }, nil
- },
- }
-
- balanceOperator := &testsCommon.BalanceOperatorStub{
- ProcessHandler: func(ctx context.Context, id uint64, sender core.AddressHandler, value string, nonce uint64) error {
- assert.Fail(t, "should not be called")
-
- return nil
- },
- }
-
- bp, _ := NewBalanceProcessor(
- dataProvider,
- blockchainDataProvider,
- balanceOperator,
- &testsCommon.ContractHandlerStub{},
- 0.01,
- )
-
- err := bp.ProcessAll(context.Background())
- require.NoError(t, err)
- })
-
- t.Run("balance processing errors, should not return error", func(t *testing.T) {
- t.Parallel()
-
- getAllWasCalled := false
- dataProvider := &testsCommon.DataProviderStub{
- GetAllHandler: func() ([]*common.BalanceEntry, error) {
- getAllWasCalled = true
-
- return []*common.BalanceEntry{
- {
- ID: 0,
- Address: "erd19x6dfsupwtsl46nmgpxw30xcka72e4z0x3ngh6h0yjy6zwtrgh5q8px2wc",
- },
- }, nil
- },
- }
-
- getAccountWasCalled := false
- blockchainDataProvider := &testsCommon.BlockchainDataProviderStub{
- GetAccountHandler: func(ctx context.Context, address core.AddressHandler) (*data.Account, error) {
- getAccountWasCalled = true
- return &data.Account{
- Nonce: 37,
- Balance: "1200000000000000000", //1.2 egld
- }, nil
- },
- ExecuteVMQueryHandler: func(ctx context.Context, vmRequest *data.VmValueRequest) (*data.VmValuesResponseData, error) {
- return &data.VmValuesResponseData{
- Data: &vm.VMOutputApi{
- ReturnData: make([][]byte, 0),
- },
- }, nil
- },
- }
-
- processBalanceOperatorCalled := false
- balanceOperator := &testsCommon.BalanceOperatorStub{
- ProcessHandler: func(ctx context.Context, id uint64, sender core.AddressHandler, value string, nonce uint64) error {
- assert.Equal(t, uint64(0), id)
- bech32Address, _ := sender.AddressAsBech32String()
- assert.Equal(t, "erd19x6dfsupwtsl46nmgpxw30xcka72e4z0x3ngh6h0yjy6zwtrgh5q8px2wc", bech32Address)
- assert.Equal(t, "1200000000000000000", value)
- assert.Equal(t, uint64(37), nonce)
- processBalanceOperatorCalled = true
-
- return expectedErr
- },
- }
-
- bp, _ := NewBalanceProcessor(
- dataProvider,
- blockchainDataProvider,
- balanceOperator,
- &testsCommon.ContractHandlerStub{},
- 0.01,
- )
-
- err := bp.ProcessAll(context.Background())
- require.NoError(t, err)
- assert.True(t, getAllWasCalled)
- assert.True(t, getAccountWasCalled)
- assert.True(t, processBalanceOperatorCalled)
- })
-
- t.Run("should work", func(t *testing.T) {
- t.Parallel()
-
- getAllWasCalled := false
- dataProvider := &testsCommon.DataProviderStub{
- GetAllHandler: func() ([]*common.BalanceEntry, error) {
- getAllWasCalled = true
-
- return []*common.BalanceEntry{
- {
- ID: 0,
- Address: "erd19x6dfsupwtsl46nmgpxw30xcka72e4z0x3ngh6h0yjy6zwtrgh5q8px2wc",
- },
- }, nil
- },
- }
-
- getAccountWasCalled := false
- blockchainDataProvider := &testsCommon.BlockchainDataProviderStub{
- GetAccountHandler: func(ctx context.Context, address core.AddressHandler) (*data.Account, error) {
- getAccountWasCalled = true
- return &data.Account{
- Nonce: 37,
- Balance: "1200000000000000000", //1.2 egld
- }, nil
- },
- GetNetworkConfigHandler: func(ctx context.Context) (*data.NetworkConfig, error) {
- return &data.NetworkConfig{
- Denomination: 18,
- }, nil
- },
- ExecuteVMQueryHandler: func(ctx context.Context, vmRequest *data.VmValueRequest) (*data.VmValuesResponseData, error) {
- return &data.VmValuesResponseData{
- Data: &vm.VMOutputApi{
- ReturnData: make([][]byte, 0),
- },
- }, nil
- },
- }
-
- processBalanceOperatorCalled := false
- balanceOperator := &testsCommon.BalanceOperatorStub{
- ProcessHandler: func(ctx context.Context, id uint64, sender core.AddressHandler, value string, nonce uint64) error {
- assert.Equal(t, uint64(0), id)
- bech32Address, _ := sender.AddressAsBech32String()
- assert.Equal(t, "erd19x6dfsupwtsl46nmgpxw30xcka72e4z0x3ngh6h0yjy6zwtrgh5q8px2wc", bech32Address)
- assert.Equal(t, "1200000000000000000", value)
- assert.Equal(t, uint64(37), nonce)
- processBalanceOperatorCalled = true
-
- return nil
- },
- }
-
- bp, _ := NewBalanceProcessor(
- dataProvider,
- blockchainDataProvider,
- balanceOperator,
- &testsCommon.ContractHandlerStub{},
- 0.01,
- )
-
- err := bp.ProcessAll(context.Background())
- require.NoError(t, err)
- assert.True(t, getAllWasCalled)
- assert.True(t, getAccountWasCalled)
- assert.True(t, processBalanceOperatorCalled)
- })
-}
diff --git a/services/crypto-payment/process/configHandler.go b/services/crypto-payment/process/configHandler.go
deleted file mode 100644
index 7ec47ba..0000000
--- a/services/crypto-payment/process/configHandler.go
+++ /dev/null
@@ -1,60 +0,0 @@
-package process
-
-import (
- "context"
- "fmt"
-
- "github.com/multiversx/mx-chain-core-go/core/check"
-)
-
-type configHandler struct {
- walletURL string
- explorerURL string
- contractHandler ContractHandler
- minimumBalance float64
-}
-
-// NewConfigHandler creates a new instance of configHandler
-func NewConfigHandler(
- walletURL string,
- explorerURL string,
- contractHandler ContractHandler,
- minimumBalance float64,
-) (*configHandler, error) {
- if check.IfNil(contractHandler) {
- return nil, fmt.Errorf("nil contract handler")
- }
-
- return &configHandler{
- walletURL: walletURL,
- explorerURL: explorerURL,
- contractHandler: contractHandler,
- minimumBalance: minimumBalance,
- }, nil
-}
-
-// GetConfig returns the configuration map
-func (ch *configHandler) GetConfig(ctx context.Context) (map[string]interface{}, error) {
- isPaused, err := ch.contractHandler.IsContractPaused(ctx)
- if err != nil {
- return nil, err
- }
-
- creditsPerEgld, err := ch.contractHandler.GetCreditsPerEGLD(ctx)
- if err != nil {
- return nil, err
- }
-
- return map[string]interface{}{
- "isContractPaused": isPaused,
- "walletURL": ch.walletURL,
- "explorerURL": ch.explorerURL,
- "creditsPerEGLD": creditsPerEgld,
- "minimumBalance": ch.minimumBalance,
- }, nil
-}
-
-// IsInterfaceNil returns true if the value under the interface is nil
-func (ch *configHandler) IsInterfaceNil() bool {
- return ch == nil
-}
diff --git a/services/crypto-payment/process/configHandler_test.go b/services/crypto-payment/process/configHandler_test.go
deleted file mode 100644
index 454155d..0000000
--- a/services/crypto-payment/process/configHandler_test.go
+++ /dev/null
@@ -1,101 +0,0 @@
-package process
-
-import (
- "context"
- "errors"
- "testing"
-
- "github.com/iulianpascalau/mx-epoch-proxy-go/services/crypto-payment/testsCommon"
- "github.com/stretchr/testify/assert"
- "github.com/stretchr/testify/require"
-)
-
-func TestNewConfigHandler(t *testing.T) {
- t.Parallel()
-
- t.Run("nil contract handler should error", func(t *testing.T) {
- t.Parallel()
-
- handler, err := NewConfigHandler("wallet", "explorer", nil, 0.05)
- require.Nil(t, handler)
- require.EqualError(t, err, "nil contract handler")
- })
-
- t.Run("success", func(t *testing.T) {
- t.Parallel()
-
- handler, err := NewConfigHandler("wallet", "explorer", &testsCommon.ContractHandlerStub{}, 0.05)
- require.NotNil(t, handler)
- require.NoError(t, err)
- require.False(t, handler.IsInterfaceNil())
- })
-}
-
-func TestConfigHandler_GetConfig(t *testing.T) {
- t.Parallel()
-
- expectedWallet := "wallet_url"
- expectedExplorer := "explorer_url"
-
- t.Run("contract paused error", func(t *testing.T) {
- t.Parallel()
-
- expectedErr := errors.New("contract paused check error")
- contractHandler := &testsCommon.ContractHandlerStub{
- IsContractPausedHandler: func(ctx context.Context) (bool, error) {
- return false, expectedErr
- },
- }
-
- handler, _ := NewConfigHandler(expectedWallet, expectedExplorer, contractHandler, 0.05)
- config, err := handler.GetConfig(context.Background())
- require.Nil(t, config)
- require.Equal(t, expectedErr, err)
- })
-
- t.Run("get requests per egld error", func(t *testing.T) {
- t.Parallel()
-
- expectedErr := errors.New("get requests error")
- contractHandler := &testsCommon.ContractHandlerStub{
- IsContractPausedHandler: func(ctx context.Context) (bool, error) {
- return false, nil
- },
- GetCreditsPerEGLDHandler: func(ctx context.Context) (uint64, error) {
- return 0, expectedErr
- },
- }
-
- handler, _ := NewConfigHandler(expectedWallet, expectedExplorer, contractHandler, 0.05)
- config, err := handler.GetConfig(context.Background())
- require.Nil(t, config)
- require.Equal(t, expectedErr, err)
- })
-
- t.Run("success", func(t *testing.T) {
- t.Parallel()
-
- expectedRate := uint64(100)
-
- contractHandler := &testsCommon.ContractHandlerStub{
- IsContractPausedHandler: func(ctx context.Context) (bool, error) {
- return true, nil
- },
- GetCreditsPerEGLDHandler: func(ctx context.Context) (uint64, error) {
- return expectedRate, nil
- },
- }
-
- expectedMinBalance := 0.05
- handler, _ := NewConfigHandler(expectedWallet, expectedExplorer, contractHandler, expectedMinBalance)
- config, err := handler.GetConfig(context.Background())
- require.NoError(t, err)
- require.NotNil(t, config)
-
- assert.True(t, config["isContractPaused"].(bool))
- assert.Equal(t, expectedRate, config["creditsPerEGLD"])
- assert.Equal(t, expectedWallet, config["walletURL"])
- assert.Equal(t, expectedExplorer, config["explorerURL"])
- assert.Equal(t, expectedMinBalance, config["minimumBalance"])
- })
-}
diff --git a/services/crypto-payment/process/contractQueryHandler.go b/services/crypto-payment/process/contractQueryHandler.go
deleted file mode 100644
index e884373..0000000
--- a/services/crypto-payment/process/contractQueryHandler.go
+++ /dev/null
@@ -1,152 +0,0 @@
-package process
-
-import (
- "context"
- "fmt"
- "math/big"
-
- "github.com/multiversx/mx-chain-core-go/core/check"
- "github.com/multiversx/mx-sdk-go/data"
-)
-
-const (
- isPausedFunc = "isPaused"
- creditsPerEgldFunc = "getCreditsPerEgld"
-
- keyIsPaused = "isPaused"
- keyCreditsPerEgld = "creditsPerEgld"
-
- contractNotFoundStatus = "contract not found"
-)
-
-type contractQueryHandler struct {
- blockchainDataProvider BlockchainDataProvider
- contractBech32Address string
- cacher Cacher
-}
-
-// NewContractQueryHandler creates a new instance of contractQueryHandler
-func NewContractQueryHandler(
- blockchainDataProvider BlockchainDataProvider,
- contractBech32Address string,
- cacher Cacher,
-) (*contractQueryHandler, error) {
- if check.IfNil(blockchainDataProvider) {
- return nil, fmt.Errorf("nil blockchain data provider")
- }
- if len(contractBech32Address) == 0 {
- return nil, fmt.Errorf("empty contract address")
- }
- if check.IfNil(cacher) {
- return nil, errNilCache
- }
-
- return &contractQueryHandler{
- blockchainDataProvider: blockchainDataProvider,
- contractBech32Address: contractBech32Address,
- cacher: cacher,
- }, nil
-}
-
-// IsContractPaused checks if the contract is paused, using caching
-func (cqh *contractQueryHandler) IsContractPaused(ctx context.Context) (bool, error) {
- isPausedCachedValue, found := cqh.cacher.Get(keyIsPaused)
- if found {
- return isPausedCachedValue.(bool), nil
- }
-
- isPaused := false
- res, err := cqh.blockchainDataProvider.ExecuteVMQuery(ctx, &data.VmValueRequest{
- Address: cqh.contractBech32Address,
- FuncName: isPausedFunc,
- CallValue: "0",
- CallerAddr: cqh.contractBech32Address, // Caller can be the contract itself for views usually, or random
- })
- if err != nil {
- return false, err
- }
-
- if res.Data == nil || res.Data.ReturnCode == contractNotFoundStatus {
- // malformed response or the contract was not found, signal that the contract is paused
- return true, nil
- }
-
- if len(res.Data.ReturnData) == 0 || len(res.Data.ReturnData[0]) == 0 {
- isPaused = false
- } else {
- isPaused = res.Data.ReturnData[0][0] == 1
- }
-
- cqh.cacher.Set(keyIsPaused, isPaused)
-
- return isPaused, nil
-}
-
-// GetCreditsPerEGLD returns the number of credits per EGLD
-func (cqh *contractQueryHandler) GetCreditsPerEGLD(ctx context.Context) (uint64, error) {
- creditsPerEgldCachedValue, found := cqh.cacher.Get(keyCreditsPerEgld)
- if found {
- return creditsPerEgldCachedValue.(uint64), nil
- }
-
- res, err := cqh.blockchainDataProvider.ExecuteVMQuery(ctx, &data.VmValueRequest{
- Address: cqh.contractBech32Address,
- FuncName: creditsPerEgldFunc,
- CallValue: "0",
- CallerAddr: cqh.contractBech32Address,
- })
- if err != nil {
- return 0, err
- }
-
- creditsPerEgld, err := vmValueToUint64Decoder(res.Data.ReturnData)
- if err != nil {
- return 0, err
- }
-
- cqh.cacher.Set(keyCreditsPerEgld, creditsPerEgld)
-
- return creditsPerEgld, nil
-}
-
-func vmValueToUint64Decoder(buff [][]byte) (uint64, error) {
- if len(buff) == 0 {
- return 0, nil
- }
-
- // Decode BigInt
- bytes := buff[0]
- val := big.NewInt(0).SetBytes(bytes)
- if !val.IsUint64() {
- return 0, fmt.Errorf("value %s is not a uint64", val.String())
- }
- return val.Uint64(), nil
-}
-
-// GetCredits returns the number of credits for a specific ID
-func (cqh *contractQueryHandler) GetCredits(ctx context.Context, id uint64) (uint64, error) {
- res, err := cqh.blockchainDataProvider.ExecuteVMQuery(ctx, &data.VmValueRequest{
- Address: cqh.contractBech32Address,
- FuncName: "getCredits",
- Args: []string{ensureEvenHex(fmt.Sprintf("%x", id))}, // hex encoded id
- CallValue: "0",
- CallerAddr: cqh.contractBech32Address,
- })
- if err != nil {
- return 0, err
- }
-
- return vmValueToUint64Decoder(res.Data.ReturnData)
-}
-
-// IsInterfaceNil returns true if the value under the interface is nil
-func (cqh *contractQueryHandler) IsInterfaceNil() bool {
- return cqh == nil
-}
-
-func ensureEvenHex(hex string) string {
- if len(hex)%2 != 0 {
- return "0" + hex
- }
- return hex
-}
diff --git a/services/crypto-payment/process/contractQueryHandler_test.go b/services/crypto-payment/process/contractQueryHandler_test.go
deleted file mode 100644
index 85e38a5..0000000
--- a/services/crypto-payment/process/contractQueryHandler_test.go
+++ /dev/null
@@ -1,361 +0,0 @@
-package process
-
-import (
- "context"
- "encoding/hex"
- "errors"
- "strings"
- "testing"
-
- "github.com/iulianpascalau/mx-epoch-proxy-go/services/crypto-payment/testsCommon"
- "github.com/multiversx/mx-chain-core-go/data/vm"
- "github.com/multiversx/mx-sdk-go/data"
- "github.com/stretchr/testify/assert"
- "github.com/stretchr/testify/require"
-)
-
-func TestNewContractQueryHandler(t *testing.T) {
- t.Parallel()
-
- t.Run("nil proxy should error", func(t *testing.T) {
- t.Parallel()
-
- handler, err := NewContractQueryHandler(nil, "erd1test", &testsCommon.CacherStub{})
- require.Nil(t, handler)
- require.EqualError(t, err, "nil blockchain data provider")
- })
-
- t.Run("empty contract address should error", func(t *testing.T) {
- t.Parallel()
-
- handler, err := NewContractQueryHandler(&testsCommon.BlockchainDataProviderStub{}, "", &testsCommon.CacherStub{})
- require.Nil(t, handler)
- require.EqualError(t, err, "empty contract address")
- })
-
- t.Run("success", func(t *testing.T) {
- t.Parallel()
-
- handler, err := NewContractQueryHandler(&testsCommon.BlockchainDataProviderStub{}, "erd1test", &testsCommon.CacherStub{})
- require.NotNil(t, handler)
- require.NoError(t, err)
- require.False(t, handler.IsInterfaceNil())
- })
-}
-
-func TestContractQueryHandler_IsContractPaused(t *testing.T) {
- t.Parallel()
-
- t.Run("proxy error", func(t *testing.T) {
- t.Parallel()
-
- expectedErr := errors.New("proxy error")
- proxy := &testsCommon.BlockchainDataProviderStub{
- ExecuteVMQueryHandler: func(ctx context.Context, vmRequest *data.VmValueRequest) (*data.VmValuesResponseData, error) {
- return nil, expectedErr
- },
- }
-
- handler, _ := NewContractQueryHandler(proxy, "erd1test", &testsCommon.CacherStub{})
- paused, err := handler.IsContractPaused(context.Background())
- require.False(t, paused)
- require.Equal(t, expectedErr, err)
- })
-
- t.Run("nil response data", func(t *testing.T) {
- t.Parallel()
-
- proxy := &testsCommon.BlockchainDataProviderStub{
- ExecuteVMQueryHandler: func(ctx context.Context, vmRequest *data.VmValueRequest) (*data.VmValuesResponseData, error) {
- return &data.VmValuesResponseData{Data: nil}, nil
- },
- }
-
- handler, _ := NewContractQueryHandler(proxy, "erd1test", &testsCommon.CacherStub{})
- paused, err := handler.IsContractPaused(context.Background())
- require.NoError(t, err)
- require.True(t, paused)
- })
-
- t.Run("nil return data", func(t *testing.T) {
- t.Parallel()
-
- proxy := &testsCommon.BlockchainDataProviderStub{
- ExecuteVMQueryHandler: func(ctx context.Context, vmRequest *data.VmValueRequest) (*data.VmValuesResponseData, error) {
- return &data.VmValuesResponseData{
- Data: &vm.VMOutputApi{ReturnData: nil},
- }, nil
- },
- }
-
- handler, _ := NewContractQueryHandler(proxy, "erd1test", &testsCommon.CacherStub{})
- paused, err := handler.IsContractPaused(context.Background())
- require.NoError(t, err)
- require.False(t, paused)
- })
-
- t.Run("empty return data", func(t *testing.T) {
- t.Parallel()
-
- proxy := &testsCommon.BlockchainDataProviderStub{
- ExecuteVMQueryHandler: func(ctx context.Context, vmRequest *data.VmValueRequest) (*data.VmValuesResponseData, error) {
- return &data.VmValuesResponseData{
- Data: &vm.VMOutputApi{ReturnData: make([][]byte, 0)},
- }, nil
- },
- }
-
- handler, _ := NewContractQueryHandler(proxy, "erd1test", &testsCommon.CacherStub{})
- paused, err := handler.IsContractPaused(context.Background())
- require.NoError(t, err)
- require.False(t, paused)
- })
-
- t.Run("empty first element in return data", func(t *testing.T) {
- t.Parallel()
-
- proxy := &testsCommon.BlockchainDataProviderStub{
- ExecuteVMQueryHandler: func(ctx context.Context, vmRequest *data.VmValueRequest) (*data.VmValuesResponseData, error) {
- return &data.VmValuesResponseData{
- Data: &vm.VMOutputApi{ReturnData: [][]byte{{}}},
- }, nil
- },
- }
-
- handler, _ := NewContractQueryHandler(proxy, "erd1test", &testsCommon.CacherStub{})
- paused, err := handler.IsContractPaused(context.Background())
- require.NoError(t, err)
- require.False(t, paused)
- })
-
- t.Run("contract missing", func(t *testing.T) {
- t.Parallel()
-
- proxy := &testsCommon.BlockchainDataProviderStub{
- ExecuteVMQueryHandler: func(ctx context.Context, vmRequest *data.VmValueRequest) (*data.VmValuesResponseData, error) {
- return &data.VmValuesResponseData{
- Data: &vm.VMOutputApi{
- ReturnCode: contractNotFoundStatus,
- },
- }, nil
- },
- }
-
- handler, _ := NewContractQueryHandler(proxy, "erd1test", &testsCommon.CacherStub{})
- paused, err := handler.IsContractPaused(context.Background())
- require.NoError(t, err)
- require.True(t, paused)
- })
-
- t.Run("paused", func(t *testing.T) {
- t.Parallel()
-
- proxy := &testsCommon.BlockchainDataProviderStub{
- ExecuteVMQueryHandler: func(ctx context.Context, vmRequest *data.VmValueRequest) (*data.VmValuesResponseData, error) {
- return &data.VmValuesResponseData{
- Data: &vm.VMOutputApi{ReturnData: [][]byte{{1}}},
- }, nil
- },
- }
-
- handler, _ := NewContractQueryHandler(proxy, "erd1test", &testsCommon.CacherStub{})
- paused, err := handler.IsContractPaused(context.Background())
- require.NoError(t, err)
- require.True(t, paused)
- })
-
- t.Run("not paused", func(t *testing.T) {
- t.Parallel()
-
- proxy := &testsCommon.BlockchainDataProviderStub{
- ExecuteVMQueryHandler: func(ctx context.Context, vmRequest *data.VmValueRequest) (*data.VmValuesResponseData, error) {
- return &data.VmValuesResponseData{
- Data: &vm.VMOutputApi{ReturnData: [][]byte{{0}}},
- }, nil
- },
- }
-
- handler, _ := NewContractQueryHandler(proxy, "erd1test", &testsCommon.CacherStub{})
- paused, err := handler.IsContractPaused(context.Background())
- require.NoError(t, err)
- require.False(t, paused)
- })
-
- t.Run("cache works", func(t *testing.T) {
- t.Parallel()
-
- calls := 0
- proxy := &testsCommon.BlockchainDataProviderStub{
- ExecuteVMQueryHandler: func(ctx context.Context, vmRequest *data.VmValueRequest) (*data.VmValuesResponseData, error) {
- calls++
- return &data.VmValuesResponseData{
- Data: &vm.VMOutputApi{ReturnData: [][]byte{{1}}},
- }, nil
- },
- }
-
- cacher := &testsCommon.CacherStub{
- GetHandler: func(key string) (interface{}, bool) {
- return true, true
- },
- }
-
- handler, _ := NewContractQueryHandler(proxy, "erd1test", cacher)
- paused, err := handler.IsContractPaused(context.Background())
- require.NoError(t, err)
- require.True(t, paused)
- require.Equal(t, 0, calls) // Should be 0 because cache hit
- })
-}
-
-func TestContractQueryHandler_GetCreditsPerEGLD(t *testing.T) {
- t.Parallel()
-
- t.Run("proxy error", func(t *testing.T) {
- t.Parallel()
-
- expectedErr := errors.New("proxy error")
- proxy := &testsCommon.BlockchainDataProviderStub{
- ExecuteVMQueryHandler: func(ctx context.Context, vmRequest *data.VmValueRequest) (*data.VmValuesResponseData, error) {
- return nil, expectedErr
- },
- }
-
- handler, _ := NewContractQueryHandler(proxy, "erd1test", &testsCommon.CacherStub{})
- val, err := handler.GetCreditsPerEGLD(context.Background())
- require.Equal(t, uint64(0), val)
- require.Equal(t, expectedErr, err)
- })
-
- t.Run("empty return data", func(t *testing.T) {
- t.Parallel()
-
- proxy := &testsCommon.BlockchainDataProviderStub{
- ExecuteVMQueryHandler: func(ctx context.Context, vmRequest *data.VmValueRequest) (*data.VmValuesResponseData, error) {
- return &data.VmValuesResponseData{
- Data: &vm.VMOutputApi{ReturnData: [][]byte{}},
- }, nil
- },
- }
-
- handler, _ := NewContractQueryHandler(proxy, "erd1test", &testsCommon.CacherStub{})
- val, err := handler.GetCreditsPerEGLD(context.Background())
- require.NoError(t, err)
- require.Equal(t, uint64(0), val)
- })
-
- t.Run("success", func(t *testing.T) {
- t.Parallel()
-
- proxy := &testsCommon.BlockchainDataProviderStub{
- ExecuteVMQueryHandler: func(ctx context.Context, vmRequest *data.VmValueRequest) (*data.VmValuesResponseData, error) {
- assert.Equal(t, "getCreditsPerEgld", vmRequest.FuncName)
- return &data.VmValuesResponseData{
- Data: &vm.VMOutputApi{ReturnData: [][]byte{{10}}},
- }, nil
- },
- }
-
- handler, _ := NewContractQueryHandler(proxy, "erd1test", &testsCommon.CacherStub{})
- val, err := handler.GetCreditsPerEGLD(context.Background())
- require.NoError(t, err)
- require.Equal(t, uint64(10), val)
- })
-
- t.Run("invalid byte format", func(t *testing.T) {
- t.Parallel()
-
- proxy := &testsCommon.BlockchainDataProviderStub{
- ExecuteVMQueryHandler: func(ctx context.Context, vmRequest *data.VmValueRequest) (*data.VmValuesResponseData, error) {
- // Return a value larger than uint64 to Trigger IsUint64 check fail if implemented or overflow check
- // Creating a large byte array
- largeBytes, _ := hex.DecodeString("FFFFFFFFFFFFFFFFFFFFFFFF") // larger than uint64
- return &data.VmValuesResponseData{
- Data: &vm.VMOutputApi{ReturnData: [][]byte{largeBytes}},
- }, nil
- },
- }
-
- handler, _ := NewContractQueryHandler(proxy, "erd1test", &testsCommon.CacherStub{})
- val, err := handler.GetCreditsPerEGLD(context.Background())
- require.Error(t, err)
- require.True(t, strings.Contains(err.Error(), "is not a uint64"))
- require.Equal(t, uint64(0), val)
- })
-}
-
-func TestContractQueryHandler_GetCredits(t *testing.T) {
- t.Parallel()
-
- t.Run("proxy error", func(t *testing.T) {
- t.Parallel()
-
- expectedErr := errors.New("proxy error")
- proxy := &testsCommon.BlockchainDataProviderStub{
- ExecuteVMQueryHandler: func(ctx context.Context, vmRequest *data.VmValueRequest) (*data.VmValuesResponseData, error) {
- return nil, expectedErr
- },
- }
-
- handler, _ := NewContractQueryHandler(proxy, "erd1test", &testsCommon.CacherStub{})
- val, err := handler.GetCredits(context.Background(), 1)
- require.Equal(t, uint64(0), val)
- require.Equal(t, expectedErr, err)
- })
-
- t.Run("empty return data", func(t *testing.T) {
- t.Parallel()
-
- proxy := &testsCommon.BlockchainDataProviderStub{
- ExecuteVMQueryHandler: func(ctx context.Context, vmRequest *data.VmValueRequest) (*data.VmValuesResponseData, error) {
- return &data.VmValuesResponseData{
- Data: &vm.VMOutputApi{ReturnData: [][]byte{}},
- }, nil
- },
- }
-
- handler, _ := NewContractQueryHandler(proxy, "erd1test", &testsCommon.CacherStub{})
- val, err := handler.GetCredits(context.Background(), 1)
- require.NoError(t, err)
- require.Equal(t, uint64(0), val)
- })
-
- t.Run("success", func(t *testing.T) {
- t.Parallel()
-
- id := uint64(123)
- proxy := &testsCommon.BlockchainDataProviderStub{
- ExecuteVMQueryHandler: func(ctx context.Context, vmRequest *data.VmValueRequest) (*data.VmValuesResponseData, error) {
- assert.Equal(t, "getCredits", vmRequest.FuncName)
- assert.Equal(t, "7b", vmRequest.Args[0]) // 123 in hex
- return &data.VmValuesResponseData{
- Data: &vm.VMOutputApi{ReturnData: [][]byte{{10}}},
- }, nil
- },
- }
-
- handler, _ := NewContractQueryHandler(proxy, "erd1test", &testsCommon.CacherStub{})
- val, err := handler.GetCredits(context.Background(), id)
- require.NoError(t, err)
- require.Equal(t, uint64(10), val)
- })
-
- t.Run("invalid byte format", func(t *testing.T) {
- t.Parallel()
-
- proxy := &testsCommon.BlockchainDataProviderStub{
- ExecuteVMQueryHandler: func(ctx context.Context, vmRequest *data.VmValueRequest) (*data.VmValuesResponseData, error) {
- largeBytes, _ := hex.DecodeString("FFFFFFFFFFFFFFFFFFFFFFFF")
- return &data.VmValuesResponseData{
- Data: &vm.VMOutputApi{ReturnData: [][]byte{largeBytes}},
- }, nil
- },
- }
-
- handler, _ := NewContractQueryHandler(proxy, "erd1test", &testsCommon.CacherStub{})
- val, err := handler.GetCredits(context.Background(), 1)
- require.Error(t, err)
- require.True(t, strings.Contains(err.Error(), "is not a uint64"))
- require.Equal(t, uint64(0), val)
- })
-}
diff --git a/services/crypto-payment/process/errors.go b/services/crypto-payment/process/errors.go
deleted file mode 100644
index f01ee4b..0000000
--- a/services/crypto-payment/process/errors.go
+++ /dev/null
@@ -1,15 +0,0 @@
-package process
-
-import "errors"
-
-var errNilDataProvider = errors.New("nil data provider")
-var errNilBlockchainDataProvider = errors.New("nil blockchain data provider")
-var errInvalidMinimumBalanceToCall = errors.New("invalid minimum balance to call the SC")
-var errNilBalanceOperator = errors.New("nil balance operator")
-var errNilUserKeysHandler = errors.New("nil user keys handler")
-var errNilRelayersKeysMap = errors.New("nil relayers keys map")
-var errZeroGasLimit = errors.New("gas limit must be greater than 0")
-var errEmptyContractBech32Address = errors.New("empty contract bech32 address")
-var errNilSender = errors.New("nil sender")
-var errContractIsPaused = errors.New("contract is paused, will not process payment addresses")
-var errNilCache = errors.New("nil cache")
diff --git a/services/crypto-payment/process/interface.go b/services/crypto-payment/process/interface.go
deleted file mode 100644
index 52b42d0..0000000
--- a/services/crypto-payment/process/interface.go
+++ /dev/null
@@ -1,72 +0,0 @@
-package process
-
-import (
- "context"
-
- "github.com/iulianpascalau/mx-epoch-proxy-go/services/crypto-payment/common"
- "github.com/multiversx/mx-chain-core-go/data/transaction"
- "github.com/multiversx/mx-sdk-go/core"
- "github.com/multiversx/mx-sdk-go/data"
-)
-
-// DataProvider defines the operations required from the storage layer
-type DataProvider interface {
- GetAll() ([]*common.BalanceEntry, error)
- Get(id uint64) (*common.BalanceEntry, error)
- IsInterfaceNil() bool
-}
-
-// BlockchainDataProvider defines the operations to fetch data from the blockchain
-type BlockchainDataProvider interface {
- GetAccount(ctx context.Context, address core.AddressHandler) (*data.Account, error)
- GetNetworkConfig(ctx context.Context) (*data.NetworkConfig, error)
- SendTransaction(ctx context.Context, transaction *transaction.FrontendTransaction) (string, error)
- SendTransactions(ctx context.Context, txs []*transaction.FrontendTransaction) ([]string, error)
- ExecuteVMQuery(ctx context.Context, vmRequest *data.VmValueRequest) (*data.VmValuesResponseData, error)
- IsInterfaceNil() bool
-}
-
-// BalanceOperator defines the operations supported by a component able to process balance changes and SC calls
-type BalanceOperator interface {
- Process(ctx context.Context, id uint64, senderAddress core.AddressHandler, value string, nonce uint64) error
- Close() error
- IsInterfaceNil() bool
-}
-
-// MultipleKeysHandler defines the operations supported by a component able to manage multiple keys
-type MultipleKeysHandler interface {
- GetBech32AddressAtIndex(index uint32) (string, error)
- Sign(index uint32, msg []byte) ([]byte, error)
- IsInterfaceNil() bool
-}
-
-// SingleKeyHandler defines the operations supported by a component able to manage a single key
-type SingleKeyHandler interface {
- Sign(msg []byte) ([]byte, error)
- GetBech32Address() string
- GetAddress() core.AddressHandler
- IsInterfaceNil() bool
-}
-
-// NonceTransactionsHandler represents the interface able to handle the current nonce and the transactions resend mechanism
-type NonceTransactionsHandler interface {
- ApplyNonceAndGasPrice(ctx context.Context, address core.AddressHandler, tx *transaction.FrontendTransaction) error
- SendTransaction(ctx context.Context, tx *transaction.FrontendTransaction) (string, error)
- Close() error
-}
-
-// ContractHandler defines the operations to query the contract state
-type ContractHandler interface {
- IsContractPaused(ctx context.Context) (bool, error)
- GetCreditsPerEGLD(ctx context.Context) (uint64, error)
- GetCredits(ctx context.Context, id uint64) (uint64, error)
- IsInterfaceNil() bool
-}
-
-// Cacher defines the operations to cache data
-type Cacher interface {
- Get(key string) (interface{}, bool)
- Set(key string, value interface{})
- Close()
- IsInterfaceNil() bool
-}
diff --git a/services/crypto-payment/process/relayedTxProcessor.go b/services/crypto-payment/process/relayedTxProcessor.go
deleted file mode 100644
index ecb09ba..0000000
--- a/services/crypto-payment/process/relayedTxProcessor.go
+++ /dev/null
@@ -1,236 +0,0 @@
-package process
-
-import (
- "context"
- "encoding/hex"
- "encoding/json"
- "fmt"
- "time"
-
- "github.com/multiversx/mx-chain-core-go/core/check"
- "github.com/multiversx/mx-chain-core-go/data/transaction"
- "github.com/multiversx/mx-chain-core-go/hashing/keccak"
- "github.com/multiversx/mx-sdk-go/blockchain"
- "github.com/multiversx/mx-sdk-go/builders"
- "github.com/multiversx/mx-sdk-go/core"
- "github.com/multiversx/mx-sdk-go/data"
- "github.com/multiversx/mx-sdk-go/interactors/nonceHandlerV2"
-)
-
-const creditsAddEndpoint = "addCredits"
-const intervalToResendTxs = time.Minute
-
-var hashSigningTxHasher = keccak.NewKeccak()
-
-type relayedTxProcessor struct {
- blockchainDataProvider BlockchainDataProvider
- userKeys MultipleKeysHandler
- relayersKeys map[uint32]SingleKeyHandler
- gasLimit uint64
- contractBech32Address string
- nonceTxHandler NonceTransactionsHandler
-}
-
-// NewRelayedTxProcessor creates a new instance of relayedTxProcessor
-func NewRelayedTxProcessor(
- blockchainDataProvider BlockchainDataProvider,
- userKeys MultipleKeysHandler,
- relayersKeys []SingleKeyHandler,
- gasLimit uint64,
- contractBech32Address string,
-) (*relayedTxProcessor, error) {
- if check.IfNil(blockchainDataProvider) {
- return nil, errNilBlockchainDataProvider
- }
- if check.IfNil(userKeys) {
- return nil, errNilUserKeysHandler
- }
-
- relayersMap, err := makeRelayersMap(relayersKeys, blockchainDataProvider)
- if err != nil {
- return nil, err
- }
-
- if gasLimit == 0 {
- return nil, errZeroGasLimit
- }
- if len(contractBech32Address) == 0 {
- return nil, errEmptyContractBech32Address
- }
-
- argsNonceTxHandler := nonceHandlerV2.ArgsNonceTransactionsHandlerV2{
- Proxy: blockchainDataProvider,
- IntervalToResend: intervalToResendTxs,
- }
-
- nonceTxHandler, err := nonceHandlerV2.NewNonceTransactionHandlerV2(argsNonceTxHandler)
- if err != nil {
- return nil, err
- }
-
- return &relayedTxProcessor{
- blockchainDataProvider: blockchainDataProvider,
- userKeys: userKeys,
- relayersKeys: relayersMap,
- gasLimit: gasLimit,
- contractBech32Address: contractBech32Address,
- nonceTxHandler: nonceTxHandler,
- }, nil
-}
-
-func makeRelayersMap(relayersKeys []SingleKeyHandler, blockchainDataProvider BlockchainDataProvider) (map[uint32]SingleKeyHandler, error) {
- if relayersKeys == nil {
- return nil, errNilRelayersKeysMap
- }
-
- networkConfig, err := blockchainDataProvider.GetNetworkConfig(context.Background())
- if err != nil {
- return nil, err
- }
-
- shardCoordinator, err := blockchain.NewShardCoordinator(networkConfig.NumShardsWithoutMeta, 0)
- if err != nil {
- return nil, err
- }
- relayersMap := make(map[uint32]SingleKeyHandler, len(relayersKeys))
- for _, relayerKey := range relayersKeys {
- shardID, errCompute := shardCoordinator.ComputeShardId(relayerKey.GetAddress())
- if errCompute != nil {
- return nil, errCompute
- }
- relayersMap[shardID] = relayerKey
- }
-
- for shardID := uint32(0); shardID < networkConfig.NumShardsWithoutMeta; shardID++ {
- if check.IfNil(relayersMap[shardID]) {
- return nil, fmt.Errorf("relayer key for shard %d is nil", shardID)
- }
- }
-
- return relayersMap, nil
-}
-
-// Process implements BalanceOperator
-func (processor *relayedTxProcessor) Process(ctx context.Context, id uint64, sender core.AddressHandler, value string, nonce uint64) error {
- networkConfig, err := processor.blockchainDataProvider.GetNetworkConfig(ctx)
- if err != nil {
- return fmt.Errorf("failed to get network config: %w", err)
- }
-
- if check.IfNil(sender) {
- return errNilSender
- }
- senderBech32Address, err := sender.AddressAsBech32String()
- if err != nil {
- return fmt.Errorf("failed to convert sender address to bech32 string: %w", err)
- }
-
- // 1. Prepare the data field
- dataFieldBuilder := builders.NewTxDataBuilder()
- dataField, err := dataFieldBuilder.Function(creditsAddEndpoint).ArgInt64(int64(id)).ToDataBytes()
- if err != nil {
- return fmt.Errorf("failed to build data field: %w", err)
- }
-
- // 2. Assemble the Frontend transaction
- tx := &transaction.FrontendTransaction{
- Nonce: nonce,
- Value: value,
- Receiver: processor.contractBech32Address,
- Sender: senderBech32Address,
- GasLimit: processor.gasLimit,
- Data: dataField,
- ChainID: networkConfig.ChainID,
- Version: networkConfig.MinTransactionVersion,
- }
- err = processor.nonceTxHandler.ApplyNonceAndGasPrice(ctx, sender, tx)
- if err != nil {
- return fmt.Errorf("failed to apply nonce and gas price: %w", err)
- }
-
- // 3. select the correct relayer (same shard with the sender)
- relayerKey, err := processor.selectRelayer(networkConfig, sender)
- if err != nil {
- return fmt.Errorf("failed to select a valid: %w", err)
- }
-
- // 4. add the relayer's address
- tx.RelayerAddr = relayerKey.GetBech32Address()
-
- // 5. Sign the frontend transaction with the key at the provided index
- unsignedtTxBytes, err := generateTransactionBytesToSign(tx)
- if err != nil {
- return fmt.Errorf("failed to generate unsigned tx bytes: %w", err)
- }
-
- userSig, err := processor.userKeys.Sign(uint32(id), unsignedtTxBytes)
- if err != nil {
- return fmt.Errorf("failed to sign the transaction with user key: %w", err)
- }
- tx.Signature = hex.EncodeToString(userSig)
-
- // 6. Sign the frontend transaction with the singleKeyHandler and populate relayer specific fields
- relayerSig, err := relayerKey.Sign(unsignedtTxBytes)
- if err != nil {
- return fmt.Errorf("failed to sign the transaction with relayer key: %w", err)
- }
- tx.RelayerSignature = hex.EncodeToString(relayerSig)
-
- // 7. Send transaction
- hash, err := processor.nonceTxHandler.SendTransaction(ctx, tx)
- if err != nil {
- return fmt.Errorf("failed to send transaction: %w", err)
- }
-
- log.Info("Transaction sent",
- "sender", senderBech32Address,
- "nonce", nonce,
- "value", value,
- "data field", string(dataField),
- "hash", hash)
- return nil
-}
-
-func generateTransactionBytesToSign(tx *transaction.FrontendTransaction) ([]byte, error) {
- txToMarshal := builders.TransactionToUnsignedTx(tx)
- unsignedMessage, err := json.Marshal(txToMarshal)
- if err != nil {
- return nil, err
- }
-
- shouldSignOnTxHash := txToMarshal.Version >= 2 && txToMarshal.Options&1 > 0
- if shouldSignOnTxHash {
- unsignedMessage = hashSigningTxHasher.Compute(string(unsignedMessage))
- }
-
- return unsignedMessage, nil
-}
-
-func (processor *relayedTxProcessor) selectRelayer(networkConfig *data.NetworkConfig, sender core.AddressHandler) (SingleKeyHandler, error) {
- shardCoordinator, err := blockchain.NewShardCoordinator(networkConfig.NumShardsWithoutMeta, 0)
- if err != nil {
- return nil, err
- }
-
- shardID, err := shardCoordinator.ComputeShardId(sender)
- if err != nil {
- return nil, err
- }
-
- relayerKey := processor.relayersKeys[shardID]
- if check.IfNil(relayerKey) {
- return nil, fmt.Errorf("no relayer key found for shard %d", shardID)
- }
-
- return relayerKey, nil
-}
-
-// Close closes any subcomponents it uses
-func (processor *relayedTxProcessor) Close() error {
- return processor.nonceTxHandler.Close()
-}
-
-// IsInterfaceNil returns true if the value under the interface is nil
-func (processor *relayedTxProcessor) IsInterfaceNil() bool {
- return processor == nil
-}
diff --git a/services/crypto-payment/process/relayedTxProcessor_test.go b/services/crypto-payment/process/relayedTxProcessor_test.go
deleted file mode 100644
index d02701c..0000000
--- a/services/crypto-payment/process/relayedTxProcessor_test.go
+++ /dev/null
@@ -1,573 +0,0 @@
-package process
-
-import (
- "bytes"
- "context"
- "encoding/hex"
- "errors"
- "testing"
-
- "github.com/iulianpascalau/mx-epoch-proxy-go/services/crypto-payment/testsCommon"
- "github.com/multiversx/mx-chain-core-go/data/transaction"
- "github.com/multiversx/mx-sdk-go/core"
- "github.com/multiversx/mx-sdk-go/data"
- "github.com/stretchr/testify/assert"
- "github.com/stretchr/testify/require"
-)
-
-func TestNewRelayedTxProcessor(t *testing.T) {
- t.Parallel()
-
- bdp := &testsCommon.BlockchainDataProviderStub{
- GetNetworkConfigHandler: func(ctx context.Context) (*data.NetworkConfig, error) {
- return &data.NetworkConfig{
- NumShardsWithoutMeta: 2,
- }, nil
- },
- }
- userKeys := &testsCommon.MultipleAddressesHandlerStub{}
- relayer0 := &testsCommon.SingleKeyHandler{
- GetAddressHandler: func() core.AddressHandler {
- return data.NewAddressFromBytes(bytes.Repeat([]byte{0}, 32))
- },
- }
- relayer1 := &testsCommon.SingleKeyHandler{
- GetAddressHandler: func() core.AddressHandler {
- return data.NewAddressFromBytes(bytes.Repeat([]byte{1}, 32))
- },
- }
- relayers := []SingleKeyHandler{relayer1, relayer0}
- expectedErr := errors.New("expected error")
-
- t.Run("nil blockchain data provider", func(t *testing.T) {
- proc, err := NewRelayedTxProcessor(nil, userKeys, relayers, 50000, "erd1test")
- require.Nil(t, proc)
- require.Equal(t, errNilBlockchainDataProvider, err)
- assert.True(t, proc.IsInterfaceNil())
- })
-
- t.Run("nil user keys", func(t *testing.T) {
- proc, err := NewRelayedTxProcessor(bdp, nil, relayers, 50000, "erd1test")
- require.Nil(t, proc)
- require.Equal(t, errNilUserKeysHandler, err)
- assert.True(t, proc.IsInterfaceNil())
- })
-
- t.Run("nil relayers keys", func(t *testing.T) {
- proc, err := NewRelayedTxProcessor(bdp, userKeys, nil, 50000, "erd1test")
- require.Nil(t, proc)
- require.Equal(t, errNilRelayersKeysMap, err)
- assert.True(t, proc.IsInterfaceNil())
- })
-
- t.Run("get network config errors", func(t *testing.T) {
- bdpLocal := &testsCommon.BlockchainDataProviderStub{
- GetNetworkConfigHandler: func(ctx context.Context) (*data.NetworkConfig, error) {
- return nil, expectedErr
- },
- }
-
- proc, err := NewRelayedTxProcessor(bdpLocal, userKeys, relayers, 50000, "erd1test")
- require.Nil(t, proc)
- require.Equal(t, expectedErr, err)
- assert.True(t, proc.IsInterfaceNil())
- })
-
- t.Run("network config error for NumShardsWithoutMeta", func(t *testing.T) {
- bdpLocal := &testsCommon.BlockchainDataProviderStub{
- GetNetworkConfigHandler: func(ctx context.Context) (*data.NetworkConfig, error) {
- return &data.NetworkConfig{
- NumShardsWithoutMeta: 0,
- }, nil
- },
- }
-
- proc, err := NewRelayedTxProcessor(bdpLocal, userKeys, relayers, 50000, "erd1test")
- require.Nil(t, proc)
- require.Error(t, err)
- require.Contains(t, err.Error(), "the number of shards must be greater than zero")
- assert.True(t, proc.IsInterfaceNil())
- })
-
- t.Run("missing relayer key for a shard", func(t *testing.T) {
- t.Run("missing shard 1 relayer", func(t *testing.T) {
- relayersLocal := []SingleKeyHandler{relayer0}
-
- proc, err := NewRelayedTxProcessor(bdp, userKeys, relayersLocal, 50000, "erd1test")
- require.Nil(t, proc)
- require.Error(t, err)
- require.Contains(t, err.Error(), "relayer key for shard 1 is nil")
- assert.True(t, proc.IsInterfaceNil())
- })
- t.Run("no relayers", func(t *testing.T) {
- relayersLocal := make([]SingleKeyHandler, 0)
-
- proc, err := NewRelayedTxProcessor(bdp, userKeys, relayersLocal, 50000, "erd1test")
- require.Nil(t, proc)
- require.Error(t, err)
- require.Contains(t, err.Error(), "relayer key for shard 0 is nil")
- assert.True(t, proc.IsInterfaceNil())
- })
- t.Run("missing shard 0 relayer", func(t *testing.T) {
- relayersLocal := []SingleKeyHandler{relayer1}
-
- proc, err := NewRelayedTxProcessor(bdp, userKeys, relayersLocal, 50000, "erd1test")
- require.Nil(t, proc)
- require.Error(t, err)
- require.Contains(t, err.Error(), "relayer key for shard 0 is nil")
- assert.True(t, proc.IsInterfaceNil())
- })
- })
-
- t.Run("zero gas limit", func(t *testing.T) {
- proc, err := NewRelayedTxProcessor(bdp, userKeys, relayers, 0, "erd1test")
- require.Nil(t, proc)
- require.Equal(t, errZeroGasLimit, err)
- assert.True(t, proc.IsInterfaceNil())
- })
-
- t.Run("empty contract address", func(t *testing.T) {
- proc, err := NewRelayedTxProcessor(bdp, userKeys, relayers, 50000, "")
- require.Nil(t, proc)
- require.Equal(t, errEmptyContractBech32Address, err)
- assert.True(t, proc.IsInterfaceNil())
- })
-
- t.Run("success", func(t *testing.T) {
- proc, err := NewRelayedTxProcessor(bdp, userKeys, relayers, 50000, "erd1test")
- require.NotNil(t, proc)
- require.NoError(t, err)
- assert.False(t, proc.IsInterfaceNil())
-
- err = proc.Close()
- require.NoError(t, err)
- })
-}
-
-func TestRelayedTxProcessor_Process(t *testing.T) {
- t.Parallel()
-
- contractAddress := "erd1test"
- senderAddr := data.NewAddressFromBytes(bytes.Repeat([]byte{1}, 32))
- relayerAddr := "erd1relayer"
- gasLimit := uint64(60000000)
- expectedErr := errors.New("expected error")
- notCallableRelayersKeys := []SingleKeyHandler{
- &testsCommon.SingleKeyHandler{
- SignHandler: func(msg []byte) ([]byte, error) {
- assert.Fail(t, "should not be called")
- return nil, nil
- },
- GetBech32AddressHandler: func() string {
- assert.Fail(t, "should not be called")
- return ""
- },
- GetAddressHandler: func() core.AddressHandler {
- return data.NewAddressFromBytes(bytes.Repeat([]byte{1}, 32))
- },
- },
- &testsCommon.SingleKeyHandler{
- SignHandler: func(msg []byte) ([]byte, error) {
- assert.Fail(t, "should not be called")
- return nil, nil
- },
- GetBech32AddressHandler: func() string {
- return relayerAddr
- },
- GetAddressHandler: func() core.AddressHandler {
- return data.NewAddressFromBytes(bytes.Repeat([]byte{0}, 32))
- },
- },
- }
-
- t.Run("nil sender", func(t *testing.T) {
- multipleKeysHandler := &testsCommon.MultipleAddressesHandlerStub{
- SignHandler: func(index uint32, msg []byte) ([]byte, error) {
- assert.Fail(t, "should not be called")
- return nil, nil
- },
- }
-
- bdp := &testsCommon.BlockchainDataProviderStub{
- GetNetworkConfigHandler: func(ctx context.Context) (*data.NetworkConfig, error) {
- return &data.NetworkConfig{
- NumShardsWithoutMeta: 2,
- }, nil
- },
- SendTransactionHandler: func(ctx context.Context, tx *transaction.FrontendTransaction) (string, error) {
- assert.Fail(t, "should not be called")
- return "", nil
- },
- }
-
- proc, err := NewRelayedTxProcessor(bdp, multipleKeysHandler, notCallableRelayersKeys, gasLimit, contractAddress)
- require.NoError(t, err)
-
- err = proc.Process(context.Background(), 5, nil, "1200000000000000000", 37)
- assert.ErrorIs(t, err, errNilSender)
- })
-
- t.Run("invalid sender", func(t *testing.T) {
- multipleKeysHandler := &testsCommon.MultipleAddressesHandlerStub{
- SignHandler: func(index uint32, msg []byte) ([]byte, error) {
- assert.Fail(t, "should not be called")
- return nil, nil
- },
- }
-
- bdp := &testsCommon.BlockchainDataProviderStub{
- GetNetworkConfigHandler: func(ctx context.Context) (*data.NetworkConfig, error) {
- return &data.NetworkConfig{
- NumShardsWithoutMeta: 2,
- }, nil
- },
- SendTransactionHandler: func(ctx context.Context, tx *transaction.FrontendTransaction) (string, error) {
- assert.Fail(t, "should not be called")
- return "", nil
- },
- }
-
- proc, err := NewRelayedTxProcessor(bdp, multipleKeysHandler, notCallableRelayersKeys, gasLimit, contractAddress)
- require.NoError(t, err)
-
- err = proc.Process(context.Background(), 5, data.NewAddressFromBytes([]byte("invalid")), "1200000000000000000", 37)
- assert.Error(t, err)
- assert.Contains(t, err.Error(), "failed to convert sender address to bech32 string: wrong size")
- })
-
- t.Run("network config fetch error", func(t *testing.T) {
- multipleKeysHandler := &testsCommon.MultipleAddressesHandlerStub{
- SignHandler: func(index uint32, msg []byte) ([]byte, error) {
- assert.Fail(t, "should not be called")
- return nil, nil
- },
- }
-
- shouldError := false
- bdp := &testsCommon.BlockchainDataProviderStub{
- GetNetworkConfigHandler: func(ctx context.Context) (*data.NetworkConfig, error) {
- if shouldError {
- return nil, expectedErr
- }
-
- return &data.NetworkConfig{
- NumShardsWithoutMeta: 2,
- }, nil
- },
- SendTransactionHandler: func(ctx context.Context, tx *transaction.FrontendTransaction) (string, error) {
- assert.Fail(t, "should not be called")
- return "", nil
- },
- }
-
- proc, err := NewRelayedTxProcessor(bdp, multipleKeysHandler, notCallableRelayersKeys, gasLimit, contractAddress)
- require.NoError(t, err)
-
- shouldError = true
- err = proc.Process(context.Background(), 5, senderAddr, "1200000000000000000", 37)
- assert.Error(t, err)
- assert.ErrorIs(t, err, expectedErr)
- })
-
- t.Run("user key signature fails", func(t *testing.T) {
- multipleKeysHandler := &testsCommon.MultipleAddressesHandlerStub{
- SignHandler: func(index uint32, msg []byte) ([]byte, error) {
- return nil, expectedErr
- },
- }
-
- bdp := &testsCommon.BlockchainDataProviderStub{
- GetNetworkConfigHandler: func(ctx context.Context) (*data.NetworkConfig, error) {
- return &data.NetworkConfig{
- NumShardsWithoutMeta: 1,
- }, nil
- },
- SendTransactionHandler: func(ctx context.Context, tx *transaction.FrontendTransaction) (string, error) {
- assert.Fail(t, "should not be called")
- return "", nil
- },
- }
-
- proc, err := NewRelayedTxProcessor(bdp, multipleKeysHandler, notCallableRelayersKeys, gasLimit, contractAddress)
- require.NoError(t, err)
-
- err = proc.Process(context.Background(), 5, senderAddr, "1200000000000000000", 37)
- assert.Error(t, err)
- assert.ErrorIs(t, err, expectedErr)
- })
-
- t.Run("wrong network config", func(t *testing.T) {
- multipleKeysHandler := &testsCommon.MultipleAddressesHandlerStub{
- SignHandler: func(index uint32, msg []byte) ([]byte, error) {
- return []byte("userSig"), nil
- },
- }
-
- numShardsWithoutMeta := uint32(2)
- bdp := &testsCommon.BlockchainDataProviderStub{
- GetNetworkConfigHandler: func(ctx context.Context) (*data.NetworkConfig, error) {
- return &data.NetworkConfig{
- NumShardsWithoutMeta: numShardsWithoutMeta,
- }, nil
- },
- SendTransactionHandler: func(ctx context.Context, tx *transaction.FrontendTransaction) (string, error) {
- assert.Fail(t, "should not be called")
- return "", nil
- },
- }
-
- relayersKeys := []SingleKeyHandler{
- &testsCommon.SingleKeyHandler{
- SignHandler: func(msg []byte) ([]byte, error) {
- assert.Fail(t, "should not be called")
- return nil, nil
- },
- GetBech32AddressHandler: func() string {
- assert.Fail(t, "should not be called")
- return ""
- },
- GetAddressHandler: func() core.AddressHandler {
- return data.NewAddressFromBytes(bytes.Repeat([]byte{0}, 32))
- },
- },
- &testsCommon.SingleKeyHandler{
- SignHandler: func(msg []byte) ([]byte, error) {
- return nil, expectedErr
- },
- GetBech32AddressHandler: func() string {
- assert.Fail(t, "should not be called")
- return ""
- },
- GetAddressHandler: func() core.AddressHandler {
- return data.NewAddressFromBytes(bytes.Repeat([]byte{1}, 32))
- },
- },
- }
-
- proc, err := NewRelayedTxProcessor(bdp, multipleKeysHandler, relayersKeys, gasLimit, contractAddress)
- require.NoError(t, err)
-
- numShardsWithoutMeta = 0
- err = proc.Process(context.Background(), 5, senderAddr, "1200000000000000000", 37)
- assert.Error(t, err)
- assert.Contains(t, err.Error(), "failed to select a valid: the number of shards must be greater than zero")
- })
-
- t.Run("missing relayer key fails", func(t *testing.T) {
- multipleKeysHandler := &testsCommon.MultipleAddressesHandlerStub{
- SignHandler: func(index uint32, msg []byte) ([]byte, error) {
- return []byte("userSig"), nil
- },
- }
-
- bdp := &testsCommon.BlockchainDataProviderStub{
- GetNetworkConfigHandler: func(ctx context.Context) (*data.NetworkConfig, error) {
- return &data.NetworkConfig{
- NumShardsWithoutMeta: 2,
- }, nil
- },
- SendTransactionHandler: func(ctx context.Context, tx *transaction.FrontendTransaction) (string, error) {
- assert.Fail(t, "should not be called")
- return "", nil
- },
- }
-
- relayersKeys := []SingleKeyHandler{
- &testsCommon.SingleKeyHandler{
- SignHandler: func(msg []byte) ([]byte, error) {
- assert.Fail(t, "should not be called")
- return nil, nil
- },
- GetBech32AddressHandler: func() string {
- assert.Fail(t, "should not be called")
- return ""
- },
- GetAddressHandler: func() core.AddressHandler {
- return data.NewAddressFromBytes(bytes.Repeat([]byte{0}, 32))
- },
- },
- &testsCommon.SingleKeyHandler{
- SignHandler: func(msg []byte) ([]byte, error) {
- return nil, expectedErr
- },
- GetBech32AddressHandler: func() string {
- assert.Fail(t, "should not be called")
- return ""
- },
- GetAddressHandler: func() core.AddressHandler {
- return data.NewAddressFromBytes(bytes.Repeat([]byte{1}, 32))
- },
- },
- }
-
- proc, err := NewRelayedTxProcessor(bdp, multipleKeysHandler, relayersKeys, gasLimit, contractAddress)
- require.NoError(t, err)
-
- delete(proc.relayersKeys, 1)
- err = proc.Process(context.Background(), 5, senderAddr, "1200000000000000000", 37)
- assert.Error(t, err)
- assert.Contains(t, err.Error(), "failed to select a valid: no relayer key found for shard 1")
- })
-
- t.Run("relayer key signature fails", func(t *testing.T) {
- multipleKeysHandler := &testsCommon.MultipleAddressesHandlerStub{
- SignHandler: func(index uint32, msg []byte) ([]byte, error) {
- return []byte("userSig"), nil
- },
- }
-
- bdp := &testsCommon.BlockchainDataProviderStub{
- GetNetworkConfigHandler: func(ctx context.Context) (*data.NetworkConfig, error) {
- return &data.NetworkConfig{
- NumShardsWithoutMeta: 2,
- }, nil
- },
- SendTransactionHandler: func(ctx context.Context, tx *transaction.FrontendTransaction) (string, error) {
- assert.Fail(t, "should not be called")
- return "", nil
- },
- }
-
- relayersKeys := []SingleKeyHandler{
- &testsCommon.SingleKeyHandler{
- SignHandler: func(msg []byte) ([]byte, error) {
- assert.Fail(t, "should not be called")
- return nil, nil
- },
- GetBech32AddressHandler: func() string {
- assert.Fail(t, "should not be called")
- return ""
- },
- GetAddressHandler: func() core.AddressHandler {
- return data.NewAddressFromBytes(bytes.Repeat([]byte{0}, 32))
- },
- },
- &testsCommon.SingleKeyHandler{
- SignHandler: func(msg []byte) ([]byte, error) {
- return nil, expectedErr
- },
- GetBech32AddressHandler: func() string {
- return relayerAddr
- },
- GetAddressHandler: func() core.AddressHandler {
- return data.NewAddressFromBytes(bytes.Repeat([]byte{1}, 32))
- },
- },
- }
-
- proc, err := NewRelayedTxProcessor(bdp, multipleKeysHandler, relayersKeys, gasLimit, contractAddress)
- require.NoError(t, err)
-
- err = proc.Process(context.Background(), 5, senderAddr, "1200000000000000000", 37)
- assert.Error(t, err)
- assert.ErrorIs(t, err, expectedErr)
- })
-
- t.Run("transaction send errors", func(t *testing.T) {
- multipleKeysHandler := &testsCommon.MultipleAddressesHandlerStub{
- SignHandler: func(index uint32, msg []byte) ([]byte, error) {
- return []byte("userSig"), nil
- },
- }
- relayersKeys := []SingleKeyHandler{
- &testsCommon.SingleKeyHandler{
- SignHandler: func(msg []byte) ([]byte, error) {
- return []byte("relayerSig"), nil
- },
- GetBech32AddressHandler: func() string {
- return relayerAddr
- },
- GetAddressHandler: func() core.AddressHandler {
- return data.NewAddressFromBytes(bytes.Repeat([]byte{0}, 32))
- },
- },
- }
-
- bdp := &testsCommon.BlockchainDataProviderStub{
- GetNetworkConfigHandler: func(ctx context.Context) (*data.NetworkConfig, error) {
- return &data.NetworkConfig{
- NumShardsWithoutMeta: 1,
- }, nil
- },
- SendTransactionHandler: func(ctx context.Context, tx *transaction.FrontendTransaction) (string, error) {
- return "", expectedErr
- },
- }
-
- proc, err := NewRelayedTxProcessor(bdp, multipleKeysHandler, relayersKeys, gasLimit, contractAddress)
- require.NoError(t, err)
-
- err = proc.Process(context.Background(), 5, senderAddr, "1200000000000000000", 37)
- assert.Error(t, err)
- assert.ErrorIs(t, err, expectedErr)
- })
-
- t.Run("shuld work", func(t *testing.T) {
- multipleKeysHandler := &testsCommon.MultipleAddressesHandlerStub{
- SignHandler: func(index uint32, msg []byte) ([]byte, error) {
- assert.Equal(t, uint32(5), index)
- return []byte("userSig"), nil
- },
- }
- relayersKeys := []SingleKeyHandler{
- &testsCommon.SingleKeyHandler{
- SignHandler: func(msg []byte) ([]byte, error) {
- return []byte("relayerSig"), nil
- },
- GetBech32AddressHandler: func() string {
- return relayerAddr
- },
- GetAddressHandler: func() core.AddressHandler {
- return data.NewAddressFromBytes(bytes.Repeat([]byte{0}, 32))
- },
- },
- }
-
- sendWasCalled := false
- bdp := &testsCommon.BlockchainDataProviderStub{
- GetNetworkConfigHandler: func(ctx context.Context) (*data.NetworkConfig, error) {
- return &data.NetworkConfig{
- ChainID: "T",
- MinGasPrice: 1000000000,
- MinTransactionVersion: 1,
- NumShardsWithoutMeta: 1,
- }, nil
- },
- GetAccountHandler: func(ctx context.Context, address core.AddressHandler) (*data.Account, error) {
- if bytes.Equal(address.AddressBytes(), senderAddr.AddressBytes()) {
- return &data.Account{
- Nonce: 37,
- }, nil
- }
-
- return &data.Account{}, nil
- },
- SendTransactionHandler: func(ctx context.Context, tx *transaction.FrontendTransaction) (string, error) {
- assert.Equal(t, uint64(37), tx.Nonce)
- assert.Equal(t, "1200000000000000000", tx.Value)
- assert.Equal(t, contractAddress, tx.Receiver)
- senderBech32, _ := senderAddr.AddressAsBech32String()
- assert.Equal(t, senderBech32, tx.Sender)
- assert.Equal(t, uint64(1000000000), tx.GasPrice)
- assert.Equal(t, gasLimit, tx.GasLimit)
- assert.Equal(t, []byte("addCredits@05"), tx.Data)
- assert.Equal(t, "T", tx.ChainID)
- assert.Equal(t, uint32(1), tx.Version)
- assert.Equal(t, hex.EncodeToString([]byte("userSig")), tx.Signature)
- assert.Equal(t, relayerAddr, tx.RelayerAddr)
- assert.Equal(t, hex.EncodeToString([]byte("relayerSig")), tx.RelayerSignature)
-
- sendWasCalled = true
-
- return "txHash", nil
- },
- }
-
- proc, err := NewRelayedTxProcessor(bdp, multipleKeysHandler, relayersKeys, gasLimit, contractAddress)
- require.NoError(t, err)
-
- err = proc.Process(context.Background(), 5, senderAddr, "1200000000000000000", 37)
- assert.NoError(t, err)
- assert.True(t, sendWasCalled)
- })
-}
diff --git a/services/crypto-payment/storage/cacher.go b/services/crypto-payment/storage/cacher.go
deleted file mode 100644
index 301c222..0000000
--- a/services/crypto-payment/storage/cacher.go
+++ /dev/null
@@ -1,76 +0,0 @@
-package storage
-
-import (
- "sync"
- "time"
-)
-
-type timeCacher struct {
- mut sync.RWMutex
- data map[string]interface{}
- ttl time.Duration
- stop chan struct{}
-}
-
-// NewTimeCacher creates a new time cacher. Concurrent safe component.
-func NewTimeCacher(ttl time.Duration) *timeCacher {
- tc := &timeCacher{
- data: make(map[string]interface{}),
- ttl: ttl,
- stop: make(chan struct{}),
- }
-
- go tc.cleanupLoop()
-
- return tc
-}
-
-// Get will try to get the value for the provided key, returning it and a boolean indicating whether the value was found
-func (tc *timeCacher) Get(key string) (interface{}, bool) {
- tc.mut.RLock()
- defer tc.mut.RUnlock()
-
- rec, found := tc.data[key]
-
- return rec, found
-}
-
-// Set will set the value for the provided key, overwriting any existing value
-func (tc *timeCacher) Set(key string, value interface{}) {
- tc.mut.Lock()
- defer tc.mut.Unlock()
-
- tc.data[key] = value
-}
-
-// Close stops the cleanup loop
-func (tc *timeCacher) Close() {
- close(tc.stop)
-}
-
-func (tc *timeCacher) cleanupLoop() {
- ticker := time.NewTicker(tc.ttl)
- defer ticker.Stop()
-
- for {
- select {
- case <-tc.stop:
- return
- case <-ticker.C:
- tc.cleanup()
- }
- }
-}
-
-// cleanup clears the entire cache
-func (tc *timeCacher) cleanup() {
- tc.mut.Lock()
- defer tc.mut.Unlock()
-
- tc.data = make(map[string]interface{})
-}
-
-// IsInterfaceNil returns true if the value under the interface is nil
-func (tc *timeCacher) IsInterfaceNil() bool {
- return tc == nil
-}
diff --git a/services/crypto-payment/storage/cacher_test.go b/services/crypto-payment/storage/cacher_test.go
deleted file mode 100644
index 5bc4da2..0000000
--- a/services/crypto-payment/storage/cacher_test.go
+++ /dev/null
@@ -1,98 +0,0 @@
-package storage
-
-import (
- "testing"
- "time"
-
- "github.com/stretchr/testify/require"
-)
-
-func TestTimeCacher_SetGet(t *testing.T) {
- t.Parallel()
-
- tc := NewTimeCacher(time.Minute)
- defer tc.Close()
-
- key := "key"
- val := "value"
-
- tc.Set(key, val)
-
- res, found := tc.Get(key)
- require.True(t, found)
- require.Equal(t, val, res)
-}
-
-func TestTimeCacher_Expiration(t *testing.T) {
- t.Parallel()
-
- ttl := 50 * time.Millisecond
- tc := NewTimeCacher(ttl)
- defer tc.Close()
-
- key := "key"
- val := "value"
-
- tc.Set(key, val)
-
- // fast check
- res, found := tc.Get(key)
- require.True(t, found)
- require.Equal(t, val, res)
-
- // wait for expiration (flush)
- time.Sleep(ttl * 2)
-
- res, found = tc.Get(key)
- require.False(t, found)
- require.Nil(t, res)
-}
-
-func TestTimeCacher_Cleanup(t *testing.T) {
- t.Parallel()
-
- // Short TTL to trigger cleanup quickly
- ttl := 10 * time.Millisecond
- tc := NewTimeCacher(ttl)
- defer tc.Close()
-
- key := "key"
- val := "value"
-
- tc.Set(key, val)
-
- // Wait for cleanup loop to run: ttl + tiny buffer
- time.Sleep(ttl * 2)
-
- // key should have been removed from the map
- tc.mut.RLock()
- _, found := tc.data[key]
- tc.mut.RUnlock()
- require.False(t, found, "key should have been removed by background cleanup")
-}
-
-func TestTimeCacher_ConcurrentAccess(t *testing.T) {
- t.Parallel()
-
- tc := NewTimeCacher(time.Millisecond * 10)
- defer tc.Close()
-
- key := "key"
- val := "value"
-
- // Start concurrent writes
- go func() {
- for i := 0; i < 100; i++ {
- tc.Set(key, val)
- time.Sleep(time.Millisecond)
- }
- }()
-
- // Start concurrent reads
- go func() {
- for i := 0; i < 100; i++ {
- tc.Get(key)
- time.Sleep(time.Millisecond)
- }
- }()
-}
diff --git a/services/crypto-payment/storage/errors.go b/services/crypto-payment/storage/errors.go
deleted file mode 100644
index 5be360c..0000000
--- a/services/crypto-payment/storage/errors.go
+++ /dev/null
@@ -1,5 +0,0 @@
-package storage
-
-import "errors"
-
-var errNilMultipleAddressesHandler = errors.New("nil multiple addresses handler")
diff --git a/services/crypto-payment/storage/interface.go b/services/crypto-payment/storage/interface.go
deleted file mode 100644
index fd7bf99..0000000
--- a/services/crypto-payment/storage/interface.go
+++ /dev/null
@@ -1,7 +0,0 @@
-package storage
-
-// MultipleAddressesHandler defines the operations implemented by a struct able to hold and manage keys & addresses
-type MultipleAddressesHandler interface {
- GetBech32AddressAtIndex(index uint32) (string, error)
- IsInterfaceNil() bool
-}
diff --git a/services/crypto-payment/storage/sqliteWrapper.go b/services/crypto-payment/storage/sqliteWrapper.go
deleted file mode 100644
index ac6bf3d..0000000
--- a/services/crypto-payment/storage/sqliteWrapper.go
+++ /dev/null
@@ -1,164 +0,0 @@
-package storage
-
-import (
- "database/sql"
- "fmt"
- "os"
- "path/filepath"
-
- "github.com/iulianpascalau/mx-epoch-proxy-go/services/crypto-payment/common"
- _ "github.com/mattn/go-sqlite3"
- "github.com/multiversx/mx-chain-core-go/core/check"
-)
-
-// sqliteWrapper handles the connection to the SQLite database
-type sqliteWrapper struct {
- db *sql.DB
- addressHandler MultipleAddressesHandler
-}
-
-// NewSQLiteWrapper creates a new instance of SQLiteWrapper
-func NewSQLiteWrapper(dbPath string, addressHandler MultipleAddressesHandler) (*sqliteWrapper, error) {
- if check.IfNil(addressHandler) {
- return nil, errNilMultipleAddressesHandler
- }
-
- err := prepareDirectories(dbPath)
- if err != nil {
- return nil, fmt.Errorf("failed to create initial empty DB file: %w", err)
- }
-
- db, err := sql.Open("sqlite3", dbPath+"?_foreign_keys=on")
- if err != nil {
- return nil, fmt.Errorf("failed to open sqlite db: %w", err)
- }
-
- err = db.Ping()
- if err != nil {
- return nil, fmt.Errorf("failed to ping sqlite db: %w", err)
- }
-
- // Enable WAL mode for better performance
- _, _ = db.Exec("PRAGMA journal_mode=WAL;")
- _, _ = db.Exec("PRAGMA synchronous=NORMAL;")
-
- wrapper := &sqliteWrapper{
- db: db,
- addressHandler: addressHandler,
- }
- err = wrapper.initializeTables()
- if err != nil {
- _ = db.Close()
- return nil, err
- }
-
- return wrapper, nil
-}
-
-func prepareDirectories(dbPath string) error {
- return os.MkdirAll(filepath.Dir(dbPath), os.ModePerm)
-}
-
-func (wrapper *sqliteWrapper) initializeTables() error {
- query := `
- CREATE TABLE IF NOT EXISTS balance_management (
- id INTEGER PRIMARY KEY AUTOINCREMENT,
- address TEXT
- );`
- _, err := wrapper.db.Exec(query)
- if err != nil {
- return fmt.Errorf("failed to create balance_management table: %w", err)
- }
- return nil
-}
-
-// Get returns the row based on the ID
-func (wrapper *sqliteWrapper) Get(id uint64) (*common.BalanceEntry, error) {
- query := `SELECT id, address FROM balance_management WHERE id = ?`
- row := wrapper.db.QueryRow(query, id)
-
- var entry common.BalanceEntry
- err := row.Scan(&entry.ID, &entry.Address)
- if err != nil {
- if err == sql.ErrNoRows {
- return nil, fmt.Errorf("entry with id %d not found", id)
- }
- return nil, fmt.Errorf("failed to get entry: %w", err)
- }
-
- return &entry, nil
-}
-
-// Add creates a new entry and returns the created id
-func (wrapper *sqliteWrapper) Add() (uint64, error) {
- tx, err := wrapper.db.Begin()
- if err != nil {
- return 0, fmt.Errorf("failed to begin transaction: %w", err)
- }
- defer func() {
- _ = tx.Rollback()
- }()
-
- query := `INSERT INTO balance_management (address) VALUES ("")`
- result, err := tx.Exec(query)
- if err != nil {
- return 0, fmt.Errorf("failed to add entry: %w", err)
- }
-
- id, err := result.LastInsertId()
- if err != nil {
- return 0, fmt.Errorf("failed to get last insert id: %w", err)
- }
-
- address, err := wrapper.addressHandler.GetBech32AddressAtIndex(uint32(id))
- if err != nil {
- return 0, fmt.Errorf("failed to generate address: %w", err)
- }
-
- updateQuery := `UPDATE balance_management SET address = ? WHERE id = ?`
- _, err = tx.Exec(updateQuery, address, id)
- if err != nil {
- return 0, fmt.Errorf("failed to update address: %w", err)
- }
-
- err = tx.Commit()
- if err != nil {
- return 0, fmt.Errorf("failed to commit transaction: %w", err)
- }
-
- return uint64(id), nil
-}
-
-// GetAll provides all rows
-func (wrapper *sqliteWrapper) GetAll() ([]*common.BalanceEntry, error) {
- query := `SELECT id, address FROM balance_management`
- rows, err := wrapper.db.Query(query)
- if err != nil {
- return nil, fmt.Errorf("failed to query all entries: %w", err)
- }
- defer func() {
- _ = rows.Close()
- }()
-
- var entries []*common.BalanceEntry
- for rows.Next() {
- var entry common.BalanceEntry
- err = rows.Scan(&entry.ID, &entry.Address)
- if err != nil {
- return nil, fmt.Errorf("failed to scan entry: %w", err)
- }
- entries = append(entries, &entry)
- }
-
- return entries, nil
-}
-
-// Close closes the database connection
-func (wrapper *sqliteWrapper) Close() error {
- return wrapper.db.Close()
-}
-
-// IsInterfaceNil returns true if the value under the interface is nil
-func (wrapper *sqliteWrapper) IsInterfaceNil() bool {
- return wrapper == nil
-}
diff --git a/services/crypto-payment/storage/sqliteWrapper_test.go b/services/crypto-payment/storage/sqliteWrapper_test.go
deleted file mode 100644
index bc031f4..0000000
--- a/services/crypto-payment/storage/sqliteWrapper_test.go
+++ /dev/null
@@ -1,145 +0,0 @@
-package storage
-
-import (
- "fmt"
- "path/filepath"
- "testing"
-
- "github.com/iulianpascalau/mx-epoch-proxy-go/services/crypto-payment/testsCommon"
- "github.com/stretchr/testify/assert"
- "github.com/stretchr/testify/require"
-)
-
-func TestNewSQLiteWrapper(t *testing.T) {
- tmpDir := t.TempDir()
- dbPath := filepath.Join(tmpDir, "test.db")
-
- t.Run("nil address handler", func(t *testing.T) {
- wrapper, err := NewSQLiteWrapper(dbPath, nil)
- require.Nil(t, wrapper)
- require.Equal(t, errNilMultipleAddressesHandler, err)
- assert.True(t, wrapper.IsInterfaceNil())
- })
-
- t.Run("success", func(t *testing.T) {
- wrapper, err := NewSQLiteWrapper(dbPath, &testsCommon.MultipleAddressesHandlerStub{})
- require.NoError(t, err)
- defer func() {
- _ = wrapper.Close()
- }()
-
- require.FileExists(t, dbPath)
- assert.False(t, wrapper.IsInterfaceNil())
- })
-}
-
-func TestSQLiteWrapper_AddAndGet(t *testing.T) {
- tmpDir := t.TempDir()
- dbPath := filepath.Join(tmpDir, "test.db")
-
- mockAddr := &testsCommon.MultipleAddressesHandlerStub{
- GetBech32AddressAtIndexHandler: func(index uint32) (string, error) {
- return fmt.Sprintf("mock-addr-%d", index), nil
- },
- }
-
- wrapper, err := NewSQLiteWrapper(dbPath, mockAddr)
- require.NoError(t, err)
- defer func() {
- _ = wrapper.Close()
- }()
-
- // Test Add
- id, err := wrapper.Add()
- require.NoError(t, err)
- require.NotZero(t, id)
-
- // Test Get
-
- entry, err := wrapper.Get(id)
- require.NoError(t, err)
- require.NotNil(t, entry)
- require.Equal(t, id, entry.ID)
- require.NotNil(t, entry)
- require.Equal(t, id, entry.ID)
- require.Equal(t, fmt.Sprintf("mock-addr-%d", id), entry.Address)
-}
-
-func TestSQLiteWrapper_GetAll(t *testing.T) {
- tmpDir := t.TempDir()
- dbPath := filepath.Join(tmpDir, "test.db")
-
- wrapper, err := NewSQLiteWrapper(dbPath, &testsCommon.MultipleAddressesHandlerStub{})
- require.NoError(t, err)
- defer func() {
- _ = wrapper.Close()
- }()
-
- // Add multiple entries
- count := 5
- ids := make([]uint64, 0, count)
- for i := 0; i < count; i++ {
- id, errAdd := wrapper.Add()
- require.NoError(t, errAdd)
- ids = append(ids, id)
- }
-
- // Test GetAll
- entries, err := wrapper.GetAll()
- require.NoError(t, err)
- require.Len(t, entries, count)
-
- // Verify IDs present
- retrievedIDs := make(map[uint64]bool)
- for _, e := range entries {
- retrievedIDs[e.ID] = true
- }
-
- for _, id := range ids {
- require.True(t, retrievedIDs[id])
- }
-}
-
-func TestSQLiteWrapper_GetNonExistent(t *testing.T) {
- tmpDir := t.TempDir()
- dbPath := filepath.Join(tmpDir, "test.db")
-
- wrapper, err := NewSQLiteWrapper(dbPath, &testsCommon.MultipleAddressesHandlerStub{})
- require.NoError(t, err)
- defer func() {
- _ = wrapper.Close()
- }()
-
- _, err = wrapper.Get(999)
- require.Error(t, err)
- require.Contains(t, err.Error(), "entry with id 999 not found")
-}
-
-func TestSQLiteWrapper_Add_ErrorGeneratingAddress(t *testing.T) {
- tmpDir := t.TempDir()
- dbPath := filepath.Join(tmpDir, "test.db")
-
- expectedErr := fmt.Errorf("gen error")
- mockAddr := &testsCommon.MultipleAddressesHandlerStub{
- GetBech32AddressAtIndexHandler: func(index uint32) (string, error) {
- return "", expectedErr
- },
- }
-
- wrapper, err := NewSQLiteWrapper(dbPath, mockAddr)
- require.NoError(t, err)
- defer func() {
- _ = wrapper.Close()
- }()
-
- id, err := wrapper.Add()
- require.Error(t, err)
- require.Contains(t, err.Error(), "failed to generate address")
- require.Contains(t, err.Error(), expectedErr.Error())
- require.Zero(t, id)
-
- // Verify nothing was inserted (transaction rolled back)
- entries, err := wrapper.GetAll()
- require.NoError(t, err)
- require.Empty(t, entries)
-}
diff --git a/services/crypto-payment/testsCommon/balanceOperatorStub.go b/services/crypto-payment/testsCommon/balanceOperatorStub.go
deleted file mode 100644
index f72a4e6..0000000
--- a/services/crypto-payment/testsCommon/balanceOperatorStub.go
+++ /dev/null
@@ -1,36 +0,0 @@
-package testsCommon
-
-import (
- "context"
-
- "github.com/multiversx/mx-sdk-go/core"
-)
-
-// BalanceOperatorStub -
-type BalanceOperatorStub struct {
- ProcessHandler func(ctx context.Context, id uint64, sender core.AddressHandler, balance string, nonce uint64) error
- CloseHandler func() error
-}
-
-// Process -
-func (stub *BalanceOperatorStub) Process(ctx context.Context, id uint64, sender core.AddressHandler, balance string, nonce uint64) error {
- if stub.ProcessHandler != nil {
- return stub.ProcessHandler(ctx, id, sender, balance, nonce)
- }
-
- return nil
-}
-
-// Close -
-func (stub *BalanceOperatorStub) Close() error {
- if stub.CloseHandler != nil {
- return stub.CloseHandler()
- }
-
- return nil
-}
-
-// IsInterfaceNil -
-func (stub *BalanceOperatorStub) IsInterfaceNil() bool {
- return stub == nil
-}
diff --git a/services/crypto-payment/testsCommon/blockchainDataProviderStub.go b/services/crypto-payment/testsCommon/blockchainDataProviderStub.go
deleted file mode 100644
index 6fb805d..0000000
--- a/services/crypto-payment/testsCommon/blockchainDataProviderStub.go
+++ /dev/null
@@ -1,66 +0,0 @@
-package testsCommon
-
-import (
- "context"
-
- "github.com/multiversx/mx-chain-core-go/data/transaction"
- "github.com/multiversx/mx-sdk-go/core"
- "github.com/multiversx/mx-sdk-go/data"
-)
-
-// BlockchainDataProviderStub -
-type BlockchainDataProviderStub struct {
- GetAccountHandler func(ctx context.Context, address core.AddressHandler) (*data.Account, error)
- GetNetworkConfigHandler func(ctx context.Context) (*data.NetworkConfig, error)
- SendTransactionHandler func(ctx context.Context, transaction *transaction.FrontendTransaction) (string, error)
- SendTransactionsHandler func(ctx context.Context, txs []*transaction.FrontendTransaction) ([]string, error)
- ExecuteVMQueryHandler func(ctx context.Context, vmRequest *data.VmValueRequest) (*data.VmValuesResponseData, error)
-}
-
-// SendTransactions -
-func (stub *BlockchainDataProviderStub) SendTransactions(ctx context.Context, txs []*transaction.FrontendTransaction) ([]string, error) {
- if stub.SendTransactionsHandler != nil {
- return stub.SendTransactionsHandler(ctx, txs)
- }
-
- return make([]string, 0), nil
-}
-
-// GetAccount -
-func (stub *BlockchainDataProviderStub) GetAccount(ctx context.Context, address core.AddressHandler) (*data.Account, error) {
- if stub.GetAccountHandler != nil {
- return stub.GetAccountHandler(ctx, address)
- }
-
- return &data.Account{}, nil
-}
-
-// GetNetworkConfig -
-func (stub *BlockchainDataProviderStub) GetNetworkConfig(ctx context.Context) (*data.NetworkConfig, error) {
- if stub.GetNetworkConfigHandler != nil {
- return stub.GetNetworkConfigHandler(ctx)
- }
- return &data.NetworkConfig{}, nil
-}
-
-// SendTransaction -
-func (stub *BlockchainDataProviderStub) SendTransaction(ctx context.Context, transaction *transaction.FrontendTransaction) (string, error) {
- if stub.SendTransactionHandler != nil {
- return stub.SendTransactionHandler(ctx, transaction)
- }
- return "", nil
-}
-
-// ExecuteVMQuery -
-func (stub *BlockchainDataProviderStub) ExecuteVMQuery(ctx context.Context, vmRequest *data.VmValueRequest) (*data.VmValuesResponseData, error) {
- if stub.ExecuteVMQueryHandler != nil {
- return stub.ExecuteVMQueryHandler(ctx, vmRequest)
- }
-
- return &data.VmValuesResponseData{}, nil
-}
-
-// IsInterfaceNil -
-func (stub *BlockchainDataProviderStub) IsInterfaceNil() bool {
- return stub == nil
-}
diff --git a/services/crypto-payment/testsCommon/cacherStub.go b/services/crypto-payment/testsCommon/cacherStub.go
deleted file mode 100644
index 7920bd7..0000000
--- a/services/crypto-payment/testsCommon/cacherStub.go
+++ /dev/null
@@ -1,36 +0,0 @@
-package testsCommon
-
-// CacherStub -
-type CacherStub struct {
- GetHandler func(key string) (interface{}, bool)
- SetHandler func(key string, value interface{})
- CloseHandler func()
- IsInterfaceNilHandler func() bool
-}
-
-// Get -
-func (stub *CacherStub) Get(key string) (interface{}, bool) {
- if stub.GetHandler != nil {
- return stub.GetHandler(key)
- }
- return nil, false
-}
-
-// Set -
-func (stub *CacherStub) Set(key string, value interface{}) {
- if stub.SetHandler != nil {
- stub.SetHandler(key, value)
- }
-}
-
-// Close -
-func (stub *CacherStub) Close() {
- if stub.CloseHandler != nil {
- stub.CloseHandler()
- }
-}
-
-// IsInterfaceNil -
-func (stub *CacherStub) IsInterfaceNil() bool {
- return stub == nil
-}
diff --git a/services/crypto-payment/testsCommon/contractHandlerStub.go b/services/crypto-payment/testsCommon/contractHandlerStub.go
deleted file mode 100644
index 04aab9c..0000000
--- a/services/crypto-payment/testsCommon/contractHandlerStub.go
+++ /dev/null
@@ -1,39 +0,0 @@
-package testsCommon
-
-import "context"
-
-// ContractHandlerStub -
-type ContractHandlerStub struct {
- IsContractPausedHandler func(ctx context.Context) (bool, error)
- GetCreditsPerEGLDHandler func(ctx context.Context) (uint64, error)
- GetCreditsHandler func(ctx context.Context, id uint64) (uint64, error)
-}
-
-// IsContractPaused -
-func (stub *ContractHandlerStub) IsContractPaused(ctx context.Context) (bool, error) {
- if stub.IsContractPausedHandler != nil {
- return stub.IsContractPausedHandler(ctx)
- }
- return false, nil
-}
-
-// GetCreditsPerEGLD -
-func (stub *ContractHandlerStub) GetCreditsPerEGLD(ctx context.Context) (uint64, error) {
- if stub.GetCreditsPerEGLDHandler != nil {
- return stub.GetCreditsPerEGLDHandler(ctx)
- }
- return 0, nil
-}
-
-// GetCredits -
-func (stub *ContractHandlerStub) GetCredits(ctx context.Context, id uint64) (uint64, error) {
- if stub.GetCreditsHandler != nil {
- return stub.GetCreditsHandler(ctx, id)
- }
- return 0, nil
-}
-
-// IsInterfaceNil -
-func (stub *ContractHandlerStub) IsInterfaceNil() bool {
- return stub == nil
-}
diff --git a/services/crypto-payment/testsCommon/dataProviderStub.go b/services/crypto-payment/testsCommon/dataProviderStub.go
deleted file mode 100644
index 0a85c63..0000000
--- a/services/crypto-payment/testsCommon/dataProviderStub.go
+++ /dev/null
@@ -1,32 +0,0 @@
-package testsCommon
-
-import "github.com/iulianpascalau/mx-epoch-proxy-go/services/crypto-payment/common"
-
-// DataProviderStub -
-type DataProviderStub struct {
- GetAllHandler func() ([]*common.BalanceEntry, error)
- GetHandler func(id uint64) (*common.BalanceEntry, error)
-}
-
-// GetAll -
-func (stub *DataProviderStub) GetAll() ([]*common.BalanceEntry, error) {
- if stub.GetAllHandler != nil {
- return stub.GetAllHandler()
- }
-
- return make([]*common.BalanceEntry, 0), nil
-}
-
-// Get -
-func (stub *DataProviderStub) Get(id uint64) (*common.BalanceEntry, error) {
- if stub.GetHandler != nil {
- return stub.GetHandler(id)
- }
-
- return nil, nil
-}
-
-// IsInterfaceNil -
-func (stub *DataProviderStub) IsInterfaceNil() bool {
- return stub == nil
-}
diff --git a/services/crypto-payment/testsCommon/multipleAddressesHandlerStub.go b/services/crypto-payment/testsCommon/multipleAddressesHandlerStub.go
deleted file mode 100644
index 093702b..0000000
--- a/services/crypto-payment/testsCommon/multipleAddressesHandlerStub.go
+++ /dev/null
@@ -1,30 +0,0 @@
-package testsCommon
-
-// MultipleAddressesHandlerStub -
-type MultipleAddressesHandlerStub struct {
- SignHandler func(index uint32, msg []byte) ([]byte, error)
- GetBech32AddressAtIndexHandler func(index uint32) (string, error)
-}
-
-// Sign -
-func (stub *MultipleAddressesHandlerStub) Sign(index uint32, msg []byte) ([]byte, error) {
- if stub.SignHandler != nil {
- return stub.SignHandler(index, msg)
- }
-
- return make([]byte, 0), nil
-}
-
-// GetBech32AddressAtIndex -
-func (stub *MultipleAddressesHandlerStub) GetBech32AddressAtIndex(index uint32) (string, error) {
- if stub.GetBech32AddressAtIndexHandler != nil {
- return stub.GetBech32AddressAtIndexHandler(index)
- }
-
- return "", nil
-}
-
-// IsInterfaceNil -
-func (stub *MultipleAddressesHandlerStub) IsInterfaceNil() bool {
- return stub == nil
-}
diff --git a/services/crypto-payment/testsCommon/singleKeyHandler.go b/services/crypto-payment/testsCommon/singleKeyHandler.go
deleted file mode 100644
index d425bcb..0000000
--- a/services/crypto-payment/testsCommon/singleKeyHandler.go
+++ /dev/null
@@ -1,42 +0,0 @@
-package testsCommon
-
-import "github.com/multiversx/mx-sdk-go/core"
-
-// SingleKeyHandler -
-type SingleKeyHandler struct {
- SignHandler func(msg []byte) ([]byte, error)
- GetBech32AddressHandler func() string
- GetAddressHandler func() core.AddressHandler
-}
-
-// Sign -
-func (stub *SingleKeyHandler) Sign(msg []byte) ([]byte, error) {
- if stub.SignHandler != nil {
- return stub.SignHandler(msg)
- }
-
- return make([]byte, 0), nil
-}
-
-// GetBech32Address -
-func (stub *SingleKeyHandler) GetBech32Address() string {
- if stub.GetBech32AddressHandler != nil {
- return stub.GetBech32AddressHandler()
- }
-
- return ""
-}
-
-// GetAddress -
-func (stub *SingleKeyHandler) GetAddress() core.AddressHandler {
- if stub.GetAddressHandler != nil {
- return stub.GetAddressHandler()
- }
-
- return nil
-}
-
-// IsInterfaceNil -
-func (stub *SingleKeyHandler) IsInterfaceNil() bool {
- return stub == nil
-}
diff --git a/services/crypto-payment/testsCommon/walletStub.go b/services/crypto-payment/testsCommon/walletStub.go
deleted file mode 100644
index 8003f50..0000000
--- a/services/crypto-payment/testsCommon/walletStub.go
+++ /dev/null
@@ -1,29 +0,0 @@
-package testsCommon
-
-import (
- "github.com/multiversx/mx-sdk-go/core"
- "github.com/multiversx/mx-sdk-go/data"
-)
-
-// WalletStub -
-type WalletStub struct {
- GetPrivateKeyFromMnemonicHandler func(mnemonic data.Mnemonic, account, addressIndex uint32) []byte
- GetAddressFromPrivateKeyHandler func(privateKeyBytes []byte) (core.AddressHandler, error)
-}
-
-// GetPrivateKeyFromMnemonic -
-func (stub *WalletStub) GetPrivateKeyFromMnemonic(mnemonic data.Mnemonic, account, addressIndex uint32) []byte {
- if stub.GetPrivateKeyFromMnemonicHandler != nil {
- return stub.GetPrivateKeyFromMnemonicHandler(mnemonic, account, addressIndex)
- }
-
- return make([]byte, 32)
-}
-
-// GetAddressFromPrivateKey -
-func (stub *WalletStub) GetAddressFromPrivateKey(privateKeyBytes []byte) (core.AddressHandler, error) {
- if stub.GetPrivateKeyFromMnemonicHandler != nil {
- return stub.GetAddressFromPrivateKeyHandler(privateKeyBytes)
- }
- return data.NewAddressFromBytes(make([]byte, 32)), nil
-}
diff --git a/services/proxy/SPECS.md b/services/proxy/SPECS.md
index 64bf769..305f9f0 100644
--- a/services/proxy/SPECS.md
+++ b/services/proxy/SPECS.md
@@ -121,5 +121,22 @@ Stores system performance metrics.
- **Settings**: Change password, update email.
- **Responsive Design**: Fully mobile-compatible UI using Glassmorphism aesthetics.
-## 7. Future / In-Progress
-- **Crypto Payment Service**: A scaffold for a `crypto-payment` service exists in the code references, intended to handle cryptocurrency payments for premium accounts. Currently in early development state.
+## 7. Crypto Payments Service
+The **Crypto Payments Service** allows users to top up their account
+credits using MultiversX native EGLD token. This functionality is decoupled into a
+standalone microservice for security reasons.
+
+- **Project Repository**: [Crypto Payments Service Source](https://github.com/iulianpascalau/mx-crypto-payments)
+- **Credits Smart Contract**: [Smart Contract Source](https://github.com/iulianpascalau/mx-credits-contract-rs)
+
+### Funcationality
+1. **Address Management**:
+ - Generates unique deposit addresses for each user.
+ - Maps on-chain payments to internal user accounts.
+2. **Payment Processing**:
+ - Monitors the blockchain for transactions.
+ - Validates transaction confirmations.
+ - Updates user credit balances upon successful payment using relayed transactions v3.
+3. **Configuration**:
+ - Manages exchange rates (credits per EGLD).
+ - Handles contract pause/resume states.
From abe781dff2b483e377184ef85d826d1dc0784a7b Mon Sep 17 00:00:00 2001
From: Iulian Pascalau
Date: Sun, 1 Feb 2026 23:31:36 +0200
Subject: [PATCH 5/8] - bump crypto-payments to v1.0.5
---
go.mod | 2 +-
go.sum | 4 ++--
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/go.mod b/go.mod
index a5adad7..8703ab7 100644
--- a/go.mod
+++ b/go.mod
@@ -7,7 +7,7 @@ toolchain go1.24.11
require (
github.com/dchest/captcha v1.1.0
github.com/golang-jwt/jwt/v5 v5.3.0
- github.com/iulianpascalau/mx-crypto-payments v1.0.4
+ github.com/iulianpascalau/mx-crypto-payments v1.0.5
github.com/joho/godotenv v1.5.1
github.com/mattn/go-sqlite3 v1.14.33
github.com/multiversx/mx-chain-core-go v1.4.1
diff --git a/go.sum b/go.sum
index 32926ba..e98a03b 100644
--- a/go.sum
+++ b/go.sum
@@ -268,8 +268,8 @@ github.com/ipfs/go-test v0.0.4 h1:DKT66T6GBB6PsDFLoO56QZPrOmzJkqU1FZH5C9ySkew=
github.com/ipfs/go-test v0.0.4/go.mod h1:qhIM1EluEfElKKM6fnWxGn822/z9knUGM1+I/OAQNKI=
github.com/ipld/go-ipld-prime v0.21.0 h1:n4JmcpOlPDIxBcY037SVfpd1G+Sj1nKZah0m6QH9C2E=
github.com/ipld/go-ipld-prime v0.21.0/go.mod h1:3RLqy//ERg/y5oShXXdx5YIp50cFGOanyMctpPjsvxQ=
-github.com/iulianpascalau/mx-crypto-payments v1.0.4 h1:mHsP6s+OpOYhK+a3v/F4SV44SQfxYKN8idDS/FKV5Go=
-github.com/iulianpascalau/mx-crypto-payments v1.0.4/go.mod h1:4/NVijzrXB9NswwfiG8QSV4KkolilWOCjcxIhpVFSUw=
+github.com/iulianpascalau/mx-crypto-payments v1.0.5 h1:VuIssbSGLPvz9LDdtWVyF8qUMtl4ea7kgByra0epZAg=
+github.com/iulianpascalau/mx-crypto-payments v1.0.5/go.mod h1:4/NVijzrXB9NswwfiG8QSV4KkolilWOCjcxIhpVFSUw=
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/jbenet/go-cienv v0.1.0/go.mod h1:TqNnHUmJgXau0nCzC7kXWeotg3J9W34CUv5Djy1+FlA=
From 55018d118c79de2c35b2e12d63b922bffc54dba7 Mon Sep 17 00:00:00 2001
From: Iulian Pascalau
Date: Mon, 2 Feb 2026 00:03:00 +0200
Subject: [PATCH 6/8] - crypto-payments repo update to v1.0.7
---
go.mod | 2 +-
go.sum | 4 ++--
integrationTests/e2e_test.go | 2 +-
integrationTests/framework/chainSimulatorWrapper.go | 2 +-
integrationTests/framework/common.go | 2 +-
integrationTests/framework/interface.go | 4 ++--
integrationTests/manual_flows_test.go | 2 +-
services/proxy/SPECS.md | 2 +-
8 files changed, 10 insertions(+), 10 deletions(-)
diff --git a/go.mod b/go.mod
index 8703ab7..a3c369c 100644
--- a/go.mod
+++ b/go.mod
@@ -7,7 +7,7 @@ toolchain go1.24.11
require (
github.com/dchest/captcha v1.1.0
github.com/golang-jwt/jwt/v5 v5.3.0
- github.com/iulianpascalau/mx-crypto-payments v1.0.5
+ github.com/iulianpascalau/mx-crypto-payments-go v1.0.7
github.com/joho/godotenv v1.5.1
github.com/mattn/go-sqlite3 v1.14.33
github.com/multiversx/mx-chain-core-go v1.4.1
diff --git a/go.sum b/go.sum
index e98a03b..a24b8c6 100644
--- a/go.sum
+++ b/go.sum
@@ -268,8 +268,8 @@ github.com/ipfs/go-test v0.0.4 h1:DKT66T6GBB6PsDFLoO56QZPrOmzJkqU1FZH5C9ySkew=
github.com/ipfs/go-test v0.0.4/go.mod h1:qhIM1EluEfElKKM6fnWxGn822/z9knUGM1+I/OAQNKI=
github.com/ipld/go-ipld-prime v0.21.0 h1:n4JmcpOlPDIxBcY037SVfpd1G+Sj1nKZah0m6QH9C2E=
github.com/ipld/go-ipld-prime v0.21.0/go.mod h1:3RLqy//ERg/y5oShXXdx5YIp50cFGOanyMctpPjsvxQ=
-github.com/iulianpascalau/mx-crypto-payments v1.0.5 h1:VuIssbSGLPvz9LDdtWVyF8qUMtl4ea7kgByra0epZAg=
-github.com/iulianpascalau/mx-crypto-payments v1.0.5/go.mod h1:4/NVijzrXB9NswwfiG8QSV4KkolilWOCjcxIhpVFSUw=
+github.com/iulianpascalau/mx-crypto-payments-go v1.0.7 h1:sEdAH9ycsBnqKdnV1/uq4+sI5THUsjpbuAbimHKNq4g=
+github.com/iulianpascalau/mx-crypto-payments-go v1.0.7/go.mod h1:W7bSzZiEQaG3iAAMMBP/5y5PWpIlXeY7d724Xa5SvGs=
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/jbenet/go-cienv v0.1.0/go.mod h1:TqNnHUmJgXau0nCzC7kXWeotg3J9W34CUv5Djy1+FlA=
diff --git a/integrationTests/e2e_test.go b/integrationTests/e2e_test.go
index 9f3687a..5bdf629 100644
--- a/integrationTests/e2e_test.go
+++ b/integrationTests/e2e_test.go
@@ -8,7 +8,7 @@ import (
"testing"
"time"
- cryptoPaymentsFramework "github.com/iulianpascalau/mx-crypto-payments/integrationTests/framework"
+ cryptoPaymentsFramework "github.com/iulianpascalau/mx-crypto-payments-go/integrationTests/framework"
"github.com/iulianpascalau/mx-epoch-proxy-go/integrationTests/framework"
"github.com/multiversx/mx-chain-core-go/data/transaction"
logger "github.com/multiversx/mx-chain-logger-go"
diff --git a/integrationTests/framework/chainSimulatorWrapper.go b/integrationTests/framework/chainSimulatorWrapper.go
index c3b356d..ab9eb3a 100644
--- a/integrationTests/framework/chainSimulatorWrapper.go
+++ b/integrationTests/framework/chainSimulatorWrapper.go
@@ -10,7 +10,7 @@ import (
"testing"
"time"
- cryptoPaymentsFramework "github.com/iulianpascalau/mx-crypto-payments/integrationTests/framework"
+ cryptoPaymentsFramework "github.com/iulianpascalau/mx-crypto-payments-go/integrationTests/framework"
"github.com/multiversx/mx-chain-core-go/core"
"github.com/multiversx/mx-chain-core-go/core/pubkeyConverter"
apiCore "github.com/multiversx/mx-chain-core-go/data/api"
diff --git a/integrationTests/framework/common.go b/integrationTests/framework/common.go
index 9971b1a..5f9fa6a 100644
--- a/integrationTests/framework/common.go
+++ b/integrationTests/framework/common.go
@@ -5,7 +5,7 @@ import (
"runtime"
"testing"
- cryptoPaymentsFramework "github.com/iulianpascalau/mx-crypto-payments/integrationTests/framework"
+ cryptoPaymentsFramework "github.com/iulianpascalau/mx-crypto-payments-go/integrationTests/framework"
"github.com/stretchr/testify/require"
)
diff --git a/integrationTests/framework/interface.go b/integrationTests/framework/interface.go
index 31be288..6faa830 100644
--- a/integrationTests/framework/interface.go
+++ b/integrationTests/framework/interface.go
@@ -3,8 +3,8 @@ package framework
import (
"context"
- "github.com/iulianpascalau/mx-crypto-payments/factory"
- "github.com/iulianpascalau/mx-crypto-payments/process"
+ "github.com/iulianpascalau/mx-crypto-payments-go/factory"
+ "github.com/iulianpascalau/mx-crypto-payments-go/process"
proxyApi "github.com/iulianpascalau/mx-epoch-proxy-go/services/proxy/api"
proxyFactory "github.com/iulianpascalau/mx-epoch-proxy-go/services/proxy/factory"
"github.com/multiversx/mx-chain-core-go/data/api"
diff --git a/integrationTests/manual_flows_test.go b/integrationTests/manual_flows_test.go
index 070f858..c83ff1a 100644
--- a/integrationTests/manual_flows_test.go
+++ b/integrationTests/manual_flows_test.go
@@ -7,7 +7,7 @@ import (
"testing"
"time"
- cryptoPaymentsFramework "github.com/iulianpascalau/mx-crypto-payments/integrationTests/framework"
+ cryptoPaymentsFramework "github.com/iulianpascalau/mx-crypto-payments-go/integrationTests/framework"
"github.com/iulianpascalau/mx-epoch-proxy-go/integrationTests/framework"
logger "github.com/multiversx/mx-chain-logger-go"
"github.com/stretchr/testify/assert"
diff --git a/services/proxy/SPECS.md b/services/proxy/SPECS.md
index 305f9f0..1daf14c 100644
--- a/services/proxy/SPECS.md
+++ b/services/proxy/SPECS.md
@@ -126,7 +126,7 @@ The **Crypto Payments Service** allows users to top up their account
credits using MultiversX native EGLD token. This functionality is decoupled into a
standalone microservice for security reasons.
-- **Project Repository**: [Crypto Payments Service Source](https://github.com/iulianpascalau/mx-crypto-payments)
+- **Project Repository**: [Crypto Payments Service Source](https://github.com/iulianpascalau/mx-crypto-payments-go)
- **Credits Smart Contract**: [Smart Contract Source](https://github.com/iulianpascalau/mx-credits-contract-rs)
### Funcationality
From 782d768624788aed07fbb96e2ae128bd7cb055fe Mon Sep 17 00:00:00 2001
From: Iulian Pascalau
Date: Mon, 2 Feb 2026 00:09:59 +0200
Subject: [PATCH 7/8] - changed the solution link on the frontend to point to
the 3 repos
---
frontend/src/Dashboard.tsx | 26 +++++++++++++++++++++++---
frontend/src/Login.tsx | 26 +++++++++++++++++++++++---
2 files changed, 46 insertions(+), 6 deletions(-)
diff --git a/frontend/src/Dashboard.tsx b/frontend/src/Dashboard.tsx
index 0cfd422..0493dbb 100644
--- a/frontend/src/Dashboard.tsx
+++ b/frontend/src/Dashboard.tsx
@@ -1,7 +1,7 @@
import { useEffect, useState } from 'react';
import { getAccessKey, clearAuth, getUserInfo, parseJwt, type User as AuthUser } from './auth';
import { useNavigate } from 'react-router-dom';
-import { LogOut, Key, Users, Copy, Trash2, Shield, Loader, Plus, User, Pencil, RotateCcw, ChevronLeft, ChevronRight, ArrowUpDown, ArrowUp, ArrowDown, Check, X as XIcon, UserCog, BookOpen, ExternalLink, Zap, AlertTriangle, CreditCard, Wallet } from 'lucide-react';
+import { LogOut, Key, Users, Copy, Trash2, Shield, Loader, Plus, User, Pencil, RotateCcw, ChevronLeft, ChevronRight, ChevronUp, ArrowUpDown, ArrowUp, ArrowDown, Check, X as XIcon, UserCog, BookOpen, ExternalLink, Zap, AlertTriangle, CreditCard, Wallet } from 'lucide-react';
import axios from 'axios';
@@ -1180,8 +1180,28 @@ export const Dashboard = () => {
-
- Build {appInfo.version} | Solution
+
+ Build {appInfo.version} |
+
diff --git a/frontend/src/Login.tsx b/frontend/src/Login.tsx
index f30dabc..db721fe 100644
--- a/frontend/src/Login.tsx
+++ b/frontend/src/Login.tsx
@@ -1,7 +1,7 @@
import React, { useState, useEffect } from 'react';
import { setAuth } from './auth';
import { useNavigate, Link, useLocation } from 'react-router-dom';
-import { Lock, User } from 'lucide-react';
+import { Lock, User, ChevronUp } from 'lucide-react';
export const Login = () => {
const [username, setUsername] = useState('');
@@ -121,8 +121,28 @@ export const Login = () => {
-
- Build {version} | Solution
+
+ Build {version} |
+
From 01cede1f4227b3c00c0591e22882511440161c52 Mon Sep 17 00:00:00 2001
From: Iulian Pascalau
Date: Fri, 6 Feb 2026 11:48:12 +0200
Subject: [PATCH 8/8] - integrated crypto-payment v1.0.9 with credits contract
v1.0.1
---
go.mod | 2 +-
go.sum | 4 ++--
integrationTests/e2e_test.go | 2 +-
integrationTests/framework/chainSimulatorWrapper.go | 2 +-
integrationTests/framework/common.go | 2 +-
integrationTests/framework/interface.go | 4 ++--
integrationTests/manual_flows_test.go | 2 +-
7 files changed, 9 insertions(+), 9 deletions(-)
diff --git a/go.mod b/go.mod
index 8703ab7..0597c93 100644
--- a/go.mod
+++ b/go.mod
@@ -7,7 +7,7 @@ toolchain go1.24.11
require (
github.com/dchest/captcha v1.1.0
github.com/golang-jwt/jwt/v5 v5.3.0
- github.com/iulianpascalau/mx-crypto-payments v1.0.5
+ github.com/iulianpascalau/mx-crypto-payments-go v1.0.9
github.com/joho/godotenv v1.5.1
github.com/mattn/go-sqlite3 v1.14.33
github.com/multiversx/mx-chain-core-go v1.4.1
diff --git a/go.sum b/go.sum
index e98a03b..2ad3921 100644
--- a/go.sum
+++ b/go.sum
@@ -268,8 +268,8 @@ github.com/ipfs/go-test v0.0.4 h1:DKT66T6GBB6PsDFLoO56QZPrOmzJkqU1FZH5C9ySkew=
github.com/ipfs/go-test v0.0.4/go.mod h1:qhIM1EluEfElKKM6fnWxGn822/z9knUGM1+I/OAQNKI=
github.com/ipld/go-ipld-prime v0.21.0 h1:n4JmcpOlPDIxBcY037SVfpd1G+Sj1nKZah0m6QH9C2E=
github.com/ipld/go-ipld-prime v0.21.0/go.mod h1:3RLqy//ERg/y5oShXXdx5YIp50cFGOanyMctpPjsvxQ=
-github.com/iulianpascalau/mx-crypto-payments v1.0.5 h1:VuIssbSGLPvz9LDdtWVyF8qUMtl4ea7kgByra0epZAg=
-github.com/iulianpascalau/mx-crypto-payments v1.0.5/go.mod h1:4/NVijzrXB9NswwfiG8QSV4KkolilWOCjcxIhpVFSUw=
+github.com/iulianpascalau/mx-crypto-payments-go v1.0.9 h1:w5KmBFzrx4XxeJ2t56crTGcDthH9veMKtYt7ltN3WHY=
+github.com/iulianpascalau/mx-crypto-payments-go v1.0.9/go.mod h1:W7bSzZiEQaG3iAAMMBP/5y5PWpIlXeY7d724Xa5SvGs=
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/jbenet/go-cienv v0.1.0/go.mod h1:TqNnHUmJgXau0nCzC7kXWeotg3J9W34CUv5Djy1+FlA=
diff --git a/integrationTests/e2e_test.go b/integrationTests/e2e_test.go
index 9f3687a..5bdf629 100644
--- a/integrationTests/e2e_test.go
+++ b/integrationTests/e2e_test.go
@@ -8,7 +8,7 @@ import (
"testing"
"time"
- cryptoPaymentsFramework "github.com/iulianpascalau/mx-crypto-payments/integrationTests/framework"
+ cryptoPaymentsFramework "github.com/iulianpascalau/mx-crypto-payments-go/integrationTests/framework"
"github.com/iulianpascalau/mx-epoch-proxy-go/integrationTests/framework"
"github.com/multiversx/mx-chain-core-go/data/transaction"
logger "github.com/multiversx/mx-chain-logger-go"
diff --git a/integrationTests/framework/chainSimulatorWrapper.go b/integrationTests/framework/chainSimulatorWrapper.go
index c3b356d..ab9eb3a 100644
--- a/integrationTests/framework/chainSimulatorWrapper.go
+++ b/integrationTests/framework/chainSimulatorWrapper.go
@@ -10,7 +10,7 @@ import (
"testing"
"time"
- cryptoPaymentsFramework "github.com/iulianpascalau/mx-crypto-payments/integrationTests/framework"
+ cryptoPaymentsFramework "github.com/iulianpascalau/mx-crypto-payments-go/integrationTests/framework"
"github.com/multiversx/mx-chain-core-go/core"
"github.com/multiversx/mx-chain-core-go/core/pubkeyConverter"
apiCore "github.com/multiversx/mx-chain-core-go/data/api"
diff --git a/integrationTests/framework/common.go b/integrationTests/framework/common.go
index 9971b1a..5f9fa6a 100644
--- a/integrationTests/framework/common.go
+++ b/integrationTests/framework/common.go
@@ -5,7 +5,7 @@ import (
"runtime"
"testing"
- cryptoPaymentsFramework "github.com/iulianpascalau/mx-crypto-payments/integrationTests/framework"
+ cryptoPaymentsFramework "github.com/iulianpascalau/mx-crypto-payments-go/integrationTests/framework"
"github.com/stretchr/testify/require"
)
diff --git a/integrationTests/framework/interface.go b/integrationTests/framework/interface.go
index 31be288..6faa830 100644
--- a/integrationTests/framework/interface.go
+++ b/integrationTests/framework/interface.go
@@ -3,8 +3,8 @@ package framework
import (
"context"
- "github.com/iulianpascalau/mx-crypto-payments/factory"
- "github.com/iulianpascalau/mx-crypto-payments/process"
+ "github.com/iulianpascalau/mx-crypto-payments-go/factory"
+ "github.com/iulianpascalau/mx-crypto-payments-go/process"
proxyApi "github.com/iulianpascalau/mx-epoch-proxy-go/services/proxy/api"
proxyFactory "github.com/iulianpascalau/mx-epoch-proxy-go/services/proxy/factory"
"github.com/multiversx/mx-chain-core-go/data/api"
diff --git a/integrationTests/manual_flows_test.go b/integrationTests/manual_flows_test.go
index 070f858..c83ff1a 100644
--- a/integrationTests/manual_flows_test.go
+++ b/integrationTests/manual_flows_test.go
@@ -7,7 +7,7 @@ import (
"testing"
"time"
- cryptoPaymentsFramework "github.com/iulianpascalau/mx-crypto-payments/integrationTests/framework"
+ cryptoPaymentsFramework "github.com/iulianpascalau/mx-crypto-payments-go/integrationTests/framework"
"github.com/iulianpascalau/mx-epoch-proxy-go/integrationTests/framework"
logger "github.com/multiversx/mx-chain-logger-go"
"github.com/stretchr/testify/assert"