diff --git a/.csharpierrc.json b/.csharpierrc.json deleted file mode 100644 index 4d807a7e..00000000 --- a/.csharpierrc.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "printWidth": 200, - "useTabs": false, - "tabWidth": 4, - "preprocessorSymbolSets": ["", "DEBUG", "RELEASE"] -} diff --git a/.editorconfig b/.editorconfig index 11926f13..79e1b281 100644 --- a/.editorconfig +++ b/.editorconfig @@ -1,143 +1,191 @@ ############################### -# Core EditorConfig Options # +# Core EditorConfig Options # ############################### root = true -# XML project files -[*.{csproj,vbproj,vcxproj,vcxproj.filters,proj,projitems,shproj}] -indent_size = 2 +############################### +# Generated Code Exclusions # +############################### -# XML config files -[*.{props,targets,ruleset,config,nuspec,resx,vsixmanifest,vsct}] -indent_size = 2 +# Exclude Thirdweb.Api generated files from all linting and formatting rules +[Thirdweb/Thirdweb.Api/ThirdwebApi.cs] +generated_code = true +dotnet_analyzer_diagnostic.severity = none +dotnet_style_qualification_for_field = false +dotnet_style_qualification_for_property = false +dotnet_style_qualification_for_method = false +dotnet_style_qualification_for_event = false +csharp_style_namespace_declarations = block_scoped +dotnet_diagnostic.IDE0130.severity = none +dotnet_diagnostic.IDE0046.severity = none +dotnet_diagnostic.IDE0045.severity = none +dotnet_diagnostic.IDE0066.severity = none +dotnet_diagnostic.IDE0028.severity = none +dotnet_diagnostic.CA1822.severity = none +dotnet_diagnostic.IDE0290.severity = none +# Disable all naming convention rules for generated code +dotnet_naming_rule.constant_fields_should_be_pascal_case.severity = none +dotnet_naming_rule.public_members_should_be_pascal_case.severity = none +dotnet_naming_rule.private_fields_should_have_underscore_prefix.severity = none -# Code files -[*.{cs,csx,vb,vbx}] +############################### +# Configurable behaviors # +############################### + +[*.{cs,csx}] +end_of_line = crlf +indent_style = space indent_size = 4 -insert_final_newline = true -charset = utf-8-bom +max_line_length = 200 ############################### -# .NET Coding Conventions # +# .NET Coding Conventions # ############################### + [*.{cs,vb}] # Organize usings -dotnet_sort_system_directives_first = true +dotnet_sort_system_directives_first = true:warning +dotnet_separate_import_directive_groups = true:warning + # this. preferences -dotnet_style_qualification_for_field = false:silent -dotnet_style_qualification_for_property = false:silent -dotnet_style_qualification_for_method = false:silent -dotnet_style_qualification_for_event = false:silent +dotnet_style_qualification_for_field = true:warning +dotnet_style_qualification_for_property = true:warning +dotnet_style_qualification_for_method = true:warning +dotnet_style_qualification_for_event = true:warning + # Language keywords vs BCL types preferences -dotnet_style_predefined_type_for_locals_parameters_members = true:silent -dotnet_style_predefined_type_for_member_access = true:silent +dotnet_style_predefined_type_for_locals_parameters_members = true:warning +dotnet_style_predefined_type_for_member_access = true:warning + # Parentheses preferences -dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity:silent -dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity:silent -dotnet_style_parentheses_in_other_binary_operators = always_for_clarity:silent -dotnet_style_parentheses_in_other_operators = never_if_unnecessary:silent +dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity:warning +dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity:warning +dotnet_style_parentheses_in_other_binary_operators = always_for_clarity:warning +dotnet_style_parentheses_in_other_operators = never_if_unnecessary:warning + # Modifier preferences -dotnet_style_require_accessibility_modifiers = for_non_interface_members:silent -dotnet_style_readonly_field = true:suggestion +dotnet_style_require_accessibility_modifiers = always:warning +dotnet_style_readonly_field = true:warning + # Expression-level preferences -dotnet_style_object_initializer = true:suggestion -dotnet_style_collection_initializer = true:suggestion -dotnet_style_explicit_tuple_names = true:suggestion -dotnet_style_null_propagation = true:suggestion -dotnet_style_coalesce_expression = true:suggestion -dotnet_style_prefer_is_null_check_over_reference_equality_method = true:silent -dotnet_style_prefer_inferred_tuple_names = true:suggestion -dotnet_style_prefer_inferred_anonymous_type_member_names = true:suggestion -dotnet_style_prefer_auto_properties = true:silent -dotnet_style_prefer_conditional_expression_over_assignment = true:silent -dotnet_style_prefer_conditional_expression_over_return = true:silent +dotnet_style_object_initializer = true:warning +dotnet_style_collection_initializer = false:warning +dotnet_style_prefer_collection_expression = false:warning +dotnet_style_explicit_tuple_names = true:warning +dotnet_style_null_propagation = true:warning +dotnet_style_coalesce_expression = true:warning +dotnet_style_prefer_is_null_check_over_reference_equality_method = true:warning +dotnet_style_prefer_inferred_tuple_names = true:warning +dotnet_style_prefer_inferred_anonymous_type_member_names = true:warning +dotnet_style_prefer_auto_properties = true:warning +dotnet_style_prefer_conditional_expression_over_assignment = true:warning +dotnet_style_prefer_conditional_expression_over_return = true:warning + +# Code Quality +dotnet_code_quality_unused_parameters = all:warning + +# Namespace preferences +csharp_style_namespace_declarations = file_scoped:warning ############################### # Naming Conventions # ############################### + # Style Definitions -dotnet_naming_style.pascal_case_style.capitalization = pascal_case -# Use PascalCase for constant fields -dotnet_naming_rule.constant_fields_should_be_pascal_case.severity = suggestion -dotnet_naming_rule.constant_fields_should_be_pascal_case.symbols = constant_fields -dotnet_naming_rule.constant_fields_should_be_pascal_case.style = pascal_case_style -dotnet_naming_symbols.constant_fields.applicable_kinds = field -dotnet_naming_symbols.constant_fields.applicable_accessibilities = * -dotnet_naming_symbols.constant_fields.required_modifiers = const +dotnet_naming_style.pascal_case_style.capitalization = pascal_case +dotnet_style_allow_multiple_blank_lines_experimental = false + +# Use PascalCase for constant fields +dotnet_naming_rule.constant_fields_should_be_pascal_case.severity = warning +dotnet_naming_rule.constant_fields_should_be_pascal_case.symbols = constant_fields +dotnet_naming_rule.constant_fields_should_be_pascal_case.style = pascal_case_style +dotnet_naming_symbols.constant_fields.applicable_kinds = field +dotnet_naming_symbols.constant_fields.applicable_accessibilities = * +dotnet_naming_symbols.constant_fields.required_modifiers = const + +# Use PascalCase for public members (properties, methods, events) +dotnet_naming_rule.public_members_should_be_pascal_case.severity = warning +dotnet_naming_rule.public_members_should_be_pascal_case.symbols = public_members +dotnet_naming_rule.public_members_should_be_pascal_case.style = pascal_case_style +dotnet_naming_symbols.public_members.applicable_kinds = property,method,event,field +dotnet_naming_symbols.public_members.applicable_accessibilities = public,protected,internal,protected_internal + +# Use camelCase with '_' prefix for private fields +dotnet_naming_style.underscore_prefix_style.capitalization = camel_case +dotnet_naming_style.underscore_prefix_style.required_prefix = _ +dotnet_naming_rule.private_fields_should_have_underscore_prefix.severity = warning +dotnet_naming_rule.private_fields_should_have_underscore_prefix.symbols = private_fields +dotnet_naming_rule.private_fields_should_have_underscore_prefix.style = underscore_prefix_style +dotnet_naming_symbols.private_fields.applicable_kinds = field +dotnet_naming_symbols.private_fields.applicable_accessibilities = private ############################### # Analyzers # ############################### -dotnet_analyzer_diagnostic.category-CodeQuality.severity = suggestion -dotnet_analyzer_diagnostic.category-Documentation.severity = suggestion -dotnet_analyzer_diagnostic.category-Design.severity = suggestion -dotnet_analyzer_diagnostic.category-Performance.severity = suggestion + +dotnet_analyzer_diagnostic.category-CodeQuality.severity = warning +dotnet_analyzer_diagnostic.category-Documentation.severity = warning +dotnet_analyzer_diagnostic.category-Design.severity = warning +dotnet_analyzer_diagnostic.category-Performance.severity = warning dotnet_analyzer_diagnostic.category-Reliability.severity = warning dotnet_analyzer_diagnostic.category-Security.severity = warning -dotnet_analyzer_diagnostic.category-Style.severity = suggestion +dotnet_analyzer_diagnostic.category-Style.severity = warning # Explicit code exclusions -dotnet_diagnostic.IDE0160.severity = none -dotnet_diagnostic.CA1848.severity = none +# Namespace does not match folder structure +dotnet_diagnostic.IDE0130.severity = none +# If statement can be simplified +dotnet_diagnostic.IDE0046.severity = none +dotnet_diagnostic.IDE0045.severity = none +# Use switch expression +dotnet_diagnostic.IDE0066.severity = none +# Use collection initializers or expressions +# dotnet_diagnostic.IDE0028.severity = none ############################### # C# Coding Conventions # ############################### [*.cs] # var preferences -csharp_style_var_for_built_in_types = true:silent -csharp_style_var_when_type_is_apparent = true:silent -csharp_style_var_elsewhere = true:silent +csharp_style_var_for_built_in_types = true:warning +csharp_style_var_when_type_is_apparent = true:warning +csharp_style_var_elsewhere = true:warning + # Expression-bodied members -csharp_style_expression_bodied_methods = false:silent -csharp_style_expression_bodied_constructors = false:silent -csharp_style_expression_bodied_operators = false:silent -csharp_style_expression_bodied_properties = true:silent -csharp_style_expression_bodied_indexers = true:silent -csharp_style_expression_bodied_accessors = true:silent +csharp_style_expression_bodied_methods = when_possible:warning +csharp_style_expression_bodied_constructors = when_possible:warning +csharp_style_expression_bodied_operators = when_possible:warning +csharp_style_expression_bodied_properties = when_possible:warning +csharp_style_expression_bodied_indexers = when_possible:warning +csharp_style_expression_bodied_accessors = when_possible:warning + # Pattern matching preferences -csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion -csharp_style_pattern_matching_over_as_with_null_check = true:suggestion +csharp_style_pattern_matching_over_is_with_cast_check = true:warning +csharp_style_pattern_matching_over_as_with_null_check = true:warning + # Null-checking preferences -csharp_style_throw_expression = true:suggestion -csharp_style_conditional_delegate_call = true:suggestion +csharp_style_throw_expression = true:warning +csharp_style_conditional_delegate_call = true:warning + # Modifier preferences -csharp_preferred_modifier_order = public,private,protected,internal,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,volatile,async:suggestion +csharp_preferred_modifier_order = public,private,protected,internal,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,volatile,async:error + # Expression-level preferences -csharp_prefer_braces = true:silent -csharp_style_deconstructed_variable_declaration = true:suggestion -csharp_prefer_simple_default_expression = true:suggestion -csharp_style_pattern_local_over_anonymous_function = true:suggestion -csharp_style_inlined_variable_declaration = true:suggestion +csharp_prefer_braces = true:warning +csharp_style_deconstructed_variable_declaration = true:warning +csharp_prefer_simple_default_expression = false:warning +csharp_style_pattern_local_over_anonymous_function = true:warning +csharp_style_inlined_variable_declaration = true:warning -############################### -# C# Formatting Rules # -############################### -# New line preferences -csharp_new_line_before_open_brace = all -csharp_new_line_before_else = true -csharp_new_line_before_catch = true -csharp_new_line_before_finally = true -csharp_new_line_before_members_in_object_initializers = true -csharp_new_line_before_members_in_anonymous_types = true -csharp_new_line_between_query_expression_clauses = true -# Indentation preferences -csharp_indent_case_contents = true -csharp_indent_switch_labels = true -csharp_indent_labels = flush_left -# Space preferences -csharp_space_after_cast = false -csharp_space_after_keywords_in_control_flow_statements = true -csharp_space_between_method_call_parameter_list_parentheses = false -csharp_space_between_method_declaration_parameter_list_parentheses = false -csharp_space_between_parentheses = false -csharp_space_before_colon_in_inheritance_clause = true -csharp_space_after_colon_in_inheritance_clause = true -csharp_space_around_binary_operators = before_and_after -csharp_space_between_method_declaration_empty_parameter_list_parentheses = false -csharp_space_between_method_call_name_and_opening_parenthesis = false -csharp_space_between_method_call_empty_parameter_list_parentheses = false -# Wrapping preferences -csharp_preserve_single_line_statements = true -csharp_preserve_single_line_blocks = true \ No newline at end of file +# CA1822: Mark members as static +dotnet_diagnostic.CA1822.severity = suggestion + +# IDE0290: Use primary constructor +dotnet_diagnostic.IDE0290.severity = silent + +# JSON002: Probable JSON string detected +dotnet_diagnostic.JSON002.severity = silent + +# CS8981: The type name only contains lower-cased ascii characters. Such names may become reserved for the language. +dotnet_diagnostic.CS8981.severity = suggestion diff --git a/.github/workflows/docfx.yml b/.github/workflows/docfx.yml index 7a959496..e746ce8b 100644 --- a/.github/workflows/docfx.yml +++ b/.github/workflows/docfx.yml @@ -1,3 +1,5 @@ +name: Publish API Reference + on: push: branches: @@ -11,7 +13,7 @@ permissions: concurrency: group: "pages" cancel-in-progress: false - + jobs: publish-docs: environment: @@ -19,20 +21,20 @@ jobs: url: ${{ steps.deployment.outputs.page_url }} runs-on: ubuntu-latest steps: - - name: Checkout - uses: actions/checkout@v3 - - name: Dotnet Setup - uses: actions/setup-dotnet@v3 - with: - dotnet-version: 8.x + - name: Checkout + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + - name: Dotnet Setup + uses: actions/setup-dotnet@b2ace4b12f4cec1b96b6361ff2694ba9e931ceb4 # v3.3.1 + with: + dotnet-version: 8.x - - run: dotnet tool update -g docfx - - run: docfx docfx.json + - run: dotnet tool update -g docfx + - run: docfx docfx.json - - name: Upload artifact - uses: actions/upload-pages-artifact@v3 - with: - path: '_site' - - name: Deploy to GitHub Pages - id: deployment - uses: actions/deploy-pages@v4 + - name: Upload artifact + uses: actions/upload-pages-artifact@56afc609e74202658d3ffba0e8f6dda462b719fa # v3.0.1 + with: + path: "_site" + - name: Deploy to GitHub Pages + id: deployment + uses: actions/deploy-pages@d6db90164ac5ed86f2b6aed7e0febac5b3c0c03e # v4.0.5 diff --git a/.github/workflows/dotnet-ci.yml b/.github/workflows/dotnet-ci.yml index 184414ff..3e76c809 100644 --- a/.github/workflows/dotnet-ci.yml +++ b/.github/workflows/dotnet-ci.yml @@ -6,15 +6,19 @@ on: pull_request: types: [opened, synchronize] +concurrency: + group: build-and-test-${{ github.ref }} + cancel-in-progress: true + jobs: build-test-cov: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Setup - uses: actions/setup-dotnet@v3 + uses: actions/setup-dotnet@b2ace4b12f4cec1b96b6361ff2694ba9e931ceb4 # v3.3.1 with: dotnet-version: | 8.0.x @@ -28,9 +32,10 @@ jobs: working-directory: ./ - name: Test + id: test run: | dotnet tool install --global coverlet.console - dotnet test /p:CollectCoverage=true /p:CoverletOutputFormat=lcov /p:CoverletOutput=./coverage.info + timeout 30m dotnet test /p:CollectCoverage=true /p:CoverletOutputFormat=lcov /p:CoverletOutput=./coverage.info shell: bash env: THIRDWEB_SECRET_KEY: ${{ secrets.THIRDWEB_SECRET_KEY }} @@ -39,9 +44,10 @@ jobs: PRIVATE_KEY: ${{ secrets.PRIVATE_KEY }} - name: Codecov - uses: codecov/codecov-action@v4 + if: always() && steps.test.outcome != 'cancelled' + uses: codecov/codecov-action@b9fd7d16f6d7d1b5d2bec1a2887e65ceed900238 # v4.6.0 with: token: ${{ secrets.CODECOV_TOKEN }} directory: ./ verbose: true - slug: thirdweb-dev/thirdweb-dotnet + slug: thirdweb-dev/dotnet diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 6725b444..9df59033 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -11,10 +11,10 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Setup .NET - uses: actions/setup-dotnet@v3 + uses: actions/setup-dotnet@b2ace4b12f4cec1b96b6361ff2694ba9e931ceb4 # v3.3.1 with: dotnet-version: "8.0.x" @@ -30,7 +30,7 @@ jobs: run: dotnet nuget push "./Thirdweb/bin/Release/*.nupkg" --api-key ${{ secrets.NUGET_API_KEY }} --source https://api.nuget.org/v3/index.json - name: Upload build artifacts - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@4cec3d8aa04e39d1a68397de0c4cd6fb9dce8ec1 # v4.6.1 with: name: build-artifacts path: | diff --git a/Directory.Build.props b/Directory.Build.props deleted file mode 100644 index 147eebb7..00000000 --- a/Directory.Build.props +++ /dev/null @@ -1,18 +0,0 @@ - - - - 0.4.0 - netstandard2.1;net6.0;net7.0;net8.0 - - - latest - true - enable - - - - $(DefaultVersion) - $(DefaultVersion) - $(DefaultVersion) - - \ No newline at end of file diff --git a/Directory.Packages.props b/Directory.Packages.props deleted file mode 100644 index fa995f44..00000000 --- a/Directory.Packages.props +++ /dev/null @@ -1,25 +0,0 @@ - - - true - - - - runtime; build; native; contentfiles; analyzers; buildtransitive - all - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/Makefile b/Makefile new file mode 100644 index 00000000..c4559759 --- /dev/null +++ b/Makefile @@ -0,0 +1,241 @@ +# Thirdweb Makefile +# Cross-platform targets to mirror tw.bat functionality +# Requires: GNU Make, dotnet SDK, optional CSharpier + +# Use bash for consistent behavior across platforms (Git Bash/MSYS2/WSL/macOS/Linux) +SHELL := bash +.SHELLFLAGS := -o pipefail -c + +# Default target +.DEFAULT_GOAL := help + +# Tools and paths +DOTNET := dotnet +API_CLIENT := Thirdweb/Thirdweb.Api/ThirdwebApi.cs +CONSOLE_PROJ := Thirdweb.Console +GENERATOR_PROJ := Thirdweb.Generator +LIB_PROJ := Thirdweb/Thirdweb.csproj + +# Defaults for publishing/building +CONFIG ?= Release +TFM ?= netstandard2.1 +RID ?= +OUT ?= + +# Colors (best effort; will be empty if tput is unavailable) +C_RST := $(shell tput sgr0 2>/dev/null || echo "") +C_BOLD := $(shell tput bold 2>/dev/null || echo "") +C_DIM := $(shell tput dim 2>/dev/null || echo "") +C_RED := $(shell tput setaf 1 2>/dev/null || echo "") +C_GRN := $(shell tput setaf 2 2>/dev/null || echo "") +C_YEL := $(shell tput setaf 3 2>/dev/null || echo "") +C_BLU := $(shell tput setaf 4 2>/dev/null || echo "") +C_MAG := $(shell tput setaf 5 2>/dev/null || echo "") +C_CYN := $(shell tput setaf 6 2>/dev/null || echo "") + +# Icons +IC_BUILD := BUILD +IC_CLEAN := CLEAN +IC_RESTORE := RESTORE +IC_TEST := TEST +IC_PACK := PACK +IC_RUN := RUN +IC_GEN := GEN +IC_INFO := INFO +IC_OK := OK +IC_WARN := WARN +IC_ERR := ERR +IC_FMT := FMT +IC_PUB := PUBLISH + +hr = printf '$(C_DIM)%s$(C_RST)\n' '--------------------------------------------------------------------' +msg = printf '%s[%s]%s %s\n' '$(1)' '$(2)' '$(C_RST)' '$(3)' + +.PHONY: help +help: + @printf '\n$(C_CYN)$(C_BOLD)%s$(C_RST)\n' 'Thirdweb Tools' + @$(hr) + @printf 'Usage: $(C_BOLD)make$(C_RST) $(C_CYN)[target]$(C_RST)\n\n' + @printf '$(C_BOLD)Targets:$(C_RST)\n' + @printf ' $(C_CYN)%-16s$(C_RST) - %s\n' 'build' 'Generate API and build the solution' + @printf ' $(C_CYN)%-16s$(C_RST) - %s\n' 'clean' 'Clean build artifacts' + @printf ' $(C_CYN)%-16s$(C_RST) - %s\n' 'restore' 'Restore NuGet packages' + @printf ' $(C_CYN)%-16s$(C_RST) - %s\n' 'test' 'Run tests' + @printf ' $(C_CYN)%-16s$(C_RST) - %s\n' 'pack' 'Generate API (if needed) and create NuGet package' + @printf ' $(C_CYN)%-16s$(C_RST) - %s\n' 'publish' 'Publish the Thirdweb project (dotnet publish)' + @printf ' $(C_CYN)%-16s$(C_RST) - %s\n' 'run' 'Run the console application' + @printf ' $(C_CYN)%-16s$(C_RST) - %s\n' 'generate' 'Generate API client from OpenAPI spec' + @printf ' $(C_CYN)%-16s$(C_RST) - %s\n' 'generate-llms' 'Generate llms.txt from XML documentation' + @printf ' $(C_CYN)%-16s$(C_RST) - %s\n' 'bump' 'Bump version (BUMP=major|minor|patch, default: patch)' + @printf ' $(C_CYN)%-16s$(C_RST) - %s\n' 'lint' 'Check code formatting (dry run)' + @printf ' $(C_CYN)%-16s$(C_RST) - %s\n' 'fix' 'Fix code formatting issues' + @printf ' $(C_CYN)%-16s$(C_RST) - %s\n' 'help' 'Show this help message' + @$(hr) + +.PHONY: publish +# Publish the Thirdweb library project +# Usage examples: +# make publish # Release publish +# make publish CONFIG=Debug # Debug config +# make publish RID=win-x64 # Target runtime +# make publish OUT=artifacts/publish # Custom output dir +publish: + @if [ ! -f '$(API_CLIENT)' ]; then \ + $(call msg,$(C_YEL),$(IC_WARN),API client not found, generating it first) ; \ + $(MAKE) --no-print-directory generate ; \ + fi + @$(call msg,$(C_BLU),$(IC_INFO),$(IC_PUB) Publishing Thirdweb project) + @CMD="$(DOTNET) publish '$(LIB_PROJ)' -c '$(CONFIG)' -f '$(TFM)'"; \ + if [ -n "$(RID)" ]; then CMD="$$CMD -r '$(RID)'"; fi; \ + if [ -n "$(OUT)" ]; then CMD="$$CMD -o '$(OUT)'"; fi; \ + echo $$CMD; eval $$CMD && \ + $(call msg,$(C_GRN),$(IC_OK),Publish succeeded) || \ + $(call msg,$(C_RED),$(IC_ERR),Publish failed) + +.PHONY: generate +# Clean previous file and generate API client +generate: + @$(call msg,$(C_BLU),$(IC_INFO),$(IC_GEN) Cleaning generated API files) + @rm -f '$(API_CLIENT)' 2>/dev/null || true + @$(call msg,$(C_BLU),$(IC_INFO),$(IC_GEN) Generating Thirdweb API client with custom generator) + @$(DOTNET) run --project '$(GENERATOR_PROJ)' --no-build >/dev/null 2>&1 \ + || ( \ + $(call msg,$(C_MAG),>> ,Building generator) ; \ + $(DOTNET) build '$(GENERATOR_PROJ)' ; \ + $(call msg,$(C_MAG),>> ,Running generator) ; \ + $(DOTNET) run --project '$(GENERATOR_PROJ)' \ + ) + @$(call msg,$(C_GRN),$(IC_OK),API client generation complete) + +.PHONY: generate-llms +# Generate llms.txt from XML documentation +generate-llms: + @$(call msg,$(C_BLU),$(IC_INFO),$(IC_BUILD) Building Thirdweb in Release mode) + @$(DOTNET) build '$(LIB_PROJ)' -c Release >/dev/null 2>&1 || { \ + $(call msg,$(C_MAG),>> ,Building Thirdweb project) ; \ + $(DOTNET) build '$(LIB_PROJ)' -c Release ; \ + } + @$(call msg,$(C_BLU),$(IC_INFO),$(IC_GEN) Generating llms.txt from XML documentation) + @$(DOTNET) run --project '$(GENERATOR_PROJ)' -- --llms && \ + $(call msg,$(C_GRN),$(IC_OK),llms.txt generation complete) || \ + $(call msg,$(C_RED),$(IC_ERR),llms.txt generation failed) + +.PHONY: build +build: + @$(MAKE) --no-print-directory generate + @$(call msg,$(C_BLU),$(IC_INFO),$(IC_BUILD) Building with dotnet build) + @$(DOTNET) build && \ + $(call msg,$(C_GRN),$(IC_OK),Build succeeded) || \ + $(call msg,$(C_RED),$(IC_ERR),Build failed) + @$(MAKE) --no-print-directory generate-llms + +.PHONY: clean +clean: + @$(call msg,$(C_BLU),$(IC_INFO),$(IC_CLEAN) Cleaning with dotnet clean) + @$(DOTNET) clean && \ + $(call msg,$(C_GRN),$(IC_OK),Clean completed) || \ + $(call msg,$(C_RED),$(IC_ERR),Clean failed) + +.PHONY: restore +restore: + @$(call msg,$(C_BLU),$(IC_INFO),$(IC_RESTORE) Restoring with dotnet restore) + @$(DOTNET) restore && \ + $(call msg,$(C_GRN),$(IC_OK),Restore completed) || \ + $(call msg,$(C_RED),$(IC_ERR),Restore failed) + +.PHONY: test +test: + @$(call msg,$(C_BLU),$(IC_INFO),$(IC_TEST) Running dotnet test) + @$(DOTNET) test && \ + $(call msg,$(C_GRN),$(IC_OK),All tests passed) || \ + $(call msg,$(C_RED),$(IC_ERR),Some tests failed) + +.PHONY: pack +pack: + @if [ ! -f '$(API_CLIENT)' ]; then \ + $(call msg,$(C_YEL),$(IC_WARN),API client not found, generating it first) ; \ + $(MAKE) --no-print-directory generate ; \ + fi + @$(call msg,$(C_BLU),$(IC_INFO),$(IC_BUILD) Building Release) + @$(DOTNET) build --configuration Release || { $(call msg,$(C_RED),$(IC_ERR),Build (Release) failed); exit 1; } + @$(call msg,$(C_BLU),$(IC_INFO),$(IC_PACK) Packing NuGet package(s)) + @$(DOTNET) pack --configuration Release && \ + $(call msg,$(C_GRN),$(IC_OK),Pack completed) || \ + $(call msg,$(C_RED),$(IC_ERR),Packing failed) + +.PHONY: run +run: + @$(call msg,$(C_BLU),$(IC_INFO),$(IC_RUN) dotnet run --project $(CONSOLE_PROJ)) + @$(DOTNET) run --project '$(CONSOLE_PROJ)' && \ + $(call msg,$(C_GRN),$(IC_OK),Application exited) || \ + $(call msg,$(C_RED),$(IC_ERR),Application exited with errors) + +.PHONY: lint +lint: + @$(call msg,$(C_BLU),$(IC_INFO),$(IC_FMT) Checking code formatting with CSharpier) + @csharpier --help >/dev/null 2>&1 || { \ + $(call msg,$(C_YEL),$(IC_WARN),CSharpier is not installed) ; \ + printf ' Install it with: dotnet tool install -g csharpier\n' ; \ + exit 0 ; \ + } + @csharpier check . >/dev/null 2>&1 || { \ + $(call msg,$(C_YEL),$(IC_WARN),Formatting issues found) ; \ + printf ' Run "make fix" to automatically fix them.\n' ; \ + exit 0 ; \ + } + @$(call msg,$(C_GRN),$(IC_OK),Code formatting is correct) + +.PHONY: fix +fix: + @$(call msg,$(C_BLU),$(IC_INFO),$(IC_FMT) Running CSharpier formatter) + @csharpier --help >/dev/null 2>&1 || { \ + $(call msg,$(C_YEL),$(IC_WARN),CSharpier is not installed) ; \ + printf ' Install it with: dotnet tool install -g csharpier\n' ; \ + exit 0 ; \ + } + @csharpier format . >/dev/null 2>&1 || { \ + $(call msg,$(C_RED),$(IC_ERR),CSharpier formatting failed) ; \ + exit 1 ; \ + } + @$(call msg,$(C_GRN),$(IC_OK),Code formatting completed) + +.PHONY: bump +# Bump version in .csproj and Constants.cs +# Usage: make bump [BUMP=major|minor|patch] (defaults to patch) +bump: + @BUMP_TYPE="$(BUMP)"; \ + if [ -z "$$BUMP_TYPE" ]; then \ + BUMP_TYPE="patch"; \ + printf '%s[%s]%s %s\n' '$(C_BLU)' '$(IC_INFO)' '$(C_RST)' "No BUMP specified, defaulting to patch"; \ + fi; \ + if [ "$$BUMP_TYPE" != "major" ] && [ "$$BUMP_TYPE" != "minor" ] && [ "$$BUMP_TYPE" != "patch" ]; then \ + printf '%s[%s]%s %s\n' '$(C_RED)' '$(IC_ERR)' '$(C_RST)' "Invalid BUMP value: $$BUMP_TYPE"; \ + printf ' Valid values: major, minor, patch\n'; \ + exit 1; \ + fi; \ + printf '%s[%s]%s %s\n' '$(C_BLU)' '$(IC_INFO)' '$(C_RST)' "Reading current version"; \ + CURRENT=$$(grep -oP '\K[^<]+' '$(LIB_PROJ)' | head -1); \ + if [ -z "$$CURRENT" ]; then \ + printf '%s[%s]%s %s\n' '$(C_RED)' '$(IC_ERR)' '$(C_RST)' "Could not read current version"; \ + exit 1; \ + fi; \ + MAJOR=$$(echo $$CURRENT | cut -d. -f1); \ + MINOR=$$(echo $$CURRENT | cut -d. -f2); \ + PATCH=$$(echo $$CURRENT | cut -d. -f3); \ + if [ "$$BUMP_TYPE" = "major" ]; then \ + MAJOR=$$((MAJOR + 1)); MINOR=0; PATCH=0; \ + elif [ "$$BUMP_TYPE" = "minor" ]; then \ + MINOR=$$((MINOR + 1)); PATCH=0; \ + elif [ "$$BUMP_TYPE" = "patch" ]; then \ + PATCH=$$((PATCH + 1)); \ + fi; \ + NEW_VERSION="$$MAJOR.$$MINOR.$$PATCH"; \ + printf '%s[%s]%s %s\n' '$(C_MAG)' '$(IC_INFO)' '$(C_RST)' "Bumping version: $$CURRENT -> $$NEW_VERSION"; \ + sed -i "s|$$CURRENT|$$NEW_VERSION|" '$(LIB_PROJ)'; \ + sed -i "s|$$CURRENT|$$NEW_VERSION|" '$(LIB_PROJ)'; \ + sed -i "s|$$CURRENT|$$NEW_VERSION|" '$(LIB_PROJ)'; \ + sed -i 's|public const string VERSION = "'"$$CURRENT"'";|public const string VERSION = "'"$$NEW_VERSION"'";|' 'Thirdweb/Thirdweb.Utils/Constants.cs'; \ + printf '%s[%s]%s %s\n' '$(C_GRN)' '$(IC_OK)' '$(C_RST)' "Version bumped to $$NEW_VERSION"; \ + printf ' Updated files:\n'; \ + printf ' - $(LIB_PROJ)\n'; \ + printf ' - Thirdweb/Thirdweb.Utils/Constants.cs\n' diff --git a/README.md b/README.md index c70cc060..a471dc71 100644 --- a/README.md +++ b/README.md @@ -1,28 +1,31 @@ -![net-banner](https://github.com/thirdweb-dev/thirdweb-dotnet/assets/43042585/6abcdae9-b49f-492a-98de-b01756e21798) +![net-banner](https://github.com/thirdweb-dev/dotnet/assets/43042585/6abcdae9-b49f-492a-98de-b01756e21798) +[.NET Documentation](https://portal.thirdweb.com/dotnet) [NuGet Version](https://www.nuget.org/packages/Thirdweb) [NuGet Downloads](https://www.nuget.org/packages/Thirdweb) -[Codecov](https://app.codecov.io/gh/thirdweb-dev/thirdweb-dotnet) - +[Codecov](https://app.codecov.io/gh/thirdweb-dev/dotnet) ## Overview -The Thirdweb .NET SDK is a comprehensive library that allows developers to interact with the blockchain using the .NET framework. It simplifies the integration of Web3 functionality into your .NET applications with a robust set of methods and classes. - - +The Thirdweb .NET SDK is a comprehensive and easy to use library that allows developers to interact with the blockchain using the .NET framework. It simplifies the integration of all [thirdweb](https://thirdweb.com/) functionality with a minimal set of dependencies. -## Features +## Core Features -- **Connect to any EVM network:** Easily connect to Ethereum and other EVM-compatible networks. -- **Query blockchain data:** Use Thirdweb RPC to fetch blockchain data efficiently. -- **Interact with smart contracts:** Simplified read and write operations for smart contracts. -- **In-App Wallets:** Integrate user-friendly wallets within your applications, supporting email, phone, and OAuth login. -- **Account Abstraction:** Simplify complex account management tasks with smart wallets. -- **Gasless Transactions:** Enable transactions without requiring users to pay gas fees. -- **Storage Solutions:** Download and upload files using IPFS. -- **Transaction Builder:** Easily build and send transactions. +- **Connect to any EVM network:** Easily connect to blockchain network with its chain id alone. +- **Interact with smart contracts:** Simplified read and write operations for smart contracts, with various out-of-the-box extensions provided. +- **In-App Wallets:** Integrate user-friendly wallets within your applications, supporting email, phone, OAuth login or plug your own auth in. +- **Ecosystem Wallets:** Basically In-App Wallets functionality wise, with the added benefit of being able to securely share your wallets with third party partners. +- **Account Abstraction:** Turn any wallet into a programmable smart wallet (EIP-4337 or EIP-7702) with built-in gas sponsorship and granular session key features. +- **Storage Solutions:** Download and upload files using IPFS or HTTPS. +- **Transaction Builder:** Create, manipulate and send low level transactions. - **Session Keys:** Advanced control for smart wallets to manage permissions and session durations. +- **Thirdweb Bridge:** Universal interface to use any asset onchain. +- **Thirdweb Nebula:** Create blockchain-powered AI Agents. +- **Thirdweb Insight:** Query blockchain data at the speed of light. +- **Thirdweb Engine:** Interact in creative ways from your backend. +- **Unity Compatibility**: This SDK has been tested successfully in [Unity 2022.3+](https://portal.thirdweb.com/unity/v5) (All build targets). - **Godot Compatibility**: This SDK has been tested successfully in [Godot .NET](https://portal.thirdweb.com/dotnet/godot) +- **MAUI Compatibility**: This SDK has been tested successfully in [MAUI](https://portal.thirdweb.com/dotnet/maui) ## Installation @@ -34,213 +37,14 @@ Run the following command to install: dotnet add package Thirdweb ``` -## Usage - -You can access the full documentation at https://portal.thirdweb.com/dotnet - -### Getting Started - -Initialize the Thirdweb client to connect to the blockchain. - -For frontend applications: - -```csharp -var client = ThirdwebClient.Create(clientId: "myClientId", bundleId: "com.my.bundleid"); -``` - -For backend applications: - -```csharp -var secretKey = Environment.GetEnvironmentVariable("THIRDWEB_SECRET_KEY"); -var client = ThirdwebClient.Create(secretKey: secretKey); -``` - -### Interacting with Smart Contracts - -You can interact with smart contracts by creating a contract instance and calling read/write methods. - -**Reading Data** - -```csharp -var contract = await ThirdwebContract.Create(client: client, address: "0x81ebd23aA79bCcF5AaFb9c9c5B0Db4223c39102e", chain: 421614); -var readResult = await ThirdwebContract.Read(contract, "name"); -Console.WriteLine($"Contract read result: {readResult}"); -``` - -**Writing Data** - -```csharp -var writeResult = await ThirdwebContract.Write(smartWallet, contract, "mintTo", 0, await smartWallet.GetAddress(), 100); -Console.WriteLine($"Contract write result: {writeResult}"); -``` - -### Wallet Interactions - -#### In-App Wallets - -In-app wallets facilitate user authentication and transactions with support for email, phone, and OAuth logins. - -**Email Login** - -```csharp -var inAppWallet = await InAppWallet.Create(client: client, email: "email@example.com"); - -if (!await inAppWallet.IsConnected()) { - await inAppWallet.SendOTP(); - Console.WriteLine("Please submit the OTP."); - var otp = Console.ReadLine(); - (var inAppWalletAddress, var canRetry) = await inAppWallet.SubmitOTP(otp); - if (inAppWalletAddress == null && canRetry) { - Console.WriteLine("Please submit the OTP again."); - otp = Console.ReadLine(); - (inAppWalletAddress, _) = await inAppWallet.SubmitOTP(otp); - } - if (inAppWalletAddress == null) { - Console.WriteLine("OTP login failed. Please try again."); - return; - } -} - -Console.WriteLine($"InAppWallet: {await inAppWallet.GetAddress()}"); -``` - -**OAuth Login** - -```csharp -var inAppWallet = await InAppWallet.Create(client, oauthProvider: OAuthProvider.Google); - -// Windows console app example -var address = await inAppWallet.LoginWithOauth( - isMobile: false, - browserOpenAction: (url) => - { - var psi = new ProcessStartInfo { FileName = url, UseShellExecute = true }; - _ = Process.Start(psi); - }, -); - -// Godot standalone example -var address = await ThirdwebManager.Instance.InAppWallet.LoginWithOauth( - isMobile: OS.GetName() == "Android" || OS.GetName() == "iOS", - browserOpenAction: (url) => OS.ShellOpen(url), - mobileRedirectScheme: "thirdweb://" -); -``` - -#### Smart Wallets - -Smart wallets offer advanced functionalities such as gasless transactions and session keys. - -**Creating a Smart Wallet** - -```csharp -var smartWallet = await SmartWallet.Create(client: client, personalWallet: inAppWallet, factoryAddress: "0xbf1C9aA4B1A085f7DA890a44E82B0A1289A40052", gasless: true, chainId: 421614); - -Console.WriteLine($"Smart Wallet: {await smartWallet.GetAddress()}"); -``` - -**Gasless Transactions** - -```csharp -var writeResult = await ThirdwebContract.Write(smartWallet, contract, "mintTo", 0, await smartWallet.GetAddress(), 100); -Console.WriteLine($"Gasless transaction result: {writeResult}"); -``` - -**Session Key Creation** - -Session keys provide temporary keys for smart wallets with specific permissions and durations. This is useful for granting limited access to a wallet. - -```csharp -var sessionKey = await smartWallet.CreateSessionKey( - signerAddress: await privateKeyWallet.GetAddress(), - approvedTargets: new List() { Constants.ADDRESS_ZERO }, - nativeTokenLimitPerTransactionInWei: "0", - permissionStartTimestamp: "0", - permissionEndTimestamp: (Utils.GetUnixTimeStampNow() + 86400).ToString(), - reqValidityStartTimestamp: "0", - reqValidityEndTimestamp: Utils.GetUnixTimeStampIn10Years().ToString() -); -``` - -You may then connect to a specific smart wallet address by passing an account override. - -```csharp -var smartWallet = await SmartWallet.Create(...same parameters with new signer, accountAddressOverride: "0xInitialSmartWalletAddress"); -``` - -#### Using Private Key Wallets - -Private key wallets allow you to interact with the blockchain using a private key. This is useful for server-side applications. - -```csharp -var privateKey = Environment.GetEnvironmentVariable("PRIVATE_KEY"); -var privateKeyWallet = await PrivateKeyWallet.Create(client: client, privateKeyHex: privateKey); -Console.WriteLine($"PrivateKey Wallet: {await privateKeyWallet.GetAddress()}"); -``` +## Documentation -### Advanced Features +[Documentation Portal](https://portal.thirdweb.com/dotnet) -**RPC Direct Access** +[Full API Reference](https://thirdweb-dev.github.io/dotnet/) -Directly interact with the blockchain using the RPC instance. This allows for low-level access to blockchain data and functions. +## Need Help? -```csharp -var rpc = ThirdwebRPC.GetRpcInstance(client, 421614); -var blockNumber = await rpc.SendRequestAsync("eth_blockNumber"); -Console.WriteLine($"Block number: {blockNumber}"); -``` - -**ZkSync Native Account Abstraction** - -ZkSync 0x71 (113) type transactions are supported through the Transaction Builder (DIY) or Smart Wallets (Managed). - -**DIY Approach** - -```csharp -var tx = await ThirdwebTransaction.Create( - client: client, - wallet: privateKeyWallet, - txInput: new ThirdwebTransactionInput() - { - From = await privateKeyWallet.GetAddress(), - To = await privateKeyWallet.GetAddress(), - Value = new HexBigInteger(BigInteger.Zero), - }, - chainId: 300 -); -tx.SetZkSyncOptions( - new ZkSyncOptions( - paymaster: "0xMyGaslessPaymaster", - paymasterInput: "0x8c5a344500000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000" - ) -); -var txHash = await ThirdwebTransaction.Send(transaction: tx); -Console.WriteLine($"Transaction hash: {txHash}"); -``` - -**Managed Approach** - -With ZkSync, you don't need to pass an account factory address, and the rest works the same. - -```csharp -var zkSyncWallet = await SmartWallet.Create(client: client, personalWallet: inAppWallet, gasless: true, chainId: 300); - -Console.WriteLine($"ZkSync Smart Wallet: {await zkSyncWallet.GetAddress()}"); - -var zkSyncWriteResult = await ThirdwebContract.Write(zkSyncWallet, contract, "mintTo", 0, await zkSyncWallet.GetAddress(), 100); -Console.WriteLine($"ZkSync gasless transaction result: {zkSyncWriteResult}"); -``` - -**Storage Solutions** - -Download and upload files using IPFS. This is useful for decentralized storage solutions. - -```csharp -var downloadResult = await ThirdwebStorage.Download(client: client, uri: "ipfs://exampleUri"); -Console.WriteLine($"Download result: {downloadResult}"); - -var uploadResult = await ThirdwebStorage.Upload(client: client, path: "path/to/file"); -Console.WriteLine($"Upload result preview: {uploadResult.PreviewUrl}"); -``` +For any questions or support, visit our [Support Portal](https://thirdweb.com/support). -For more information, please refer to the [official documentation](https://portal.thirdweb.com/dotnet). +Thank you for trying out the Thirdweb .NET SDK! diff --git a/Thirdweb.Console/Program.cs b/Thirdweb.Console/Program.cs index 5b05dfb5..f3ff8fef 100644 --- a/Thirdweb.Console/Program.cs +++ b/Thirdweb.Console/Program.cs @@ -1,184 +1,506 @@ -using Thirdweb; -using dotenv.net; +#pragma warning disable IDE0005 +#pragma warning disable IDE0059 + using System.Diagnostics; +using dotenv.net; +using Newtonsoft.Json; +using Thirdweb; DotEnv.Load(); // Do not use secret keys client side, use client id/bundle id instead var secretKey = Environment.GetEnvironmentVariable("THIRDWEB_SECRET_KEY"); -// Do not use private keys client side, use InAppWallet/SmartWallet instead -var privateKey = Environment.GetEnvironmentVariable("PRIVATE_KEY"); - -// Fetch timeout options are optional, default is 60000ms -var client = ThirdwebClient.Create(secretKey: secretKey, fetchTimeoutOptions: new TimeoutOptions(storage: 30000, rpc: 60000)); - -var contract = await ThirdwebContract.Create(client: client, address: "0x81ebd23aA79bCcF5AaFb9c9c5B0Db4223c39102e", chain: 421614); -var readResult = await contract.ERC20_Name(); -Console.WriteLine($"Contract read result: {readResult}"); - -// Create wallets (this is an advanced use case, typically one wallet is plenty) -var privateKeyWallet = await PrivateKeyWallet.Create(client: client, privateKeyHex: privateKey); - -// var inAppWallet = await InAppWallet.Create(client: client, email: "firekeeper+awsless@thirdweb.com"); // or email: null, phoneNumber: "+1234567890" - -var inAppWallet = await InAppWallet.Create(client: client, authprovider: AuthProvider.Google); // or email: null, phoneNumber: "+1234567890" - -// Reset InAppWallet (optional step for testing login flow) -if (await inAppWallet.IsConnected()) -{ - await inAppWallet.Disconnect(); -} - -// Relog if InAppWallet not logged in -if (!await inAppWallet.IsConnected()) -{ - var address = await inAppWallet.LoginWithOauth( - isMobile: false, - (url) => - { - var psi = new ProcessStartInfo { FileName = url, UseShellExecute = true }; - _ = Process.Start(psi); - }, - "thirdweb://", - new InAppWalletBrowser() - ); - Console.WriteLine($"InAppWallet address: {address}"); -} - -// await inAppWallet.SendOTP(); -// Console.WriteLine("Please submit the OTP."); -// retry: -// var otp = Console.ReadLine(); -// (var inAppWalletAddress, var canRetry) = await inAppWallet.SubmitOTP(otp); -// if (inAppWalletAddress == null && canRetry) +// Fetch timeout options are optional, default is 120000ms +var client = ThirdwebClient.Create(secretKey: secretKey); + +#region Signing Messages + +// Create a guest wallet +var guestWallet = await InAppWallet.Create(client, authProvider: AuthProvider.Guest); +var walletAddress = await guestWallet.LoginWithGuest(); +Console.WriteLine($"Guest Wallet address: {walletAddress}"); + +var signature = await guestWallet.PersonalSign("Hello, Thirdweb!"); +Console.WriteLine($"Guest Wallet personal sign: {signature}"); + +#endregion + +#region Reading from Contracts + +// var contract = await ThirdwebContract.Create(client: client, address: "0xbc4ca0eda7647a8ab7c2061c2e118a18a936f13d", chain: 1); +// var nfts = await contract.ERC721_GetNFT(0); +// Console.WriteLine($"NFTs: {JsonConvert.SerializeObject(nfts, Formatting.Indented)}"); + +#endregion + +#region User Wallets (Social Auth Example) + +// var inAppWalletOAuth = await InAppWallet.Create(client: client, authProvider: AuthProvider.Google); +// if (!await inAppWalletOAuth.IsConnected()) // { -// Console.WriteLine("Please submit the OTP again."); -// goto retry; +// _ = await inAppWalletOAuth.LoginWithOauth( +// isMobile: false, +// (url) => +// { +// var psi = new ProcessStartInfo { FileName = url, UseShellExecute = true }; +// _ = Process.Start(psi); +// }, +// "thirdweb://", +// new InAppWalletBrowser() +// ); // } -// if (inAppWalletAddress == null) +// var inAppWalletOAuthAddress = await inAppWalletOAuth.GetAddress(); +// Console.WriteLine($"InAppWallet OAuth address: {inAppWalletOAuthAddress}"); + +// var inAppWalletAuthDetails = inAppWalletOAuth.GetUserAuthDetails(); +// Console.WriteLine($"InAppWallet OAuth auth details: {JsonConvert.SerializeObject(inAppWalletAuthDetails, Formatting.Indented)}"); + +#endregion + +#region Server Wallets + +// // ServerWallet is compatible with IThirdwebWallet and can be used with any SDK method/extension +// var serverWallet = await ServerWallet.Create( +// client: client, +// label: "Test", +// // Optional, defaults to Auto - we choose between EIP-7702, EIP-4337 or native zkSync AA execution / EOA is also available +// executionOptions: new AutoExecutionOptions() +// ); + +// var serverWalletAddress = await serverWallet.GetAddress(); +// Console.WriteLine($"Server Wallet address: {serverWalletAddress}"); + +// var serverWalletPersonalSig = await serverWallet.PersonalSign("Hello, Thirdweb!"); +// Console.WriteLine($"Server Wallet personal sign: {serverWalletPersonalSig}"); + +// var json = +// /*lang=json,strict*/ +// "{\"types\":{\"EIP712Domain\":[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"version\",\"type\":\"string\"},{\"name\":\"chainId\",\"type\":\"uint256\"},{\"name\":\"verifyingContract\",\"type\":\"address\"}],\"Person\":[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"wallet\",\"type\":\"address\"}],\"Mail\":[{\"name\":\"from\",\"type\":\"Person\"},{\"name\":\"to\",\"type\":\"Person\"},{\"name\":\"contents\",\"type\":\"string\"}]},\"primaryType\":\"Mail\",\"domain\":{\"name\":\"Ether Mail\",\"version\":\"1\",\"chainId\":84532,\"verifyingContract\":\"0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC\"},\"message\":{\"from\":{\"name\":\"Cow\",\"wallet\":\"0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826\"},\"to\":{\"name\":\"Bob\",\"wallet\":\"0xbBbBBBBbbBBBbbbBbbBbbBBbBbbBbBbBbBbbBBbB\"},\"contents\":\"Hello, Bob!\"}}"; +// var serverWalletTypedDataSign = await serverWallet.SignTypedDataV4(json); +// Console.WriteLine($"Server Wallet typed data sign: {serverWalletTypedDataSign}"); + +// // Simple self transfer +// var serverWalletReceipt = await serverWallet.Transfer(chainId: 84532, toAddress: await serverWallet.GetAddress(), weiAmount: 0); +// Console.WriteLine($"Server Wallet Hash: {serverWalletReceipt.TransactionHash}"); + +// // ServerWallet forcing ERC-4337 Execution Mode +// var smartServerWallet = await ServerWallet.Create(client: client, label: "Test", executionOptions: new ERC4337ExecutionOptions(chainId: 84532, signerAddress: serverWalletAddress)); +// var smartServerWalletAddress = await smartServerWallet.GetAddress(); +// Console.WriteLine($"Smart Server Wallet address: {smartServerWalletAddress}"); + +// var smartServerWalletPersonalSig = await smartServerWallet.PersonalSign("Hello, Thirdweb!"); +// Console.WriteLine($"Smart Server Wallet personal sign: {smartServerWalletPersonalSig}"); + +// var smartServerWalletTypedDataSign = await smartServerWallet.SignTypedDataV4(json); +// Console.WriteLine($"Smart Server Wallet typed data sign: {smartServerWalletTypedDataSign}"); + +// // Simple self transfer +// var smartServerWalletReceipt = await smartServerWallet.Transfer(chainId: 84532, toAddress: await smartServerWallet.GetAddress(), weiAmount: 0); +// Console.WriteLine($"Server Wallet Hash: {smartServerWalletReceipt.TransactionHash}"); + +#endregion + +#region Thirdweb API Wrapper + +// var metadata = await client.Api.GetContractMetadataAsync(chainId: 1, address: "0xBd3531dA5CF5857e7CfAA92426877b022e612cf8"); + +// Console.WriteLine($"ABI: {JsonConvert.SerializeObject(metadata.Result.Output.Abi, Formatting.Indented)}"); +// Console.WriteLine($"Compiler version: {metadata.Result.Compiler.Version}"); + +#endregion + +#region AA 7702 + +// var chain = 84532; // 7702-compatible chain + +// // Connect to EOA +// var smartEoa = await InAppWallet.Create(client, authProvider: AuthProvider.Guest, executionMode: ExecutionMode.EIP7702Sponsored); +// if (!await smartEoa.IsConnected()) // { -// Console.WriteLine("OTP login failed. Please try again."); -// return; -// } -// Console.WriteLine($"InAppWallet address: {inAppWalletAddress}"); +// _ = await smartEoa.LoginWithGuest(defaultSessionIdOverride: new Guid().ToString()); // } +// var smartEoaAddress = await smartEoa.GetAddress(); +// Console.WriteLine($"User Wallet address: {await smartEoa.GetAddress()}"); + +// // Transact, will upgrade EOA +// var receipt = await smartEoa.Transfer(chainId: chain, toAddress: await Utils.GetAddressFromENS(client, "vitalik.eth"), weiAmount: 0); +// Console.WriteLine($"Transfer Receipt: {receipt.TransactionHash}"); + +#endregion + +#region AA 0.6 + +// var smartWallet06 = await SmartWallet.Create(personalWallet: guestWallet, chainId: 421614, gasless: true); +// var receipt06 = await smartWallet06.Transfer(chainId: 421614, toAddress: await smartWallet06.GetAddress(), weiAmount: 0); +// Console.WriteLine($"Receipt: {receipt06}"); + +#endregion + +#region AA 0.7 + +// var smartWallet07 = await SmartWallet.Create(personalWallet: guestWallet, chainId: 421614, gasless: true, entryPoint: Constants.ENTRYPOINT_ADDRESS_V07); +// var receipt07 = await smartWallet07.Transfer(chainId: 421614, toAddress: await smartWallet07.GetAddress(), weiAmount: 0); +// Console.WriteLine($"Receipt: {receipt07}"); + +#endregion + +#region AA ZkSync + +// var zkSmartWallet = await SmartWallet.Create(personalWallet: privateKeyWallet, chainId: 11124, gasless: true); + +// var hash = await zkSmartWallet.SendTransaction(new ThirdwebTransactionInput(chainId: 11124, to: await zkSmartWallet.GetAddress(), value: 0, data: "0x")); + +// Console.WriteLine($"Transaction hash: {hash}"); + +#endregion + +#region Deploy Contract + +// var serverWallet = await ServerWallet.Create(client: client, label: "TestFromDotnet"); + +// var abi = +// "[ { \"inputs\": [], \"name\": \"welcome\", \"outputs\": [ { \"internalType\": \"string\", \"name\": \"\", \"type\": \"string\" } ], \"stateMutability\": \"pure\", \"type\": \"function\" } ]"; -// Prepare a transaction directly, or with Contract.Prepare -// var tx = await ThirdwebTransaction.Create( +// var contractAddress = await ThirdwebContract.Deploy( // client: client, -// wallet: privateKeyWallet, -// txInput: new ThirdwebTransactionInput() +// chainId: 11155111, +// serverWalletAddress: await serverWallet.GetAddress(), +// bytecode: "6080604052348015600e575f5ffd5b5061014e8061001c5f395ff3fe608060405234801561000f575f5ffd5b5060043610610029575f3560e01c8063b627cf3b1461002d575b5f5ffd5b61003561004b565b60405161004291906100f8565b60405180910390f35b60606040518060400160405280601481526020017f57656c636f6d6520746f20746869726477656221000000000000000000000000815250905090565b5f81519050919050565b5f82825260208201905092915050565b8281835e5f83830152505050565b5f601f19601f8301169050919050565b5f6100ca82610088565b6100d48185610092565b93506100e48185602086016100a2565b6100ed816100b0565b840191505092915050565b5f6020820190508181035f83015261011081846100c0565b90509291505056fea264697066735822122001498e9d7d6125ce22613ef32fdb7e8e03bf11ad361d7b00e210b82d7b7e0d4464736f6c634300081e0033", +// abi: abi +// ); +// Console.WriteLine($"Contract deployed at: {contractAddress}"); + +// var contract = await ThirdwebContract.Create(client: client, address: contractAddress, chain: 11155111, abi: abi); +// var welcomeMessage = await contract.Read("welcome"); +// Console.WriteLine($"Welcome message from deployed contract: {welcomeMessage}"); + +#endregion + +#region Get Social Profiles + +// var socialProfiles = await Utils.GetSocialProfiles(client, "joenrv.eth"); +// Console.WriteLine($"Social Profiles: {socialProfiles}"); + +#endregion + +#region EIP-7702 (Low Level) + +// var chain = 42220; // 7702-compatible chain + +// // Connect to EOA +// var smartEoa = await InAppWallet.Create(client, authProvider: AuthProvider.Guest, executionMode: ExecutionMode.EIP7702Sponsored); +// if (!await smartEoa.IsConnected()) +// { +// _ = await smartEoa.LoginWithGuest(defaultSessionIdOverride: new Guid().ToString()); +// } +// var smartEoaAddress = await smartEoa.GetAddress(); +// Console.WriteLine($"User Wallet address: {await smartEoa.GetAddress()}"); + +// // Upgrade EOA - This wallet explicitly uses EIP-7702 delegation to the thirdweb MinimalAccount (will delegate upon first tx) +// var signerAddress = await Utils.GetAddressFromENS(client, "vitalik.eth"); + +// // Transact, will upgrade EOA +// var receipt = await smartEoa.Transfer(chainId: chain, toAddress: signerAddress, weiAmount: 0); +// Console.WriteLine($"Transfer Receipt: {receipt.TransactionHash}"); + +// // Double check that it was upgraded +// var isDelegated = await Utils.IsDeployed(client, chain, smartEoaAddress); +// Console.WriteLine($"Is delegated: {isDelegated}"); + +// // Create a session key +// var sessionKeyReceipt = await smartEoa.CreateSessionKey(chainId: chain, signerAddress: signerAddress, durationInSeconds: 86400, grantFullPermissions: true); +// Console.WriteLine($"Session key receipt: {sessionKeyReceipt.TransactionHash}"); + +// // Validate session key config +// var hasFullPermissions = await smartEoa.SignerHasFullPermissions(chain, signerAddress); +// Console.WriteLine($"Signer has full permissions: {hasFullPermissions}"); + +// var sessionExpiration = await smartEoa.GetSessionExpirationForSigner(chain, signerAddress); +// Console.WriteLine($"Session expires in {sessionExpiration - Utils.GetUnixTimeStampNow()} seconds"); + +// // Create a session key with granular permissions +// var granularSessionKeyReceipt = await smartEoa.CreateSessionKey( +// chainId: chain, +// signerAddress: signerAddress, +// durationInSeconds: 86400, +// grantFullPermissions: false, +// transferPolicies: new List // { -// From = await privateKeyWallet.GetAddress(), -// To = await privateKeyWallet.GetAddress(), -// Value = new HexBigInteger(BigInteger.Zero), -// }, -// chainId: 300 +// new() +// { +// Target = signerAddress, +// MaxValuePerUse = BigInteger.Parse("0.001".ToWei()), +// ValueLimit = new UsageLimit +// { +// LimitType = 1, // Lifetime +// Limit = BigInteger.Parse("0.01".ToWei()), +// Period = 86400, // 1 day +// } +// } +// } // ); -// // Set zkSync options -// tx.SetZkSyncOptions( -// new ZkSyncOptions( -// // Paymaster contract address -// paymaster: "0xbA226d47Cbb2731CBAA67C916c57d68484AA269F", -// // IPaymasterFlow interface encoded data -// paymasterInput: "0x8c5a344500000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000" -// ) +// // Validate session key config +// var sessionState = await smartEoa.GetSessionStateForSigner(chain, signerAddress); +// Console.WriteLine($"Session state: {JsonConvert.SerializeObject(sessionState, Formatting.Indented)}"); + +// var transferPolcies = await smartEoa.GetTransferPoliciesForSigner(chain, signerAddress); +// Console.WriteLine($"Transfer policies: {JsonConvert.SerializeObject(transferPolcies, Formatting.Indented)}"); + +// var callPolicies = await smartEoa.GetCallPoliciesForSigner(chain, signerAddress); +// Console.WriteLine($"Call policies: {JsonConvert.SerializeObject(callPolicies, Formatting.Indented)}"); + +#endregion + +#region Smart Ecosystem Wallet + +// var eco = await EcosystemWallet.Create(client: client, ecosystemId: "ecosystem.the-bonfire", authProvider: AuthProvider.Github); +// if (!await eco.IsConnected()) +// { +// _ = await eco.LoginWithOauth( +// isMobile: false, +// browserOpenAction: (url) => +// { +// var psi = new ProcessStartInfo { FileName = url, UseShellExecute = true }; +// _ = Process.Start(psi); +// } +// ); +// } +// var smartEco = await SmartWallet.Create(eco, 421614); +// var addy = await smartEco.GetAddress(); +// Console.WriteLine($"Smart Ecosystem Wallet address: {addy}"); + +#endregion + +#region Ecosystem Wallet + +// var ecosystemWallet = await EcosystemWallet.Create(client: client, ecosystemId: "ecosystem.the-bonfire", authProvider: AuthProvider.Telegram); + +// if (!await ecosystemWallet.IsConnected()) +// { +// _ = await ecosystemWallet.LoginWithOauth( +// isMobile: false, +// (url) => +// { +// var psi = new ProcessStartInfo { FileName = url, UseShellExecute = true }; +// _ = Process.Start(psi); +// }, +// "thirdweb://", +// new InAppWalletBrowser() +// ); +// } +// var ecosystemWalletAddress = await ecosystemWallet.GetAddress(); +// Console.WriteLine($"Ecosystem Wallet address: {ecosystemWalletAddress}"); + +// var ecosystemPersonalSignature = await ecosystemWallet.PersonalSign("Hello, Thirdweb!"); +// Console.WriteLine($"Ecosystem Wallet personal sign: {ecosystemPersonalSignature}"); + +// var ecosystemTypedSignature = await ecosystemWallet.SignTypedDataV4( +// /*lang=json,strict*/ +// "{\"types\": {\"EIP712Domain\": [{\"name\": \"name\",\"type\": \"string\"},{\"name\": \"version\",\"type\": \"string\"},{\"name\": \"chainId\",\"type\": \"uint256\"},{\"name\": \"verifyingContract\",\"type\": \"address\"}],\"Person\": [{\"name\": \"name\",\"type\": \"string\"},{\"name\": \"wallet\",\"type\": \"address\"}],\"Mail\": [{\"name\": \"from\",\"type\": \"Person\"},{\"name\": \"to\",\"type\": \"Person\"},{\"name\": \"contents\",\"type\": \"string\"}]},\"primaryType\": \"Mail\",\"domain\": {\"name\": \"Ether Mail\",\"version\": \"1\",\"chainId\": 1,\"verifyingContract\": \"0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC\"},\"message\": {\"from\": {\"name\": \"Cow\",\"wallet\": \"0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826\"},\"to\": {\"name\": \"Bob\",\"wallet\": \"0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB\"},\"contents\": \"Hello, Bob!\"}}" // ); +// Console.WriteLine($"Ecosystem Wallet typed sign: {ecosystemTypedSignature}"); -// // Send as usual, it's now gasless! -// var txHash = await ThirdwebTransaction.Send(transaction: tx); -// Console.WriteLine($"Transaction hash: {txHash}"); - -// var zkSmartWallet = await SmartWallet.Create(client: client, personalWallet: privateKeyWallet, chainId: 302, gasless: true); -// Console.WriteLine($"Smart wallet address: {await zkSmartWallet.GetAddress()}"); -// var zkAaTx = await ThirdwebTransaction.Create(client, zkSmartWallet, new ThirdwebTransactionInput() { From = await zkSmartWallet.GetAddress(), To = await zkSmartWallet.GetAddress(), }, 302); -// var zkSyncSignatureBasedAaTxHash = await ThirdwebTransaction.Send(zkAaTx); -// Console.WriteLine($"Transaction hash: {zkSyncSignatureBasedAaTxHash}"); - -// Create smart wallet with InAppWallet signer -// var smartWallet = await SmartWallet.Create(client: client, personalWallet: inAppWallet, factoryAddress: "0xbf1C9aA4B1A085f7DA890a44E82B0A1289A40052", gasless: true, chainId: 421614); -// var res = await smartWallet.Authenticate("http://localhost:8000", 421614); -// Console.WriteLine($"Smart wallet auth result: {res}"); - -// // Grant a session key to pk wallet (advanced use case) -// _ = await smartWallet.CreateSessionKey( -// signerAddress: await privateKeyWallet.GetAddress(), -// approvedTargets: new List() { Constants.ADDRESS_ZERO }, -// nativeTokenLimitPerTransactionInWei: "0", -// permissionStartTimestamp: "0", -// permissionEndTimestamp: (Utils.GetUnixTimeStampNow() + 86400).ToString(), -// reqValidityStartTimestamp: "0", -// reqValidityEndTimestamp: Utils.GetUnixTimeStampIn10Years().ToString() +// var ecosystemWalletOther = await EcosystemWallet.Create(client: client, ecosystemId: "ecosystem.the-bonfire", authProvider: AuthProvider.Telegram); +// var linkedAccounts = await ecosystemWallet.LinkAccount( +// walletToLink: ecosystemWalletOther, +// browserOpenAction: (url) => +// { +// var psi = new ProcessStartInfo { FileName = url, UseShellExecute = true }; +// _ = Process.Start(psi); +// } // ); +// Console.WriteLine($"Linked accounts: {JsonConvert.SerializeObject(linkedAccounts, Formatting.Indented)}"); -// // Reconnect to same smart wallet with pk wallet as signer (specifying wallet address override) -// smartWallet = await SmartWallet.Create( -// client: client, -// personalWallet: privateKeyWallet, -// factoryAddress: "0xbf1C9aA4B1A085f7DA890a44E82B0A1289A40052", -// gasless: true, -// chainId: 421614, -// accountAddressOverride: await smartWallet.GetAddress() +// var ecosystemSmartWallet = await SmartWallet.Create(ecosystemWallet, 421614); + +// var ecosystemTx = await ThirdwebTransaction.Create(wallet: ecosystemSmartWallet, txInput: new ThirdwebTransactionInput(chainId: 421614, to: await ecosystemWallet.GetAddress())); + +// var ecosystemTxHash = await ThirdwebTransaction.Send(ecosystemTx); +// Console.WriteLine($"Ecosystem Wallet transaction hash: {ecosystemTxHash}"); + +#endregion + +#region Maximum low level zksync tx + +// var chainId = 300; + +// var zkRawWallet = await PrivateKeyWallet.Generate(client: client); +// var zkRawAddy = await zkRawWallet.GetAddress(); +// Console.WriteLine($"ZkSync raw address: {zkRawAddy}"); + +// // Less raw example + +// var zkRawTx = await ThirdwebTransaction.Create( +// wallet: zkRawWallet, +// txInput: new ThirdwebTransactionInput(chainId: chainId, from: zkRawAddy, to: zkRawAddy, value: 0, data: "0x", zkSync: new ZkSyncOptions(gasPerPubdataByteLimit: 50000)) // ); -// // Log addresses -// Console.WriteLine($"PrivateKey Wallet: {await privateKeyWallet.GetAddress()}"); -// Console.WriteLine($"InAppWallet: {await inAppWallet.GetAddress()}"); -// Console.WriteLine($"Smart Wallet: {await smartWallet.GetAddress()}"); - -// // Sign, triggering deploy as needed and 1271 verification if it's a smart wallet -// var message = "Hello, Thirdweb!"; -// var signature = await smartWallet.PersonalSign(message); -// Console.WriteLine($"Signed message: {signature}"); - -// var balanceBefore = await ThirdwebContract.Read(contract, "balanceOf", await smartWallet.GetAddress()); -// Console.WriteLine($"Balance before mint: {balanceBefore}"); - -// var writeResult = await ThirdwebContract.Write(smartWallet, contract, "mintTo", 0, await smartWallet.GetAddress(), 100); -// Console.WriteLine($"Contract write result: {writeResult}"); - -// var balanceAfter = await ThirdwebContract.Read(contract, "balanceOf", await smartWallet.GetAddress()); -// Console.WriteLine($"Balance after mint: {balanceAfter}"); - -// // Transaction Builder -// var preparedTx = await ThirdwebContract.Prepare(wallet: smartWallet, contract: contract, method: "mintTo", weiValue: 0, parameters: new object[] { await smartWallet.GetAddress(), 100 }); -// Console.WriteLine($"Prepared transaction: {preparedTx}"); -// var estimatedCosts = await ThirdwebTransaction.EstimateGasCosts(preparedTx); -// Console.WriteLine($"Estimated ETH gas cost: {estimatedCosts.ether}"); -// var totalCosts = await ThirdwebTransaction.EstimateTotalCosts(preparedTx); -// Console.WriteLine($"Estimated ETH total cost: {totalCosts.ether}"); -// var simulationData = await ThirdwebTransaction.Simulate(preparedTx); -// Console.WriteLine($"Simulation data: {simulationData}"); -// var txHash = await ThirdwebTransaction.Send(preparedTx); -// Console.WriteLine($"Transaction hash: {txHash}"); -// var receipt = await ThirdwebTransaction.WaitForTransactionReceipt(client, 421614, txHash); -// Console.WriteLine($"Transaction receipt: {JsonConvert.SerializeObject(receipt)}"); - -// // Transaction Builder - raw transfer -// var rawTx = new ThirdwebTransactionInput +// zkRawTx = await ThirdwebTransaction.Prepare(zkRawTx); + +// Console.WriteLine($"ZkSync raw transaction: {zkRawTx}"); +// Console.WriteLine("Make sure you have enough funds!"); +// Console.ReadLine(); + +// var receipt = await ThirdwebTransaction.SendAndWaitForTransactionReceipt(zkRawTx); +// Console.WriteLine($"Receipt: {receipt}"); + +// // Extremely raw example + +// var zkRawTx = new Thirdweb.AccountAbstraction.ZkSyncAATransaction // { -// From = await smartWallet.GetAddress(), -// To = await smartWallet.GetAddress(), -// Value = new HexBigInteger(BigInteger.Zero), -// Data = "0x", +// TxType = 0x71, +// From = new HexBigInteger(zkRawAddy).Value, +// To = new HexBigInteger(zkRawAddy).Value, +// GasLimit = 250000, +// GasPerPubdataByteLimit = 50000, +// MaxFeePerGas = 1000000000, +// MaxPriorityFeePerGas = 1000000000, +// Paymaster = 0, +// Nonce = 0, +// Value = 0, +// Data = new byte[] { 0x00 }, +// FactoryDeps = new List(), +// PaymasterInput = Array.Empty(), // }; -// var preparedRawTx = await ThirdwebTransaction.Create(client: client, wallet: smartWallet, txInput: rawTx, chainId: 421614); -// Console.WriteLine($"Prepared raw transaction: {preparedRawTx}"); -// var estimatedCostsRaw = await ThirdwebTransaction.EstimateGasCosts(preparedRawTx); -// Console.WriteLine($"Estimated ETH gas cost: {estimatedCostsRaw.ether}"); -// var totalCostsRaw = await ThirdwebTransaction.EstimateTotalCosts(preparedRawTx); -// Console.WriteLine($"Estimated ETH total cost: {totalCostsRaw.ether}"); -// var simulationDataRaw = await ThirdwebTransaction.Simulate(preparedRawTx); -// Console.WriteLine($"Simulation data: {simulationDataRaw}"); -// var txHashRaw = await ThirdwebTransaction.Send(preparedRawTx); -// Console.WriteLine($"Raw transaction hash: {txHashRaw}"); -// var receiptRaw = await ThirdwebTransaction.WaitForTransactionReceipt(client, 421614, txHashRaw); -// Console.WriteLine($"Raw transaction receipt: {JsonConvert.SerializeObject(receiptRaw)}"); - - -// Storage actions +// var signedZkRawTx = await EIP712.GenerateSignature_ZkSyncTransaction("zkSync", "2", chainId, zkRawTx, zkRawWallet); + +// Console.WriteLine($"ZkSync raw transaction: {JsonConvert.SerializeObject(zkRawTx, Formatting.Indented)}"); +// Console.WriteLine("Make sure you have enough funds!"); +// Console.ReadLine(); + +// var rpcInstance = ThirdwebRPC.GetRpcInstance(client, chainId); +// var hash = await rpcInstance.SendRequestAsync("eth_sendRawTransaction", signedZkRawTx); +// Console.WriteLine($"Transaction hash: {hash}"); + +#endregion + +#region Backend Wallet Auth + +// var inAppWalletBackend = await InAppWallet.Create(client: client, authProvider: AuthProvider.Backend, walletSecret: "very-secret"); +// if (!await inAppWalletBackend.IsConnected()) +// { +// _ = await inAppWalletBackend.LoginWithBackend(); +// } +// var inAppWalletBackendAddress = await inAppWalletBackend.GetAddress(); +// Console.WriteLine($"InAppWallet Backend address: {inAppWalletBackendAddress}"); + +#endregion + +#region Account Linking + +// var inAppWalletMain = await InAppWallet.Create(client: client, authProvider: AuthProvider.Telegram); +// if (!await inAppWalletMain.IsConnected()) +// { +// _ = await inAppWalletMain.LoginWithOauth( +// isMobile: false, +// (url) => +// { +// var psi = new ProcessStartInfo { FileName = url, UseShellExecute = true }; +// _ = Process.Start(psi); +// }, +// "thirdweb://", +// new InAppWalletBrowser() +// ); +// } +// Console.WriteLine($"Main InAppWallet address: {await inAppWalletMain.GetAddress()}"); + +// var oldLinkedAccounts = await inAppWalletMain.GetLinkedAccounts(); +// Console.WriteLine($"Old linked accounts: {JsonConvert.SerializeObject(oldLinkedAccounts, Formatting.Indented)}"); + +// // External wallet variant +// var externalWallet = await PrivateKeyWallet.Generate(client: client); +// var inAppWalletToLink = await InAppWallet.Create(client: client, authProvider: AuthProvider.Siwe, siweSigner: externalWallet); +// var linkedAccounts = await inAppWalletMain.LinkAccount(walletToLink: inAppWalletToLink, chainId: 421614); +// Console.WriteLine($"Linked accounts: {JsonConvert.SerializeObject(linkedAccounts, Formatting.Indented)}"); + +// var unlinkingResult = await inAppWalletMain.UnlinkAccount(linkedAccounts.First(linkedAccounts => linkedAccounts.Type == "siwe")); +// Console.WriteLine($"Unlinking result: {JsonConvert.SerializeObject(unlinkingResult, Formatting.Indented)}"); + +#endregion + +#region Smart Wallet - Authenticate + +// var appWallet = await InAppWallet.Create(client: client, authProvider: AuthProvider.Google); +// if (!await appWallet.IsConnected()) +// { +// _ = await appWallet.LoginWithOauth( +// isMobile: false, +// (url) => +// { +// var psi = new ProcessStartInfo { FileName = url, UseShellExecute = true }; +// _ = Process.Start(psi); +// }, +// "thirdweb://", +// new InAppWalletBrowser() +// ); +// } +// var smartWallet = await SmartWallet.Create(appWallet, 37714555429); + +// var data = await smartWallet.Authenticate( +// domain: "https://myepicdomain.com", +// chainId: 37714555429, +// authPayloadPath: "/my-epic-auth/login", +// authLoginPath: "/my-epic-auth/login", +// separatePayloadAndSignatureInBody: true, +// authPayloadMethod: "GET", +// authLoginMethod: "POST" +// ); +// Console.WriteLine($"Token: {data["token"]}"); + +#endregion + +#region TokenPaymaster - Celo CUSD + +// var chainId = 42220; // celo + +// var erc20SmartWallet = await SmartWallet.Create(personalWallet: privateKeyWallet, chainId: chainId, tokenPaymaster: TokenPaymaster.CELO_CUSD); + +// var erc20SmartWalletAddress = await erc20SmartWallet.GetAddress(); +// Console.WriteLine($"ERC20 Smart Wallet address: {erc20SmartWalletAddress}"); + +// var receipt = await erc20SmartWallet.Transfer(chainId: chainId, toAddress: erc20SmartWalletAddress, weiAmount: 0); +// Console.WriteLine($"Receipt: {JsonConvert.SerializeObject(receipt, Formatting.Indented)}"); + +#endregion + +#region TokenPaymaster - Base USDC + +// var chainId = 8453; // base + +// var erc20SmartWallet = await SmartWallet.Create(personalWallet: privateKeyWallet, chainId: chainId, tokenPaymaster: TokenPaymaster.BASE_USDC); + +// var erc20SmartWalletAddress = await erc20SmartWallet.GetAddress(); +// Console.WriteLine($"ERC20 Smart Wallet address: {erc20SmartWalletAddress}"); + +// var receipt = await erc20SmartWallet.Transfer(chainId: chainId, toAddress: erc20SmartWalletAddress, weiAmount: 0); +// Console.WriteLine($"Receipt: {JsonConvert.SerializeObject(receipt, Formatting.Indented)}"); + +#endregion + +#region TokenPaymaster - Lisk LSK + +// var chainId = 1135; // lisk + +// var erc20SmartWallet = await SmartWallet.Create(personalWallet: privateKeyWallet, chainId: chainId, tokenPaymaster: TokenPaymaster.LISK_LSK); + +// var erc20SmartWalletAddress = await erc20SmartWallet.GetAddress(); +// Console.WriteLine($"ERC20 Smart Wallet address: {erc20SmartWalletAddress}"); + +// var receipt = await erc20SmartWallet.Transfer(chainId: chainId, toAddress: erc20SmartWalletAddress, weiAmount: 0); +// Console.WriteLine($"Receipt: {JsonConvert.SerializeObject(receipt, Formatting.Indented)}"); + +#endregion + +#region Chain Data Fetching + +// var chainData = await Utils.GetChainMetadata(client, 421614); +// Console.WriteLine($"Chain data: {JsonConvert.SerializeObject(chainData, Formatting.Indented)}"); + +#endregion + +#region Storage Actions // // Will download from IPFS or normal urls // var downloadResult = await ThirdwebStorage.Download(client: client, uri: "AnyUrlIncludingIpfs"); @@ -188,9 +510,13 @@ // var uploadResult = await ThirdwebStorage.Upload(client: client, path: "AnyPath"); // Console.WriteLine($"Upload result preview: {uploadResult.PreviewUrl}"); +#endregion -// Access RPC directly if needed, generally not recommended +#region RPC Access +// // Access RPC directly if needed, generally not recommended // var rpc = ThirdwebRPC.GetRpcInstance(client, 421614); // var blockNumber = await rpc.SendRequestAsync("eth_blockNumber"); // Console.WriteLine($"Block number: {blockNumber}"); + +#endregion diff --git a/Thirdweb.Console/Thirdweb.Console.csproj b/Thirdweb.Console/Thirdweb.Console.csproj index 2acaa4b5..899409eb 100644 --- a/Thirdweb.Console/Thirdweb.Console.csproj +++ b/Thirdweb.Console/Thirdweb.Console.csproj @@ -1,26 +1,22 @@ - - Exe net8.0 + latest + true enable enable false - - - + - PreserveNewest - - \ No newline at end of file + diff --git a/Thirdweb.Generator/Program.cs b/Thirdweb.Generator/Program.cs new file mode 100644 index 00000000..41e29e0c --- /dev/null +++ b/Thirdweb.Generator/Program.cs @@ -0,0 +1,458 @@ +using System.Globalization; +using System.Text; +using System.Xml.Linq; +using NJsonSchema; +using NSwag; +using NSwag.CodeGeneration.CSharp; + +static string FindRepoRoot() +{ + var dir = new DirectoryInfo(Directory.GetCurrentDirectory()); + while (dir != null) + { + if (File.Exists(Path.Combine(dir.FullName, "thirdweb.sln"))) + { + return dir.FullName; + } + dir = dir.Parent; + } + // Fallback to current directory + return Directory.GetCurrentDirectory(); +} + +static void GenerateLlmsTxt(string repoRoot) +{ + var xmlPath = Path.Combine(repoRoot, "Thirdweb", "bin", "Release", "netstandard2.1", "Thirdweb.xml"); + var outputPath = Path.Combine(repoRoot, "llms.txt"); + + if (!File.Exists(xmlPath)) + { + Console.WriteLine($"XML documentation not found at {xmlPath}"); + Console.WriteLine("Please build the project in Release mode first."); + Environment.Exit(1); + } + + Console.WriteLine($"Reading XML documentation from {xmlPath}..."); + var doc = XDocument.Load(xmlPath); + var sb = new StringBuilder(); + + _ = sb.AppendLine("THIRDWEB .NET SDK - API DOCUMENTATION"); + _ = sb.AppendLine("====================================="); + _ = sb.AppendLine(); + + var assembly = doc.Root?.Element("assembly")?.Element("name")?.Value; + if (assembly != null) + { + _ = sb.AppendLine($"Assembly: {assembly}"); + _ = sb.AppendLine(); + } + + var members = doc.Root?.Element("members")?.Elements("member"); + if (members != null) + { + foreach (var member in members) + { + var name = member.Attribute("name")?.Value; + if (string.IsNullOrEmpty(name)) + { + continue; + } + + _ = sb.AppendLine(new string('-', 80)); + _ = sb.AppendLine(name); + _ = sb.AppendLine(new string('-', 80)); + + // Parse signature for better display + var signature = ParseMemberSignature(name); + if (signature != null) + { + _ = sb.AppendLine(); + _ = sb.AppendLine($"KIND: {signature.Kind}"); + if (!string.IsNullOrEmpty(signature.ReturnType)) + { + _ = sb.AppendLine($"RETURN TYPE: {signature.ReturnType}"); + } + } + + // Group param elements by name attribute + var paramDocs = member.Elements("param").Select(p => new { Name = p.Attribute("name")?.Value, Description = p.Value.Trim() }).Where(p => !string.IsNullOrEmpty(p.Name)).ToList(); + + // Display parameters with their names and types + if (signature?.Parameters != null && signature.Parameters.Count > 0) + { + _ = sb.AppendLine(); + _ = sb.AppendLine("PARAMETERS:"); + for (var i = 0; i < signature.Parameters.Count; i++) + { + var param = signature.Parameters[i]; + // Try to get the actual parameter name from documentation + var paramDoc = i < paramDocs.Count ? paramDocs[i] : null; + var paramName = paramDoc?.Name ?? param.Name; + + _ = sb.AppendLine($" - {paramName} ({param.Type})"); + if (paramDoc != null && !string.IsNullOrEmpty(paramDoc.Description)) + { + _ = sb.AppendLine($" {NormalizeXmlText(paramDoc.Description).Replace("\n", "\n ")}"); + } + } + } + + // Display other elements (summary, remarks, returns, exception, etc.) + foreach (var element in member.Elements()) + { + if (element.Name.LocalName == "param") + { + continue; // Already handled above + } + + var content = element.Value.Trim(); + if (string.IsNullOrEmpty(content)) + { + continue; + } + + _ = sb.AppendLine(); + var elementName = element.Name.LocalName.ToUpper(); + + // Add attribute info for exceptions and type params + var nameAttr = element.Attribute("name")?.Value; + var crefAttr = element.Attribute("cref")?.Value; + if (!string.IsNullOrEmpty(nameAttr)) + { + elementName += $" ({nameAttr})"; + } + else if (!string.IsNullOrEmpty(crefAttr)) + { + elementName += $" ({crefAttr})"; + } + + _ = sb.AppendLine($"{elementName}:"); + _ = sb.AppendLine(NormalizeXmlText(content)); + } + + _ = sb.AppendLine(); + } + } + + File.WriteAllText(outputPath, sb.ToString()); + Console.WriteLine($"Generated llms.txt at {outputPath}"); +} + +static MemberSignature? ParseMemberSignature(string memberName) +{ + if (string.IsNullOrEmpty(memberName) || memberName.Length < 2) + { + return null; + } + + var kind = memberName[0] switch + { + 'M' => "Method", + 'P' => "Property", + 'T' => "Type", + 'F' => "Field", + 'E' => "Event", + _ => "Unknown", + }; + + var fullSignature = memberName[2..]; // Remove "M:", "P:", etc. + + // For methods, parse parameters and return type + if (memberName[0] == 'M') + { + var parameters = new List(); + var methodName = fullSignature; + var returnType = "System.Threading.Tasks.Task"; // Default for async methods + + // Extract parameters from signature + var paramStart = fullSignature.IndexOf('('); + if (paramStart >= 0) + { + methodName = fullSignature[..paramStart]; + var paramEnd = fullSignature.LastIndexOf(')'); + if (paramEnd > paramStart) + { + var paramString = fullSignature[(paramStart + 1)..paramEnd]; + if (!string.IsNullOrEmpty(paramString)) + { + var paramParts = SplitParameters(paramString); + for (var i = 0; i < paramParts.Count; i++) + { + var paramType = SimplifyTypeName(paramParts[i]); + parameters.Add(new ParameterInfo { Name = $"param{i + 1}", Type = paramType }); + } + } + } + + // Check if there's a return type after the parameters + if (paramEnd + 1 < fullSignature.Length && fullSignature[paramEnd + 1] == '~') + { + returnType = SimplifyTypeName(fullSignature[(paramEnd + 2)..]); + } + } + + return new MemberSignature + { + Kind = kind, + Parameters = parameters, + ReturnType = parameters.Count > 0 || fullSignature.Contains("Async") ? returnType : null, + }; + } + + return new MemberSignature { Kind = kind }; +} + +static List SplitParameters(string paramString) +{ + var parameters = new List(); + var current = new StringBuilder(); + var depth = 0; + + foreach (var c in paramString) + { + if (c is '{' or '<') + { + depth++; + } + else if (c is '}' or '>') + { + depth--; + } + else if (c == ',' && depth == 0) + { + parameters.Add(current.ToString()); + _ = current.Clear(); + continue; + } + + _ = current.Append(c); + } + + if (current.Length > 0) + { + parameters.Add(current.ToString()); + } + + return parameters; +} + +static string SimplifyTypeName(string fullTypeName) +{ + // Remove assembly information + var typeName = fullTypeName.Split(',')[0]; + + // Simplify common generic types + typeName = typeName + .Replace("System.Threading.Tasks.Task{", "Task<") + .Replace("System.Collections.Generic.List{", "List<") + .Replace("System.Collections.Generic.Dictionary{", "Dictionary<") + .Replace("System.Nullable{", "Nullable<") + .Replace("System.String", "string") + .Replace("System.Int32", "int") + .Replace("System.Int64", "long") + .Replace("System.Boolean", "bool") + .Replace("System.Byte", "byte") + .Replace("System.Object", "object") + .Replace('{', '<') + .Replace('}', '>'); + + return typeName; +} + +static string NormalizeXmlText(string text) +{ + var lines = text.Split('\n'); + var normalized = new StringBuilder(); + + foreach (var line in lines) + { + var trimmed = line.Trim(); + if (!string.IsNullOrEmpty(trimmed)) + { + _ = normalized.AppendLine(trimmed); + } + } + + return normalized.ToString().TrimEnd(); +} + +var cmdArgs = Environment.GetCommandLineArgs(); +if (cmdArgs.Length > 1 && cmdArgs[1] == "--llms") +{ + var root = FindRepoRoot(); + GenerateLlmsTxt(root); + return; +} + +var specUrl = "https://api.thirdweb.com/openapi.json"; +var repoRoot = FindRepoRoot(); +var outputPath = Path.Combine(repoRoot, "Thirdweb", "Thirdweb.Api", "ThirdwebApi.cs"); + +Console.WriteLine($"Loading OpenAPI from {specUrl}..."); +var document = await OpenApiDocument.FromUrlAsync(specUrl); + +Console.WriteLine("Deduplicating enum values across all schemas (inline + components)..."); + +var visited = new HashSet(); + +void DedupeEnumOnSchema(JsonSchema schema, string? debugPath) +{ + if (schema == null) + { + return; + } + if (!visited.Add(schema)) + { + return; + } + + var s = schema.ActualSchema ?? schema; + + if (s.Enumeration != null && s.Enumeration.Count > 0) + { + var seen = new HashSet(StringComparer.Ordinal); + var newEnum = new List(); + var enumList = s.Enumeration.ToList(); + + for (var i = 0; i < enumList.Count; i++) + { + var v = enumList[i]; + var key = Convert.ToString(v, CultureInfo.InvariantCulture) ?? ""; + if (seen.Add(key)) + { + newEnum.Add(v!); + } + } + + if (newEnum.Count != s.Enumeration.Count) + { + s.Enumeration.Clear(); + foreach (var v in newEnum) + { + s.Enumeration.Add(v); + } + + // Remove x-enumNames to avoid misalignment with deduped values + if (s.ExtensionData != null && s.ExtensionData.ContainsKey("x-enumNames")) + { + _ = s.ExtensionData.Remove("x-enumNames"); + } + + Console.WriteLine($" - Deduped enum at {debugPath ?? ""}: {newEnum.Count} unique values"); + } + } + + // Recurse into nested schemas + foreach (var p in s.Properties) + { + DedupeEnumOnSchema(p.Value, $"{debugPath}/properties/{p.Key}"); + } + + if (s.AdditionalPropertiesSchema != null) + { + DedupeEnumOnSchema(s.AdditionalPropertiesSchema, $"{debugPath}/additionalProperties"); + } + + if (s.Item != null) + { + DedupeEnumOnSchema(s.Item, $"{debugPath}/items"); + } + + foreach (var a in s.AllOf) + { + DedupeEnumOnSchema(a, $"{debugPath}/allOf"); + } + foreach (var o in s.OneOf) + { + DedupeEnumOnSchema(o, $"{debugPath}/oneOf"); + } + foreach (var a in s.AnyOf) + { + DedupeEnumOnSchema(a, $"{debugPath}/anyOf"); + } + if (s.Not != null) + { + DedupeEnumOnSchema(s.Not, $"{debugPath}/not"); + } +} + +// Components +foreach (var kvp in document.Components.Schemas) +{ + DedupeEnumOnSchema(kvp.Value, $"#/components/schemas/{kvp.Key}"); +} + +// Parameters +foreach (var path in document.Paths) +{ + foreach (var opKvp in path.Value) + { + var op = opKvp.Value; + foreach (var prm in op.Parameters) + { + if (prm.Schema != null) + { + DedupeEnumOnSchema(prm.Schema, $"#/paths{path.Key}/{op.OperationId}/parameters/{prm.Name}"); + } + } + // Request body + var rb = op.RequestBody; + if (rb?.Content != null) + { + foreach (var c in rb.Content) + { + if (c.Value.Schema != null) + { + DedupeEnumOnSchema(c.Value.Schema, $"#/paths{path.Key}/{op.OperationId}/requestBody/{c.Key}"); + } + } + } + // Responses + foreach (var resp in op.Responses) + { + if (resp.Value.Content != null) + { + foreach (var c in resp.Value.Content) + { + if (c.Value.Schema != null) + { + DedupeEnumOnSchema(c.Value.Schema, $"#/paths{path.Key}/{op.OperationId}/responses/{resp.Key}/{c.Key}"); + } + } + } + } + } +} + +var settings = new CSharpClientGeneratorSettings +{ + ClassName = "ThirdwebApiClient", + CSharpGeneratorSettings = { Namespace = "Thirdweb.Api", ClassStyle = NJsonSchema.CodeGeneration.CSharp.CSharpClassStyle.Poco }, + GenerateClientClasses = true, + GenerateDtoTypes = true, + GenerateExceptionClasses = true, + ClientClassAccessModifier = "public", + // Use our HttpClient wrapper type + HttpClientType = "ThirdwebHttpClientWrapper", +}; + +Console.WriteLine("Generating C# client code..."); +var generator = new CSharpClientGenerator(document, settings); +var code = generator.GenerateFile(); + +Directory.CreateDirectory(Path.GetDirectoryName(outputPath)!); +await File.WriteAllTextAsync(outputPath, code); +Console.WriteLine($"Wrote generated client to {outputPath}"); + +internal class MemberSignature +{ + public string Kind { get; set; } = ""; + public List? Parameters { get; set; } + public string? ReturnType { get; set; } +} + +internal class ParameterInfo +{ + public string Name { get; set; } = ""; + public string Type { get; set; } = ""; +} diff --git a/Thirdweb.Generator/Thirdweb.Generator.csproj b/Thirdweb.Generator/Thirdweb.Generator.csproj new file mode 100644 index 00000000..6d6375cd --- /dev/null +++ b/Thirdweb.Generator/Thirdweb.Generator.csproj @@ -0,0 +1,12 @@ + + + Exe + net8.0 + enable + enable + + + + + + diff --git a/Thirdweb.Tests/BaseTests.cs b/Thirdweb.Tests/BaseTests.cs index 04a3f830..cc70c5fe 100644 --- a/Thirdweb.Tests/BaseTests.cs +++ b/Thirdweb.Tests/BaseTests.cs @@ -4,23 +4,47 @@ namespace Thirdweb.Tests; public class BaseTests { - protected readonly ITestOutputHelper _output; - protected readonly string? _secretKey; - protected readonly string? _clientIdBundleIdOnly; - protected readonly string? _bundleIdBundleIdOnly; + protected ITestOutputHelper Output { get; } + protected string? SecretKey { get; } + protected string? ClientIdBundleIdOnly { get; } + protected string? BundleIdBundleIdOnly { get; } + + protected ThirdwebClient Client { get; } public BaseTests(ITestOutputHelper output) { DotEnv.Load(); - _output = output; - _secretKey = Environment.GetEnvironmentVariable("THIRDWEB_SECRET_KEY"); - _clientIdBundleIdOnly = Environment.GetEnvironmentVariable("THIRDWEB_CLIENT_ID_BUNDLE_ID_ONLY"); - _bundleIdBundleIdOnly = Environment.GetEnvironmentVariable("THIRDWEB_BUNDLE_ID_BUNDLE_ID_ONLY"); + this.Output = output; + this.SecretKey = Environment.GetEnvironmentVariable("THIRDWEB_SECRET_KEY"); + this.ClientIdBundleIdOnly = Environment.GetEnvironmentVariable("THIRDWEB_CLIENT_ID_BUNDLE_ID_ONLY"); + this.BundleIdBundleIdOnly = Environment.GetEnvironmentVariable("THIRDWEB_BUNDLE_ID_BUNDLE_ID_ONLY"); + + this.Client = ThirdwebClient.Create(secretKey: this.SecretKey); + + this.Output.WriteLine($"Started {this.GetType().FullName}"); } - [Fact] + [Fact(Timeout = 120000)] public void DotEnvTest() { - Assert.NotNull(_secretKey); + Assert.NotNull(this.SecretKey); + } + + public async Task GetGuestAccount() + { + var iaw = await InAppWallet.Create(this.Client, authProvider: AuthProvider.Guest); + if (await iaw.IsConnected()) + { + await iaw.Disconnect(); + } + _ = await iaw.LoginWithGuest(defaultSessionIdOverride: Guid.NewGuid().ToString()); + return iaw; + } + + public async Task GetSmartAccount(int chainId = 421614) + { + var guestAccount = await this.GetGuestAccount(); + var smartAccount = await SmartWallet.Create(personalWallet: guestAccount, chainId: chainId); + return smartAccount; } } diff --git a/Thirdweb.Tests/Thirdweb.Client.Tests.cs b/Thirdweb.Tests/Thirdweb.Client/Thirdweb.Client.Tests.cs similarity index 74% rename from Thirdweb.Tests/Thirdweb.Client.Tests.cs rename to Thirdweb.Tests/Thirdweb.Client/Thirdweb.Client.Tests.cs index e9c27cc5..cc62e8a9 100644 --- a/Thirdweb.Tests/Thirdweb.Client.Tests.cs +++ b/Thirdweb.Tests/Thirdweb.Client/Thirdweb.Client.Tests.cs @@ -1,28 +1,28 @@ -namespace Thirdweb.Tests; +namespace Thirdweb.Tests.Client; public class ClientTests : BaseTests { public ClientTests(ITestOutputHelper output) : base(output) { } - [Fact] + [Fact(Timeout = 120000)] public void NoSecretKeyNoClientId() { - Assert.Throws(() => ThirdwebClient.Create()); + _ = Assert.Throws(() => ThirdwebClient.Create()); } - [Fact] + [Fact(Timeout = 120000)] public void SecretKeyInitialization() { - var client = ThirdwebClient.Create(secretKey: _secretKey); + var client = ThirdwebClient.Create(secretKey: this.SecretKey); Assert.NotNull(client.ClientId); Assert.NotNull(client.SecretKey); Assert.Null(client.BundleId); Assert.Equal(client.ClientId, Utils.ComputeClientIdFromSecretKey(client.SecretKey)); - Assert.Equal(client.SecretKey, _secretKey); + Assert.Equal(client.SecretKey, this.SecretKey); } - [Fact] + [Fact(Timeout = 120000)] public void ClientIdInitialization() { var clientId = "test-client-id"; @@ -33,7 +33,7 @@ public void ClientIdInitialization() Assert.Equal(client.ClientId, clientId); } - [Fact] + [Fact(Timeout = 120000)] public void BundleIdInitialization() { var bundleId = "test-bundle-id"; @@ -41,20 +41,20 @@ public void BundleIdInitialization() Assert.Equal("ClientId or SecretKey must be provided", exception.Message); } - [Fact] + [Fact(Timeout = 120000)] public void ClientIdAndSecretKeyInitialization() { var clientId = "test-client-id"; - var client = ThirdwebClient.Create(clientId: clientId, secretKey: _secretKey); + var client = ThirdwebClient.Create(clientId: clientId, secretKey: this.SecretKey); Assert.NotNull(client.ClientId); Assert.NotNull(client.SecretKey); Assert.Null(client.BundleId); - Assert.NotEqual(client.ClientId, clientId); - Assert.Equal(client.ClientId, Utils.ComputeClientIdFromSecretKey(client.SecretKey)); - Assert.Equal(client.SecretKey, _secretKey); + Assert.Equal(client.ClientId, clientId); + Assert.NotEqual(client.ClientId, Utils.ComputeClientIdFromSecretKey(client.SecretKey)); + Assert.Equal(client.SecretKey, this.SecretKey); } - [Fact] + [Fact(Timeout = 120000)] public void ClientIdAndBundleIdInitialization() { var clientId = "test-client-id"; @@ -67,23 +67,23 @@ public void ClientIdAndBundleIdInitialization() Assert.Equal(client.BundleId, bundleId); } - [Fact] + [Fact(Timeout = 120000)] public void SecretKeyAndBundleIdInitialization() { var bundleId = "test-bundle-id"; - var client = ThirdwebClient.Create(secretKey: _secretKey, bundleId: bundleId); + var client = ThirdwebClient.Create(secretKey: this.SecretKey, bundleId: bundleId); Assert.NotNull(client.SecretKey); Assert.NotNull(client.BundleId); Assert.NotNull(client.ClientId); - Assert.Equal(client.SecretKey, _secretKey); + Assert.Equal(client.SecretKey, this.SecretKey); Assert.Equal(client.BundleId, bundleId); Assert.Equal(client.ClientId, Utils.ComputeClientIdFromSecretKey(client.SecretKey)); } - [Fact] + [Fact(Timeout = 120000)] public void TimeoutOptions() { - var client = ThirdwebClient.Create(secretKey: _secretKey, fetchTimeoutOptions: new TimeoutOptions(storage: 30000, rpc: 30000, other: 30000)); + var client = ThirdwebClient.Create(secretKey: this.SecretKey, fetchTimeoutOptions: new TimeoutOptions(storage: 30000, rpc: 30000, other: 30000)); Assert.NotNull(client.FetchTimeoutOptions); Assert.Equal(30000, client.FetchTimeoutOptions.GetTimeout(TimeoutType.Storage)); Assert.Equal(30000, client.FetchTimeoutOptions.GetTimeout(TimeoutType.Rpc)); @@ -91,10 +91,10 @@ public void TimeoutOptions() Assert.Equal(Constants.DEFAULT_FETCH_TIMEOUT, client.FetchTimeoutOptions.GetTimeout(TimeoutType.Other + 1)); } - [Fact] + [Fact(Timeout = 120000)] public void NoTimeoutOptions() { - var client = ThirdwebClient.Create(secretKey: _secretKey); + var client = ThirdwebClient.Create(secretKey: this.SecretKey); Assert.NotNull(client.FetchTimeoutOptions); Assert.Equal(Constants.DEFAULT_FETCH_TIMEOUT, client.FetchTimeoutOptions.GetTimeout(TimeoutType.Storage)); Assert.Equal(Constants.DEFAULT_FETCH_TIMEOUT, client.FetchTimeoutOptions.GetTimeout(TimeoutType.Rpc)); diff --git a/Thirdweb.Tests/Thirdweb.Contracts.Tests.cs b/Thirdweb.Tests/Thirdweb.Contracts/Thirdweb.Contracts.Tests.cs similarity index 55% rename from Thirdweb.Tests/Thirdweb.Contracts.Tests.cs rename to Thirdweb.Tests/Thirdweb.Contracts/Thirdweb.Contracts.Tests.cs index 9a9e1e0a..a9b6a1a3 100644 --- a/Thirdweb.Tests/Thirdweb.Contracts.Tests.cs +++ b/Thirdweb.Tests/Thirdweb.Contracts/Thirdweb.Contracts.Tests.cs @@ -1,103 +1,154 @@ -using System.Numerics; -using Newtonsoft.Json.Linq; +using System.Numerics; -namespace Thirdweb.Tests; +namespace Thirdweb.Tests.Contracts; public class ContractsTests : BaseTests { public ContractsTests(ITestOutputHelper output) : base(output) { } - [Fact] + [Fact(Timeout = 120000)] public async Task FetchAbi() { - var abi = await ThirdwebContract.FetchAbi(client: ThirdwebClient.Create(secretKey: _secretKey), address: "0x1320Cafa93fb53Ed9068E3272cb270adbBEf149C", chainId: 84532); + var abi = await ThirdwebContract.FetchAbi(client: this.Client, address: "0x1320Cafa93fb53Ed9068E3272cb270adbBEf149C", chainId: 84532); Assert.NotNull(abi); Assert.NotEmpty(abi); } - [Fact] + [Fact(Timeout = 120000)] public async Task InitTest_NullClient() { var exception = await Assert.ThrowsAsync(async () => await ThirdwebContract.Create(null, "0x123", 1, "[]")); Assert.Contains("Client must be provided", exception.Message); } - [Fact] + [Fact(Timeout = 120000)] public async Task InitTest_NullAddress() { - var exception = await Assert.ThrowsAsync(async () => await ThirdwebContract.Create(ThirdwebClient.Create(secretKey: _secretKey), null, 1, "[]")); + var exception = await Assert.ThrowsAsync(async () => await ThirdwebContract.Create(this.Client, null, 1, "[]")); Assert.Contains("Address must be provided", exception.Message); } - [Fact] + [Fact(Timeout = 120000)] public async Task InitTest_ZeroChain() { - var exception = await Assert.ThrowsAsync(async () => await ThirdwebContract.Create(ThirdwebClient.Create(secretKey: _secretKey), "0x123", 0, "[]")); + var exception = await Assert.ThrowsAsync(async () => await ThirdwebContract.Create(this.Client, "0x123", 0, "[]")); Assert.Contains("Chain must be provided", exception.Message); } - [Fact] + [Fact(Timeout = 120000)] public async Task InitTest_NullAbi() { - var res = await ThirdwebContract.Create(ThirdwebClient.Create(secretKey: _secretKey), "0x81ebd23aA79bCcF5AaFb9c9c5B0Db4223c39102e", 421614, null); + var res = await ThirdwebContract.Create(this.Client, "0x81ebd23aA79bCcF5AaFb9c9c5B0Db4223c39102e", 421614, null); Assert.NotNull(res); } - [Fact] + [Fact(Timeout = 120000)] public async Task ReadTest_String() { - var contract = await GetContract(); + var contract = await this.GetContract(); var result = await ThirdwebContract.Read(contract, "name"); Assert.Equal("Kitty DropERC20", result); } - [Fact] + [Fact(Timeout = 120000)] public async Task ReadTest_BigInteger() { - var contract = await GetContract(); + var contract = await this.GetContract(); var result = await ThirdwebContract.Read(contract, "decimals"); Assert.Equal(18, result); } [Nethereum.ABI.FunctionEncoding.Attributes.FunctionOutput] - private class GetPlatformFeeInfoOutputDTO : Nethereum.ABI.FunctionEncoding.Attributes.IFunctionOutputDTO + private sealed class GetPlatformFeeInfoOutputDTO : Nethereum.ABI.FunctionEncoding.Attributes.IFunctionOutputDTO { [Nethereum.ABI.FunctionEncoding.Attributes.Parameter("address", "", 1)] - public virtual required string ReturnValue1 { get; set; } + public required string ReturnValue1 { get; set; } [Nethereum.ABI.FunctionEncoding.Attributes.Parameter("uint16", "", 2)] - public virtual required ushort ReturnValue2 { get; set; } + public required ushort ReturnValue2 { get; set; } } - [Fact] + [Fact(Timeout = 120000)] public async Task ReadTest_Tuple() { - var contract = await GetContract(); + var contract = await this.GetContract(); var result = await ThirdwebContract.Read(contract, "getPlatformFeeInfo"); Assert.Equal("0xDaaBDaaC8073A7dAbdC96F6909E8476ab4001B34", result.ReturnValue1); Assert.Equal(0, result.ReturnValue2); } - private class AllowlistProof + [Fact(Timeout = 120000)] + public async Task ReadTest_4Bytes() { - public List Proof { get; set; } = new(); + var contract = await this.GetContract(); + var result = await ThirdwebContract.Read(contract, "0x06fdde03"); + Assert.Equal("Kitty DropERC20", result); + } + + [Fact(Timeout = 120000)] + public async Task ReadTest_FullSig() + { + var contract = await this.GetContract(); + var result = await ThirdwebContract.Read(contract, "function name() view returns (string)"); + Assert.Equal("Kitty DropERC20", result); + } + + [Fact(Timeout = 120000)] + public async Task ReadTest_PartialSig() + { + var contract = await this.GetContract(); + var result = await ThirdwebContract.Read(contract, "name()"); + Assert.Equal("Kitty DropERC20", result); + } + + [Fact(Timeout = 120000)] + public async Task PrepareTest_NoSig() + { + var contract = await this.GetContract(); + var exception = await Assert.ThrowsAsync(async () => await ThirdwebContract.Prepare(null, contract, "sup", 0)); + Assert.Contains("Method signature not found in contract ABI.", exception.Message); + } + + [Fact(Timeout = 120000)] + public async Task ReadTest_TupleIntoArray() + { + var contract = await ThirdwebContract.Create(this.Client, "0xEb4AAB0253a50918a2Cbb7ADBaab78Ad19C07Bb1", 421614); + var result = await contract.Read>("getReserves"); + Assert.NotNull(result); + Assert.NotEmpty(result); + Assert.True(result.Count == 3); + } + + [Fact(Timeout = 120000)] + public async Task ReadTest_TupleIntoList() + { + var contract = await ThirdwebContract.Create(this.Client, "0xEb4AAB0253a50918a2Cbb7ADBaab78Ad19C07Bb1", 421614); + var result = await contract.Read>("getReserves"); + Assert.NotNull(result); + Assert.NotEmpty(result); + Assert.True(result.Count == 3); + } + + private sealed class AllowlistProof + { + public List Proof { get; set; } = new List(); public BigInteger QuantityLimitPerWallet { get; set; } = BigInteger.Zero; public BigInteger PricePerToken { get; set; } = BigInteger.Zero; public string Currency { get; set; } = Constants.ADDRESS_ZERO; } - [Fact] + [Fact(Timeout = 120000)] public async Task WriteTest_SmartAccount() { - var contract = await GetContract(); - var smartAccount = await GetAccount(); + var contract = await this.GetContract(); + var smartAccount = await this.GetAccount(); var receiver = await smartAccount.GetAddress(); var quantity = BigInteger.One; var currency = Constants.NATIVE_TOKEN_ADDRESS; var pricePerToken = BigInteger.Zero; - var allowlistProof = new object[] { new byte[] { }, BigInteger.Zero, BigInteger.Zero, Constants.ADDRESS_ZERO }; - var data = new byte[] { }; + var allowlistProof = new object[] { Array.Empty(), BigInteger.Zero, BigInteger.Zero, Constants.ADDRESS_ZERO }; + var data = Array.Empty(); var result = await ThirdwebContract.Write(smartAccount, contract, "claim", 0, receiver, quantity, currency, pricePerToken, allowlistProof, data); Assert.NotNull(result); var receipt = await ThirdwebTransaction.WaitForTransactionReceipt(contract.Client, contract.Chain, result.TransactionHash); @@ -105,17 +156,46 @@ public async Task WriteTest_SmartAccount() Assert.Equal(result.TransactionHash, receipt.TransactionHash); } - [Fact] + [Fact(Timeout = 120000)] + public async Task WriteTest_SmartAccount_FullSig() + { + var contract = await this.GetContract(); + var smartAccount = await this.GetAccount(); + var receiver = await smartAccount.GetAddress(); + var quantity = BigInteger.One; + var currency = Constants.NATIVE_TOKEN_ADDRESS; + var pricePerToken = BigInteger.Zero; + var allowlistProof = new object[] { Array.Empty(), BigInteger.Zero, BigInteger.Zero, Constants.ADDRESS_ZERO }; + var data = Array.Empty(); + var result = await ThirdwebContract.Write( + smartAccount, + contract, + "claim(address, uint256, address, uint256, (bytes32[], uint256, uint256, address), bytes)", + 0, + receiver, + quantity, + currency, + pricePerToken, + allowlistProof, + data + ); + Assert.NotNull(result); + var receipt = await ThirdwebTransaction.WaitForTransactionReceipt(contract.Client, contract.Chain, result.TransactionHash); + Assert.NotNull(receipt); + Assert.Equal(result.TransactionHash, receipt.TransactionHash); + } + + [Fact(Timeout = 120000)] public async Task WriteTest_PrivateKeyAccount() { - var contract = await GetContract(); - var privateKeyAccount = await PrivateKeyWallet.Generate(contract.Client); + var contract = await this.GetContract(); + var privateKeyAccount = await this.GetGuestAccount(); var receiver = await privateKeyAccount.GetAddress(); var quantity = BigInteger.One; var currency = Constants.NATIVE_TOKEN_ADDRESS; var pricePerToken = BigInteger.Zero; - var allowlistProof = new object[] { new byte[] { }, BigInteger.Zero, BigInteger.Zero, Constants.ADDRESS_ZERO }; - var data = new byte[] { }; + var allowlistProof = new object[] { Array.Empty(), BigInteger.Zero, BigInteger.Zero, Constants.ADDRESS_ZERO }; + var data = Array.Empty(); try { var res = await ThirdwebContract.Write(privateKeyAccount, contract, "claim", 0, receiver, quantity, currency, pricePerToken, allowlistProof, data); @@ -129,30 +209,16 @@ public async Task WriteTest_PrivateKeyAccount() } } - [Fact] + [Fact(Timeout = 120000)] public async Task SignatureMint_Generate() { - var client = ThirdwebClient.Create(secretKey: _secretKey); - var signer = await PrivateKeyWallet.Generate(client); + var signer = await this.GetGuestAccount(); var randomDomain = "Test"; var randomVersion = "1.0.0"; var randomChainId = 421614; var randomContractAddress = "0xD04F98C88cE1054c90022EE34d566B9237a1203C"; - // GenerateSignature_MinimalForwarder - var forwardRequest = new Forwarder_ForwardRequest - { - From = "0x123", - To = "0x456", - Value = BigInteger.Zero, - Gas = BigInteger.Zero, - Nonce = BigInteger.Zero, - Data = "0x" - }; - var signature = await EIP712.GenerateSignature_MinimalForwarder(randomDomain, randomVersion, randomChainId, randomContractAddress, forwardRequest, signer); - Assert.NotNull(signature); - Assert.StartsWith("0x", signature); // GenerateSignature_TokenERC20 var mintRequest20 = new TokenERC20_MintRequest { @@ -163,7 +229,7 @@ public async Task SignatureMint_Generate() Currency = Constants.ADDRESS_ZERO, ValidityEndTimestamp = 0, ValidityStartTimestamp = Utils.GetUnixTimeStampIn10Years(), - Uid = new byte[] { 0x01 } + Uid = new byte[] { 0x01 }, }; var signature20 = await EIP712.GenerateSignature_TokenERC20(randomDomain, randomVersion, randomChainId, randomContractAddress, mintRequest20, signer); Assert.NotNull(signature20); @@ -181,7 +247,7 @@ public async Task SignatureMint_Generate() Currency = Constants.ADDRESS_ZERO, ValidityEndTimestamp = 0, ValidityStartTimestamp = Utils.GetUnixTimeStampIn10Years(), - Uid = new byte[] { 0x01 } + Uid = new byte[] { 0x01 }, }; var signature721 = await EIP712.GenerateSignature_TokenERC721(randomDomain, randomVersion, randomChainId, randomContractAddress, mintRequest721, signer); Assert.NotNull(signature721); @@ -201,7 +267,7 @@ public async Task SignatureMint_Generate() Currency = Constants.ADDRESS_ZERO, ValidityEndTimestamp = 0, ValidityStartTimestamp = Utils.GetUnixTimeStampIn10Years(), - Uid = new byte[] { 0x01 } + Uid = new byte[] { 0x01 }, }; var signature1155 = await EIP712.GenerateSignature_TokenERC1155(randomDomain, randomVersion, randomChainId, randomContractAddress, mintRequest1155, signer); Assert.NotNull(signature1155); @@ -210,16 +276,15 @@ public async Task SignatureMint_Generate() private async Task GetAccount() { - var client = ThirdwebClient.Create(secretKey: _secretKey); - var privateKeyAccount = await PrivateKeyWallet.Generate(client); + var privateKeyAccount = await this.GetGuestAccount(); var smartAccount = await SmartWallet.Create(personalWallet: privateKeyAccount, factoryAddress: "0xbf1C9aA4B1A085f7DA890a44E82B0A1289A40052", gasless: true, chainId: 421614); return smartAccount; } private async Task GetContract() { - var client = ThirdwebClient.Create(secretKey: _secretKey); - var contract = await ThirdwebContract.Create(client: client, address: "0xEBB8a39D865465F289fa349A67B3391d8f910da9", chain: 421614); + var client = this.Client; + var contract = await ThirdwebContract.Create(client: client, address: "0xEBB8a39D865465F289fa349A67B3391d8f910da9", chain: 421614); // DropERC20 return contract; } } diff --git a/Thirdweb.Tests/Thirdweb.Extensions.Tests.cs b/Thirdweb.Tests/Thirdweb.Extensions.Tests.cs deleted file mode 100644 index b5867014..00000000 --- a/Thirdweb.Tests/Thirdweb.Extensions.Tests.cs +++ /dev/null @@ -1,1504 +0,0 @@ -using System.Numerics; -using Nethereum.Util; - -namespace Thirdweb.Tests -{ - public class ExtensionsTests : BaseTests - { - private readonly string _tokenErc20ContractAddress = "0x81ebd23aA79bCcF5AaFb9c9c5B0Db4223c39102e"; - private readonly string _tokenErc721ContractAddress = "0x345E7B4CCA26725197f1Bed802A05691D8EF7770"; - private readonly string _tokenErc1155ContractAddress = "0x83b5851134DAA0E28d855E7fBbdB6B412b46d26B"; - private readonly string _dropErc20ContractAddress = "0xEBB8a39D865465F289fa349A67B3391d8f910da9"; - private readonly string _dropErc721ContractAddress = "0xD811CB13169C175b64bf8897e2Fd6a69C6343f5C"; - private readonly string _dropErc1155ContractAddress = "0x6A7a26c9a595E6893C255C9dF0b593e77518e0c3"; - - private readonly BigInteger _chainId = 421614; - private readonly ThirdwebClient _client; - - public ExtensionsTests(ITestOutputHelper output) - : base(output) - { - _client = ThirdwebClient.Create(secretKey: _secretKey); - } - - private async Task GetSmartWallet() - { - var privateKeyWallet = await PrivateKeyWallet.Generate(_client); - return await SmartWallet.Create(personalWallet: privateKeyWallet, chainId: 421614); - } - - private async Task GetTokenERC20Contract() - { - return await ThirdwebContract.Create(_client, _tokenErc20ContractAddress, _chainId); - } - - private async Task GetTokenERC721Contract() - { - return await ThirdwebContract.Create(_client, _tokenErc721ContractAddress, _chainId); - } - - private async Task GetTokenERC1155Contract() - { - return await ThirdwebContract.Create(_client, _tokenErc1155ContractAddress, _chainId); - } - - private async Task GetDrop20Contract() - { - return await ThirdwebContract.Create(_client, _dropErc20ContractAddress, _chainId); - } - - private async Task GetDrop721Contract() - { - return await ThirdwebContract.Create(_client, _dropErc721ContractAddress, _chainId); - } - - private async Task GetDrop1155Contract() - { - return await ThirdwebContract.Create(_client, _dropErc1155ContractAddress, _chainId); - } - - #region Common - - [Fact] - public async Task NullChecks() - { - var client = ThirdwebClient.Create(secretKey: _secretKey); - var contract = await ThirdwebContract.Create(client, _tokenErc20ContractAddress, _chainId); - var wallet = await GetSmartWallet(); - var testNFT = new NFT { Metadata = new NFTMetadata { Image = "image_url" } }; - var validAddress = "0x0000000000000000000000000000000000000000"; - - // GetMetadata - _ = await Assert.ThrowsAsync(() => ThirdwebExtensions.GetMetadata(null)); - - // GetNFTImageBytes - _ = await Assert.ThrowsAsync(() => ThirdwebExtensions.GetNFTImageBytes(testNFT, null)); - - // GetDefaultRoyaltyInfo - _ = await Assert.ThrowsAsync(() => ThirdwebExtensions.GetDefaultRoyaltyInfo(null)); - - // GetPrimarySaleRecipient - _ = await Assert.ThrowsAsync(() => ThirdwebExtensions.GetPrimarySaleRecipient(null)); - - // GetBalanceRaw - _ = await Assert.ThrowsAsync(() => ThirdwebExtensions.GetBalanceRaw(null, _chainId, validAddress)); - _ = await Assert.ThrowsAsync(() => ThirdwebExtensions.GetBalanceRaw(client, 0, validAddress)); - _ = await Assert.ThrowsAsync(() => ThirdwebExtensions.GetBalanceRaw(client, _chainId, null)); - - // GetBalance (contract) - _ = await Assert.ThrowsAsync(() => ThirdwebExtensions.GetBalance(null)); - - // GetBalance (wallet) - _ = await Assert.ThrowsAsync(() => ThirdwebExtensions.GetBalance(null, _chainId)); - _ = await Assert.ThrowsAsync(() => ThirdwebExtensions.GetBalance(wallet, 0)); - - // Transfer - _ = await Assert.ThrowsAsync(() => ThirdwebExtensions.Transfer(null, _chainId, validAddress, 0)); - _ = await Assert.ThrowsAsync(() => ThirdwebExtensions.Transfer(wallet, 0, validAddress, 0)); - _ = await Assert.ThrowsAsync(() => ThirdwebExtensions.Transfer(wallet, _chainId, null, 0)); - _ = await Assert.ThrowsAsync(() => ThirdwebExtensions.Transfer(wallet, _chainId, validAddress, -1)); - } - - [Fact] - public async Task GetMetadata() - { - var contract = await GetTokenERC20Contract(); - var metadata = await contract.GetMetadata(); - Assert.NotNull(metadata); - Assert.NotNull(metadata.Name); - Assert.NotEmpty(metadata.Name); - Assert.NotNull(metadata.Symbol); - Assert.NotEmpty(metadata.Symbol); - Assert.NotNull(metadata.Description); - Assert.NotEmpty(metadata.Description); - Assert.NotNull(metadata.Image); - Assert.NotEmpty(metadata.Image); - } - - [Fact] - public async Task GetNFTBytes_721() - { - var contract = await GetDrop721Contract(); - var nft = await contract.ERC721_GetNFT(0); - var bytes = await nft.GetNFTImageBytes(contract.Client); - Assert.NotNull(bytes); - Assert.NotEmpty(bytes); - } - - [Fact] - public async Task GetNFTBytes_1155() - { - var contract = await GetDrop1155Contract(); - var nft = await contract.ERC1155_GetNFT(0); - var bytes = await nft.GetNFTImageBytes(contract.Client); - Assert.NotNull(bytes); - Assert.NotEmpty(bytes); - } - - [Fact] - public async Task GetPrimarySaleRecipient() - { - var contract = await GetTokenERC20Contract(); - var primarySaleRecipient = await contract.GetPrimarySaleRecipient(); - Assert.NotNull(primarySaleRecipient); - Assert.NotEmpty(primarySaleRecipient); - } - - [Fact] - public async Task GetBalanceRaw() - { - var address = "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"; // vitalik.eth - var chainId = BigInteger.One; - var balance = await ThirdwebExtensions.GetBalanceRaw(_client, chainId, address); - Assert.True(balance >= 0); - } - - [Fact] - public async Task GetBalanceRaw_WithERC20() - { - var address = "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"; // vitalik.eth - var chainId = _chainId; - var contractAddress = _tokenErc20ContractAddress; - var balance = await ThirdwebExtensions.GetBalanceRaw(_client, chainId, address, contractAddress); - Assert.True(balance >= 0); - } - - [Fact] - public async Task GetBalance_Contract() - { - var contract = await GetTokenERC20Contract(); - var balance = await contract.GetBalance(); - Assert.True(balance >= 0); - } - - [Fact] - public async Task GetBalance_Contract_WithERC20() - { - var contract = await GetTokenERC20Contract(); - var balance = await contract.GetBalance(_tokenErc20ContractAddress); - Assert.True(balance >= 0); - } - - [Fact] - public async Task GetBalance_Wallet() - { - var client = ThirdwebClient.Create(secretKey: _secretKey); - var wallet = await GetSmartWallet(); - var balance = await wallet.GetBalance(_chainId); - Assert.True(balance >= 0); - } - - [Fact] - public async Task GetBalance_Wallet_WithERC20() - { - var client = ThirdwebClient.Create(secretKey: _secretKey); - var wallet = await GetSmartWallet(); - var balance = await wallet.GetBalance(_chainId, _tokenErc20ContractAddress); - Assert.True(balance >= 0); - } - - [Fact] - public async Task Transfer() - { - var client = ThirdwebClient.Create(secretKey: _secretKey); - var wallet = await GetSmartWallet(); - var toAddress = await wallet.GetAddress(); - var receipt = await wallet.Transfer(_chainId, toAddress, BigInteger.Zero); - Assert.NotNull(receipt); - Assert.True(receipt.TransactionHash.Length == 66); - } - - #endregion - - - #region ERC20 - - [Fact] - public async Task ERC20_NullChecks() - { - var client = ThirdwebClient.Create(secretKey: _secretKey); - var contract = await ThirdwebContract.Create(client, _tokenErc20ContractAddress, _chainId); - var wallet = await GetSmartWallet(); - var validAddress = "0x0000000000000000000000000000000000000000"; - - // ERC20_BalanceOf - _ = await Assert.ThrowsAsync(async () => await contract.ERC20_BalanceOf(null)); - _ = await Assert.ThrowsAsync(async () => await contract.ERC20_BalanceOf(string.Empty)); - - // ERC20_Allowance - _ = await Assert.ThrowsAsync(async () => await contract.ERC20_Allowance(null, null)); - _ = await Assert.ThrowsAsync(async () => await contract.ERC20_Allowance(string.Empty, null)); - _ = await Assert.ThrowsAsync(async () => await contract.ERC20_Allowance(null, string.Empty)); - _ = await Assert.ThrowsAsync(async () => await contract.ERC20_Allowance(validAddress, null)); - _ = await Assert.ThrowsAsync(async () => await contract.ERC20_Allowance(null, validAddress)); - - // ERC20_Approve - _ = await Assert.ThrowsAsync(async () => await contract.ERC20_Approve(null, null, BigInteger.Zero)); - _ = await Assert.ThrowsAsync(async () => await contract.ERC20_Approve(wallet, null, BigInteger.Zero)); - _ = await Assert.ThrowsAsync(async () => await contract.ERC20_Approve(wallet, string.Empty, BigInteger.Zero)); - - // ERC20_Transfer - _ = await Assert.ThrowsAsync(async () => await contract.ERC20_Transfer(null, null, BigInteger.Zero)); - _ = await Assert.ThrowsAsync(async () => await contract.ERC20_Transfer(wallet, null, BigInteger.Zero)); - _ = await Assert.ThrowsAsync(async () => await contract.ERC20_Transfer(wallet, string.Empty, BigInteger.Zero)); - - // ERC20_TransferFrom - _ = await Assert.ThrowsAsync(async () => await contract.ERC20_TransferFrom(null, null, null, BigInteger.Zero)); - _ = await Assert.ThrowsAsync(async () => await contract.ERC20_TransferFrom(wallet, null, null, BigInteger.Zero)); - _ = await Assert.ThrowsAsync(async () => await contract.ERC20_TransferFrom(wallet, string.Empty, null, BigInteger.Zero)); - _ = await Assert.ThrowsAsync(async () => await contract.ERC20_TransferFrom(wallet, validAddress, null, BigInteger.Zero)); - _ = await Assert.ThrowsAsync(async () => await contract.ERC20_TransferFrom(wallet, validAddress, string.Empty, BigInteger.Zero)); - - // Null wallet checks - wallet = null; - - _ = await Assert.ThrowsAsync(async () => await contract.ERC20_Approve(wallet, validAddress, BigInteger.Zero)); - _ = await Assert.ThrowsAsync(async () => await contract.ERC20_Transfer(wallet, validAddress, BigInteger.Zero)); - _ = await Assert.ThrowsAsync(async () => await contract.ERC20_TransferFrom(wallet, validAddress, validAddress, BigInteger.Zero)); - - // Null contract checks - contract = null; - - _ = await Assert.ThrowsAsync(async () => await contract.ERC20_BalanceOf(validAddress)); - _ = await Assert.ThrowsAsync(async () => await contract.ERC20_TotalSupply()); - _ = await Assert.ThrowsAsync(async () => await contract.ERC20_Decimals()); - _ = await Assert.ThrowsAsync(async () => await contract.ERC20_Symbol()); - _ = await Assert.ThrowsAsync(async () => await contract.ERC20_Name()); - _ = await Assert.ThrowsAsync(async () => await contract.ERC20_Allowance(validAddress, validAddress)); - _ = await Assert.ThrowsAsync(async () => await contract.ERC20_Approve(wallet, validAddress, BigInteger.Zero)); - _ = await Assert.ThrowsAsync(async () => await contract.ERC20_Transfer(wallet, validAddress, BigInteger.Zero)); - _ = await Assert.ThrowsAsync(async () => await contract.ERC20_TransferFrom(wallet, validAddress, validAddress, BigInteger.Zero)); - } - - [Fact] - public async Task ERC20_BalanceOf() - { - var contract = await GetTokenERC20Contract(); - var ownerAddress = Constants.ADDRESS_ZERO; - var balance = await contract.ERC20_BalanceOf(ownerAddress); - Assert.True(balance >= 0); - } - - [Fact] - public async Task ERC20_TotalSupply() - { - var contract = await GetTokenERC20Contract(); - var totalSupply = await contract.ERC20_TotalSupply(); - Assert.True(totalSupply > 0); - } - - [Fact] - public async Task ERC20_Decimals() - { - var contract = await GetTokenERC20Contract(); - var decimals = await contract.ERC20_Decimals(); - Assert.InRange(decimals, 0, 18); - } - - [Fact] - public async Task ERC20_Symbol() - { - var contract = await GetTokenERC20Contract(); - var symbol = await contract.ERC20_Symbol(); - Assert.False(string.IsNullOrEmpty(symbol)); - } - - [Fact] - public async Task ERC20_Name() - { - var contract = await GetTokenERC20Contract(); - var name = await contract.ERC20_Name(); - Assert.False(string.IsNullOrEmpty(name)); - } - - [Fact] - public async Task ERC20_Allowance() - { - var contract = await GetTokenERC20Contract(); - var ownerAddress = Constants.ADDRESS_ZERO; - var spenderAddress = contract.Address; - var allowance = await contract.ERC20_Allowance(ownerAddress, spenderAddress); - Assert.True(allowance >= 0); - } - - [Fact] - public async Task ERC20_Approve() - { - var contract = await GetTokenERC20Contract(); - var wallet = await GetSmartWallet(); - var spenderAddress = contract.Address; - var amount = BigInteger.Parse("1000000000000000000"); - var receipt = await contract.ERC20_Approve(wallet, spenderAddress, amount); - Assert.True(receipt.TransactionHash.Length == 66); - } - - #endregion - - #region ERC721 - - [Fact] - public async Task ERC721_NullChecks() - { - var client = ThirdwebClient.Create(secretKey: _secretKey); - var contract = await ThirdwebContract.Create(client, _tokenErc721ContractAddress, _chainId); - var wallet = await GetSmartWallet(); - var validAddress = "0x0000000000000000000000000000000000000000"; - - // ERC721_BalanceOf - _ = await Assert.ThrowsAsync(async () => await contract.ERC721_BalanceOf(null)); - _ = await Assert.ThrowsAsync(async () => await contract.ERC721_BalanceOf(string.Empty)); - - // ERC721_OwnerOf - _ = await Assert.ThrowsAsync(async () => await contract.ERC721_OwnerOf(BigInteger.MinusOne)); - - // ERC721_TokenURI - _ = await Assert.ThrowsAsync(async () => await contract.ERC721_TokenURI(BigInteger.MinusOne)); - - // ERC721_Approve - _ = await Assert.ThrowsAsync(async () => await contract.ERC721_Approve(null, null, BigInteger.Zero)); - _ = await Assert.ThrowsAsync(async () => await contract.ERC721_Approve(wallet, null, BigInteger.Zero)); - _ = await Assert.ThrowsAsync(async () => await contract.ERC721_Approve(wallet, string.Empty, BigInteger.Zero)); - - // ERC721_GetApproved - _ = await Assert.ThrowsAsync(async () => await contract.ERC721_GetApproved(BigInteger.MinusOne)); - - // ERC721_IsApprovedForAll - _ = await Assert.ThrowsAsync(async () => await contract.ERC721_IsApprovedForAll(null, null)); - _ = await Assert.ThrowsAsync(async () => await contract.ERC721_IsApprovedForAll(string.Empty, null)); - _ = await Assert.ThrowsAsync(async () => await contract.ERC721_IsApprovedForAll(validAddress, null)); - _ = await Assert.ThrowsAsync(async () => await contract.ERC721_IsApprovedForAll(validAddress, string.Empty)); - - // ERC721_SetApprovalForAll - _ = await Assert.ThrowsAsync(async () => await contract.ERC721_SetApprovalForAll(null, null, false)); - _ = await Assert.ThrowsAsync(async () => await contract.ERC721_SetApprovalForAll(wallet, null, false)); - _ = await Assert.ThrowsAsync(async () => await contract.ERC721_SetApprovalForAll(wallet, string.Empty, false)); - - // ERC721_TransferFrom - _ = await Assert.ThrowsAsync(async () => await contract.ERC721_TransferFrom(null, null, null, BigInteger.Zero)); - _ = await Assert.ThrowsAsync(async () => await contract.ERC721_TransferFrom(wallet, null, null, BigInteger.Zero)); - _ = await Assert.ThrowsAsync(async () => await contract.ERC721_TransferFrom(wallet, string.Empty, null, BigInteger.Zero)); - _ = await Assert.ThrowsAsync(async () => await contract.ERC721_TransferFrom(wallet, validAddress, null, BigInteger.Zero)); - _ = await Assert.ThrowsAsync(async () => await contract.ERC721_TransferFrom(wallet, validAddress, string.Empty, BigInteger.Zero)); - - // ERC721_SafeTransferFrom - _ = await Assert.ThrowsAsync(async () => await contract.ERC721_SafeTransferFrom(null, null, null, BigInteger.Zero)); - _ = await Assert.ThrowsAsync(async () => await contract.ERC721_SafeTransferFrom(wallet, null, null, BigInteger.Zero)); - _ = await Assert.ThrowsAsync(async () => await contract.ERC721_SafeTransferFrom(wallet, string.Empty, null, BigInteger.Zero)); - _ = await Assert.ThrowsAsync(async () => await contract.ERC721_SafeTransferFrom(wallet, validAddress, null, BigInteger.Zero)); - _ = await Assert.ThrowsAsync(async () => await contract.ERC721_SafeTransferFrom(wallet, validAddress, string.Empty, BigInteger.Zero)); - - // ERC721_TokenOfOwnerByIndex - _ = await Assert.ThrowsAsync(async () => await contract.ERC721_TokenOfOwnerByIndex(null, BigInteger.Zero)); - _ = await Assert.ThrowsAsync(async () => await contract.ERC721_TokenOfOwnerByIndex(string.Empty, BigInteger.Zero)); - - // Null wallet checks - wallet = null; - - _ = await Assert.ThrowsAsync(async () => await contract.ERC721_Approve(wallet, validAddress, BigInteger.Zero)); - _ = await Assert.ThrowsAsync(async () => await contract.ERC721_SetApprovalForAll(wallet, validAddress, false)); - _ = await Assert.ThrowsAsync(async () => await contract.ERC721_TransferFrom(wallet, validAddress, validAddress, BigInteger.Zero)); - _ = await Assert.ThrowsAsync(async () => await contract.ERC721_SafeTransferFrom(wallet, validAddress, validAddress, BigInteger.Zero)); - - // Null contract checks - contract = null; - - _ = await Assert.ThrowsAsync(async () => await contract.ERC721_BalanceOf(validAddress)); - _ = await Assert.ThrowsAsync(async () => await contract.ERC721_OwnerOf(BigInteger.Zero)); - _ = await Assert.ThrowsAsync(async () => await contract.ERC721_Name()); - _ = await Assert.ThrowsAsync(async () => await contract.ERC721_Symbol()); - _ = await Assert.ThrowsAsync(async () => await contract.ERC721_TokenURI(BigInteger.Zero)); - _ = await Assert.ThrowsAsync(async () => await contract.ERC721_GetApproved(BigInteger.Zero)); - _ = await Assert.ThrowsAsync(async () => await contract.ERC721_IsApprovedForAll(validAddress, validAddress)); - _ = await Assert.ThrowsAsync(async () => await contract.ERC721_SetApprovalForAll(wallet, validAddress, false)); - _ = await Assert.ThrowsAsync(async () => await contract.ERC721_TransferFrom(wallet, validAddress, validAddress, BigInteger.Zero)); - _ = await Assert.ThrowsAsync(async () => await contract.ERC721_SafeTransferFrom(wallet, validAddress, validAddress, BigInteger.Zero)); - _ = await Assert.ThrowsAsync(async () => await contract.ERC721_Approve(wallet, validAddress, BigInteger.Zero)); - _ = await Assert.ThrowsAsync(async () => await contract.ERC721_TokenOfOwnerByIndex(validAddress, BigInteger.Zero)); - } - - [Fact] - public async Task ERC721_BalanceOf() - { - var contract = await GetTokenERC721Contract(); - var wallet = await GetSmartWallet(); - var ownerAddress = await wallet.GetAddress(); - var balance = await contract.ERC721_BalanceOf(ownerAddress); - Assert.True(balance >= 0); - } - - [Fact] - public async Task ERC721_OwnerOf() - { - var contract = await GetTokenERC721Contract(); - var tokenId = BigInteger.Parse("1"); - var owner = await contract.ERC721_OwnerOf(tokenId); - Assert.False(string.IsNullOrEmpty(owner)); - } - - [Fact] - public async Task ERC721_Name() - { - var contract = await GetTokenERC721Contract(); - var name = await contract.ERC721_Name(); - Assert.False(string.IsNullOrEmpty(name)); - } - - [Fact] - public async Task ERC721_Symbol() - { - var contract = await GetTokenERC721Contract(); - var symbol = await contract.ERC721_Symbol(); - Assert.False(string.IsNullOrEmpty(symbol)); - } - - [Fact] - public async Task ERC721_TokenURI() - { - var contract = await GetTokenERC721Contract(); - var tokenId = BigInteger.Parse("1"); - var uri = await contract.ERC721_TokenURI(tokenId); - Assert.False(string.IsNullOrEmpty(uri)); - } - - [Fact] - public async Task ERC721_GetApproved() - { - var contract = await GetTokenERC721Contract(); - var tokenId = BigInteger.Parse("1"); - var approved = await contract.ERC721_GetApproved(tokenId); - Assert.False(string.IsNullOrEmpty(approved)); - } - - [Fact] - public async Task ERC721_IsApprovedForAll() - { - var contract = await GetTokenERC721Contract(); - var ownerAddress = Constants.ADDRESS_ZERO; - var operatorAddress = contract.Address; - var isApproved = await contract.ERC721_IsApprovedForAll(ownerAddress, operatorAddress); - Assert.True(isApproved || !isApproved); - } - - [Fact] - public async Task ERC721_TotalSupply() - { - var contract = await GetTokenERC721Contract(); - var totalSupply = await contract.ERC721_TotalSupply(); - Assert.True(totalSupply >= 0); - } - - [Fact] - public async Task ERC721_TokenOfOwnerByIndex() - { - var contract = await GetTokenERC721Contract(); - var ownerAddress = "0xE33653ce510Ee767d8824b5EcDeD27125D49889D"; - var index = BigInteger.Zero; - var tokenId = await contract.ERC721_TokenOfOwnerByIndex(ownerAddress, index); - Assert.True(tokenId >= 0); - } - - [Fact] - public async Task ERC721_SetApprovalForAll() - { - var contract = await GetTokenERC721Contract(); - var wallet = await GetSmartWallet(); - var operatorAddress = contract.Address; - var approved = true; - var receipt = await contract.ERC721_SetApprovalForAll(wallet, operatorAddress, approved); - Assert.True(receipt.TransactionHash.Length == 66); - } - - #endregion - - #region ERC1155 - - [Fact] - public async Task ERC1155_NullChecks() - { - var client = ThirdwebClient.Create(secretKey: _secretKey); - var contract = await ThirdwebContract.Create(client, _tokenErc1155ContractAddress, _chainId); - var wallet = await GetSmartWallet(); - var validAddress = "0x0000000000000000000000000000000000000000"; - var validTokenId = BigInteger.One; - var validAmount = BigInteger.One; - var validData = new byte[] { }; - - // ERC1155_BalanceOf - _ = await Assert.ThrowsAsync(async () => await contract.ERC1155_BalanceOf(null, validTokenId)); - _ = await Assert.ThrowsAsync(async () => await contract.ERC1155_BalanceOf(string.Empty, validTokenId)); - _ = await Assert.ThrowsAsync(async () => await contract.ERC1155_BalanceOf(validAddress, BigInteger.MinusOne)); - - // ERC1155_BalanceOfBatch - _ = await Assert.ThrowsAsync(async () => await contract.ERC1155_BalanceOfBatch(null, new BigInteger[] { validTokenId })); - _ = await Assert.ThrowsAsync(async () => await contract.ERC1155_BalanceOfBatch(new string[] { validAddress }, null)); - - // ERC1155_SetApprovalForAll - _ = await Assert.ThrowsAsync(async () => await contract.ERC1155_SetApprovalForAll(null, null, false)); - _ = await Assert.ThrowsAsync(async () => await contract.ERC1155_SetApprovalForAll(wallet, null, false)); - _ = await Assert.ThrowsAsync(async () => await contract.ERC1155_SetApprovalForAll(wallet, string.Empty, false)); - - // ERC1155_IsApprovedForAll - _ = await Assert.ThrowsAsync(async () => await contract.ERC1155_IsApprovedForAll(null, null)); - _ = await Assert.ThrowsAsync(async () => await contract.ERC1155_IsApprovedForAll(string.Empty, null)); - _ = await Assert.ThrowsAsync(async () => await contract.ERC1155_IsApprovedForAll(validAddress, null)); - _ = await Assert.ThrowsAsync(async () => await contract.ERC1155_IsApprovedForAll(validAddress, string.Empty)); - - // ERC1155_SafeTransferFrom - _ = await Assert.ThrowsAsync(async () => await contract.ERC1155_SafeTransferFrom(null, null, null, validTokenId, validAmount, validData)); - _ = await Assert.ThrowsAsync(async () => await contract.ERC1155_SafeTransferFrom(wallet, null, null, validTokenId, validAmount, validData)); - _ = await Assert.ThrowsAsync(async () => await contract.ERC1155_SafeTransferFrom(wallet, string.Empty, null, validTokenId, validAmount, validData)); - _ = await Assert.ThrowsAsync(async () => await contract.ERC1155_SafeTransferFrom(wallet, validAddress, null, validTokenId, validAmount, validData)); - _ = await Assert.ThrowsAsync(async () => await contract.ERC1155_SafeTransferFrom(wallet, validAddress, string.Empty, validTokenId, validAmount, validData)); - _ = await Assert.ThrowsAsync( - async () => await contract.ERC1155_SafeTransferFrom(wallet, validAddress, validAddress, BigInteger.MinusOne, validAmount, validData) - ); - - // ERC1155_SafeBatchTransferFrom - _ = await Assert.ThrowsAsync( - async () => await contract.ERC1155_SafeBatchTransferFrom(null, null, null, new BigInteger[] { validTokenId }, new BigInteger[] { validAmount }, validData) - ); - _ = await Assert.ThrowsAsync( - async () => await contract.ERC1155_SafeBatchTransferFrom(wallet, null, null, new BigInteger[] { validTokenId }, new BigInteger[] { validAmount }, validData) - ); - _ = await Assert.ThrowsAsync( - async () => await contract.ERC1155_SafeBatchTransferFrom(wallet, string.Empty, null, new BigInteger[] { validTokenId }, new BigInteger[] { validAmount }, validData) - ); - _ = await Assert.ThrowsAsync( - async () => await contract.ERC1155_SafeBatchTransferFrom(wallet, validAddress, null, new BigInteger[] { validTokenId }, new BigInteger[] { validAmount }, validData) - ); - _ = await Assert.ThrowsAsync( - async () => await contract.ERC1155_SafeBatchTransferFrom(wallet, validAddress, string.Empty, new BigInteger[] { validTokenId }, new BigInteger[] { validAmount }, validData) - ); - _ = await Assert.ThrowsAsync( - async () => await contract.ERC1155_SafeBatchTransferFrom(wallet, validAddress, validAddress, null, new BigInteger[] { validAmount }, validData) - ); - _ = await Assert.ThrowsAsync( - async () => await contract.ERC1155_SafeBatchTransferFrom(wallet, validAddress, validAddress, new BigInteger[] { validTokenId }, null, validData) - ); - - // ERC1155_URI - _ = await Assert.ThrowsAsync(async () => await contract.ERC1155_URI(BigInteger.MinusOne)); - - // ERC1155_TotalSupply (with tokenId) - _ = await Assert.ThrowsAsync(async () => await contract.ERC1155_TotalSupply(BigInteger.MinusOne)); - - // Null wallet checks - wallet = null; - - _ = await Assert.ThrowsAsync(async () => await contract.ERC1155_SetApprovalForAll(wallet, validAddress, false)); - _ = await Assert.ThrowsAsync(async () => await contract.ERC1155_SafeTransferFrom(wallet, validAddress, validAddress, validTokenId, validAmount, validData)); - _ = await Assert.ThrowsAsync( - async () => await contract.ERC1155_SafeBatchTransferFrom(wallet, validAddress, validAddress, new BigInteger[] { validTokenId }, new BigInteger[] { validAmount }, validData) - ); - - // Null contract checks - contract = null; - - _ = await Assert.ThrowsAsync(async () => await contract.ERC1155_BalanceOf(validAddress, validTokenId)); - _ = await Assert.ThrowsAsync(async () => await contract.ERC1155_BalanceOfBatch(new string[] { validAddress }, new BigInteger[] { validTokenId })); - _ = await Assert.ThrowsAsync(async () => await contract.ERC1155_SetApprovalForAll(wallet, validAddress, false)); - _ = await Assert.ThrowsAsync(async () => await contract.ERC1155_IsApprovedForAll(validAddress, validAddress)); - _ = await Assert.ThrowsAsync(async () => await contract.ERC1155_SafeTransferFrom(wallet, validAddress, validAddress, validTokenId, validAmount, validData)); - _ = await Assert.ThrowsAsync( - async () => await contract.ERC1155_SafeBatchTransferFrom(wallet, validAddress, validAddress, new BigInteger[] { validTokenId }, new BigInteger[] { validAmount }, validData) - ); - _ = await Assert.ThrowsAsync(async () => await contract.ERC1155_URI(validTokenId)); - _ = await Assert.ThrowsAsync(async () => await contract.ERC1155_TotalSupply(validTokenId)); - _ = await Assert.ThrowsAsync(async () => await contract.ERC1155_TotalSupply()); - } - - [Fact] - public async Task ERC1155_BalanceOf() - { - var contract = await GetTokenERC1155Contract(); - var wallet = await GetSmartWallet(); - var ownerAddress = await wallet.GetAddress(); - var tokenId = BigInteger.Parse("1"); - var balance = await contract.ERC1155_BalanceOf(ownerAddress, tokenId); - Assert.True(balance >= 0); - } - - [Fact] - public async Task ERC1155_BalanceOfBatch() - { - var contract = await GetTokenERC1155Contract(); - var wallet = await GetSmartWallet(); - var ownerAddresses = new string[] { await wallet.GetAddress(), await wallet.GetAddress() }; - var tokenIds = new BigInteger[] { BigInteger.Parse("1"), BigInteger.Parse("2") }; - var balances = await contract.ERC1155_BalanceOfBatch(ownerAddresses, tokenIds); - Assert.True(balances.Count == ownerAddresses.Length); - } - - [Fact] - public async Task ERC1155_IsApprovedForAll() - { - var contract = await GetTokenERC1155Contract(); - var ownerAddress = Constants.ADDRESS_ZERO; - var operatorAddress = contract.Address; - var isApproved = await contract.ERC1155_IsApprovedForAll(ownerAddress, operatorAddress); - Assert.True(isApproved || !isApproved); - } - - [Fact] - public async Task ERC1155_URI() - { - var contract = await GetTokenERC1155Contract(); - var tokenId = BigInteger.Parse("1"); - var uri = await contract.ERC1155_URI(tokenId); - Assert.False(string.IsNullOrEmpty(uri)); - } - - [Fact] - public async Task ERC1155_SetApprovalForAll() - { - var contract = await GetTokenERC1155Contract(); - var wallet = await GetSmartWallet(); - var operatorAddress = contract.Address; - var approved = true; - var receipt = await contract.ERC1155_SetApprovalForAll(wallet, operatorAddress, approved); - Assert.True(receipt.TransactionHash.Length == 66); - } - - [Fact] - public async Task ERC1155_TotalSupply() - { - var contract = await GetTokenERC1155Contract(); - var totalSupply = await contract.ERC1155_TotalSupply(); - Assert.True(totalSupply >= 0); - } - - [Fact] - public async Task ERC1155_TotalSupply_WithTokenId() - { - var contract = await GetTokenERC1155Contract(); - var tokenId = BigInteger.Parse("1"); - var totalSupply = await contract.ERC1155_TotalSupply(tokenId); - Assert.True(totalSupply >= 0); - } - - #endregion - - #region NFT - - [Fact] - public async Task NFT_NullChecks() - { - var client = ThirdwebClient.Create(secretKey: _secretKey); - var contract721 = await GetTokenERC721Contract(); - var contract1155 = await GetTokenERC1155Contract(); - - // ERC721 Null Checks - _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.ERC721_GetNFT(null, BigInteger.Zero)); - _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.ERC721_GetAllNFTs(null)); - _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.ERC721_GetOwnedNFTs(null, "owner")); - _ = await Assert.ThrowsAsync(async () => await contract721.ERC721_GetOwnedNFTs(null)); - _ = await Assert.ThrowsAsync(async () => await contract721.ERC721_GetOwnedNFTs(string.Empty)); - - // ERC1155 Null Checks - _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.ERC1155_GetNFT(null, BigInteger.Zero)); - _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.ERC1155_GetAllNFTs(null)); - _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.ERC1155_GetOwnedNFTs(null, "owner")); - _ = await Assert.ThrowsAsync(async () => await contract1155.ERC1155_GetOwnedNFTs(null)); - _ = await Assert.ThrowsAsync(async () => await contract1155.ERC1155_GetOwnedNFTs(string.Empty)); - - // ERC721 Token ID Out of Range Checks - _ = await Assert.ThrowsAsync(async () => await contract721.ERC721_GetNFT(BigInteger.MinusOne)); - - // ERC1155 Token ID Out of Range Checks - _ = await Assert.ThrowsAsync(async () => await contract1155.ERC1155_GetNFT(BigInteger.MinusOne)); - - // Null contract checks - contract721 = null; - _ = await Assert.ThrowsAsync(async () => await contract721.ERC721_GetNFT(0)); - _ = await Assert.ThrowsAsync(async () => await contract721.ERC721_GetAllNFTs()); - _ = await Assert.ThrowsAsync(async () => await contract721.ERC721_GetOwnedNFTs("owner")); - - contract1155 = null; - _ = await Assert.ThrowsAsync(async () => await contract1155.ERC1155_GetNFT(0)); - _ = await Assert.ThrowsAsync(async () => await contract1155.ERC1155_GetAllNFTs()); - _ = await Assert.ThrowsAsync(async () => await contract1155.ERC1155_GetOwnedNFTs("owner")); - } - - [Fact] - public async Task GetNFT_721() - { - var contract = await GetTokenERC721Contract(); - var nft = await contract.ERC721_GetNFT(0); - Assert.NotNull(nft.Owner); - Assert.NotEmpty(nft.Owner); - Assert.Equal(NFTType.ERC721, nft.Type); - Assert.True(nft.Supply == 1); - Assert.Null(nft.QuantityOwned); - } - - [Fact] - public async Task GetAllNFTs_721() - { - var contract = await GetTokenERC721Contract(); - var nfts = await contract.ERC721_GetAllNFTs(); - Assert.NotNull(nfts); - Assert.NotEmpty(nfts); - } - - [Fact] - public async Task GetAllNFTs_721_WithRange() - { - var contract = await GetTokenERC721Contract(); - var nfts = await contract.ERC721_GetAllNFTs(1, 2); - Assert.NotNull(nfts); - Assert.NotEmpty(nfts); - Assert.True(nfts.Count == 1); - } - - [Fact] - public async Task GetOwnedNFTs_721() - { - var contract = await GetTokenERC721Contract(); - var ownerAddress = contract.Address; - var nfts = await contract.ERC721_GetOwnedNFTs(ownerAddress); - Assert.NotNull(nfts); - } - - [Fact] - public async Task GetNFT_1155() - { - var contract = await GetTokenERC1155Contract(); - var nft = await contract.ERC1155_GetNFT(0); - Assert.Equal(NFTType.ERC1155, nft.Type); - Assert.True(nft.Supply >= 0); - } - - [Fact] - public async Task GetAllNFTs_1155() - { - var contract = await GetTokenERC1155Contract(); - var nfts = await contract.ERC1155_GetAllNFTs(); - Assert.NotNull(nfts); - Assert.NotEmpty(nfts); - } - - [Fact] - public async Task GetAllNFTs_1155_WithRange() - { - var contract = await GetTokenERC1155Contract(); - var nfts = await contract.ERC1155_GetAllNFTs(1, 2); - Assert.NotNull(nfts); - Assert.NotEmpty(nfts); - Assert.True(nfts.Count == 1); - } - - [Fact] - public async Task GetOwnedNFTs_1155() - { - var contract = await GetTokenERC1155Contract(); - var ownerAddress = contract.Address; - var nfts = await contract.ERC1155_GetOwnedNFTs(ownerAddress); - Assert.NotNull(nfts); - } - - #endregion - - #region DropERC20 - - [Fact] - public async Task DropERC20_NullChecks() - { - var client = ThirdwebClient.Create(secretKey: _secretKey); - var contract = await ThirdwebContract.Create(client, _dropErc20ContractAddress, _chainId); - var wallet = await GetSmartWallet(); - var validAddress = "0x0000000000000000000000000000000000000000"; - var validAmount = "10"; - var validClaimConditionId = BigInteger.One; - var invalidClaimConditionId = BigInteger.MinusOne; - - // DropERC20_Claim null checks - _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.DropERC20_Claim(null, wallet, validAddress, validAmount)); - _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.DropERC20_Claim(contract, null, validAddress, validAmount)); - _ = await Assert.ThrowsAsync(async () => await contract.DropERC20_Claim(wallet, null, validAmount)); - _ = await Assert.ThrowsAsync(async () => await contract.DropERC20_Claim(wallet, string.Empty, validAmount)); - _ = await Assert.ThrowsAsync(async () => await contract.DropERC20_Claim(wallet, validAddress, null)); - _ = await Assert.ThrowsAsync(async () => await contract.DropERC20_Claim(wallet, validAddress, string.Empty)); - - // DropERC20_GetActiveClaimConditionId null checks - _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.DropERC20_GetActiveClaimConditionId(null)); - - // DropERC20_GetClaimConditionById null and out of range checks - _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.DropERC20_GetClaimConditionById(null, validClaimConditionId)); - _ = await Assert.ThrowsAsync(async () => await contract.DropERC20_GetClaimConditionById(invalidClaimConditionId)); - - // DropERC20_GetActiveClaimCondition null checks - _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.DropERC20_GetActiveClaimCondition(null)); - - // Null contract checks - contract = null; - _ = await Assert.ThrowsAsync(async () => await contract.DropERC20_Claim(wallet, validAddress, validAmount)); - _ = await Assert.ThrowsAsync(async () => await contract.DropERC20_GetActiveClaimConditionId()); - _ = await Assert.ThrowsAsync(async () => await contract.DropERC20_GetClaimConditionById(validClaimConditionId)); - _ = await Assert.ThrowsAsync(async () => await contract.DropERC20_GetActiveClaimCondition()); - } - - [Fact] - public async Task DropERC20_Claim() - { - var contract = await GetDrop20Contract(); - var wallet = await GetSmartWallet(); - var receiverAddress = await wallet.GetAddress(); - var balanceBefore = await contract.ERC20_BalanceOf(receiverAddress); - var receipt = await contract.DropERC20_Claim(wallet, receiverAddress, "1.5"); - var balanceAfter = await contract.ERC20_BalanceOf(receiverAddress); - Assert.NotNull(receipt); - Assert.True(receipt.TransactionHash.Length == 66); - Assert.True(balanceAfter == balanceBefore + BigInteger.Parse("1.5".ToWei())); - } - - [Fact] - public async Task DropERC20_GetActiveClaimConditionId() - { - var contract = await GetDrop20Contract(); - var conditionId = await contract.DropERC20_GetActiveClaimConditionId(); - Assert.True(conditionId >= 0); - } - - [Fact] - public async Task DropERC20_GetClaimConditionById() - { - var contract = await GetDrop20Contract(); - var conditionId = await contract.DropERC20_GetActiveClaimConditionId(); - var condition = await contract.DropERC20_GetClaimConditionById(conditionId); - Assert.NotNull(condition); - Assert.True(condition.Currency.Length == 42); - } - - [Fact] - public async Task DropERC20_GetActiveClaimCondition() - { - var contract = await GetDrop20Contract(); - var condition = await contract.DropERC20_GetActiveClaimCondition(); - Assert.NotNull(condition); - Assert.True(condition.Currency.Length == 42); - - // Compare to raw GetClaimConditionById - var conditionId = await contract.DropERC20_GetActiveClaimConditionId(); - var conditionById = await contract.DropERC20_GetClaimConditionById(conditionId); - Assert.Equal(condition.Currency, conditionById.Currency); - } - - #endregion - - #region DropERC721 - - [Fact] - public async Task DropERC721_NullChecks() - { - var client = ThirdwebClient.Create(secretKey: _secretKey); - var contract = await ThirdwebContract.Create(client, _dropErc721ContractAddress, _chainId); - var wallet = await GetSmartWallet(); - var validAddress = "0x0000000000000000000000000000000000000000"; - var validQuantity = BigInteger.One; - var invalidQuantity = BigInteger.Zero; - var validClaimConditionId = BigInteger.One; - var invalidClaimConditionId = BigInteger.MinusOne; - - // DropERC721_Claim null checks - _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.DropERC721_Claim(null, wallet, validAddress, validQuantity)); - _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.DropERC721_Claim(contract, null, validAddress, validQuantity)); - _ = await Assert.ThrowsAsync(async () => await contract.DropERC721_Claim(wallet, null, validQuantity)); - _ = await Assert.ThrowsAsync(async () => await contract.DropERC721_Claim(wallet, string.Empty, validQuantity)); - _ = await Assert.ThrowsAsync(async () => await contract.DropERC721_Claim(wallet, validAddress, invalidQuantity)); - - // DropERC721_GetActiveClaimConditionId null checks - _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.DropERC721_GetActiveClaimConditionId(null)); - - // DropERC721_GetClaimConditionById null and out of range checks - _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.DropERC721_GetClaimConditionById(null, validClaimConditionId)); - _ = await Assert.ThrowsAsync(async () => await contract.DropERC721_GetClaimConditionById(invalidClaimConditionId)); - - // DropERC721_GetActiveClaimCondition null checks - _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.DropERC721_GetActiveClaimCondition(null)); - - // Null contract checks - contract = null; - _ = await Assert.ThrowsAsync(async () => await contract.DropERC721_Claim(wallet, validAddress, validQuantity)); - _ = await Assert.ThrowsAsync(async () => await contract.DropERC721_GetActiveClaimConditionId()); - _ = await Assert.ThrowsAsync(async () => await contract.DropERC721_GetClaimConditionById(validClaimConditionId)); - _ = await Assert.ThrowsAsync(async () => await contract.DropERC721_GetActiveClaimCondition()); - } - - [Fact] - public async Task DropERC721_Claim_ShouldThrowTokens() - { - var contract = await GetDrop721Contract(); - var wallet = await GetSmartWallet(); - var ex = await Assert.ThrowsAsync(async () => await contract.DropERC721_Claim(wallet, await wallet.GetAddress(), 1)); - Assert.Contains("!Tokens", ex.Message); - } - - [Fact] - public async Task DropERC721_GetActiveClaimConditionId() - { - var contract = await GetDrop721Contract(); - var conditionId = await contract.DropERC721_GetActiveClaimConditionId(); - Assert.True(conditionId >= 0); - } - - [Fact] - public async Task DropERC721_GetClaimConditionById() - { - var contract = await GetDrop721Contract(); - var conditionId = await contract.DropERC721_GetActiveClaimConditionId(); - var condition = await contract.DropERC721_GetClaimConditionById(conditionId); - Assert.NotNull(condition); - Assert.True(condition.Currency.Length == 42); - } - - [Fact] - public async Task DropERC721_GetActiveClaimCondition() - { - var contract = await GetDrop721Contract(); - var condition = await contract.DropERC721_GetActiveClaimCondition(); - Assert.NotNull(condition); - Assert.True(condition.Currency.Length == 42); - - // Compare to raw GetClaimConditionById - var conditionId = await contract.DropERC721_GetActiveClaimConditionId(); - var conditionById = await contract.DropERC721_GetClaimConditionById(conditionId); - Assert.Equal(condition.Currency, conditionById.Currency); - } - - #endregion - - #region DropERC1155 - - [Fact] - public async Task DropERC1155_NullChecks() - { - var client = ThirdwebClient.Create(secretKey: _secretKey); - var contract = await ThirdwebContract.Create(client, _dropErc1155ContractAddress, _chainId); - var wallet = await GetSmartWallet(); - var validAddress = "0x0000000000000000000000000000000000000000"; - var validTokenId = BigInteger.One; - var invalidTokenId = BigInteger.MinusOne; - var validQuantity = BigInteger.One; - var invalidQuantity = BigInteger.Zero; - var validClaimConditionId = BigInteger.One; - var invalidClaimConditionId = BigInteger.MinusOne; - - // DropERC1155_Claim null checks - _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.DropERC1155_Claim(null, wallet, validAddress, validTokenId, validQuantity)); - _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.DropERC1155_Claim(contract, null, validAddress, validTokenId, validQuantity)); - _ = await Assert.ThrowsAsync(async () => await contract.DropERC1155_Claim(wallet, null, validTokenId, validQuantity)); - _ = await Assert.ThrowsAsync(async () => await contract.DropERC1155_Claim(wallet, string.Empty, validTokenId, validQuantity)); - _ = await Assert.ThrowsAsync(async () => await contract.DropERC1155_Claim(wallet, validAddress, invalidTokenId, validQuantity)); - _ = await Assert.ThrowsAsync(async () => await contract.DropERC1155_Claim(wallet, validAddress, validTokenId, invalidQuantity)); - - // DropERC1155_GetActiveClaimConditionId null and out of range checks - _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.DropERC1155_GetActiveClaimConditionId(null, validTokenId)); - _ = await Assert.ThrowsAsync(async () => await contract.DropERC1155_GetActiveClaimConditionId(invalidTokenId)); - - // DropERC1155_GetClaimConditionById null and out of range checks - _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.DropERC1155_GetClaimConditionById(null, validTokenId, validClaimConditionId)); - _ = await Assert.ThrowsAsync(async () => await contract.DropERC1155_GetClaimConditionById(invalidTokenId, validClaimConditionId)); - _ = await Assert.ThrowsAsync(async () => await contract.DropERC1155_GetClaimConditionById(validTokenId, invalidClaimConditionId)); - - // DropERC1155_GetActiveClaimCondition null and out of range checks - _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.DropERC1155_GetActiveClaimCondition(null, validTokenId)); - _ = await Assert.ThrowsAsync(async () => await contract.DropERC1155_GetActiveClaimCondition(invalidTokenId)); - - // Null contract checks - contract = null; - _ = await Assert.ThrowsAsync(async () => await contract.DropERC1155_Claim(wallet, validAddress, validTokenId, validQuantity)); - _ = await Assert.ThrowsAsync(async () => await contract.DropERC1155_GetActiveClaimConditionId(validTokenId)); - _ = await Assert.ThrowsAsync(async () => await contract.DropERC1155_GetClaimConditionById(validTokenId, validClaimConditionId)); - _ = await Assert.ThrowsAsync(async () => await contract.DropERC1155_GetActiveClaimCondition(validTokenId)); - } - - [Fact] - public async Task DropERC1155_Claim() - { - var contract = await GetDrop1155Contract(); - var wallet = await GetSmartWallet(); - var tokenId = 0; - var quantity = 10; - var receiverAddress = await wallet.GetAddress(); - - var balanceBefore = await contract.ERC1155_BalanceOf(receiverAddress, tokenId); - var receipt = await contract.DropERC1155_Claim(wallet, receiverAddress, tokenId, quantity); - var balanceAfter = await contract.ERC1155_BalanceOf(receiverAddress, tokenId); - Assert.NotNull(receipt); - Assert.True(receipt.TransactionHash.Length == 66); - Assert.True(balanceAfter == balanceBefore + quantity); - } - - [Fact] - public async Task DropERC1155_GetActiveClaimConditionId() - { - var contract = await GetDrop1155Contract(); - var tokenId = 0; - var conditionId = await contract.DropERC1155_GetActiveClaimConditionId(tokenId); - Assert.True(conditionId >= 0); - } - - [Fact] - public async Task DropERC1155_GetClaimConditionById() - { - var contract = await GetDrop1155Contract(); - var tokenId = 0; - var conditionId = await contract.DropERC1155_GetActiveClaimConditionId(tokenId); - var condition = await contract.DropERC1155_GetClaimConditionById(tokenId, conditionId); - Assert.NotNull(condition); - Assert.True(condition.Currency.Length == 42); - } - - [Fact] - public async Task DropERC1155_GetActiveClaimCondition() - { - var contract = await GetDrop1155Contract(); - var tokenId = 0; - var condition = await contract.DropERC1155_GetActiveClaimCondition(tokenId); - Assert.NotNull(condition); - Assert.True(condition.Currency.Length == 42); - - // Compare to raw GetClaimConditionById - var conditionId = await contract.DropERC1155_GetActiveClaimConditionId(tokenId); - var conditionById = await contract.DropERC1155_GetClaimConditionById(tokenId, conditionId); - Assert.Equal(condition.Currency, conditionById.Currency); - } - - #endregion - - #region TokenERC20 - - [Fact] - public async Task TokenERC20_NullChecks() - { - var client = ThirdwebClient.Create(secretKey: _secretKey); - var contract = await ThirdwebContract.Create(client, _tokenErc20ContractAddress, _chainId); - var wallet = await GetSmartWallet(); - var validAddress = "0x0000000000000000000000000000000000000000"; - var validAmount = "100"; - var invalidAmount = string.Empty; - var validSignature = "0x123"; - var invalidSignature = string.Empty; - - var validMintRequest = new TokenERC20_MintRequest - { - To = validAddress, - PrimarySaleRecipient = validAddress, - Quantity = BigInteger.One, - Price = BigInteger.One, - Currency = Constants.NATIVE_TOKEN_ADDRESS, - ValidityStartTimestamp = 0, - ValidityEndTimestamp = 0, - Uid = Guid.NewGuid().ToByteArray().PadTo32Bytes() - }; - - // TokenERC20_MintTo null checks - _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC20_MintTo(null, wallet, validAddress, validAmount)); - _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC20_MintTo(contract, null, validAddress, validAmount)); - _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC20_MintTo(contract, wallet, null, validAmount)); - _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC20_MintTo(contract, wallet, string.Empty, validAmount)); - _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC20_MintTo(contract, wallet, validAddress, null)); - _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC20_MintTo(contract, wallet, validAddress, string.Empty)); - - // TokenERC20_MintWithSignature null checks - _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC20_MintWithSignature(null, wallet, validMintRequest, validSignature)); - _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC20_MintWithSignature(contract, null, validMintRequest, validSignature)); - _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC20_MintWithSignature(contract, wallet, null, validSignature)); - _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC20_MintWithSignature(contract, wallet, validMintRequest, null)); - _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC20_MintWithSignature(contract, wallet, validMintRequest, string.Empty)); - - // TokenERC20_GenerateMintSignature null checks - _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC20_GenerateMintSignature(null, wallet, validMintRequest)); - _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC20_GenerateMintSignature(contract, null, validMintRequest)); - _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC20_GenerateMintSignature(contract, wallet, null)); - - // TokenERC20_VerifyMintSignature null checks - _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC20_VerifyMintSignature(null, validMintRequest, validSignature)); - _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC20_VerifyMintSignature(contract, null, validSignature)); - _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC20_VerifyMintSignature(contract, validMintRequest, null)); - _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC20_VerifyMintSignature(contract, validMintRequest, string.Empty)); - - // Null contract checks - contract = null; - _ = await Assert.ThrowsAsync(async () => await contract.TokenERC20_MintTo(wallet, validAddress, validAmount)); - _ = await Assert.ThrowsAsync(async () => await contract.TokenERC20_MintWithSignature(wallet, validMintRequest, validSignature)); - _ = await Assert.ThrowsAsync(async () => await contract.TokenERC20_GenerateMintSignature(wallet, validMintRequest)); - _ = await Assert.ThrowsAsync(async () => await contract.TokenERC20_VerifyMintSignature(validMintRequest, validSignature)); - } - - // TODO: MintTo - - // TODO: MintWithSignature - - [Fact] - public async Task TokenERC20_GenerateMintSignature_WithVerify() - { - var contract = await GetTokenERC20Contract(); - var fakeAuthorizedSigner = await PrivateKeyWallet.Generate(_client); - var randomReceiver = await PrivateKeyWallet.Generate(_client); - var mintRequest = new TokenERC20_MintRequest { To = await randomReceiver.GetAddress(), Quantity = BigInteger.Parse("1.5".ToWei()), }; - - (var payload, var signature) = await contract.TokenERC20_GenerateMintSignature(fakeAuthorizedSigner, mintRequest); - - // returned payload should be filled with defaults - Assert.NotNull(payload); - Assert.NotNull(payload.To); - Assert.True(payload.To.Length == 42); - Assert.True(payload.To == await randomReceiver.GetAddress()); - Assert.NotNull(payload.PrimarySaleRecipient); - Assert.True(payload.PrimarySaleRecipient.Length == 42); - Assert.True(payload.Quantity != BigInteger.Zero); - Assert.True(payload.Price >= 0); - Assert.NotNull(payload.Currency); - Assert.True(payload.Currency.Length == 42); - Assert.True(payload.ValidityStartTimestamp >= 0); - Assert.True(payload.ValidityEndTimestamp >= 0); - Assert.NotNull(payload.Uid); - Assert.True(payload.Uid.Length == 32); // bytes32 - - // signature should not be valid - Assert.NotNull(signature); - Assert.NotEmpty(signature); - var verifyResult = await contract.TokenERC20_VerifyMintSignature(payload, signature); - Assert.False(verifyResult.IsValid); - Assert.Equal(await fakeAuthorizedSigner.GetAddress(), verifyResult.Signer); - } - - #endregion - - #region TokenERC721 - - [Fact] - public async Task TokenERC721_NullChecks() - { - var client = ThirdwebClient.Create(secretKey: _secretKey); - var contract = await ThirdwebContract.Create(client, _tokenErc721ContractAddress, _chainId); - var wallet = await GetSmartWallet(); - var validAddress = "0x0000000000000000000000000000000000000000"; - var validTokenId = BigInteger.One; - var invalidTokenId = BigInteger.MinusOne; - var validUri = "ipfs://validUri"; - var invalidUri = null as string; - var validSignature = "0x123"; - var invalidSignature = string.Empty; - - var validMintRequest = new TokenERC721_MintRequest - { - To = validAddress, - PrimarySaleRecipient = validAddress, - Uri = validUri, - Price = BigInteger.One, - Currency = Constants.NATIVE_TOKEN_ADDRESS, - ValidityStartTimestamp = 0, - ValidityEndTimestamp = 0, - Uid = Guid.NewGuid().ToByteArray().PadTo32Bytes() - }; - - // TokenERC721_MintTo (with URI) null checks - _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC721_MintTo(null, wallet, validAddress, validTokenId, validUri)); - _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC721_MintTo(contract, null, validAddress, validTokenId, validUri)); - _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC721_MintTo(contract, wallet, null, validTokenId, validUri)); - _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC721_MintTo(contract, wallet, string.Empty, validTokenId, validUri)); - _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC721_MintTo(contract, wallet, validAddress, invalidTokenId, validUri)); - _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC721_MintTo(contract, wallet, validAddress, validTokenId, invalidUri)); - - // TokenERC721_MintTo (with metadata) null checks - _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC721_MintTo(null, wallet, validAddress, validTokenId, new NFTMetadata())); - _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC721_MintTo(contract, null, validAddress, validTokenId, new NFTMetadata())); - _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC721_MintTo(contract, wallet, null, validTokenId, new NFTMetadata())); - _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC721_MintTo(contract, wallet, string.Empty, validTokenId, new NFTMetadata())); - _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC721_MintTo(contract, wallet, validAddress, invalidTokenId, new NFTMetadata())); - - // TokenERC721_MintWithSignature null checks - _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC721_MintWithSignature(null, wallet, validMintRequest, validSignature)); - _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC721_MintWithSignature(contract, null, validMintRequest, validSignature)); - _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC721_MintWithSignature(contract, wallet, null, validSignature)); - _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC721_MintWithSignature(contract, wallet, validMintRequest, null)); - _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC721_MintWithSignature(contract, wallet, validMintRequest, string.Empty)); - - // TokenERC721_GenerateMintSignature null checks - _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC721_GenerateMintSignature(null, wallet, validMintRequest)); - _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC721_GenerateMintSignature(contract, null, validMintRequest)); - _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC721_GenerateMintSignature(contract, wallet, null)); - - // TokenERC721_VerifyMintSignature null checks - _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC721_VerifyMintSignature(null, validMintRequest, validSignature)); - _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC721_VerifyMintSignature(contract, null, validSignature)); - _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC721_VerifyMintSignature(contract, validMintRequest, null)); - _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC721_VerifyMintSignature(contract, validMintRequest, string.Empty)); - - // Null contract checks - contract = null; - _ = await Assert.ThrowsAsync(async () => await contract.TokenERC721_MintTo(wallet, validAddress, validTokenId, validUri)); - _ = await Assert.ThrowsAsync(async () => await contract.TokenERC721_MintTo(wallet, validAddress, validTokenId, new NFTMetadata())); - _ = await Assert.ThrowsAsync(async () => await contract.TokenERC721_MintWithSignature(wallet, validMintRequest, validSignature)); - _ = await Assert.ThrowsAsync(async () => await contract.TokenERC721_GenerateMintSignature(wallet, validMintRequest)); - _ = await Assert.ThrowsAsync(async () => await contract.TokenERC721_VerifyMintSignature(validMintRequest, validSignature)); - } - - // TODO: MintTo - - // TODO: MintWithSignature - - [Fact] - public async Task TokenERC721_GenerateMintSignature_WithUri_WithVerify() - { - var contract = await GetTokenERC721Contract(); - var fakeAuthorizedSigner = await PrivateKeyWallet.Generate(_client); - var randomReceiver = await PrivateKeyWallet.Generate(_client); - var mintRequest = new TokenERC721_MintRequest { To = await randomReceiver.GetAddress(), Uri = "", }; - - (var payload, var signature) = await contract.TokenERC721_GenerateMintSignature(fakeAuthorizedSigner, mintRequest); - - // returned payload should be filled with defaults - Assert.NotNull(payload); - Assert.NotNull(payload.To); - Assert.True(payload.To.Length == 42); - Assert.True(payload.To == await randomReceiver.GetAddress()); - Assert.True(payload.RoyaltyRecipient.Length == 42); - Assert.True(payload.RoyaltyBps >= 0); - Assert.NotNull(payload.PrimarySaleRecipient); - Assert.True(payload.PrimarySaleRecipient.Length == 42); - Assert.True(payload.Price >= 0); - Assert.NotNull(payload.Currency); - Assert.True(payload.Currency.Length == 42); - Assert.True(payload.ValidityStartTimestamp >= 0); - Assert.True(payload.ValidityEndTimestamp >= 0); - Assert.NotNull(payload.Uid); - Assert.True(payload.Uid.Length == 32); // bytes32 - - // signature should not be valid - Assert.NotNull(signature); - Assert.NotEmpty(signature); - var verifyResult = await contract.TokenERC721_VerifyMintSignature(payload, signature); - Assert.False(verifyResult.IsValid); - Assert.Equal(await fakeAuthorizedSigner.GetAddress(), verifyResult.Signer); - } - - [Fact] - public async Task TokenERC721_GenerateMintSignature_WithNFTMetadata_WithVerify() - { - var contract = await GetTokenERC721Contract(); - var fakeAuthorizedSigner = await PrivateKeyWallet.Generate(_client); - var randomReceiver = await PrivateKeyWallet.Generate(_client); - var mintRequest = new TokenERC721_MintRequest { To = await randomReceiver.GetAddress() }; - - (var payload, var signature) = await contract.TokenERC721_GenerateMintSignature( - fakeAuthorizedSigner, - mintRequest, - new NFTMetadata - { - Name = "Test", - Description = "Test", - Image = "Test", - ExternalUrl = "Test", - Attributes = new Dictionary { { "Test", "Test" } }, - } - ); - - // returned payload should be filled with defaults - Assert.NotNull(payload); - Assert.NotNull(payload.To); - Assert.True(payload.To.Length == 42); - Assert.True(payload.To == await randomReceiver.GetAddress()); - Assert.True(payload.RoyaltyRecipient.Length == 42); - Assert.True(payload.RoyaltyBps >= 0); - Assert.NotNull(payload.PrimarySaleRecipient); - Assert.True(payload.PrimarySaleRecipient.Length == 42); - Assert.True(payload.Price >= 0); - Assert.NotNull(payload.Currency); - Assert.True(payload.Currency.Length == 42); - Assert.True(payload.ValidityStartTimestamp >= 0); - Assert.True(payload.ValidityEndTimestamp >= 0); - Assert.NotNull(payload.Uid); - Assert.True(payload.Uid.Length == 32); // bytes32 - Assert.NotNull(payload.Uri); - Assert.True(payload.Uri.Length > 0); - - // signature should not be valid - Assert.NotNull(signature); - Assert.NotEmpty(signature); - var verifyResult = await contract.TokenERC721_VerifyMintSignature(payload, signature); - Assert.False(verifyResult.IsValid); - Assert.Equal(await fakeAuthorizedSigner.GetAddress(), verifyResult.Signer); - } - - #endregion - - #region TokenERC1155 - - [Fact] - public async Task TokenERC1155_NullChecks() - { - var client = ThirdwebClient.Create(secretKey: _secretKey); - var contract = await ThirdwebContract.Create(client, _tokenErc1155ContractAddress, _chainId); - var wallet = await GetSmartWallet(); - var validAddress = "0x0000000000000000000000000000000000000000"; - var validTokenId = BigInteger.One; - var invalidTokenId = BigInteger.MinusOne; - var validQuantity = BigInteger.One; - var invalidQuantity = BigInteger.Zero; - var validUri = "ipfs://validUri"; - var invalidUri = null as string; - var validSignature = "0x123"; - var invalidSignature = string.Empty; - - var validMintRequest = new TokenERC1155_MintRequest - { - To = validAddress, - PrimarySaleRecipient = validAddress, - Uri = validUri, - Quantity = BigInteger.One, - PricePerToken = BigInteger.One, - Currency = Constants.NATIVE_TOKEN_ADDRESS, - ValidityStartTimestamp = 0, - ValidityEndTimestamp = 0, - Uid = Guid.NewGuid().ToByteArray().PadTo32Bytes() - }; - - // TokenERC1155_MintTo (with URI) null checks - _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC1155_MintTo(null, wallet, validAddress, validTokenId, validQuantity, validUri)); - _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC1155_MintTo(contract, null, validAddress, validTokenId, validQuantity, validUri)); - _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC1155_MintTo(contract, wallet, null, validTokenId, validQuantity, validUri)); - _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC1155_MintTo(contract, wallet, string.Empty, validTokenId, validQuantity, validUri)); - _ = await Assert.ThrowsAsync( - async () => await ThirdwebExtensions.TokenERC1155_MintTo(contract, wallet, validAddress, invalidTokenId, validQuantity, validUri) - ); - _ = await Assert.ThrowsAsync( - async () => await ThirdwebExtensions.TokenERC1155_MintTo(contract, wallet, validAddress, validTokenId, invalidQuantity, validUri) - ); - _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC1155_MintTo(contract, wallet, validAddress, validTokenId, validQuantity, invalidUri)); - - // TokenERC1155_MintTo (with metadata) null checks - _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC1155_MintTo(null, wallet, validAddress, validTokenId, validQuantity, new NFTMetadata())); - _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC1155_MintTo(contract, null, validAddress, validTokenId, validQuantity, new NFTMetadata())); - _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC1155_MintTo(contract, wallet, null, validTokenId, validQuantity, new NFTMetadata())); - _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC1155_MintTo(contract, wallet, string.Empty, validTokenId, validQuantity, new NFTMetadata())); - _ = await Assert.ThrowsAsync( - async () => await ThirdwebExtensions.TokenERC1155_MintTo(contract, wallet, validAddress, invalidTokenId, validQuantity, new NFTMetadata()) - ); - _ = await Assert.ThrowsAsync( - async () => await ThirdwebExtensions.TokenERC1155_MintTo(contract, wallet, validAddress, validTokenId, invalidQuantity, new NFTMetadata()) - ); - - // TokenERC1155_MintWithSignature null checks - _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC1155_MintWithSignature(null, wallet, validMintRequest, validSignature)); - _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC1155_MintWithSignature(contract, null, validMintRequest, validSignature)); - _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC1155_MintWithSignature(contract, wallet, null, validSignature)); - _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC1155_MintWithSignature(contract, wallet, validMintRequest, null)); - _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC1155_MintWithSignature(contract, wallet, validMintRequest, string.Empty)); - - // TokenERC1155_GenerateMintSignature null checks - _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC1155_GenerateMintSignature(null, wallet, validMintRequest)); - _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC1155_GenerateMintSignature(contract, null, validMintRequest)); - _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC1155_GenerateMintSignature(contract, wallet, null)); - - // TokenERC1155_VerifyMintSignature null checks - _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC1155_VerifyMintSignature(null, validMintRequest, validSignature)); - _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC1155_VerifyMintSignature(contract, null, validSignature)); - _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC1155_VerifyMintSignature(contract, validMintRequest, null)); - _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC1155_VerifyMintSignature(contract, validMintRequest, string.Empty)); - - // Null contract checks - contract = null; - _ = await Assert.ThrowsAsync(async () => await contract.TokenERC1155_MintTo(wallet, validAddress, validTokenId, validQuantity, validUri)); - _ = await Assert.ThrowsAsync(async () => await contract.TokenERC1155_MintTo(wallet, validAddress, validTokenId, validQuantity, new NFTMetadata())); - _ = await Assert.ThrowsAsync(async () => await contract.TokenERC1155_MintWithSignature(wallet, validMintRequest, validSignature)); - _ = await Assert.ThrowsAsync(async () => await contract.TokenERC1155_GenerateMintSignature(wallet, validMintRequest)); - _ = await Assert.ThrowsAsync(async () => await contract.TokenERC1155_VerifyMintSignature(validMintRequest, validSignature)); - } - - // TODO: MintTo - - // TODO: MintWithSignature - - [Fact] - public async Task TokenERC1155_GenerateMintSignature_WithUri_WithVerify() - { - var contract = await GetTokenERC1155Contract(); - var fakeAuthorizedSigner = await PrivateKeyWallet.Generate(_client); - var randomReceiver = await PrivateKeyWallet.Generate(_client); - var mintRequest = new TokenERC1155_MintRequest { To = await randomReceiver.GetAddress(), Uri = "", }; - - (var payload, var signature) = await contract.TokenERC1155_GenerateMintSignature(fakeAuthorizedSigner, mintRequest); - - // returned payload should be filled with defaults - Assert.NotNull(payload); - Assert.NotNull(payload.To); - Assert.True(payload.To.Length == 42); - Assert.True(payload.To == await randomReceiver.GetAddress()); - Assert.True(payload.RoyaltyRecipient.Length == 42); - Assert.True(payload.RoyaltyBps >= 0); - Assert.NotNull(payload.PrimarySaleRecipient); - Assert.True(payload.PrimarySaleRecipient.Length == 42); - Assert.True(payload.PricePerToken >= 0); - Assert.NotNull(payload.Currency); - Assert.True(payload.Currency.Length == 42); - Assert.True(payload.ValidityStartTimestamp >= 0); - Assert.True(payload.ValidityEndTimestamp >= 0); - Assert.NotNull(payload.Uid); - Assert.True(payload.Uid.Length == 32); // bytes32 - Assert.NotNull(payload.TokenId); - Assert.True(payload.TokenId >= 0); - - // signature should not be valid - Assert.NotNull(signature); - Assert.NotEmpty(signature); - var verifyResult = await contract.TokenERC1155_VerifyMintSignature(payload, signature); - Assert.False(verifyResult.IsValid); - Assert.Equal(await fakeAuthorizedSigner.GetAddress(), verifyResult.Signer); - } - - [Fact] - public async Task TokenERC1155_GenerateMintSignature_WithNFTMetadata_WithVerify() - { - var contract = await GetTokenERC1155Contract(); - var fakeAuthorizedSigner = await PrivateKeyWallet.Generate(_client); - var randomReceiver = await PrivateKeyWallet.Generate(_client); - var mintRequest = new TokenERC1155_MintRequest { To = await randomReceiver.GetAddress() }; - - (var payload, var signature) = await contract.TokenERC1155_GenerateMintSignature( - fakeAuthorizedSigner, - mintRequest, - new NFTMetadata - { - Name = "Test", - Description = "Test", - Image = "Test", - ExternalUrl = "Test", - Attributes = new Dictionary { { "Test", "Test" } }, - } - ); - - // returned payload should be filled with defaults - Assert.NotNull(payload); - Assert.NotNull(payload.To); - Assert.True(payload.To.Length == 42); - Assert.True(payload.To == await randomReceiver.GetAddress()); - Assert.True(payload.RoyaltyRecipient.Length == 42); - Assert.True(payload.RoyaltyBps >= 0); - Assert.NotNull(payload.PrimarySaleRecipient); - Assert.True(payload.PrimarySaleRecipient.Length == 42); - Assert.True(payload.PricePerToken >= 0); - Assert.NotNull(payload.Currency); - Assert.True(payload.Currency.Length == 42); - Assert.True(payload.ValidityStartTimestamp >= 0); - Assert.True(payload.ValidityEndTimestamp >= 0); - Assert.NotNull(payload.Uid); - Assert.True(payload.Uid.Length == 32); // bytes32 - Assert.NotNull(payload.TokenId); - Assert.True(payload.TokenId >= 0); - Assert.NotNull(payload.Uri); - Assert.True(payload.Uri.Length > 0); - - // signature should not be valid - Assert.NotNull(signature); - Assert.NotEmpty(signature); - var verifyResult = await contract.TokenERC1155_VerifyMintSignature(payload, signature); - Assert.False(verifyResult.IsValid); - Assert.Equal(await fakeAuthorizedSigner.GetAddress(), verifyResult.Signer); - } - - #endregion - } -} diff --git a/Thirdweb.Tests/Thirdweb.Extensions/Thirdweb.Extensions.Tests.cs b/Thirdweb.Tests/Thirdweb.Extensions/Thirdweb.Extensions.Tests.cs new file mode 100644 index 00000000..ad8293cc --- /dev/null +++ b/Thirdweb.Tests/Thirdweb.Extensions/Thirdweb.Extensions.Tests.cs @@ -0,0 +1,1783 @@ +using System.Numerics; +using Nethereum.Util; + +namespace Thirdweb.Tests.Extensions; + +public class ExtensionsTests : BaseTests +{ + private readonly string _tokenErc20ContractAddress = "0x81ebd23aA79bCcF5AaFb9c9c5B0Db4223c39102e"; + private readonly string _tokenErc721ContractAddress = "0x345E7B4CCA26725197f1Bed802A05691D8EF7770"; + private readonly string _tokenErc1155ContractAddress = "0x83b5851134DAA0E28d855E7fBbdB6B412b46d26B"; + private readonly string _dropErc20ContractAddress = "0xEBB8a39D865465F289fa349A67B3391d8f910da9"; + private readonly string _dropErc721ContractAddress = "0xD811CB13169C175b64bf8897e2Fd6a69C6343f5C"; + private readonly string _dropErc1155ContractAddress = "0x6A7a26c9a595E6893C255C9dF0b593e77518e0c3"; + private readonly string _erc721AContractAddressTaiko = "0xCA99F9DbF4A13D4de05B41a68041dcE7929cb5e0"; + + private readonly BigInteger _chainId = 421614; + + public ExtensionsTests(ITestOutputHelper output) + : base(output) { } + + private async Task GetSmartWallet() + { + var privateKeyWallet = await this.GetGuestAccount(); + return await SmartWallet.Create(personalWallet: privateKeyWallet, chainId: 421614); + } + + private async Task GetTokenERC20Contract() + { + return await ThirdwebContract.Create(this.Client, this._tokenErc20ContractAddress, this._chainId); + } + + private async Task GetTokenERC721Contract() + { + return await ThirdwebContract.Create(this.Client, this._tokenErc721ContractAddress, this._chainId); + } + + private async Task GetTokenERC1155Contract() + { + return await ThirdwebContract.Create(this.Client, this._tokenErc1155ContractAddress, this._chainId); + } + + private async Task GetDrop20Contract() + { + return await ThirdwebContract.Create(this.Client, this._dropErc20ContractAddress, this._chainId); + } + + private async Task GetDrop721Contract() + { + return await ThirdwebContract.Create(this.Client, this._dropErc721ContractAddress, this._chainId); + } + + private async Task GetDrop1155Contract() + { + return await ThirdwebContract.Create(this.Client, this._dropErc1155ContractAddress, this._chainId); + } + + private async Task GetERC721AContract() + { + return await ThirdwebContract.Create( + this.Client, + this._erc721AContractAddressTaiko, + 167000, + /*lang=json,strict*/ + "[{\"inputs\":[{\"components\":[{\"components\":[{\"components\":[{\"internalType\":\"string\",\"name\":\"name\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"metadataURI\",\"type\":\"string\"},{\"internalType\":\"address\",\"name\":\"implementation\",\"type\":\"address\"}],\"internalType\":\"struct IExtension.ExtensionMetadata\",\"name\":\"metadata\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"bytes4\",\"name\":\"functionSelector\",\"type\":\"bytes4\"},{\"internalType\":\"string\",\"name\":\"functionSignature\",\"type\":\"string\"}],\"internalType\":\"struct IExtension.ExtensionFunction[]\",\"name\":\"functions\",\"type\":\"tuple[]\"}],\"internalType\":\"struct IExtension.Extension[]\",\"name\":\"extensions\",\"type\":\"tuple[]\"}],\"internalType\":\"struct TaikoSmashRoyaleRouter.SMRealmHeroTaikoConstructorParams\",\"name\":\"_SMRealmHeroTaikoConstructorParams\",\"type\":\"tuple\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"ApprovalCallerNotOwnerNorApproved\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ApprovalQueryForNonexistentToken\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"BalanceQueryForZeroAddress\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_size\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_start\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_end\",\"type\":\"uint256\"}],\"name\":\"InvalidCodeAtRange\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidQueryRange\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MintERC2309QuantityExceedsLimit\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MintToZeroAddress\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MintZeroQuantity\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OwnerQueryForNonexistentToken\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OwnershipNotInitializedForExtraData\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TransferCallerNotOwnerNorApproved\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TransferFromIncorrectOwner\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TransferToNonERC721ReceiverImplementer\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TransferToZeroAddress\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"URIQueryForNonexistentToken\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"WriteError\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"approved\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"}],\"name\":\"Approval\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"approved\",\"type\":\"bool\"}],\"name\":\"ApprovalForAll\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"fromTokenId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"toTokenId\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"ConsecutiveTransfer\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"string\",\"name\":\"prevURI\",\"type\":\"string\"},{\"indexed\":false,\"internalType\":\"string\",\"name\":\"newURI\",\"type\":\"string\"}],\"name\":\"ContractURIUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newRoyaltyRecipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newRoyaltyBps\",\"type\":\"uint256\"}],\"name\":\"DefaultRoyalty\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"string\",\"name\":\"name\",\"type\":\"string\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"implementation\",\"type\":\"address\"},{\"components\":[{\"components\":[{\"internalType\":\"string\",\"name\":\"name\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"metadataURI\",\"type\":\"string\"},{\"internalType\":\"address\",\"name\":\"implementation\",\"type\":\"address\"}],\"internalType\":\"struct IExtension.ExtensionMetadata\",\"name\":\"metadata\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"bytes4\",\"name\":\"functionSelector\",\"type\":\"bytes4\"},{\"internalType\":\"string\",\"name\":\"functionSignature\",\"type\":\"string\"}],\"internalType\":\"struct IExtension.ExtensionFunction[]\",\"name\":\"functions\",\"type\":\"tuple[]\"}],\"indexed\":false,\"internalType\":\"struct IExtension.Extension\",\"name\":\"extension\",\"type\":\"tuple\"}],\"name\":\"ExtensionAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"string\",\"name\":\"name\",\"type\":\"string\"},{\"components\":[{\"components\":[{\"internalType\":\"string\",\"name\":\"name\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"metadataURI\",\"type\":\"string\"},{\"internalType\":\"address\",\"name\":\"implementation\",\"type\":\"address\"}],\"internalType\":\"struct IExtension.ExtensionMetadata\",\"name\":\"metadata\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"bytes4\",\"name\":\"functionSelector\",\"type\":\"bytes4\"},{\"internalType\":\"string\",\"name\":\"functionSignature\",\"type\":\"string\"}],\"internalType\":\"struct IExtension.ExtensionFunction[]\",\"name\":\"functions\",\"type\":\"tuple[]\"}],\"indexed\":false,\"internalType\":\"struct IExtension.Extension\",\"name\":\"extension\",\"type\":\"tuple\"}],\"name\":\"ExtensionRemoved\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"string\",\"name\":\"name\",\"type\":\"string\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"implementation\",\"type\":\"address\"},{\"components\":[{\"components\":[{\"internalType\":\"string\",\"name\":\"name\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"metadataURI\",\"type\":\"string\"},{\"internalType\":\"address\",\"name\":\"implementation\",\"type\":\"address\"}],\"internalType\":\"struct IExtension.ExtensionMetadata\",\"name\":\"metadata\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"bytes4\",\"name\":\"functionSelector\",\"type\":\"bytes4\"},{\"internalType\":\"string\",\"name\":\"functionSignature\",\"type\":\"string\"}],\"internalType\":\"struct IExtension.ExtensionFunction[]\",\"name\":\"functions\",\"type\":\"tuple[]\"}],\"indexed\":false,\"internalType\":\"struct IExtension.Extension\",\"name\":\"extension\",\"type\":\"tuple\"}],\"name\":\"ExtensionReplaced\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"string\",\"name\":\"name\",\"type\":\"string\"},{\"indexed\":true,\"internalType\":\"bytes4\",\"name\":\"functionSelector\",\"type\":\"bytes4\"},{\"components\":[{\"internalType\":\"string\",\"name\":\"name\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"metadataURI\",\"type\":\"string\"},{\"internalType\":\"address\",\"name\":\"implementation\",\"type\":\"address\"}],\"indexed\":false,\"internalType\":\"struct IExtension.ExtensionMetadata\",\"name\":\"extMetadata\",\"type\":\"tuple\"}],\"name\":\"FunctionDisabled\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"string\",\"name\":\"name\",\"type\":\"string\"},{\"indexed\":true,\"internalType\":\"bytes4\",\"name\":\"functionSelector\",\"type\":\"bytes4\"},{\"components\":[{\"internalType\":\"bytes4\",\"name\":\"functionSelector\",\"type\":\"bytes4\"},{\"internalType\":\"string\",\"name\":\"functionSignature\",\"type\":\"string\"}],\"indexed\":false,\"internalType\":\"struct IExtension.ExtensionFunction\",\"name\":\"extFunction\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"string\",\"name\":\"name\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"metadataURI\",\"type\":\"string\"},{\"internalType\":\"address\",\"name\":\"implementation\",\"type\":\"address\"}],\"indexed\":false,\"internalType\":\"struct IExtension.ExtensionMetadata\",\"name\":\"extMetadata\",\"type\":\"tuple\"}],\"name\":\"FunctionEnabled\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"version\",\"type\":\"uint8\"}],\"name\":\"Initialized\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"prevOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"OwnerUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"}],\"name\":\"PrimarySaleRecipientUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"previousAdminRole\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"newAdminRole\",\"type\":\"bytes32\"}],\"name\":\"RoleAdminChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleGranted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleRevoked\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"royaltyRecipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"royaltyBps\",\"type\":\"uint256\"}],\"name\":\"RoyaltyForToken\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"}],\"name\":\"Transfer\",\"type\":\"event\"},{\"stateMutability\":\"payable\",\"type\":\"fallback\"},{\"inputs\":[],\"name\":\"DEFAULT_ADMIN_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"_extensionName\",\"type\":\"string\"},{\"internalType\":\"bytes4\",\"name\":\"_functionSelector\",\"type\":\"bytes4\"}],\"name\":\"_disableFunctionInExtension\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"components\":[{\"internalType\":\"string\",\"name\":\"name\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"metadataURI\",\"type\":\"string\"},{\"internalType\":\"address\",\"name\":\"implementation\",\"type\":\"address\"}],\"internalType\":\"struct IExtension.ExtensionMetadata\",\"name\":\"metadata\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"bytes4\",\"name\":\"functionSelector\",\"type\":\"bytes4\"},{\"internalType\":\"string\",\"name\":\"functionSignature\",\"type\":\"string\"}],\"internalType\":\"struct IExtension.ExtensionFunction[]\",\"name\":\"functions\",\"type\":\"tuple[]\"}],\"internalType\":\"struct IExtension.Extension\",\"name\":\"_extension\",\"type\":\"tuple\"}],\"name\":\"addExtension\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"}],\"name\":\"approve\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"balanceOf\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"}],\"name\":\"burn\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"contractURI\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"contractVersion\",\"outputs\":[{\"internalType\":\"uint8\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"defaultExtensions\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"_extensionName\",\"type\":\"string\"},{\"internalType\":\"bytes4\",\"name\":\"_functionSelector\",\"type\":\"bytes4\"}],\"name\":\"disableFunctionInExtension\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"disableUpgradeability\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"_extensionName\",\"type\":\"string\"},{\"components\":[{\"internalType\":\"bytes4\",\"name\":\"functionSelector\",\"type\":\"bytes4\"},{\"internalType\":\"string\",\"name\":\"functionSignature\",\"type\":\"string\"}],\"internalType\":\"struct IExtension.ExtensionFunction\",\"name\":\"_function\",\"type\":\"tuple\"}],\"name\":\"enableFunctionInExtension\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"}],\"name\":\"explicitOwnershipOf\",\"outputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"startTimestamp\",\"type\":\"uint64\"},{\"internalType\":\"bool\",\"name\":\"burned\",\"type\":\"bool\"},{\"internalType\":\"uint24\",\"name\":\"extraData\",\"type\":\"uint24\"}],\"internalType\":\"struct IERC721AUpgradeable.TokenOwnership\",\"name\":\"ownership\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getAllExtensions\",\"outputs\":[{\"components\":[{\"components\":[{\"internalType\":\"string\",\"name\":\"name\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"metadataURI\",\"type\":\"string\"},{\"internalType\":\"address\",\"name\":\"implementation\",\"type\":\"address\"}],\"internalType\":\"struct IExtension.ExtensionMetadata\",\"name\":\"metadata\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"bytes4\",\"name\":\"functionSelector\",\"type\":\"bytes4\"},{\"internalType\":\"string\",\"name\":\"functionSignature\",\"type\":\"string\"}],\"internalType\":\"struct IExtension.ExtensionFunction[]\",\"name\":\"functions\",\"type\":\"tuple[]\"}],\"internalType\":\"struct IExtension.Extension[]\",\"name\":\"allExtensions\",\"type\":\"tuple[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"}],\"name\":\"getApproved\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getDefaultRoyaltyInfo\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint16\",\"name\":\"\",\"type\":\"uint16\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"extensionName\",\"type\":\"string\"}],\"name\":\"getExtension\",\"outputs\":[{\"components\":[{\"components\":[{\"internalType\":\"string\",\"name\":\"name\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"metadataURI\",\"type\":\"string\"},{\"internalType\":\"address\",\"name\":\"implementation\",\"type\":\"address\"}],\"internalType\":\"struct IExtension.ExtensionMetadata\",\"name\":\"metadata\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"bytes4\",\"name\":\"functionSelector\",\"type\":\"bytes4\"},{\"internalType\":\"string\",\"name\":\"functionSignature\",\"type\":\"string\"}],\"internalType\":\"struct IExtension.ExtensionFunction[]\",\"name\":\"functions\",\"type\":\"tuple[]\"}],\"internalType\":\"struct IExtension.Extension\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"_functionSelector\",\"type\":\"bytes4\"}],\"name\":\"getImplementationForFunction\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"functionSelector\",\"type\":\"bytes4\"}],\"name\":\"getMetadataForFunction\",\"outputs\":[{\"components\":[{\"internalType\":\"string\",\"name\":\"name\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"metadataURI\",\"type\":\"string\"},{\"internalType\":\"address\",\"name\":\"implementation\",\"type\":\"address\"}],\"internalType\":\"struct IExtension.ExtensionMetadata\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleAdmin\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_tokenId\",\"type\":\"uint256\"}],\"name\":\"getRoyaltyInfoForToken\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint16\",\"name\":\"\",\"type\":\"uint16\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"grantRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"hasRole\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"hasRoleWithSwitch\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_defaultAdmin\",\"type\":\"address\"},{\"internalType\":\"string\",\"name\":\"_name\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"_symbol\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"_contractURI\",\"type\":\"string\"},{\"internalType\":\"address[]\",\"name\":\"_trustedForwarders\",\"type\":\"address[]\"},{\"internalType\":\"address\",\"name\":\"_saleRecipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_royaltyRecipient\",\"type\":\"address\"},{\"internalType\":\"uint128\",\"name\":\"_royaltyBps\",\"type\":\"uint128\"}],\"name\":\"initialize\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"}],\"name\":\"isApprovedForAll\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"isContractLocked\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"forwarder\",\"type\":\"address\"}],\"name\":\"isTrustedForwarder\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes[]\",\"name\":\"data\",\"type\":\"bytes[]\"}],\"name\":\"multicall\",\"outputs\":[{\"internalType\":\"bytes[]\",\"name\":\"results\",\"type\":\"bytes[]\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"name\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"nextTokenIdToClaim\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"nextTokenIdToMint\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"}],\"name\":\"ownerOf\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"primarySaleRecipient\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"_extensionName\",\"type\":\"string\"}],\"name\":\"removeExtension\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"renounceRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"components\":[{\"internalType\":\"string\",\"name\":\"name\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"metadataURI\",\"type\":\"string\"},{\"internalType\":\"address\",\"name\":\"implementation\",\"type\":\"address\"}],\"internalType\":\"struct IExtension.ExtensionMetadata\",\"name\":\"metadata\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"bytes4\",\"name\":\"functionSelector\",\"type\":\"bytes4\"},{\"internalType\":\"string\",\"name\":\"functionSignature\",\"type\":\"string\"}],\"internalType\":\"struct IExtension.ExtensionFunction[]\",\"name\":\"functions\",\"type\":\"tuple[]\"}],\"internalType\":\"struct IExtension.Extension\",\"name\":\"_extension\",\"type\":\"tuple\"}],\"name\":\"replaceExtension\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"revokeRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"salePrice\",\"type\":\"uint256\"}],\"name\":\"royaltyInfo\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"royaltyAmount\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"}],\"name\":\"safeTransferFrom\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"_data\",\"type\":\"bytes\"}],\"name\":\"safeTransferFrom\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"approved\",\"type\":\"bool\"}],\"name\":\"setApprovalForAll\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"_uri\",\"type\":\"string\"}],\"name\":\"setContractURI\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_royaltyRecipient\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_royaltyBps\",\"type\":\"uint256\"}],\"name\":\"setDefaultRoyaltyInfo\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_newOwner\",\"type\":\"address\"}],\"name\":\"setOwner\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_saleRecipient\",\"type\":\"address\"}],\"name\":\"setPrimarySaleRecipient\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_tokenId\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"_recipient\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_bps\",\"type\":\"uint256\"}],\"name\":\"setRoyaltyInfoForToken\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"startTokenId\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"symbol\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_tokenId\",\"type\":\"uint256\"}],\"name\":\"tokenURI\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"tokensOfOwner\",\"outputs\":[{\"internalType\":\"uint256[]\",\"name\":\"\",\"type\":\"uint256[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"start\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"stop\",\"type\":\"uint256\"}],\"name\":\"tokensOfOwnerIn\",\"outputs\":[{\"internalType\":\"uint256[]\",\"name\":\"\",\"type\":\"uint256[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"totalMinted\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"totalSupply\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"}],\"name\":\"transferFrom\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}]" + ); + } + + #region Common + + [Fact(Timeout = 120000)] + public async Task NullChecks() + { + var client = ThirdwebClient.Create(secretKey: this.SecretKey); + var contract = await ThirdwebContract.Create(client, this._tokenErc20ContractAddress, this._chainId); + var wallet = await this.GetSmartWallet(); + var testNFT = new NFT { Metadata = new NFTMetadata { Image = "image_url" } }; + var validAddress = "0x0000000000000000000000000000000000000000"; + + // GetMetadata + _ = await Assert.ThrowsAsync(() => ThirdwebExtensions.GetMetadata(null)); + + // GetNFTImageBytes + _ = await Assert.ThrowsAsync(() => ThirdwebExtensions.GetNFTImageBytes(testNFT, null)); + + // GetDefaultRoyaltyInfo + _ = await Assert.ThrowsAsync(() => ThirdwebExtensions.GetDefaultRoyaltyInfo(null)); + + // GetPrimarySaleRecipient + _ = await Assert.ThrowsAsync(() => ThirdwebExtensions.GetPrimarySaleRecipient(null)); + + // GetBalanceRaw + _ = await Assert.ThrowsAsync(() => ThirdwebExtensions.GetBalanceRaw(null, this._chainId, validAddress)); + _ = await Assert.ThrowsAsync(() => ThirdwebExtensions.GetBalanceRaw(client, 0, validAddress)); + _ = await Assert.ThrowsAsync(() => ThirdwebExtensions.GetBalanceRaw(client, this._chainId, null)); + + // GetBalance (contract) + _ = await Assert.ThrowsAsync(() => ThirdwebExtensions.GetBalance(null)); + + // GetBalance (wallet) + _ = await Assert.ThrowsAsync(() => ThirdwebExtensions.GetBalance(null, this._chainId)); + _ = await Assert.ThrowsAsync(() => ThirdwebExtensions.GetBalance(wallet, 0)); + + // Transfer + _ = await Assert.ThrowsAsync(() => ThirdwebExtensions.Transfer(null, this._chainId, validAddress, 0)); + _ = await Assert.ThrowsAsync(() => ThirdwebExtensions.Transfer(wallet, 0, validAddress, 0)); + _ = await Assert.ThrowsAsync(() => ThirdwebExtensions.Transfer(wallet, this._chainId, null, 0)); + _ = await Assert.ThrowsAsync(() => ThirdwebExtensions.Transfer(wallet, this._chainId, validAddress, -1)); + + // GetTransactionCountRaw + _ = await Assert.ThrowsAsync(() => ThirdwebExtensions.GetTransactionCountRaw(null, this._chainId, validAddress)); + _ = await Assert.ThrowsAsync(() => ThirdwebExtensions.GetTransactionCountRaw(client, 0, validAddress)); + _ = await Assert.ThrowsAsync(() => ThirdwebExtensions.GetTransactionCountRaw(client, this._chainId, null)); + + // GetTransactionCount + _ = await Assert.ThrowsAsync(() => ThirdwebExtensions.GetTransactionCount(null)); + _ = await Assert.ThrowsAsync(() => ThirdwebExtensions.GetTransactionCount(null, "latest")); + + // ERC721_TokenByIndex + _ = await Assert.ThrowsAsync(() => ThirdwebExtensions.ERC721_TokenByIndex(null, 0)); + + // SupportsInterface + _ = await Assert.ThrowsAsync(() => ThirdwebExtensions.SupportsInterface(null, "0x01ffc9a7")); + } + + [Fact(Timeout = 120000)] + public async Task SupportsInterface_ERC721() + { + var contract = await this.GetDrop721Contract(); + var supportsInterface = await contract.SupportsInterface(Constants.IERC721_INTERFACE_ID); + Assert.True(supportsInterface); + } + + [Fact(Timeout = 120000)] + public async Task SupportsInterface_ERC1155() + { + var contract = await this.GetDrop1155Contract(); + var supportsInterface = await contract.SupportsInterface(Constants.IERC1155_INTERFACE_ID); + Assert.True(supportsInterface); + } + + [Fact(Timeout = 120000)] + public async Task SupportsInterface_False() + { + var contract = await this.GetTokenERC20Contract(); + var supportsInterface = await contract.SupportsInterface(Constants.IERC721_INTERFACE_ID); + Assert.False(supportsInterface); + } + + [Fact(Timeout = 120000)] + public async Task GetMetadata() + { + var contract = await this.GetTokenERC20Contract(); + var metadata = await contract.GetMetadata(); + Assert.NotNull(metadata); + Assert.NotNull(metadata.Name); + Assert.NotEmpty(metadata.Name); + Assert.NotNull(metadata.Symbol); + Assert.NotEmpty(metadata.Symbol); + Assert.NotNull(metadata.Description); + Assert.NotEmpty(metadata.Description); + Assert.NotNull(metadata.Image); + Assert.NotEmpty(metadata.Image); + } + + [Fact(Timeout = 120000)] + public async Task GetNFTBytes_721() + { + var contract = await this.GetDrop721Contract(); + var nft = await contract.ERC721_GetNFT(0); + var bytes = await nft.GetNFTImageBytes(contract.Client); + Assert.NotNull(bytes); + Assert.NotEmpty(bytes); + } + + [Fact(Timeout = 120000)] + public async Task GetNFTBytes_1155() + { + var contract = await this.GetDrop1155Contract(); + var nft = await contract.ERC1155_GetNFT(0); + var bytes = await nft.GetNFTImageBytes(contract.Client); + Assert.NotNull(bytes); + Assert.NotEmpty(bytes); + } + + [Fact(Timeout = 120000)] + public async Task GetPrimarySaleRecipient() + { + var contract = await this.GetTokenERC20Contract(); + var primarySaleRecipient = await contract.GetPrimarySaleRecipient(); + Assert.NotNull(primarySaleRecipient); + Assert.NotEmpty(primarySaleRecipient); + } + + [Fact(Timeout = 120000)] + public async Task GetBalanceRaw() + { + var address = "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"; // vitalik.eth + var chainId = BigInteger.One; + var balance = await ThirdwebExtensions.GetBalanceRaw(this.Client, chainId, address); + Assert.True(balance >= 0); + } + + [Fact(Timeout = 120000)] + public async Task GetBalanceRaw_WithERC20() + { + var address = "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"; // vitalik.eth + var chainId = this._chainId; + var contractAddress = this._tokenErc20ContractAddress; + var balance = await ThirdwebExtensions.GetBalanceRaw(this.Client, chainId, address, contractAddress); + Assert.True(balance >= 0); + } + + [Fact(Timeout = 120000)] + public async Task GetBalance_Contract() + { + var contract = await this.GetTokenERC20Contract(); + var balance = await contract.GetBalance(); + Assert.True(balance >= 0); + } + + [Fact(Timeout = 120000)] + public async Task GetBalance_Contract_WithERC20() + { + var contract = await this.GetTokenERC20Contract(); + var balance = await contract.GetBalance(this._tokenErc20ContractAddress); + Assert.True(balance >= 0); + } + + [Fact(Timeout = 120000)] + public async Task GetBalance_Wallet() + { + _ = ThirdwebClient.Create(secretKey: this.SecretKey); + var wallet = await this.GetSmartWallet(); + var balance = await wallet.GetBalance(this._chainId); + Assert.True(balance >= 0); + } + + [Fact(Timeout = 120000)] + public async Task GetBalance_Wallet_WithERC20() + { + _ = ThirdwebClient.Create(secretKey: this.SecretKey); + var wallet = await this.GetSmartWallet(); + var balance = await wallet.GetBalance(this._chainId, this._tokenErc20ContractAddress); + Assert.True(balance >= 0); + } + + [Fact(Timeout = 120000)] + public async Task GetTransactionCountRaw() + { + var address = "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"; // vitalik.eth + var chainId = BigInteger.One; + var transactionCount = await ThirdwebExtensions.GetTransactionCountRaw(this.Client, chainId, address); + Assert.True(transactionCount >= 0); + } + + [Fact(Timeout = 120000)] + public async Task GetTransactionCountRaw_WithBlockTag() + { + var address = "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"; // vitalik.eth + var chainId = this._chainId; + var blockTag = "latest"; + var transactionCount = await ThirdwebExtensions.GetTransactionCountRaw(this.Client, chainId, address, blockTag); + Assert.True(transactionCount >= 0); + } + + [Fact(Timeout = 120000)] + public async Task GetTransactionCount_Contract() + { + var contract = await this.GetTokenERC20Contract(); + var transactionCount = await contract.GetTransactionCount(); + Assert.True(transactionCount >= 0); + } + + [Fact(Timeout = 120000)] + public async Task GetTransactionCount_Contract_WithBlockTag() + { + var contract = await this.GetTokenERC20Contract(); + var blockTag = "latest"; + var transactionCount = await contract.GetTransactionCount(blockTag); + Assert.True(transactionCount >= 0); + } + + [Fact(Timeout = 120000)] + public async Task GetTransactionCount_Wallet() + { + var wallet = await this.GetSmartWallet(); + var transactionCount = await wallet.GetTransactionCount(this._chainId); + Assert.True(transactionCount >= 0); + } + + [Fact(Timeout = 120000)] + public async Task GetTransactionCount_Wallet_WithBlockTag() + { + var wallet = await this.GetSmartWallet(); + var blockTag = "latest"; + var transactionCount = await wallet.GetTransactionCount(this._chainId, blockTag); + Assert.True(transactionCount >= 0); + } + + [Fact(Timeout = 120000)] + public async Task Transfer() + { + _ = ThirdwebClient.Create(secretKey: this.SecretKey); + var wallet = await this.GetSmartWallet(); + var toAddress = await wallet.GetAddress(); + var receipt = await wallet.Transfer(this._chainId, toAddress, BigInteger.Zero); + Assert.NotNull(receipt); + Assert.True(receipt.TransactionHash.Length == 66); + } + + [Fact(Timeout = 120000)] + public async Task TransferERC20Override() + { + var token = await this.GetTokenERC20Contract(); + var wallet = await this.GetSmartWallet(); + var receipt = await wallet.Transfer(this._chainId, await wallet.GetAddress(), BigInteger.Zero, token.Address); + Assert.NotNull(receipt); + Assert.True(receipt.TransactionHash.Length == 66); + } + + [Fact(Timeout = 120000)] + public async Task Contract_Read() + { + var contract = await this.GetTokenERC20Contract(); + var result = await contract.Read("name"); + Assert.NotNull(result); + Assert.NotEmpty(result); + } + + [Fact(Timeout = 120000)] + public async Task Contract_Write() + { + var contract = await this.GetTokenERC20Contract(); + var wallet = await this.GetSmartWallet(); + var receipt = await contract.Write(wallet, "approve", 0, contract.Address, BigInteger.Zero); + Assert.NotNull(receipt); + Assert.True(receipt.TransactionHash.Length == 66); + } + + [Fact(Timeout = 120000)] + public async Task Contract_Prepare() + { + var contract = await this.GetTokenERC20Contract(); + var wallet = await this.GetSmartWallet(); + var transaction = await contract.Prepare(wallet, "approve", 0, contract.Address, BigInteger.Zero); + Assert.NotNull(transaction); + Assert.NotNull(transaction.Input.Data); + Assert.NotNull(transaction.Input.To); + Assert.NotNull(transaction.Input.Value); + } + + #endregion + + #region ERC20 + + [Fact(Timeout = 120000)] + public async Task ERC20_NullChecks() + { + var client = ThirdwebClient.Create(secretKey: this.SecretKey); + var contract = await ThirdwebContract.Create(client, this._tokenErc20ContractAddress, this._chainId); + var wallet = await this.GetSmartWallet(); + var validAddress = "0x0000000000000000000000000000000000000000"; + + // ERC20_BalanceOf + _ = await Assert.ThrowsAsync(async () => await contract.ERC20_BalanceOf(null)); + _ = await Assert.ThrowsAsync(async () => await contract.ERC20_BalanceOf(string.Empty)); + + // ERC20_Allowance + _ = await Assert.ThrowsAsync(async () => await contract.ERC20_Allowance(null, null)); + _ = await Assert.ThrowsAsync(async () => await contract.ERC20_Allowance(string.Empty, null)); + _ = await Assert.ThrowsAsync(async () => await contract.ERC20_Allowance(null, string.Empty)); + _ = await Assert.ThrowsAsync(async () => await contract.ERC20_Allowance(validAddress, null)); + _ = await Assert.ThrowsAsync(async () => await contract.ERC20_Allowance(null, validAddress)); + + // ERC20_Approve + _ = await Assert.ThrowsAsync(async () => await contract.ERC20_Approve(null, null, BigInteger.Zero)); + _ = await Assert.ThrowsAsync(async () => await contract.ERC20_Approve(wallet, null, BigInteger.Zero)); + _ = await Assert.ThrowsAsync(async () => await contract.ERC20_Approve(wallet, string.Empty, BigInteger.Zero)); + + // ERC20_Transfer + _ = await Assert.ThrowsAsync(async () => await contract.ERC20_Transfer(null, null, BigInteger.Zero)); + _ = await Assert.ThrowsAsync(async () => await contract.ERC20_Transfer(wallet, null, BigInteger.Zero)); + _ = await Assert.ThrowsAsync(async () => await contract.ERC20_Transfer(wallet, string.Empty, BigInteger.Zero)); + + // ERC20_TransferFrom + _ = await Assert.ThrowsAsync(async () => await contract.ERC20_TransferFrom(null, null, null, BigInteger.Zero)); + _ = await Assert.ThrowsAsync(async () => await contract.ERC20_TransferFrom(wallet, null, null, BigInteger.Zero)); + _ = await Assert.ThrowsAsync(async () => await contract.ERC20_TransferFrom(wallet, string.Empty, null, BigInteger.Zero)); + _ = await Assert.ThrowsAsync(async () => await contract.ERC20_TransferFrom(wallet, validAddress, null, BigInteger.Zero)); + _ = await Assert.ThrowsAsync(async () => await contract.ERC20_TransferFrom(wallet, validAddress, string.Empty, BigInteger.Zero)); + + // Null wallet checks + wallet = null; + + _ = await Assert.ThrowsAsync(async () => await contract.ERC20_Approve(wallet, validAddress, BigInteger.Zero)); + _ = await Assert.ThrowsAsync(async () => await contract.ERC20_Transfer(wallet, validAddress, BigInteger.Zero)); + _ = await Assert.ThrowsAsync(async () => await contract.ERC20_TransferFrom(wallet, validAddress, validAddress, BigInteger.Zero)); + + // Null contract checks + contract = null; + + _ = await Assert.ThrowsAsync(async () => await contract.ERC20_BalanceOf(validAddress)); + _ = await Assert.ThrowsAsync(async () => await contract.ERC20_TotalSupply()); + _ = await Assert.ThrowsAsync(async () => await contract.ERC20_Decimals()); + _ = await Assert.ThrowsAsync(async () => await contract.ERC20_Symbol()); + _ = await Assert.ThrowsAsync(async () => await contract.ERC20_Name()); + _ = await Assert.ThrowsAsync(async () => await contract.ERC20_Allowance(validAddress, validAddress)); + _ = await Assert.ThrowsAsync(async () => await contract.ERC20_Approve(wallet, validAddress, BigInteger.Zero)); + _ = await Assert.ThrowsAsync(async () => await contract.ERC20_Transfer(wallet, validAddress, BigInteger.Zero)); + _ = await Assert.ThrowsAsync(async () => await contract.ERC20_TransferFrom(wallet, validAddress, validAddress, BigInteger.Zero)); + } + + [Fact(Timeout = 120000)] + public async Task ERC20_BalanceOf() + { + var contract = await this.GetTokenERC20Contract(); + var ownerAddress = Constants.ADDRESS_ZERO; + var balance = await contract.ERC20_BalanceOf(ownerAddress); + Assert.True(balance >= 0); + } + + [Fact(Timeout = 120000)] + public async Task ERC20_TotalSupply() + { + var contract = await this.GetTokenERC20Contract(); + var totalSupply = await contract.ERC20_TotalSupply(); + Assert.True(totalSupply > 0); + } + + [Fact(Timeout = 120000)] + public async Task ERC20_Decimals() + { + var contract = await this.GetTokenERC20Contract(); + var decimals = await contract.ERC20_Decimals(); + Assert.InRange(decimals, 0, 18); + } + + [Fact(Timeout = 120000)] + public async Task ERC20_Symbol() + { + var contract = await this.GetTokenERC20Contract(); + var symbol = await contract.ERC20_Symbol(); + Assert.False(string.IsNullOrEmpty(symbol)); + } + + [Fact(Timeout = 120000)] + public async Task ERC20_Name() + { + var contract = await this.GetTokenERC20Contract(); + var name = await contract.ERC20_Name(); + Assert.False(string.IsNullOrEmpty(name)); + } + + [Fact(Timeout = 120000)] + public async Task ERC20_Allowance() + { + var contract = await this.GetTokenERC20Contract(); + var ownerAddress = Constants.ADDRESS_ZERO; + var spenderAddress = contract.Address; + var allowance = await contract.ERC20_Allowance(ownerAddress, spenderAddress); + Assert.True(allowance >= 0); + } + + [Fact(Timeout = 120000)] + public async Task ERC20_Approve() + { + var contract = await this.GetTokenERC20Contract(); + var wallet = await this.GetSmartWallet(); + var spenderAddress = contract.Address; + var amount = BigInteger.Parse("1000000000000000000"); + var receipt = await contract.ERC20_Approve(wallet, spenderAddress, amount); + Assert.True(receipt.TransactionHash.Length == 66); + } + + #endregion + + #region ERC721A + + [Fact(Timeout = 120000)] + public async Task ERC721A_TokensOfOwner() + { + var contract = await this.GetERC721AContract(); + var ownerAddress = "0x10a798EC43A776c39BA19978EDb6e4a7706326FA"; + var tokens = await contract.ERC721A_TokensOfOwner(ownerAddress); + Assert.NotNull(tokens); + Assert.NotEmpty(tokens); + } + + [Fact(Timeout = 120000)] + public async Task ERC721A_TokensOfOwnerIn() + { + var contract = await this.GetERC721AContract(); + var ownerAddress = "0x10a798EC43A776c39BA19978EDb6e4a7706326FA"; + var tokens = await contract.ERC721A_TokensOfOwnerIn(ownerAddress, 0, 1); + Assert.NotNull(tokens); + Assert.NotEmpty(tokens); + } + + #endregion + + #region ERC721 + + [Fact(Timeout = 120000)] + public async Task ERC721_NullChecks() + { + var client = ThirdwebClient.Create(secretKey: this.SecretKey); + var contract = await ThirdwebContract.Create(client, this._tokenErc721ContractAddress, this._chainId); + var wallet = await this.GetSmartWallet(); + var validAddress = "0x0000000000000000000000000000000000000000"; + + // ERC721_BalanceOf + _ = await Assert.ThrowsAsync(async () => await contract.ERC721_BalanceOf(null)); + _ = await Assert.ThrowsAsync(async () => await contract.ERC721_BalanceOf(string.Empty)); + + // ERC721_OwnerOf + _ = await Assert.ThrowsAsync(async () => await contract.ERC721_OwnerOf(BigInteger.MinusOne)); + + // ERC721_TokenURI + _ = await Assert.ThrowsAsync(async () => await contract.ERC721_TokenURI(BigInteger.MinusOne)); + + // ERC721_Approve + _ = await Assert.ThrowsAsync(async () => await contract.ERC721_Approve(null, null, BigInteger.Zero)); + _ = await Assert.ThrowsAsync(async () => await contract.ERC721_Approve(wallet, null, BigInteger.Zero)); + _ = await Assert.ThrowsAsync(async () => await contract.ERC721_Approve(wallet, string.Empty, BigInteger.Zero)); + + // ERC721_GetApproved + _ = await Assert.ThrowsAsync(async () => await contract.ERC721_GetApproved(BigInteger.MinusOne)); + + // ERC721_IsApprovedForAll + _ = await Assert.ThrowsAsync(async () => await contract.ERC721_IsApprovedForAll(null, null)); + _ = await Assert.ThrowsAsync(async () => await contract.ERC721_IsApprovedForAll(string.Empty, null)); + _ = await Assert.ThrowsAsync(async () => await contract.ERC721_IsApprovedForAll(validAddress, null)); + _ = await Assert.ThrowsAsync(async () => await contract.ERC721_IsApprovedForAll(validAddress, string.Empty)); + + // ERC721_SetApprovalForAll + _ = await Assert.ThrowsAsync(async () => await contract.ERC721_SetApprovalForAll(null, null, false)); + _ = await Assert.ThrowsAsync(async () => await contract.ERC721_SetApprovalForAll(wallet, null, false)); + _ = await Assert.ThrowsAsync(async () => await contract.ERC721_SetApprovalForAll(wallet, string.Empty, false)); + + // ERC721_TransferFrom + _ = await Assert.ThrowsAsync(async () => await contract.ERC721_TransferFrom(null, null, null, BigInteger.Zero)); + _ = await Assert.ThrowsAsync(async () => await contract.ERC721_TransferFrom(wallet, null, null, BigInteger.Zero)); + _ = await Assert.ThrowsAsync(async () => await contract.ERC721_TransferFrom(wallet, string.Empty, null, BigInteger.Zero)); + _ = await Assert.ThrowsAsync(async () => await contract.ERC721_TransferFrom(wallet, validAddress, null, BigInteger.Zero)); + _ = await Assert.ThrowsAsync(async () => await contract.ERC721_TransferFrom(wallet, validAddress, string.Empty, BigInteger.Zero)); + + // ERC721_SafeTransferFrom + _ = await Assert.ThrowsAsync(async () => await contract.ERC721_SafeTransferFrom(null, null, null, BigInteger.Zero)); + _ = await Assert.ThrowsAsync(async () => await contract.ERC721_SafeTransferFrom(wallet, null, null, BigInteger.Zero)); + _ = await Assert.ThrowsAsync(async () => await contract.ERC721_SafeTransferFrom(wallet, string.Empty, null, BigInteger.Zero)); + _ = await Assert.ThrowsAsync(async () => await contract.ERC721_SafeTransferFrom(wallet, validAddress, null, BigInteger.Zero)); + _ = await Assert.ThrowsAsync(async () => await contract.ERC721_SafeTransferFrom(wallet, validAddress, string.Empty, BigInteger.Zero)); + + // ERC721_TokenOfOwnerByIndex + _ = await Assert.ThrowsAsync(async () => await contract.ERC721_TokenOfOwnerByIndex(null, BigInteger.Zero)); + _ = await Assert.ThrowsAsync(async () => await contract.ERC721_TokenOfOwnerByIndex(string.Empty, BigInteger.Zero)); + + // Null wallet checks + wallet = null; + + _ = await Assert.ThrowsAsync(async () => await contract.ERC721_Approve(wallet, validAddress, BigInteger.Zero)); + _ = await Assert.ThrowsAsync(async () => await contract.ERC721_SetApprovalForAll(wallet, validAddress, false)); + _ = await Assert.ThrowsAsync(async () => await contract.ERC721_TransferFrom(wallet, validAddress, validAddress, BigInteger.Zero)); + _ = await Assert.ThrowsAsync(async () => await contract.ERC721_SafeTransferFrom(wallet, validAddress, validAddress, BigInteger.Zero)); + + // Null contract checks + contract = null; + + _ = await Assert.ThrowsAsync(async () => await contract.ERC721_BalanceOf(validAddress)); + _ = await Assert.ThrowsAsync(async () => await contract.ERC721_OwnerOf(BigInteger.Zero)); + _ = await Assert.ThrowsAsync(async () => await contract.ERC721_Name()); + _ = await Assert.ThrowsAsync(async () => await contract.ERC721_Symbol()); + _ = await Assert.ThrowsAsync(async () => await contract.ERC721_TokenURI(BigInteger.Zero)); + _ = await Assert.ThrowsAsync(async () => await contract.ERC721_GetApproved(BigInteger.Zero)); + _ = await Assert.ThrowsAsync(async () => await contract.ERC721_IsApprovedForAll(validAddress, validAddress)); + _ = await Assert.ThrowsAsync(async () => await contract.ERC721_SetApprovalForAll(wallet, validAddress, false)); + _ = await Assert.ThrowsAsync(async () => await contract.ERC721_TransferFrom(wallet, validAddress, validAddress, BigInteger.Zero)); + _ = await Assert.ThrowsAsync(async () => await contract.ERC721_SafeTransferFrom(wallet, validAddress, validAddress, BigInteger.Zero)); + _ = await Assert.ThrowsAsync(async () => await contract.ERC721_Approve(wallet, validAddress, BigInteger.Zero)); + _ = await Assert.ThrowsAsync(async () => await contract.ERC721_TokenOfOwnerByIndex(validAddress, BigInteger.Zero)); + } + + [Fact(Timeout = 120000)] + public async Task ERC721_BalanceOf() + { + var contract = await this.GetTokenERC721Contract(); + var wallet = await this.GetSmartWallet(); + var ownerAddress = await wallet.GetAddress(); + var balance = await contract.ERC721_BalanceOf(ownerAddress); + Assert.True(balance >= 0); + } + + [Fact(Timeout = 120000)] + public async Task ERC721_OwnerOf() + { + var contract = await this.GetTokenERC721Contract(); + var tokenId = BigInteger.Parse("1"); + var owner = await contract.ERC721_OwnerOf(tokenId); + Assert.False(string.IsNullOrEmpty(owner)); + } + + [Fact(Timeout = 120000)] + public async Task ERC721_Name() + { + var contract = await this.GetTokenERC721Contract(); + var name = await contract.ERC721_Name(); + Assert.False(string.IsNullOrEmpty(name)); + } + + [Fact(Timeout = 120000)] + public async Task ERC721_Symbol() + { + var contract = await this.GetTokenERC721Contract(); + var symbol = await contract.ERC721_Symbol(); + Assert.False(string.IsNullOrEmpty(symbol)); + } + + [Fact(Timeout = 120000)] + public async Task ERC721_TokenURI() + { + var contract = await this.GetTokenERC721Contract(); + var tokenId = BigInteger.Parse("1"); + var uri = await contract.ERC721_TokenURI(tokenId); + Assert.False(string.IsNullOrEmpty(uri)); + } + + [Fact(Timeout = 120000)] + public async Task ERC721_GetApproved() + { + var contract = await this.GetTokenERC721Contract(); + var tokenId = BigInteger.Parse("1"); + var approved = await contract.ERC721_GetApproved(tokenId); + Assert.False(string.IsNullOrEmpty(approved)); + } + + [Fact(Timeout = 120000)] + public async Task ERC721_IsApprovedForAll() + { + var contract = await this.GetTokenERC721Contract(); + var ownerAddress = Constants.ADDRESS_ZERO; + var operatorAddress = contract.Address; + var isApproved = await contract.ERC721_IsApprovedForAll(ownerAddress, operatorAddress); + Assert.True(isApproved || !isApproved); + } + + [Fact(Timeout = 120000)] + public async Task ERC721_TotalSupply() + { + var contract = await this.GetTokenERC721Contract(); + var totalSupply = await contract.ERC721_TotalSupply(); + Assert.True(totalSupply >= 0); + } + + [Fact(Timeout = 120000)] + public async Task ERC721_TokenOfOwnerByIndex() + { + var contract = await this.GetTokenERC721Contract(); + var ownerAddress = "0xE33653ce510Ee767d8824b5EcDeD27125D49889D"; + var index = BigInteger.Zero; + var tokenId = await contract.ERC721_TokenOfOwnerByIndex(ownerAddress, index); + Assert.True(tokenId >= 0); + } + + [Fact(Timeout = 120000)] + public async Task ERC721_SetApprovalForAll() + { + var contract = await this.GetTokenERC721Contract(); + var wallet = await this.GetSmartWallet(); + var operatorAddress = contract.Address; + var approved = true; + var receipt = await contract.ERC721_SetApprovalForAll(wallet, operatorAddress, approved); + Assert.True(receipt.TransactionHash.Length == 66); + } + + #endregion + + #region ERC1155 + + [Fact(Timeout = 120000)] + public async Task ERC1155_NullChecks() + { + var client = ThirdwebClient.Create(secretKey: this.SecretKey); + var contract = await ThirdwebContract.Create(client, this._tokenErc1155ContractAddress, this._chainId); + var wallet = await this.GetSmartWallet(); + var validAddress = "0x0000000000000000000000000000000000000000"; + var validTokenId = BigInteger.One; + var validAmount = BigInteger.One; + var validData = Array.Empty(); + + // ERC1155_BalanceOf + _ = await Assert.ThrowsAsync(async () => await contract.ERC1155_BalanceOf(null, validTokenId)); + _ = await Assert.ThrowsAsync(async () => await contract.ERC1155_BalanceOf(string.Empty, validTokenId)); + _ = await Assert.ThrowsAsync(async () => await contract.ERC1155_BalanceOf(validAddress, BigInteger.MinusOne)); + + // ERC1155_BalanceOfBatch + _ = await Assert.ThrowsAsync(async () => await contract.ERC1155_BalanceOfBatch(null, new BigInteger[] { validTokenId })); + _ = await Assert.ThrowsAsync(async () => await contract.ERC1155_BalanceOfBatch(new string[] { validAddress }, null)); + + // ERC1155_SetApprovalForAll + _ = await Assert.ThrowsAsync(async () => await contract.ERC1155_SetApprovalForAll(null, null, false)); + _ = await Assert.ThrowsAsync(async () => await contract.ERC1155_SetApprovalForAll(wallet, null, false)); + _ = await Assert.ThrowsAsync(async () => await contract.ERC1155_SetApprovalForAll(wallet, string.Empty, false)); + + // ERC1155_IsApprovedForAll + _ = await Assert.ThrowsAsync(async () => await contract.ERC1155_IsApprovedForAll(null, null)); + _ = await Assert.ThrowsAsync(async () => await contract.ERC1155_IsApprovedForAll(string.Empty, null)); + _ = await Assert.ThrowsAsync(async () => await contract.ERC1155_IsApprovedForAll(validAddress, null)); + _ = await Assert.ThrowsAsync(async () => await contract.ERC1155_IsApprovedForAll(validAddress, string.Empty)); + + // ERC1155_SafeTransferFrom + _ = await Assert.ThrowsAsync(async () => await contract.ERC1155_SafeTransferFrom(null, null, null, validTokenId, validAmount, validData)); + _ = await Assert.ThrowsAsync(async () => await contract.ERC1155_SafeTransferFrom(wallet, null, null, validTokenId, validAmount, validData)); + _ = await Assert.ThrowsAsync(async () => await contract.ERC1155_SafeTransferFrom(wallet, string.Empty, null, validTokenId, validAmount, validData)); + _ = await Assert.ThrowsAsync(async () => await contract.ERC1155_SafeTransferFrom(wallet, validAddress, null, validTokenId, validAmount, validData)); + _ = await Assert.ThrowsAsync(async () => await contract.ERC1155_SafeTransferFrom(wallet, validAddress, string.Empty, validTokenId, validAmount, validData)); + _ = await Assert.ThrowsAsync(async () => await contract.ERC1155_SafeTransferFrom(wallet, validAddress, validAddress, BigInteger.MinusOne, validAmount, validData)); + + // ERC1155_SafeBatchTransferFrom + _ = await Assert.ThrowsAsync(async () => + await contract.ERC1155_SafeBatchTransferFrom(null, null, null, new BigInteger[] { validTokenId }, new BigInteger[] { validAmount }, validData) + ); + _ = await Assert.ThrowsAsync(async () => + await contract.ERC1155_SafeBatchTransferFrom(wallet, null, null, new BigInteger[] { validTokenId }, new BigInteger[] { validAmount }, validData) + ); + _ = await Assert.ThrowsAsync(async () => + await contract.ERC1155_SafeBatchTransferFrom(wallet, string.Empty, null, new BigInteger[] { validTokenId }, new BigInteger[] { validAmount }, validData) + ); + _ = await Assert.ThrowsAsync(async () => + await contract.ERC1155_SafeBatchTransferFrom(wallet, validAddress, null, new BigInteger[] { validTokenId }, new BigInteger[] { validAmount }, validData) + ); + _ = await Assert.ThrowsAsync(async () => + await contract.ERC1155_SafeBatchTransferFrom(wallet, validAddress, string.Empty, new BigInteger[] { validTokenId }, new BigInteger[] { validAmount }, validData) + ); + _ = await Assert.ThrowsAsync(async () => + await contract.ERC1155_SafeBatchTransferFrom(wallet, validAddress, validAddress, null, new BigInteger[] { validAmount }, validData) + ); + _ = await Assert.ThrowsAsync(async () => + await contract.ERC1155_SafeBatchTransferFrom(wallet, validAddress, validAddress, new BigInteger[] { validTokenId }, null, validData) + ); + + // ERC1155_URI + _ = await Assert.ThrowsAsync(async () => await contract.ERC1155_URI(BigInteger.MinusOne)); + + // ERC1155_TotalSupply (with tokenId) + _ = await Assert.ThrowsAsync(async () => await contract.ERC1155_TotalSupply(BigInteger.MinusOne)); + + // Null wallet checks + wallet = null; + + _ = await Assert.ThrowsAsync(async () => await contract.ERC1155_SetApprovalForAll(wallet, validAddress, false)); + _ = await Assert.ThrowsAsync(async () => await contract.ERC1155_SafeTransferFrom(wallet, validAddress, validAddress, validTokenId, validAmount, validData)); + _ = await Assert.ThrowsAsync(async () => + await contract.ERC1155_SafeBatchTransferFrom(wallet, validAddress, validAddress, new BigInteger[] { validTokenId }, new BigInteger[] { validAmount }, validData) + ); + + // Null contract checks + contract = null; + + _ = await Assert.ThrowsAsync(async () => await contract.ERC1155_BalanceOf(validAddress, validTokenId)); + _ = await Assert.ThrowsAsync(async () => await contract.ERC1155_BalanceOfBatch(new string[] { validAddress }, new BigInteger[] { validTokenId })); + _ = await Assert.ThrowsAsync(async () => await contract.ERC1155_SetApprovalForAll(wallet, validAddress, false)); + _ = await Assert.ThrowsAsync(async () => await contract.ERC1155_IsApprovedForAll(validAddress, validAddress)); + _ = await Assert.ThrowsAsync(async () => await contract.ERC1155_SafeTransferFrom(wallet, validAddress, validAddress, validTokenId, validAmount, validData)); + _ = await Assert.ThrowsAsync(async () => + await contract.ERC1155_SafeBatchTransferFrom(wallet, validAddress, validAddress, new BigInteger[] { validTokenId }, new BigInteger[] { validAmount }, validData) + ); + _ = await Assert.ThrowsAsync(async () => await contract.ERC1155_URI(validTokenId)); + _ = await Assert.ThrowsAsync(async () => await contract.ERC1155_TotalSupply(validTokenId)); + _ = await Assert.ThrowsAsync(async () => await contract.ERC1155_TotalSupply()); + } + + [Fact(Timeout = 120000)] + public async Task ERC1155_BalanceOf() + { + var contract = await this.GetTokenERC1155Contract(); + var wallet = await this.GetSmartWallet(); + var ownerAddress = await wallet.GetAddress(); + var tokenId = BigInteger.Parse("1"); + var balance = await contract.ERC1155_BalanceOf(ownerAddress, tokenId); + Assert.True(balance >= 0); + } + + [Fact(Timeout = 120000)] + public async Task ERC1155_BalanceOfBatch() + { + var contract = await this.GetTokenERC1155Contract(); + var wallet = await this.GetSmartWallet(); + var ownerAddresses = new string[] { await wallet.GetAddress(), await wallet.GetAddress() }; + var tokenIds = new BigInteger[] { BigInteger.Parse("1"), BigInteger.Parse("2") }; + var balances = await contract.ERC1155_BalanceOfBatch(ownerAddresses, tokenIds); + Assert.True(balances.Count == ownerAddresses.Length); + } + + [Fact(Timeout = 120000)] + public async Task ERC1155_IsApprovedForAll() + { + var contract = await this.GetTokenERC1155Contract(); + var ownerAddress = Constants.ADDRESS_ZERO; + var operatorAddress = contract.Address; + var isApproved = await contract.ERC1155_IsApprovedForAll(ownerAddress, operatorAddress); + Assert.True(isApproved || !isApproved); + } + + [Fact(Timeout = 120000)] + public async Task ERC1155_URI() + { + var contract = await this.GetTokenERC1155Contract(); + var tokenId = BigInteger.Parse("1"); + var uri = await contract.ERC1155_URI(tokenId); + Assert.False(string.IsNullOrEmpty(uri)); + } + + [Fact(Timeout = 120000)] + public async Task ERC1155_SetApprovalForAll() + { + var contract = await this.GetTokenERC1155Contract(); + var wallet = await this.GetSmartWallet(); + var operatorAddress = contract.Address; + var approved = true; + var receipt = await contract.ERC1155_SetApprovalForAll(wallet, operatorAddress, approved); + Assert.True(receipt.TransactionHash.Length == 66); + } + + [Fact(Timeout = 120000)] + public async Task ERC1155_TotalSupply() + { + var contract = await this.GetTokenERC1155Contract(); + var totalSupply = await contract.ERC1155_TotalSupply(); + Assert.True(totalSupply >= 0); + } + + [Fact(Timeout = 120000)] + public async Task ERC1155_TotalSupply_WithTokenId() + { + var contract = await this.GetTokenERC1155Contract(); + var tokenId = BigInteger.Parse("1"); + var totalSupply = await contract.ERC1155_TotalSupply(tokenId); + Assert.True(totalSupply >= 0); + } + + #endregion + + #region NFT + + [Fact(Timeout = 120000)] + public async Task NFT_NullChecks() + { + var client = ThirdwebClient.Create(secretKey: this.SecretKey); + var contract721 = await this.GetTokenERC721Contract(); + var contract1155 = await this.GetTokenERC1155Contract(); + + // ERC721 Null Checks + _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.ERC721_GetNFT(null, BigInteger.Zero)); + _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.ERC721_GetAllNFTs(null)); + _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.ERC721_GetOwnedNFTs(null, "owner")); + _ = await Assert.ThrowsAsync(async () => await contract721.ERC721_GetOwnedNFTs(null)); + _ = await Assert.ThrowsAsync(async () => await contract721.ERC721_GetOwnedNFTs(string.Empty)); + + // ERC1155 Null Checks + _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.ERC1155_GetNFT(null, BigInteger.Zero)); + _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.ERC1155_GetAllNFTs(null)); + _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.ERC1155_GetOwnedNFTs(null, "owner")); + _ = await Assert.ThrowsAsync(async () => await contract1155.ERC1155_GetOwnedNFTs(null)); + _ = await Assert.ThrowsAsync(async () => await contract1155.ERC1155_GetOwnedNFTs(string.Empty)); + + // ERC721 Token ID Out of Range Checks + _ = await Assert.ThrowsAsync(async () => await contract721.ERC721_GetNFT(BigInteger.MinusOne)); + + // ERC1155 Token ID Out of Range Checks + _ = await Assert.ThrowsAsync(async () => await contract1155.ERC1155_GetNFT(BigInteger.MinusOne)); + + // Null contract checks + contract721 = null; + _ = await Assert.ThrowsAsync(async () => await contract721.ERC721_GetNFT(0)); + _ = await Assert.ThrowsAsync(async () => await contract721.ERC721_GetAllNFTs()); + _ = await Assert.ThrowsAsync(async () => await contract721.ERC721_GetOwnedNFTs("owner")); + + contract1155 = null; + _ = await Assert.ThrowsAsync(async () => await contract1155.ERC1155_GetNFT(0)); + _ = await Assert.ThrowsAsync(async () => await contract1155.ERC1155_GetAllNFTs()); + _ = await Assert.ThrowsAsync(async () => await contract1155.ERC1155_GetOwnedNFTs("owner")); + } + + [Fact(Timeout = 120000)] + public async Task GetNFT_721() + { + var contract = await this.GetTokenERC721Contract(); + var nft = await contract.ERC721_GetNFT(0); + Assert.NotNull(nft.Owner); + Assert.NotEmpty(nft.Owner); + Assert.Equal(NFTType.ERC721, nft.Type); + Assert.True(nft.Supply == 1); + Assert.True(nft.QuantityOwned == 1); + } + + [Fact(Timeout = 120000)] + public async Task GetNFT_721_NoOwner() + { + var contract = await this.GetTokenERC721Contract(); + var nft = await contract.ERC721_GetNFT(0, false); + Assert.Equal(Constants.ADDRESS_ZERO, nft.Owner); + Assert.Equal(NFTType.ERC721, nft.Type); + Assert.True(nft.Supply == 1); + Assert.True(nft.QuantityOwned == 1); + } + + [Fact(Timeout = 120000)] + public async Task GetAllNFTs_721() + { + var contract = await this.GetTokenERC721Contract(); + var nfts = await contract.ERC721_GetAllNFTs(); + Assert.NotNull(nfts); + Assert.NotEmpty(nfts); + } + + [Fact(Timeout = 120000)] + public async Task GetAllNFTs_721_NoOwner() + { + var contract = await this.GetTokenERC721Contract(); + var nfts = await contract.ERC721_GetAllNFTs(fillOwner: false); + Assert.NotNull(nfts); + Assert.NotEmpty(nfts); + Assert.True(nfts.All(nft => nft.Owner == Constants.ADDRESS_ZERO)); + } + + [Fact(Timeout = 120000)] + public async Task GetAllNFTs_721_ExceedTotalSupply() + { + var contract = await this.GetTokenERC721Contract(); + var allNfts = await contract.ERC721_GetAllNFTs(); + var nfts = await contract.ERC721_GetAllNFTs(0, int.MaxValue); + Assert.NotNull(nfts); + Assert.NotEmpty(nfts); + Assert.True(nfts.Count == allNfts.Count); + } + + [Fact(Timeout = 120000)] + public async Task GetAllNFTs_721_WithRange() + { + var contract = await this.GetTokenERC721Contract(); + var nfts = await contract.ERC721_GetAllNFTs(1, 2); + Assert.NotNull(nfts); + Assert.NotEmpty(nfts); + } + + [Fact(Timeout = 120000)] + public async Task GetOwnedNFTs_721() + { + var contract = await this.GetTokenERC721Contract(); + var ownerAddress = contract.Address; + var nfts = await contract.ERC721_GetOwnedNFTs(ownerAddress); + Assert.NotNull(nfts); + } + + [Fact(Timeout = 120000)] + public async Task GetOwnedNFTs_721_ExceedTotalSupply() + { + var contract = await this.GetTokenERC721Contract(); + var ownerAddress = contract.Address; + var allNfts = await contract.ERC721_GetOwnedNFTs(ownerAddress); + var nfts = await contract.ERC721_GetOwnedNFTs(ownerAddress, 0, int.MaxValue); + Assert.NotNull(nfts); + Assert.True(nfts.Count == allNfts.Count); + } + + [Fact(Timeout = 120000)] + public async Task GetOwnedNFTs_721_WithRange() + { + var contract = await this.GetTokenERC721Contract(); + var ownerAddress = contract.Address; + var nfts = await contract.ERC721_GetOwnedNFTs(ownerAddress, 1, 2); + Assert.NotNull(nfts); + } + + [Fact(Timeout = 120000)] + public async Task GetOwnedNFTs_721A() + { + var contract = await this.GetERC721AContract(); + var ownerAddress = "0x10a798EC43A776c39BA19978EDb6e4a7706326FA"; + var nfts = await contract.ERC721_GetOwnedNFTs(ownerAddress); + Assert.NotNull(nfts); + Assert.True(nfts.Count > 0); + } + + [Fact(Timeout = 120000)] + public async Task GetOwnedNFTs_721A_WithRange() + { + var contract = await this.GetERC721AContract(); + var ownerAddress = "0x10a798EC43A776c39BA19978EDb6e4a7706326FA"; + var nfts = await contract.ERC721_GetOwnedNFTs(ownerAddress, 0, 280); + Assert.NotNull(nfts); + Assert.True(nfts.Count == 2); + + nfts = await contract.ERC721_GetOwnedNFTs(ownerAddress, 0, 1); + Assert.NotNull(nfts); + Assert.True(nfts.Count == 1); + } + + [Fact(Timeout = 120000)] + public async Task GetNFT_1155() + { + var contract = await this.GetTokenERC1155Contract(); + var nft = await contract.ERC1155_GetNFT(0); + Assert.Equal(NFTType.ERC1155, nft.Type); + Assert.True(nft.Supply >= 0); + } + + [Fact(Timeout = 120000)] + public async Task GetNFT_1155_NoSupply() + { + var contract = await this.GetTokenERC1155Contract(); + var nft = await contract.ERC1155_GetNFT(0, false); + Assert.Equal(NFTType.ERC1155, nft.Type); + Assert.True(nft.Supply == -1); + } + + [Fact(Timeout = 120000)] + public async Task GetAllNFTs_1155() + { + var contract = await this.GetTokenERC1155Contract(); + var nfts = await contract.ERC1155_GetAllNFTs(); + Assert.NotNull(nfts); + Assert.NotEmpty(nfts); + } + + [Fact(Timeout = 120000)] + public async Task GetAllNFTs_1155_NoSupply() + { + var contract = await this.GetTokenERC1155Contract(); + var nfts = await contract.ERC1155_GetAllNFTs(fillSupply: false); + Assert.NotNull(nfts); + Assert.NotEmpty(nfts); + Assert.True(nfts.All(nft => nft.Supply == -1)); + } + + [Fact(Timeout = 120000)] + public async Task GetAllNFTs_1155_ExceedTotalSupply() + { + var contract = await this.GetTokenERC1155Contract(); + var allNfts = await contract.ERC1155_GetAllNFTs(); + var nfts = await contract.ERC1155_GetAllNFTs(0, int.MaxValue); + Assert.NotNull(nfts); + Assert.NotEmpty(nfts); + Assert.True(nfts.Count == allNfts.Count); + } + + [Fact(Timeout = 120000)] + public async Task GetAllNFTs_1155_WithRange() + { + var contract = await this.GetTokenERC1155Contract(); + var nfts = await contract.ERC1155_GetAllNFTs(1, 2); + Assert.NotNull(nfts); + Assert.NotEmpty(nfts); + } + + [Fact(Timeout = 120000)] + public async Task GetOwnedNFTs_1155() + { + var contract = await this.GetTokenERC1155Contract(); + var ownerAddress = contract.Address; + var nfts = await contract.ERC1155_GetOwnedNFTs(ownerAddress); + Assert.NotNull(nfts); + } + + [Fact(Timeout = 120000)] + public async Task GetOwnedNFTs_1155_ExceedTotalSupply() + { + var contract = await this.GetTokenERC1155Contract(); + var ownerAddress = contract.Address; + var allNfts = await contract.ERC1155_GetOwnedNFTs(ownerAddress); + var nfts = await contract.ERC1155_GetOwnedNFTs(ownerAddress, 0, int.MaxValue); + Assert.NotNull(nfts); + Assert.True(nfts.Count == allNfts.Count); + } + + [Fact(Timeout = 120000)] + public async Task GetOwnedNFTs_1155_WithRange() + { + var contract = await this.GetTokenERC1155Contract(); + var ownerAddress = contract.Address; + var nfts = await contract.ERC1155_GetOwnedNFTs(ownerAddress, 1, 2); + Assert.NotNull(nfts); + } + + #endregion + + #region DropERC20 + + [Fact(Timeout = 120000)] + public async Task DropERC20_NullChecks() + { + var client = ThirdwebClient.Create(secretKey: this.SecretKey); + var contract = await ThirdwebContract.Create(client, this._dropErc20ContractAddress, this._chainId); + var wallet = await this.GetSmartWallet(); + var validAddress = "0x0000000000000000000000000000000000000000"; + var validAmount = "10"; + var validClaimConditionId = BigInteger.One; + var invalidClaimConditionId = BigInteger.MinusOne; + + // DropERC20_Claim null checks + _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.DropERC20_Claim(null, wallet, validAddress, validAmount)); + _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.DropERC20_Claim(contract, null, validAddress, validAmount)); + _ = await Assert.ThrowsAsync(async () => await contract.DropERC20_Claim(wallet, null, validAmount)); + _ = await Assert.ThrowsAsync(async () => await contract.DropERC20_Claim(wallet, string.Empty, validAmount)); + _ = await Assert.ThrowsAsync(async () => await contract.DropERC20_Claim(wallet, validAddress, null)); + _ = await Assert.ThrowsAsync(async () => await contract.DropERC20_Claim(wallet, validAddress, string.Empty)); + + // DropERC20_GetActiveClaimConditionId null checks + _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.DropERC20_GetActiveClaimConditionId(null)); + + // DropERC20_GetClaimConditionById null and out of range checks + _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.DropERC20_GetClaimConditionById(null, validClaimConditionId)); + _ = await Assert.ThrowsAsync(async () => await contract.DropERC20_GetClaimConditionById(invalidClaimConditionId)); + + // DropERC20_GetActiveClaimCondition null checks + _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.DropERC20_GetActiveClaimCondition(null)); + + // Null contract checks + contract = null; + _ = await Assert.ThrowsAsync(async () => await contract.DropERC20_Claim(wallet, validAddress, validAmount)); + _ = await Assert.ThrowsAsync(async () => await contract.DropERC20_GetActiveClaimConditionId()); + _ = await Assert.ThrowsAsync(async () => await contract.DropERC20_GetClaimConditionById(validClaimConditionId)); + _ = await Assert.ThrowsAsync(async () => await contract.DropERC20_GetActiveClaimCondition()); + } + + [Fact(Timeout = 120000)] + public async Task DropERC20_Claim() + { + var contract = await this.GetDrop20Contract(); + var wallet = await this.GetSmartWallet(); + var receiverAddress = await wallet.GetAddress(); + var balanceBefore = await contract.ERC20_BalanceOf(receiverAddress); + var receipt = await contract.DropERC20_Claim(wallet, receiverAddress, "1.5"); + var balanceAfter = await contract.ERC20_BalanceOf(receiverAddress); + Assert.NotNull(receipt); + Assert.True(receipt.TransactionHash.Length == 66); + Assert.True(balanceAfter == balanceBefore + BigInteger.Parse("1.5".ToWei())); + } + + [Fact(Timeout = 120000)] + public async Task DropERC20_GetActiveClaimConditionId() + { + var contract = await this.GetDrop20Contract(); + var conditionId = await contract.DropERC20_GetActiveClaimConditionId(); + Assert.True(conditionId >= 0); + } + + [Fact(Timeout = 120000)] + public async Task DropERC20_GetClaimConditionById() + { + var contract = await this.GetDrop20Contract(); + var conditionId = await contract.DropERC20_GetActiveClaimConditionId(); + var condition = await contract.DropERC20_GetClaimConditionById(conditionId); + Assert.NotNull(condition); + Assert.True(condition.Currency.Length == 42); + } + + [Fact(Timeout = 120000)] + public async Task DropERC20_GetActiveClaimCondition() + { + var contract = await this.GetDrop20Contract(); + var condition = await contract.DropERC20_GetActiveClaimCondition(); + Assert.NotNull(condition); + Assert.True(condition.Currency.Length == 42); + + // Compare to raw GetClaimConditionById + var conditionId = await contract.DropERC20_GetActiveClaimConditionId(); + var conditionById = await contract.DropERC20_GetClaimConditionById(conditionId); + Assert.Equal(condition.Currency, conditionById.Currency); + } + + #endregion + + #region DropERC721 + + [Fact(Timeout = 120000)] + public async Task DropERC721_NullChecks() + { + var client = ThirdwebClient.Create(secretKey: this.SecretKey); + var contract = await ThirdwebContract.Create(client, this._dropErc721ContractAddress, this._chainId); + var wallet = await this.GetSmartWallet(); + var validAddress = "0x0000000000000000000000000000000000000000"; + var validQuantity = BigInteger.One; + var invalidQuantity = BigInteger.Zero; + var validClaimConditionId = BigInteger.One; + var invalidClaimConditionId = BigInteger.MinusOne; + + // DropERC721_Claim null checks + _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.DropERC721_Claim(null, wallet, validAddress, validQuantity)); + _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.DropERC721_Claim(contract, null, validAddress, validQuantity)); + _ = await Assert.ThrowsAsync(async () => await contract.DropERC721_Claim(wallet, null, validQuantity)); + _ = await Assert.ThrowsAsync(async () => await contract.DropERC721_Claim(wallet, string.Empty, validQuantity)); + _ = await Assert.ThrowsAsync(async () => await contract.DropERC721_Claim(wallet, validAddress, invalidQuantity)); + + // DropERC721_GetActiveClaimConditionId null checks + _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.DropERC721_GetActiveClaimConditionId(null)); + + // DropERC721_GetClaimConditionById null and out of range checks + _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.DropERC721_GetClaimConditionById(null, validClaimConditionId)); + _ = await Assert.ThrowsAsync(async () => await contract.DropERC721_GetClaimConditionById(invalidClaimConditionId)); + + // DropERC721_GetActiveClaimCondition null checks + _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.DropERC721_GetActiveClaimCondition(null)); + + // Null contract checks + contract = null; + _ = await Assert.ThrowsAsync(async () => await contract.DropERC721_Claim(wallet, validAddress, validQuantity)); + _ = await Assert.ThrowsAsync(async () => await contract.DropERC721_GetActiveClaimConditionId()); + _ = await Assert.ThrowsAsync(async () => await contract.DropERC721_GetClaimConditionById(validClaimConditionId)); + _ = await Assert.ThrowsAsync(async () => await contract.DropERC721_GetActiveClaimCondition()); + } + + // + // public async Task DropERC721_Claim_ShouldThrowTokens() + // { + // var contract = await GetDrop721Contract(); + // var wallet = await GetSmartWallet(); + // var ex = await Assert.ThrowsAsync(async () => await contract.DropERC721_Claim(wallet, await wallet.GetAddress(), 1)); + // Assert.Contains("!Tokens", ex.Message); + // } + + [Fact(Timeout = 120000)] + public async Task DropERC721_GetActiveClaimConditionId() + { + var contract = await this.GetDrop721Contract(); + var conditionId = await contract.DropERC721_GetActiveClaimConditionId(); + Assert.True(conditionId >= 0); + } + + [Fact(Timeout = 120000)] + public async Task DropERC721_GetClaimConditionById() + { + var contract = await this.GetDrop721Contract(); + var conditionId = await contract.DropERC721_GetActiveClaimConditionId(); + var condition = await contract.DropERC721_GetClaimConditionById(conditionId); + Assert.NotNull(condition); + Assert.True(condition.Currency.Length == 42); + } + + [Fact(Timeout = 120000)] + public async Task DropERC721_GetActiveClaimCondition() + { + var contract = await this.GetDrop721Contract(); + var condition = await contract.DropERC721_GetActiveClaimCondition(); + Assert.NotNull(condition); + Assert.True(condition.Currency.Length == 42); + + // Compare to raw GetClaimConditionById + var conditionId = await contract.DropERC721_GetActiveClaimConditionId(); + var conditionById = await contract.DropERC721_GetClaimConditionById(conditionId); + Assert.Equal(condition.Currency, conditionById.Currency); + } + + #endregion + + #region DropERC1155 + + [Fact(Timeout = 120000)] + public async Task DropERC1155_NullChecks() + { + var client = ThirdwebClient.Create(secretKey: this.SecretKey); + var contract = await ThirdwebContract.Create(client, this._dropErc1155ContractAddress, this._chainId); + var wallet = await this.GetSmartWallet(); + var validAddress = "0x0000000000000000000000000000000000000000"; + var validTokenId = BigInteger.One; + var invalidTokenId = BigInteger.MinusOne; + var validQuantity = BigInteger.One; + var invalidQuantity = BigInteger.Zero; + var validClaimConditionId = BigInteger.One; + var invalidClaimConditionId = BigInteger.MinusOne; + + // DropERC1155_Claim null checks + _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.DropERC1155_Claim(null, wallet, validAddress, validTokenId, validQuantity)); + _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.DropERC1155_Claim(contract, null, validAddress, validTokenId, validQuantity)); + _ = await Assert.ThrowsAsync(async () => await contract.DropERC1155_Claim(wallet, null, validTokenId, validQuantity)); + _ = await Assert.ThrowsAsync(async () => await contract.DropERC1155_Claim(wallet, string.Empty, validTokenId, validQuantity)); + _ = await Assert.ThrowsAsync(async () => await contract.DropERC1155_Claim(wallet, validAddress, invalidTokenId, validQuantity)); + _ = await Assert.ThrowsAsync(async () => await contract.DropERC1155_Claim(wallet, validAddress, validTokenId, invalidQuantity)); + + // DropERC1155_GetActiveClaimConditionId null and out of range checks + _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.DropERC1155_GetActiveClaimConditionId(null, validTokenId)); + _ = await Assert.ThrowsAsync(async () => await contract.DropERC1155_GetActiveClaimConditionId(invalidTokenId)); + + // DropERC1155_GetClaimConditionById null and out of range checks + _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.DropERC1155_GetClaimConditionById(null, validTokenId, validClaimConditionId)); + _ = await Assert.ThrowsAsync(async () => await contract.DropERC1155_GetClaimConditionById(invalidTokenId, validClaimConditionId)); + _ = await Assert.ThrowsAsync(async () => await contract.DropERC1155_GetClaimConditionById(validTokenId, invalidClaimConditionId)); + + // DropERC1155_GetActiveClaimCondition null and out of range checks + _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.DropERC1155_GetActiveClaimCondition(null, validTokenId)); + _ = await Assert.ThrowsAsync(async () => await contract.DropERC1155_GetActiveClaimCondition(invalidTokenId)); + + // Null contract checks + contract = null; + _ = await Assert.ThrowsAsync(async () => await contract.DropERC1155_Claim(wallet, validAddress, validTokenId, validQuantity)); + _ = await Assert.ThrowsAsync(async () => await contract.DropERC1155_GetActiveClaimConditionId(validTokenId)); + _ = await Assert.ThrowsAsync(async () => await contract.DropERC1155_GetClaimConditionById(validTokenId, validClaimConditionId)); + _ = await Assert.ThrowsAsync(async () => await contract.DropERC1155_GetActiveClaimCondition(validTokenId)); + } + + [Fact(Timeout = 120000)] + public async Task DropERC1155_Claim() + { + var contract = await this.GetDrop1155Contract(); + var wallet = await this.GetSmartWallet(); + var tokenId = 0; + var quantity = 10; + var receiverAddress = await wallet.GetAddress(); + + var balanceBefore = await contract.ERC1155_BalanceOf(receiverAddress, tokenId); + var receipt = await contract.DropERC1155_Claim(wallet, receiverAddress, tokenId, quantity); + var balanceAfter = await contract.ERC1155_BalanceOf(receiverAddress, tokenId); + Assert.NotNull(receipt); + Assert.True(receipt.TransactionHash.Length == 66); + Assert.True(balanceAfter == balanceBefore + quantity); + } + + [Fact(Timeout = 120000)] + public async Task DropERC1155_GetActiveClaimConditionId() + { + var contract = await this.GetDrop1155Contract(); + var tokenId = 0; + var conditionId = await contract.DropERC1155_GetActiveClaimConditionId(tokenId); + Assert.True(conditionId >= 0); + } + + [Fact(Timeout = 120000)] + public async Task DropERC1155_GetClaimConditionById() + { + var contract = await this.GetDrop1155Contract(); + var tokenId = 0; + var conditionId = await contract.DropERC1155_GetActiveClaimConditionId(tokenId); + var condition = await contract.DropERC1155_GetClaimConditionById(tokenId, conditionId); + Assert.NotNull(condition); + Assert.True(condition.Currency.Length == 42); + } + + [Fact(Timeout = 120000)] + public async Task DropERC1155_GetActiveClaimCondition() + { + var contract = await this.GetDrop1155Contract(); + var tokenId = 0; + var condition = await contract.DropERC1155_GetActiveClaimCondition(tokenId); + Assert.NotNull(condition); + Assert.True(condition.Currency.Length == 42); + + // Compare to raw GetClaimConditionById + var conditionId = await contract.DropERC1155_GetActiveClaimConditionId(tokenId); + var conditionById = await contract.DropERC1155_GetClaimConditionById(tokenId, conditionId); + Assert.Equal(condition.Currency, conditionById.Currency); + } + + #endregion + + #region TokenERC20 + + [Fact(Timeout = 120000)] + public async Task TokenERC20_NullChecks() + { + var client = ThirdwebClient.Create(secretKey: this.SecretKey); + var contract = await ThirdwebContract.Create(client, this._tokenErc20ContractAddress, this._chainId); + var wallet = await this.GetSmartWallet(); + var validAddress = "0x0000000000000000000000000000000000000000"; + var validAmount = "100"; + var invalidAmount = string.Empty; + var validSignature = "0x123"; + var invalidSignature = string.Empty; + + var validMintRequest = new TokenERC20_MintRequest + { + To = validAddress, + PrimarySaleRecipient = validAddress, + Quantity = BigInteger.One, + Price = BigInteger.One, + Currency = Constants.NATIVE_TOKEN_ADDRESS, + ValidityStartTimestamp = 0, + ValidityEndTimestamp = 0, + Uid = Guid.NewGuid().ToByteArray().PadTo32Bytes(), + }; + + // TokenERC20_MintTo null checks + _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC20_MintTo(null, wallet, validAddress, validAmount)); + _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC20_MintTo(contract, null, validAddress, validAmount)); + _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC20_MintTo(contract, wallet, null, validAmount)); + _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC20_MintTo(contract, wallet, string.Empty, validAmount)); + _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC20_MintTo(contract, wallet, validAddress, null)); + _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC20_MintTo(contract, wallet, validAddress, string.Empty)); + + // TokenERC20_MintWithSignature null checks + _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC20_MintWithSignature(null, wallet, validMintRequest, validSignature)); + _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC20_MintWithSignature(contract, null, validMintRequest, validSignature)); + _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC20_MintWithSignature(contract, wallet, null, validSignature)); + _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC20_MintWithSignature(contract, wallet, validMintRequest, null)); + _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC20_MintWithSignature(contract, wallet, validMintRequest, string.Empty)); + + // TokenERC20_GenerateMintSignature null checks + _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC20_GenerateMintSignature(null, wallet, validMintRequest)); + _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC20_GenerateMintSignature(contract, null, validMintRequest)); + _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC20_GenerateMintSignature(contract, wallet, null)); + + // TokenERC20_VerifyMintSignature null checks + _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC20_VerifyMintSignature(null, validMintRequest, validSignature)); + _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC20_VerifyMintSignature(contract, null, validSignature)); + _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC20_VerifyMintSignature(contract, validMintRequest, null)); + _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC20_VerifyMintSignature(contract, validMintRequest, string.Empty)); + + // Null contract checks + contract = null; + _ = await Assert.ThrowsAsync(async () => await contract.TokenERC20_MintTo(wallet, validAddress, validAmount)); + _ = await Assert.ThrowsAsync(async () => await contract.TokenERC20_MintWithSignature(wallet, validMintRequest, validSignature)); + _ = await Assert.ThrowsAsync(async () => await contract.TokenERC20_GenerateMintSignature(wallet, validMintRequest)); + _ = await Assert.ThrowsAsync(async () => await contract.TokenERC20_VerifyMintSignature(validMintRequest, validSignature)); + } + + // TODO: MintTo + + // TODO: MintWithSignature + + [Fact(Timeout = 120000)] + public async Task TokenERC20_GenerateMintSignature_WithVerify() + { + var contract = await this.GetTokenERC20Contract(); + var fakeAuthorizedSigner = await this.GetGuestAccount(); + var randomReceiver = await this.GetGuestAccount(); + var mintRequest = new TokenERC20_MintRequest { To = await randomReceiver.GetAddress(), Quantity = BigInteger.Parse("1.5".ToWei()) }; + + (var payload, var signature) = await contract.TokenERC20_GenerateMintSignature(fakeAuthorizedSigner, mintRequest); + + // returned payload should be filled with defaults + Assert.NotNull(payload); + Assert.NotNull(payload.To); + Assert.True(payload.To.Length == 42); + Assert.True(payload.To == await randomReceiver.GetAddress()); + Assert.NotNull(payload.PrimarySaleRecipient); + Assert.True(payload.PrimarySaleRecipient.Length == 42); + Assert.True(payload.Quantity != BigInteger.Zero); + Assert.True(payload.Price >= 0); + Assert.NotNull(payload.Currency); + Assert.True(payload.Currency.Length == 42); + Assert.True(payload.ValidityStartTimestamp >= 0); + Assert.True(payload.ValidityEndTimestamp >= 0); + Assert.NotNull(payload.Uid); + Assert.True(payload.Uid.Length == 32); // bytes32 + + // signature should not be valid + Assert.NotNull(signature); + Assert.NotEmpty(signature); + var verifyResult = await contract.TokenERC20_VerifyMintSignature(payload, signature); + Assert.False(verifyResult.IsValid); + Assert.Equal(await fakeAuthorizedSigner.GetAddress(), verifyResult.Signer); + } + + #endregion + + #region TokenERC721 + + [Fact(Timeout = 120000)] + public async Task TokenERC721_NullChecks() + { + var client = ThirdwebClient.Create(secretKey: this.SecretKey); + var contract = await ThirdwebContract.Create(client, this._tokenErc721ContractAddress, this._chainId); + var wallet = await this.GetSmartWallet(); + var validAddress = "0x0000000000000000000000000000000000000000"; + var validTokenId = BigInteger.One; + var invalidTokenId = BigInteger.MinusOne; + var validUri = "ipfs://validUri"; + var invalidUri = null as string; + var validSignature = "0x123"; + var invalidSignature = string.Empty; + + var validMintRequest = new TokenERC721_MintRequest + { + To = validAddress, + PrimarySaleRecipient = validAddress, + Uri = validUri, + Price = BigInteger.One, + Currency = Constants.NATIVE_TOKEN_ADDRESS, + ValidityStartTimestamp = 0, + ValidityEndTimestamp = 0, + Uid = Guid.NewGuid().ToByteArray().PadTo32Bytes(), + }; + + // TokenERC721_MintTo (with URI) null checks + _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC721_MintTo(null, wallet, validAddress, validUri)); + _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC721_MintTo(contract, null, validAddress, validUri)); + _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC721_MintTo(contract, wallet, null, validUri)); + _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC721_MintTo(contract, wallet, string.Empty, validUri)); + _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC721_MintTo(contract, wallet, validAddress, invalidUri)); + + // TokenERC721_MintTo (with metadata) null checks + _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC721_MintTo(null, wallet, validAddress, new NFTMetadata())); + _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC721_MintTo(contract, null, validAddress, new NFTMetadata())); + _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC721_MintTo(contract, wallet, null, new NFTMetadata())); + _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC721_MintTo(contract, wallet, string.Empty, new NFTMetadata())); + + // TokenERC721_MintWithSignature null checks + _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC721_MintWithSignature(null, wallet, validMintRequest, validSignature)); + _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC721_MintWithSignature(contract, null, validMintRequest, validSignature)); + _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC721_MintWithSignature(contract, wallet, null, validSignature)); + _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC721_MintWithSignature(contract, wallet, validMintRequest, null)); + _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC721_MintWithSignature(contract, wallet, validMintRequest, string.Empty)); + + // TokenERC721_GenerateMintSignature null checks + _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC721_GenerateMintSignature(null, wallet, validMintRequest)); + _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC721_GenerateMintSignature(contract, null, validMintRequest)); + _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC721_GenerateMintSignature(contract, wallet, null)); + + // TokenERC721_VerifyMintSignature null checks + _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC721_VerifyMintSignature(null, validMintRequest, validSignature)); + _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC721_VerifyMintSignature(contract, null, validSignature)); + _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC721_VerifyMintSignature(contract, validMintRequest, null)); + _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC721_VerifyMintSignature(contract, validMintRequest, string.Empty)); + + // Null contract checks + contract = null; + _ = await Assert.ThrowsAsync(async () => await contract.TokenERC721_MintTo(wallet, validAddress, validUri)); + _ = await Assert.ThrowsAsync(async () => await contract.TokenERC721_MintTo(wallet, validAddress, new NFTMetadata())); + _ = await Assert.ThrowsAsync(async () => await contract.TokenERC721_MintWithSignature(wallet, validMintRequest, validSignature)); + _ = await Assert.ThrowsAsync(async () => await contract.TokenERC721_GenerateMintSignature(wallet, validMintRequest)); + _ = await Assert.ThrowsAsync(async () => await contract.TokenERC721_VerifyMintSignature(validMintRequest, validSignature)); + } + + // TODO: MintTo + + // TODO: MintWithSignature + + [Fact(Timeout = 120000)] + public async Task TokenERC721_GenerateMintSignature_WithUri_WithVerify() + { + var contract = await this.GetTokenERC721Contract(); + var fakeAuthorizedSigner = await this.GetGuestAccount(); + var randomReceiver = await this.GetGuestAccount(); + var mintRequest = new TokenERC721_MintRequest { To = await randomReceiver.GetAddress(), Uri = "" }; + + (var payload, var signature) = await contract.TokenERC721_GenerateMintSignature(fakeAuthorizedSigner, mintRequest); + + // returned payload should be filled with defaults + Assert.NotNull(payload); + Assert.NotNull(payload.To); + Assert.True(payload.To.Length == 42); + Assert.True(payload.To == await randomReceiver.GetAddress()); + Assert.True(payload.RoyaltyRecipient.Length == 42); + Assert.True(payload.RoyaltyBps >= 0); + Assert.NotNull(payload.PrimarySaleRecipient); + Assert.True(payload.PrimarySaleRecipient.Length == 42); + Assert.True(payload.Price >= 0); + Assert.NotNull(payload.Currency); + Assert.True(payload.Currency.Length == 42); + Assert.True(payload.ValidityStartTimestamp >= 0); + Assert.True(payload.ValidityEndTimestamp >= 0); + Assert.NotNull(payload.Uid); + Assert.True(payload.Uid.Length == 32); // bytes32 + + // signature should not be valid + Assert.NotNull(signature); + Assert.NotEmpty(signature); + var verifyResult = await contract.TokenERC721_VerifyMintSignature(payload, signature); + Assert.False(verifyResult.IsValid); + Assert.Equal(await fakeAuthorizedSigner.GetAddress(), verifyResult.Signer); + } + + [Fact(Timeout = 120000)] + public async Task TokenERC721_GenerateMintSignature_WithNFTMetadata_WithVerify() + { + var contract = await this.GetTokenERC721Contract(); + var fakeAuthorizedSigner = await this.GetGuestAccount(); + var randomReceiver = await this.GetGuestAccount(); + var mintRequest = new TokenERC721_MintRequest { To = await randomReceiver.GetAddress() }; + + (var payload, var signature) = await contract.TokenERC721_GenerateMintSignature( + fakeAuthorizedSigner, + mintRequest, + new NFTMetadata + { + Name = "Test", + Description = "Test", + Image = "Test", + ExternalUrl = "Test", + Attributes = new Dictionary { { "Test", "Test" } }, + } + ); + + // returned payload should be filled with defaults + Assert.NotNull(payload); + Assert.NotNull(payload.To); + Assert.True(payload.To.Length == 42); + Assert.True(payload.To == await randomReceiver.GetAddress()); + Assert.True(payload.RoyaltyRecipient.Length == 42); + Assert.True(payload.RoyaltyBps >= 0); + Assert.NotNull(payload.PrimarySaleRecipient); + Assert.True(payload.PrimarySaleRecipient.Length == 42); + Assert.True(payload.Price >= 0); + Assert.NotNull(payload.Currency); + Assert.True(payload.Currency.Length == 42); + Assert.True(payload.ValidityStartTimestamp >= 0); + Assert.True(payload.ValidityEndTimestamp >= 0); + Assert.NotNull(payload.Uid); + Assert.True(payload.Uid.Length == 32); // bytes32 + Assert.NotNull(payload.Uri); + Assert.True(payload.Uri.Length > 0); + + // signature should not be valid + Assert.NotNull(signature); + Assert.NotEmpty(signature); + var verifyResult = await contract.TokenERC721_VerifyMintSignature(payload, signature); + Assert.False(verifyResult.IsValid); + Assert.Equal(await fakeAuthorizedSigner.GetAddress(), verifyResult.Signer); + } + + #endregion + + #region TokenERC1155 + + [Fact(Timeout = 120000)] + public async Task TokenERC1155_NullChecks() + { + var client = ThirdwebClient.Create(secretKey: this.SecretKey); + var contract = await ThirdwebContract.Create(client, this._tokenErc1155ContractAddress, this._chainId); + var wallet = await this.GetSmartWallet(); + var validAddress = "0x0000000000000000000000000000000000000000"; + var validTokenId = BigInteger.One; + var invalidTokenId = BigInteger.MinusOne; + var validQuantity = BigInteger.One; + var invalidQuantity = BigInteger.Zero; + var validUri = "ipfs://validUri"; + var invalidUri = null as string; + var validSignature = "0x123"; + var invalidSignature = string.Empty; + + var validMintRequest = new TokenERC1155_MintRequest + { + To = validAddress, + PrimarySaleRecipient = validAddress, + Uri = validUri, + Quantity = BigInteger.One, + PricePerToken = BigInteger.One, + Currency = Constants.NATIVE_TOKEN_ADDRESS, + ValidityStartTimestamp = 0, + ValidityEndTimestamp = 0, + Uid = Guid.NewGuid().ToByteArray().PadTo32Bytes(), + }; + + // TokenERC1155_MintTo (with URI) null checks + _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC1155_MintTo(null, wallet, validAddress, validTokenId, validQuantity, validUri)); + _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC1155_MintTo(contract, null, validAddress, validTokenId, validQuantity, validUri)); + _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC1155_MintTo(contract, wallet, null, validTokenId, validQuantity, validUri)); + _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC1155_MintTo(contract, wallet, string.Empty, validTokenId, validQuantity, validUri)); + _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC1155_MintTo(contract, wallet, validAddress, invalidTokenId, validQuantity, validUri)); + _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC1155_MintTo(contract, wallet, validAddress, validTokenId, invalidQuantity, validUri)); + _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC1155_MintTo(contract, wallet, validAddress, validTokenId, validQuantity, invalidUri)); + + // TokenERC1155_MintTo (with metadata) null checks + _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC1155_MintTo(null, wallet, validAddress, validTokenId, validQuantity, new NFTMetadata())); + _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC1155_MintTo(contract, null, validAddress, validTokenId, validQuantity, new NFTMetadata())); + _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC1155_MintTo(contract, wallet, null, validTokenId, validQuantity, new NFTMetadata())); + _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC1155_MintTo(contract, wallet, string.Empty, validTokenId, validQuantity, new NFTMetadata())); + _ = await Assert.ThrowsAsync(async () => + await ThirdwebExtensions.TokenERC1155_MintTo(contract, wallet, validAddress, invalidTokenId, validQuantity, new NFTMetadata()) + ); + _ = await Assert.ThrowsAsync(async () => + await ThirdwebExtensions.TokenERC1155_MintTo(contract, wallet, validAddress, validTokenId, invalidQuantity, new NFTMetadata()) + ); + + // TokenERC1155_MintWithSignature null checks + _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC1155_MintWithSignature(null, wallet, validMintRequest, validSignature)); + _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC1155_MintWithSignature(contract, null, validMintRequest, validSignature)); + _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC1155_MintWithSignature(contract, wallet, null, validSignature)); + _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC1155_MintWithSignature(contract, wallet, validMintRequest, null)); + _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC1155_MintWithSignature(contract, wallet, validMintRequest, string.Empty)); + + // TokenERC1155_GenerateMintSignature null checks + _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC1155_GenerateMintSignature(null, wallet, validMintRequest)); + _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC1155_GenerateMintSignature(contract, null, validMintRequest)); + _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC1155_GenerateMintSignature(contract, wallet, null)); + + // TokenERC1155_VerifyMintSignature null checks + _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC1155_VerifyMintSignature(null, validMintRequest, validSignature)); + _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC1155_VerifyMintSignature(contract, null, validSignature)); + _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC1155_VerifyMintSignature(contract, validMintRequest, null)); + _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC1155_VerifyMintSignature(contract, validMintRequest, string.Empty)); + + // Null contract checks + contract = null; + _ = await Assert.ThrowsAsync(async () => await contract.TokenERC1155_MintTo(wallet, validAddress, validTokenId, validQuantity, validUri)); + _ = await Assert.ThrowsAsync(async () => await contract.TokenERC1155_MintTo(wallet, validAddress, validTokenId, validQuantity, new NFTMetadata())); + _ = await Assert.ThrowsAsync(async () => await contract.TokenERC1155_MintWithSignature(wallet, validMintRequest, validSignature)); + _ = await Assert.ThrowsAsync(async () => await contract.TokenERC1155_GenerateMintSignature(wallet, validMintRequest)); + _ = await Assert.ThrowsAsync(async () => await contract.TokenERC1155_VerifyMintSignature(validMintRequest, validSignature)); + } + + // TODO: MintTo + + // TODO: MintWithSignature + + [Fact(Timeout = 120000)] + public async Task TokenERC1155_GenerateMintSignature_WithUri_WithVerify() + { + var contract = await this.GetTokenERC1155Contract(); + var fakeAuthorizedSigner = await this.GetGuestAccount(); + var randomReceiver = await this.GetGuestAccount(); + var mintRequest = new TokenERC1155_MintRequest { To = await randomReceiver.GetAddress(), Uri = "" }; + + (var payload, var signature) = await contract.TokenERC1155_GenerateMintSignature(fakeAuthorizedSigner, mintRequest); + + // returned payload should be filled with defaults + Assert.NotNull(payload); + Assert.NotNull(payload.To); + Assert.True(payload.To.Length == 42); + Assert.True(payload.To == await randomReceiver.GetAddress()); + Assert.True(payload.RoyaltyRecipient.Length == 42); + Assert.True(payload.RoyaltyBps >= 0); + Assert.NotNull(payload.PrimarySaleRecipient); + Assert.True(payload.PrimarySaleRecipient.Length == 42); + Assert.True(payload.PricePerToken >= 0); + Assert.NotNull(payload.Currency); + Assert.True(payload.Currency.Length == 42); + Assert.True(payload.ValidityStartTimestamp >= 0); + Assert.True(payload.ValidityEndTimestamp >= 0); + Assert.NotNull(payload.Uid); + Assert.True(payload.Uid.Length == 32); // bytes32 + Assert.NotNull(payload.TokenId); + Assert.True(payload.TokenId >= 0); + + // signature should not be valid + Assert.NotNull(signature); + Assert.NotEmpty(signature); + var verifyResult = await contract.TokenERC1155_VerifyMintSignature(payload, signature); + Assert.False(verifyResult.IsValid); + Assert.Equal(await fakeAuthorizedSigner.GetAddress(), verifyResult.Signer); + } + + [Fact(Timeout = 120000)] + public async Task TokenERC1155_GenerateMintSignature_WithNFTMetadata_WithVerify() + { + var contract = await this.GetTokenERC1155Contract(); + var fakeAuthorizedSigner = await this.GetGuestAccount(); + var randomReceiver = await this.GetGuestAccount(); + var mintRequest = new TokenERC1155_MintRequest { To = await randomReceiver.GetAddress() }; + + (var payload, var signature) = await contract.TokenERC1155_GenerateMintSignature( + fakeAuthorizedSigner, + mintRequest, + new NFTMetadata + { + Name = "Test", + Description = "Test", + Image = "Test", + ExternalUrl = "Test", + Attributes = new Dictionary { { "Test", "Test" } }, + } + ); + + // returned payload should be filled with defaults + Assert.NotNull(payload); + Assert.NotNull(payload.To); + Assert.True(payload.To.Length == 42); + Assert.True(payload.To == await randomReceiver.GetAddress()); + Assert.True(payload.RoyaltyRecipient.Length == 42); + Assert.True(payload.RoyaltyBps >= 0); + Assert.NotNull(payload.PrimarySaleRecipient); + Assert.True(payload.PrimarySaleRecipient.Length == 42); + Assert.True(payload.PricePerToken >= 0); + Assert.NotNull(payload.Currency); + Assert.True(payload.Currency.Length == 42); + Assert.True(payload.ValidityStartTimestamp >= 0); + Assert.True(payload.ValidityEndTimestamp >= 0); + Assert.NotNull(payload.Uid); + Assert.True(payload.Uid.Length == 32); // bytes32 + Assert.NotNull(payload.TokenId); + Assert.True(payload.TokenId >= 0); + Assert.NotNull(payload.Uri); + Assert.True(payload.Uri.Length > 0); + + // signature should not be valid + Assert.NotNull(signature); + Assert.NotEmpty(signature); + var verifyResult = await contract.TokenERC1155_VerifyMintSignature(payload, signature); + Assert.False(verifyResult.IsValid); + Assert.Equal(await fakeAuthorizedSigner.GetAddress(), verifyResult.Signer); + } + + #endregion +} diff --git a/Thirdweb.Tests/Thirdweb.Http.Tests.cs b/Thirdweb.Tests/Thirdweb.Http.Tests.cs deleted file mode 100644 index 24f5d091..00000000 --- a/Thirdweb.Tests/Thirdweb.Http.Tests.cs +++ /dev/null @@ -1,358 +0,0 @@ -using System.Numerics; -using System.Text; - -namespace Thirdweb.Tests -{ - public class HttpTests : BaseTests - { - public HttpTests(ITestOutputHelper output) - : base(output) { } - - #region ThirdwebHttpClient - - [Fact] - public async Task GetAsync_ShouldReturnSuccessResponse() - { - // Arrange - var httpClient = new ThirdwebHttpClient(); - var requestUri = "https://jsonplaceholder.typicode.com/posts/1"; - - // Act - var response = await httpClient.GetAsync(requestUri); - - // Assert - Assert.True(response.IsSuccessStatusCode); - Assert.Equal(200, response.StatusCode); - } - - [Fact] - public async Task PostAsync_ShouldReturnSuccessResponse() - { - // Arrange - var httpClient = new ThirdwebHttpClient(); - var requestUri = "https://jsonplaceholder.typicode.com/posts"; - var content = new StringContent("{\"title\": \"foo\", \"body\": \"bar\", \"userId\": 1}", System.Text.Encoding.UTF8, "application/json"); - - // Act - var response = await httpClient.PostAsync(requestUri, content); - - // Assert - Assert.True(response.IsSuccessStatusCode); - Assert.Equal(201, response.StatusCode); - } - - [Fact] - public void SetHeaders_ShouldAddHeaders() - { - // Arrange - var httpClient = new ThirdwebHttpClient(); - var headers = new Dictionary { { "Authorization", "Bearer token" } }; - - // Act - httpClient.SetHeaders(headers); - - // Assert - _ = Assert.Single(httpClient.Headers); - Assert.Equal("Bearer token", httpClient.Headers["Authorization"]); - } - - [Fact] - public void ClearHeaders_ShouldRemoveAllHeaders() - { - // Arrange - var httpClient = new ThirdwebHttpClient(); - var headers = new Dictionary { { "Authorization", "Bearer token" } }; - httpClient.SetHeaders(headers); - - // Act - httpClient.ClearHeaders(); - - // Assert - Assert.Empty(httpClient.Headers); - } - - [Fact] - public void AddHeader_ShouldAddHeader() - { - // Arrange - var httpClient = new ThirdwebHttpClient(); - - // Act - httpClient.AddHeader("Authorization", "Bearer token"); - - // Assert - _ = Assert.Single(httpClient.Headers); - Assert.Equal("Bearer token", httpClient.Headers["Authorization"]); - } - - [Fact] - public void RemoveHeader_ShouldRemoveHeader() - { - // Arrange - var httpClient = new ThirdwebHttpClient(); - httpClient.AddHeader("Authorization", "Bearer token"); - - // Act - httpClient.RemoveHeader("Authorization"); - - // Assert - Assert.Empty(httpClient.Headers); - } - - [Fact] - public async Task PutAsync_ShouldThrowNotImplementedException() - { - // Arrange - var httpClient = new ThirdwebHttpClient(); - var requestUri = "https://jsonplaceholder.typicode.com/posts/1"; - var content = new StringContent("{\"title\": \"foo\", \"body\": \"bar\", \"userId\": 1}", System.Text.Encoding.UTF8, "application/json"); - - // Act & Assert - _ = await Assert.ThrowsAsync(() => httpClient.PutAsync(requestUri, content)); - } - - [Fact] - public async Task DeleteAsync_ShouldThrowNotImplementedException() - { - // Arrange - var httpClient = new ThirdwebHttpClient(); - var requestUri = "https://jsonplaceholder.typicode.com/posts/1"; - - // Act & Assert - _ = await Assert.ThrowsAsync(() => httpClient.DeleteAsync(requestUri)); - } - - [Fact] - public void Dispose_ShouldDisposeHttpClient() - { - // Arrange - var httpClient = new ThirdwebHttpClient(); - - // Act - httpClient.Dispose(); - - // Assert - // Check that disposing twice does not throw an exception - var exception = Record.Exception(() => httpClient.Dispose()); - Assert.Null(exception); - } - - #endregion - - #region ThirdwebHttpContent - - [Fact] - public async Task Constructor_WithString_ShouldInitializeContent() - { - // Arrange - var contentString = "Hello, World!"; - var expectedBytes = Encoding.UTF8.GetBytes(contentString); - - // Act - var content = new ThirdwebHttpContent(contentString); - var resultBytes = await content.ReadAsByteArrayAsync(); - - // Assert - Assert.Equal(expectedBytes, resultBytes); - } - - [Fact] - public async Task Constructor_WithByteArray_ShouldInitializeContent() - { - // Arrange - var contentBytes = Encoding.UTF8.GetBytes("Hello, World!"); - - // Act - var content = new ThirdwebHttpContent(contentBytes); - var resultBytes = await content.ReadAsByteArrayAsync(); - - // Assert - Assert.Equal(contentBytes, resultBytes); - } - - [Fact] - public async Task Constructor_WithStream_ShouldInitializeContent() - { - // Arrange - var contentString = "Hello, World!"; - var contentStream = new MemoryStream(Encoding.UTF8.GetBytes(contentString)); - var expectedBytes = Encoding.UTF8.GetBytes(contentString); - - // Act - var content = new ThirdwebHttpContent(contentStream); - var resultBytes = await content.ReadAsByteArrayAsync(); - - // Assert - Assert.Equal(expectedBytes, resultBytes); - } - - [Fact] - public async Task ReadAsStringAsync_ShouldReturnContentAsString() - { - // Arrange - var contentString = "Hello, World!"; - var content = new ThirdwebHttpContent(contentString); - - // Act - var resultString = await content.ReadAsStringAsync(); - - // Assert - Assert.Equal(contentString, resultString); - } - - [Fact] - public async Task ReadAsByteArrayAsync_ShouldReturnContentAsByteArray() - { - // Arrange - var contentBytes = Encoding.UTF8.GetBytes("Hello, World!"); - var content = new ThirdwebHttpContent(contentBytes); - - // Act - var resultBytes = await content.ReadAsByteArrayAsync(); - - // Assert - Assert.Equal(contentBytes, resultBytes); - } - - [Fact] - public async Task ReadAsStreamAsync_ShouldReturnContentAsStream() - { - // Arrange - var contentString = "Hello, World!"; - var content = new ThirdwebHttpContent(contentString); - var expectedStream = new MemoryStream(Encoding.UTF8.GetBytes(contentString)); - - // Act - var resultStream = await content.ReadAsStreamAsync(); - - // Assert - using (var reader = new StreamReader(resultStream)) - using (var expectedReader = new StreamReader(expectedStream)) - { - var resultString = await reader.ReadToEndAsync(); - var expectedString = await expectedReader.ReadToEndAsync(); - Assert.Equal(expectedString, resultString); - } - } - -#nullable disable - - [Fact] - public void Constructor_WithNullString_ShouldThrowArgumentNullException() - { - // Arrange, Act & Assert - _ = Assert.Throws(() => new ThirdwebHttpContent((string)null)); - } - - [Fact] - public void Constructor_WithNullByteArray_ShouldThrowArgumentNullException() - { - // Arrange, Act & Assert - _ = Assert.Throws(() => new ThirdwebHttpContent((byte[])null)); - } - - [Fact] - public void Constructor_WithNullStream_ShouldThrowArgumentNullException() - { - // Arrange, Act & Assert - _ = Assert.Throws(() => new ThirdwebHttpContent((Stream)null)); - } - -#nullable restore - - #endregion - - #region ThirdwebHttpResponseMessage - - [Fact] - public void Constructor_ShouldInitializeProperties() - { - // Arrange - var statusCode = 200; - var content = new ThirdwebHttpContent("Test Content"); - var isSuccessStatusCode = true; - - // Act - var responseMessage = new ThirdwebHttpResponseMessage(statusCode, content, isSuccessStatusCode); - - // Assert - Assert.Equal(statusCode, responseMessage.StatusCode); - Assert.Equal(content, responseMessage.Content); - Assert.Equal(isSuccessStatusCode, responseMessage.IsSuccessStatusCode); - } - - [Fact] - public void EnsureSuccessStatusCode_ShouldReturnSelfOnSuccess() - { - // Arrange - var statusCode = 200; - var content = new ThirdwebHttpContent("Test Content"); - var isSuccessStatusCode = true; - var responseMessage = new ThirdwebHttpResponseMessage(statusCode, content, isSuccessStatusCode); - - // Act - var result = responseMessage.EnsureSuccessStatusCode(); - - // Assert - Assert.Equal(responseMessage, result); - } - - [Fact] - public async Task EnsureSuccessStatusCode_ShouldThrowExceptionOnFailure() - { - // Arrange - var statusCode = 400; - var content = new ThirdwebHttpContent("Error Content"); - var isSuccessStatusCode = false; - var responseMessage = new ThirdwebHttpResponseMessage(statusCode, content, isSuccessStatusCode); - - // Act & Assert - var exception = await Assert.ThrowsAsync(() => Task.FromResult(responseMessage.EnsureSuccessStatusCode())); - var contentString = await content.ReadAsStringAsync(); - Assert.Equal($"Request failed with status code {statusCode} and content: {contentString}", exception.Message); - } - - [Fact] - public void StatusCode_ShouldSetAndGet() - { - // Arrange - var responseMessage = new ThirdwebHttpResponseMessage(200, new ThirdwebHttpContent("Test Content"), true); - - // Act - responseMessage.StatusCode = 404; - - // Assert - Assert.Equal(404, responseMessage.StatusCode); - } - - [Fact] - public void Content_ShouldSetAndGet() - { - // Arrange - var initialContent = new ThirdwebHttpContent("Initial Content"); - var newContent = new ThirdwebHttpContent("New Content"); - var responseMessage = new ThirdwebHttpResponseMessage(200, initialContent, true); - - // Act - responseMessage.Content = newContent; - - // Assert - Assert.Equal(newContent, responseMessage.Content); - } - - [Fact] - public void IsSuccessStatusCode_ShouldSetAndGet() - { - // Arrange - var responseMessage = new ThirdwebHttpResponseMessage(200, new ThirdwebHttpContent("Test Content"), true); - - // Act - responseMessage.IsSuccessStatusCode = false; - - // Assert - Assert.False(responseMessage.IsSuccessStatusCode); - } - - #endregion - } -} diff --git a/Thirdweb.Tests/Thirdweb.Http/Thirdweb.Http.Tests.cs b/Thirdweb.Tests/Thirdweb.Http/Thirdweb.Http.Tests.cs new file mode 100644 index 00000000..d0ed13d6 --- /dev/null +++ b/Thirdweb.Tests/Thirdweb.Http/Thirdweb.Http.Tests.cs @@ -0,0 +1,365 @@ +using System.Text; + +namespace Thirdweb.Tests.Http; + +public class HttpTests : BaseTests +{ + public HttpTests(ITestOutputHelper output) + : base(output) { } + + #region ThirdwebHttpClient + + [Fact(Timeout = 120000)] + public async Task GetAsync_ShouldReturnSuccessResponse() + { + // Arrange + var httpClient = new ThirdwebHttpClient(); + var requestUri = "https://jsonplaceholder.typicode.com/posts/1"; + + // Act + var response = await httpClient.GetAsync(requestUri); + + // Assert + Assert.True(response.IsSuccessStatusCode); + Assert.Equal(200, response.StatusCode); + } + + [Fact(Timeout = 120000)] + public async Task PostAsync_ShouldReturnSuccessResponse() + { + // Arrange + var httpClient = new ThirdwebHttpClient(); + var requestUri = "https://jsonplaceholder.typicode.com/posts"; + var content = new StringContent( /*lang=json,strict*/ + "{\"title\": \"foo\", \"body\": \"bar\", \"userId\": 1}", + Encoding.UTF8, + "application/json" + ); + + // Act + var response = await httpClient.PostAsync(requestUri, content); + + // Assert + Assert.True(response.IsSuccessStatusCode); + Assert.Equal(201, response.StatusCode); + } + + [Fact(Timeout = 120000)] + public void SetHeaders_ShouldAddHeaders() + { + // Arrange + var httpClient = new ThirdwebHttpClient(); + var headers = new Dictionary { { "Authorization", "Bearer token" } }; + + // Act + httpClient.SetHeaders(headers); + + // Assert + _ = Assert.Single(httpClient.Headers); + Assert.Equal("Bearer token", httpClient.Headers["Authorization"]); + } + + [Fact(Timeout = 120000)] + public void ClearHeaders_ShouldRemoveAllHeaders() + { + // Arrange + var httpClient = new ThirdwebHttpClient(); + var headers = new Dictionary { { "Authorization", "Bearer token" } }; + httpClient.SetHeaders(headers); + + // Act + httpClient.ClearHeaders(); + + // Assert + Assert.Empty(httpClient.Headers); + } + + [Fact(Timeout = 120000)] + public void AddHeader_ShouldAddHeader() + { + // Arrange + var httpClient = new ThirdwebHttpClient(); + + // Act + httpClient.AddHeader("Authorization", "Bearer token"); + + // Assert + _ = Assert.Single(httpClient.Headers); + Assert.Equal("Bearer token", httpClient.Headers["Authorization"]); + } + + [Fact(Timeout = 120000)] + public void RemoveHeader_ShouldRemoveHeader() + { + // Arrange + var httpClient = new ThirdwebHttpClient(); + httpClient.AddHeader("Authorization", "Bearer token"); + + // Act + httpClient.RemoveHeader("Authorization"); + + // Assert + Assert.Empty(httpClient.Headers); + } + + [Fact(Timeout = 120000)] + public async Task PutAsync_ShouldThrowNotImplementedException() + { + // Arrange + var httpClient = new ThirdwebHttpClient(); + var requestUri = "https://jsonplaceholder.typicode.com/posts/1"; + var content = new StringContent( /*lang=json,strict*/ + "{\"title\": \"foo\", \"body\": \"bar\", \"userId\": 1}", + Encoding.UTF8, + "application/json" + ); + + // Act & Assert + _ = await Assert.ThrowsAsync(() => httpClient.PutAsync(requestUri, content)); + } + + [Fact(Timeout = 120000)] + public async Task DeleteAsync_ShouldThrowNotImplementedException() + { + // Arrange + var httpClient = new ThirdwebHttpClient(); + var requestUri = "https://jsonplaceholder.typicode.com/posts/1"; + + // Act & Assert + _ = await Assert.ThrowsAsync(() => httpClient.DeleteAsync(requestUri)); + } + + [Fact(Timeout = 120000)] + public void Dispose_ShouldDisposeHttpClient() + { + // Arrange + var httpClient = new ThirdwebHttpClient(); + + // Act + httpClient.Dispose(); + + // Assert + // Check that disposing twice does not throw an exception + var exception = Record.Exception(httpClient.Dispose); + Assert.Null(exception); + } + + #endregion + + #region ThirdwebHttpContent + + [Fact(Timeout = 120000)] + public async Task Constructor_WithString_ShouldInitializeContent() + { + // Arrange + var contentString = "Hello, World!"; + var expectedBytes = Encoding.UTF8.GetBytes(contentString); + + // Act + var content = new ThirdwebHttpContent(contentString); + var resultBytes = await content.ReadAsByteArrayAsync(); + + // Assert + Assert.Equal(expectedBytes, resultBytes); + } + + [Fact(Timeout = 120000)] + public async Task Constructor_WithByteArray_ShouldInitializeContent() + { + // Arrange + var contentBytes = Encoding.UTF8.GetBytes("Hello, World!"); + + // Act + var content = new ThirdwebHttpContent(contentBytes); + var resultBytes = await content.ReadAsByteArrayAsync(); + + // Assert + Assert.Equal(contentBytes, resultBytes); + } + + [Fact(Timeout = 120000)] + public async Task Constructor_WithStream_ShouldInitializeContent() + { + // Arrange + var contentString = "Hello, World!"; + var contentStream = new MemoryStream(Encoding.UTF8.GetBytes(contentString)); + var expectedBytes = Encoding.UTF8.GetBytes(contentString); + + // Act + var content = new ThirdwebHttpContent(contentStream); + var resultBytes = await content.ReadAsByteArrayAsync(); + + // Assert + Assert.Equal(expectedBytes, resultBytes); + } + + [Fact(Timeout = 120000)] + public async Task ReadAsStringAsync_ShouldReturnContentAsString() + { + // Arrange + var contentString = "Hello, World!"; + var content = new ThirdwebHttpContent(contentString); + + // Act + var resultString = await content.ReadAsStringAsync(); + + // Assert + Assert.Equal(contentString, resultString); + } + + [Fact(Timeout = 120000)] + public async Task ReadAsByteArrayAsync_ShouldReturnContentAsByteArray() + { + // Arrange + var contentBytes = Encoding.UTF8.GetBytes("Hello, World!"); + var content = new ThirdwebHttpContent(contentBytes); + + // Act + var resultBytes = await content.ReadAsByteArrayAsync(); + + // Assert + Assert.Equal(contentBytes, resultBytes); + } + + [Fact(Timeout = 120000)] + public async Task ReadAsStreamAsync_ShouldReturnContentAsStream() + { + // Arrange + var contentString = "Hello, World!"; + var content = new ThirdwebHttpContent(contentString); + var expectedStream = new MemoryStream(Encoding.UTF8.GetBytes(contentString)); + + // Act + var resultStream = await content.ReadAsStreamAsync(); + + // Assert + using var reader = new StreamReader(resultStream); + using var expectedReader = new StreamReader(expectedStream); + var resultString = await reader.ReadToEndAsync(); + var expectedString = await expectedReader.ReadToEndAsync(); + Assert.Equal(expectedString, resultString); + } + +#nullable disable + + [Fact(Timeout = 120000)] + public void Constructor_WithNullString_ShouldThrowArgumentNullException() + { + // Arrange, Act & Assert + _ = Assert.Throws(() => new ThirdwebHttpContent((string)null)); + } + + [Fact(Timeout = 120000)] + public void Constructor_WithNullByteArray_ShouldThrowArgumentNullException() + { + // Arrange, Act & Assert + _ = Assert.Throws(() => new ThirdwebHttpContent((byte[])null)); + } + + [Fact(Timeout = 120000)] + public void Constructor_WithNullStream_ShouldThrowArgumentNullException() + { + // Arrange, Act & Assert + _ = Assert.Throws(() => new ThirdwebHttpContent((Stream)null)); + } + +#nullable restore + + #endregion + + #region ThirdwebHttpResponseMessage + + [Fact(Timeout = 120000)] + public void Constructor_ShouldInitializeProperties() + { + // Arrange + var statusCode = 200; + var content = new ThirdwebHttpContent("Test Content"); + var isSuccessStatusCode = true; + + // Act + var responseMessage = new ThirdwebHttpResponseMessage(statusCode, content, isSuccessStatusCode); + + // Assert + Assert.Equal(statusCode, responseMessage.StatusCode); + Assert.Equal(content, responseMessage.Content); + Assert.Equal(isSuccessStatusCode, responseMessage.IsSuccessStatusCode); + } + + [Fact(Timeout = 120000)] + public void EnsureSuccessStatusCode_ShouldReturnSelfOnSuccess() + { + // Arrange + var statusCode = 200; + var content = new ThirdwebHttpContent("Test Content"); + var isSuccessStatusCode = true; + var responseMessage = new ThirdwebHttpResponseMessage(statusCode, content, isSuccessStatusCode); + + // Act + var result = responseMessage.EnsureSuccessStatusCode(); + + // Assert + Assert.Equal(responseMessage, result); + } + + [Fact(Timeout = 120000)] + public async Task EnsureSuccessStatusCode_ShouldThrowExceptionOnFailure() + { + // Arrange + var statusCode = 400; + var content = new ThirdwebHttpContent("Error Content"); + var isSuccessStatusCode = false; + var responseMessage = new ThirdwebHttpResponseMessage(statusCode, content, isSuccessStatusCode); + + // Act & Assert + var exception = await Assert.ThrowsAsync(() => Task.FromResult(responseMessage.EnsureSuccessStatusCode())); + var contentString = await content.ReadAsStringAsync(); + Assert.Equal($"Request failed with status code {statusCode} and content: {contentString}", exception.Message); + } + + [Fact(Timeout = 120000)] + public void StatusCode_ShouldSetAndGet() + { + // Arrange + var responseMessage = new ThirdwebHttpResponseMessage(200, new ThirdwebHttpContent("Test Content"), true) + { + // Act + StatusCode = 404, + }; + + // Assert + Assert.Equal(404, responseMessage.StatusCode); + } + + [Fact(Timeout = 120000)] + public void Content_ShouldSetAndGet() + { + // Arrange + var initialContent = new ThirdwebHttpContent("Initial Content"); + var newContent = new ThirdwebHttpContent("New Content"); + var responseMessage = new ThirdwebHttpResponseMessage(200, initialContent, true) + { + // Act + Content = newContent, + }; + + // Assert + Assert.Equal(newContent, responseMessage.Content); + } + + [Fact(Timeout = 120000)] + public void IsSuccessStatusCode_ShouldSetAndGet() + { + // Arrange + var responseMessage = new ThirdwebHttpResponseMessage(200, new ThirdwebHttpContent("Test Content"), true) + { + // Act + IsSuccessStatusCode = false, + }; + + // Assert + Assert.False(responseMessage.IsSuccessStatusCode); + } + + #endregion +} diff --git a/Thirdweb.Tests/Thirdweb.PrivateKeyWallet.Tests.cs b/Thirdweb.Tests/Thirdweb.PrivateKeyWallet.Tests.cs deleted file mode 100644 index d619f248..00000000 --- a/Thirdweb.Tests/Thirdweb.PrivateKeyWallet.Tests.cs +++ /dev/null @@ -1,376 +0,0 @@ -using Nethereum.Hex.HexTypes; - -namespace Thirdweb.Tests; - -public class PrivateKeyWalletTests : BaseTests -{ - public PrivateKeyWalletTests(ITestOutputHelper output) - : base(output) { } - - private async Task GetAccount() - { - var client = ThirdwebClient.Create(secretKey: _secretKey); - var privateKeyAccount = await PrivateKeyWallet.Generate(client); - return privateKeyAccount; - } - - [Fact] - public async Task Initialization_Success() - { - var account = await GetAccount(); - Assert.NotNull(account); - } - - [Fact] - public async void Initialization_NullPrivateKey() - { - var client = ThirdwebClient.Create(secretKey: _secretKey); - var ex = await Assert.ThrowsAsync(async () => await PrivateKeyWallet.Create(client, null)); - Assert.Equal("Private key cannot be null or empty. (Parameter 'privateKeyHex')", ex.Message); - } - - [Fact] - public async Task Connect() - { - var account = await GetAccount(); - Assert.True(await account.IsConnected()); - } - - [Fact] - public async Task GetAddress() - { - var account = await GetAccount(); - var address = await account.GetAddress(); - Assert.True(address.Length == 42); - } - - [Fact] - public async Task EthSign_Success() - { - var account = await GetAccount(); - var message = "Hello, World!"; - var signature = await account.EthSign(message); - Assert.True(signature.Length == 132); - } - - [Fact] - public async Task EthSign_NullMessage() - { - var account = await GetAccount(); - var ex = await Assert.ThrowsAsync(() => account.EthSign(null as string)); - Assert.Equal("Message to sign cannot be null. (Parameter 'message')", ex.Message); - } - - [Fact] - public async Task EthSignRaw_Success() - { - var account = await GetAccount(); - var message = "Hello, World!"; - var signature = await account.EthSign(System.Text.Encoding.UTF8.GetBytes(message)); - Assert.True(signature.Length == 132); - } - - [Fact] - public async Task EthSignRaw_NullMessage() - { - var account = await GetAccount(); - var ex = await Assert.ThrowsAsync(() => account.EthSign(null as byte[])); - Assert.Equal("Message to sign cannot be null. (Parameter 'rawMessage')", ex.Message); - } - - [Fact] - public async Task PersonalSign_Success() - { - var account = await GetAccount(); - var message = "Hello, World!"; - var signature = await account.PersonalSign(message); - Assert.True(signature.Length == 132); - } - - [Fact] - public async Task PersonalSign_EmptyMessage() - { - var account = await GetAccount(); - var ex = await Assert.ThrowsAsync(() => account.PersonalSign(string.Empty)); - Assert.Equal("Message to sign cannot be null. (Parameter 'message')", ex.Message); - } - - [Fact] - public async Task PersonalSign_NullyMessage() - { - var account = await GetAccount(); - - var ex = await Assert.ThrowsAsync(() => account.PersonalSign(null as string)); - Assert.Equal("Message to sign cannot be null. (Parameter 'message')", ex.Message); - } - - [Fact] - public async Task PersonalSignRaw_Success() - { - var account = await GetAccount(); - var message = System.Text.Encoding.UTF8.GetBytes("Hello, World!"); - var signature = await account.PersonalSign(message); - Assert.True(signature.Length == 132); - } - - [Fact] - public async Task PersonalSignRaw_NullMessage() - { - var account = await GetAccount(); - var ex = await Assert.ThrowsAsync(() => account.PersonalSign(null as byte[])); - Assert.Equal("Message to sign cannot be null. (Parameter 'rawMessage')", ex.Message); - } - - [Fact] - public async Task SignTypedDataV4_Success() - { - var account = await GetAccount(); - var json = - "{\"types\":{\"EIP712Domain\":[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"version\",\"type\":\"string\"},{\"name\":\"chainId\",\"type\":\"uint256\"},{\"name\":\"verifyingContract\",\"type\":\"address\"}],\"Person\":[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"wallet\",\"type\":\"address\"}],\"Mail\":[{\"name\":\"from\",\"type\":\"Person\"},{\"name\":\"to\",\"type\":\"Person\"},{\"name\":\"contents\",\"type\":\"string\"}]},\"primaryType\":\"Mail\",\"domain\":{\"name\":\"Ether Mail\",\"version\":\"1\",\"chainId\":1,\"verifyingContract\":\"0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC\"},\"message\":{\"from\":{\"name\":\"Cow\",\"wallet\":\"0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826\"},\"to\":{\"name\":\"Bob\",\"wallet\":\"0xbBbBBBBbbBBBbbbBbbBbbBBbBbbBbBbBbBbbBBbB\"},\"contents\":\"Hello, Bob!\"}}"; - var signature = await account.SignTypedDataV4(json); - Assert.True(signature.Length == 132); - } - - [Fact] - public async Task SignTypedDataV4_NullJson() - { - var account = await GetAccount(); - var ex = await Assert.ThrowsAsync(() => account.SignTypedDataV4(null)); - Assert.Equal("Json to sign cannot be null. (Parameter 'json')", ex.Message); - } - - [Fact] - public async Task SignTypedDataV4_EmptyJson() - { - var account = await GetAccount(); - var ex = await Assert.ThrowsAsync(() => account.SignTypedDataV4(string.Empty)); - Assert.Equal("Json to sign cannot be null. (Parameter 'json')", ex.Message); - } - - [Fact] - public async Task SignTypedDataV4_Typed() - { - var account = await GetAccount(); - var typedData = EIP712.GetTypedDefinition_SmartAccount_AccountMessage("Account", "1", 421614, await account.GetAddress()); - var accountMessage = new AccountAbstraction.AccountMessage { Message = System.Text.Encoding.UTF8.GetBytes("Hello, world!") }; - var signature = await account.SignTypedDataV4(accountMessage, typedData); - Assert.True(signature.Length == 132); - } - - [Fact] - public async Task SignTypedDataV4_Typed_NullData() - { - var account = await GetAccount(); - var typedData = EIP712.GetTypedDefinition_SmartAccount_AccountMessage("Account", "1", 421614, await account.GetAddress()); - var ex = await Assert.ThrowsAsync(() => account.SignTypedDataV4(null as string, typedData)); - Assert.Equal("Data to sign cannot be null. (Parameter 'data')", ex.Message); - } - - [Fact] - public async Task SignTransaction_Success() - { - var account = await GetAccount(); - var transaction = new ThirdwebTransactionInput - { - From = await account.GetAddress(), - To = Constants.ADDRESS_ZERO, - // Value = new HexBigInteger(0), - Gas = new HexBigInteger(21000), - Data = "0x", - Nonce = new HexBigInteger(99999999999), - GasPrice = new HexBigInteger(10000000000), - ChainId = new HexBigInteger(421614) - }; - var signature = await account.SignTransaction(transaction); - Assert.NotNull(signature); - } - - [Fact] - public async Task SignTransaction_NoFrom_Success() - { - var account = await GetAccount(); - var transaction = new ThirdwebTransactionInput - { - To = Constants.ADDRESS_ZERO, - // Value = new HexBigInteger(0), - Gas = new HexBigInteger(21000), - Data = "0x", - Nonce = new HexBigInteger(99999999999), - GasPrice = new HexBigInteger(10000000000), - ChainId = new HexBigInteger(421614) - }; - var signature = await account.SignTransaction(transaction); - Assert.NotNull(signature); - } - - [Fact] - public async Task SignTransaction_NullTransaction() - { - var account = await GetAccount(); - var ex = await Assert.ThrowsAsync(() => account.SignTransaction(null)); - Assert.Equal("Value cannot be null. (Parameter 'transaction')", ex.Message); - } - - [Fact] - public async Task SignTransaction_NoNonce() - { - var account = await GetAccount(); - var transaction = new ThirdwebTransactionInput - { - From = await account.GetAddress(), - To = Constants.ADDRESS_ZERO, - Value = new HexBigInteger(0), - Gas = new HexBigInteger(21000), - Data = "0x" - }; - var ex = await Assert.ThrowsAsync(() => account.SignTransaction(transaction)); - Assert.Equal("Transaction nonce has not been set (Parameter 'transaction')", ex.Message); - } - - [Fact] - public async Task SignTransaction_WrongFrom() - { - var account = await GetAccount(); - var transaction = new ThirdwebTransactionInput - { - From = Constants.ADDRESS_ZERO, - To = Constants.ADDRESS_ZERO, - Value = new HexBigInteger(0), - Gas = new HexBigInteger(21000), - Data = "0x", - Nonce = new HexBigInteger(99999999999), - ChainId = new HexBigInteger(421614) - }; - var ex = await Assert.ThrowsAsync(() => account.SignTransaction(transaction)); - Assert.Equal("Transaction 'From' address does not match the wallet address", ex.Message); - } - - [Fact] - public async Task SignTransaction_NoGasPrice() - { - var account = await GetAccount(); - var transaction = new ThirdwebTransactionInput - { - From = await account.GetAddress(), - To = Constants.ADDRESS_ZERO, - Value = new HexBigInteger(0), - Gas = new HexBigInteger(21000), - Data = "0x", - Nonce = new HexBigInteger(99999999999), - ChainId = new HexBigInteger(421614) - }; - var ex = await Assert.ThrowsAsync(() => account.SignTransaction(transaction)); - Assert.Equal("Transaction MaxPriorityFeePerGas and MaxFeePerGas must be set for EIP-1559 transactions", ex.Message); - } - - [Fact] - public async Task SignTransaction_1559_Success() - { - var account = await GetAccount(); - var transaction = new ThirdwebTransactionInput - { - From = await account.GetAddress(), - To = Constants.ADDRESS_ZERO, - Value = new HexBigInteger(0), - Gas = new HexBigInteger(21000), - Data = "0x", - Nonce = new HexBigInteger(99999999999), - MaxFeePerGas = new HexBigInteger(10000000000), - MaxPriorityFeePerGas = new HexBigInteger(10000000000), - ChainId = new HexBigInteger(421614) - }; - var signature = await account.SignTransaction(transaction); - Assert.NotNull(signature); - } - - [Fact] - public async Task SignTransaction_1559_NoMaxFeePerGas() - { - var account = await GetAccount(); - var transaction = new ThirdwebTransactionInput - { - From = await account.GetAddress(), - To = Constants.ADDRESS_ZERO, - Value = new HexBigInteger(0), - Gas = new HexBigInteger(21000), - Data = "0x", - Nonce = new HexBigInteger(99999999999), - MaxPriorityFeePerGas = new HexBigInteger(10000000000), - ChainId = new HexBigInteger(421614) - }; - var ex = await Assert.ThrowsAsync(() => account.SignTransaction(transaction)); - Assert.Equal("Transaction MaxPriorityFeePerGas and MaxFeePerGas must be set for EIP-1559 transactions", ex.Message); - } - - [Fact] - public async Task SignTransaction_1559_NoMaxPriorityFeePerGas() - { - var account = await GetAccount(); - var transaction = new ThirdwebTransactionInput - { - From = await account.GetAddress(), - To = Constants.ADDRESS_ZERO, - Value = new HexBigInteger(0), - Gas = new HexBigInteger(21000), - Data = "0x", - Nonce = new HexBigInteger(99999999999), - MaxFeePerGas = new HexBigInteger(10000000000), - ChainId = new HexBigInteger(421614) - }; - var ex = await Assert.ThrowsAsync(() => account.SignTransaction(transaction)); - Assert.Equal("Transaction MaxPriorityFeePerGas and MaxFeePerGas must be set for EIP-1559 transactions", ex.Message); - } - - [Fact] - public async Task IsConnected_True() - { - var account = await GetAccount(); - Assert.True(await account.IsConnected()); - } - - [Fact] - public async Task IsConnected_False() - { - var account = await GetAccount(); - await account.Disconnect(); - Assert.False(await account.IsConnected()); - } - - [Fact] - public async Task Disconnect() - { - var account = await GetAccount(); - await account.Disconnect(); - Assert.False(await account.IsConnected()); - } - - [Fact] - public async Task Disconnect_NotConnected() - { - var account = await GetAccount(); - await account.Disconnect(); - Assert.False(await account.IsConnected()); - } - - [Fact] - public async Task Disconnect_Connected() - { - var account = await GetAccount(); - await account.Disconnect(); - Assert.False(await account.IsConnected()); - } - - [Fact] - public async Task SendTransaction_InvalidOperation() - { - var account = await GetAccount(); - var transaction = new ThirdwebTransactionInput - { - From = await account.GetAddress(), - To = Constants.ADDRESS_ZERO, - Value = new HexBigInteger(0), - Data = "0x", - }; - _ = await Assert.ThrowsAsync(() => account.SendTransaction(transaction)); - } -} diff --git a/Thirdweb.Tests/Thirdweb.RPC.Tests.cs b/Thirdweb.Tests/Thirdweb.RPC.Tests.cs deleted file mode 100644 index 643e8760..00000000 --- a/Thirdweb.Tests/Thirdweb.RPC.Tests.cs +++ /dev/null @@ -1,169 +0,0 @@ -using System.Numerics; -using System.Reflection; - -namespace Thirdweb.Tests; - -public class RpcTests : BaseTests -{ - public RpcTests(ITestOutputHelper output) - : base(output) { } - - [Fact] - public async Task GetBlockNumber() - { - var client = ThirdwebClient.Create(secretKey: _secretKey, fetchTimeoutOptions: new TimeoutOptions(rpc: 10000)); - var rpc = ThirdwebRPC.GetRpcInstance(client, 1); - var blockNumber = await rpc.SendRequestAsync("eth_blockNumber"); - Assert.NotNull(blockNumber); - Assert.StartsWith("0x", blockNumber); - } - - [Fact] - public async Task TestAuth() - { - var client = ThirdwebClient.Create(clientId: "hi", fetchTimeoutOptions: new TimeoutOptions(rpc: 60000)); - var rpc = ThirdwebRPC.GetRpcInstance(client, 1); - _ = await Assert.ThrowsAsync(async () => await rpc.SendRequestAsync("eth_blockNumber")); - } - - [Fact] - public async Task TestTimeout() - { - var client = ThirdwebClient.Create(secretKey: _secretKey, fetchTimeoutOptions: new TimeoutOptions(rpc: 0)); - var rpc = ThirdwebRPC.GetRpcInstance(client, 1); - _ = await Assert.ThrowsAsync(async () => await rpc.SendRequestAsync("eth_chainId")); - } - - [Fact] - public async Task TestBatch() - { - var client = ThirdwebClient.Create(secretKey: _secretKey); - var rpc = ThirdwebRPC.GetRpcInstance(client, 1); - var req = rpc.SendRequestAsync("eth_blockNumber"); - _ = await rpc.SendRequestAsync("eth_chainId"); - var blockNumberTasks = new List>(); - for (var i = 0; i < 100; i++) - { - blockNumberTasks.Add(rpc.SendRequestAsync("eth_blockNumber")); - } - var results = await Task.WhenAll(blockNumberTasks); - Assert.Equal(100, results.Length); - Assert.All(results, result => Assert.StartsWith("0x", result)); - Assert.All(results, result => Assert.Equal(results[0], result)); - } - - [Fact] - public async Task TestDeserialization() - { - var client = ThirdwebClient.Create(secretKey: _secretKey); - var rpc = ThirdwebRPC.GetRpcInstance(client, 1); - var exception = await Assert.ThrowsAsync(async () => await rpc.SendRequestAsync("eth_blockNumber")); - Assert.Equal("Failed to deserialize RPC response.", exception.Message); - } - - [Fact] - public void TestBadInitialization() - { - var clientException = Assert.Throws(() => ThirdwebRPC.GetRpcInstance(null, 0)); - Assert.Equal("client", clientException.ParamName); - var chainIdException = Assert.Throws(() => ThirdwebRPC.GetRpcInstance(ThirdwebClient.Create(secretKey: _secretKey), 0)); - Assert.Equal("Invalid Chain ID", chainIdException.Message); - } - - [Fact] - public async Task TestBundleIdRpc() - { - var client = ThirdwebClient.Create(clientId: _clientIdBundleIdOnly, bundleId: _bundleIdBundleIdOnly); - var rpc = ThirdwebRPC.GetRpcInstance(client, 1); - var blockNumber = await rpc.SendRequestAsync("eth_blockNumber"); - Assert.NotNull(blockNumber); - Assert.StartsWith("0x", blockNumber); - } - - [Fact] - public async Task TestRpcError() - { - var client = ThirdwebClient.Create(secretKey: _secretKey); - var rpc = ThirdwebRPC.GetRpcInstance(client, 1); - var exception = await Assert.ThrowsAsync(async () => await rpc.SendRequestAsync("eth_invalidMethod")); - Assert.Contains("RPC Error for request", exception.Message); - } - - [Fact] - public async Task TestCache() - { - var client = ThirdwebClient.Create(secretKey: _secretKey); - var rpc = ThirdwebRPC.GetRpcInstance(client, 1); - var blockNumber1 = await rpc.SendRequestAsync("eth_blockNumber"); - await Task.Delay(100); - var blockNumber2 = await rpc.SendRequestAsync("eth_blockNumber"); - Assert.Equal(blockNumber1, blockNumber2); - } - - [Fact] - public async Task TestBatchSizeLimit() - { - var client = ThirdwebClient.Create(secretKey: _secretKey); - var rpc = ThirdwebRPC.GetRpcInstance(client, 1); - var blockNumberTasks = new List>(); - for (var i = 0; i < 101; i++) - { - blockNumberTasks.Add(rpc.SendRequestAsync("eth_blockNumber")); - } - var results = await Task.WhenAll(blockNumberTasks); - Assert.Equal(101, results.Length); - Assert.All(results, result => Assert.StartsWith("0x", result)); - } - - [Fact] - public void Timer_StartsAndStops() - { - var timer = new ThirdwebRPCTimer(TimeSpan.FromMilliseconds(100)); - timer.Start(); - Assert.True(IsTimerRunning(timer)); - - timer.Stop(); - Assert.False(IsTimerRunning(timer)); - } - - [Fact] - public async Task Timer_ElapsedEventFires() - { - var timer = new ThirdwebRPCTimer(TimeSpan.FromMilliseconds(100)); - var eventFired = false; - - timer.Elapsed += () => eventFired = true; - timer.Start(); - - await Task.Delay(200); // Wait for the timer to elapse at least once - Assert.True(eventFired); - - timer.Stop(); - } - - [Fact] - public void Timer_DisposeStopsTimer() - { - var timer = new ThirdwebRPCTimer(TimeSpan.FromMilliseconds(100)); - timer.Start(); - timer.Dispose(); - Assert.False(IsTimerRunning(timer)); - } - - private bool IsTimerRunning(ThirdwebRPCTimer timer) - { - var fieldInfo = typeof(ThirdwebRPCTimer).GetField("_isRunning", BindingFlags.NonPublic | BindingFlags.Instance); - if (fieldInfo == null) - { - throw new InvalidOperationException("The field '_isRunning' was not found."); - } - - var value = fieldInfo.GetValue(timer); - if (value == null) - { - throw new InvalidOperationException("The field '_isRunning' value is null."); - } - - return (bool)value; - } -} diff --git a/Thirdweb.Tests/Thirdweb.RPC/Thirdweb.RPC.Tests.cs b/Thirdweb.Tests/Thirdweb.RPC/Thirdweb.RPC.Tests.cs new file mode 100644 index 00000000..57628b3e --- /dev/null +++ b/Thirdweb.Tests/Thirdweb.RPC/Thirdweb.RPC.Tests.cs @@ -0,0 +1,157 @@ +using System.Numerics; + +namespace Thirdweb.Tests.RPC; + +public class RpcTests : BaseTests +{ + public RpcTests(ITestOutputHelper output) + : base(output) { } + + [Fact] + public void RpcOverride_None() + { + var client = ThirdwebClient.Create(secretKey: this.SecretKey); + var thirdwebRpc = $"https://1.rpc.thirdweb.com/{client.ClientId}"; + var rpc = ThirdwebRPC.GetRpcInstance(client, 1); + Assert.Equal(thirdwebRpc, rpc.RpcUrl.AbsoluteUri); + } + + [Fact] + public void RpcOverride_Single() + { + var customRpc = "https://eth.llamarpc.com/"; + var client = ThirdwebClient.Create(secretKey: this.SecretKey, rpcOverrides: new Dictionary { { 1, customRpc } }); + var rpc = ThirdwebRPC.GetRpcInstance(client, 1); + Assert.Equal(customRpc, client.RpcOverrides[1]); + Assert.Equal(customRpc, rpc.RpcUrl.AbsoluteUri); + } + + [Fact] + public void RpcOverride_Multiple() + { + var customRpc1 = "https://eth.llamarpc.com/"; + var customRpc42161 = "https://arbitrum.llamarpc.com/"; + var client = ThirdwebClient.Create(secretKey: this.SecretKey, rpcOverrides: new Dictionary { { 1, customRpc1 }, { 42161, customRpc42161 } }); + var rpc1 = ThirdwebRPC.GetRpcInstance(client, 1); + var rpc42161 = ThirdwebRPC.GetRpcInstance(client, 42161); + Assert.Equal(customRpc1, client.RpcOverrides[1]); + Assert.Equal(customRpc1, rpc1.RpcUrl.AbsoluteUri); + Assert.Equal(customRpc42161, client.RpcOverrides[42161]); + Assert.Equal(customRpc42161, rpc42161.RpcUrl.AbsoluteUri); + } + + [Fact] + public void RpcOverride_Single_Default() + { + var customRpc = "https://eth.llamarpc.com/"; + var client = ThirdwebClient.Create(secretKey: this.SecretKey, rpcOverrides: new Dictionary { { 1, customRpc } }); + + var thirdwebRpc = $"https://42161.rpc.thirdweb.com/{client.ClientId}"; + + var rpc1 = ThirdwebRPC.GetRpcInstance(client, 1); + Assert.Equal(customRpc, rpc1.RpcUrl.AbsoluteUri); + + var rpc42161 = ThirdwebRPC.GetRpcInstance(client, 42161); + Assert.Equal(thirdwebRpc, rpc42161.RpcUrl.AbsoluteUri); + } + + [Fact] + public void RpcOverride_Multiple_Default() + { + var customRpc1 = "https://eth.llamarpc.com/"; + var customRpc42161 = "https://arbitrum.llamarpc.com/"; + var client = ThirdwebClient.Create(secretKey: this.SecretKey, rpcOverrides: new Dictionary { { 1, customRpc1 }, { 42161, customRpc42161 } }); + + var thirdwebRpc = $"https://421614.rpc.thirdweb.com/{client.ClientId}"; + + var rpc1 = ThirdwebRPC.GetRpcInstance(client, 1); + Assert.Equal(customRpc1, rpc1.RpcUrl.AbsoluteUri); + + var rpc42161 = ThirdwebRPC.GetRpcInstance(client, 42161); + Assert.Equal(customRpc42161, rpc42161.RpcUrl.AbsoluteUri); + + var rpc421614 = ThirdwebRPC.GetRpcInstance(client, 421614); + Assert.Equal(thirdwebRpc, rpc421614.RpcUrl.AbsoluteUri); + } + + [Fact(Timeout = 120000)] + public async Task Request_WithRpcOverride() + { + var customRpc = "https://eth.llamarpc.com/"; + var client = ThirdwebClient.Create(secretKey: this.SecretKey, rpcOverrides: new Dictionary { { 1, customRpc } }); + + var rpc = ThirdwebRPC.GetRpcInstance(client, 1); + var blockNumber = await rpc.SendRequestAsync("eth_blockNumber"); + Assert.NotNull(blockNumber); + Assert.StartsWith("0x", blockNumber); + + var rpc2 = ThirdwebRPC.GetRpcInstance(client, 42161); + var blockNumber2 = await rpc2.SendRequestAsync("eth_blockNumber"); + Assert.NotNull(blockNumber2); + Assert.StartsWith("0x", blockNumber2); + } + + [Fact(Timeout = 120000)] + public async Task GetBlockNumber() + { + var client = ThirdwebClient.Create(secretKey: this.SecretKey, fetchTimeoutOptions: new TimeoutOptions(rpc: 10000)); + var rpc = ThirdwebRPC.GetRpcInstance(client, 1); + var blockNumber = await rpc.SendRequestAsync("eth_blockNumber"); + Assert.NotNull(blockNumber); + Assert.StartsWith("0x", blockNumber); + } + + [Fact(Timeout = 120000)] + public async Task TestAuth() + { + var client = ThirdwebClient.Create(clientId: "hi", fetchTimeoutOptions: new TimeoutOptions(rpc: 60000)); + var rpc = ThirdwebRPC.GetRpcInstance(client, 1); + var ex = await Assert.ThrowsAsync(async () => await rpc.SendRequestAsync("eth_blockNumber")); + Assert.Contains("401", ex.Message); + } + + [Fact(Timeout = 120000)] + public async Task TestTimeout() + { + var client = ThirdwebClient.Create(secretKey: this.SecretKey, fetchTimeoutOptions: new TimeoutOptions(rpc: 0)); + var rpc = ThirdwebRPC.GetRpcInstance(client, 1); + _ = await Assert.ThrowsAsync(async () => await rpc.SendRequestAsync("eth_chainId")); + } + + [Fact(Timeout = 120000)] + public async Task TestDeserialization() + { + var client = ThirdwebClient.Create(secretKey: this.SecretKey); + var rpc = ThirdwebRPC.GetRpcInstance(client, 1); + var exception = await Assert.ThrowsAsync(async () => await rpc.SendRequestAsync("eth_blockNumber")); + Assert.Equal("Failed to deserialize RPC response.", exception.Message); + } + + [Fact(Timeout = 120000)] + public void TestBadInitialization() + { + var clientException = Assert.Throws(() => ThirdwebRPC.GetRpcInstance(null, 0)); + Assert.Equal("client", clientException.ParamName); + var chainIdException = Assert.Throws(() => ThirdwebRPC.GetRpcInstance(ThirdwebClient.Create(secretKey: this.SecretKey), 0)); + Assert.Equal("Invalid Chain ID", chainIdException.Message); + } + + [Fact(Timeout = 120000)] + public async Task TestBundleIdRpc() + { + var client = ThirdwebClient.Create(clientId: this.ClientIdBundleIdOnly, bundleId: this.BundleIdBundleIdOnly); + var rpc = ThirdwebRPC.GetRpcInstance(client, 1); + var blockNumber = await rpc.SendRequestAsync("eth_blockNumber"); + Assert.NotNull(blockNumber); + Assert.StartsWith("0x", blockNumber); + } + + [Fact(Timeout = 120000)] + public async Task TestRpcError() + { + var client = ThirdwebClient.Create(secretKey: this.SecretKey); + var rpc = ThirdwebRPC.GetRpcInstance(client, 1); + var exception = await Assert.ThrowsAsync(async () => await rpc.SendRequestAsync("eth_invalidMethod")); + Assert.Contains("RPC Error for request", exception.Message); + } +} diff --git a/Thirdweb.Tests/Thirdweb.SmartWallet.Tests.cs b/Thirdweb.Tests/Thirdweb.SmartWallet.Tests.cs deleted file mode 100644 index 9ddaff62..00000000 --- a/Thirdweb.Tests/Thirdweb.SmartWallet.Tests.cs +++ /dev/null @@ -1,224 +0,0 @@ -using System.Numerics; -using Nethereum.Hex.HexTypes; - -namespace Thirdweb.Tests; - -public class SmartWalletTests : BaseTests -{ - public SmartWalletTests(ITestOutputHelper output) - : base(output) { } - - private async Task GetSmartAccount() - { - var client = ThirdwebClient.Create(secretKey: _secretKey); - var privateKeyAccount = await PrivateKeyWallet.Generate(client); - var smartAccount = await SmartWallet.Create(personalWallet: privateKeyAccount, factoryAddress: "0xbf1C9aA4B1A085f7DA890a44E82B0A1289A40052", gasless: true, chainId: 421614); - return smartAccount; - } - - [Fact] - public async Task Initialization_Success() - { - var account = await GetSmartAccount(); - Assert.NotNull(await account.GetAddress()); - } - - [Fact] - public async Task Initialization_WithoutFactory_Success() - { - var client = ThirdwebClient.Create(secretKey: _secretKey); - var privateKeyAccount = await PrivateKeyWallet.Generate(client); - var smartAccount = await SmartWallet.Create(personalWallet: privateKeyAccount, chainId: 421614); - Assert.NotNull(await smartAccount.GetAddress()); - } - - [Fact] - public async Task Initialization_Fail() - { - var client = ThirdwebClient.Create(secretKey: _secretKey); - var privateKeyAccount = await PrivateKeyWallet.Generate(client); - await privateKeyAccount.Disconnect(); - var ex = await Assert.ThrowsAsync( - async () => await SmartWallet.Create(personalWallet: privateKeyAccount, factoryAddress: "0xbf1C9aA4B1A085f7DA890a44E82B0A1289A40052", gasless: true, chainId: 421614) - ); - Assert.Equal("SmartAccount.Connect: Personal account must be connected.", ex.Message); - } - - [Fact] - public async Task ForceDeploy_Success() - { - var client = ThirdwebClient.Create(secretKey: _secretKey); - var privateKeyAccount = await PrivateKeyWallet.Generate(client); - var smartAccount = await SmartWallet.Create(personalWallet: privateKeyAccount, factoryAddress: "0xbf1C9aA4B1A085f7DA890a44E82B0A1289A40052", gasless: true, chainId: 421614); - await smartAccount.ForceDeploy(); - Assert.True(await smartAccount.IsDeployed()); - } - - [Fact] - public async Task IsDeployed_True() - { - var account = await GetSmartAccount(); - await account.ForceDeploy(); - Assert.True(await account.IsDeployed()); - } - - [Fact] - public async Task IsDeployed_False() - { - var client = ThirdwebClient.Create(secretKey: _secretKey); - var privateKeyAccount = await PrivateKeyWallet.Generate(client); - var smartAccount = await SmartWallet.Create( - personalWallet: privateKeyAccount, - factoryAddress: "0xbf1C9aA4B1A085f7DA890a44E82B0A1289A40052", - gasless: true, - chainId: 421614, - accountAddressOverride: "0x75A4e181286F5767c38dFBE65fe1Ad4793aCB642" // vanity - ); - Assert.False(await smartAccount.IsDeployed()); - } - - [Fact] - public async Task SendTransaction_Success() - { - var account = await GetSmartAccount(); - var tx = await account.SendTransaction( - new ThirdwebTransactionInput() - { - From = await account.GetAddress(), - To = await account.GetAddress(), - Value = new HexBigInteger(BigInteger.Parse("0")), - } - ); - Assert.NotNull(tx); - } - - [Fact] - public async Task SendTransaction_ClientBundleId_Success() - { - var client = ThirdwebClient.Create(clientId: _clientIdBundleIdOnly, bundleId: _bundleIdBundleIdOnly); - var privateKeyAccount = await PrivateKeyWallet.Generate(client); - var smartAccount = await SmartWallet.Create(personalWallet: privateKeyAccount, factoryAddress: "0xbf1C9aA4B1A085f7DA890a44E82B0A1289A40052", gasless: true, chainId: 421614); - var tx = await smartAccount.SendTransaction( - new ThirdwebTransactionInput() - { - From = await smartAccount.GetAddress(), - To = await smartAccount.GetAddress(), - Value = new HexBigInteger(BigInteger.Parse("0")), - } - ); - Assert.NotNull(tx); - } - - [Fact] - public async Task SendTransaction_Fail() - { - var account = await GetSmartAccount(); - var ex = await Assert.ThrowsAsync(async () => await account.SendTransaction(null)); - Assert.Equal("SmartAccount.SendTransaction: Transaction input is required.", ex.Message); - } - - [Fact] - public async Task GetAddress() - { - var account = await GetSmartAccount(); - var address = await account.GetAddress(); - Assert.NotNull(address); - } - - [Fact] - public async Task GetPersonalAccount() - { - var account = await GetSmartAccount(); - var personalAccount = await account.GetPersonalAccount(); - Assert.NotNull(personalAccount); - _ = Assert.IsType(personalAccount); - } - - [Fact] - public async Task GetAddress_WithOverride() - { - var client = ThirdwebClient.Create(secretKey: _secretKey); - var privateKeyAccount = await PrivateKeyWallet.Generate(client); - var smartAccount = await SmartWallet.Create( - personalWallet: privateKeyAccount, - factoryAddress: "0xbf1C9aA4B1A085f7DA890a44E82B0A1289A40052", - gasless: true, - chainId: 421614, - accountAddressOverride: "0x75A4e181286F5767c38dFBE65fe1Ad4793aCB642" // vanity - ); - var address = await smartAccount.GetAddress(); - Assert.Equal("0x75A4e181286F5767c38dFBE65fe1Ad4793aCB642", address); - } - - [Fact] - public async Task PersonalSign() // This is the only different signing mechanism for smart wallets, also tests isValidSignature - { - var account = await GetSmartAccount(); - var sig = await account.PersonalSign("Hello, world!"); - Assert.NotNull(sig); - } - - [Fact] - public async Task IsValidSiganture_Invalid() - { - var account = await GetSmartAccount(); - var sig = await account.PersonalSign("Hello, world!"); - Assert.NotNull(sig); - sig += "1"; - var res = await account.IsValidSignature("Hello, world!", sig); - Assert.False(res); - } - - [Fact] - public async Task CreateSessionKey() - { - var account = await GetSmartAccount(); - var receipt = await account.CreateSessionKey( - signerAddress: "0x253d077C45A3868d0527384e0B34e1e3088A3908", - approvedTargets: new List() { Constants.ADDRESS_ZERO }, - nativeTokenLimitPerTransactionInWei: "0", - permissionStartTimestamp: "0", - permissionEndTimestamp: (Utils.GetUnixTimeStampNow() + 86400).ToString(), - reqValidityStartTimestamp: "0", - reqValidityEndTimestamp: Utils.GetUnixTimeStampIn10Years().ToString() - ); - Assert.NotNull(receipt); - Assert.NotNull(receipt.TransactionHash); - } - - [Fact] - public async Task AddAdmin() - { - var account = await GetSmartAccount(); - var receipt = await account.AddAdmin("0x039d7D195f6f8537003fFC19e86cd91De5e9C431"); - Assert.NotNull(receipt); - Assert.NotNull(receipt.TransactionHash); - } - - [Fact] - public async Task RemoveAdmin() - { - var account = await GetSmartAccount(); - var receipt = await account.RemoveAdmin("0x039d7D195f6f8537003fFC19e86cd91De5e9C431"); - Assert.NotNull(receipt); - Assert.NotNull(receipt.TransactionHash); - } - - [Fact] - public async Task IsConnected() - { - var account = await GetSmartAccount(); - Assert.True(await account.IsConnected()); - - await account.Disconnect(); - Assert.False(await account.IsConnected()); - } - - [Fact] - public async Task Disconnect() - { - var account = await GetSmartAccount(); - await account.Disconnect(); - Assert.False(await account.IsConnected()); - } -} diff --git a/Thirdweb.Tests/Thirdweb.Storage.Tests.cs b/Thirdweb.Tests/Thirdweb.Storage.Tests.cs deleted file mode 100644 index e4fe5abf..00000000 --- a/Thirdweb.Tests/Thirdweb.Storage.Tests.cs +++ /dev/null @@ -1,129 +0,0 @@ -namespace Thirdweb.Tests; - -public class StorageTests : BaseTests -{ - public StorageTests(ITestOutputHelper output) - : base(output) { } - - [Fact] - public async Task DownloadTest_SecretKey() - { - var client = ThirdwebClient.Create(secretKey: _secretKey); - var res = await ThirdwebStorage.Download(client, "https://1.rpc.thirdweb.com/providers"); - Assert.NotNull(res); - } - - [Fact] - public async Task DownloadTest_Client_BundleId() - { - var client = ThirdwebClient.Create(clientId: _clientIdBundleIdOnly, bundleId: _bundleIdBundleIdOnly); - var res = await ThirdwebStorage.Download(client, "https://1.rpc.thirdweb.com/providers"); - Assert.NotNull(res); - } - - [Fact] - public async Task DownloadTest_Deserialization() - { - var client = ThirdwebClient.Create(secretKey: _secretKey); - var res = await ThirdwebStorage.Download>(client, "https://1.rpc.thirdweb.com/providers"); - Assert.NotNull(res); - Assert.NotEmpty(res); - } - - [Fact] - public async Task DownloadTest_NullUri() - { - var client = ThirdwebClient.Create(secretKey: _secretKey); - var exception = await Assert.ThrowsAsync(() => ThirdwebStorage.Download(client, null)); - Assert.Equal("uri", exception.ParamName); - } - - [Fact] - public async Task DownloadTest_ThirdwebIPFS() - { - var client = ThirdwebClient.Create(secretKey: _secretKey); - var res = await ThirdwebStorage.Download(client, "ipfs://QmRHf3sBEAaSkaPdjrnYZS7VH1jVgvNBJNoUXmiUyvUpNM/8"); - Assert.NotNull(res); - } - - [Fact] - public async Task DownloadTest_Bytes() - { - var client = ThirdwebClient.Create(secretKey: _secretKey); - var res = await ThirdwebStorage.Download(client, "https://1.rpc.thirdweb.com/providers"); - Assert.NotNull(res); - Assert.NotEmpty(res); - } - - [Fact] - public async Task DownloadTest_400() - { - var client = ThirdwebClient.Create(secretKey: _secretKey); - var exception = await Assert.ThrowsAsync(() => ThirdwebStorage.Download(client, "https://0.rpc.thirdweb.com/")); - Assert.Contains("Failed to download", exception.Message); - Assert.Contains("400", exception.Message); - } - - [Fact] - public async Task DownloadTest_Timeout() - { - var client = ThirdwebClient.Create(secretKey: _secretKey, fetchTimeoutOptions: new TimeoutOptions(storage: 0)); - var exception = await Assert.ThrowsAsync(() => ThirdwebStorage.Download(client, "https://1.rpc.thirdweb.com/providers", 1)); - Assert.Contains("A task was canceled", exception.Message); - } - - [Fact] - public async Task UploadTest_SecretKey() - { - var client = ThirdwebClient.Create(secretKey: _secretKey); - var path = Path.Combine(Path.GetTempPath(), "testJson.json"); - File.WriteAllText(path, "{\"test\": \"test\"}"); - var res = await ThirdwebStorage.Upload(client, path); - Assert.StartsWith($"https://{client.ClientId}.ipfscdn.io/ipfs/", res.PreviewUrl); - } - - [Fact] - public async Task UploadTest_Client_BundleId() - { - var client = ThirdwebClient.Create(clientId: _clientIdBundleIdOnly, bundleId: _bundleIdBundleIdOnly); - var path = Path.Combine(Path.GetTempPath(), "testJson.json"); - File.WriteAllText(path, "{\"test\": \"test\"}"); - var res = await ThirdwebStorage.Upload(client, path); - Assert.StartsWith($"https://{client.ClientId}.ipfscdn.io/ipfs/", res.PreviewUrl); - } - - [Fact] - public async Task UploadTest_NullPath() - { - var client = ThirdwebClient.Create(secretKey: _secretKey); - var exception = await Assert.ThrowsAsync(() => ThirdwebStorage.Upload(client, null)); - Assert.Equal("path", exception.ParamName); - } - - [Fact] - public async Task UploadTest_401() - { - var client = ThirdwebClient.Create(clientId: "invalid", bundleId: "hello"); - var path = Path.Combine(Path.GetTempPath(), "testJson.json"); - File.WriteAllText(path, "{\"test\": \"test\"}"); - var exception = await Assert.ThrowsAsync(() => ThirdwebStorage.Upload(client, path)); - Assert.Contains("Failed to upload", exception.Message); - Assert.Contains("401", exception.Message); - } - - [Fact] - public async Task UploadTest_RawBytes_Null() - { - var client = ThirdwebClient.Create(secretKey: _secretKey); - var exception = await Assert.ThrowsAsync(() => ThirdwebStorage.UploadRaw(client, null)); - Assert.Equal("rawBytes", exception.ParamName); - } - - [Fact] - public async Task UploadTest_RawBytes_Empty() - { - var client = ThirdwebClient.Create(secretKey: _secretKey); - var exception = await Assert.ThrowsAsync(() => ThirdwebStorage.UploadRaw(client, new byte[0])); - Assert.Equal("rawBytes", exception.ParamName); - } -} diff --git a/Thirdweb.Tests/Thirdweb.Storage/Thirdweb.Storage.Tests.cs b/Thirdweb.Tests/Thirdweb.Storage/Thirdweb.Storage.Tests.cs new file mode 100644 index 00000000..d8d11dc0 --- /dev/null +++ b/Thirdweb.Tests/Thirdweb.Storage/Thirdweb.Storage.Tests.cs @@ -0,0 +1,153 @@ +using Newtonsoft.Json; + +namespace Thirdweb.Tests.Storage; + +public class StorageTests : BaseTests +{ + public StorageTests(ITestOutputHelper output) + : base(output) { } + + [Fact(Timeout = 120000)] + public async Task DownloadTest_SecretKey() + { + var client = ThirdwebClient.Create(secretKey: this.SecretKey); + var res = await ThirdwebStorage.Download(client, "https://1.rpc.thirdweb.com/providers"); + Assert.NotNull(res); + } + + [Fact(Timeout = 120000)] + public async Task DownloadTest_Client_BundleId() + { + var client = ThirdwebClient.Create(clientId: this.ClientIdBundleIdOnly, bundleId: this.BundleIdBundleIdOnly); + var res = await ThirdwebStorage.Download(client, "https://1.rpc.thirdweb.com/providers"); + Assert.NotNull(res); + } + + [Fact(Timeout = 120000)] + public async Task DownloadTest_Deserialization() + { + var client = ThirdwebClient.Create(secretKey: this.SecretKey); + var res = await ThirdwebStorage.Download>(client, "https://1.rpc.thirdweb.com/providers"); + Assert.NotNull(res); + Assert.NotEmpty(res); + } + + [Fact(Timeout = 120000)] + public async Task DownloadTest_NullUri() + { + var client = ThirdwebClient.Create(secretKey: this.SecretKey); + var exception = await Assert.ThrowsAsync(() => ThirdwebStorage.Download(client, null)); + Assert.Equal("uri", exception.ParamName); + } + + [Fact(Timeout = 120000)] + public async Task DownloadTest_ThirdwebIPFS() + { + var client = ThirdwebClient.Create(secretKey: this.SecretKey); + var res = await ThirdwebStorage.Download(client, "ipfs://QmRHf3sBEAaSkaPdjrnYZS7VH1jVgvNBJNoUXmiUyvUpNM/8"); + Assert.NotNull(res); + } + + [Fact(Timeout = 120000)] + public async Task DownloadTest_Bytes() + { + var client = ThirdwebClient.Create(secretKey: this.SecretKey); + var res = await ThirdwebStorage.Download(client, "https://1.rpc.thirdweb.com/providers"); + Assert.NotNull(res); + Assert.NotEmpty(res); + } + + [Fact(Timeout = 120000)] + public async Task DownloadTest_Base64Uri() + { + var uri = + "data:application/json;base64,eyJuYW1lIjogIllvbml4IiwgImRlc2NyaXB0aW9uIjogIkZyb20gYSBkaXN0YW50IGZ1dHVyZSwgVGFpa28gTGFicyBoYXMgZGV2ZWxvcGVkIGEgc2VjcmV0IHdlYXBvbiB0byBjb21iYXQgdGhlIGdyZWF0IGNhbGFtaXR5IGtub3duIGFzICdGZWVzLCcgYSBtYXNzaXZlIGdhcyBjbG91ZCB0aGF0IHBvaXNvbnMgdGhlIGVudGlyZSBwbGFuZXQsIHB1dHRpbmcgYWxsIGNpdGl6ZW5zIGF0IHJpc2suIEFsdGhvdWdoIHRoZSBpZGVhIGlzIGJyaWxsaWFudCwgdGhlIFRhaWtvIE1vbmtleXMgYXJlIHN0aWxsIGltbWF0dXJlLCBhbG1vc3Qgc3R1cGlkISBUaGUgb25seSB3YXkgdG8gZmlnaHQgdGhpcyBzY291cmdlIGlzIHRvIGZpbmQgYSB3YXkgdG8gdHJhaW4gdGhlbSwgdHVybmluZyB0aGVtIGludG8gdGhlIG1vc3QgcG93ZXJmdWwgc2VjcmV0IHdlYXBvbiBvZiBhbGwuIEJ5IGNoYW5jZSwgYSBicmlkZ2UgaGFzIG9wZW5lZCBiZXR3ZWVuIHR3byB3b3JsZHMsIGFuZCBpdCBzZWVtcyB0aGF0IHRoZSBNb25rZXkgUmVhbG0gaXMgdGhlIGJlc3QgcGxhY2UgdG8gaW1wbGVtZW50IHRoZSBncmFuZCBwbGFuISBGaWdodCBhbmQgYmVjb21lIHRoZSBiZXN0IG1vbmtleTsgb25seSB5b3UgY2FuIG1ha2UgR2FzIEZlZXMgYSBkaXN0YW50IG1lbW9yeS4iLCAiaW1hZ2UiOiAiaXBmczovL1FtVzFqOFRKZGRSOVdVWEhDODFlb05SWGoyYVY4NndzRnJWWnJVYTRyY1dyejIvU01UYWlrb0xvdy5qcGciLCAiYW5pbWF0aW9uX3VybCI6ICJpcGZzOi8vUW1XMWo4VEpkZFI5V1VYSEM4MWVvTlJYajJhVjg2d3NGclZaclVhNHJjV3J6Mi9TTVRhaWtvSGlnaC5qcGciLCAicHJvcGVydGllcyI6IHsiTnVtYmVyIjogMSwgIlJQRyBDbGFzcyI6ICJOb25lIiwgIkNsYW4iOiAiU3R1cGlkIE1vbmtzIiwgIkxldmVsIjogMX19"; + + var client = ThirdwebClient.Create(secretKey: this.SecretKey); + var res = await ThirdwebStorage.Download(client, uri); + Assert.NotNull(res.Properties); + var propertiesObj = JsonConvert.DeserializeObject>(JsonConvert.SerializeObject(res.Properties)); + Assert.True(propertiesObj!.Count > 0); + } + + [Fact(Timeout = 120000)] + public async Task DownloadTest_404() + { + var client = ThirdwebClient.Create(secretKey: this.SecretKey); + var exception = await Assert.ThrowsAsync(() => ThirdwebStorage.Download(client, "https://example.com/invalid-file")); + Assert.Contains("Failed to download", exception.Message); + Assert.Contains("404", exception.Message); + } + + [Fact(Timeout = 120000)] + public async Task DownloadTest_Timeout() + { + var client = ThirdwebClient.Create(secretKey: this.SecretKey, fetchTimeoutOptions: new TimeoutOptions(storage: 0)); + var exception = await Assert.ThrowsAsync(() => ThirdwebStorage.Download(client, "https://1.rpc.thirdweb.com/providers", 1)); + Assert.Contains("A task was canceled", exception.Message); + } + + [Fact(Timeout = 120000)] + public async Task UploadTest_SecretKey() + { + var client = ThirdwebClient.Create(secretKey: this.SecretKey); + var path = Path.Combine(Path.GetTempPath(), "testJson.json"); + File.WriteAllText( + path, /*lang=json,strict*/ + "{\"test\": \"test\"}" + ); + var res = await ThirdwebStorage.Upload(client, path); + Assert.StartsWith($"https://{client.ClientId}.ipfscdn.io/ipfs/", res.PreviewUrl); + } + + [Fact(Timeout = 120000)] + public async Task UploadTest_Client_BundleId() + { + var client = ThirdwebClient.Create(clientId: this.ClientIdBundleIdOnly, bundleId: this.BundleIdBundleIdOnly); + var path = Path.Combine(Path.GetTempPath(), "testJson.json"); + File.WriteAllText( + path, /*lang=json,strict*/ + "{\"test\": \"test\"}" + ); + var res = await ThirdwebStorage.Upload(client, path); + Assert.StartsWith($"https://{client.ClientId}.ipfscdn.io/ipfs/", res.PreviewUrl); + } + + [Fact(Timeout = 120000)] + public async Task UploadTest_NullPath() + { + var client = ThirdwebClient.Create(secretKey: this.SecretKey); + var exception = await Assert.ThrowsAsync(() => ThirdwebStorage.Upload(client, null)); + Assert.Equal("path", exception.ParamName); + } + + [Fact(Timeout = 120000)] + public async Task UploadTest_401() + { + var client = ThirdwebClient.Create(clientId: "invalid", bundleId: "hello"); + var path = Path.Combine(Path.GetTempPath(), "testJson.json"); + File.WriteAllText( + path, /*lang=json,strict*/ + "{\"test\": \"test\"}" + ); + var exception = await Assert.ThrowsAsync(() => ThirdwebStorage.Upload(client, path)); + Assert.Contains("Failed to upload", exception.Message); + Assert.Contains("401", exception.Message); + } + + [Fact(Timeout = 120000)] + public async Task UploadTest_RawBytes_Null() + { + var client = ThirdwebClient.Create(secretKey: this.SecretKey); + var exception = await Assert.ThrowsAsync(() => ThirdwebStorage.UploadRaw(client, null)); + Assert.Equal("rawBytes", exception.ParamName); + } + + [Fact(Timeout = 120000)] + public async Task UploadTest_RawBytes_Empty() + { + var client = ThirdwebClient.Create(secretKey: this.SecretKey); + var exception = await Assert.ThrowsAsync(() => ThirdwebStorage.UploadRaw(client, Array.Empty())); + Assert.Equal("rawBytes", exception.ParamName); + } +} diff --git a/Thirdweb.Tests/Thirdweb.Tests.csproj b/Thirdweb.Tests/Thirdweb.Tests.csproj index 8170719b..465551a0 100644 --- a/Thirdweb.Tests/Thirdweb.Tests.csproj +++ b/Thirdweb.Tests/Thirdweb.Tests.csproj @@ -1,43 +1,40 @@ - net8.0 + latest + true enable enable false true - - + runtime; build; native; contentfiles; analyzers; buildtransitive all - - - - runtime; build; native; contentfiles; analyzers; buildtransitive + + + all - - runtime; build; native; contentfiles; analyzers; buildtransitive + all + + - - - + + PreserveNewest + - - + PreserveNewest - - - \ No newline at end of file + diff --git a/Thirdweb.Tests/Thirdweb.Transactions.Tests.cs b/Thirdweb.Tests/Thirdweb.Transactions/Thirdweb.Transactions.Tests.cs similarity index 54% rename from Thirdweb.Tests/Thirdweb.Transactions.Tests.cs rename to Thirdweb.Tests/Thirdweb.Transactions/Thirdweb.Transactions.Tests.cs index 11d455fc..a84321cd 100644 --- a/Thirdweb.Tests/Thirdweb.Transactions.Tests.cs +++ b/Thirdweb.Tests/Thirdweb.Transactions/Thirdweb.Transactions.Tests.cs @@ -1,7 +1,6 @@ using System.Numerics; -using Nethereum.Hex.HexTypes; -namespace Thirdweb.Tests; +namespace Thirdweb.Tests.Transactions; public class TransactionTests : BaseTests { @@ -10,130 +9,144 @@ public TransactionTests(ITestOutputHelper output) private async Task CreateSampleTransaction() { - var client = ThirdwebClient.Create(secretKey: _secretKey); - var wallet = await PrivateKeyWallet.Generate(client); - var chainId = new BigInteger(421614); - - var transaction = await ThirdwebTransaction.Create(wallet, new ThirdwebTransactionInput() { From = await wallet.GetAddress(), To = await wallet.GetAddress(), }, chainId); + var wallet = await this.GetGuestAccount(); + var transaction = await ThirdwebTransaction.Create(wallet, new ThirdwebTransactionInput(421614) { To = await wallet.GetAddress() }); return transaction; } - [Fact] + [Fact(Timeout = 120000)] + public void ConstructorArgs_TransactionInput() + { + var input = new ThirdwebTransactionInput( + from: "0x123", + to: "0x456", + nonce: 123, + gas: 123, + gasPrice: 123, + value: 123, + data: "0x123", + chainId: 123, + maxFeePerGas: 123, + maxPriorityFeePerGas: 123, + zkSync: new ZkSyncOptions() + ); + + Assert.Equal("0x123", input.From); + Assert.Equal("0x456", input.To); + Assert.Equal(123, input.Nonce.Value); + Assert.Equal(123, input.Gas.Value); + Assert.Equal(123, input.GasPrice.Value); + Assert.Equal(123, input.Value.Value); + Assert.Equal("0x123", input.Data); + Assert.Equal(123, input.ChainId.Value); + Assert.Equal(123, input.MaxFeePerGas.Value); + Assert.Equal(123, input.MaxPriorityFeePerGas.Value); + Assert.NotNull(input.ZkSync); + } + + [Fact(Timeout = 120000)] public async Task Create_ValidatesInputParameters() { - var client = ThirdwebClient.Create(secretKey: _secretKey); - var wallet = await PrivateKeyWallet.Generate(client); - var txInput = new ThirdwebTransactionInput() { From = await wallet.GetAddress(), To = Constants.ADDRESS_ZERO }; - var chainId = new BigInteger(421614); - var transaction = await ThirdwebTransaction.Create(wallet, txInput, chainId); + var wallet = await this.GetGuestAccount(); + var txInput = new ThirdwebTransactionInput(421614) { To = Constants.ADDRESS_ZERO }; + var transaction = await ThirdwebTransaction.Create(wallet, txInput); Assert.NotNull(transaction); } - [Fact] + [Fact(Timeout = 120000)] public async Task Create_ThrowsOnNoTo() { - var client = ThirdwebClient.Create(secretKey: _secretKey); - var wallet = await PrivateKeyWallet.Generate(client); - var txInput = new ThirdwebTransactionInput() { From = await wallet.GetAddress() }; - var ex = await Assert.ThrowsAsync(() => ThirdwebTransaction.Create(wallet, txInput, 421614)); + var client = this.Client; + var wallet = await this.GetGuestAccount(); + var txInput = new ThirdwebTransactionInput(421614) { }; + var ex = await Assert.ThrowsAsync(() => ThirdwebTransaction.Create(wallet, txInput)); Assert.Contains("Transaction recipient (to) must be provided", ex.Message); } - [Fact] - public async Task Create_ThrowsOnInvalidAddress() - { - var client = ThirdwebClient.Create(secretKey: _secretKey); - var wallet = await PrivateKeyWallet.Generate(client); - var txInput = new ThirdwebTransactionInput() { From = "0xHello", To = Constants.ADDRESS_ZERO }; - var ex = await Assert.ThrowsAsync(() => ThirdwebTransaction.Create(wallet, txInput, 421614)); - Assert.Contains("Transaction sender (from) must match wallet address", ex.Message); - } - - [Fact] + [Fact(Timeout = 120000)] public async Task Create_ThrowsOnNoWallet() { - var client = ThirdwebClient.Create(secretKey: _secretKey); - var wallet = await PrivateKeyWallet.Generate(client); - var txInput = new ThirdwebTransactionInput() { From = await wallet.GetAddress(), To = Constants.ADDRESS_ZERO }; - var ex = await Assert.ThrowsAsync(() => ThirdwebTransaction.Create(null, txInput, 421614)); + var client = this.Client; + var wallet = await this.GetGuestAccount(); + var txInput = new ThirdwebTransactionInput(421614) { To = Constants.ADDRESS_ZERO }; + var ex = await Assert.ThrowsAsync(() => ThirdwebTransaction.Create(null, txInput)); Assert.Contains("Wallet must be provided", ex.Message); } - [Fact] + [Fact(Timeout = 120000)] public async Task Create_ThrowsOnChainIdZero() { - var client = ThirdwebClient.Create(secretKey: _secretKey); - var wallet = await PrivateKeyWallet.Generate(client); - var txInput = new ThirdwebTransactionInput() { From = await wallet.GetAddress(), To = Constants.ADDRESS_ZERO }; - var ex = await Assert.ThrowsAsync(() => ThirdwebTransaction.Create(wallet, txInput, BigInteger.Zero)); + var client = this.Client; + var wallet = await this.GetGuestAccount(); + var ex = Assert.Throws(() => new ThirdwebTransactionInput(0) { To = Constants.ADDRESS_ZERO }); Assert.Contains("Invalid Chain ID", ex.Message); } - [Fact] + [Fact(Timeout = 120000)] public async Task ToString_OverridesCorrectly() { - var transaction = await CreateSampleTransaction(); + var transaction = await this.CreateSampleTransaction(); Assert.NotNull(transaction.ToString()); Assert.StartsWith("{", transaction.ToString()); } - [Fact] + [Fact(Timeout = 120000)] public async Task SetTo_UpdatesToAddress() { - var transaction = await CreateSampleTransaction(); + var transaction = await this.CreateSampleTransaction(); _ = transaction.SetTo("0x456"); Assert.Equal("0x456", transaction.Input.To); } - [Fact] + [Fact(Timeout = 120000)] public async Task SetValue_SetsValue() { - var transaction = await CreateSampleTransaction(); + var transaction = await this.CreateSampleTransaction(); var value = new BigInteger(1000); _ = transaction.SetValue(value); - Assert.Equal(value.ToHexBigInteger(), transaction.Input.Value); + Assert.Equal(value, transaction.Input.Value.Value); } - [Fact] + [Fact(Timeout = 120000)] public async Task SetData_SetsData() { - var transaction = await CreateSampleTransaction(); + var transaction = await this.CreateSampleTransaction(); var data = "0x123456"; _ = transaction.SetData(data); Assert.Equal(data, transaction.Input.Data); } - [Fact] + [Fact(Timeout = 120000)] public async Task SetGasPrice_SetsGasPrice() { - var transaction = await CreateSampleTransaction(); + var transaction = await this.CreateSampleTransaction(); var gas = new BigInteger(1000); _ = transaction.SetGasPrice(gas); - Assert.Equal(gas.ToHexBigInteger(), transaction.Input.GasPrice); + Assert.Equal(gas, transaction.Input.GasPrice.Value); } - [Fact] + [Fact(Timeout = 120000)] public async Task SetMaxFeePerGas_SetsMaxFeePerGas() { - var transaction = await CreateSampleTransaction(); + var transaction = await this.CreateSampleTransaction(); var gas = new BigInteger(1000); _ = transaction.SetMaxFeePerGas(gas); - Assert.Equal(gas.ToHexBigInteger(), transaction.Input.MaxFeePerGas); + Assert.Equal(gas, transaction.Input.MaxFeePerGas.Value); } - [Fact] + [Fact(Timeout = 120000)] public async Task SetMaxPriorityFeePerGas_SetsMaxPriorityFeePerGas() { - var transaction = await CreateSampleTransaction(); + var transaction = await this.CreateSampleTransaction(); var gas = new BigInteger(1000); _ = transaction.SetMaxPriorityFeePerGas(gas); - Assert.Equal(gas.ToHexBigInteger(), transaction.Input.MaxPriorityFeePerGas); + Assert.Equal(gas, transaction.Input.MaxPriorityFeePerGas.Value); } - [Fact] + [Fact(Timeout = 120000)] public async Task SetAllGasParams_ThrowsInvalid() { - var transaction = await CreateSampleTransaction(); + var transaction = await this.CreateSampleTransaction(); var gas = new BigInteger(1000); _ = transaction.SetTo(Constants.ADDRESS_ZERO); _ = transaction.SetGasPrice(gas); @@ -143,50 +156,40 @@ public async Task SetAllGasParams_ThrowsInvalid() Assert.Contains("Transaction GasPrice and MaxFeePerGas/MaxPriorityFeePerGas cannot be set at the same time", ex.Message); } - [Fact] + [Fact(Timeout = 120000)] public async Task Sign_SmartWallet_SignsTransaction() { - var client = ThirdwebClient.Create(secretKey: _secretKey); - var privateKeyAccount = await PrivateKeyWallet.Generate(client); + var privateKeyAccount = await this.GetGuestAccount(); var smartAccount = await SmartWallet.Create(personalWallet: privateKeyAccount, factoryAddress: "0xbf1C9aA4B1A085f7DA890a44E82B0A1289A40052", gasless: true, chainId: 421614); - var transaction = await ThirdwebTransaction.Create( - smartAccount, - new ThirdwebTransactionInput() - { - To = Constants.ADDRESS_ZERO, - Value = new HexBigInteger(0), - Data = "0x" - }, - 421614 - ); + var transaction = await ThirdwebTransaction.Create(smartAccount, new ThirdwebTransactionInput(421614) { To = Constants.ADDRESS_ZERO }); var signed = await ThirdwebTransaction.Sign(transaction); Assert.NotNull(signed); } - [Fact] + [Fact(Timeout = 120000)] public async Task Send_ThrowsIfToAddressNotProvided() { - var transaction = await CreateSampleTransaction(); + var transaction = await this.CreateSampleTransaction(); _ = transaction.SetTo(null); _ = await Assert.ThrowsAsync(() => ThirdwebTransaction.Send(transaction)); } - [Fact] + [Fact(Timeout = 120000)] public async Task Send_CorrectlyHandlesNonce() { - var transaction = await CreateSampleTransaction(); + var transaction = await this.CreateSampleTransaction(); _ = transaction.SetNonce(123); Assert.Equal("0x7b", transaction.Input.Nonce.HexValue); Assert.Equal("123", transaction.Input.Nonce.Value.ToString()); } - [Fact] + [Fact(Timeout = 120000)] public async Task SetZkSyncOptions_DefaultsToZeroNull() { // Both null - var transaction = await CreateSampleTransaction(); + var transaction = await this.CreateSampleTransaction(); _ = transaction.SetZkSyncOptions(new ZkSyncOptions()); Assert.Equal(0, transaction.Input.ZkSync?.Paymaster); Assert.Null(transaction.Input.ZkSync?.PaymasterInput); @@ -194,29 +197,27 @@ public async Task SetZkSyncOptions_DefaultsToZeroNull() Assert.Null(transaction.Input.ZkSync?.FactoryDeps); // Paymaster null - transaction = await CreateSampleTransaction(); + transaction = await this.CreateSampleTransaction(); _ = transaction.SetZkSyncOptions(new ZkSyncOptions(paymaster: null, paymasterInput: "0x")); Assert.Equal(0, transaction.Input.ZkSync?.Paymaster); - Assert.Null(transaction.Input.ZkSync?.PaymasterInput); + Assert.Equal(transaction.Input.ZkSync?.PaymasterInput, Array.Empty()); Assert.Null(transaction.Input.ZkSync?.GasPerPubdataByteLimit); - Assert.Null(transaction.Input.ZkSync?.FactoryDeps); + Assert.Equal(transaction.Input.ZkSync?.FactoryDeps, new List()); // PaymasterInput null - transaction = await CreateSampleTransaction(); + transaction = await this.CreateSampleTransaction(); _ = transaction.SetZkSyncOptions(new ZkSyncOptions(paymaster: "0x", paymasterInput: null)); Assert.Equal(0, transaction.Input.ZkSync?.Paymaster); - Assert.Null(transaction.Input.ZkSync?.PaymasterInput); + Assert.Equal(transaction.Input.ZkSync?.PaymasterInput, Array.Empty()); Assert.Null(transaction.Input.ZkSync?.GasPerPubdataByteLimit); - Assert.Null(transaction.Input.ZkSync?.FactoryDeps); + Assert.Equal(transaction.Input.ZkSync?.FactoryDeps, new List()); } - [Fact] + [Fact(Timeout = 120000)] public async Task Send_ZkSync_TransfersGaslessly() { - var transaction = await CreateSampleTransaction(); + var transaction = await this.CreateSampleTransaction(); _ = transaction.SetChainId(300); - _ = transaction.SetTo("0xbA226d47Cbb2731CBAA67C916c57d68484AA269F"); - _ = transaction.SetValue(BigInteger.Zero); _ = transaction.SetZkSyncOptions( new ZkSyncOptions( paymaster: "0xbA226d47Cbb2731CBAA67C916c57d68484AA269F", @@ -230,13 +231,11 @@ public async Task Send_ZkSync_TransfersGaslessly() Assert.StartsWith("0x", receipt.TransactionHash); } - [Fact] + [Fact(Timeout = 120000)] public async Task Send_ZkSync_NoGasPerPubFactoryDepsTransfersGaslessly() { - var transaction = await CreateSampleTransaction(); + var transaction = await this.CreateSampleTransaction(); _ = transaction.SetChainId(300); - _ = transaction.SetTo("0xbA226d47Cbb2731CBAA67C916c57d68484AA269F"); - _ = transaction.SetValue(BigInteger.Zero); _ = transaction.SetZkSyncOptions( new ZkSyncOptions( paymaster: "0xbA226d47Cbb2731CBAA67C916c57d68484AA269F", @@ -248,88 +247,70 @@ public async Task Send_ZkSync_NoGasPerPubFactoryDepsTransfersGaslessly() Assert.StartsWith("0x", receipt.TransactionHash); } - [Fact] + [Fact(Timeout = 120000)] public async Task EstimateTotalCosts_CalculatesCostsCorrectly() { - var transaction = await CreateSampleTransaction(); + var transaction = await this.CreateSampleTransaction(); _ = transaction.SetValue(new BigInteger(1000)); _ = transaction.SetGasLimit(21000); _ = transaction.SetGasPrice(new BigInteger(1000000000)); var costs = await ThirdwebTransaction.EstimateTotalCosts(transaction); - Assert.NotEqual(BigInteger.Zero, costs.wei); + Assert.NotEqual(BigInteger.Zero, costs.Wei); } - [Fact] + [Fact(Timeout = 120000)] public async Task EstimateTotalCosts_WithoutSetting_CalculatesCostsCorrectly() { - var transaction = await CreateSampleTransaction(); + var transaction = await this.CreateSampleTransaction(); transaction.Input.From = Constants.ADDRESS_ZERO; _ = transaction.SetValue(new BigInteger(1000)); var costs = await ThirdwebTransaction.EstimateTotalCosts(transaction); - Assert.NotEqual(BigInteger.Zero, costs.wei); + Assert.NotEqual(BigInteger.Zero, costs.Wei); } - [Fact] + [Fact(Timeout = 120000)] public async Task EstimateTotalCosts_WithoutValue_CalculatesCostsCorrectly() { - var transaction = await CreateSampleTransaction(); + var transaction = await this.CreateSampleTransaction(); var costs = await ThirdwebTransaction.EstimateTotalCosts(transaction); - Assert.NotEqual(BigInteger.Zero, costs.wei); + Assert.NotEqual(BigInteger.Zero, costs.Wei); } - [Fact] + [Fact(Timeout = 120000)] public async Task EstimateGasCosts_CalculatesCostsCorrectly() { - var transaction = await CreateSampleTransaction(); + var transaction = await this.CreateSampleTransaction(); _ = transaction.SetValue(new BigInteger(1000)); _ = transaction.SetGasLimit(21000); _ = transaction.SetGasPrice(new BigInteger(1000000000)); var costs = await ThirdwebTransaction.EstimateGasCosts(transaction); - Assert.NotEqual(BigInteger.Zero, costs.wei); + Assert.NotEqual(BigInteger.Zero, costs.Wei); } - [Fact] + [Fact(Timeout = 120000)] public async Task EstimateGasCosts_WithoutSetting_CalculatesCostsCorrectly() { - var transaction = await CreateSampleTransaction(); + var transaction = await this.CreateSampleTransaction(); transaction.Input.From = Constants.ADDRESS_ZERO; _ = transaction.SetValue(new BigInteger(1000)); var costs = await ThirdwebTransaction.EstimateGasCosts(transaction); - Assert.NotEqual(BigInteger.Zero, costs.wei); + Assert.NotEqual(BigInteger.Zero, costs.Wei); } - // [Fact] - // public async Task EstimateGasCosts_SmartWalletHigherThanPrivateKeyWallet() - // { - // var client = ThirdwebClient.Create(secretKey: _secretKey); - // var privateKeyAccount = await PrivateKeyWallet.Generate(client); - // var smartAccount = await SmartWallet.Create(client, personalWallet: privateKeyAccount, factoryAddress: "0xbf1C9aA4B1A085f7DA890a44E82B0A1289A40052", gasless: true, chainId: 421614); - - // var transaction = await ThirdwebTransaction.Create(client, smartAccount, new ThirdwebTransactionInput() { To = Constants.ADDRESS_ZERO, Value = new HexBigInteger(1000), }, 421614); - - // var smartCosts = await ThirdwebTransaction.EstimateGasCosts(transaction); - - // transaction = await ThirdwebTransaction.Create(client, privateKeyAccount, new ThirdwebTransactionInput() { To = Constants.ADDRESS_ZERO, Value = new HexBigInteger(1000), }, 421614); - - // var privateCosts = await ThirdwebTransaction.EstimateGasCosts(transaction); - - // Assert.True(smartCosts.wei > privateCosts.wei); - // } - - [Fact] + [Fact(Timeout = 120000)] public async Task EstimateTotalCosts_HigherThanGasCostsByValue() { - var transaction = await CreateSampleTransaction(); + var transaction = await this.CreateSampleTransaction(); _ = transaction.SetValue(new BigInteger(1000000000000000000)); // 100 gwei accounting for fluctuations _ = transaction.SetGasLimit(21000); @@ -338,23 +319,14 @@ public async Task EstimateTotalCosts_HigherThanGasCostsByValue() var costs = await Task.WhenAll(totalCostsTask, gasCostsTask); - Assert.True(costs[0].wei > costs[1].wei); - Assert.True(costs[0].wei - costs[1].wei == transaction.Input.Value.Value); + Assert.True(costs[0].Wei > costs[1].Wei); + Assert.True(costs[0].Wei - costs[1].Wei == transaction.Input.Value.Value); } - [Fact] + [Fact(Timeout = 120000)] public async Task EstimateGasFees_ReturnsCorrectly() { - var transaction = await ThirdwebTransaction.Create( - await PrivateKeyWallet.Generate(ThirdwebClient.Create(secretKey: _secretKey)), - new ThirdwebTransactionInput() - { - To = Constants.ADDRESS_ZERO, - Value = new HexBigInteger(0), - Data = "0x", - }, - 250 // fantom for 1559 non zero prio - ); + var transaction = await ThirdwebTransaction.Create(await this.GetGuestAccount(), new ThirdwebTransactionInput(250) { To = Constants.ADDRESS_ZERO }); (var maxFee, var maxPrio) = await ThirdwebTransaction.EstimateGasFees(transaction); @@ -363,20 +335,20 @@ await PrivateKeyWallet.Generate(ThirdwebClient.Create(secretKey: _secretKey)), Assert.NotEqual(maxFee, maxPrio); } - [Fact] + [Fact(Timeout = 120000)] public async Task EstimateGasPrice_BumpsCorrectly() { - var transaction = await CreateSampleTransaction(); + var transaction = await this.CreateSampleTransaction(); var gasPrice = await ThirdwebTransaction.EstimateGasPrice(transaction, withBump: false); var gasPriceWithBump = await ThirdwebTransaction.EstimateGasPrice(transaction, withBump: true); Assert.NotEqual(gasPrice, gasPriceWithBump); Assert.True(gasPriceWithBump > gasPrice); } - [Fact] + [Fact(Timeout = 120000)] public async Task Simulate_ThrowsInsufficientFunds() { - var transaction = await CreateSampleTransaction(); + var transaction = await this.CreateSampleTransaction(); _ = transaction.SetValue(new BigInteger(1000000000000000000)); _ = transaction.SetGasLimit(21000); @@ -384,23 +356,12 @@ public async Task Simulate_ThrowsInsufficientFunds() Assert.Contains("insufficient funds", exception.Message); } - [Fact] + [Fact(Timeout = 120000)] public async Task Simulate_ReturnsDataOrThrowsIntrinsic() { - var client = ThirdwebClient.Create(secretKey: _secretKey); - var privateKeyAccount = await PrivateKeyWallet.Generate(client); + var privateKeyAccount = await this.GetGuestAccount(); var smartAccount = await SmartWallet.Create(personalWallet: privateKeyAccount, factoryAddress: "0xbf1C9aA4B1A085f7DA890a44E82B0A1289A40052", gasless: true, chainId: 421614); - var transaction = await ThirdwebTransaction.Create( - smartAccount, - new ThirdwebTransactionInput() - { - To = Constants.ADDRESS_ZERO, - Value = new HexBigInteger(0), - Data = "0x", - Gas = new HexBigInteger(250000), - }, - 421614 - ); + var transaction = await ThirdwebTransaction.Create(smartAccount, new ThirdwebTransactionInput(chainId: 421614, to: Constants.ADDRESS_ZERO, gas: 250000)); try { @@ -413,15 +374,14 @@ public async Task Simulate_ReturnsDataOrThrowsIntrinsic() } } - [Fact] + [Fact(Timeout = 120000)] public async Task WaitForTransactionReceipt() { - var client = ThirdwebClient.Create(secretKey: _secretKey); + var client = this.Client; var chainId = 421614; var normalTxHash = "0x5a0b6cdb01ecfb25b368d3de1ac844414980ee3c330ec8c1435117b75027b5d7"; var failedTxHash = "0xd2840219ffe172377c8a455c13d95e4dca204d5c0dd72232093e092eef412488"; var aaTxHash = "0xbf76bd85e1759cf5cf9f4c7c52e76a74d32687f0b516017ff28192d04df50782"; - var aaSilentRevertTxHash = "0x8ada86c63846da7a3f91b8c8332de03f134e7619886425df858ee5400a9d9958"; var normalReceipt = await ThirdwebTransaction.WaitForTransactionReceipt(client, chainId, normalTxHash); Assert.NotNull(normalReceipt); @@ -431,30 +391,16 @@ public async Task WaitForTransactionReceipt() var aaReceipt = await ThirdwebTransaction.WaitForTransactionReceipt(client, chainId, aaTxHash); Assert.NotNull(aaReceipt); - - var aaFailedReceipt = await Assert.ThrowsAsync(async () => await ThirdwebTransaction.WaitForTransactionReceipt(client, chainId, aaSilentRevertTxHash)); - Assert.StartsWith($"Transaction {aaSilentRevertTxHash} execution silently reverted", aaFailedReceipt.Message); } - [Fact] - public async Task WaitForTransactionReceipt_AAReasonString() - { - var client = ThirdwebClient.Create(secretKey: _secretKey); - var chainId = 84532; - var aaSilentRevertTxHashWithReason = "0x5374743bbb749df47a279ac21e6ed472c30cd471923a7bc78db6a40e1b6924de"; - var aaFailedReceiptWithReason = await Assert.ThrowsAsync(async () => await ThirdwebTransaction.WaitForTransactionReceipt(client, chainId, aaSilentRevertTxHashWithReason)); - Assert.StartsWith($"Transaction {aaSilentRevertTxHashWithReason} execution silently reverted:", aaFailedReceiptWithReason.Message); - } - - [Fact] + [Fact(Timeout = 120000)] public async Task WaitForTransactionReceipt_CancellationToken() { - var client = ThirdwebClient.Create(secretKey: _secretKey); + var client = this.Client; var chainId = 421614; var normalTxHash = "0x5a0b6cdb01ecfb25b368d3de1ac844414980ee3c330ec8c1435117b75027b5d7"; var failedTxHash = "0xd2840219ffe172377c8a455c13d95e4dca204d5c0dd72232093e092eef412488"; var aaTxHash = "0xbf76bd85e1759cf5cf9f4c7c52e76a74d32687f0b516017ff28192d04df50782"; - var aaSilentRevertTxHash = "0x8ada86c63846da7a3f91b8c8332de03f134e7619886425df858ee5400a9d9958"; var cts = new CancellationTokenSource(); cts.CancelAfter(10000); @@ -473,22 +419,20 @@ public async Task WaitForTransactionReceipt_CancellationToken() cts = new CancellationTokenSource(); cts.CancelAfter(10000); - var aaFailedReceipt = await Assert.ThrowsAsync(async () => await ThirdwebTransaction.WaitForTransactionReceipt(client, chainId, aaSilentRevertTxHash, cts.Token)); - Assert.StartsWith($"Transaction {aaSilentRevertTxHash} execution silently reverted", aaFailedReceipt.Message); - - var infiniteTxHash = "0x55181384a4b908ddf6311cf0eb55ea0aa2b1ef4d9e0cc047eab9051fec284958"; - cts = new CancellationTokenSource(); - cts.CancelAfter(1); - var infiniteReceipt = await Assert.ThrowsAsync(async () => await ThirdwebTransaction.WaitForTransactionReceipt(client, chainId, infiniteTxHash, cts.Token)); - Assert.Equal($"Transaction receipt polling for hash {infiniteTxHash} was cancelled.", infiniteReceipt.Message); - - cts = new CancellationTokenSource(); - var infiniteReceipt2 = Assert.ThrowsAsync(() => ThirdwebTransaction.WaitForTransactionReceipt(client, chainId, infiniteTxHash, cts.Token)); - await Task.Delay(2000); - cts.Cancel(); - Assert.Equal($"Transaction receipt polling for hash {infiniteTxHash} was cancelled.", (await infiniteReceipt2).Message); var aaReceipt2 = await ThirdwebTransaction.WaitForTransactionReceipt(client, chainId, aaTxHash, CancellationToken.None); Assert.NotNull(aaReceipt2); } + + [Fact(Timeout = 120000)] + public async Task WaitForTransactionReceipt_ToStringReturnsJson() + { + var client = this.Client; + var chainId = 421614; + var normalTxHash = "0x5a0b6cdb01ecfb25b368d3de1ac844414980ee3c330ec8c1435117b75027b5d7"; + + var normalReceipt = await ThirdwebTransaction.WaitForTransactionReceipt(client, chainId, normalTxHash); + Assert.NotNull(normalReceipt); + Assert.StartsWith("{", normalReceipt.ToString()); + } } diff --git a/Thirdweb.Tests/Thirdweb.Transactions/Thirdweb.ZkSmartWallet.Tests.cs b/Thirdweb.Tests/Thirdweb.Transactions/Thirdweb.ZkSmartWallet.Tests.cs new file mode 100644 index 00000000..09b9dba4 --- /dev/null +++ b/Thirdweb.Tests/Thirdweb.Transactions/Thirdweb.ZkSmartWallet.Tests.cs @@ -0,0 +1,152 @@ +namespace Thirdweb.Tests.Wallets; + +public class ZkSmartWalletTests : BaseTests +{ + public ZkSmartWalletTests(ITestOutputHelper output) + : base(output) { } + + private async Task GetSmartAccount(int zkChainId = 300, bool gasless = true) + { + var privateKeyAccount = await this.GetGuestAccount(); + var smartAccount = await SmartWallet.Create(personalWallet: privateKeyAccount, gasless: gasless, chainId: zkChainId); + return smartAccount; + } + + [Fact(Timeout = 120000)] + public async Task GetAddress_Success() + { + var account = await this.GetSmartAccount(); + Assert.NotNull(await account.GetAddress()); + } + + [Fact(Timeout = 120000)] + public async Task PersonalSign_Success() + { + var account = await this.GetSmartAccount(zkChainId: 300); + var message = "Hello, World!"; + var signature = await account.PersonalSign(message); + Assert.NotNull(signature); + Assert.True(signature.Length > 0); + } + + [Fact(Timeout = 120000)] + public async Task CreateSessionKey_Throws() + { + var account = await this.GetSmartAccount(); + _ = await Assert.ThrowsAsync(async () => + await account.CreateSessionKey( + signerAddress: await account.GetAddress(), + approvedTargets: new List() { Constants.ADDRESS_ZERO }, + nativeTokenLimitPerTransactionInWei: "0", + permissionStartTimestamp: "0", + permissionEndTimestamp: (Utils.GetUnixTimeStampNow() + 86400).ToString(), + reqValidityStartTimestamp: "0", + reqValidityEndTimestamp: Utils.GetUnixTimeStampIn10Years().ToString() + ) + ); + } + + [Fact(Timeout = 120000)] + public async Task AddAdmin_Throws() + { + var account = await this.GetSmartAccount(); + _ = await Assert.ThrowsAsync(async () => await account.AddAdmin(Constants.ADDRESS_ZERO)); + } + + [Fact(Timeout = 120000)] + public async Task RemoveAdmin_Throws() + { + var account = await this.GetSmartAccount(); + _ = await Assert.ThrowsAsync(async () => await account.RemoveAdmin(Constants.ADDRESS_ZERO)); + } + + [Fact(Timeout = 120000)] + public async Task IsDeployed_ReturnsTrue() + { + var account = await this.GetSmartAccount(); + Assert.True(await account.IsDeployed()); + } + + [Fact(Timeout = 120000)] + public async Task SendGaslessZkTx_Success() + { + var account = await this.GetSmartAccount(); + var hash = await account.SendTransaction( + new ThirdwebTransactionInput(300) + { + From = await account.GetAddress(), + To = await account.GetAddress(), + Value = new Nethereum.Hex.HexTypes.HexBigInteger(0), + Data = "0x", + } + ); + Assert.NotNull(hash); + Assert.True(hash.Length == 66); + } + + // + // public async Task SendGaslessZkTx_ZkCandy_Success() + // { + // var account = await this.GetSmartAccount(zkChainId: 302); + // var hash = await account.SendTransaction( + // new ThirdwebTransactionInput(302) + // { + // From = await account.GetAddress(), + // To = await account.GetAddress(), + // Value = new Nethereum.Hex.HexTypes.HexBigInteger(0), + // Data = "0x" + // } + // ); + // Assert.NotNull(hash); + // Assert.True(hash.Length == 66); + // } + + // [Fact(Timeout = 120000)] + // public async Task SendGaslessZkTx_Abstract_Success() + // { + // var account = await this.GetSmartAccount(zkChainId: 11124); + // var hash = await account.SendTransaction( + // new ThirdwebTransactionInput(11124) + // { + // From = await account.GetAddress(), + // To = await account.GetAddress(), + // Value = new Nethereum.Hex.HexTypes.HexBigInteger(0), + // Data = "0x" + // } + // ); + // Assert.NotNull(hash); + // Assert.True(hash.Length == 66); + // } + + // [Fact(Timeout = 120000)] + // public async Task SendGaslessZkTx_Creator_Success() + // { + // var account = await this.GetSmartAccount(zkChainId: 4654); + // var hash = await account.SendTransaction( + // new ThirdwebTransactionInput(4654) + // { + // From = await account.GetAddress(), + // To = await account.GetAddress(), + // Value = new Nethereum.Hex.HexTypes.HexBigInteger(0), + // Data = "0x" + // } + // ); + // Assert.NotNull(hash); + // Assert.True(hash.Length == 66); + // } + + [Fact(Timeout = 120000)] + public async Task ZkSync_Switch() + { + var account = await this.GetSmartAccount(zkChainId: 300); + _ = await account.SendTransaction( + new ThirdwebTransactionInput(11124) + { + From = await account.GetAddress(), + To = await account.GetAddress(), + Value = new Nethereum.Hex.HexTypes.HexBigInteger(0), + Data = "0x", + } + ); + } +} diff --git a/Thirdweb.Tests/Thirdweb.Utils.Tests.cs b/Thirdweb.Tests/Thirdweb.Utils.Tests.cs deleted file mode 100644 index 1e562cd0..00000000 --- a/Thirdweb.Tests/Thirdweb.Utils.Tests.cs +++ /dev/null @@ -1,431 +0,0 @@ -using System.Numerics; - -namespace Thirdweb.Tests; - -public class UtilsTests : BaseTests -{ - public UtilsTests(ITestOutputHelper output) - : base(output) { } - - [Fact] - public void ComputeClientIdFromSecretKey() - { - Assert.True(Utils.ComputeClientIdFromSecretKey(_secretKey).Length == 32); - } - - [Fact] - public void HexConcat() - { - var hexStrings = new string[] { "0x1234", "0x5678", "0x90AB" }; - Assert.Equal("0x1234567890AB", Utils.HexConcat(hexStrings)); - } - - [Fact] - public void HashPrefixedMessage() - { - var messageStr = "Hello, World!"; - var message = System.Text.Encoding.UTF8.GetBytes(messageStr); - var hashStr = Utils.HashPrefixedMessage(messageStr); - var hash = Utils.HashPrefixedMessage(message); - Assert.Equal(hashStr, Utils.BytesToHex(hash)); - Assert.Equal("0xc8ee0d506e864589b799a645ddb88b08f5d39e8049f9f702b3b61fa15e55fc73", hashStr); - } - - [Fact] - public void HashMessage() - { - var messageStr = "Hello, World!"; - var message = System.Text.Encoding.UTF8.GetBytes(messageStr); - var hashStr = Utils.HashMessage(messageStr); - var hash = Utils.HashMessage(message); - Assert.Equal(hashStr, Utils.BytesToHex(hash)); - Assert.Equal("0xacaf3289d7b601cbd114fb36c4d29c85bbfd5e133f14cb355c3fd8d99367964f", hashStr); - } - - [Fact] - public void BytesToHex() - { - var bytes = new byte[] { 0x12, 0x34, 0x56, 0x78, 0x90, 0xAB, 0xCD, 0xEF }; - Assert.Equal("0x1234567890abcdef", Utils.BytesToHex(bytes)); - } - - [Fact] - public void HexToBytes() - { - var hex = "0x1234567890abcdef"; - var bytes = Utils.HexToBytes(hex); - Assert.Equal(new byte[] { 0x12, 0x34, 0x56, 0x78, 0x90, 0xAB, 0xCD, 0xEF }, bytes); - } - - [Fact] - public void StringToHex() - { - var str = "Hello, World!"; - var hex = Utils.StringToHex(str); - Assert.Equal("0x48656c6c6f2c20576f726c6421", hex); - } - - [Fact] - public void HexToString() - { - var hex = "0x48656c6c6f2c20576f726c6421"; - var str = Utils.HexToString(hex); - Assert.Equal("Hello, World!", str); - } - - [Fact] - public void GetUnixTimeStampNow() - { - var now = DateTimeOffset.UtcNow.ToUnixTimeSeconds(); - var now2 = Utils.GetUnixTimeStampNow(); - Assert.Equal(now, now2); - } - - [Fact] - public void GetUnixTimeStampIn10Years() - { - var now = DateTimeOffset.UtcNow.ToUnixTimeSeconds(); - var tenYears = 60 * 60 * 24 * 365 * 10; - var tenYearsFromNow = now + tenYears; - var tenYearsFromNow2 = Utils.GetUnixTimeStampIn10Years(); - Assert.Equal(tenYearsFromNow, tenYearsFromNow2); - } - - [Fact] - public void ReplaceIPFS() - { - var uri = "ipfs://QmXn1b6Q7"; - var gateway = "https://myawesomegateway.io/ipfs/"; - var replaced = Utils.ReplaceIPFS(uri, gateway); - Assert.Equal("https://myawesomegateway.io/ipfs/QmXn1b6Q7", replaced); - - uri = "https://myawesomegateway.io/ipfs/QmXn1b6Q7"; - replaced = Utils.ReplaceIPFS(uri, gateway); - Assert.Equal("https://myawesomegateway.io/ipfs/QmXn1b6Q7", replaced); - - uri = "ipfs://QmXn1b6Q7"; - gateway = null; - replaced = Utils.ReplaceIPFS(uri, gateway); - Assert.Equal("https://ipfs.io/ipfs/QmXn1b6Q7", replaced); - } - - [Fact] - public void ToWei_ConvertsCorrectly() - { - var eth = "1.5"; - var expectedWei = "1500000000000000000"; - Assert.Equal(expectedWei, Utils.ToWei(eth)); - } - - [Fact] - public void ToWei_ThrowsOnInvalidInput() - { - var invalidEth = "abc"; - _ = Assert.Throws(() => Utils.ToWei(invalidEth)); - } - - [Fact] - public void ToWei_ThrowsExceptionForInvalidInput() - { - var invalidEth = "invalid"; - _ = Assert.Throws(() => Utils.ToWei(invalidEth)); - } - - [Fact] - public void ToWei_ConvertsNegativeValue() - { - var negativeEth = "-1.5"; - var expectedWei = new BigInteger(-1.5 * Math.Pow(10, 18)).ToString(); - Assert.Equal(expectedWei, Utils.ToWei(negativeEth)); - } - - [Fact] - public void ToWei_ConvertsLargeFloat() - { - var largeEth = "1234567890.123456789"; - var expectedWei = new BigInteger(1234567890.123456789 * Math.Pow(10, 18)).ToString(); - Assert.Equal(expectedWei, Utils.ToWei(largeEth)); - } - - [Fact] - public void ToEth_ConvertsCorrectly() - { - var wei = "1500000000000000000"; - var expectedEth = "1.5000"; - Assert.Equal(expectedEth, Utils.ToEth(wei)); - } - - [Fact] - public void ToEth_WithCommas() - { - var wei = "1234500000000000000000"; - var expectedEth = "1,234.5000"; - Assert.Equal(expectedEth, Utils.ToEth(wei, 4, true)); - } - - [Fact] - public void ToEth_ConvertsZeroWei() - { - var zeroWei = "0"; - Assert.Equal("0.0000", Utils.ToEth(zeroWei)); - } - - [Fact] - public void ToEth_ConvertsSmallWei() - { - var smallWei = "1234"; - Assert.Equal("0.0000", Utils.ToEth(smallWei)); - } - - [Fact] - public void FormatERC20_NoDecimalsNoCommas() - { - var wei = "1500000000000000000"; - var expectedEth = "2"; - Assert.Equal(expectedEth, Utils.FormatERC20(wei, 0)); - } - - [Fact] - public void FormatERC20_LargeNumberWithCommas() - { - var wei = "1000000000000000000000000"; - var expectedEth = "1,000,000"; - Assert.Equal(expectedEth, Utils.FormatERC20(wei, 0, 18, true)); - } - - [Fact] - public void FormatERC20_ConvertsZeroWei() - { - var zeroWei = "0"; - Assert.Equal("0", Utils.FormatERC20(zeroWei, 0)); - } - - [Fact] - public void FormatERC20_SmallFractionalWei() - { - var fractionalWei = "10"; - Assert.Equal("0.0000", Utils.FormatERC20(fractionalWei, 4)); - } - - [Fact] - public void FormatERC20_ThrowsOnInvalidWei() - { - var invalidWei = "not_a_number"; - Assert.Throws(() => Utils.FormatERC20(invalidWei, 4)); - } - - [Fact] - public void GenerateSIWE_ReturnsCorrectValue() - { - var loginPayloadData = new LoginPayloadData - { - Version = "1", - ChainId = "421614", - Nonce = "0", - Address = Constants.ADDRESS_ZERO, - Domain = "thirdweb.com", - IssuedAt = "0", - ExpirationTime = "0", - InvalidBefore = "0" - }; - var expectedSIWE = - "thirdweb.com wants you to sign in with your Ethereum account:\n0x0000000000000000000000000000000000000000\n\n\nVersion: 1\nChain ID: 421614\nNonce: 0\nIssued At: 0\nExpiration Time: 0\nNot Before: 0"; - var siwe = Utils.GenerateSIWE(loginPayloadData); - Assert.Equal(expectedSIWE, siwe); - } - - [Fact] - public void GenerateSIWE_WithAllOptional_ReturnsCorrectValue() - { - var loginPayloadData = new LoginPayloadData - { - Version = "1", - ChainId = "421614", - Nonce = "0", - Address = Constants.ADDRESS_ZERO, - Domain = "thirdweb.com", - IssuedAt = "0", - ExpirationTime = "0", - InvalidBefore = "0", - Statement = "This is a statement", - Uri = "https://thirdweb.com", - Resources = new List() { "resource1", "resource2" } - }; - var expectedSIWE = - "thirdweb.com wants you to sign in with your Ethereum account:\n0x0000000000000000000000000000000000000000\n\nThis is a statement\n\nURI: https://thirdweb.com\nVersion: 1\nChain ID: 421614\nNonce: 0\nIssued At: 0\nExpiration Time: 0\nNot Before: 0\nResources:\n- resource1\n- resource2"; - var siwe = Utils.GenerateSIWE(loginPayloadData); - Assert.Equal(expectedSIWE, siwe); - } - - [Fact] - public void GenerateSIWE_WithResources_ReturnsCorrectValue() - { - var loginPayloadData = new LoginPayloadData - { - Version = "1", - ChainId = "421614", - Nonce = "0", - Address = Constants.ADDRESS_ZERO, - Domain = "thirdweb.com", - IssuedAt = "0", - ExpirationTime = "0", - InvalidBefore = "0", - Resources = new List() { "resource1", "resource2" } - }; - var expectedSIWE = - "thirdweb.com wants you to sign in with your Ethereum account:\n0x0000000000000000000000000000000000000000\n\n\nVersion: 1\nChain ID: 421614\nNonce: 0\nIssued At: 0\nExpiration Time: 0\nNot Before: 0\nResources:\n- resource1\n- resource2"; - var siwe = Utils.GenerateSIWE(loginPayloadData); - Assert.Equal(expectedSIWE, siwe); - } - - [Fact] - public void GenerateSIWE_ThrowsOnNullLoginPayloadData() - { - LoginPayloadData? loginPayloadData = null; - _ = Assert.Throws(() => Utils.GenerateSIWE(loginPayloadData)); - } - - [Fact] - public void GenerateSIWE_ThrowsOnNullDomain() - { - var loginPayloadData = new LoginPayloadData - { - Version = "1", - ChainId = "421614", - Nonce = "0", - Address = Constants.ADDRESS_ZERO, - Domain = null!, - IssuedAt = "0", - ExpirationTime = "0", - InvalidBefore = "0" - }; - _ = Assert.Throws(() => Utils.GenerateSIWE(loginPayloadData)); - } - - [Fact] - public void GenerateSIWE_ThrowsOnNullAddress() - { - var loginPayloadData = new LoginPayloadData - { - Version = "1", - ChainId = "421614", - Nonce = "0", - Address = null!, - Domain = "thirdweb.com", - IssuedAt = "0", - ExpirationTime = "0", - InvalidBefore = "0" - }; - _ = Assert.Throws(() => Utils.GenerateSIWE(loginPayloadData)); - } - - [Fact] - public void GenerateSIWE_ThrowsOnNullVersion() - { - var loginPayloadData = new LoginPayloadData - { - Version = null!, - ChainId = "421614", - Nonce = "0", - Address = Constants.ADDRESS_ZERO, - Domain = "thirdweb.com", - IssuedAt = "0", - ExpirationTime = "0", - InvalidBefore = "0" - }; - _ = Assert.Throws(() => Utils.GenerateSIWE(loginPayloadData)); - } - - [Fact] - public void GenerateSIWE_ThrowsOnNullChainId() - { - var loginPayloadData = new LoginPayloadData - { - Version = "1", - ChainId = null!, - Nonce = "0", - Address = Constants.ADDRESS_ZERO, - Domain = "thirdweb.com", - IssuedAt = "0", - ExpirationTime = "0", - InvalidBefore = "0" - }; - _ = Assert.Throws(() => Utils.GenerateSIWE(loginPayloadData)); - } - - [Fact] - public void GenerateSIWE_ThrowsOnNullNonce() - { - var loginPayloadData = new LoginPayloadData - { - Version = "1", - ChainId = "421614", - Nonce = null!, - Address = Constants.ADDRESS_ZERO, - Domain = "thirdweb.com", - IssuedAt = "0", - ExpirationTime = "0", - InvalidBefore = "0" - }; - _ = Assert.Throws(() => Utils.GenerateSIWE(loginPayloadData)); - } - - [Fact] - public void GenerateSIWE_ThrowsOnNullIssuedAt() - { - var loginPayloadData = new LoginPayloadData - { - Version = "1", - ChainId = "421614", - Nonce = "0", - Address = Constants.ADDRESS_ZERO, - Domain = "thirdweb.com", - IssuedAt = null!, - ExpirationTime = "0", - InvalidBefore = "0" - }; - _ = Assert.Throws(() => Utils.GenerateSIWE(loginPayloadData)); - } - - [Fact] - public void ToChecksumAddress_ReturnsCorrectValue() - { - var address = "0x5aAeb6053F3E94C9b9A09f33669435E7Ef1BeAed".ToLower(); - var checksumAddress = Utils.ToChecksumAddress(address); - Assert.Equal("0x5aAeb6053F3E94C9b9A09f33669435E7Ef1BeAed", checksumAddress); - } - - [Fact] - public void AdjustDecimals_ReturnsCorrectValue() - { - var value = new BigInteger(1500000000000000000); // 1.5 ETH - var adjustedValue = value.AdjustDecimals(18, 0); - Assert.Equal(new BigInteger(1), adjustedValue); - } - - [Fact] - public void AdjustDecimals_ReturnsCorrectValue2() - { - var value = new BigInteger(1500000000000000000); // 1.5 ETH - // Not having 18 decimals is a sin - var adjustedValue = value.AdjustDecimals(18, 2); - Assert.Equal(new BigInteger(150), adjustedValue); - } - - [Fact] - public void AdjustDecimals_ReturnsCorrectValue3() - { - var value = new BigInteger(1500000000000000000); // 1.5 ETH - var adjustedValue = value.AdjustDecimals(18, 18); - Assert.Equal(new BigInteger(1500000000000000000), adjustedValue); - } - - [Fact] - public void AdjustDecimals_ReturnsCorrectValue4() - { - var value = new BigInteger(1500000000000000000); // 1.5 ETH - // In some fictional world where ETH equivalent has 19 decimals - var adjustedValue = value.AdjustDecimals(18, 19); - Assert.Equal(new BigInteger(15000000000000000000), adjustedValue); - } -} diff --git a/Thirdweb.Tests/Thirdweb.Utils/Thirdweb.Utils.Tests.cs b/Thirdweb.Tests/Thirdweb.Utils/Thirdweb.Utils.Tests.cs new file mode 100644 index 00000000..62108582 --- /dev/null +++ b/Thirdweb.Tests/Thirdweb.Utils/Thirdweb.Utils.Tests.cs @@ -0,0 +1,844 @@ +using System.Numerics; +using Newtonsoft.Json.Linq; + +namespace Thirdweb.Tests.Utilities; + +public class UtilsTests : BaseTests +{ + public UtilsTests(ITestOutputHelper output) + : base(output) { } + + [Fact(Timeout = 120000)] + public void ComputeClientIdFromSecretKey() + { + Assert.True(Utils.ComputeClientIdFromSecretKey(this.SecretKey).Length == 32); + } + + [Fact(Timeout = 120000)] + public void HexConcat() + { + var hexStrings = new string[] { "0x1234", "0x5678", "0x90AB" }; + Assert.Equal("0x1234567890AB", Utils.HexConcat(hexStrings)); + } + + [Fact(Timeout = 120000)] + public void HashPrefixedMessage() + { + var messageStr = "Hello, World!"; + var message = System.Text.Encoding.UTF8.GetBytes(messageStr); + var hashStr = Utils.HashPrefixedMessage(messageStr); + var hash = Utils.HashPrefixedMessage(message); + Assert.Equal(hashStr, Utils.BytesToHex(hash)); + Assert.Equal("0xc8ee0d506e864589b799a645ddb88b08f5d39e8049f9f702b3b61fa15e55fc73", hashStr); + } + + [Fact(Timeout = 120000)] + public void HashMessage() + { + var messageStr = "Hello, World!"; + var hashStr = "0x" + Utils.HashMessage(messageStr); + + var message = System.Text.Encoding.UTF8.GetBytes(messageStr); + var hash = Utils.HashMessage(message); + + Assert.Equal(hashStr, Utils.BytesToHex(hash)); + Assert.Equal("0xacaf3289d7b601cbd114fb36c4d29c85bbfd5e133f14cb355c3fd8d99367964f", hashStr); + } + + [Fact(Timeout = 120000)] + public void BytesToHex() + { + var bytes = new byte[] { 0x12, 0x34, 0x56, 0x78, 0x90, 0xAB, 0xCD, 0xEF }; + Assert.Equal("0x1234567890abcdef", Utils.BytesToHex(bytes)); + } + + [Fact(Timeout = 120000)] + public void HexToBytes() + { + var hex = "0x1234567890abcdef"; + var bytes = Utils.HexToBytes(hex); + Assert.Equal(new byte[] { 0x12, 0x34, 0x56, 0x78, 0x90, 0xAB, 0xCD, 0xEF }, bytes); + } + + [Fact(Timeout = 120000)] + public void StringToHex() + { + var str = "Hello, World!"; + var hex = Utils.StringToHex(str); + Assert.Equal("0x48656c6c6f2c20576f726c6421", hex); + } + + [Fact(Timeout = 120000)] + public void HexToString() + { + var hex = "0x48656c6c6f2c20576f726c6421"; + var str = Utils.HexToString(hex); + Assert.Equal("Hello, World!", str); + } + + [Fact(Timeout = 120000)] + public void GetUnixTimeStampNow() + { + var now = DateTimeOffset.UtcNow.ToUnixTimeSeconds(); + var now2 = Utils.GetUnixTimeStampNow(); + Assert.Equal(now, now2); + } + + [Fact(Timeout = 120000)] + public void GetUnixTimeStampIn10Years() + { + var now = DateTimeOffset.UtcNow.ToUnixTimeSeconds(); + var tenYears = 60 * 60 * 24 * 365 * 10; + var tenYearsFromNow = now + tenYears; + var tenYearsFromNow2 = Utils.GetUnixTimeStampIn10Years(); + Assert.Equal(tenYearsFromNow, tenYearsFromNow2); + } + + [Fact(Timeout = 120000)] + public void ReplaceIPFS() + { + var uri = "ipfs://QmXn1b6Q7"; + var gateway = "https://myawesomegateway.io/ipfs/"; + var replaced = Utils.ReplaceIPFS(uri, gateway); + Assert.Equal("https://myawesomegateway.io/ipfs/QmXn1b6Q7", replaced); + + uri = "https://myawesomegateway.io/ipfs/QmXn1b6Q7"; + replaced = Utils.ReplaceIPFS(uri, gateway); + Assert.Equal("https://myawesomegateway.io/ipfs/QmXn1b6Q7", replaced); + + uri = "ipfs://QmXn1b6Q7"; + gateway = null; + replaced = Utils.ReplaceIPFS(uri, gateway); + Assert.Equal("https://ipfs.io/ipfs/QmXn1b6Q7", replaced); + } + + [Fact(Timeout = 120000)] + public void ToWei_ConvertsCorrectly() + { + var eth = "1.5"; + var expectedWei = "1500000000000000000"; + Assert.Equal(expectedWei, Utils.ToWei(eth)); + } + + [Fact(Timeout = 120000)] + public void ToWei_ThrowsOnInvalidInput() + { + var invalidEth = "abc"; + _ = Assert.Throws(() => Utils.ToWei(invalidEth)); + } + + [Fact(Timeout = 120000)] + public void ToWei_ThrowsExceptionForInvalidInput() + { + var invalidEth = "invalid"; + _ = Assert.Throws(() => Utils.ToWei(invalidEth)); + } + + [Fact(Timeout = 120000)] + public void ToWei_ConvertsNegativeValue() + { + var negativeEth = "-1.5"; + var expectedWei = new BigInteger(-1.5 * Math.Pow(10, 18)).ToString(); + Assert.Equal(expectedWei, Utils.ToWei(negativeEth)); + } + + [Fact(Timeout = 120000)] + public void ToWei_ConvertsLargeFloat() + { + var largeEth = "1234567890.123456789"; + var expectedWei = new BigInteger(1234567890.123456789 * Math.Pow(10, 18)).ToString(); + Assert.Equal(expectedWei, Utils.ToWei(largeEth)); + } + + [Fact(Timeout = 120000)] + public void ToEth_ConvertsCorrectly() + { + var wei = "1500000000000000000"; + var expectedEth = "1.5000"; + Assert.Equal(expectedEth, Utils.ToEth(wei)); + } + + [Fact(Timeout = 120000)] + public void ToEth_WithCommas() + { + var wei = "1234500000000000000000"; + var expectedEth = "1,234.5000"; + Assert.Equal(expectedEth, Utils.ToEth(wei, 4, true)); + } + + [Fact(Timeout = 120000)] + public void ToEth_ConvertsZeroWei() + { + var zeroWei = "0"; + Assert.Equal("0.0000", Utils.ToEth(zeroWei)); + } + + [Fact(Timeout = 120000)] + public void ToEth_ConvertsSmallWei() + { + var smallWei = "1234"; + Assert.Equal("0.0000", Utils.ToEth(smallWei)); + } + + [Fact(Timeout = 120000)] + public void FormatERC20_NoDecimalsNoCommas() + { + var wei = "1500000000000000000"; + var expectedEth = "2"; + Assert.Equal(expectedEth, Utils.FormatERC20(wei, 0)); + } + + [Fact(Timeout = 120000)] + public void FormatERC20_LargeNumberWithCommas() + { + var wei = "1000000000000000000000000"; + var expectedEth = "1,000,000"; + Assert.Equal(expectedEth, Utils.FormatERC20(wei, 0, 18, true)); + } + + [Fact(Timeout = 120000)] + public void FormatERC20_ConvertsZeroWei() + { + var zeroWei = "0"; + Assert.Equal("0", Utils.FormatERC20(zeroWei, 0)); + } + + [Fact(Timeout = 120000)] + public void FormatERC20_SmallFractionalWei() + { + var fractionalWei = "10"; + Assert.Equal("0.0000", Utils.FormatERC20(fractionalWei, 4)); + } + + [Fact(Timeout = 120000)] + public void FormatERC20_ThrowsOnInvalidWei() + { + var invalidWei = "not_a_number"; + _ = Assert.Throws(() => Utils.FormatERC20(invalidWei, 4)); + } + + [Fact(Timeout = 120000)] + public void GenerateSIWE_ReturnsCorrectValue() + { + var loginPayloadData = new LoginPayloadData + { + Version = "1", + ChainId = "421614", + Nonce = "0", + Address = Constants.ADDRESS_ZERO, + Domain = "thirdweb.com", + IssuedAt = "0", + ExpirationTime = "0", + InvalidBefore = "0", + }; + var expectedSIWE = + "thirdweb.com wants you to sign in with your Ethereum account:\n0x0000000000000000000000000000000000000000\n\n\nVersion: 1\nChain ID: 421614\nNonce: 0\nIssued At: 0\nExpiration Time: 0\nNot Before: 0"; + var siwe = Utils.GenerateSIWE(loginPayloadData); + Assert.Equal(expectedSIWE, siwe); + } + + [Fact(Timeout = 120000)] + public void GenerateSIWE_WithAllOptional_ReturnsCorrectValue() + { + var loginPayloadData = new LoginPayloadData + { + Version = "1", + ChainId = "421614", + Nonce = "0", + Address = Constants.ADDRESS_ZERO, + Domain = "thirdweb.com", + IssuedAt = "0", + ExpirationTime = "0", + InvalidBefore = "0", + Statement = "This is a statement", + Uri = "https://thirdweb.com", + Resources = new List() { "resource1", "resource2" }, + }; + var expectedSIWE = + "thirdweb.com wants you to sign in with your Ethereum account:\n0x0000000000000000000000000000000000000000\n\nThis is a statement\n\nURI: https://thirdweb.com\nVersion: 1\nChain ID: 421614\nNonce: 0\nIssued At: 0\nExpiration Time: 0\nNot Before: 0\nResources:\n- resource1\n- resource2"; + var siwe = Utils.GenerateSIWE(loginPayloadData); + Assert.Equal(expectedSIWE, siwe); + } + + [Fact(Timeout = 120000)] + public void GenerateSIWE_WithResources_ReturnsCorrectValue() + { + var loginPayloadData = new LoginPayloadData + { + Version = "1", + ChainId = "421614", + Nonce = "0", + Address = Constants.ADDRESS_ZERO, + Domain = "thirdweb.com", + IssuedAt = "0", + ExpirationTime = "0", + InvalidBefore = "0", + Resources = new List() { "resource1", "resource2" }, + }; + var expectedSIWE = + "thirdweb.com wants you to sign in with your Ethereum account:\n0x0000000000000000000000000000000000000000\n\n\nVersion: 1\nChain ID: 421614\nNonce: 0\nIssued At: 0\nExpiration Time: 0\nNot Before: 0\nResources:\n- resource1\n- resource2"; + var siwe = Utils.GenerateSIWE(loginPayloadData); + Assert.Equal(expectedSIWE, siwe); + } + + [Fact(Timeout = 120000)] + public void GenerateSIWE_ThrowsOnNullLoginPayloadData() + { + LoginPayloadData? loginPayloadData = null; + _ = Assert.Throws(() => Utils.GenerateSIWE(loginPayloadData)); + } + + [Fact(Timeout = 120000)] + public void GenerateSIWE_ThrowsOnNullDomain() + { + var loginPayloadData = new LoginPayloadData + { + Version = "1", + ChainId = "421614", + Nonce = "0", + Address = Constants.ADDRESS_ZERO, + Domain = null!, + IssuedAt = "0", + ExpirationTime = "0", + InvalidBefore = "0", + }; + _ = Assert.Throws(() => Utils.GenerateSIWE(loginPayloadData)); + } + + [Fact(Timeout = 120000)] + public void GenerateSIWE_ThrowsOnNullAddress() + { + var loginPayloadData = new LoginPayloadData + { + Version = "1", + ChainId = "421614", + Nonce = "0", + Address = null!, + Domain = "thirdweb.com", + IssuedAt = "0", + ExpirationTime = "0", + InvalidBefore = "0", + }; + _ = Assert.Throws(() => Utils.GenerateSIWE(loginPayloadData)); + } + + [Fact(Timeout = 120000)] + public void GenerateSIWE_ThrowsOnNullVersion() + { + var loginPayloadData = new LoginPayloadData + { + Version = null!, + ChainId = "421614", + Nonce = "0", + Address = Constants.ADDRESS_ZERO, + Domain = "thirdweb.com", + IssuedAt = "0", + ExpirationTime = "0", + InvalidBefore = "0", + }; + _ = Assert.Throws(() => Utils.GenerateSIWE(loginPayloadData)); + } + + [Fact(Timeout = 120000)] + public void GenerateSIWE_ThrowsOnNullChainId() + { + var loginPayloadData = new LoginPayloadData + { + Version = "1", + ChainId = null!, + Nonce = "0", + Address = Constants.ADDRESS_ZERO, + Domain = "thirdweb.com", + IssuedAt = "0", + ExpirationTime = "0", + InvalidBefore = "0", + }; + _ = Assert.Throws(() => Utils.GenerateSIWE(loginPayloadData)); + } + + [Fact(Timeout = 120000)] + public void GenerateSIWE_ThrowsOnNullNonce() + { + var loginPayloadData = new LoginPayloadData + { + Version = "1", + ChainId = "421614", + Nonce = null!, + Address = Constants.ADDRESS_ZERO, + Domain = "thirdweb.com", + IssuedAt = "0", + ExpirationTime = "0", + InvalidBefore = "0", + }; + _ = Assert.Throws(() => Utils.GenerateSIWE(loginPayloadData)); + } + + [Fact(Timeout = 120000)] + public void GenerateSIWE_ThrowsOnNullIssuedAt() + { + var loginPayloadData = new LoginPayloadData + { + Version = "1", + ChainId = "421614", + Nonce = "0", + Address = Constants.ADDRESS_ZERO, + Domain = "thirdweb.com", + IssuedAt = null!, + ExpirationTime = "0", + InvalidBefore = "0", + }; + _ = Assert.Throws(() => Utils.GenerateSIWE(loginPayloadData)); + } + + [Fact(Timeout = 120000)] + public void ToChecksumAddress_ReturnsCorrectValue() + { + var address = "0x5aAeb6053F3E94C9b9A09f33669435E7Ef1BeAed".ToLower(); + var checksumAddress = Utils.ToChecksumAddress(address); + Assert.Equal("0x5aAeb6053F3E94C9b9A09f33669435E7Ef1BeAed", checksumAddress); + } + + [Fact(Timeout = 120000)] + public void AdjustDecimals_ReturnsCorrectValue() + { + var value = new BigInteger(1500000000000000000); // 1.5 ETH + var adjustedValue = value.AdjustDecimals(18, 0); + Assert.Equal(new BigInteger(1), adjustedValue); + } + + [Fact(Timeout = 120000)] + public void AdjustDecimals_ReturnsCorrectValue2() + { + var value = new BigInteger(1500000000000000000); // 1.5 ETH + // Not having 18 decimals is a sin + var adjustedValue = value.AdjustDecimals(18, 2); + Assert.Equal(new BigInteger(150), adjustedValue); + } + + [Fact(Timeout = 120000)] + public void AdjustDecimals_ReturnsCorrectValue3() + { + var value = new BigInteger(1500000000000000000); // 1.5 ETH + var adjustedValue = value.AdjustDecimals(18, 18); + Assert.Equal(new BigInteger(1500000000000000000), adjustedValue); + } + + [Fact(Timeout = 120000)] + public void AdjustDecimals_ReturnsCorrectValue4() + { + var value = new BigInteger(1500000000000000000); // 1.5 ETH + // In some fictional world where ETH equivalent has 19 decimals + var adjustedValue = value.AdjustDecimals(18, 19); + Assert.Equal(new BigInteger(15000000000000000000), adjustedValue); + } + + [Fact(Timeout = 120000)] + public async Task FetchThirdwebChainDataAsync_ReturnsChainData_WhenResponseIsSuccessful() + { + var timer = System.Diagnostics.Stopwatch.StartNew(); + var chainId = new BigInteger(1); + + var chainData = await Utils.GetChainMetadata(this.Client, chainId); + Assert.NotNull(chainData); + _ = Assert.IsType(chainData); + + Assert.Equal("Ethereum Mainnet", chainData.Name); + Assert.Equal("eth", chainData.ShortName); + Assert.Equal(1, chainData.ChainId); + Assert.Equal(1, chainData.NetworkId); + Assert.Equal("ethereum", chainData.Slug); + Assert.Equal("https://ethereum.org", chainData.InfoURL); + Assert.NotNull(chainData.Icon); + Assert.NotNull(chainData.NativeCurrency); + Assert.NotNull(chainData.NativeCurrency.Name); + Assert.NotNull(chainData.NativeCurrency.Symbol); + Assert.Equal(18, chainData.NativeCurrency.Decimals); + Assert.NotNull(chainData.Explorers); + + timer.Stop(); + var timeAttempt1 = timer.ElapsedMilliseconds; + + timer.Restart(); + var chainData2 = await Utils.GetChainMetadata(this.Client, chainId); + Assert.NotNull(chainData2); + _ = Assert.IsType(chainData); + + var timeAttempt2 = timer.ElapsedMilliseconds; + Assert.True(timeAttempt1 > timeAttempt2); + } + + [Fact(Timeout = 120000)] + public async Task FetchThirdwebChainDataAsync_ReturnsStack_WhenResponseIsSuccessful() + { + var chainId = new BigInteger(4654); + + var chainData = await Utils.GetChainMetadata(this.Client, chainId); + Assert.NotNull(chainData); + _ = Assert.IsType(chainData); + Assert.NotNull(chainData.StackType); + Assert.Contains("zksync", chainData.StackType); + } + + [Fact(Timeout = 120000)] + public async Task FetchThirdwebChainDataAsync_ThrowsException_WhenResponseHasError() + { + var chainId = 123124125418928133; + + var exception = await Assert.ThrowsAsync(async () => await Utils.GetChainMetadata(this.Client, chainId)); + + Assert.Contains("Failed to fetch chain data", exception.Message); + } + + [Fact(Timeout = 120000)] + public async Task FetchThirdwebChainDataAsync_ThrowsException_InvalidChainId() + { + var chainId = BigInteger.Zero; + + var exception = await Assert.ThrowsAsync(async () => await Utils.GetChainMetadata(this.Client, chainId)); + + Assert.Contains("Invalid chain", exception.Message); + } + + [Fact(Timeout = 120000)] + public async void ToJsonExternalWalletFriendly_ReturnsCorrectValue4() + { + var pkWallet = await this.GetGuestAccount(); // Assume external wallet + var msg = new AccountAbstraction.AccountMessage { Message = new byte[] { 0x01, 0x02, 0x03, 0x04 } }; + var verifyingContract = await pkWallet.GetAddress(); // doesn't matter here + var typedDataRaw = EIP712.GetTypedDefinition_SmartAccount_AccountMessage("Account", "1", 137, verifyingContract); + var json = Utils.ToJsonExternalWalletFriendly(typedDataRaw, msg); + var jsonObject = JObject.Parse(json); + var internalMsg = jsonObject.SelectToken("$.message.message"); + Assert.NotNull(internalMsg); + Assert.Equal("0x01020304", internalMsg); + } + + [Fact(Timeout = 120000)] + public void HexToBytes32_ReturnsCorrectly() + { + var hex = "0x1"; + var bytes32 = Utils.HexToBytes32(hex); + var expectedBytes = new byte[32]; + expectedBytes[31] = 1; + Assert.Equal(expectedBytes, bytes32); + + hex = "1"; + bytes32 = Utils.HexToBytes32(hex); + Assert.Equal(expectedBytes, bytes32); + + var hexTooLarge = "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef"; + _ = Assert.Throws(() => Utils.HexToBytes32(hexTooLarge)); + } + + [Fact(Timeout = 120000)] + public async Task GetENSFromAddress_ThrowsException_WhenAddressIsNull() + { + var exception = await Assert.ThrowsAsync(async () => await Utils.GetENSFromAddress(this.Client, null)); + + Assert.Equal("address", exception.ParamName); + } + + [Fact(Timeout = 120000)] + public async Task GetENSFromAddress_ThrowsException_WhenAddressIsInvalid() + { + var invalidAddress = "invalid_address"; + var exception = await Assert.ThrowsAsync(async () => await Utils.GetENSFromAddress(this.Client, invalidAddress)); + + Assert.Contains("Invalid address", exception.Message); + } + + [Fact(Timeout = 120000)] + public async Task GetENSFromAddress_ReturnsENSName_WhenAddressIsValid() + { + var validAddress = "0xDaaBDaaC8073A7dAbdC96F6909E8476ab4001B34"; + var expectedENSName = "0xfirekeeper.eth"; + var ensName = await Utils.GetENSFromAddress(this.Client, validAddress); + + Assert.Equal(expectedENSName, ensName); + + ensName = await Utils.GetENSFromAddress(this.Client, validAddress); + Assert.Equal(expectedENSName, ensName); + } + + [Fact(Timeout = 120000)] + public async Task GetAddressFromENS_ThrowsException_WhenENSNameIsNull() + { + var exception = await Assert.ThrowsAsync(async () => await Utils.GetAddressFromENS(this.Client, null)); + Assert.Equal("ensName", exception.ParamName); + } + + [Fact(Timeout = 120000)] + public async Task GetAddressFromENS_ReturnsENSName_WhenENSNameIsAlreadyAddress() + { + var address = "0xDaaBDaaC8073A7dAbdC96F6909E8476ab4001B34".ToLower(); + var result = await Utils.GetAddressFromENS(this.Client, address); + Assert.Equal(address.ToChecksumAddress(), result); + } + + [Fact(Timeout = 120000)] + public async Task GetAddressFromENS_ThrowsException_WhenENSNameIsInvalid() + { + var invalidENSName = "invalid_name"; + var exception = await Assert.ThrowsAsync(async () => await Utils.GetAddressFromENS(this.Client, invalidENSName)); + + Assert.Contains("Invalid ENS name", exception.Message); + } + + [Fact(Timeout = 120000)] + public async Task GetAddressFromENS_ReturnsAddress_WhenENSNameIsValid() + { + var validENSName = "0xfirekeeper.eth"; + var expectedAddress = "0xDaaBDaaC8073A7dAbdC96F6909E8476ab4001B34"; + var result = await Utils.GetAddressFromENS(this.Client, validENSName); + + Assert.Equal(expectedAddress.ToChecksumAddress(), result); + + result = await Utils.GetAddressFromENS(this.Client, validENSName); + Assert.Equal(expectedAddress.ToChecksumAddress(), result); + } + + /* + public static async Task IsDeployed(ThirdwebClient client, BigInteger chainId, string address) + { + var rpc = ThirdwebRPC.GetRpcInstance(client, chainId); + var code = await rpc.SendRequestAsync("eth_getCode", address, "latest"); + return code != "0x"; + } + */ + + [Fact(Timeout = 120000)] + public async Task IsDeployed_ReturnsTrue_WhenContractIsDeployed() + { + var chainId = new BigInteger(1); + var address = "0xBC4CA0EdA7647A8aB7C2061c2E118A18a936f13D"; + var isDeployed = await Utils.IsDeployed(this.Client, chainId, address); + + Assert.True(isDeployed); + } + + [Fact(Timeout = 120000)] + public async Task IsDeployed_ReturnsFalse_WhenContractIsNotDeployed() + { + var isDeployed = await Utils.IsDeployed(this.Client, 1, "0x519D4173E79214D0e7857CcbF1DAb20ceADe85eE"); + Assert.False(isDeployed); + } + + [Fact(Timeout = 120000)] + public async Task GetSocialProfiles_WithENS() + { + var socialProfiles = await Utils.GetSocialProfiles(this.Client, "joenrv.eth"); + + Assert.NotNull(socialProfiles); + Assert.True(socialProfiles.EnsProfiles.Count > 0); + } + + [Fact(Timeout = 120000)] + public async Task GetSocialProfiles_WithAddress() + { + var address = "0x2247d5d238d0f9d37184d8332aE0289d1aD9991b"; + var socialProfiles = await Utils.GetSocialProfiles(this.Client, address); + + Assert.NotNull(socialProfiles); + Assert.True(socialProfiles.EnsProfiles.Count > 0); + } + + [Fact(Timeout = 120000)] + public async Task GetSocialProfiles_ThrowsException_WhenInputIsInvalid() + { + var invalidInput = "invalid_input"; + var exception = await Assert.ThrowsAsync(async () => await Utils.GetSocialProfiles(this.Client, invalidInput)); + + Assert.Contains("Invalid address or ENS.", exception.Message); + } + + [Fact(Timeout = 120000)] + public async Task GetSocialProfiles_ThrowsException_WhenInputIsNull() + { + var exception = await Assert.ThrowsAsync(async () => await Utils.GetSocialProfiles(this.Client, null)); + + Assert.Equal("addressOrEns", exception.ParamName); + } + + [Fact(Timeout = 120000)] + public async Task GetSocialProfiles_ThrowsException_InvalidAuth() + { + var client = ThirdwebClient.Create("a"); + var exception = await Assert.ThrowsAsync(async () => await Utils.GetSocialProfiles(client, "joenrv.eth")); + + Assert.Contains("Failed to fetch social profiles", exception.Message); + } + + [Fact(Timeout = 120000)] + public async Task IsEip155Enforced_ReturnsFalse_WhenChainIs1() + { + var chainId = new BigInteger(1); + var isEip155Enforced = await Utils.IsEip155Enforced(this.Client, chainId); + + Assert.False(isEip155Enforced); + } + + // [Fact(Timeout = 120000)] + // public async Task IsEip155Enforced_ReturnsTrue_WhenChainIs842() + // { + // var chainId = new BigInteger(842); + // var isEip155Enforced = await Utils.IsEip155Enforced(this.Client, chainId); + + // Assert.True(isEip155Enforced); + // } + + [Fact(Timeout = 120000)] + public void ReconstructHttpClient_WithHeaders() + { + var newClient = Utils.ReconstructHttpClient(this.Client.HttpClient, this.Client.HttpClient.Headers); + var newHeaders = newClient.Headers; + + Assert.NotNull(newHeaders); + Assert.Equal(this.Client.HttpClient.Headers, newHeaders); + } + + [Fact(Timeout = 120000)] + public void ReconstructHttpClient_WithoutHeaders() + { + var newClient = Utils.ReconstructHttpClient(this.Client.HttpClient); + var newHeaders = newClient.Headers; + + Assert.NotNull(newHeaders); + Assert.Empty(newHeaders); + } + + [Fact(Timeout = 120000)] + public async Task FetchGasPrice_Success() + { + var gasPrice = await Utils.FetchGasPrice(this.Client, 1); + Assert.True(gasPrice > 0); + } + + [Fact(Timeout = 120000)] + public async Task FetchGasFees_1() + { + var (maxFee, maxPrio) = await Utils.FetchGasFees(this.Client, 1); + Assert.True(maxFee > 0); + Assert.True(maxPrio > 0); + Assert.NotEqual(maxFee, maxPrio); + } + + [Fact(Timeout = 120000)] + public async Task FetchGasFees_137() + { + var (maxFee, maxPrio) = await Utils.FetchGasFees(this.Client, 137); + Assert.True(maxFee > 0); + Assert.True(maxPrio > 0); + Assert.True(maxFee > maxPrio); + } + + [Fact(Timeout = 120000)] + public async Task FetchGasFees_80002() + { + var (maxFee, maxPrio) = await Utils.FetchGasFees(this.Client, 80002); + Assert.True(maxFee > 0); + Assert.True(maxPrio > 0); + Assert.True(maxFee > maxPrio); + } + + [Fact] + public void PreprocessTypedDataJson_FormatsBigIntegers() + { + // Arrange + var inputJson = + /*lang=json,strict*/ + @" + { + ""from"": 973250616940336452028326648501327235277017847475, + ""data"": ""0x"", + ""nested"": { + ""value"": 4294967295 + }, + ""array"": [ + 123, + 973250616940336452028326648501327235277017847475 + ] + }"; + + var expectedJson = + /*lang=json,strict*/ + @" + { + ""from"": ""973250616940336452028326648501327235277017847475"", + ""data"": ""0x"", + ""nested"": { + ""value"": 4294967295 + }, + ""array"": [ + 123, + ""973250616940336452028326648501327235277017847475"" + ] + }"; + + // Act + var processedJson = Utils.PreprocessTypedDataJson(inputJson); + + // Assert + var expectedJObject = JObject.Parse(expectedJson); + var processedJObject = JObject.Parse(processedJson); + + Assert.Equal(expectedJObject, processedJObject); + } + + [Fact] + public void PreprocessTypedDataJson_NoLargeNumbers_NoChange() + { + // Arrange + var inputJson = + /*lang=json,strict*/ + @" + { + ""value"": 123, + ""nested"": { + ""value"": 456 + }, + ""array"": [1, 2, 3] + }"; + + // Act + var processedJson = Utils.PreprocessTypedDataJson(inputJson); + var expectedJObject = JObject.Parse(inputJson); + var processedJObject = JObject.Parse(processedJson); + + // Assert + Assert.Equal(expectedJObject, processedJObject); + } + + [Fact] + public void PreprocessTypedDataJson_NestedLargeNumbers() + { + // Arrange + var inputJson = + /*lang=json,strict*/ + @" + { + ""nested"": { + ""value"": 973250616940336452028326648501327235277017847475 + }, + ""array"": [123, 973250616940336452028326648501327235277017847475] + }"; + + var expectedJson = + /*lang=json,strict*/ + @" + { + ""nested"": { + ""value"": ""973250616940336452028326648501327235277017847475"" + }, + ""array"": [123, ""973250616940336452028326648501327235277017847475""] + }"; + + // Act + var processedJson = Utils.PreprocessTypedDataJson(inputJson); + + // Assert + var expectedJObject = JObject.Parse(expectedJson); + var processedJObject = JObject.Parse(processedJson); + + Assert.Equal(expectedJObject, processedJObject); + } +} diff --git a/Thirdweb.Tests/Thirdweb.Wallets/Thirdweb.SmartWallet.Tests.cs b/Thirdweb.Tests/Thirdweb.Wallets/Thirdweb.SmartWallet.Tests.cs new file mode 100644 index 00000000..ca62cbc1 --- /dev/null +++ b/Thirdweb.Tests/Thirdweb.Wallets/Thirdweb.SmartWallet.Tests.cs @@ -0,0 +1,482 @@ +namespace Thirdweb.Tests.Wallets; + +public class SmartWalletTests : BaseTests +{ + public SmartWalletTests(ITestOutputHelper output) + : base(output) { } + + private async Task GetSmartAccount() + { + var privateKeyAccount = await this.GetGuestAccount(); + var smartAccount = await SmartWallet.Create(personalWallet: privateKeyAccount, gasless: true, chainId: 421614); + return smartAccount; + } + + [Fact(Timeout = 120000)] + public async Task Initialization_Success() + { + var account = await this.GetSmartAccount(); + Assert.NotNull(await account.GetAddress()); + } + + [Fact(Timeout = 120000)] + public async Task Initialization_WithoutFactory_Success() + { + _ = this.Client; + var privateKeyAccount = await this.GetGuestAccount(); + var smartAccount = await SmartWallet.Create(personalWallet: privateKeyAccount, chainId: 421614); + Assert.NotNull(await smartAccount.GetAddress()); + } + + [Fact(Timeout = 120000)] + public async Task Initialization_Fail() + { + var client = this.Client; + var privateKeyAccount = await this.GetGuestAccount(); + await privateKeyAccount.Disconnect(); + var ex = await Assert.ThrowsAsync(async () => + await SmartWallet.Create(personalWallet: privateKeyAccount, factoryAddress: "0xbf1C9aA4B1A085f7DA890a44E82B0A1289A40052", gasless: true, chainId: 421614) + ); + Assert.Equal("SmartAccount.Connect: Personal account must be connected.", ex.Message); + } + + [Fact(Timeout = 120000)] + public async Task ForceDeploy_Success() + { + _ = this.Client; + var privateKeyAccount = await this.GetGuestAccount(); + var smartAccount = await SmartWallet.Create(personalWallet: privateKeyAccount, factoryAddress: "0xbf1C9aA4B1A085f7DA890a44E82B0A1289A40052", gasless: true, chainId: 421614); + await smartAccount.ForceDeploy(); + Assert.True(await smartAccount.IsDeployed()); + } + + [Fact(Timeout = 120000)] + public async Task IsDeployed_True() + { + var account = await this.GetSmartAccount(); + await account.ForceDeploy(); + Assert.True(await account.IsDeployed()); + } + + [Fact(Timeout = 120000)] + public async Task IsDeployed_False() + { + _ = this.Client; + var privateKeyAccount = await this.GetGuestAccount(); + var smartAccount = await SmartWallet.Create( + personalWallet: privateKeyAccount, + factoryAddress: "0xbf1C9aA4B1A085f7DA890a44E82B0A1289A40052", + gasless: true, + chainId: 421614, + accountAddressOverride: "0x75A4e181286F5767c38dFBE65fe1Ad4793aCB642" // vanity + ); + Assert.False(await smartAccount.IsDeployed()); + } + + [Fact(Timeout = 120000)] + public async Task ExecuteTransaction_Success() + { + var account = await this.GetSmartAccount(); + var tx = await account.ExecuteTransaction(new ThirdwebTransactionInput(421614) { To = await account.GetAddress() }); + Assert.NotNull(tx); + } + + [Fact(Timeout = 120000)] + public async Task SendTransaction_Success() + { + var account = await this.GetSmartAccount(); + var tx = await account.SendTransaction(new ThirdwebTransactionInput(421614) { To = await account.GetAddress() }); + Assert.NotNull(tx); + } + + [Fact(Timeout = 120000)] + public async Task SendTransaction_ClientBundleId_Success() + { + _ = ThirdwebClient.Create(clientId: this.ClientIdBundleIdOnly, bundleId: this.BundleIdBundleIdOnly); + var privateKeyAccount = await this.GetGuestAccount(); + var smartAccount = await SmartWallet.Create(personalWallet: privateKeyAccount, factoryAddress: "0xbf1C9aA4B1A085f7DA890a44E82B0A1289A40052", gasless: true, chainId: 421614); + var tx = await smartAccount.SendTransaction(new ThirdwebTransactionInput(421614) { To = await smartAccount.GetAddress() }); + Assert.NotNull(tx); + } + + [Fact(Timeout = 120000)] + public async Task SendTransaction_Fail() + { + var account = await this.GetSmartAccount(); + var ex = await Assert.ThrowsAsync(async () => await account.SendTransaction(null)); + Assert.Equal("SmartAccount.SendTransaction: Transaction input is required.", ex.Message); + } + + [Fact(Timeout = 120000)] + public async Task GetAddress() + { + var account = await this.GetSmartAccount(); + var address = await account.GetAddress(); + Assert.NotNull(address); + } + + [Fact(Timeout = 120000)] + public async Task GetPersonalAccount() + { + var account = await this.GetSmartAccount(); + var personalAccount = await account.GetPersonalWallet(); + Assert.NotNull(personalAccount); + _ = Assert.IsType(personalAccount); + } + + [Fact(Timeout = 120000)] + public async Task GetAddress_WithOverride() + { + _ = this.Client; + var privateKeyAccount = await this.GetGuestAccount(); + var smartAccount = await SmartWallet.Create( + personalWallet: privateKeyAccount, + factoryAddress: "0xbf1C9aA4B1A085f7DA890a44E82B0A1289A40052", + gasless: true, + chainId: 421614, + accountAddressOverride: "0x75A4e181286F5767c38dFBE65fe1Ad4793aCB642" // vanity + ); + var address = await smartAccount.GetAddress(); + Assert.Equal("0x75A4e181286F5767c38dFBE65fe1Ad4793aCB642", address); + } + + [Fact(Timeout = 120000)] + public async Task PersonalSign() // This is the only different signing mechanism for smart wallets, also tests isValidSignature + { + var account = await this.GetSmartAccount(); + + // ERC-6942 Verification + var sig = await account.PersonalSign("Hello, world!"); + Assert.NotNull(sig); + + // Raw EIP-1271 Verification + await account.ForceDeploy(); + var sig2 = await account.PersonalSign("Hello, world!"); + Assert.NotNull(sig2); + } + + [Fact(Timeout = 120000)] + public async Task IsValidSiganture_Invalid() + { + var account = await this.GetSmartAccount(); + var sig = await account.PersonalSign("Hello, world!"); + Assert.NotNull(sig); + sig += "1"; + var res = await account.IsValidSignature("Hello, world!", sig); + Assert.False(res); + } + + [Fact(Timeout = 120000)] + public async Task CreateSessionKey() + { + var account = await this.GetSmartAccount(); + var receipt = await account.CreateSessionKey( + signerAddress: "0x253d077C45A3868d0527384e0B34e1e3088A3908", + approvedTargets: new List { Constants.ADDRESS_ZERO }, + nativeTokenLimitPerTransactionInWei: "0", + permissionStartTimestamp: "0", + permissionEndTimestamp: (Utils.GetUnixTimeStampNow() + 86400).ToString(), + reqValidityStartTimestamp: "0", + reqValidityEndTimestamp: Utils.GetUnixTimeStampIn10Years().ToString() + ); + Assert.NotNull(receipt); + Assert.NotNull(receipt.TransactionHash); + } + + [Fact(Timeout = 120000)] + public async Task AddAdmin() + { + var account = await this.GetSmartAccount(); + var receipt = await account.AddAdmin("0x039d7D195f6f8537003fFC19e86cd91De5e9C431"); + Assert.NotNull(receipt); + Assert.NotNull(receipt.TransactionHash); + } + + [Fact(Timeout = 120000)] + public async Task RemoveAdmin() + { + var account = await this.GetSmartAccount(); + var receipt = await account.RemoveAdmin("0x039d7D195f6f8537003fFC19e86cd91De5e9C431"); + Assert.NotNull(receipt); + Assert.NotNull(receipt.TransactionHash); + } + + [Fact(Timeout = 120000)] + public async Task IsConnected() + { + var account = await this.GetSmartAccount(); + Assert.True(await account.IsConnected()); + + await account.Disconnect(); + Assert.False(await account.IsConnected()); + } + + [Fact(Timeout = 120000)] + public async Task Disconnect() + { + var account = await this.GetSmartAccount(); + await account.Disconnect(); + Assert.False(await account.IsConnected()); + } + + [Fact(Timeout = 120000)] + public async Task GetAllActiveSigners() + { + var account = await this.GetSmartAccount(); + var signers = await account.GetAllActiveSigners(); + Assert.NotNull(signers); + var count = signers.Count; + + // add signer + var randomSigner = await (await this.GetGuestAccount()).GetAddress(); + _ = await account.CreateSessionKey( + signerAddress: randomSigner, + approvedTargets: new List() { Constants.ADDRESS_ZERO }, + nativeTokenLimitPerTransactionInWei: "0", + permissionStartTimestamp: "0", + permissionEndTimestamp: (Utils.GetUnixTimeStampNow() + 86400).ToString(), + reqValidityStartTimestamp: "0", + reqValidityEndTimestamp: Utils.GetUnixTimeStampIn10Years().ToString() + ); + + await ThirdwebTask.Delay(1000); + + signers = await account.GetAllActiveSigners(); + + Assert.Equal(count + 1, signers.Count); + + // remove signer + _ = await account.RevokeSessionKey(signerAddress: randomSigner); + + signers = await account.GetAllActiveSigners(); + + Assert.Equal(count, signers.Count); + } + + [Fact(Timeout = 120000)] + public async Task GetAllAdmins() + { + var account = await this.GetSmartAccount(); + await account.ForceDeploy(); + var admins = await account.GetAllAdmins(); + Assert.NotNull(admins); + var count = admins.Count; + + // add admin + var randomAdmin = await (await this.GetGuestAccount()).GetAddress(); + _ = await account.AddAdmin(randomAdmin); + + admins = await account.GetAllAdmins(); + + Assert.Equal(count + 1, admins.Count); + + // remove admin + _ = await account.RemoveAdmin(randomAdmin); + + admins = await account.GetAllAdmins(); + + Assert.Equal(count, admins.Count); + } + + [Fact(Timeout = 120000)] + public async Task SendTransaction_07_Success() + { + var smartWallet07 = await SmartWallet.Create( + personalWallet: await this.GetGuestAccount(), + chainId: 11155111, + gasless: true, + factoryAddress: "0xc5A43D081Dc10316EE640504Ea1cBc74666F3874", + entryPoint: Constants.ENTRYPOINT_ADDRESS_V07 + ); + + var hash07 = await smartWallet07.SendTransaction(new ThirdwebTransactionInput(11155111) { To = await smartWallet07.GetAddress() }); + + Assert.NotNull(hash07); + Assert.True(hash07.Length == 66); + } + + [Fact(Timeout = 120000)] + public async Task ExecuteTransaction_07_WhenAll_Success() + { + var smartWallet07 = await SmartWallet.Create( + personalWallet: await this.GetGuestAccount(), + chainId: 11155111, + gasless: true, + factoryAddress: "0xc5A43D081Dc10316EE640504Ea1cBc74666F3874", + entryPoint: Constants.ENTRYPOINT_ADDRESS_V07 + ); + + var hash07 = smartWallet07.ExecuteTransaction(new ThirdwebTransactionInput(11155111) { To = await smartWallet07.GetAddress() }); + var hash07_2 = smartWallet07.ExecuteTransaction(new ThirdwebTransactionInput(11155111) { To = await smartWallet07.GetAddress() }); + + var hashes = await Task.WhenAll(hash07, hash07_2); + + Assert.True(hashes.Length == 2); + Assert.True(hashes[0].TransactionHash.Length == 66); + Assert.True(hashes[1].TransactionHash.Length == 66); + } + + [Fact(Timeout = 120000)] + public async Task SwitchNetwork_Success() + { + var smartWallet = await SmartWallet.Create(personalWallet: await this.GetGuestAccount(), chainId: 11155111); + var addy1 = await smartWallet.GetAddress(); + await smartWallet.SwitchNetwork(421614); + var addy2 = await smartWallet.GetAddress(); + Assert.Equal(addy1, addy2); + } + + [Fact(Timeout = 120000)] + public async Task SwitchNetwork_WithCustomFactory_ToZk_Success() + { + var smartWallet = await SmartWallet.Create(personalWallet: await this.GetGuestAccount(), chainId: 11155111, factoryAddress: "0xc5A43D081Dc10316EE640504Ea1cBc74666F3874"); + var addy1 = await smartWallet.GetAddress(); + await smartWallet.SwitchNetwork(300); + var addy2 = await smartWallet.GetAddress(); + Assert.NotEqual(addy1, addy2); + } + + [Fact(Timeout = 120000)] + public async Task SwitchNetwork_WithCustomFactory_FromZk_Success() + { + var smartWallet = await SmartWallet.Create(personalWallet: await this.GetGuestAccount(), chainId: 300, factoryAddress: "0xc5A43D081Dc10316EE640504Ea1cBc74666F3874"); + var addy1 = await smartWallet.GetAddress(); + await smartWallet.SwitchNetwork(11155111); + var addy2 = await smartWallet.GetAddress(); + Assert.NotEqual(addy1, addy2); + } + + [Fact(Timeout = 120000)] + public async Task SwitchNetwork_ZkToNonZkSuccess() + { + var smartWallet = await SmartWallet.Create(personalWallet: await this.GetGuestAccount(), chainId: 300); + var addy1 = await smartWallet.GetAddress(); + await smartWallet.SwitchNetwork(421614); + var addy2 = await smartWallet.GetAddress(); + Assert.NotEqual(addy1, addy2); + } + + [Fact(Timeout = 120000)] + public async Task SwitchNetwork_NonZkToZk_Success() + { + var smartWallet = await SmartWallet.Create(personalWallet: await this.GetGuestAccount(), chainId: 421614); + var addy1 = await smartWallet.GetAddress(); + await smartWallet.SwitchNetwork(300); + var addy2 = await smartWallet.GetAddress(); + Assert.NotEqual(addy1, addy2); + } + + [Fact(Timeout = 120000)] + public async Task SignAuthorization_WithInAppWallet_Success() + { + var smartWallet = await SmartWallet.Create(personalWallet: await this.GetGuestAccount(), chainId: 421614); + var smartWalletSigner = await smartWallet.GetPersonalWallet(); + var signature1 = await smartWallet.SignAuthorization(chainId: 421614, contractAddress: Constants.ADDRESS_ZERO, willSelfExecute: true); + var signature2 = await smartWalletSigner.SignAuthorization(chainId: 421614, contractAddress: Constants.ADDRESS_ZERO, willSelfExecute: true); + Assert.Equal(signature1.ChainId, signature2.ChainId); + Assert.Equal(signature1.Address, signature2.Address); + Assert.Equal(signature1.Nonce, signature2.Nonce); + } + + // [Fact(Timeout = 120000)] + // public async Task MultiChainTransaction_Success() + // { + // var chainId1 = 11155111; + // var chainId2 = 421614; + + // var smartWallet = await SmartWallet.Create(personalWallet: await this.GetGuestAccount(), chainId: chainId1, gasless: true); + + // var randomAddy = await (await this.GetGuestAccount()).GetAddress(); + + // var receipt1 = await smartWallet.ExecuteTransaction(new ThirdwebTransactionInput(chainId1) { To = randomAddy, }); + // var nonce1 = await smartWallet.GetTransactionCount(chainId: chainId1, blocktag: "latest"); + // var address1 = await smartWallet.GetAddress(); + + // var receipt2 = await smartWallet.ExecuteTransaction(new ThirdwebTransactionInput(chainId2) { To = randomAddy, }); + // var nonce2 = await smartWallet.GetTransactionCount(chainId: chainId2, blocktag: "latest"); + // var address2 = await smartWallet.GetAddress(); + + // Assert.NotNull(address1); + // Assert.NotNull(address2); + // Assert.Equal(address1, address2); + + // Assert.NotNull(receipt1); + // Assert.NotNull(receipt2); + + // Assert.True(receipt1.TransactionHash.Length == 66); + // Assert.True(receipt2.TransactionHash.Length == 66); + + // Assert.Equal(receipt1.To, receipt2.To); + + // Assert.Equal(nonce1, 1); + // Assert.Equal(nonce2, 1); + // } + + // [Fact(Timeout = 120000)] + // public async Task MultiChainTransaction_ZkToNonZk_Success() + // { + // var chainId1 = 300; + // var chainId2 = 421614; + + // var smartWallet = await SmartWallet.Create(personalWallet: await this.GetGuestAccount(), chainId: chainId1, gasless: true); + + // var randomAddy = await (await this.GetGuestAccount()).GetAddress(); + + // var receipt1 = await smartWallet.ExecuteTransaction(new ThirdwebTransactionInput(chainId1) { To = randomAddy, }); + // var nonce1 = await smartWallet.GetTransactionCount(chainId: chainId1, blocktag: "latest"); + // var address1 = await smartWallet.GetAddress(); + + // var receipt2 = await smartWallet.ExecuteTransaction(new ThirdwebTransactionInput(chainId2) { To = randomAddy, }); + // var nonce2 = await smartWallet.GetTransactionCount(chainId: chainId2, blocktag: "latest"); + // var address2 = await smartWallet.GetAddress(); + + // Assert.NotNull(address1); + // Assert.NotNull(address2); + // Assert.NotEqual(address1, address2); + + // Assert.NotNull(receipt1); + // Assert.NotNull(receipt2); + + // Assert.True(receipt1.TransactionHash.Length == 66); + // Assert.True(receipt2.TransactionHash.Length == 66); + + // Assert.NotEqual(receipt1.To, receipt2.To); + + // Assert.Equal(nonce1, 1); + // Assert.Equal(nonce2, 1); + // } + + // [Fact(Timeout = 120000)] + // public async Task MultiChainTransaction_NonZkToZk_Success() + // { + // var chainId1 = 421614; + // var chainId2 = 300; + + // var smartWallet = await SmartWallet.Create(personalWallet: await this.GetGuestAccount(), chainId: chainId1, gasless: true); + + // var randomAddy = await (await this.GetGuestAccount()).GetAddress(); + + // var receipt1 = await smartWallet.ExecuteTransaction(new ThirdwebTransactionInput(chainId1) { To = randomAddy, }); + // var nonce1 = await smartWallet.GetTransactionCount(chainId: chainId1, blocktag: "latest"); + // var address1 = await smartWallet.GetAddress(); + + // var receipt2 = await smartWallet.ExecuteTransaction(new ThirdwebTransactionInput(chainId2) { To = randomAddy, }); + // var nonce2 = await smartWallet.GetTransactionCount(chainId: chainId2, blocktag: "latest"); + // var address2 = await smartWallet.GetAddress(); + + // Assert.NotNull(address1); + // Assert.NotNull(address2); + // Assert.NotEqual(address1, address2); + + // Assert.NotNull(receipt1); + // Assert.NotNull(receipt2); + + // Assert.True(receipt1.TransactionHash.Length == 66); + // Assert.True(receipt2.TransactionHash.Length == 66); + + // Assert.NotEqual(receipt1.To, receipt2.To); + + // Assert.Equal(nonce1, 1); + // Assert.Equal(nonce2, 1); + // } +} diff --git a/Thirdweb.Tests/Thirdweb.Wallets.Tests.cs b/Thirdweb.Tests/Thirdweb.Wallets/Thirdweb.Wallets.Tests.cs similarity index 65% rename from Thirdweb.Tests/Thirdweb.Wallets.Tests.cs rename to Thirdweb.Tests/Thirdweb.Wallets/Thirdweb.Wallets.Tests.cs index cf719229..d318cdc1 100644 --- a/Thirdweb.Tests/Thirdweb.Wallets.Tests.cs +++ b/Thirdweb.Tests/Thirdweb.Wallets/Thirdweb.Wallets.Tests.cs @@ -1,83 +1,56 @@ -using Nethereum.Hex.HexTypes; - -namespace Thirdweb.Tests; +namespace Thirdweb.Tests.Wallets; public class WalletTests : BaseTests { public WalletTests(ITestOutputHelper output) : base(output) { } - private async Task GetAccount() - { - var client = ThirdwebClient.Create(secretKey: _secretKey); - var privateKeyAccount = await PrivateKeyWallet.Generate(client); - var smartAccount = await SmartWallet.Create(personalWallet: privateKeyAccount, factoryAddress: "0xbf1C9aA4B1A085f7DA890a44E82B0A1289A40052", gasless: true, chainId: 421614); - return smartAccount; - } - - [Fact] + [Fact(Timeout = 120000)] public async Task GetAddress() { - var wallet = await GetAccount(); + var wallet = await this.GetSmartAccount(); Assert.Equal(await wallet.GetAddress(), await wallet.GetAddress()); } - [Fact] - public async Task EthSignRaw() - { - var wallet = await GetAccount(); - var message = "Hello, world!"; - var signature = await wallet.EthSign(System.Text.Encoding.UTF8.GetBytes(message)); - Assert.NotNull(signature); - } - - [Fact] - public async Task EthSign() - { - var wallet = await GetAccount(); - var message = "Hello, world!"; - var signature = await wallet.EthSign(message); - Assert.NotNull(signature); - } - - [Fact] + [Fact(Timeout = 120000)] public async Task PersonalSignRaw() { - var wallet = await GetAccount(); + var wallet = await this.GetGuestAccount(); var message = "Hello, world!"; var signature = await wallet.PersonalSign(System.Text.Encoding.UTF8.GetBytes(message)); Assert.NotNull(signature); } - [Fact] + [Fact(Timeout = 120000)] public async Task PersonalSign() { - var wallet = await GetAccount(); + var wallet = await this.GetGuestAccount(); var message = "Hello, world!"; var signature = await wallet.PersonalSign(message); Assert.NotNull(signature); } - [Fact] + [Fact(Timeout = 120000)] public async Task SignTypedDataV4() { - var wallet = await GetAccount(); + var wallet = await this.GetSmartAccount(); var json = + /*lang=json,strict*/ "{\"types\":{\"EIP712Domain\":[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"version\",\"type\":\"string\"},{\"name\":\"chainId\",\"type\":\"uint256\"},{\"name\":\"verifyingContract\",\"type\":\"address\"}],\"Person\":[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"wallet\",\"type\":\"address\"}],\"Mail\":[{\"name\":\"from\",\"type\":\"Person\"},{\"name\":\"to\",\"type\":\"Person\"},{\"name\":\"contents\",\"type\":\"string\"}]},\"primaryType\":\"Mail\",\"domain\":{\"name\":\"Ether Mail\",\"version\":\"1\",\"chainId\":1,\"verifyingContract\":\"0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC\"},\"message\":{\"from\":{\"name\":\"Cow\",\"wallet\":\"0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826\"},\"to\":{\"name\":\"Bob\",\"wallet\":\"0xbBbBBBBbbBBBbbbBbbBbbBBbBbbBbBbBbBbbBBbB\"},\"contents\":\"Hello, Bob!\"}}"; var signature = await wallet.SignTypedDataV4(json); Assert.NotNull(signature); } - [Fact] + [Fact(Timeout = 120000)] public async Task SignTypedDataV4_Typed() { - var wallet = await GetAccount(); + var wallet = await this.GetSmartAccount(); var typedData = EIP712.GetTypedDefinition_SmartAccount_AccountMessage("Account", "1", 421614, await wallet.GetAddress()); var accountMessage = new AccountAbstraction.AccountMessage { Message = System.Text.Encoding.UTF8.GetBytes("Hello, world!").HashPrefixedMessage() }; var signature = await wallet.SignTypedDataV4(accountMessage, typedData); Assert.NotNull(signature); - var signerAcc = await (wallet).GetPersonalAccount(); + var signerAcc = await wallet.GetPersonalWallet(); var gen1 = await EIP712.GenerateSignature_SmartAccount_AccountMessage( "Account", "1", @@ -97,7 +70,7 @@ await wallet.GetAddress(), PermissionStartTimestamp = 0, ReqValidityStartTimestamp = 0, PermissionEndTimestamp = 0, - Uid = new byte[32] + Uid = new byte[32], }; var typedData2 = EIP712.GetTypedDefinition_SmartAccount("Account", "1", 421614, await wallet.GetAddress()); @@ -108,22 +81,30 @@ await wallet.GetAddress(), Assert.Equal(gen2, signature2); } - [Fact] + [Fact(Timeout = 120000)] public async Task SignTransaction() { - var wallet = await GetAccount(); - var transaction = new ThirdwebTransactionInput - { - To = await wallet.GetAddress(), - Data = "0x", - Value = new HexBigInteger(0), - Gas = new HexBigInteger(21000), - GasPrice = new HexBigInteger(10000000000), - Nonce = new HexBigInteger(9999999999999), - ChainId = new HexBigInteger(421614), - }; - var rpc = ThirdwebRPC.GetRpcInstance(ThirdwebClient.Create(secretKey: _secretKey), 421614); + var wallet = await this.GetSmartAccount(); + var transaction = new ThirdwebTransactionInput(chainId: 421614, to: await wallet.GetAddress(), data: "0x", value: 0, gas: 21000, gasPrice: 10000000000, nonce: 9999999999999); + _ = ThirdwebRPC.GetRpcInstance(this.Client, 421614); var signature = await wallet.SignTransaction(transaction); Assert.NotNull(signature); } + + [Fact(Timeout = 120000)] + public async Task SwitchNetwork_Success() + { + var smartWallet = await this.GetSmartAccount(); + var wrappedSmartWallet = await SmartWallet.Create(personalWallet: smartWallet, chainId: 421614); + + Assert.Equal(421614, smartWallet.ActiveChainId); + Assert.Equal(421614, wrappedSmartWallet.ActiveChainId); + + await wrappedSmartWallet.SwitchNetwork(11155111); + + Assert.Equal(11155111, wrappedSmartWallet.ActiveChainId); + Assert.Equal(11155111, smartWallet.ActiveChainId); + + await (await this.GetGuestAccount()).SwitchNetwork(11155111); + } } diff --git a/Thirdweb.Tests/Thirdweb.ZkSmartWallet.Tests.cs b/Thirdweb.Tests/Thirdweb.ZkSmartWallet.Tests.cs deleted file mode 100644 index 904b041b..00000000 --- a/Thirdweb.Tests/Thirdweb.ZkSmartWallet.Tests.cs +++ /dev/null @@ -1,109 +0,0 @@ -namespace Thirdweb.Tests; - -public class ZkSmartWalletTests : BaseTests -{ - private readonly ThirdwebClient _zkClient; - - public ZkSmartWalletTests(ITestOutputHelper output) - : base(output) - { - _zkClient = ThirdwebClient.Create(secretKey: _secretKey); - } - - private async Task GetSmartAccount(int zkChainId = 300, bool gasless = true) - { - var privateKeyAccount = await PrivateKeyWallet.Generate(_zkClient); - var smartAccount = await SmartWallet.Create(personalWallet: privateKeyAccount, gasless: gasless, chainId: zkChainId); - return smartAccount; - } - - [Fact] - public async Task GetAddress_Success() - { - var account = await GetSmartAccount(); - Assert.NotNull(await account.GetAddress()); - } - - [Fact] - public async Task PersonalSign_Success() - { - var account = await GetSmartAccount(zkChainId: 302); - var message = "Hello, World!"; - var signature = await account.PersonalSign(message); - Assert.NotNull(signature); - Assert.True(signature.Length > 0); - } - - [Fact] - public async Task CreateSessionKey_Throws() - { - var account = await GetSmartAccount(); - _ = await Assert.ThrowsAsync( - async () => - await account.CreateSessionKey( - signerAddress: await account.GetAddress(), - approvedTargets: new List() { Constants.ADDRESS_ZERO }, - nativeTokenLimitPerTransactionInWei: "0", - permissionStartTimestamp: "0", - permissionEndTimestamp: (Utils.GetUnixTimeStampNow() + 86400).ToString(), - reqValidityStartTimestamp: "0", - reqValidityEndTimestamp: Utils.GetUnixTimeStampIn10Years().ToString() - ) - ); - } - - [Fact] - public async Task AddAdmin_Throws() - { - var account = await GetSmartAccount(); - _ = await Assert.ThrowsAsync(async () => await account.AddAdmin(Constants.ADDRESS_ZERO)); - } - - [Fact] - public async Task RemoveAdmin_Throws() - { - var account = await GetSmartAccount(); - _ = await Assert.ThrowsAsync(async () => await account.RemoveAdmin(Constants.ADDRESS_ZERO)); - } - - [Fact] - public async Task IsDeployed_ReturnsTrue() - { - var account = await GetSmartAccount(); - Assert.True(await account.IsDeployed()); - } - - [Fact] - public async Task SendGaslessZkTx_Success() - { - var account = await GetSmartAccount(); - var hash = await account.SendTransaction( - new ThirdwebTransactionInput() - { - From = await account.GetAddress(), - To = await account.GetAddress(), - Value = new Nethereum.Hex.HexTypes.HexBigInteger(0), - Data = "0x" - } - ); - Assert.NotNull(hash); - Assert.True(hash.Length == 66); - } - - [Fact] - public async Task SendGaslessZkTx_ZkCandy_Success() - { - var account = await GetSmartAccount(zkChainId: 302); - var hash = await account.SendTransaction( - new ThirdwebTransactionInput() - { - From = await account.GetAddress(), - To = await account.GetAddress(), - Value = new Nethereum.Hex.HexTypes.HexBigInteger(0), - Data = "0x" - } - ); - Assert.NotNull(hash); - Assert.True(hash.Length == 66); - } -} diff --git a/Thirdweb.Tests/xunit.runner.json b/Thirdweb.Tests/xunit.runner.json new file mode 100644 index 00000000..8ddedc76 --- /dev/null +++ b/Thirdweb.Tests/xunit.runner.json @@ -0,0 +1,8 @@ +{ + "$schema": "https://xunit.net/schema/current/xunit.runner.schema.json", + "parallelizeTestCollections": false, + "longRunningTestSeconds": 90, + "diagnosticMessages": true, + "showLiveOutput": true, + "stopOnFail": true +} diff --git a/Thirdweb/Thirdweb.Api/ThirdwebApi.cs b/Thirdweb/Thirdweb.Api/ThirdwebApi.cs new file mode 100644 index 00000000..8f187bb8 --- /dev/null +++ b/Thirdweb/Thirdweb.Api/ThirdwebApi.cs @@ -0,0 +1,18995 @@ +//---------------------- +// +// Generated using the NSwag toolchain v14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0)) (http://NSwag.org) +// +//---------------------- + +#pragma warning disable 108 // Disable "CS0108 '{derivedDto}.ToJson()' hides inherited member '{dtoBase}.ToJson()'. Use the new keyword if hiding was intended." +#pragma warning disable 114 // Disable "CS0114 '{derivedDto}.RaisePropertyChanged(String)' hides inherited member 'dtoBase.RaisePropertyChanged(String)'. To make the current member override that implementation, add the override keyword. Otherwise add the new keyword." +#pragma warning disable 472 // Disable "CS0472 The result of the expression is always 'false' since a value of type 'Int32' is never equal to 'null' of type 'Int32?' +#pragma warning disable 612 // Disable "CS0612 '...' is obsolete" +#pragma warning disable 649 // Disable "CS0649 Field is never assigned to, and will always have its default value null" +#pragma warning disable 1573 // Disable "CS1573 Parameter '...' has no matching param tag in the XML comment for ... +#pragma warning disable 1591 // Disable "CS1591 Missing XML comment for publicly visible type or member ..." +#pragma warning disable 8073 // Disable "CS8073 The result of the expression is always 'false' since a value of type 'T' is never equal to 'null' of type 'T?'" +#pragma warning disable 3016 // Disable "CS3016 Arrays as attribute arguments is not CLS-compliant" +#pragma warning disable 8600 // Disable "CS8600 Converting null literal or possible null value to non-nullable type" +#pragma warning disable 8602 // Disable "CS8602 Dereference of a possibly null reference" +#pragma warning disable 8603 // Disable "CS8603 Possible null reference return" +#pragma warning disable 8604 // Disable "CS8604 Possible null reference argument for parameter" +#pragma warning disable 8625 // Disable "CS8625 Cannot convert null literal to non-nullable reference type" +#pragma warning disable 8765 // Disable "CS8765 Nullability of type of parameter doesn't match overridden member (possibly because of nullability attributes)." + +namespace Thirdweb.Api +{ + using System = global::System; + + [System.CodeDom.Compiler.GeneratedCode("NSwag", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class ThirdwebApiClient + { + #pragma warning disable 8618 + private string _baseUrl; + #pragma warning restore 8618 + + private ThirdwebHttpClientWrapper _httpClient; + private static System.Lazy _settings = new System.Lazy(CreateSerializerSettings, true); + private Newtonsoft.Json.JsonSerializerSettings _instanceSettings; + + #pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. + public ThirdwebApiClient(ThirdwebHttpClientWrapper httpClient) + #pragma warning restore CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. + { + BaseUrl = "https://api.thirdweb.com"; + _httpClient = httpClient; + Initialize(); + } + + private static Newtonsoft.Json.JsonSerializerSettings CreateSerializerSettings() + { + var settings = new Newtonsoft.Json.JsonSerializerSettings(); + UpdateJsonSerializerSettings(settings); + return settings; + } + + public string BaseUrl + { + get { return _baseUrl; } + set + { + _baseUrl = value; + if (!string.IsNullOrEmpty(_baseUrl) && !_baseUrl.EndsWith("/")) + _baseUrl += '/'; + } + } + + protected Newtonsoft.Json.JsonSerializerSettings JsonSerializerSettings { get { return _instanceSettings ?? _settings.Value; } } + + static partial void UpdateJsonSerializerSettings(Newtonsoft.Json.JsonSerializerSettings settings); + + partial void Initialize(); + + partial void PrepareRequest(ThirdwebHttpClientWrapper client, System.Net.Http.HttpRequestMessage request, string url); + partial void PrepareRequest(ThirdwebHttpClientWrapper client, System.Net.Http.HttpRequestMessage request, System.Text.StringBuilder urlBuilder); + partial void ProcessResponse(ThirdwebHttpClientWrapper client, System.Net.Http.HttpResponseMessage response); + + /// + /// Initiate Auth + /// + /// + /// Start any authentication flow in one unified endpoint. This endpoint supports all authentication methods including SMS, email, OAuth, passkey, and SIWE (Sign-In with Ethereum). + ///
+ ///
**Supported Methods:** + ///
- **SMS** - Send verification code to phone number + ///
- **Email** - Send verification code to email address + ///
- **Passkey** - Generate WebAuthn challenge for biometric authentication + ///
- **SIWE** - Generate Sign-In with Ethereum payload + ///
+ ///
**Flow:** + ///
1. Choose your authentication method + ///
2. Provide method-specific parameters + ///
3. Receive challenge data to complete authentication + ///
4. Use the /complete endpoint to finish the process + ///
+ ///
**OAuth:** + ///
+ ///
The OAuth method uses a dedicated `/auth/social` endpoint instead of this one: + ///
+ ///
`GET /auth/social?provider=google&redirectUrl=...` + ///
+ ///
**Custom (JWT, auth-payload) and Guest:** + ///
+ ///
For custom authentication (JWT, auth-payload) and for guest authentication, you can skip this step and use the `/auth/complete` endpoint directly. + ///
+ ///
**Authentication:** Requires `x-client-id` header for frontend usage or `x-secret-key` for backend usage. + ///
+ /// Authentication initiated successfully. Use the returned challenge data to complete authentication. + /// A server side error occurred. + public virtual System.Threading.Tasks.Task InitiateAuthenticationAsync(Body body) + { + return InitiateAuthenticationAsync(body, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Initiate Auth + /// + /// + /// Start any authentication flow in one unified endpoint. This endpoint supports all authentication methods including SMS, email, OAuth, passkey, and SIWE (Sign-In with Ethereum). + ///
+ ///
**Supported Methods:** + ///
- **SMS** - Send verification code to phone number + ///
- **Email** - Send verification code to email address + ///
- **Passkey** - Generate WebAuthn challenge for biometric authentication + ///
- **SIWE** - Generate Sign-In with Ethereum payload + ///
+ ///
**Flow:** + ///
1. Choose your authentication method + ///
2. Provide method-specific parameters + ///
3. Receive challenge data to complete authentication + ///
4. Use the /complete endpoint to finish the process + ///
+ ///
**OAuth:** + ///
+ ///
The OAuth method uses a dedicated `/auth/social` endpoint instead of this one: + ///
+ ///
`GET /auth/social?provider=google&redirectUrl=...` + ///
+ ///
**Custom (JWT, auth-payload) and Guest:** + ///
+ ///
For custom authentication (JWT, auth-payload) and for guest authentication, you can skip this step and use the `/auth/complete` endpoint directly. + ///
+ ///
**Authentication:** Requires `x-client-id` header for frontend usage or `x-secret-key` for backend usage. + ///
+ /// Authentication initiated successfully. Use the returned challenge data to complete authentication. + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task InitiateAuthenticationAsync(Body body, System.Threading.CancellationToken cancellationToken) + { + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + var json_ = Newtonsoft.Json.JsonConvert.SerializeObject(body, JsonSerializerSettings); + var content_ = new System.Net.Http.StringContent(json_); + content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json"); + request_.Content = content_; + request_.Method = new System.Net.Http.HttpMethod("POST"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + var urlBuilder_ = new System.Text.StringBuilder(); + if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl); + // Operation Path: "v1/auth/initiate" + urlBuilder_.Append("v1/auth/initiate"); + + PrepareRequest(client_, request_, urlBuilder_); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + PrepareRequest(client_, request_, url_); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = new System.Collections.Generic.Dictionary>(); + foreach (var item_ in response_.Headers) + headers_[item_.Key] = item_.Value; + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + ProcessResponse(client_, response_); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 400) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Invalid request - Check your method and parameters", status_, responseText_, headers_, null); + } + else + if (status_ == 429) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Rate limit exceeded - Please wait before trying again", status_, responseText_, headers_, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// Complete Auth + /// + /// + /// Complete the authentication flow and receive your wallet credentials. After initiating authentication, use this endpoint to submit the required verification data. + ///
+ ///
**Completion Methods:** + ///
- **SMS/Email** - Submit the verification code you received + ///
- **Passkey** - Provide the WebAuthn signature response + ///
- **SIWE** - Submit your signed Ethereum message + ///
- **Guest** - Create an ephemeral guest wallet + ///
- **Custom (JWT, auth-payload)** - Send your JWT token or custom payload + ///
+ ///
**Response:** + ///
- `isNewUser` - Whether this is a new wallet creation + ///
- `token` - JWT token for authenticated API requests + ///
- `type` - The authentication method used + ///
- `userId` - Unique identifier for the authenticated user + ///
- `walletAddress` - Your new or existing wallet address + ///
+ ///
**Next step - Verify your token:** + ///
```javascript + ///
// Verify the token and get complete wallet details (server-side) + ///
fetch('/v1/wallets/me', { + ///
headers: { + ///
'Authorization': 'Bearer ' + token, + ///
'x-secret-key': 'your-secret-key' + ///
} + ///
}) + ///
.then(response => response.json()) + ///
.then(data => { + ///
console.log('Wallet verified:', data.result.address); + ///
console.log('Auth profiles:', data.result.profiles); + ///
}); + ///
``` + ///
+ ///
**Authentication:** Requires `x-client-id` header for frontend usage or `x-secret-key` for backend usage. + ///
+ /// Authentication completed successfully. You now have wallet access. + /// A server side error occurred. + public virtual System.Threading.Tasks.Task CompleteAuthenticationAsync(Body2 body) + { + return CompleteAuthenticationAsync(body, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Complete Auth + /// + /// + /// Complete the authentication flow and receive your wallet credentials. After initiating authentication, use this endpoint to submit the required verification data. + ///
+ ///
**Completion Methods:** + ///
- **SMS/Email** - Submit the verification code you received + ///
- **Passkey** - Provide the WebAuthn signature response + ///
- **SIWE** - Submit your signed Ethereum message + ///
- **Guest** - Create an ephemeral guest wallet + ///
- **Custom (JWT, auth-payload)** - Send your JWT token or custom payload + ///
+ ///
**Response:** + ///
- `isNewUser` - Whether this is a new wallet creation + ///
- `token` - JWT token for authenticated API requests + ///
- `type` - The authentication method used + ///
- `userId` - Unique identifier for the authenticated user + ///
- `walletAddress` - Your new or existing wallet address + ///
+ ///
**Next step - Verify your token:** + ///
```javascript + ///
// Verify the token and get complete wallet details (server-side) + ///
fetch('/v1/wallets/me', { + ///
headers: { + ///
'Authorization': 'Bearer ' + token, + ///
'x-secret-key': 'your-secret-key' + ///
} + ///
}) + ///
.then(response => response.json()) + ///
.then(data => { + ///
console.log('Wallet verified:', data.result.address); + ///
console.log('Auth profiles:', data.result.profiles); + ///
}); + ///
``` + ///
+ ///
**Authentication:** Requires `x-client-id` header for frontend usage or `x-secret-key` for backend usage. + ///
+ /// Authentication completed successfully. You now have wallet access. + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task CompleteAuthenticationAsync(Body2 body, System.Threading.CancellationToken cancellationToken) + { + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + var json_ = Newtonsoft.Json.JsonConvert.SerializeObject(body, JsonSerializerSettings); + var content_ = new System.Net.Http.StringContent(json_); + content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json"); + request_.Content = content_; + request_.Method = new System.Net.Http.HttpMethod("POST"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + var urlBuilder_ = new System.Text.StringBuilder(); + if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl); + // Operation Path: "v1/auth/complete" + urlBuilder_.Append("v1/auth/complete"); + + PrepareRequest(client_, request_, urlBuilder_); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + PrepareRequest(client_, request_, url_); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = new System.Collections.Generic.Dictionary>(); + foreach (var item_ in response_.Headers) + headers_[item_.Key] = item_.Value; + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + ProcessResponse(client_, response_); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 400) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Invalid credentials or request - Check your challenge ID and verification data", status_, responseText_, headers_, null); + } + else + if (status_ == 429) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Rate limit exceeded - Please wait before trying again", status_, responseText_, headers_, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// Link Auth + /// + /// + /// Link an additional authentication method or external wallet to the currently authenticated user. Provide the authentication token from another completed login (for example, a SIWE wallet or OAuth account) and this endpoint will associate it with the user's existing wallet. + ///
+ ///
**Usage:** + ///
1. Complete an authentication flow using `/auth/complete` to obtain the new authentication token + ///
2. Call this endpoint with the token you want to link + ///
3. Receive the full list of linked authentication profiles for the wallet + ///
+ ///
**Authentication:** Requires both client authentication (`x-client-id` or `x-secret-key`) and a wallet access token via `Authorization: Bearer <jwt>`. + ///
+ /// Authentication method linked successfully. The response contains the updated list of linked authentication profiles. + /// A server side error occurred. + public virtual System.Threading.Tasks.Task LinkAuthenticationAsync(Body3 body) + { + return LinkAuthenticationAsync(body, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Link Auth + /// + /// + /// Link an additional authentication method or external wallet to the currently authenticated user. Provide the authentication token from another completed login (for example, a SIWE wallet or OAuth account) and this endpoint will associate it with the user's existing wallet. + ///
+ ///
**Usage:** + ///
1. Complete an authentication flow using `/auth/complete` to obtain the new authentication token + ///
2. Call this endpoint with the token you want to link + ///
3. Receive the full list of linked authentication profiles for the wallet + ///
+ ///
**Authentication:** Requires both client authentication (`x-client-id` or `x-secret-key`) and a wallet access token via `Authorization: Bearer <jwt>`. + ///
+ /// Authentication method linked successfully. The response contains the updated list of linked authentication profiles. + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task LinkAuthenticationAsync(Body3 body, System.Threading.CancellationToken cancellationToken) + { + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + var json_ = Newtonsoft.Json.JsonConvert.SerializeObject(body, JsonSerializerSettings); + var content_ = new System.Net.Http.StringContent(json_); + content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json"); + request_.Content = content_; + request_.Method = new System.Net.Http.HttpMethod("POST"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + var urlBuilder_ = new System.Text.StringBuilder(); + if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl); + // Operation Path: "v1/auth/link" + urlBuilder_.Append("v1/auth/link"); + + PrepareRequest(client_, request_, urlBuilder_); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + PrepareRequest(client_, request_, url_); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = new System.Collections.Generic.Dictionary>(); + foreach (var item_ in response_.Headers) + headers_[item_.Key] = item_.Value; + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + ProcessResponse(client_, response_); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 400) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Invalid request parameters", status_, responseText_, headers_, null); + } + else + if (status_ == 401) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Wallet authentication required. Include Authorization: Bearer header.", status_, responseText_, headers_, null); + } + else + if (status_ == 429) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Rate limit exceeded - Please wait before trying again", status_, responseText_, headers_, null); + } + else + if (status_ == 502) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Third-party provider did not return any linked accounts after processing the request.", status_, responseText_, headers_, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// Unlink Auth + /// + /// + /// Disconnect an authentication method or external wallet from the currently authenticated user. Provide the identifiers for the provider you want to remove (for example, an email address or wallet address) and this endpoint will detach it from the user's account. + ///
+ ///
**Usage:** + ///
1. Choose the provider type you want to disconnect (email, phone, siwe, oauth, etc.) + ///
2. Supply the provider-specific identifiers in the request body + ///
3. Receive the updated list of linked authentication profiles + ///
+ ///
**Authentication:** Requires both client authentication (`x-client-id` or `x-secret-key`) and a wallet access token via `Authorization: Bearer <jwt>`. + ///
+ /// Authentication method unlinked successfully. The response contains the updated list of linked authentication profiles. + /// A server side error occurred. + public virtual System.Threading.Tasks.Task UnlinkAuthenticationAsync(Body4 body) + { + return UnlinkAuthenticationAsync(body, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Unlink Auth + /// + /// + /// Disconnect an authentication method or external wallet from the currently authenticated user. Provide the identifiers for the provider you want to remove (for example, an email address or wallet address) and this endpoint will detach it from the user's account. + ///
+ ///
**Usage:** + ///
1. Choose the provider type you want to disconnect (email, phone, siwe, oauth, etc.) + ///
2. Supply the provider-specific identifiers in the request body + ///
3. Receive the updated list of linked authentication profiles + ///
+ ///
**Authentication:** Requires both client authentication (`x-client-id` or `x-secret-key`) and a wallet access token via `Authorization: Bearer <jwt>`. + ///
+ /// Authentication method unlinked successfully. The response contains the updated list of linked authentication profiles. + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task UnlinkAuthenticationAsync(Body4 body, System.Threading.CancellationToken cancellationToken) + { + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + var json_ = Newtonsoft.Json.JsonConvert.SerializeObject(body, JsonSerializerSettings); + var content_ = new System.Net.Http.StringContent(json_); + content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json"); + request_.Content = content_; + request_.Method = new System.Net.Http.HttpMethod("POST"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + var urlBuilder_ = new System.Text.StringBuilder(); + if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl); + // Operation Path: "v1/auth/unlink" + urlBuilder_.Append("v1/auth/unlink"); + + PrepareRequest(client_, request_, urlBuilder_); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + PrepareRequest(client_, request_, url_); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = new System.Collections.Generic.Dictionary>(); + foreach (var item_ in response_.Headers) + headers_[item_.Key] = item_.Value; + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + ProcessResponse(client_, response_); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 400) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Invalid request parameters", status_, responseText_, headers_, null); + } + else + if (status_ == 401) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Wallet authentication required. Include Authorization: Bearer header.", status_, responseText_, headers_, null); + } + else + if (status_ == 429) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Rate limit exceeded - Please wait before trying again", status_, responseText_, headers_, null); + } + else + if (status_ == 502) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Third-party provider did not return any linked accounts after processing the request.", status_, responseText_, headers_, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// Social Auth + /// + /// + /// Complete OAuth authentication with social providers in a single step. Unlike other auth methods that require separate initiate/complete calls, OAuth is handled entirely through redirects. + ///
+ ///
**OAuth Flow (Self-Contained):** + ///
1. Redirect your user to this endpoint with provider and redirectUrl + ///
2. User completes OAuth flow with the provider + ///
3. User is redirected back to your redirectUrl with wallet credentials + ///
+ ///
**Why OAuth is different:** OAuth providers handle the challenge/response flow externally, so no separate `/complete` step is needed. + ///
+ ///
**Example:** + ///
Redirect user to: `GET /v1/auth/social?provider=google&redirectUrl=https://myapp.com/auth/callback` + ///
+ ///
**Callback Handling:** + ///
After OAuth completion, user arrives at your redirectUrl with an `authResult` query parameter: + ///
``` + ///
https://myapp.com/auth/callback?authResult=%7B%22storedToken%22%3A%7B%22authDetails%22%3A%7B...%7D%2C%22cookieString%22%3A%22eyJ...%22%7D%7D + ///
``` + ///
+ ///
**Extract JWT token in your callback:** + ///
```javascript + ///
// Parse the authResult from URL + ///
const urlParams = new URLSearchParams(window.location.search); + ///
const authResultString = urlParams.get('authResult'); + ///
const authResult = JSON.parse(authResultString!); + ///
+ ///
// Extract the JWT token + ///
const token = authResult.storedToken.cookieString; + ///
``` + ///
+ ///
**Verify and use the JWT token:** + ///
```javascript + ///
// Use the JWT token for authenticated requests + ///
fetch('/v1/wallets/me', { + ///
headers: { + ///
'Authorization': 'Bearer ' + token, + ///
'x-secret-key': 'your-secret-key' + ///
} + ///
}) + ///
.then(response => response.json()) + ///
.then(data => { + ///
console.log('Wallet verified:', data.result.address); + ///
console.log('Auth profiles:', data.result.profiles); + ///
}); + ///
``` + ///
+ ///
**Authentication Options:** + ///
Choose one of two ways to provide your client credentials: + ///
+ ///
**Option 1: Query Parameter (Recommended for OAuth flows)** + ///
``` + ///
GET /v1/auth/social?provider=google&redirectUrl=https://myapp.com/callback&clientId=your_client_id + ///
``` + ///
+ ///
**Option 2: Header (Alternative)** + ///
``` + ///
GET /v1/auth/social?provider=google&redirectUrl=https://myapp.com/callback + ///
Headers: x-client-id: your_client_id + ///
``` + ///
+ /// The OAuth provider to use + /// URL to redirect the user to after OAuth completion + /// Client ID (alternative to x-client-id header for standard OAuth flows) + /// A server side error occurred. + public virtual System.Threading.Tasks.Task SocialAuthenticationAsync(Provider provider, System.Uri redirectUrl, string clientId) + { + return SocialAuthenticationAsync(provider, redirectUrl, clientId, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Social Auth + /// + /// + /// Complete OAuth authentication with social providers in a single step. Unlike other auth methods that require separate initiate/complete calls, OAuth is handled entirely through redirects. + ///
+ ///
**OAuth Flow (Self-Contained):** + ///
1. Redirect your user to this endpoint with provider and redirectUrl + ///
2. User completes OAuth flow with the provider + ///
3. User is redirected back to your redirectUrl with wallet credentials + ///
+ ///
**Why OAuth is different:** OAuth providers handle the challenge/response flow externally, so no separate `/complete` step is needed. + ///
+ ///
**Example:** + ///
Redirect user to: `GET /v1/auth/social?provider=google&redirectUrl=https://myapp.com/auth/callback` + ///
+ ///
**Callback Handling:** + ///
After OAuth completion, user arrives at your redirectUrl with an `authResult` query parameter: + ///
``` + ///
https://myapp.com/auth/callback?authResult=%7B%22storedToken%22%3A%7B%22authDetails%22%3A%7B...%7D%2C%22cookieString%22%3A%22eyJ...%22%7D%7D + ///
``` + ///
+ ///
**Extract JWT token in your callback:** + ///
```javascript + ///
// Parse the authResult from URL + ///
const urlParams = new URLSearchParams(window.location.search); + ///
const authResultString = urlParams.get('authResult'); + ///
const authResult = JSON.parse(authResultString!); + ///
+ ///
// Extract the JWT token + ///
const token = authResult.storedToken.cookieString; + ///
``` + ///
+ ///
**Verify and use the JWT token:** + ///
```javascript + ///
// Use the JWT token for authenticated requests + ///
fetch('/v1/wallets/me', { + ///
headers: { + ///
'Authorization': 'Bearer ' + token, + ///
'x-secret-key': 'your-secret-key' + ///
} + ///
}) + ///
.then(response => response.json()) + ///
.then(data => { + ///
console.log('Wallet verified:', data.result.address); + ///
console.log('Auth profiles:', data.result.profiles); + ///
}); + ///
``` + ///
+ ///
**Authentication Options:** + ///
Choose one of two ways to provide your client credentials: + ///
+ ///
**Option 1: Query Parameter (Recommended for OAuth flows)** + ///
``` + ///
GET /v1/auth/social?provider=google&redirectUrl=https://myapp.com/callback&clientId=your_client_id + ///
``` + ///
+ ///
**Option 2: Header (Alternative)** + ///
``` + ///
GET /v1/auth/social?provider=google&redirectUrl=https://myapp.com/callback + ///
Headers: x-client-id: your_client_id + ///
``` + ///
+ /// The OAuth provider to use + /// URL to redirect the user to after OAuth completion + /// Client ID (alternative to x-client-id header for standard OAuth flows) + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task SocialAuthenticationAsync(Provider provider, System.Uri redirectUrl, string clientId, System.Threading.CancellationToken cancellationToken) + { + if (provider == null) + throw new System.ArgumentNullException("provider"); + + if (redirectUrl == null) + throw new System.ArgumentNullException("redirectUrl"); + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + request_.Method = new System.Net.Http.HttpMethod("GET"); + + var urlBuilder_ = new System.Text.StringBuilder(); + if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl); + // Operation Path: "v1/auth/social" + urlBuilder_.Append("v1/auth/social"); + urlBuilder_.Append('?'); + urlBuilder_.Append(System.Uri.EscapeDataString("provider")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(provider, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + urlBuilder_.Append(System.Uri.EscapeDataString("redirectUrl")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(redirectUrl, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + if (clientId != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("clientId")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(clientId, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + urlBuilder_.Length--; + + PrepareRequest(client_, request_, urlBuilder_); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + PrepareRequest(client_, request_, url_); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = new System.Collections.Generic.Dictionary>(); + foreach (var item_ in response_.Headers) + headers_[item_.Key] = item_.Value; + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + ProcessResponse(client_, response_); + + var status_ = (int)response_.StatusCode; + if (status_ == 302) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Redirects to OAuth provider for authentication", status_, responseText_, headers_, null); + } + else + if (status_ == 400) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Invalid request parameters", status_, responseText_, headers_, null); + } + else + + if (status_ == 200 || status_ == 204) + { + + return; + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// Get My Wallet + /// + /// + /// Retrieve the authenticated user's wallet information including wallet addresses and linked authentication wallets. This endpoint provides comprehensive user data for the currently authenticated session. + ///
+ ///
**Returns:** + ///
- userId - Unique identifier for this wallet in thirdweb auth + ///
- Primary wallet address + ///
- Smart wallet address (if available) + ///
- Wallet creation timestamp + ///
- Public key in hexadecimal format (if available) + ///
- All linked authentication profiles (email, phone, OAuth providers) + ///
+ ///
**Authentication:** Requires `Authorization: Bearer <jwt>` header with a valid user authentication token. + ///
+ /// Wallet retrieved successfully. Returns comprehensive user information including wallet addresses, public key, and linked wallets. + /// A server side error occurred. + public virtual System.Threading.Tasks.Task GetMyWalletAsync() + { + return GetMyWalletAsync(System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Get My Wallet + /// + /// + /// Retrieve the authenticated user's wallet information including wallet addresses and linked authentication wallets. This endpoint provides comprehensive user data for the currently authenticated session. + ///
+ ///
**Returns:** + ///
- userId - Unique identifier for this wallet in thirdweb auth + ///
- Primary wallet address + ///
- Smart wallet address (if available) + ///
- Wallet creation timestamp + ///
- Public key in hexadecimal format (if available) + ///
- All linked authentication profiles (email, phone, OAuth providers) + ///
+ ///
**Authentication:** Requires `Authorization: Bearer <jwt>` header with a valid user authentication token. + ///
+ /// Wallet retrieved successfully. Returns comprehensive user information including wallet addresses, public key, and linked wallets. + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task GetMyWalletAsync(System.Threading.CancellationToken cancellationToken) + { + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + request_.Method = new System.Net.Http.HttpMethod("GET"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + var urlBuilder_ = new System.Text.StringBuilder(); + if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl); + // Operation Path: "v1/wallets/me" + urlBuilder_.Append("v1/wallets/me"); + + PrepareRequest(client_, request_, urlBuilder_); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + PrepareRequest(client_, request_, url_); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = new System.Collections.Generic.Dictionary>(); + foreach (var item_ in response_.Headers) + headers_[item_.Key] = item_.Value; + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + ProcessResponse(client_, response_); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 401) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Authentication required. The request must include a valid `Authorization: Bearer ` header.", status_, responseText_, headers_, null); + } + else + if (status_ == 404) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Wallet not found. The authenticated user does not exist in the system.", status_, responseText_, headers_, null); + } + else + if (status_ == 500) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Internal server error. This may occur due to service unavailability or unexpected server errors.", status_, responseText_, headers_, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// List User Wallets + /// + /// + /// Get all user wallet details with filtering and pagination for your project. + ///
+ ///
**Authentication**: This endpoint requires backend authentication using the `x-secret-key` header. The secret key should never be exposed publicly. + ///
+ /// Filter results by the unique user identifier returned by auth flows. + /// Returns a list of user wallet addresses, smart wallet addresses, and auth details. + /// A server side error occurred. + public virtual System.Threading.Tasks.Task ListUserWalletsAsync(double? limit, double? page, string email, string phone, string address, string externalWalletAddress, string id, string userId) + { + return ListUserWalletsAsync(limit, page, email, phone, address, externalWalletAddress, id, userId, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// List User Wallets + /// + /// + /// Get all user wallet details with filtering and pagination for your project. + ///
+ ///
**Authentication**: This endpoint requires backend authentication using the `x-secret-key` header. The secret key should never be exposed publicly. + ///
+ /// Filter results by the unique user identifier returned by auth flows. + /// Returns a list of user wallet addresses, smart wallet addresses, and auth details. + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task ListUserWalletsAsync(double? limit, double? page, string email, string phone, string address, string externalWalletAddress, string id, string userId, System.Threading.CancellationToken cancellationToken) + { + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + request_.Method = new System.Net.Http.HttpMethod("GET"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + var urlBuilder_ = new System.Text.StringBuilder(); + if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl); + // Operation Path: "v1/wallets/user" + urlBuilder_.Append("v1/wallets/user"); + urlBuilder_.Append('?'); + if (limit != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("limit")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(limit, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + if (page != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("page")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(page, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + if (email != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("email")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(email, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + if (phone != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("phone")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(phone, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + if (address != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("address")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(address, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + if (externalWalletAddress != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("externalWalletAddress")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(externalWalletAddress, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + if (id != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("id")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(id, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + if (userId != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("userId")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(userId, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + urlBuilder_.Length--; + + PrepareRequest(client_, request_, urlBuilder_); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + PrepareRequest(client_, request_, url_); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = new System.Collections.Generic.Dictionary>(); + foreach (var item_ in response_.Headers) + headers_[item_.Key] = item_.Value; + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + ProcessResponse(client_, response_); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 401) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Authentication required. The request must include a valid `x-secret-key` header for backend authentication.", status_, responseText_, headers_, null); + } + else + if (status_ == 500) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Internal server error. This may occur due to service unavailability or unexpected server errors.", status_, responseText_, headers_, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// Create User Wallet + /// + /// + /// Create a user wallet with a wallet based on their authentication strategy. This endpoint creates a wallet in advance that can be claimed later when the user authenticates. + ///
+ ///
**Authentication**: This endpoint requires backend authentication using the `x-secret-key` header. The secret key should never be exposed publicly. + ///
+ /// Successfully created a user wallet with wallet. + /// A server side error occurred. + public virtual System.Threading.Tasks.Task CreateUserWalletAsync(Body5 body) + { + return CreateUserWalletAsync(body, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Create User Wallet + /// + /// + /// Create a user wallet with a wallet based on their authentication strategy. This endpoint creates a wallet in advance that can be claimed later when the user authenticates. + ///
+ ///
**Authentication**: This endpoint requires backend authentication using the `x-secret-key` header. The secret key should never be exposed publicly. + ///
+ /// Successfully created a user wallet with wallet. + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task CreateUserWalletAsync(Body5 body, System.Threading.CancellationToken cancellationToken) + { + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + var json_ = Newtonsoft.Json.JsonConvert.SerializeObject(body, JsonSerializerSettings); + var content_ = new System.Net.Http.StringContent(json_); + content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json"); + request_.Content = content_; + request_.Method = new System.Net.Http.HttpMethod("POST"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + var urlBuilder_ = new System.Text.StringBuilder(); + if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl); + // Operation Path: "v1/wallets/user" + urlBuilder_.Append("v1/wallets/user"); + + PrepareRequest(client_, request_, urlBuilder_); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + PrepareRequest(client_, request_, url_); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = new System.Collections.Generic.Dictionary>(); + foreach (var item_ in response_.Headers) + headers_[item_.Key] = item_.Value; + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + ProcessResponse(client_, response_); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 400) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Invalid request. This may occur due to missing required fields based on the authentication strategy, invalid strategy, or malformed request data.", status_, responseText_, headers_, null); + } + else + if (status_ == 401) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Authentication required. The request must include a valid `x-secret-key` header for backend authentication.", status_, responseText_, headers_, null); + } + else + if (status_ == 500) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Internal server error. This may occur due to service unavailability or unexpected server errors.", status_, responseText_, headers_, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// List Server Wallets + /// + /// + /// Get all server wallet details with pagination for your project. + ///
+ ///
**Authentication**: This endpoint requires backend authentication using the `x-secret-key` header. The secret key should never be exposed publicly. + ///
+ /// Returns a list of server wallet addresses, smart wallet addresses, and auth details. + /// A server side error occurred. + public virtual System.Threading.Tasks.Task ListServerWalletsAsync(double? limit, double? page) + { + return ListServerWalletsAsync(limit, page, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// List Server Wallets + /// + /// + /// Get all server wallet details with pagination for your project. + ///
+ ///
**Authentication**: This endpoint requires backend authentication using the `x-secret-key` header. The secret key should never be exposed publicly. + ///
+ /// Returns a list of server wallet addresses, smart wallet addresses, and auth details. + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task ListServerWalletsAsync(double? limit, double? page, System.Threading.CancellationToken cancellationToken) + { + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + request_.Method = new System.Net.Http.HttpMethod("GET"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + var urlBuilder_ = new System.Text.StringBuilder(); + if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl); + // Operation Path: "v1/wallets/server" + urlBuilder_.Append("v1/wallets/server"); + urlBuilder_.Append('?'); + if (limit != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("limit")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(limit, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + if (page != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("page")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(page, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + urlBuilder_.Length--; + + PrepareRequest(client_, request_, urlBuilder_); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + PrepareRequest(client_, request_, url_); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = new System.Collections.Generic.Dictionary>(); + foreach (var item_ in response_.Headers) + headers_[item_.Key] = item_.Value; + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + ProcessResponse(client_, response_); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 401) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Authentication required. The request must include a valid `x-secret-key` header for backend authentication.", status_, responseText_, headers_, null); + } + else + if (status_ == 500) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Internal server error. This may occur due to service unavailability or unexpected server errors.", status_, responseText_, headers_, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// Create Server Wallet + /// + /// + /// Creates a server wallet from a unique identifier. If the wallet already exists, it will return the existing wallet. + ///
+ ///
**Authentication**: This endpoint requires backend authentication using the `x-secret-key` header. The secret key should never be exposed publicly. + ///
+ /// Server wallet created or connected successfully. Returns wallet addresses for subsequent operations. + /// A server side error occurred. + public virtual System.Threading.Tasks.Task CreateServerWalletAsync(Body6 body) + { + return CreateServerWalletAsync(body, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Create Server Wallet + /// + /// + /// Creates a server wallet from a unique identifier. If the wallet already exists, it will return the existing wallet. + ///
+ ///
**Authentication**: This endpoint requires backend authentication using the `x-secret-key` header. The secret key should never be exposed publicly. + ///
+ /// Server wallet created or connected successfully. Returns wallet addresses for subsequent operations. + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task CreateServerWalletAsync(Body6 body, System.Threading.CancellationToken cancellationToken) + { + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + var json_ = Newtonsoft.Json.JsonConvert.SerializeObject(body, JsonSerializerSettings); + var content_ = new System.Net.Http.StringContent(json_); + content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json"); + request_.Content = content_; + request_.Method = new System.Net.Http.HttpMethod("POST"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + var urlBuilder_ = new System.Text.StringBuilder(); + if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl); + // Operation Path: "v1/wallets/server" + urlBuilder_.Append("v1/wallets/server"); + + PrepareRequest(client_, request_, urlBuilder_); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + PrepareRequest(client_, request_, url_); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = new System.Collections.Generic.Dictionary>(); + foreach (var item_ in response_.Headers) + headers_[item_.Key] = item_.Value; + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + ProcessResponse(client_, response_); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 400) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Invalid request parameters. This occurs when the identifier format is invalid or required parameters are missing.", status_, responseText_, headers_, null); + } + else + if (status_ == 401) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Authentication required. For backend usage, include `x-secret-key` header.", status_, responseText_, headers_, null); + } + else + if (status_ == 500) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Internal server error. This may occur due to wallet service unavailability, smart wallet deployment issues, or unexpected server errors.", status_, responseText_, headers_, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// Get Balance + /// + /// + /// Get native or ERC20 token balance for a wallet address. Can retrieve live balances for any ERC20 token on a signle chain, or native token balances across multiple chains. + ///
+ ///
**Authentication**: Pass `x-client-id` header for frontend usage from allowlisted origins or `x-secret-key` for backend usage. + ///
+ /// A valid Ethereum address (0x-prefixed hex string) or ENS name (e.g., vitalik.eth). + /// Chain ID(s) to request balance data for. You can specify multiple chain IDs by repeating the parameter, up to a maximum of 50. Example: ?chainId=1&chainId=137 + /// The token contract address. Omit for native token (ETH, MATIC, etc.). + /// Wallet native balances retrieved successfully. Returns detailed native token balance information for each chain including token metadata and formatted values. + /// A server side error occurred. + public virtual System.Threading.Tasks.Task GetWalletBalanceAsync(string address, System.Collections.Generic.IEnumerable chainId, string tokenAddress) + { + return GetWalletBalanceAsync(address, chainId, tokenAddress, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Get Balance + /// + /// + /// Get native or ERC20 token balance for a wallet address. Can retrieve live balances for any ERC20 token on a signle chain, or native token balances across multiple chains. + ///
+ ///
**Authentication**: Pass `x-client-id` header for frontend usage from allowlisted origins or `x-secret-key` for backend usage. + ///
+ /// A valid Ethereum address (0x-prefixed hex string) or ENS name (e.g., vitalik.eth). + /// Chain ID(s) to request balance data for. You can specify multiple chain IDs by repeating the parameter, up to a maximum of 50. Example: ?chainId=1&chainId=137 + /// The token contract address. Omit for native token (ETH, MATIC, etc.). + /// Wallet native balances retrieved successfully. Returns detailed native token balance information for each chain including token metadata and formatted values. + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task GetWalletBalanceAsync(string address, System.Collections.Generic.IEnumerable chainId, string tokenAddress, System.Threading.CancellationToken cancellationToken) + { + if (address == null) + throw new System.ArgumentNullException("address"); + + if (chainId == null) + throw new System.ArgumentNullException("chainId"); + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + request_.Method = new System.Net.Http.HttpMethod("GET"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + var urlBuilder_ = new System.Text.StringBuilder(); + if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl); + // Operation Path: "v1/wallets/{address}/balance" + urlBuilder_.Append("v1/wallets/"); + urlBuilder_.Append(System.Uri.EscapeDataString(ConvertToString(address, System.Globalization.CultureInfo.InvariantCulture))); + urlBuilder_.Append("/balance"); + urlBuilder_.Append('?'); + urlBuilder_.Append(System.Uri.EscapeDataString("chainId") + "="); + foreach (var item_ in chainId) + { + urlBuilder_.Append(System.Uri.EscapeDataString(ConvertToString(item_, System.Globalization.CultureInfo.InvariantCulture))).Append(","); + } + urlBuilder_.Length--; + urlBuilder_.Append("&"); + if (tokenAddress != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("tokenAddress")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(tokenAddress, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + urlBuilder_.Length--; + + PrepareRequest(client_, request_, urlBuilder_); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + PrepareRequest(client_, request_, url_); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = new System.Collections.Generic.Dictionary>(); + foreach (var item_ in response_.Headers) + headers_[item_.Key] = item_.Value; + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + ProcessResponse(client_, response_); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 400) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Invalid request parameters. This occurs when the wallet address format is invalid, chainId array is empty or exceeds the maximum limit of 50, or chain IDs are invalid.", status_, responseText_, headers_, null); + } + else + if (status_ == 401) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Authentication required. The request must include a valid `x-client-id` header for frontend usage or `x-secret-key` for backend usage.", status_, responseText_, headers_, null); + } + else + if (status_ == 500) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Internal server error. This may occur due to blockchain connectivity issues, RPC service unavailability, or unexpected server errors.", status_, responseText_, headers_, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// Get Transactions + /// + /// + /// Retrieves transactions for a specific wallet address across one or more blockchain networks. This endpoint provides comprehensive transaction data including both incoming and outgoing transactions, with block information, gas details, transaction status, and function calls. Results can be filtered, paginated, and sorted to meet specific requirements. + ///
+ ///
**Authentication**: Pass `x-client-id` header for frontend usage from allowlisted origins or `x-secret-key` for backend usage. + ///
+ /// A valid Ethereum address (0x-prefixed hex string) or ENS name (e.g., vitalik.eth). + /// Chain ID(s) to request transaction data for. You can specify multiple chain IDs by repeating the parameter, up to a maximum of 50. Example: ?chainId=1&chainId=137 + /// Filter by block timestamp (Unix timestamp) greater than or equal to this value + /// Filter by block timestamp (Unix timestamp) less than or equal to this value + /// Filter by block number greater than or equal to this value + /// Filter by block number less than or equal to this value + /// Filter by transaction value (in wei) greater than this value + /// Filter by function selector (4-byte method ID), e.g., '0xa9059cbb' for ERC-20 transfer + /// Current page number + /// Number of items per page + /// Sort order: 'asc' for ascending, 'desc' for descending + /// Wallet transactions retrieved successfully. Returns transaction data with metadata including pagination information and chain details. Includes decoded function calls when ABI is available. + /// A server side error occurred. + public virtual System.Threading.Tasks.Task GetWalletTransactionsAsync(string address, System.Collections.Generic.IEnumerable chainId, int? filterBlockTimestampGte, int? filterBlockTimestampLte, int? filterBlockNumberGte, int? filterBlockNumberLte, string filterValueGt, string filterFunctionSelector, double? page, double? limit, SortOrder? sortOrder) + { + return GetWalletTransactionsAsync(address, chainId, filterBlockTimestampGte, filterBlockTimestampLte, filterBlockNumberGte, filterBlockNumberLte, filterValueGt, filterFunctionSelector, page, limit, sortOrder, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Get Transactions + /// + /// + /// Retrieves transactions for a specific wallet address across one or more blockchain networks. This endpoint provides comprehensive transaction data including both incoming and outgoing transactions, with block information, gas details, transaction status, and function calls. Results can be filtered, paginated, and sorted to meet specific requirements. + ///
+ ///
**Authentication**: Pass `x-client-id` header for frontend usage from allowlisted origins or `x-secret-key` for backend usage. + ///
+ /// A valid Ethereum address (0x-prefixed hex string) or ENS name (e.g., vitalik.eth). + /// Chain ID(s) to request transaction data for. You can specify multiple chain IDs by repeating the parameter, up to a maximum of 50. Example: ?chainId=1&chainId=137 + /// Filter by block timestamp (Unix timestamp) greater than or equal to this value + /// Filter by block timestamp (Unix timestamp) less than or equal to this value + /// Filter by block number greater than or equal to this value + /// Filter by block number less than or equal to this value + /// Filter by transaction value (in wei) greater than this value + /// Filter by function selector (4-byte method ID), e.g., '0xa9059cbb' for ERC-20 transfer + /// Current page number + /// Number of items per page + /// Sort order: 'asc' for ascending, 'desc' for descending + /// Wallet transactions retrieved successfully. Returns transaction data with metadata including pagination information and chain details. Includes decoded function calls when ABI is available. + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task GetWalletTransactionsAsync(string address, System.Collections.Generic.IEnumerable chainId, int? filterBlockTimestampGte, int? filterBlockTimestampLte, int? filterBlockNumberGte, int? filterBlockNumberLte, string filterValueGt, string filterFunctionSelector, double? page, double? limit, SortOrder? sortOrder, System.Threading.CancellationToken cancellationToken) + { + if (address == null) + throw new System.ArgumentNullException("address"); + + if (chainId == null) + throw new System.ArgumentNullException("chainId"); + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + request_.Method = new System.Net.Http.HttpMethod("GET"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + var urlBuilder_ = new System.Text.StringBuilder(); + if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl); + // Operation Path: "v1/wallets/{address}/transactions" + urlBuilder_.Append("v1/wallets/"); + urlBuilder_.Append(System.Uri.EscapeDataString(ConvertToString(address, System.Globalization.CultureInfo.InvariantCulture))); + urlBuilder_.Append("/transactions"); + urlBuilder_.Append('?'); + urlBuilder_.Append(System.Uri.EscapeDataString("chainId") + "="); + foreach (var item_ in chainId) + { + urlBuilder_.Append(System.Uri.EscapeDataString(ConvertToString(item_, System.Globalization.CultureInfo.InvariantCulture))).Append(","); + } + urlBuilder_.Length--; + urlBuilder_.Append("&"); + if (filterBlockTimestampGte != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("filterBlockTimestampGte")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(filterBlockTimestampGte, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + if (filterBlockTimestampLte != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("filterBlockTimestampLte")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(filterBlockTimestampLte, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + if (filterBlockNumberGte != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("filterBlockNumberGte")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(filterBlockNumberGte, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + if (filterBlockNumberLte != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("filterBlockNumberLte")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(filterBlockNumberLte, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + if (filterValueGt != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("filterValueGt")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(filterValueGt, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + if (filterFunctionSelector != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("filterFunctionSelector")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(filterFunctionSelector, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + if (page != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("page")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(page, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + if (limit != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("limit")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(limit, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + if (sortOrder != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("sortOrder")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(sortOrder, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + urlBuilder_.Length--; + + PrepareRequest(client_, request_, urlBuilder_); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + PrepareRequest(client_, request_, url_); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = new System.Collections.Generic.Dictionary>(); + foreach (var item_ in response_.Headers) + headers_[item_.Key] = item_.Value; + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + ProcessResponse(client_, response_); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 400) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Invalid request parameters. This occurs when the wallet address format is invalid, chainId array is empty or exceeds the maximum limit of 50, or pagination parameters are out of range.", status_, responseText_, headers_, null); + } + else + if (status_ == 401) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Authentication required. The request must include a valid `x-client-id` header for frontend usage or `x-secret-key` for backend usage.", status_, responseText_, headers_, null); + } + else + if (status_ == 404) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Wallet not found or no transactions available for the specified wallet address on the given blockchain networks.", status_, responseText_, headers_, null); + } + else + if (status_ == 500) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Internal server error. This may occur due to network connectivity issues, external service unavailability, or unexpected server errors.", status_, responseText_, headers_, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// Get Tokens + /// + /// + /// Retrieves token balances for a specific wallet address across one or more blockchain networks. This endpoint provides comprehensive token data including ERC-20 tokens with their balances, metadata, and price information. Results can be filtered by chain, sorted by balance or USD value, and customized to include/exclude spam tokens, native tokens, and tokens without price data. Supports pagination and metadata resolution options. + ///
+ ///
**Authentication**: Pass `x-client-id` header for frontend usage from allowlisted origins or `x-secret-key` for backend usage. + ///
+ /// A valid Ethereum address (0x-prefixed hex string) or ENS name (e.g., vitalik.eth). + /// Chain ID(s) to request token data for. You can specify multiple chain IDs by repeating the parameter, up to a maximum of 50. Example: ?chainId=1&chainId=137 + /// Token addresses to filter by. If provided, only tokens with these addresses will be returned. + /// The number of tokens to return per chain (default: 20, max: 500). + /// The page number for pagination (default: 1, max: 20). + /// Whether to include token metadata (default: true). + /// Whether to resolve metadata links to fetch additional token information (default: true). + /// Whether to include tokens marked as spam (default: false). + /// Whether to include native tokens (e.g., ETH, MATIC) in the results (default: true). + /// Field to sort tokens by: 'balance' for token balance, 'token_address' for token address, 'token_price' for token price, 'usd_value' for USD value (default: usd_value). + /// Sort order: 'asc' for ascending, 'desc' for descending (default: desc). + /// Whether to include tokens without price data (default: true). + /// Wallet tokens retrieved successfully. Returns token data with metadata including pagination information and chain details. Includes token balances, metadata, and price information when available. Results are sorted by the specified criteria (default: USD value descending) and filtered according to the provided parameters. + /// A server side error occurred. + public virtual System.Threading.Tasks.Task GetWalletTokensAsync(string address, System.Collections.Generic.IEnumerable chainId, System.Collections.Generic.IEnumerable tokenAddresses, int? limit, int? page, Metadata? metadata, ResolveMetadataLinks? resolveMetadataLinks, IncludeSpam? includeSpam, IncludeNative? includeNative, SortBy? sortBy, SortOrder2? sortOrder, IncludeWithoutPrice? includeWithoutPrice) + { + return GetWalletTokensAsync(address, chainId, tokenAddresses, limit, page, metadata, resolveMetadataLinks, includeSpam, includeNative, sortBy, sortOrder, includeWithoutPrice, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Get Tokens + /// + /// + /// Retrieves token balances for a specific wallet address across one or more blockchain networks. This endpoint provides comprehensive token data including ERC-20 tokens with their balances, metadata, and price information. Results can be filtered by chain, sorted by balance or USD value, and customized to include/exclude spam tokens, native tokens, and tokens without price data. Supports pagination and metadata resolution options. + ///
+ ///
**Authentication**: Pass `x-client-id` header for frontend usage from allowlisted origins or `x-secret-key` for backend usage. + ///
+ /// A valid Ethereum address (0x-prefixed hex string) or ENS name (e.g., vitalik.eth). + /// Chain ID(s) to request token data for. You can specify multiple chain IDs by repeating the parameter, up to a maximum of 50. Example: ?chainId=1&chainId=137 + /// Token addresses to filter by. If provided, only tokens with these addresses will be returned. + /// The number of tokens to return per chain (default: 20, max: 500). + /// The page number for pagination (default: 1, max: 20). + /// Whether to include token metadata (default: true). + /// Whether to resolve metadata links to fetch additional token information (default: true). + /// Whether to include tokens marked as spam (default: false). + /// Whether to include native tokens (e.g., ETH, MATIC) in the results (default: true). + /// Field to sort tokens by: 'balance' for token balance, 'token_address' for token address, 'token_price' for token price, 'usd_value' for USD value (default: usd_value). + /// Sort order: 'asc' for ascending, 'desc' for descending (default: desc). + /// Whether to include tokens without price data (default: true). + /// Wallet tokens retrieved successfully. Returns token data with metadata including pagination information and chain details. Includes token balances, metadata, and price information when available. Results are sorted by the specified criteria (default: USD value descending) and filtered according to the provided parameters. + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task GetWalletTokensAsync(string address, System.Collections.Generic.IEnumerable chainId, System.Collections.Generic.IEnumerable tokenAddresses, int? limit, int? page, Metadata? metadata, ResolveMetadataLinks? resolveMetadataLinks, IncludeSpam? includeSpam, IncludeNative? includeNative, SortBy? sortBy, SortOrder2? sortOrder, IncludeWithoutPrice? includeWithoutPrice, System.Threading.CancellationToken cancellationToken) + { + if (address == null) + throw new System.ArgumentNullException("address"); + + if (chainId == null) + throw new System.ArgumentNullException("chainId"); + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + request_.Method = new System.Net.Http.HttpMethod("GET"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + var urlBuilder_ = new System.Text.StringBuilder(); + if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl); + // Operation Path: "v1/wallets/{address}/tokens" + urlBuilder_.Append("v1/wallets/"); + urlBuilder_.Append(System.Uri.EscapeDataString(ConvertToString(address, System.Globalization.CultureInfo.InvariantCulture))); + urlBuilder_.Append("/tokens"); + urlBuilder_.Append('?'); + urlBuilder_.Append(System.Uri.EscapeDataString("chainId") + "="); + foreach (var item_ in chainId) + { + urlBuilder_.Append(System.Uri.EscapeDataString(ConvertToString(item_, System.Globalization.CultureInfo.InvariantCulture))).Append(","); + } + urlBuilder_.Length--; + urlBuilder_.Append("&"); + if (tokenAddresses != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("tokenAddresses") + "="); + foreach (var item_ in tokenAddresses) + { + urlBuilder_.Append(System.Uri.EscapeDataString(ConvertToString(item_, System.Globalization.CultureInfo.InvariantCulture))).Append(","); + } + urlBuilder_.Length--; + urlBuilder_.Append("&"); + } + if (limit != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("limit")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(limit, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + if (page != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("page")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(page, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + if (metadata != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("metadata")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(metadata, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + if (resolveMetadataLinks != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("resolveMetadataLinks")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(resolveMetadataLinks, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + if (includeSpam != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("includeSpam")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(includeSpam, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + if (includeNative != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("includeNative")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(includeNative, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + if (sortBy != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("sortBy")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(sortBy, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + if (sortOrder != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("sortOrder")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(sortOrder, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + if (includeWithoutPrice != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("includeWithoutPrice")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(includeWithoutPrice, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + urlBuilder_.Length--; + + PrepareRequest(client_, request_, urlBuilder_); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + PrepareRequest(client_, request_, url_); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = new System.Collections.Generic.Dictionary>(); + foreach (var item_ in response_.Headers) + headers_[item_.Key] = item_.Value; + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + ProcessResponse(client_, response_); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 400) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Invalid request parameters. This occurs when the wallet address format is invalid, chainId array is empty or exceeds the maximum limit of 50, or pagination parameters are out of range.", status_, responseText_, headers_, null); + } + else + if (status_ == 401) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Authentication required. The request must include a valid `x-client-id` header for frontend usage or `x-secret-key` for backend usage.", status_, responseText_, headers_, null); + } + else + if (status_ == 404) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Wallet not found or no tokens available for the specified wallet address on the given blockchain networks.", status_, responseText_, headers_, null); + } + else + if (status_ == 500) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Internal server error. This may occur due to network connectivity issues, external service unavailability, or unexpected server errors.", status_, responseText_, headers_, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// Get NFTs + /// + /// + /// Retrieves NFTs for a specific wallet address across one or more blockchain networks. This endpoint provides comprehensive NFT data including metadata, attributes, and collection information. Results can be filtered by chain and paginated to meet specific requirements. + ///
+ ///
**Authentication**: Pass `x-client-id` header for frontend usage from allowlisted origins or `x-secret-key` for backend usage. + ///
+ /// A valid Ethereum address (0x-prefixed hex string) or ENS name (e.g., vitalik.eth). + /// Chain ID(s) to request NFT data for. You can specify multiple chain IDs by repeating the parameter, up to a maximum of 50. Example: ?chainId=1&chainId=137 + /// NFT contract addresses to filter by. If provided, only NFTs with these addresses will be returned. + /// The number of NFTs to return per chain (default: 20, max: 500). + /// The page number for pagination (default: 1, max: 20). + /// Wallet NFTs retrieved successfully. Returns NFT data with metadata including pagination information and chain details. Includes NFT metadata, attributes, and collection information when available. + /// A server side error occurred. + public virtual System.Threading.Tasks.Task GetWalletNFTsAsync(string address, System.Collections.Generic.IEnumerable chainId, System.Collections.Generic.IEnumerable contractAddresses, int? limit, int? page) + { + return GetWalletNFTsAsync(address, chainId, contractAddresses, limit, page, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Get NFTs + /// + /// + /// Retrieves NFTs for a specific wallet address across one or more blockchain networks. This endpoint provides comprehensive NFT data including metadata, attributes, and collection information. Results can be filtered by chain and paginated to meet specific requirements. + ///
+ ///
**Authentication**: Pass `x-client-id` header for frontend usage from allowlisted origins or `x-secret-key` for backend usage. + ///
+ /// A valid Ethereum address (0x-prefixed hex string) or ENS name (e.g., vitalik.eth). + /// Chain ID(s) to request NFT data for. You can specify multiple chain IDs by repeating the parameter, up to a maximum of 50. Example: ?chainId=1&chainId=137 + /// NFT contract addresses to filter by. If provided, only NFTs with these addresses will be returned. + /// The number of NFTs to return per chain (default: 20, max: 500). + /// The page number for pagination (default: 1, max: 20). + /// Wallet NFTs retrieved successfully. Returns NFT data with metadata including pagination information and chain details. Includes NFT metadata, attributes, and collection information when available. + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task GetWalletNFTsAsync(string address, System.Collections.Generic.IEnumerable chainId, System.Collections.Generic.IEnumerable contractAddresses, int? limit, int? page, System.Threading.CancellationToken cancellationToken) + { + if (address == null) + throw new System.ArgumentNullException("address"); + + if (chainId == null) + throw new System.ArgumentNullException("chainId"); + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + request_.Method = new System.Net.Http.HttpMethod("GET"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + var urlBuilder_ = new System.Text.StringBuilder(); + if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl); + // Operation Path: "v1/wallets/{address}/nfts" + urlBuilder_.Append("v1/wallets/"); + urlBuilder_.Append(System.Uri.EscapeDataString(ConvertToString(address, System.Globalization.CultureInfo.InvariantCulture))); + urlBuilder_.Append("/nfts"); + urlBuilder_.Append('?'); + urlBuilder_.Append(System.Uri.EscapeDataString("chainId") + "="); + foreach (var item_ in chainId) + { + urlBuilder_.Append(System.Uri.EscapeDataString(ConvertToString(item_, System.Globalization.CultureInfo.InvariantCulture))).Append(","); + } + urlBuilder_.Length--; + urlBuilder_.Append("&"); + if (contractAddresses != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("contractAddresses") + "="); + foreach (var item_ in contractAddresses) + { + urlBuilder_.Append(System.Uri.EscapeDataString(ConvertToString(item_, System.Globalization.CultureInfo.InvariantCulture))).Append(","); + } + urlBuilder_.Length--; + urlBuilder_.Append("&"); + } + if (limit != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("limit")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(limit, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + if (page != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("page")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(page, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + urlBuilder_.Length--; + + PrepareRequest(client_, request_, urlBuilder_); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + PrepareRequest(client_, request_, url_); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = new System.Collections.Generic.Dictionary>(); + foreach (var item_ in response_.Headers) + headers_[item_.Key] = item_.Value; + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + ProcessResponse(client_, response_); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 400) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Invalid request parameters. This occurs when the wallet address format is invalid, chainId array is empty or exceeds the maximum limit of 50, or pagination parameters are out of range.", status_, responseText_, headers_, null); + } + else + if (status_ == 401) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Authentication required. The request must include a valid `x-client-id` header for frontend usage or `x-secret-key` for backend usage.", status_, responseText_, headers_, null); + } + else + if (status_ == 404) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Wallet not found or no NFTs available for the specified wallet address on the given blockchain networks.", status_, responseText_, headers_, null); + } + else + if (status_ == 500) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Internal server error. This may occur due to network connectivity issues, external service unavailability, or unexpected server errors.", status_, responseText_, headers_, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// Sign Message + /// + /// + /// Signs an arbitrary message using the specified wallet. This endpoint supports both text and hexadecimal message formats. The signing is performed using thirdweb Engine with smart wallet support for gasless transactions. + ///
+ ///
**Authentication**: This endpoint requires project authentication and wallet authentication. For backend usage, use `x-secret-key` header. For frontend usage, use `x-client-id` + `Authorization: Bearer <jwt>` headers. + ///
+ /// Message signed successfully. Returns the cryptographic signature that can be used for verification. + /// A server side error occurred. + public virtual System.Threading.Tasks.Task SignMessageAsync(Body7 body) + { + return SignMessageAsync(body, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Sign Message + /// + /// + /// Signs an arbitrary message using the specified wallet. This endpoint supports both text and hexadecimal message formats. The signing is performed using thirdweb Engine with smart wallet support for gasless transactions. + ///
+ ///
**Authentication**: This endpoint requires project authentication and wallet authentication. For backend usage, use `x-secret-key` header. For frontend usage, use `x-client-id` + `Authorization: Bearer <jwt>` headers. + ///
+ /// Message signed successfully. Returns the cryptographic signature that can be used for verification. + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task SignMessageAsync(Body7 body, System.Threading.CancellationToken cancellationToken) + { + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + var json_ = Newtonsoft.Json.JsonConvert.SerializeObject(body, JsonSerializerSettings); + var content_ = new System.Net.Http.StringContent(json_); + content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json"); + request_.Content = content_; + request_.Method = new System.Net.Http.HttpMethod("POST"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + var urlBuilder_ = new System.Text.StringBuilder(); + if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl); + // Operation Path: "v1/wallets/sign-message" + urlBuilder_.Append("v1/wallets/sign-message"); + + PrepareRequest(client_, request_, urlBuilder_); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + PrepareRequest(client_, request_, url_); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = new System.Collections.Generic.Dictionary>(); + foreach (var item_ in response_.Headers) + headers_[item_.Key] = item_.Value; + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + ProcessResponse(client_, response_); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 400) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Invalid request parameters. This occurs when the wallet address format is invalid, chainId is not supported, or the message format is incorrect.", status_, responseText_, headers_, null); + } + else + if (status_ == 401) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Authentication required. For backend usage, include `x-secret-key` header. For frontend usage, include `x-client-id` + `Authorization: Bearer ` headers.", status_, responseText_, headers_, null); + } + else + if (status_ == 500) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Internal server error. This may occur due to wallet connectivity issues, signing service unavailability, or unexpected server errors.", status_, responseText_, headers_, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// Sign Typed Data + /// + /// + /// Signs structured data according to the EIP-712 standard using the specified wallet. This is commonly used for secure message signing in DeFi protocols, NFT marketplaces, and other dApps that require structured data verification. The typed data includes domain separation and type definitions for enhanced security. + ///
+ ///
**Authentication**: This endpoint requires project authentication and wallet authentication. For backend usage, use `x-secret-key` header. For frontend usage, use `x-client-id` + `Authorization: Bearer <jwt>` headers. + ///
+ /// Typed data signed successfully. Returns the EIP-712 compliant signature that can be used for on-chain verification. + /// A server side error occurred. + public virtual System.Threading.Tasks.Task SignTypedDataAsync(Body8 body) + { + return SignTypedDataAsync(body, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Sign Typed Data + /// + /// + /// Signs structured data according to the EIP-712 standard using the specified wallet. This is commonly used for secure message signing in DeFi protocols, NFT marketplaces, and other dApps that require structured data verification. The typed data includes domain separation and type definitions for enhanced security. + ///
+ ///
**Authentication**: This endpoint requires project authentication and wallet authentication. For backend usage, use `x-secret-key` header. For frontend usage, use `x-client-id` + `Authorization: Bearer <jwt>` headers. + ///
+ /// Typed data signed successfully. Returns the EIP-712 compliant signature that can be used for on-chain verification. + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task SignTypedDataAsync(Body8 body, System.Threading.CancellationToken cancellationToken) + { + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + var json_ = Newtonsoft.Json.JsonConvert.SerializeObject(body, JsonSerializerSettings); + var content_ = new System.Net.Http.StringContent(json_); + content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json"); + request_.Content = content_; + request_.Method = new System.Net.Http.HttpMethod("POST"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + var urlBuilder_ = new System.Text.StringBuilder(); + if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl); + // Operation Path: "v1/wallets/sign-typed-data" + urlBuilder_.Append("v1/wallets/sign-typed-data"); + + PrepareRequest(client_, request_, urlBuilder_); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + PrepareRequest(client_, request_, url_); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = new System.Collections.Generic.Dictionary>(); + foreach (var item_ in response_.Headers) + headers_[item_.Key] = item_.Value; + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + ProcessResponse(client_, response_); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 400) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Invalid request parameters. This occurs when the typed data structure is malformed, domain parameters are incorrect, or wallet address format is invalid.", status_, responseText_, headers_, null); + } + else + if (status_ == 401) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Authentication required. The request must include valid `x-wallet-access-token` headers for accessing the wallet, as well as a x-client-id (frontend) or x-secret-key (backend) for project authentication.", status_, responseText_, headers_, null); + } + else + if (status_ == 500) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Internal server error. This may occur due to wallet connectivity issues, signing service unavailability, or unexpected server errors.", status_, responseText_, headers_, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// Send Tokens + /// + /// + /// Send tokens to multiple recipients in a single transaction batch. Supports native tokens (ETH, MATIC, etc.), ERC20 tokens, ERC721 NFTs, and ERC1155 tokens. The token type is automatically determined based on the provided parameters and ERC165 interface detection: + ///
+ ///
- **Native Token**: No `tokenAddress` provided + ///
- **ERC20**: `tokenAddress` provided, no `tokenId` + ///
- **ERC721/ERC1155**: `tokenAddress` and `tokenId` provided. Auto detects contract type: + ///
- ERC721: quantity must be '1' + ///
- ERC1155: any quantity allowed (including '1') + ///
+ ///
**Authentication**: This endpoint requires project authentication and wallet authentication. For backend usage, use `x-secret-key` header. For frontend usage, use `x-client-id` + `Authorization: Bearer <jwt>` headers. + ///
+ /// Tokens sent successfully. Returns transaction IDs for tracking and monitoring. + /// A server side error occurred. + public virtual System.Threading.Tasks.Task SendTokensAsync(Body9 body) + { + return SendTokensAsync(body, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Send Tokens + /// + /// + /// Send tokens to multiple recipients in a single transaction batch. Supports native tokens (ETH, MATIC, etc.), ERC20 tokens, ERC721 NFTs, and ERC1155 tokens. The token type is automatically determined based on the provided parameters and ERC165 interface detection: + ///
+ ///
- **Native Token**: No `tokenAddress` provided + ///
- **ERC20**: `tokenAddress` provided, no `tokenId` + ///
- **ERC721/ERC1155**: `tokenAddress` and `tokenId` provided. Auto detects contract type: + ///
- ERC721: quantity must be '1' + ///
- ERC1155: any quantity allowed (including '1') + ///
+ ///
**Authentication**: This endpoint requires project authentication and wallet authentication. For backend usage, use `x-secret-key` header. For frontend usage, use `x-client-id` + `Authorization: Bearer <jwt>` headers. + ///
+ /// Tokens sent successfully. Returns transaction IDs for tracking and monitoring. + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task SendTokensAsync(Body9 body, System.Threading.CancellationToken cancellationToken) + { + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + var json_ = Newtonsoft.Json.JsonConvert.SerializeObject(body, JsonSerializerSettings); + var content_ = new System.Net.Http.StringContent(json_); + content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json"); + request_.Content = content_; + request_.Method = new System.Net.Http.HttpMethod("POST"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + var urlBuilder_ = new System.Text.StringBuilder(); + if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl); + // Operation Path: "v1/wallets/send" + urlBuilder_.Append("v1/wallets/send"); + + PrepareRequest(client_, request_, urlBuilder_); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + PrepareRequest(client_, request_, url_); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = new System.Collections.Generic.Dictionary>(); + foreach (var item_ in response_.Headers) + headers_[item_.Key] = item_.Value; + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + ProcessResponse(client_, response_); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 400) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Invalid request parameters. This occurs when token parameters are malformed, insufficient balance, invalid contract data, or unsupported token type.", status_, responseText_, headers_, null); + } + else + if (status_ == 401) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Authentication required. For backend usage, include `x-secret-key` header. For frontend usage, include `x-client-id` + `Authorization: Bearer ` headers.", status_, responseText_, headers_, null); + } + else + if (status_ == 500) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Internal server error. This may occur due to blockchain connectivity issues, gas estimation failures, contract execution errors, or unexpected server errors.", status_, responseText_, headers_, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// List Contracts + /// + /// + /// Retrieves a list of all smart contracts imported by the authenticated client on the thirdweb dashboard. This endpoint provides access to contracts that have been added to your dashboard for management and interaction. Results include contract metadata, deployment information, and import timestamps. + ///
+ ///
**Authentication**: This endpoint requires backend authentication using the `x-secret-key` header. The secret key should never be exposed publicly. + ///
+ ///
**Note**: For detailed contract metadata including compilation information, ABI, and source code, use the dedicated metadata endpoint: `GET /v1/contracts/{chainId}/{address}/metadata`. + ///
+ /// The number of contracts to return (default: 20, max: 100). + /// The page number for pagination (default: 1). + /// Successfully retrieved list of contracts + /// A server side error occurred. + public virtual System.Threading.Tasks.Task ListContractsAsync(int? limit, int? page) + { + return ListContractsAsync(limit, page, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// List Contracts + /// + /// + /// Retrieves a list of all smart contracts imported by the authenticated client on the thirdweb dashboard. This endpoint provides access to contracts that have been added to your dashboard for management and interaction. Results include contract metadata, deployment information, and import timestamps. + ///
+ ///
**Authentication**: This endpoint requires backend authentication using the `x-secret-key` header. The secret key should never be exposed publicly. + ///
+ ///
**Note**: For detailed contract metadata including compilation information, ABI, and source code, use the dedicated metadata endpoint: `GET /v1/contracts/{chainId}/{address}/metadata`. + ///
+ /// The number of contracts to return (default: 20, max: 100). + /// The page number for pagination (default: 1). + /// Successfully retrieved list of contracts + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task ListContractsAsync(int? limit, int? page, System.Threading.CancellationToken cancellationToken) + { + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + request_.Method = new System.Net.Http.HttpMethod("GET"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + var urlBuilder_ = new System.Text.StringBuilder(); + if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl); + // Operation Path: "v1/contracts" + urlBuilder_.Append("v1/contracts"); + urlBuilder_.Append('?'); + if (limit != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("limit")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(limit, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + if (page != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("page")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(page, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + urlBuilder_.Length--; + + PrepareRequest(client_, request_, urlBuilder_); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + PrepareRequest(client_, request_, url_); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = new System.Collections.Generic.Dictionary>(); + foreach (var item_ in response_.Headers) + headers_[item_.Key] = item_.Value; + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + ProcessResponse(client_, response_); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 400) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Invalid request parameters", status_, responseText_, headers_, null); + } + else + if (status_ == 401) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Authentication required. The request must include a valid `x-secret-key` header for backend authentication.", status_, responseText_, headers_, null); + } + else + if (status_ == 429) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Rate limit exceeded", status_, responseText_, headers_, null); + } + else + if (status_ == 500) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Internal server error", status_, responseText_, headers_, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// Deploy Contract + /// + /// + /// Deploy a new smart contract to a blockchain network using raw bytecode. This endpoint allows you to deploy contracts by providing the contract bytecode, ABI, constructor parameters, and optional salt for deterministic deployment. + ///
+ ///
**Authentication**: This endpoint requires backend authentication using the `x-secret-key` header. The secret key should never be exposed publicly. + ///
+ /// Contract deployed successfully + /// A server side error occurred. + public virtual System.Threading.Tasks.Task DeployContractAsync(Body10 body) + { + return DeployContractAsync(body, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Deploy Contract + /// + /// + /// Deploy a new smart contract to a blockchain network using raw bytecode. This endpoint allows you to deploy contracts by providing the contract bytecode, ABI, constructor parameters, and optional salt for deterministic deployment. + ///
+ ///
**Authentication**: This endpoint requires backend authentication using the `x-secret-key` header. The secret key should never be exposed publicly. + ///
+ /// Contract deployed successfully + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task DeployContractAsync(Body10 body, System.Threading.CancellationToken cancellationToken) + { + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + var json_ = Newtonsoft.Json.JsonConvert.SerializeObject(body, JsonSerializerSettings); + var content_ = new System.Net.Http.StringContent(json_); + content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json"); + request_.Content = content_; + request_.Method = new System.Net.Http.HttpMethod("POST"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + var urlBuilder_ = new System.Text.StringBuilder(); + if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl); + // Operation Path: "v1/contracts" + urlBuilder_.Append("v1/contracts"); + + PrepareRequest(client_, request_, urlBuilder_); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + PrepareRequest(client_, request_, url_); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = new System.Collections.Generic.Dictionary>(); + foreach (var item_ in response_.Headers) + headers_[item_.Key] = item_.Value; + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + ProcessResponse(client_, response_); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 400) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Invalid request parameters", status_, responseText_, headers_, null); + } + else + if (status_ == 401) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Authentication required. The request must include a valid `x-secret-key` header for backend authentication.", status_, responseText_, headers_, null); + } + else + if (status_ == 429) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Rate limit exceeded", status_, responseText_, headers_, null); + } + else + if (status_ == 500) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Internal server error", status_, responseText_, headers_, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// Read Contract + /// + /// + /// Executes multiple read-only contract method calls in a single batch request. This endpoint allows efficient batch reading from multiple contracts on the same chain, significantly reducing the number of HTTP requests needed. Each call specifies the contract address, method signature, and optional parameters. Results are returned in the same order as the input calls, with individual success/failure status for each operation. + ///
+ ///
**Authentication**: Pass `x-client-id` header for frontend usage from allowlisted origins or `x-secret-key` for backend usage. + ///
+ /// Contract read operations completed successfully. Returns an array of results corresponding to each input call, including both successful and failed operations. + /// A server side error occurred. + public virtual System.Threading.Tasks.Task ReadContractAsync(Body11 body) + { + return ReadContractAsync(body, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Read Contract + /// + /// + /// Executes multiple read-only contract method calls in a single batch request. This endpoint allows efficient batch reading from multiple contracts on the same chain, significantly reducing the number of HTTP requests needed. Each call specifies the contract address, method signature, and optional parameters. Results are returned in the same order as the input calls, with individual success/failure status for each operation. + ///
+ ///
**Authentication**: Pass `x-client-id` header for frontend usage from allowlisted origins or `x-secret-key` for backend usage. + ///
+ /// Contract read operations completed successfully. Returns an array of results corresponding to each input call, including both successful and failed operations. + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task ReadContractAsync(Body11 body, System.Threading.CancellationToken cancellationToken) + { + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + var json_ = Newtonsoft.Json.JsonConvert.SerializeObject(body, JsonSerializerSettings); + var content_ = new System.Net.Http.StringContent(json_); + content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json"); + request_.Content = content_; + request_.Method = new System.Net.Http.HttpMethod("POST"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + var urlBuilder_ = new System.Text.StringBuilder(); + if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl); + // Operation Path: "v1/contracts/read" + urlBuilder_.Append("v1/contracts/read"); + + PrepareRequest(client_, request_, urlBuilder_); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + PrepareRequest(client_, request_, url_); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = new System.Collections.Generic.Dictionary>(); + foreach (var item_ in response_.Headers) + headers_[item_.Key] = item_.Value; + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + ProcessResponse(client_, response_); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 400) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Invalid request parameters. This occurs when the chainId is not supported, contract addresses are invalid, function signatures are malformed, or the calls array is empty.", status_, responseText_, headers_, null); + } + else + if (status_ == 401) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Authentication required. The request must include a valid `x-client-id` header for frontend usage or `x-secret-key` for backend usage.", status_, responseText_, headers_, null); + } + else + if (status_ == 500) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Internal server error. This may occur due to engine connectivity issues, RPC node unavailability, or unexpected server errors.", status_, responseText_, headers_, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// Write Contract + /// + /// + /// Executes write operations (transactions) on smart contracts. This is a convenience endpoint that simplifies contract interaction by accepting method signatures and parameters directly, without requiring manual transaction encoding. All calls are executed against the same contract address and chain, making it ideal for batch operations. + ///
+ ///
**Authentication**: This endpoint requires project authentication and wallet authentication. For backend usage, use `x-secret-key` header. For frontend usage, use `x-client-id` + `Authorization: Bearer <jwt>` headers. + ///
+ /// Contract write operations submitted successfully. Returns transaction IDs for tracking and monitoring. + /// A server side error occurred. + public virtual System.Threading.Tasks.Task WriteContractAsync(Body12 body) + { + return WriteContractAsync(body, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Write Contract + /// + /// + /// Executes write operations (transactions) on smart contracts. This is a convenience endpoint that simplifies contract interaction by accepting method signatures and parameters directly, without requiring manual transaction encoding. All calls are executed against the same contract address and chain, making it ideal for batch operations. + ///
+ ///
**Authentication**: This endpoint requires project authentication and wallet authentication. For backend usage, use `x-secret-key` header. For frontend usage, use `x-client-id` + `Authorization: Bearer <jwt>` headers. + ///
+ /// Contract write operations submitted successfully. Returns transaction IDs for tracking and monitoring. + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task WriteContractAsync(Body12 body, System.Threading.CancellationToken cancellationToken) + { + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + var json_ = Newtonsoft.Json.JsonConvert.SerializeObject(body, JsonSerializerSettings); + var content_ = new System.Net.Http.StringContent(json_); + content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json"); + request_.Content = content_; + request_.Method = new System.Net.Http.HttpMethod("POST"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + var urlBuilder_ = new System.Text.StringBuilder(); + if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl); + // Operation Path: "v1/contracts/write" + urlBuilder_.Append("v1/contracts/write"); + + PrepareRequest(client_, request_, urlBuilder_); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + PrepareRequest(client_, request_, url_); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = new System.Collections.Generic.Dictionary>(); + foreach (var item_ in response_.Headers) + headers_[item_.Key] = item_.Value; + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + ProcessResponse(client_, response_); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 400) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Invalid request parameters. This occurs when contract parameters are malformed, method signatures are invalid, insufficient balance, or unsupported contract methods.", status_, responseText_, headers_, null); + } + else + if (status_ == 401) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Authentication required. For backend usage, include `x-secret-key` header. For frontend usage, include `x-client-id` + `Authorization: Bearer ` headers.", status_, responseText_, headers_, null); + } + else + if (status_ == 402) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new ApiException("Payment required. Insufficient wallet balance to complete the purchase.", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 404) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Contract not found. The specified contract address does not exist on the given blockchain network or is not accessible.", status_, responseText_, headers_, null); + } + else + if (status_ == 500) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Internal server error. This may occur due to blockchain connectivity issues, gas estimation failures, contract execution errors, or unexpected server errors.", status_, responseText_, headers_, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// Get Transactions + /// + /// + /// Retrieves transactions for a specific smart contract address on a specific blockchain network. This endpoint provides comprehensive transaction data including block information, gas details, transaction status, and function calls. Results can be filtered, paginated, and sorted to meet specific requirements. + ///
+ ///
**Authentication**: Pass `x-client-id` header for frontend usage from allowlisted origins or `x-secret-key` for backend usage. + ///
+ /// The blockchain network identifier where the contract is deployed. + /// The smart contract address or ENS name. + /// Filter by transaction sender address + /// Filter by transaction recipient address + /// Filter by block timestamp (Unix timestamp) greater than or equal to this value + /// Filter by block timestamp (Unix timestamp) less than or equal to this value + /// Filter by block number greater than or equal to this value + /// Filter by block number less than or equal to this value + /// Filter by transaction value (in wei) greater than this value + /// Filter by function selector (4-byte method ID), e.g., '0xa9059cbb' for ERC-20 transfer + /// Current page number + /// Number of items per page + /// Sort order: 'asc' for ascending, 'desc' for descending + /// Contract transactions retrieved successfully. Returns transaction data with metadata including pagination information. Includes decoded function calls when ABI is available. + /// A server side error occurred. + public virtual System.Threading.Tasks.Task GetContractTransactionsAsync(int chainId, string address, string filterFromAddress, string filterToAddress, int? filterBlockTimestampGte, int? filterBlockTimestampLte, int? filterBlockNumberGte, int? filterBlockNumberLte, string filterValueGt, string filterFunctionSelector, double? page, double? limit, SortOrder3? sortOrder) + { + return GetContractTransactionsAsync(chainId, address, filterFromAddress, filterToAddress, filterBlockTimestampGte, filterBlockTimestampLte, filterBlockNumberGte, filterBlockNumberLte, filterValueGt, filterFunctionSelector, page, limit, sortOrder, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Get Transactions + /// + /// + /// Retrieves transactions for a specific smart contract address on a specific blockchain network. This endpoint provides comprehensive transaction data including block information, gas details, transaction status, and function calls. Results can be filtered, paginated, and sorted to meet specific requirements. + ///
+ ///
**Authentication**: Pass `x-client-id` header for frontend usage from allowlisted origins or `x-secret-key` for backend usage. + ///
+ /// The blockchain network identifier where the contract is deployed. + /// The smart contract address or ENS name. + /// Filter by transaction sender address + /// Filter by transaction recipient address + /// Filter by block timestamp (Unix timestamp) greater than or equal to this value + /// Filter by block timestamp (Unix timestamp) less than or equal to this value + /// Filter by block number greater than or equal to this value + /// Filter by block number less than or equal to this value + /// Filter by transaction value (in wei) greater than this value + /// Filter by function selector (4-byte method ID), e.g., '0xa9059cbb' for ERC-20 transfer + /// Current page number + /// Number of items per page + /// Sort order: 'asc' for ascending, 'desc' for descending + /// Contract transactions retrieved successfully. Returns transaction data with metadata including pagination information. Includes decoded function calls when ABI is available. + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task GetContractTransactionsAsync(int chainId, string address, string filterFromAddress, string filterToAddress, int? filterBlockTimestampGte, int? filterBlockTimestampLte, int? filterBlockNumberGte, int? filterBlockNumberLte, string filterValueGt, string filterFunctionSelector, double? page, double? limit, SortOrder3? sortOrder, System.Threading.CancellationToken cancellationToken) + { + if (chainId == null) + throw new System.ArgumentNullException("chainId"); + + if (address == null) + throw new System.ArgumentNullException("address"); + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + request_.Method = new System.Net.Http.HttpMethod("GET"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + var urlBuilder_ = new System.Text.StringBuilder(); + if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl); + // Operation Path: "v1/contracts/{chainId}/{address}/transactions" + urlBuilder_.Append("v1/contracts/"); + urlBuilder_.Append(System.Uri.EscapeDataString(ConvertToString(chainId, System.Globalization.CultureInfo.InvariantCulture))); + urlBuilder_.Append('/'); + urlBuilder_.Append(System.Uri.EscapeDataString(ConvertToString(address, System.Globalization.CultureInfo.InvariantCulture))); + urlBuilder_.Append("/transactions"); + urlBuilder_.Append('?'); + if (filterFromAddress != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("filterFromAddress")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(filterFromAddress, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + if (filterToAddress != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("filterToAddress")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(filterToAddress, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + if (filterBlockTimestampGte != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("filterBlockTimestampGte")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(filterBlockTimestampGte, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + if (filterBlockTimestampLte != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("filterBlockTimestampLte")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(filterBlockTimestampLte, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + if (filterBlockNumberGte != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("filterBlockNumberGte")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(filterBlockNumberGte, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + if (filterBlockNumberLte != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("filterBlockNumberLte")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(filterBlockNumberLte, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + if (filterValueGt != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("filterValueGt")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(filterValueGt, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + if (filterFunctionSelector != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("filterFunctionSelector")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(filterFunctionSelector, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + if (page != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("page")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(page, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + if (limit != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("limit")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(limit, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + if (sortOrder != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("sortOrder")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(sortOrder, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + urlBuilder_.Length--; + + PrepareRequest(client_, request_, urlBuilder_); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + PrepareRequest(client_, request_, url_); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = new System.Collections.Generic.Dictionary>(); + foreach (var item_ in response_.Headers) + headers_[item_.Key] = item_.Value; + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + ProcessResponse(client_, response_); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 400) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Invalid request parameters. This occurs when the contract address or chainId format is invalid, or pagination parameters are out of range.", status_, responseText_, headers_, null); + } + else + if (status_ == 401) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Authentication required. The request must include a valid `x-client-id` header for frontend usage or `x-secret-key` for backend usage.", status_, responseText_, headers_, null); + } + else + if (status_ == 404) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Contract not found or no transactions available for the specified contract address on the given blockchain network.", status_, responseText_, headers_, null); + } + else + if (status_ == 500) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Internal server error. This may occur due to network connectivity issues, external service unavailability, or unexpected server errors.", status_, responseText_, headers_, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// Get Events + /// + /// + /// Retrieves events emitted by a specific smart contract address on a specific blockchain network. This endpoint provides comprehensive event data including block information, transaction details, event topics, and optional ABI decoding. Results can be filtered, paginated, and sorted to meet specific requirements. + ///
+ ///
**Authentication**: Pass `x-client-id` header for frontend usage from allowlisted origins or `x-secret-key` for backend usage. + ///
+ /// The blockchain network identifier where the contract is deployed. + /// The smart contract address or ENS name. + /// Filter by event signature hash, e.g., '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef' for Transfer event + /// Filter by event topic 0 (event signature hash) + /// Filter by event topic 1 + /// Filter by event topic 2 + /// Filter by event topic 3 + /// Filter by block timestamp (Unix timestamp) greater than or equal to this value + /// Filter by block timestamp (Unix timestamp) less than or equal to this value + /// Filter by block number greater than or equal to this value + /// Filter by block number less than or equal to this value + /// Current page number + /// Number of items per page + /// Sort order: 'asc' for ascending, 'desc' for descending + /// Contract events retrieved successfully. Returns event data with metadata including pagination information. Includes decoded event parameters when ABI is available. + /// A server side error occurred. + public virtual System.Threading.Tasks.Task GetContractEventsAsync(int chainId, string address, string signature, string filterTopic0, string filterTopic1, string filterTopic2, string filterTopic3, int? filterBlockTimestampGte, int? filterBlockTimestampLte, int? filterBlockNumberGte, int? filterBlockNumberLte, double? page, double? limit, SortOrder4? sortOrder) + { + return GetContractEventsAsync(chainId, address, signature, filterTopic0, filterTopic1, filterTopic2, filterTopic3, filterBlockTimestampGte, filterBlockTimestampLte, filterBlockNumberGte, filterBlockNumberLte, page, limit, sortOrder, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Get Events + /// + /// + /// Retrieves events emitted by a specific smart contract address on a specific blockchain network. This endpoint provides comprehensive event data including block information, transaction details, event topics, and optional ABI decoding. Results can be filtered, paginated, and sorted to meet specific requirements. + ///
+ ///
**Authentication**: Pass `x-client-id` header for frontend usage from allowlisted origins or `x-secret-key` for backend usage. + ///
+ /// The blockchain network identifier where the contract is deployed. + /// The smart contract address or ENS name. + /// Filter by event signature hash, e.g., '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef' for Transfer event + /// Filter by event topic 0 (event signature hash) + /// Filter by event topic 1 + /// Filter by event topic 2 + /// Filter by event topic 3 + /// Filter by block timestamp (Unix timestamp) greater than or equal to this value + /// Filter by block timestamp (Unix timestamp) less than or equal to this value + /// Filter by block number greater than or equal to this value + /// Filter by block number less than or equal to this value + /// Current page number + /// Number of items per page + /// Sort order: 'asc' for ascending, 'desc' for descending + /// Contract events retrieved successfully. Returns event data with metadata including pagination information. Includes decoded event parameters when ABI is available. + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task GetContractEventsAsync(int chainId, string address, string signature, string filterTopic0, string filterTopic1, string filterTopic2, string filterTopic3, int? filterBlockTimestampGte, int? filterBlockTimestampLte, int? filterBlockNumberGte, int? filterBlockNumberLte, double? page, double? limit, SortOrder4? sortOrder, System.Threading.CancellationToken cancellationToken) + { + if (chainId == null) + throw new System.ArgumentNullException("chainId"); + + if (address == null) + throw new System.ArgumentNullException("address"); + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + request_.Method = new System.Net.Http.HttpMethod("GET"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + var urlBuilder_ = new System.Text.StringBuilder(); + if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl); + // Operation Path: "v1/contracts/{chainId}/{address}/events" + urlBuilder_.Append("v1/contracts/"); + urlBuilder_.Append(System.Uri.EscapeDataString(ConvertToString(chainId, System.Globalization.CultureInfo.InvariantCulture))); + urlBuilder_.Append('/'); + urlBuilder_.Append(System.Uri.EscapeDataString(ConvertToString(address, System.Globalization.CultureInfo.InvariantCulture))); + urlBuilder_.Append("/events"); + urlBuilder_.Append('?'); + if (signature != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("signature")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(signature, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + if (filterTopic0 != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("filterTopic0")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(filterTopic0, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + if (filterTopic1 != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("filterTopic1")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(filterTopic1, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + if (filterTopic2 != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("filterTopic2")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(filterTopic2, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + if (filterTopic3 != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("filterTopic3")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(filterTopic3, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + if (filterBlockTimestampGte != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("filterBlockTimestampGte")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(filterBlockTimestampGte, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + if (filterBlockTimestampLte != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("filterBlockTimestampLte")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(filterBlockTimestampLte, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + if (filterBlockNumberGte != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("filterBlockNumberGte")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(filterBlockNumberGte, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + if (filterBlockNumberLte != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("filterBlockNumberLte")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(filterBlockNumberLte, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + if (page != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("page")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(page, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + if (limit != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("limit")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(limit, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + if (sortOrder != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("sortOrder")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(sortOrder, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + urlBuilder_.Length--; + + PrepareRequest(client_, request_, urlBuilder_); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + PrepareRequest(client_, request_, url_); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = new System.Collections.Generic.Dictionary>(); + foreach (var item_ in response_.Headers) + headers_[item_.Key] = item_.Value; + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + ProcessResponse(client_, response_); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 400) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Invalid request parameters. This occurs when the contract address or chainId format is invalid, or pagination parameters are out of range.", status_, responseText_, headers_, null); + } + else + if (status_ == 401) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Authentication required. The request must include a valid `x-client-id` header for frontend usage or `x-secret-key` for backend usage.", status_, responseText_, headers_, null); + } + else + if (status_ == 404) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Contract not found or no events available for the specified contract address on the given blockchain network.", status_, responseText_, headers_, null); + } + else + if (status_ == 500) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Internal server error. This may occur due to network connectivity issues, external service unavailability, or unexpected server errors.", status_, responseText_, headers_, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// Get Metadata + /// + /// + /// Retrieves detailed metadata for a specific smart contract from the thirdweb contract metadata service. This includes compilation information, ABI, documentation, and other contract-related metadata. Note: Source code is excluded from the response to keep it lightweight and suitable for programmatic access. + ///
+ ///
**Authentication**: This endpoint requires backend authentication using the `x-secret-key` header. The secret key should never be exposed publicly. + ///
+ ///
**Metadata Source**: The metadata is fetched from the thirdweb contract metadata service and includes detailed Solidity compilation information, contract ABI, and developer documentation. + ///
+ /// The blockchain network identifier where the contract is deployed. + /// The smart contract address or ENS name. + /// Successfully retrieved contract metadata + /// A server side error occurred. + public virtual System.Threading.Tasks.Task GetContractMetadataAsync(int chainId, string address) + { + return GetContractMetadataAsync(chainId, address, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Get Metadata + /// + /// + /// Retrieves detailed metadata for a specific smart contract from the thirdweb contract metadata service. This includes compilation information, ABI, documentation, and other contract-related metadata. Note: Source code is excluded from the response to keep it lightweight and suitable for programmatic access. + ///
+ ///
**Authentication**: This endpoint requires backend authentication using the `x-secret-key` header. The secret key should never be exposed publicly. + ///
+ ///
**Metadata Source**: The metadata is fetched from the thirdweb contract metadata service and includes detailed Solidity compilation information, contract ABI, and developer documentation. + ///
+ /// The blockchain network identifier where the contract is deployed. + /// The smart contract address or ENS name. + /// Successfully retrieved contract metadata + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task GetContractMetadataAsync(int chainId, string address, System.Threading.CancellationToken cancellationToken) + { + if (chainId == null) + throw new System.ArgumentNullException("chainId"); + + if (address == null) + throw new System.ArgumentNullException("address"); + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + request_.Method = new System.Net.Http.HttpMethod("GET"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + var urlBuilder_ = new System.Text.StringBuilder(); + if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl); + // Operation Path: "v1/contracts/{chainId}/{address}/metadata" + urlBuilder_.Append("v1/contracts/"); + urlBuilder_.Append(System.Uri.EscapeDataString(ConvertToString(chainId, System.Globalization.CultureInfo.InvariantCulture))); + urlBuilder_.Append('/'); + urlBuilder_.Append(System.Uri.EscapeDataString(ConvertToString(address, System.Globalization.CultureInfo.InvariantCulture))); + urlBuilder_.Append("/metadata"); + + PrepareRequest(client_, request_, urlBuilder_); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + PrepareRequest(client_, request_, url_); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = new System.Collections.Generic.Dictionary>(); + foreach (var item_ in response_.Headers) + headers_[item_.Key] = item_.Value; + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + ProcessResponse(client_, response_); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 400) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Invalid request parameters", status_, responseText_, headers_, null); + } + else + if (status_ == 401) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Authentication required. The request must include a valid `x-secret-key` header for backend authentication.", status_, responseText_, headers_, null); + } + else + if (status_ == 404) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Contract metadata not found", status_, responseText_, headers_, null); + } + else + if (status_ == 429) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Rate limit exceeded", status_, responseText_, headers_, null); + } + else + if (status_ == 500) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Internal server error", status_, responseText_, headers_, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// Get Signatures + /// + /// + /// Retrieves human-readable ABI signatures for a specific smart contract. This endpoint fetches the contract metadata from the thirdweb service, extracts the ABI, and converts it into an array of human-readable function and event signatures that can be used directly with contract interaction methods. + ///
+ ///
**Authentication**: This endpoint requires backend authentication using the `x-secret-key` header. The secret key should never be exposed publicly. + ///
+ ///
**Usage**: The returned signatures can be used directly in contract read/write operations or event filtering. Each signature follows the standard Solidity format and includes function parameters, return types, state mutability, and event indexing information. + ///
+ /// The blockchain network identifier where the contract is deployed. + /// The smart contract address or ENS name. + /// Successfully retrieved contract signatures + /// A server side error occurred. + public virtual System.Threading.Tasks.Task GetContractSignaturesAsync(int chainId, string address) + { + return GetContractSignaturesAsync(chainId, address, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Get Signatures + /// + /// + /// Retrieves human-readable ABI signatures for a specific smart contract. This endpoint fetches the contract metadata from the thirdweb service, extracts the ABI, and converts it into an array of human-readable function and event signatures that can be used directly with contract interaction methods. + ///
+ ///
**Authentication**: This endpoint requires backend authentication using the `x-secret-key` header. The secret key should never be exposed publicly. + ///
+ ///
**Usage**: The returned signatures can be used directly in contract read/write operations or event filtering. Each signature follows the standard Solidity format and includes function parameters, return types, state mutability, and event indexing information. + ///
+ /// The blockchain network identifier where the contract is deployed. + /// The smart contract address or ENS name. + /// Successfully retrieved contract signatures + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task GetContractSignaturesAsync(int chainId, string address, System.Threading.CancellationToken cancellationToken) + { + if (chainId == null) + throw new System.ArgumentNullException("chainId"); + + if (address == null) + throw new System.ArgumentNullException("address"); + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + request_.Method = new System.Net.Http.HttpMethod("GET"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + var urlBuilder_ = new System.Text.StringBuilder(); + if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl); + // Operation Path: "v1/contracts/{chainId}/{address}/signatures" + urlBuilder_.Append("v1/contracts/"); + urlBuilder_.Append(System.Uri.EscapeDataString(ConvertToString(chainId, System.Globalization.CultureInfo.InvariantCulture))); + urlBuilder_.Append('/'); + urlBuilder_.Append(System.Uri.EscapeDataString(ConvertToString(address, System.Globalization.CultureInfo.InvariantCulture))); + urlBuilder_.Append("/signatures"); + + PrepareRequest(client_, request_, urlBuilder_); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + PrepareRequest(client_, request_, url_); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = new System.Collections.Generic.Dictionary>(); + foreach (var item_ in response_.Headers) + headers_[item_.Key] = item_.Value; + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + ProcessResponse(client_, response_); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 400) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Invalid request parameters", status_, responseText_, headers_, null); + } + else + if (status_ == 401) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Authentication required. The request must include a valid `x-secret-key` header for backend authentication.", status_, responseText_, headers_, null); + } + else + if (status_ == 404) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Contract metadata not found or ABI is not available", status_, responseText_, headers_, null); + } + else + if (status_ == 429) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Rate limit exceeded", status_, responseText_, headers_, null); + } + else + if (status_ == 500) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Internal server error", status_, responseText_, headers_, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// Get Transaction + /// + /// + /// Retrieves detailed information about a specific transaction using its unique identifier. Returns comprehensive transaction data including execution status, blockchain details, and any associated metadata. + ///
+ ///
**Authentication**: Pass `x-client-id` header for frontend usage from allowlisted origins or `x-secret-key` for backend usage. + ///
+ /// Unique identifier of the transaction to retrieve. + /// Transaction details retrieved successfully. Returns comprehensive transaction information including status, blockchain details, and execution metadata. + /// A server side error occurred. + public virtual System.Threading.Tasks.Task GetTransactionByIdAsync(string transactionId) + { + return GetTransactionByIdAsync(transactionId, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Get Transaction + /// + /// + /// Retrieves detailed information about a specific transaction using its unique identifier. Returns comprehensive transaction data including execution status, blockchain details, and any associated metadata. + ///
+ ///
**Authentication**: Pass `x-client-id` header for frontend usage from allowlisted origins or `x-secret-key` for backend usage. + ///
+ /// Unique identifier of the transaction to retrieve. + /// Transaction details retrieved successfully. Returns comprehensive transaction information including status, blockchain details, and execution metadata. + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task GetTransactionByIdAsync(string transactionId, System.Threading.CancellationToken cancellationToken) + { + if (transactionId == null) + throw new System.ArgumentNullException("transactionId"); + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + request_.Method = new System.Net.Http.HttpMethod("GET"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + var urlBuilder_ = new System.Text.StringBuilder(); + if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl); + // Operation Path: "v1/transactions/{transactionId}" + urlBuilder_.Append("v1/transactions/"); + urlBuilder_.Append(System.Uri.EscapeDataString(ConvertToString(transactionId, System.Globalization.CultureInfo.InvariantCulture))); + + PrepareRequest(client_, request_, urlBuilder_); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + PrepareRequest(client_, request_, url_); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = new System.Collections.Generic.Dictionary>(); + foreach (var item_ in response_.Headers) + headers_[item_.Key] = item_.Value; + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + ProcessResponse(client_, response_); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 400) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Invalid request parameters. This occurs when the transaction ID format is invalid or malformed.", status_, responseText_, headers_, null); + } + else + if (status_ == 401) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Authentication required. The request must include a valid `x-client-id` header for frontend usage or `x-secret-key` for backend usage.", status_, responseText_, headers_, null); + } + else + if (status_ == 404) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Transaction not found. The specified transaction ID does not exist or is not associated with the authenticated client.", status_, responseText_, headers_, null); + } + else + if (status_ == 500) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Internal server error. This may occur due to engine connectivity issues, database unavailability, or unexpected server errors.", status_, responseText_, headers_, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// List Transactions + /// + /// + /// Retrieves a paginated list of transactions associated with the authenticated client. Results are sorted by creation date in descending order (most recent first). Supports filtering by wallet address and pagination controls. + ///
+ ///
**Authentication**: Pass `x-client-id` header for frontend usage from allowlisted origins or `x-secret-key` for backend usage. + ///
+ /// Filter transactions by sender wallet address or ENS name. + /// Number of transactions to return per page (1-100). + /// Page number for pagination, starting from 1. + /// Transactions retrieved successfully. Returns a paginated list of transactions with metadata including creation and confirmation timestamps. + /// A server side error occurred. + public virtual System.Threading.Tasks.Task ListTransactionsAsync(string from, int? limit, int? page) + { + return ListTransactionsAsync(from, limit, page, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// List Transactions + /// + /// + /// Retrieves a paginated list of transactions associated with the authenticated client. Results are sorted by creation date in descending order (most recent first). Supports filtering by wallet address and pagination controls. + ///
+ ///
**Authentication**: Pass `x-client-id` header for frontend usage from allowlisted origins or `x-secret-key` for backend usage. + ///
+ /// Filter transactions by sender wallet address or ENS name. + /// Number of transactions to return per page (1-100). + /// Page number for pagination, starting from 1. + /// Transactions retrieved successfully. Returns a paginated list of transactions with metadata including creation and confirmation timestamps. + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task ListTransactionsAsync(string from, int? limit, int? page, System.Threading.CancellationToken cancellationToken) + { + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + request_.Method = new System.Net.Http.HttpMethod("GET"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + var urlBuilder_ = new System.Text.StringBuilder(); + if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl); + // Operation Path: "v1/transactions" + urlBuilder_.Append("v1/transactions"); + urlBuilder_.Append('?'); + if (from != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("from")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(from, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + if (limit != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("limit")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(limit, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + if (page != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("page")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(page, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + urlBuilder_.Length--; + + PrepareRequest(client_, request_, urlBuilder_); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + PrepareRequest(client_, request_, url_); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = new System.Collections.Generic.Dictionary>(); + foreach (var item_ in response_.Headers) + headers_[item_.Key] = item_.Value; + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + ProcessResponse(client_, response_); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 400) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Invalid request parameters. This occurs when pagination parameters are out of range or wallet address format is invalid.", status_, responseText_, headers_, null); + } + else + if (status_ == 401) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Authentication required. The request must include a valid `x-client-id` header for frontend usage or `x-secret-key` for backend usage.", status_, responseText_, headers_, null); + } + else + if (status_ == 500) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Internal server error. This may occur due to engine connectivity issues, database unavailability, or unexpected server errors.", status_, responseText_, headers_, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// Send Transactions + /// + /// + /// Submits pre-encoded blockchain transactions with custom data payloads. This endpoint is for low-level transaction submission where you have already encoded the transaction data. For smart contract method calls, use /v1/contracts/write. For native token transfers, use /v1/wallets/send. + ///
+ ///
**Authentication**: This endpoint requires project authentication and wallet authentication. For backend usage, use `x-secret-key` header. For frontend usage, use `x-client-id` + `Authorization: Bearer <jwt>` headers. + ///
+ /// Encoded transactions submitted successfully. Returns the transaction IDs for tracking and monitoring. + /// A server side error occurred. + public virtual System.Threading.Tasks.Task SendTransactionsAsync(Body13 body) + { + return SendTransactionsAsync(body, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Send Transactions + /// + /// + /// Submits pre-encoded blockchain transactions with custom data payloads. This endpoint is for low-level transaction submission where you have already encoded the transaction data. For smart contract method calls, use /v1/contracts/write. For native token transfers, use /v1/wallets/send. + ///
+ ///
**Authentication**: This endpoint requires project authentication and wallet authentication. For backend usage, use `x-secret-key` header. For frontend usage, use `x-client-id` + `Authorization: Bearer <jwt>` headers. + ///
+ /// Encoded transactions submitted successfully. Returns the transaction IDs for tracking and monitoring. + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task SendTransactionsAsync(Body13 body, System.Threading.CancellationToken cancellationToken) + { + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + var json_ = Newtonsoft.Json.JsonConvert.SerializeObject(body, JsonSerializerSettings); + var content_ = new System.Net.Http.StringContent(json_); + content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json"); + request_.Content = content_; + request_.Method = new System.Net.Http.HttpMethod("POST"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + var urlBuilder_ = new System.Text.StringBuilder(); + if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl); + // Operation Path: "v1/transactions" + urlBuilder_.Append("v1/transactions"); + + PrepareRequest(client_, request_, urlBuilder_); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + PrepareRequest(client_, request_, url_); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = new System.Collections.Generic.Dictionary>(); + foreach (var item_ in response_.Headers) + headers_[item_.Key] = item_.Value; + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + ProcessResponse(client_, response_); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 400) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Invalid request parameters. This occurs when transaction data is malformed, insufficient balance, or invalid encoded data.", status_, responseText_, headers_, null); + } + else + if (status_ == 401) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Authentication required. For backend usage, include `x-secret-key` header. For frontend usage, include `x-client-id` + `Authorization: Bearer ` headers.", status_, responseText_, headers_, null); + } + else + if (status_ == 402) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new ApiException("Payment required. Insufficient wallet balance to complete the purchase.", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 500) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Internal server error. This may occur due to blockchain connectivity issues, gas estimation failures, or unexpected server errors.", status_, responseText_, headers_, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// Create Payment + /// + /// + /// Create a payment to be executed. Users can complete the payment via hosted UI (link is returned), a transaction execution referencing the product ID, or embedded widgets with the product ID. + ///
+ ///
**Authentication**: This endpoint requires project authentication. + ///
+ /// Payment created successfully. Returns the ID and link to complete the payment. + /// A server side error occurred. + public virtual System.Threading.Tasks.Task CreatePaymentAsync(Body14 body) + { + return CreatePaymentAsync(body, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Create Payment + /// + /// + /// Create a payment to be executed. Users can complete the payment via hosted UI (link is returned), a transaction execution referencing the product ID, or embedded widgets with the product ID. + ///
+ ///
**Authentication**: This endpoint requires project authentication. + ///
+ /// Payment created successfully. Returns the ID and link to complete the payment. + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task CreatePaymentAsync(Body14 body, System.Threading.CancellationToken cancellationToken) + { + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + var json_ = Newtonsoft.Json.JsonConvert.SerializeObject(body, JsonSerializerSettings); + var content_ = new System.Net.Http.StringContent(json_); + content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json"); + request_.Content = content_; + request_.Method = new System.Net.Http.HttpMethod("POST"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + var urlBuilder_ = new System.Text.StringBuilder(); + if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl); + // Operation Path: "v1/payments" + urlBuilder_.Append("v1/payments"); + + PrepareRequest(client_, request_, urlBuilder_); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + PrepareRequest(client_, request_, url_); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = new System.Collections.Generic.Dictionary>(); + foreach (var item_ in response_.Headers) + headers_[item_.Key] = item_.Value; + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + ProcessResponse(client_, response_); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 400) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Invalid request parameters.", status_, responseText_, headers_, null); + } + else + if (status_ == 401) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Authentication required. For backend usage, include `x-secret-key` header. For frontend usage, include `x-client-id` + `Authorization: Bearer ` headers.", status_, responseText_, headers_, null); + } + else + if (status_ == 500) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Internal server error. This may occur due to network connectivity issues, wallet creation failures, or transaction execution failures.", status_, responseText_, headers_, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// Complete Payment + /// + /// + /// Completes a payment using its default token and amount. If the user does not have sufficient funds in the product's default payment token a 402 status will be returned containing a link and raw quote for purchase fulfillment. + ///
+ ///
**Authentication**: This endpoint requires project authentication. + ///
+ /// Product purchased successfully. Returns the transaction used for the purchase. + /// A server side error occurred. + public virtual System.Threading.Tasks.Task PaymentsPurchaseAsync(string id, Body15 body) + { + return PaymentsPurchaseAsync(id, body, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Complete Payment + /// + /// + /// Completes a payment using its default token and amount. If the user does not have sufficient funds in the product's default payment token a 402 status will be returned containing a link and raw quote for purchase fulfillment. + ///
+ ///
**Authentication**: This endpoint requires project authentication. + ///
+ /// Product purchased successfully. Returns the transaction used for the purchase. + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task PaymentsPurchaseAsync(string id, Body15 body, System.Threading.CancellationToken cancellationToken) + { + if (id == null) + throw new System.ArgumentNullException("id"); + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + var json_ = Newtonsoft.Json.JsonConvert.SerializeObject(body, JsonSerializerSettings); + var content_ = new System.Net.Http.StringContent(json_); + content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json"); + request_.Content = content_; + request_.Method = new System.Net.Http.HttpMethod("POST"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + var urlBuilder_ = new System.Text.StringBuilder(); + if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl); + // Operation Path: "v1/payments/{id}" + urlBuilder_.Append("v1/payments/"); + urlBuilder_.Append(System.Uri.EscapeDataString(ConvertToString(id, System.Globalization.CultureInfo.InvariantCulture))); + + PrepareRequest(client_, request_, urlBuilder_); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + PrepareRequest(client_, request_, url_); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = new System.Collections.Generic.Dictionary>(); + foreach (var item_ in response_.Headers) + headers_[item_.Key] = item_.Value; + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + ProcessResponse(client_, response_); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 400) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Invalid request parameters.", status_, responseText_, headers_, null); + } + else + if (status_ == 401) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Authentication required. For backend usage, include `x-secret-key` header. For frontend usage, include `x-client-id` + `Authorization: Bearer ` headers.", status_, responseText_, headers_, null); + } + else + if (status_ == 402) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new ApiException("Payment required. Insufficient wallet balance to complete the purchase.", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 500) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Internal server error. This may occur due to network connectivity issues, wallet creation failures, or transaction execution failures.", status_, responseText_, headers_, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// Get Payment History + /// + /// + /// Get payment history for a specific payment link + /// + /// Payment history retrieved successfully + /// A server side error occurred. + public virtual System.Threading.Tasks.Task GetPaymentHistoryAsync(string id) + { + return GetPaymentHistoryAsync(id, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Get Payment History + /// + /// + /// Get payment history for a specific payment link + /// + /// Payment history retrieved successfully + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task GetPaymentHistoryAsync(string id, System.Threading.CancellationToken cancellationToken) + { + if (id == null) + throw new System.ArgumentNullException("id"); + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + request_.Method = new System.Net.Http.HttpMethod("GET"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + var urlBuilder_ = new System.Text.StringBuilder(); + if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl); + // Operation Path: "v1/payments/{id}" + urlBuilder_.Append("v1/payments/"); + urlBuilder_.Append(System.Uri.EscapeDataString(ConvertToString(id, System.Globalization.CultureInfo.InvariantCulture))); + + PrepareRequest(client_, request_, urlBuilder_); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + PrepareRequest(client_, request_, url_); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = new System.Collections.Generic.Dictionary>(); + foreach (var item_ in response_.Headers) + headers_[item_.Key] = item_.Value; + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + ProcessResponse(client_, response_); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 400) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new ApiException("Bad request", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 404) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new ApiException("Payment link not found", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// x402 - Verify payment + /// + /// + /// Verify an x402 payment payload against the provided payment requirements. Compatible with any standard x402 middleware. + /// + /// Verification successful + /// A server side error occurred. + public virtual System.Threading.Tasks.Task VerifyX402PaymentAsync(Body16 body) + { + return VerifyX402PaymentAsync(body, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// x402 - Verify payment + /// + /// + /// Verify an x402 payment payload against the provided payment requirements. Compatible with any standard x402 middleware. + /// + /// Verification successful + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task VerifyX402PaymentAsync(Body16 body, System.Threading.CancellationToken cancellationToken) + { + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + var json_ = Newtonsoft.Json.JsonConvert.SerializeObject(body, JsonSerializerSettings); + var content_ = new System.Net.Http.StringContent(json_); + content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json"); + request_.Content = content_; + request_.Method = new System.Net.Http.HttpMethod("POST"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + var urlBuilder_ = new System.Text.StringBuilder(); + if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl); + // Operation Path: "v1/payments/x402/verify" + urlBuilder_.Append("v1/payments/x402/verify"); + + PrepareRequest(client_, request_, urlBuilder_); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + PrepareRequest(client_, request_, url_); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = new System.Collections.Generic.Dictionary>(); + foreach (var item_ in response_.Headers) + headers_[item_.Key] = item_.Value; + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + ProcessResponse(client_, response_); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 400) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Invalid request parameters", status_, responseText_, headers_, null); + } + else + if (status_ == 401) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Authentication required. For backend usage, include `x-secret-key` header.", status_, responseText_, headers_, null); + } + else + if (status_ == 500) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Internal server error", status_, responseText_, headers_, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// x402 - Settle payment + /// + /// + /// Settle an x402 payment. Compatible with any standard x402 middleware. + /// + /// Settlement successful + /// A server side error occurred. + public virtual System.Threading.Tasks.Task SettleX402PaymentAsync(Body17 body) + { + return SettleX402PaymentAsync(body, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// x402 - Settle payment + /// + /// + /// Settle an x402 payment. Compatible with any standard x402 middleware. + /// + /// Settlement successful + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task SettleX402PaymentAsync(Body17 body, System.Threading.CancellationToken cancellationToken) + { + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + var json_ = Newtonsoft.Json.JsonConvert.SerializeObject(body, JsonSerializerSettings); + var content_ = new System.Net.Http.StringContent(json_); + content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json"); + request_.Content = content_; + request_.Method = new System.Net.Http.HttpMethod("POST"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + var urlBuilder_ = new System.Text.StringBuilder(); + if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl); + // Operation Path: "v1/payments/x402/settle" + urlBuilder_.Append("v1/payments/x402/settle"); + + PrepareRequest(client_, request_, urlBuilder_); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + PrepareRequest(client_, request_, url_); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = new System.Collections.Generic.Dictionary>(); + foreach (var item_ in response_.Headers) + headers_[item_.Key] = item_.Value; + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + ProcessResponse(client_, response_); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 400) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Invalid request parameters", status_, responseText_, headers_, null); + } + else + if (status_ == 401) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Authentication required. For backend usage, include `x-secret-key` header.", status_, responseText_, headers_, null); + } + else + if (status_ == 500) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Internal server error", status_, responseText_, headers_, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// x402 - Supported payment methods + /// + /// + /// List supported x402 payment methods, optionally filtered by token address and chainId. Compatible with any standard x402 middleware. + /// + /// A valid Ethereum address (0x-prefixed hex string) or ENS name (e.g., vitalik.eth). + /// Chain ID in CAIP-2 format (e.g., 'eip155:1' for Ethereum, 'solana:mainnet' for Solana). Also accepts legacy numeric IDs for EVM chains. + /// Supported payment kinds + /// A server side error occurred. + public virtual System.Threading.Tasks.Task SupportedX402PaymentsAsync(string tokenAddress, ChainId chainId) + { + return SupportedX402PaymentsAsync(tokenAddress, chainId, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// x402 - Supported payment methods + /// + /// + /// List supported x402 payment methods, optionally filtered by token address and chainId. Compatible with any standard x402 middleware. + /// + /// A valid Ethereum address (0x-prefixed hex string) or ENS name (e.g., vitalik.eth). + /// Chain ID in CAIP-2 format (e.g., 'eip155:1' for Ethereum, 'solana:mainnet' for Solana). Also accepts legacy numeric IDs for EVM chains. + /// Supported payment kinds + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task SupportedX402PaymentsAsync(string tokenAddress, ChainId chainId, System.Threading.CancellationToken cancellationToken) + { + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + request_.Method = new System.Net.Http.HttpMethod("GET"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + var urlBuilder_ = new System.Text.StringBuilder(); + if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl); + // Operation Path: "v1/payments/x402/supported" + urlBuilder_.Append("v1/payments/x402/supported"); + urlBuilder_.Append('?'); + if (tokenAddress != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("tokenAddress")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(tokenAddress, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + if (chainId != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("chainId")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(chainId, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + urlBuilder_.Length--; + + PrepareRequest(client_, request_, urlBuilder_); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + PrepareRequest(client_, request_, url_); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = new System.Collections.Generic.Dictionary>(); + foreach (var item_ in response_.Headers) + headers_[item_.Key] = item_.Value; + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + ProcessResponse(client_, response_); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 401) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Authentication required. For backend usage, include `x-secret-key` header.", status_, responseText_, headers_, null); + } + else + if (status_ == 500) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Internal server error", status_, responseText_, headers_, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// x402 - Fetch with payment + /// + /// + /// Fetch any given url. If the url returns HTTP 402 payment required, this endpoint handles payment with the authenticated wallet. + ///
+ ///
Optionally pass a 'from' query parameter with the authenticated wallet address (server or user wallet) to complete the payment. + ///
+ ///
If no 'from' parameter is passed, the default project wallet address will be used. + ///
+ ///
- Works with any x402 compatible endpoint. + ///
- Automatically selects a compatible payment method. + ///
- Signs the appropriate payment payload. + ///
- Sends the payment to the url. + ///
- Returns the final result from the url called. + ///
+ ///
Request body and headers are always passed through to the url called. + ///
+ ///
**Authentication**: This endpoint requires wallet authentication for the payment. For frontend usage, include `x-client-id` and `Authorization: Bearer <jwt>` headers. For backend usage, include `x-secret-key` header. + ///
+ /// A valid blockchain address. Accepts Ethereum (0x...) and Solana (base58) addresses, as well as ENS names for Ethereum. + /// A valid blockchain address. Accepts Ethereum (0x...) and Solana (base58) addresses, as well as ENS names for Ethereum. + /// Chain ID to use for the payment. Supports CAIP-2 strings (e.g., 'eip155:1', 'solana:mainnet') or legacy numeric EVM IDs. + /// Returns the final result from the API call + /// A server side error occurred. + public virtual System.Threading.Tasks.Task FetchWithPaymentAsync(string from, System.Uri url, Method method, string maxValue, string asset, ChainId2 chainId, object body) + { + return FetchWithPaymentAsync(from, url, method, maxValue, asset, chainId, body, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// x402 - Fetch with payment + /// + /// + /// Fetch any given url. If the url returns HTTP 402 payment required, this endpoint handles payment with the authenticated wallet. + ///
+ ///
Optionally pass a 'from' query parameter with the authenticated wallet address (server or user wallet) to complete the payment. + ///
+ ///
If no 'from' parameter is passed, the default project wallet address will be used. + ///
+ ///
- Works with any x402 compatible endpoint. + ///
- Automatically selects a compatible payment method. + ///
- Signs the appropriate payment payload. + ///
- Sends the payment to the url. + ///
- Returns the final result from the url called. + ///
+ ///
Request body and headers are always passed through to the url called. + ///
+ ///
**Authentication**: This endpoint requires wallet authentication for the payment. For frontend usage, include `x-client-id` and `Authorization: Bearer <jwt>` headers. For backend usage, include `x-secret-key` header. + ///
+ /// A valid blockchain address. Accepts Ethereum (0x...) and Solana (base58) addresses, as well as ENS names for Ethereum. + /// A valid blockchain address. Accepts Ethereum (0x...) and Solana (base58) addresses, as well as ENS names for Ethereum. + /// Chain ID to use for the payment. Supports CAIP-2 strings (e.g., 'eip155:1', 'solana:mainnet') or legacy numeric EVM IDs. + /// Returns the final result from the API call + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task FetchWithPaymentAsync(string from, System.Uri url, Method method, string maxValue, string asset, ChainId2 chainId, object body, System.Threading.CancellationToken cancellationToken) + { + if (url == null) + throw new System.ArgumentNullException("url"); + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + var json_ = Newtonsoft.Json.JsonConvert.SerializeObject(body, JsonSerializerSettings); + var content_ = new System.Net.Http.StringContent(json_); + content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("*/*"); + request_.Content = content_; + request_.Method = new System.Net.Http.HttpMethod("POST"); + + var urlBuilder_ = new System.Text.StringBuilder(); + if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl); + // Operation Path: "v1/payments/x402/fetch" + urlBuilder_.Append("v1/payments/x402/fetch"); + urlBuilder_.Append('?'); + if (from != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("from")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(from, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + urlBuilder_.Append(System.Uri.EscapeDataString("url")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(url, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + if (method != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("method")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(method, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + if (maxValue != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("maxValue")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(maxValue, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + if (asset != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("asset")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(asset, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + if (chainId != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("chainId")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(chainId, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + urlBuilder_.Length--; + + PrepareRequest(client_, request_, urlBuilder_); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + PrepareRequest(client_, request_, url_); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = new System.Collections.Generic.Dictionary>(); + foreach (var item_ in response_.Headers) + headers_[item_.Key] = item_.Value; + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + ProcessResponse(client_, response_); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + return; + } + else + if (status_ == 400) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Invalid request parameters", status_, responseText_, headers_, null); + } + else + if (status_ == 401) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Authentication required. For frontend usage, include `x-client-id` and `Authorization: Bearer ` headers. For backend usage, include `x-secret-key` header.", status_, responseText_, headers_, null); + } + else + if (status_ == 402) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new ApiException("Payment required. The user does not have enough funds to cover the payment requirements. Returns a payment link to fund the wallet and complete the payment.", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 500) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Internal server error", status_, responseText_, headers_, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// x402 - Discover resources + /// + /// + /// Discover payable x402 compatible services and HTTP endpoints that can be paid for using the fetchWithPayment tool. Use this tool to browse services, APIs and endpoints to find what you need for your tasks. Each item has a resource url that you can call with the fetchWithPayment tool.Price is in the base units of the asset. For example, if the price is 1000000 and the asset is USDC (which is the default and has 6 decimals), the price is 1 USDC.Examples: if network is eip155:8453, asset is 0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913, max amount required is 10000, resource is https://api.example.com/paid-api, then you should interpret that as "the api.example.com/paid-api service costs 0.01 USDC per call". + /// + /// List of discovered x402 resources + /// A server side error occurred. + public virtual System.Threading.Tasks.Task ListPayableServicesAsync(double? limit, double? offset, string query, SortBy2? sortBy, SortOrder5? sortOrder) + { + return ListPayableServicesAsync(limit, offset, query, sortBy, sortOrder, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// x402 - Discover resources + /// + /// + /// Discover payable x402 compatible services and HTTP endpoints that can be paid for using the fetchWithPayment tool. Use this tool to browse services, APIs and endpoints to find what you need for your tasks. Each item has a resource url that you can call with the fetchWithPayment tool.Price is in the base units of the asset. For example, if the price is 1000000 and the asset is USDC (which is the default and has 6 decimals), the price is 1 USDC.Examples: if network is eip155:8453, asset is 0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913, max amount required is 10000, resource is https://api.example.com/paid-api, then you should interpret that as "the api.example.com/paid-api service costs 0.01 USDC per call". + /// + /// List of discovered x402 resources + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task ListPayableServicesAsync(double? limit, double? offset, string query, SortBy2? sortBy, SortOrder5? sortOrder, System.Threading.CancellationToken cancellationToken) + { + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + request_.Method = new System.Net.Http.HttpMethod("GET"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + var urlBuilder_ = new System.Text.StringBuilder(); + if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl); + // Operation Path: "v1/payments/x402/discovery/resources" + urlBuilder_.Append("v1/payments/x402/discovery/resources"); + urlBuilder_.Append('?'); + if (limit != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("limit")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(limit, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + if (offset != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("offset")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(offset, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + if (query != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("query")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(query, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + if (sortBy != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("sortBy")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(sortBy, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + if (sortOrder != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("sortOrder")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(sortOrder, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + urlBuilder_.Length--; + + PrepareRequest(client_, request_, urlBuilder_); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + PrepareRequest(client_, request_, url_); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = new System.Collections.Generic.Dictionary>(); + foreach (var item_ in response_.Headers) + headers_[item_.Key] = item_.Value; + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + ProcessResponse(client_, response_); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 401) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Authentication required. For backend usage, include `x-secret-key` header.", status_, responseText_, headers_, null); + } + else + if (status_ == 500) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Internal server error", status_, responseText_, headers_, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// x402 - Get payment accepts + /// + /// + /// Transform payment configuration into x402 payment requirements. This endpoint converts high-level payment parameters (like USD amounts or ERC20 token specifications) into the standardized x402 payment requirements format used by x402-compatible middleware. + /// + /// Returns x402 payment requirements + /// A server side error occurred. + public virtual System.Threading.Tasks.Task GetX402AcceptsAsync(Body18 body) + { + return GetX402AcceptsAsync(body, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// x402 - Get payment accepts + /// + /// + /// Transform payment configuration into x402 payment requirements. This endpoint converts high-level payment parameters (like USD amounts or ERC20 token specifications) into the standardized x402 payment requirements format used by x402-compatible middleware. + /// + /// Returns x402 payment requirements + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task GetX402AcceptsAsync(Body18 body, System.Threading.CancellationToken cancellationToken) + { + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + var json_ = Newtonsoft.Json.JsonConvert.SerializeObject(body, JsonSerializerSettings); + var content_ = new System.Net.Http.StringContent(json_); + content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json"); + request_.Content = content_; + request_.Method = new System.Net.Http.HttpMethod("POST"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + var urlBuilder_ = new System.Text.StringBuilder(); + if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl); + // Operation Path: "v1/payments/x402/accepts" + urlBuilder_.Append("v1/payments/x402/accepts"); + + PrepareRequest(client_, request_, urlBuilder_); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + PrepareRequest(client_, request_, url_); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = new System.Collections.Generic.Dictionary>(); + foreach (var item_ in response_.Headers) + headers_[item_.Key] = item_.Value; + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + ProcessResponse(client_, response_); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 400) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Invalid request parameters", status_, responseText_, headers_, null); + } + else + if (status_ == 401) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Authentication required. For backend usage, include `x-secret-key` header.", status_, responseText_, headers_, null); + } + else + if (status_ == 402) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new ApiException("Payment required \u2013 returns x402 payment requirements", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 500) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Internal server error", status_, responseText_, headers_, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// Create Token + /// + /// + /// Create a new ERC20 token with the provided metadata and starting price. The token is immediately available for purchase using thirdweb Payments. + ///
+ ///
**Authentication**: This endpoint requires project authentication and wallet authentication. For backend usage, use `x-secret-key` header. For frontend usage, use `x-client-id` + `Authorization: Bearer <jwt>` headers. + ///
+ /// The token is being deployed. Returns the predicted token address. + /// A server side error occurred. + public virtual System.Threading.Tasks.Task CreateTokenAsync(Body19 body) + { + return CreateTokenAsync(body, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Create Token + /// + /// + /// Create a new ERC20 token with the provided metadata and starting price. The token is immediately available for purchase using thirdweb Payments. + ///
+ ///
**Authentication**: This endpoint requires project authentication and wallet authentication. For backend usage, use `x-secret-key` header. For frontend usage, use `x-client-id` + `Authorization: Bearer <jwt>` headers. + ///
+ /// The token is being deployed. Returns the predicted token address. + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task CreateTokenAsync(Body19 body, System.Threading.CancellationToken cancellationToken) + { + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + var json_ = Newtonsoft.Json.JsonConvert.SerializeObject(body, JsonSerializerSettings); + var content_ = new System.Net.Http.StringContent(json_); + content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json"); + request_.Content = content_; + request_.Method = new System.Net.Http.HttpMethod("POST"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + var urlBuilder_ = new System.Text.StringBuilder(); + if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl); + // Operation Path: "v1/tokens" + urlBuilder_.Append("v1/tokens"); + + PrepareRequest(client_, request_, urlBuilder_); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + PrepareRequest(client_, request_, url_); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = new System.Collections.Generic.Dictionary>(); + foreach (var item_ in response_.Headers) + headers_[item_.Key] = item_.Value; + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + ProcessResponse(client_, response_); + + var status_ = (int)response_.StatusCode; + if (status_ == 202) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 400) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Invalid request parameters.", status_, responseText_, headers_, null); + } + else + if (status_ == 401) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Authentication required. For backend usage, include `x-secret-key` header. For frontend usage, include `x-client-id` + `Authorization: Bearer ` headers.", status_, responseText_, headers_, null); + } + else + if (status_ == 402) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Payment required. Insufficient wallet balance to deploy the contract.", status_, responseText_, headers_, null); + } + else + if (status_ == 500) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Internal server error. This may occur due to network connectivity issues, wallet creation failures, or transaction execution failures.", status_, responseText_, headers_, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// List Tokens + /// + /// + /// Lists or search existing tokens based on the provided filters. Supports querying by chain ID, token address, symbol, and/or name. + ///
+ ///
+ ///
+ ///
**Authentication**: Pass `x-client-id` header for frontend usage from allowlisted origins or `x-secret-key` for backend usage. + ///
+ /// Number of tokens to return per page (1-100). + /// Page number for pagination, starting from 1. + /// Limit tokens to a specific chain. + /// Get a specific token by contract address + /// Limit tokens to a specific symbol. + /// Limit tokens to a specific name. + /// Tokens returned successfully. + /// A server side error occurred. + public virtual System.Threading.Tasks.Task ListTokensAsync(int? limit, int? page, int? chainId, string tokenAddress, string symbol, string name) + { + return ListTokensAsync(limit, page, chainId, tokenAddress, symbol, name, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// List Tokens + /// + /// + /// Lists or search existing tokens based on the provided filters. Supports querying by chain ID, token address, symbol, and/or name. + ///
+ ///
+ ///
+ ///
**Authentication**: Pass `x-client-id` header for frontend usage from allowlisted origins or `x-secret-key` for backend usage. + ///
+ /// Number of tokens to return per page (1-100). + /// Page number for pagination, starting from 1. + /// Limit tokens to a specific chain. + /// Get a specific token by contract address + /// Limit tokens to a specific symbol. + /// Limit tokens to a specific name. + /// Tokens returned successfully. + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task ListTokensAsync(int? limit, int? page, int? chainId, string tokenAddress, string symbol, string name, System.Threading.CancellationToken cancellationToken) + { + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + request_.Method = new System.Net.Http.HttpMethod("GET"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + var urlBuilder_ = new System.Text.StringBuilder(); + if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl); + // Operation Path: "v1/tokens" + urlBuilder_.Append("v1/tokens"); + urlBuilder_.Append('?'); + if (limit != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("limit")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(limit, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + if (page != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("page")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(page, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + if (chainId != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("chainId")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(chainId, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + if (tokenAddress != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("tokenAddress")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(tokenAddress, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + if (symbol != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("symbol")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(symbol, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + if (name != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("name")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(name, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + urlBuilder_.Length--; + + PrepareRequest(client_, request_, urlBuilder_); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + PrepareRequest(client_, request_, url_); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = new System.Collections.Generic.Dictionary>(); + foreach (var item_ in response_.Headers) + headers_[item_.Key] = item_.Value; + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + ProcessResponse(client_, response_); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 400) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Invalid request parameters.", status_, responseText_, headers_, null); + } + else + if (status_ == 401) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Authentication required. For backend usage, include `x-secret-key` header. For frontend usage, include `x-client-id` + `Authorization: Bearer ` headers.", status_, responseText_, headers_, null); + } + else + if (status_ == 500) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Internal server error. This may occur due to network connectivity issues, wallet creation failures, or transaction execution failures.", status_, responseText_, headers_, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// Get Owners + /// + /// + /// Retrieves a paginated list of owners for a given token contract on a specific chain. Supports ERC-20 tokens, ERC-721 NFTs, and ERC-1155 tokens: + ///
+ ///
- **ERC-20**: No `tokenId` provided - returns token holders with balances + ///
- **NFT Collection**: No `tokenId` provided - returns all owners of any token in the collection + ///
- **Specific NFT**: `tokenId` provided - returns owner(s) of that specific token ID + ///
+ ///
The token standard is automatically detected using ERC165 interface detection when needed. + ///
+ ///
**Authentication**: Pass `x-client-id` header for frontend usage from allowlisted origins or `x-secret-key` for backend usage. + ///
+ /// The blockchain network identifier. Common values include: 1 (Ethereum), 8453 (Base), 137 (Polygon), 56 (BSC), 43114 (Avalanche), 42161 (Arbitrum), 10 (Optimism). + /// A valid Ethereum address (0x-prefixed hex string) or ENS name (e.g., vitalik.eth). + /// Optional token ID for NFT owners. If provided, returns owners of the specific NFT token. + /// Number of owners to return per page (1-100). + /// Page number for pagination, starting from 1. + /// Token owners retrieved successfully. Returns owners with pagination information. For ERC-20 tokens, `amount` represents token balance. For NFTs, `amount` represents quantity owned (usually '1' for ERC-721, can be >1 for ERC-1155). + /// A server side error occurred. + public virtual System.Threading.Tasks.Task GetTokenOwnersAsync(int chainId, string address, string tokenId, int? limit, int? page) + { + return GetTokenOwnersAsync(chainId, address, tokenId, limit, page, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Get Owners + /// + /// + /// Retrieves a paginated list of owners for a given token contract on a specific chain. Supports ERC-20 tokens, ERC-721 NFTs, and ERC-1155 tokens: + ///
+ ///
- **ERC-20**: No `tokenId` provided - returns token holders with balances + ///
- **NFT Collection**: No `tokenId` provided - returns all owners of any token in the collection + ///
- **Specific NFT**: `tokenId` provided - returns owner(s) of that specific token ID + ///
+ ///
The token standard is automatically detected using ERC165 interface detection when needed. + ///
+ ///
**Authentication**: Pass `x-client-id` header for frontend usage from allowlisted origins or `x-secret-key` for backend usage. + ///
+ /// The blockchain network identifier. Common values include: 1 (Ethereum), 8453 (Base), 137 (Polygon), 56 (BSC), 43114 (Avalanche), 42161 (Arbitrum), 10 (Optimism). + /// A valid Ethereum address (0x-prefixed hex string) or ENS name (e.g., vitalik.eth). + /// Optional token ID for NFT owners. If provided, returns owners of the specific NFT token. + /// Number of owners to return per page (1-100). + /// Page number for pagination, starting from 1. + /// Token owners retrieved successfully. Returns owners with pagination information. For ERC-20 tokens, `amount` represents token balance. For NFTs, `amount` represents quantity owned (usually '1' for ERC-721, can be >1 for ERC-1155). + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task GetTokenOwnersAsync(int chainId, string address, string tokenId, int? limit, int? page, System.Threading.CancellationToken cancellationToken) + { + if (chainId == null) + throw new System.ArgumentNullException("chainId"); + + if (address == null) + throw new System.ArgumentNullException("address"); + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + request_.Method = new System.Net.Http.HttpMethod("GET"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + var urlBuilder_ = new System.Text.StringBuilder(); + if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl); + // Operation Path: "v1/tokens/{chainId}/{address}/owners" + urlBuilder_.Append("v1/tokens/"); + urlBuilder_.Append(System.Uri.EscapeDataString(ConvertToString(chainId, System.Globalization.CultureInfo.InvariantCulture))); + urlBuilder_.Append('/'); + urlBuilder_.Append(System.Uri.EscapeDataString(ConvertToString(address, System.Globalization.CultureInfo.InvariantCulture))); + urlBuilder_.Append("/owners"); + urlBuilder_.Append('?'); + if (tokenId != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("tokenId")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(tokenId, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + if (limit != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("limit")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(limit, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + if (page != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("page")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(page, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + urlBuilder_.Length--; + + PrepareRequest(client_, request_, urlBuilder_); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + PrepareRequest(client_, request_, url_); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = new System.Collections.Generic.Dictionary>(); + foreach (var item_ in response_.Headers) + headers_[item_.Key] = item_.Value; + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + ProcessResponse(client_, response_); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 400) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Invalid request parameters.", status_, responseText_, headers_, null); + } + else + if (status_ == 401) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Authentication required. The request must include a valid `x-client-id` header for frontend usage or `x-secret-key` for backend usage.", status_, responseText_, headers_, null); + } + else + if (status_ == 404) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Token not found or no owners available.", status_, responseText_, headers_, null); + } + else + if (status_ == 500) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Internal server error.", status_, responseText_, headers_, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// List Supported Chains + /// + /// + /// List all blockchain networks available for cross-chain bridging. Each chain includes metadata and native currency details. + ///
+ ///
**Authentication**: Pass `x-client-id` header for frontend usage from allowlisted origins or `x-secret-key` for backend usage. + ///
+ /// Successfully retrieved supported bridge chains. + /// A server side error occurred. + public virtual System.Threading.Tasks.Task GetBridgeChainsAsync() + { + return GetBridgeChainsAsync(System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// List Supported Chains + /// + /// + /// List all blockchain networks available for cross-chain bridging. Each chain includes metadata and native currency details. + ///
+ ///
**Authentication**: Pass `x-client-id` header for frontend usage from allowlisted origins or `x-secret-key` for backend usage. + ///
+ /// Successfully retrieved supported bridge chains. + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task GetBridgeChainsAsync(System.Threading.CancellationToken cancellationToken) + { + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + request_.Method = new System.Net.Http.HttpMethod("GET"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + var urlBuilder_ = new System.Text.StringBuilder(); + if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl); + // Operation Path: "v1/bridge/chains" + urlBuilder_.Append("v1/bridge/chains"); + + PrepareRequest(client_, request_, urlBuilder_); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + PrepareRequest(client_, request_, url_); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = new System.Collections.Generic.Dictionary>(); + foreach (var item_ in response_.Headers) + headers_[item_.Key] = item_.Value; + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + ProcessResponse(client_, response_); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 401) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Authentication required. For backend usage, include `x-secret-key` header. For frontend usage, include `x-client-id` header.", status_, responseText_, headers_, null); + } + else + if (status_ == 500) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Internal server error occurred while fetching bridge chains.", status_, responseText_, headers_, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// List Supported Routes + /// + /// + /// List supported bridge routes with simple pagination and optional chain or token filters. + ///
+ ///
**Authentication**: Pass `x-client-id` header for frontend usage from allowlisted origins or `x-secret-key` for backend usage. + ///
+ /// Maximum number of routes to return (1-100). + /// Page number for pagination, starting at 1. + /// Filter routes by the origin chain ID. + /// Filter routes by the destination chain ID. + /// Filter routes by origin token address. + /// Filter routes by destination token address. + /// Maximum number of bridge steps allowed in the route. + /// Successfully retrieved supported bridge routes. + /// A server side error occurred. + public virtual System.Threading.Tasks.Task GetBridgeSupportedRoutesAsync(int? limit, int? page, int? originChainId, int? destinationChainId, string originTokenAddress, string destinationTokenAddress, int? maxSteps) + { + return GetBridgeSupportedRoutesAsync(limit, page, originChainId, destinationChainId, originTokenAddress, destinationTokenAddress, maxSteps, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// List Supported Routes + /// + /// + /// List supported bridge routes with simple pagination and optional chain or token filters. + ///
+ ///
**Authentication**: Pass `x-client-id` header for frontend usage from allowlisted origins or `x-secret-key` for backend usage. + ///
+ /// Maximum number of routes to return (1-100). + /// Page number for pagination, starting at 1. + /// Filter routes by the origin chain ID. + /// Filter routes by the destination chain ID. + /// Filter routes by origin token address. + /// Filter routes by destination token address. + /// Maximum number of bridge steps allowed in the route. + /// Successfully retrieved supported bridge routes. + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task GetBridgeSupportedRoutesAsync(int? limit, int? page, int? originChainId, int? destinationChainId, string originTokenAddress, string destinationTokenAddress, int? maxSteps, System.Threading.CancellationToken cancellationToken) + { + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + request_.Method = new System.Net.Http.HttpMethod("GET"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + var urlBuilder_ = new System.Text.StringBuilder(); + if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl); + // Operation Path: "v1/bridge/routes" + urlBuilder_.Append("v1/bridge/routes"); + urlBuilder_.Append('?'); + if (limit != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("limit")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(limit, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + if (page != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("page")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(page, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + if (originChainId != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("originChainId")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(originChainId, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + if (destinationChainId != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("destinationChainId")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(destinationChainId, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + if (originTokenAddress != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("originTokenAddress")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(originTokenAddress, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + if (destinationTokenAddress != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("destinationTokenAddress")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(destinationTokenAddress, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + if (maxSteps != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("maxSteps")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(maxSteps, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + urlBuilder_.Length--; + + PrepareRequest(client_, request_, urlBuilder_); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + PrepareRequest(client_, request_, url_); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = new System.Collections.Generic.Dictionary>(); + foreach (var item_ in response_.Headers) + headers_[item_.Key] = item_.Value; + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + ProcessResponse(client_, response_); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 400) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Invalid request parameters.", status_, responseText_, headers_, null); + } + else + if (status_ == 401) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Authentication required. For backend usage, include `x-secret-key` header. For frontend usage, include `x-client-id` header.", status_, responseText_, headers_, null); + } + else + if (status_ == 500) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Internal server error occurred while fetching bridge routes.", status_, responseText_, headers_, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// Convert Fiat to Crypto + /// + /// + /// Convert fiat currency amount to cryptocurrency token amount. Supports multiple fiat currencies based on available price data for the specific token. Returns the equivalent amount of crypto tokens for the specified fiat amount based on current market prices. If price data is not available for the requested currency, the API will return a 404 error. + ///
+ ///
**Native Tokens**: To get the price of native tokens (like ETH on Ethereum), use the address `0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE`. For example, to get the price of ETH on Ethereum Mainnet (chainId: 1), pass `to=0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE`. + ///
+ ///
**Authentication**: Pass `x-client-id` header for frontend usage from allowlisted origins or `x-secret-key` for backend usage. + ///
+ /// The fiat currency symbol + /// The amount of fiat currency to convert + /// The blockchain network identifier + /// The token address on the specified chain to convert to + /// Conversion completed successfully. Returns the amount of crypto tokens equivalent to the specified fiat amount. + /// A server side error occurred. + public virtual System.Threading.Tasks.Task ConvertFiatToCryptoAsync(From from, string fromAmount, int chainId, string to) + { + return ConvertFiatToCryptoAsync(from, fromAmount, chainId, to, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Convert Fiat to Crypto + /// + /// + /// Convert fiat currency amount to cryptocurrency token amount. Supports multiple fiat currencies based on available price data for the specific token. Returns the equivalent amount of crypto tokens for the specified fiat amount based on current market prices. If price data is not available for the requested currency, the API will return a 404 error. + ///
+ ///
**Native Tokens**: To get the price of native tokens (like ETH on Ethereum), use the address `0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE`. For example, to get the price of ETH on Ethereum Mainnet (chainId: 1), pass `to=0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE`. + ///
+ ///
**Authentication**: Pass `x-client-id` header for frontend usage from allowlisted origins or `x-secret-key` for backend usage. + ///
+ /// The fiat currency symbol + /// The amount of fiat currency to convert + /// The blockchain network identifier + /// The token address on the specified chain to convert to + /// Conversion completed successfully. Returns the amount of crypto tokens equivalent to the specified fiat amount. + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task ConvertFiatToCryptoAsync(From from, string fromAmount, int chainId, string to, System.Threading.CancellationToken cancellationToken) + { + if (from == null) + throw new System.ArgumentNullException("from"); + + if (fromAmount == null) + throw new System.ArgumentNullException("fromAmount"); + + if (chainId == null) + throw new System.ArgumentNullException("chainId"); + + if (to == null) + throw new System.ArgumentNullException("to"); + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + request_.Method = new System.Net.Http.HttpMethod("GET"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + var urlBuilder_ = new System.Text.StringBuilder(); + if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl); + // Operation Path: "v1/bridge/convert" + urlBuilder_.Append("v1/bridge/convert"); + urlBuilder_.Append('?'); + urlBuilder_.Append(System.Uri.EscapeDataString("from")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(from, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + urlBuilder_.Append(System.Uri.EscapeDataString("fromAmount")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(fromAmount, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + urlBuilder_.Append(System.Uri.EscapeDataString("chainId")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(chainId, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + urlBuilder_.Append(System.Uri.EscapeDataString("to")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(to, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + urlBuilder_.Length--; + + PrepareRequest(client_, request_, urlBuilder_); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + PrepareRequest(client_, request_, url_); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = new System.Collections.Generic.Dictionary>(); + foreach (var item_ in response_.Headers) + headers_[item_.Key] = item_.Value; + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + ProcessResponse(client_, response_); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 400) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Bad request. Invalid parameters such as invalid amounts, malformed token address, or invalid currency code.", status_, responseText_, headers_, null); + } + else + if (status_ == 401) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Authentication required. Include `x-client-id` header for frontend usage or `x-secret-key` for backend usage.", status_, responseText_, headers_, null); + } + else + if (status_ == 404) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Token not found, price data unavailable for the specified token on the given chain, or price data not available for the requested currency.", status_, responseText_, headers_, null); + } + else + if (status_ == 429) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Too many requests. Rate limit exceeded.", status_, responseText_, headers_, null); + } + else + if (status_ == 500) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Internal server error. This may occur due to network connectivity issues or external service failures.", status_, responseText_, headers_, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// Swap or Bridge Tokens + /// + /// + /// Swap one token for another using the optimal route available. You can specify a tokenIn amount (if exact='input') or tokenOut amount (if exact='output'), but not both. The corresponding output or input amount will be returned as the quote. + ///
+ ///
**Authentication**: This endpoint requires project authentication and wallet authentication. For backend usage, use `x-secret-key` header. For frontend usage, use `x-client-id` + `Authorization: Bearer <jwt>` headers. + ///
+ /// Swap completed successfully. Returns the transaction used for the swap. + /// A server side error occurred. + public virtual System.Threading.Tasks.Task BridgeSwapAsync(Body20 body) + { + return BridgeSwapAsync(body, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Swap or Bridge Tokens + /// + /// + /// Swap one token for another using the optimal route available. You can specify a tokenIn amount (if exact='input') or tokenOut amount (if exact='output'), but not both. The corresponding output or input amount will be returned as the quote. + ///
+ ///
**Authentication**: This endpoint requires project authentication and wallet authentication. For backend usage, use `x-secret-key` header. For frontend usage, use `x-client-id` + `Authorization: Bearer <jwt>` headers. + ///
+ /// Swap completed successfully. Returns the transaction used for the swap. + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task BridgeSwapAsync(Body20 body, System.Threading.CancellationToken cancellationToken) + { + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + var json_ = Newtonsoft.Json.JsonConvert.SerializeObject(body, JsonSerializerSettings); + var content_ = new System.Net.Http.StringContent(json_); + content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json"); + request_.Content = content_; + request_.Method = new System.Net.Http.HttpMethod("POST"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + var urlBuilder_ = new System.Text.StringBuilder(); + if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl); + // Operation Path: "v1/bridge/swap" + urlBuilder_.Append("v1/bridge/swap"); + + PrepareRequest(client_, request_, urlBuilder_); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + PrepareRequest(client_, request_, url_); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = new System.Collections.Generic.Dictionary>(); + foreach (var item_ in response_.Headers) + headers_[item_.Key] = item_.Value; + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + ProcessResponse(client_, response_); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 400) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Invalid request parameters.", status_, responseText_, headers_, null); + } + else + if (status_ == 401) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Authentication required. For backend usage, include `x-secret-key` header. For frontend usage, include `x-client-id` + `Authorization: Bearer ` headers.", status_, responseText_, headers_, null); + } + else + if (status_ == 402) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new ApiException("Payment required. Insufficient wallet balance to complete the purchase.", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 500) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Internal server error. This may occur due to network connectivity issues, wallet creation failures, or transaction execution failures.", status_, responseText_, headers_, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// List Solana Wallets + /// + /// + /// List all Solana wallets created for your project. Supports pagination with page and limit parameters. + ///
+ ///
**Authentication**: This endpoint requires backend authentication using the x-secret-key header. The secret key should never be exposed publicly. + ///
+ /// Page number for paginated results. Starts at 1. + /// Maximum number of wallets to return per page. + /// Successfully retrieved Solana wallets with pagination metadata. + /// A server side error occurred. + public virtual System.Threading.Tasks.Task ListSolanaWalletsAsync(int? page, int? limit) + { + return ListSolanaWalletsAsync(page, limit, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// List Solana Wallets + /// + /// + /// List all Solana wallets created for your project. Supports pagination with page and limit parameters. + ///
+ ///
**Authentication**: This endpoint requires backend authentication using the x-secret-key header. The secret key should never be exposed publicly. + ///
+ /// Page number for paginated results. Starts at 1. + /// Maximum number of wallets to return per page. + /// Successfully retrieved Solana wallets with pagination metadata. + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task ListSolanaWalletsAsync(int? page, int? limit, System.Threading.CancellationToken cancellationToken) + { + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + request_.Method = new System.Net.Http.HttpMethod("GET"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + var urlBuilder_ = new System.Text.StringBuilder(); + if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl); + // Operation Path: "v1/solana/wallets" + urlBuilder_.Append("v1/solana/wallets"); + urlBuilder_.Append('?'); + if (page != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("page")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(page, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + if (limit != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("limit")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(limit, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + urlBuilder_.Length--; + + PrepareRequest(client_, request_, urlBuilder_); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + PrepareRequest(client_, request_, url_); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = new System.Collections.Generic.Dictionary>(); + foreach (var item_ in response_.Headers) + headers_[item_.Key] = item_.Value; + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + ProcessResponse(client_, response_); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 401) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Authentication required. Include x-secret-key or Authorization headers.", status_, responseText_, headers_, null); + } + else + if (status_ == 500) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Internal server error occurred while listing wallets.", status_, responseText_, headers_, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// Create Solana Wallet + /// + /// + /// Create a new Solana wallet or return the existing wallet for a given label. Labels must be unique within your project. + ///
+ ///
**Authentication**: This endpoint requires backend authentication using the x-secret-key header. The secret key should never be exposed publicly. + ///
+ /// Solana wallet retrieved for the provided label. + /// A server side error occurred. + public virtual System.Threading.Tasks.Task CreateSolanaWalletAsync(Body21 body) + { + return CreateSolanaWalletAsync(body, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Create Solana Wallet + /// + /// + /// Create a new Solana wallet or return the existing wallet for a given label. Labels must be unique within your project. + ///
+ ///
**Authentication**: This endpoint requires backend authentication using the x-secret-key header. The secret key should never be exposed publicly. + ///
+ /// Solana wallet retrieved for the provided label. + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task CreateSolanaWalletAsync(Body21 body, System.Threading.CancellationToken cancellationToken) + { + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + var json_ = Newtonsoft.Json.JsonConvert.SerializeObject(body, JsonSerializerSettings); + var content_ = new System.Net.Http.StringContent(json_); + content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json"); + request_.Content = content_; + request_.Method = new System.Net.Http.HttpMethod("POST"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + var urlBuilder_ = new System.Text.StringBuilder(); + if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl); + // Operation Path: "v1/solana/wallets" + urlBuilder_.Append("v1/solana/wallets"); + + PrepareRequest(client_, request_, urlBuilder_); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + PrepareRequest(client_, request_, url_); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = new System.Collections.Generic.Dictionary>(); + foreach (var item_ in response_.Headers) + headers_[item_.Key] = item_.Value; + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + ProcessResponse(client_, response_); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 201) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new ApiException("Solana wallet created for the provided label.", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 401) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Authentication required. Include x-secret-key or Authorization headers.", status_, responseText_, headers_, null); + } + else + if (status_ == 500) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Internal server error occurred while creating wallet.", status_, responseText_, headers_, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// Get Solana Wallet Balance + /// + /// + /// Get the SOL or SPL token balance for a Solana wallet on a specific Solana network. + ///
+ ///
**Authentication**: Pass `x-client-id` for frontend usage from allowlisted origins or `x-secret-key` for backend usage. + ///
+ /// Public key of the Solana wallet. + /// Solana network to query. Choose either solana:mainnet or solana:devnet. + /// SPL token mint address. Omit to retrieve native SOL balance. + /// Wallet balance retrieved successfully for the requested Solana network. + /// A server side error occurred. + public virtual System.Threading.Tasks.Task GetSolanaWalletBalanceAsync(string address, string chainId, string tokenAddress) + { + return GetSolanaWalletBalanceAsync(address, chainId, tokenAddress, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Get Solana Wallet Balance + /// + /// + /// Get the SOL or SPL token balance for a Solana wallet on a specific Solana network. + ///
+ ///
**Authentication**: Pass `x-client-id` for frontend usage from allowlisted origins or `x-secret-key` for backend usage. + ///
+ /// Public key of the Solana wallet. + /// Solana network to query. Choose either solana:mainnet or solana:devnet. + /// SPL token mint address. Omit to retrieve native SOL balance. + /// Wallet balance retrieved successfully for the requested Solana network. + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task GetSolanaWalletBalanceAsync(string address, string chainId, string tokenAddress, System.Threading.CancellationToken cancellationToken) + { + if (address == null) + throw new System.ArgumentNullException("address"); + + if (chainId == null) + throw new System.ArgumentNullException("chainId"); + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + request_.Method = new System.Net.Http.HttpMethod("GET"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + var urlBuilder_ = new System.Text.StringBuilder(); + if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl); + // Operation Path: "v1/solana/wallets/{address}/balance" + urlBuilder_.Append("v1/solana/wallets/"); + urlBuilder_.Append(System.Uri.EscapeDataString(ConvertToString(address, System.Globalization.CultureInfo.InvariantCulture))); + urlBuilder_.Append("/balance"); + urlBuilder_.Append('?'); + urlBuilder_.Append(System.Uri.EscapeDataString("chainId")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(chainId, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + if (tokenAddress != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("tokenAddress")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(tokenAddress, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + urlBuilder_.Length--; + + PrepareRequest(client_, request_, urlBuilder_); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + PrepareRequest(client_, request_, url_); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = new System.Collections.Generic.Dictionary>(); + foreach (var item_ in response_.Headers) + headers_[item_.Key] = item_.Value; + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + ProcessResponse(client_, response_); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 400) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Invalid request parameters. This occurs when the wallet address or token mint is invalid, or the request mixes a token mint with multiple networks.", status_, responseText_, headers_, null); + } + else + if (status_ == 401) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Authentication required. Include `x-client-id` or `x-secret-key` headers.", status_, responseText_, headers_, null); + } + else + if (status_ == 500) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Internal server error. This may occur due to RPC connectivity issues or unexpected failures.", status_, responseText_, headers_, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// Sign Solana Message + /// + /// + /// Sign an arbitrary message with a Solana wallet. Supports both text and hexadecimal message formats with automatic format detection. + ///
+ ///
**Authentication**: This endpoint requires backend authentication using the x-secret-key header. The secret key should never be exposed publicly. + ///
+ /// Message signed successfully. Returns the base58 signature. + /// A server side error occurred. + public virtual System.Threading.Tasks.Task SignSolanaMessageAsync(Body22 body) + { + return SignSolanaMessageAsync(body, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Sign Solana Message + /// + /// + /// Sign an arbitrary message with a Solana wallet. Supports both text and hexadecimal message formats with automatic format detection. + ///
+ ///
**Authentication**: This endpoint requires backend authentication using the x-secret-key header. The secret key should never be exposed publicly. + ///
+ /// Message signed successfully. Returns the base58 signature. + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task SignSolanaMessageAsync(Body22 body, System.Threading.CancellationToken cancellationToken) + { + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + var json_ = Newtonsoft.Json.JsonConvert.SerializeObject(body, JsonSerializerSettings); + var content_ = new System.Net.Http.StringContent(json_); + content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json"); + request_.Content = content_; + request_.Method = new System.Net.Http.HttpMethod("POST"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + var urlBuilder_ = new System.Text.StringBuilder(); + if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl); + // Operation Path: "v1/solana/sign-message" + urlBuilder_.Append("v1/solana/sign-message"); + + PrepareRequest(client_, request_, urlBuilder_); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + PrepareRequest(client_, request_, url_); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = new System.Collections.Generic.Dictionary>(); + foreach (var item_ in response_.Headers) + headers_[item_.Key] = item_.Value; + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + ProcessResponse(client_, response_); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 401) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Authentication required. Include x-secret-key or Authorization headers.", status_, responseText_, headers_, null); + } + else + if (status_ == 500) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Internal server error occurred while signing the message.", status_, responseText_, headers_, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// Sign Solana Transaction + /// + /// + /// Sign a Solana transaction using a server wallet without broadcasting it. Provide either a serialized transaction or the instructions to assemble one, along with execution options. + ///
+ ///
**Authentication**: This endpoint requires backend authentication using the x-secret-key header. Optionally, include x-vault-access-token if your wallet is managed via Vault. + ///
+ /// Transaction signed successfully. Returns the signature and the fully signed transaction payload. + /// A server side error occurred. + public virtual System.Threading.Tasks.Task SignSolanaTransactionAsync(Body23 body) + { + return SignSolanaTransactionAsync(body, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Sign Solana Transaction + /// + /// + /// Sign a Solana transaction using a server wallet without broadcasting it. Provide either a serialized transaction or the instructions to assemble one, along with execution options. + ///
+ ///
**Authentication**: This endpoint requires backend authentication using the x-secret-key header. Optionally, include x-vault-access-token if your wallet is managed via Vault. + ///
+ /// Transaction signed successfully. Returns the signature and the fully signed transaction payload. + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task SignSolanaTransactionAsync(Body23 body, System.Threading.CancellationToken cancellationToken) + { + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + var json_ = Newtonsoft.Json.JsonConvert.SerializeObject(body, JsonSerializerSettings); + var content_ = new System.Net.Http.StringContent(json_); + content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json"); + request_.Content = content_; + request_.Method = new System.Net.Http.HttpMethod("POST"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + var urlBuilder_ = new System.Text.StringBuilder(); + if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl); + // Operation Path: "v1/solana/sign-transaction" + urlBuilder_.Append("v1/solana/sign-transaction"); + + PrepareRequest(client_, request_, urlBuilder_); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + PrepareRequest(client_, request_, url_); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = new System.Collections.Generic.Dictionary>(); + foreach (var item_ in response_.Headers) + headers_[item_.Key] = item_.Value; + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + ProcessResponse(client_, response_); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 401) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Authentication required. Include x-secret-key or Authorization headers.", status_, responseText_, headers_, null); + } + else + if (status_ == 500) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Internal server error occurred while signing the transaction.", status_, responseText_, headers_, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// Broadcast Signed Solana Transaction + /// + /// + /// Broadcast a signed Solana transaction to the network and wait for confirmation. This endpoint accepts a base64 encoded signed transaction (such as the output from /v1/solana/sign-transaction), submits it to the Solana blockchain, and polls until the transaction is confirmed (up to 30 seconds). + ///
+ ///
The endpoint waits for the transaction to reach 'confirmed' or 'finalized' status before returning. If the transaction fails on-chain, detailed error information is returned including instruction index, error type, and the transaction signature for debugging. + ///
+ ///
**Authentication**: This endpoint requires backend authentication using the x-secret-key header. + ///
+ /// Transaction broadcast and confirmed successfully. Returns the transaction signature (equivalent to EVM transaction hash). + /// A server side error occurred. + public virtual System.Threading.Tasks.Task BroadcastSolanaTransactionAsync(Body24 body) + { + return BroadcastSolanaTransactionAsync(body, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Broadcast Signed Solana Transaction + /// + /// + /// Broadcast a signed Solana transaction to the network and wait for confirmation. This endpoint accepts a base64 encoded signed transaction (such as the output from /v1/solana/sign-transaction), submits it to the Solana blockchain, and polls until the transaction is confirmed (up to 30 seconds). + ///
+ ///
The endpoint waits for the transaction to reach 'confirmed' or 'finalized' status before returning. If the transaction fails on-chain, detailed error information is returned including instruction index, error type, and the transaction signature for debugging. + ///
+ ///
**Authentication**: This endpoint requires backend authentication using the x-secret-key header. + ///
+ /// Transaction broadcast and confirmed successfully. Returns the transaction signature (equivalent to EVM transaction hash). + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task BroadcastSolanaTransactionAsync(Body24 body, System.Threading.CancellationToken cancellationToken) + { + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + var json_ = Newtonsoft.Json.JsonConvert.SerializeObject(body, JsonSerializerSettings); + var content_ = new System.Net.Http.StringContent(json_); + content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json"); + request_.Content = content_; + request_.Method = new System.Net.Http.HttpMethod("POST"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + var urlBuilder_ = new System.Text.StringBuilder(); + if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl); + // Operation Path: "v1/solana/broadcast-transaction" + urlBuilder_.Append("v1/solana/broadcast-transaction"); + + PrepareRequest(client_, request_, urlBuilder_); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + PrepareRequest(client_, request_, url_); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = new System.Collections.Generic.Dictionary>(); + foreach (var item_ in response_.Headers) + headers_[item_.Key] = item_.Value; + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + ProcessResponse(client_, response_); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 400) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Transaction failed on-chain. Response includes detailed error information with the transaction signature, error type, and instruction index (if applicable). Common errors include InsufficientFunds, InstructionError (program execution failure), InvalidAccountData, etc.", status_, responseText_, headers_, null); + } + else + if (status_ == 401) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Authentication required. Include x-secret-key or Authorization headers.", status_, responseText_, headers_, null); + } + else + if (status_ == 500) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Internal server error occurred while broadcasting or polling the transaction.", status_, responseText_, headers_, null); + } + else + if (status_ == 504) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Transaction was not confirmed within the 30 second timeout period. The transaction may still be pending or dropped.", status_, responseText_, headers_, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// Send Solana Tokens + /// + /// + /// Transfer native SOL or SPL tokens on Solana. Automatically handles token account creation for SPL tokens if needed. + ///
+ ///
**Authentication**: This endpoint requires backend authentication using the x-secret-key header. The secret key should never be exposed publicly. + ///
+ /// Transfer queued successfully. Returns the transaction identifier for status polling. + /// A server side error occurred. + public virtual System.Threading.Tasks.Task SendSolanaTokensAsync(Body25 body) + { + return SendSolanaTokensAsync(body, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Send Solana Tokens + /// + /// + /// Transfer native SOL or SPL tokens on Solana. Automatically handles token account creation for SPL tokens if needed. + ///
+ ///
**Authentication**: This endpoint requires backend authentication using the x-secret-key header. The secret key should never be exposed publicly. + ///
+ /// Transfer queued successfully. Returns the transaction identifier for status polling. + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task SendSolanaTokensAsync(Body25 body, System.Threading.CancellationToken cancellationToken) + { + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + var json_ = Newtonsoft.Json.JsonConvert.SerializeObject(body, JsonSerializerSettings); + var content_ = new System.Net.Http.StringContent(json_); + content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json"); + request_.Content = content_; + request_.Method = new System.Net.Http.HttpMethod("POST"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + var urlBuilder_ = new System.Text.StringBuilder(); + if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl); + // Operation Path: "v1/solana/send" + urlBuilder_.Append("v1/solana/send"); + + PrepareRequest(client_, request_, urlBuilder_); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + PrepareRequest(client_, request_, url_); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = new System.Collections.Generic.Dictionary>(); + foreach (var item_ in response_.Headers) + headers_[item_.Key] = item_.Value; + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + ProcessResponse(client_, response_); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 202) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new ApiException("Transfer accepted for asynchronous processing. Returns the transaction identifier for status polling.", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 401) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Authentication required. Include x-secret-key or Authorization headers.", status_, responseText_, headers_, null); + } + else + if (status_ == 500) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Internal server error occurred while processing the transfer.", status_, responseText_, headers_, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// Send Solana Transaction + /// + /// + /// Submit a Solana transaction composed of one or more instructions. Transactions are queued and processed asynchronously. + ///
+ ///
**Authentication**: This endpoint requires backend authentication using the x-secret-key header. The secret key should never be exposed publicly. + ///
+ /// Transaction queued successfully. Returns the transaction identifier for status polling. + /// A server side error occurred. + public virtual System.Threading.Tasks.Task SendSolanaTransactionAsync(Body26 body) + { + return SendSolanaTransactionAsync(body, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Send Solana Transaction + /// + /// + /// Submit a Solana transaction composed of one or more instructions. Transactions are queued and processed asynchronously. + ///
+ ///
**Authentication**: This endpoint requires backend authentication using the x-secret-key header. The secret key should never be exposed publicly. + ///
+ /// Transaction queued successfully. Returns the transaction identifier for status polling. + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task SendSolanaTransactionAsync(Body26 body, System.Threading.CancellationToken cancellationToken) + { + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + var json_ = Newtonsoft.Json.JsonConvert.SerializeObject(body, JsonSerializerSettings); + var content_ = new System.Net.Http.StringContent(json_); + content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json"); + request_.Content = content_; + request_.Method = new System.Net.Http.HttpMethod("POST"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + var urlBuilder_ = new System.Text.StringBuilder(); + if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl); + // Operation Path: "v1/solana/transactions" + urlBuilder_.Append("v1/solana/transactions"); + + PrepareRequest(client_, request_, urlBuilder_); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + PrepareRequest(client_, request_, url_); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = new System.Collections.Generic.Dictionary>(); + foreach (var item_ in response_.Headers) + headers_[item_.Key] = item_.Value; + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + ProcessResponse(client_, response_); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 202) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new ApiException("Transaction accepted for asynchronous processing. Returns the transaction identifier for status polling.", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 401) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Authentication required. Include x-secret-key or Authorization headers.", status_, responseText_, headers_, null); + } + else + if (status_ == 500) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Internal server error occurred while processing the transaction.", status_, responseText_, headers_, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// Get Solana Swap Quote + /// + /// + /// Get a quote for swapping tokens on Solana. This endpoint returns the expected output amount and swap details without executing the transaction. + ///
+ ///
**Important**: Swaps are only available on Solana mainnet. + ///
+ ///
**Authentication**: This endpoint requires backend authentication using the x-secret-key header. + ///
+ /// Solana wallet address that will execute the swap. + /// Input token mint address (the token being sold). + /// Output token mint address (the token being purchased). + /// Amount of input token to swap, expressed in the smallest unit (e.g., lamports for SOL). + /// Quote fetched successfully. Returns expected output amount and swap details. + /// A server side error occurred. + public virtual System.Threading.Tasks.Task GetSwapQuoteAsync(string address, string tokenIn, string tokenOut, string amount, string chainId) + { + return GetSwapQuoteAsync(address, tokenIn, tokenOut, amount, chainId, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Get Solana Swap Quote + /// + /// + /// Get a quote for swapping tokens on Solana. This endpoint returns the expected output amount and swap details without executing the transaction. + ///
+ ///
**Important**: Swaps are only available on Solana mainnet. + ///
+ ///
**Authentication**: This endpoint requires backend authentication using the x-secret-key header. + ///
+ /// Solana wallet address that will execute the swap. + /// Input token mint address (the token being sold). + /// Output token mint address (the token being purchased). + /// Amount of input token to swap, expressed in the smallest unit (e.g., lamports for SOL). + /// Quote fetched successfully. Returns expected output amount and swap details. + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task GetSwapQuoteAsync(string address, string tokenIn, string tokenOut, string amount, string chainId, System.Threading.CancellationToken cancellationToken) + { + if (address == null) + throw new System.ArgumentNullException("address"); + + if (tokenIn == null) + throw new System.ArgumentNullException("tokenIn"); + + if (tokenOut == null) + throw new System.ArgumentNullException("tokenOut"); + + if (amount == null) + throw new System.ArgumentNullException("amount"); + + if (chainId == null) + throw new System.ArgumentNullException("chainId"); + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + request_.Method = new System.Net.Http.HttpMethod("GET"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + var urlBuilder_ = new System.Text.StringBuilder(); + if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl); + // Operation Path: "v1/solana/swap" + urlBuilder_.Append("v1/solana/swap"); + urlBuilder_.Append('?'); + urlBuilder_.Append(System.Uri.EscapeDataString("address")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(address, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + urlBuilder_.Append(System.Uri.EscapeDataString("tokenIn")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(tokenIn, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + urlBuilder_.Append(System.Uri.EscapeDataString("tokenOut")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(tokenOut, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + urlBuilder_.Append(System.Uri.EscapeDataString("amount")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(amount, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + urlBuilder_.Append(System.Uri.EscapeDataString("chainId")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(chainId, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + urlBuilder_.Length--; + + PrepareRequest(client_, request_, urlBuilder_); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + PrepareRequest(client_, request_, url_); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = new System.Collections.Generic.Dictionary>(); + foreach (var item_ in response_.Headers) + headers_[item_.Key] = item_.Value; + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + ProcessResponse(client_, response_); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 400) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Invalid request parameters or quote API error. Check the error message for details.", status_, responseText_, headers_, null); + } + else + if (status_ == 401) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Authentication required. Include x-secret-key or Authorization headers.", status_, responseText_, headers_, null); + } + else + if (status_ == 500) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Internal server error occurred while fetching the quote.", status_, responseText_, headers_, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// Swap Solana Tokens + /// + /// + /// Execute a token swap on Solana. This endpoint handles the full swap flow: fetching the optimal swap route, signing the transaction with your server wallet, executing the swap, and polling until confirmation. + ///
+ ///
The swap uses aggregated liquidity across Solana DEXs to provide optimal routing. The endpoint waits for the transaction to reach 'confirmed' or 'finalized' status before returning (up to 30 seconds). + ///
+ ///
**Important**: Swaps are only available on Solana mainnet. + ///
+ ///
**Authentication**: This endpoint requires backend authentication using the x-secret-key header. + ///
+ /// Swap executed and confirmed successfully. Returns the transaction signature and swap details including input/output amounts. + /// A server side error occurred. + public virtual System.Threading.Tasks.Task SwapSolanaTokensAsync(Body27 body) + { + return SwapSolanaTokensAsync(body, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Swap Solana Tokens + /// + /// + /// Execute a token swap on Solana. This endpoint handles the full swap flow: fetching the optimal swap route, signing the transaction with your server wallet, executing the swap, and polling until confirmation. + ///
+ ///
The swap uses aggregated liquidity across Solana DEXs to provide optimal routing. The endpoint waits for the transaction to reach 'confirmed' or 'finalized' status before returning (up to 30 seconds). + ///
+ ///
**Important**: Swaps are only available on Solana mainnet. + ///
+ ///
**Authentication**: This endpoint requires backend authentication using the x-secret-key header. + ///
+ /// Swap executed and confirmed successfully. Returns the transaction signature and swap details including input/output amounts. + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task SwapSolanaTokensAsync(Body27 body, System.Threading.CancellationToken cancellationToken) + { + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + var json_ = Newtonsoft.Json.JsonConvert.SerializeObject(body, JsonSerializerSettings); + var content_ = new System.Net.Http.StringContent(json_); + content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json"); + request_.Content = content_; + request_.Method = new System.Net.Http.HttpMethod("POST"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + var urlBuilder_ = new System.Text.StringBuilder(); + if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl); + // Operation Path: "v1/solana/swap" + urlBuilder_.Append("v1/solana/swap"); + + PrepareRequest(client_, request_, urlBuilder_); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + PrepareRequest(client_, request_, url_); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = new System.Collections.Generic.Dictionary>(); + foreach (var item_ in response_.Headers) + headers_[item_.Key] = item_.Value; + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + ProcessResponse(client_, response_); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 400) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Invalid request parameters, swap API error, or transaction failed on-chain. Check the error message for details.", status_, responseText_, headers_, null); + } + else + if (status_ == 401) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Authentication required. Include x-secret-key or Authorization headers.", status_, responseText_, headers_, null); + } + else + if (status_ == 500) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Internal server error occurred during swap execution or confirmation.", status_, responseText_, headers_, null); + } + else + if (status_ == 504) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Transaction was not confirmed within the 30 second timeout period. The swap may still be pending or dropped.", status_, responseText_, headers_, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// Get Solana Transaction + /// + /// + /// Retrieve the status and details of a queued Solana transaction using the identifier returned when the transaction was submitted. + ///
+ ///
**Authentication**: This endpoint requires backend authentication using the x-secret-key header. The secret key should never be exposed publicly. + ///
+ /// Identifier returned when the transaction was queued. + /// Transaction status retrieved successfully. + /// A server side error occurred. + public virtual System.Threading.Tasks.Task GetSolanaTransactionAsync(string transactionId) + { + return GetSolanaTransactionAsync(transactionId, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Get Solana Transaction + /// + /// + /// Retrieve the status and details of a queued Solana transaction using the identifier returned when the transaction was submitted. + ///
+ ///
**Authentication**: This endpoint requires backend authentication using the x-secret-key header. The secret key should never be exposed publicly. + ///
+ /// Identifier returned when the transaction was queued. + /// Transaction status retrieved successfully. + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task GetSolanaTransactionAsync(string transactionId, System.Threading.CancellationToken cancellationToken) + { + if (transactionId == null) + throw new System.ArgumentNullException("transactionId"); + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + request_.Method = new System.Net.Http.HttpMethod("GET"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + var urlBuilder_ = new System.Text.StringBuilder(); + if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl); + // Operation Path: "v1/solana/transactions/:transactionId" + urlBuilder_.Append("v1/solana/transactions/:transactionId"); + + PrepareRequest(client_, request_, urlBuilder_); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + PrepareRequest(client_, request_, url_); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = new System.Collections.Generic.Dictionary>(); + foreach (var item_ in response_.Headers) + headers_[item_.Key] = item_.Value; + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + ProcessResponse(client_, response_); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 401) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Authentication required. Include x-secret-key or Authorization headers.", status_, responseText_, headers_, null); + } + else + if (status_ == 404) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Transaction not found. The identifier may be invalid or expired.", status_, responseText_, headers_, null); + } + else + if (status_ == 500) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Internal server error occurred while fetching transaction status.", status_, responseText_, headers_, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// Chat + /// + /// + /// Thirdweb AI chat completion API (BETA). + ///
+ ///
Send natural language queries to interact with any EVM chain, read data, prepare transactions, swap tokens, deploy contracts, payments and more. + ///
+ ///
Compatible with standard OpenAI API chat completion format, can be used raw or with any popular AI library. + ///
+ ///
**Authentication**: Pass `x-client-id` header for frontend usage from allowlisted origins or `x-secret-key` for backend usage. + ///
+ /// AI assistant response or SSE stream when stream=true + /// A server side error occurred. + public virtual System.Threading.Tasks.Task ChatAsync(Body28 body) + { + return ChatAsync(body, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Chat + /// + /// + /// Thirdweb AI chat completion API (BETA). + ///
+ ///
Send natural language queries to interact with any EVM chain, read data, prepare transactions, swap tokens, deploy contracts, payments and more. + ///
+ ///
Compatible with standard OpenAI API chat completion format, can be used raw or with any popular AI library. + ///
+ ///
**Authentication**: Pass `x-client-id` header for frontend usage from allowlisted origins or `x-secret-key` for backend usage. + ///
+ /// AI assistant response or SSE stream when stream=true + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task ChatAsync(Body28 body, System.Threading.CancellationToken cancellationToken) + { + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + var json_ = Newtonsoft.Json.JsonConvert.SerializeObject(body, JsonSerializerSettings); + var content_ = new System.Net.Http.StringContent(json_); + content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json"); + request_.Content = content_; + request_.Method = new System.Net.Http.HttpMethod("POST"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + var urlBuilder_ = new System.Text.StringBuilder(); + if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl); + // Operation Path: "ai/chat" + urlBuilder_.Append("ai/chat"); + + PrepareRequest(client_, request_, urlBuilder_); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + PrepareRequest(client_, request_, url_); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = new System.Collections.Generic.Dictionary>(); + foreach (var item_ in response_.Headers) + headers_[item_.Key] = item_.Value; + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + ProcessResponse(client_, response_); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + protected struct ObjectResponseResult + { + public ObjectResponseResult(T responseObject, string responseText) + { + this.Object = responseObject; + this.Text = responseText; + } + + public T Object { get; } + + public string Text { get; } + } + + public bool ReadResponseAsString { get; set; } + + protected virtual async System.Threading.Tasks.Task> ReadObjectResponseAsync(System.Net.Http.HttpResponseMessage response, System.Collections.Generic.IReadOnlyDictionary> headers, System.Threading.CancellationToken cancellationToken) + { + if (response == null || response.Content == null) + { + return new ObjectResponseResult(default(T), string.Empty); + } + + if (ReadResponseAsString) + { + var responseText = await response.Content.ReadAsStringAsync().ConfigureAwait(false); + try + { + var typedBody = Newtonsoft.Json.JsonConvert.DeserializeObject(responseText, JsonSerializerSettings); + return new ObjectResponseResult(typedBody, responseText); + } + catch (Newtonsoft.Json.JsonException exception) + { + var message = "Could not deserialize the response body string as " + typeof(T).FullName + "."; + throw new ApiException(message, (int)response.StatusCode, responseText, headers, exception); + } + } + else + { + try + { + using (var responseStream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false)) + using (var streamReader = new System.IO.StreamReader(responseStream)) + using (var jsonTextReader = new Newtonsoft.Json.JsonTextReader(streamReader)) + { + var serializer = Newtonsoft.Json.JsonSerializer.Create(JsonSerializerSettings); + var typedBody = serializer.Deserialize(jsonTextReader); + return new ObjectResponseResult(typedBody, string.Empty); + } + } + catch (Newtonsoft.Json.JsonException exception) + { + var message = "Could not deserialize the response body stream as " + typeof(T).FullName + "."; + throw new ApiException(message, (int)response.StatusCode, string.Empty, headers, exception); + } + } + } + + private string ConvertToString(object value, System.Globalization.CultureInfo cultureInfo) + { + if (value == null) + { + return ""; + } + + if (value is System.Enum) + { + var name = System.Enum.GetName(value.GetType(), value); + if (name != null) + { + var field = System.Reflection.IntrospectionExtensions.GetTypeInfo(value.GetType()).GetDeclaredField(name); + if (field != null) + { + var attribute = System.Reflection.CustomAttributeExtensions.GetCustomAttribute(field, typeof(System.Runtime.Serialization.EnumMemberAttribute)) + as System.Runtime.Serialization.EnumMemberAttribute; + if (attribute != null) + { + return attribute.Value != null ? attribute.Value : name; + } + } + + var converted = System.Convert.ToString(System.Convert.ChangeType(value, System.Enum.GetUnderlyingType(value.GetType()), cultureInfo)); + return converted == null ? string.Empty : converted; + } + } + else if (value is bool) + { + return System.Convert.ToString((bool)value, cultureInfo).ToLowerInvariant(); + } + else if (value is byte[]) + { + return System.Convert.ToBase64String((byte[]) value); + } + else if (value is string[]) + { + return string.Join(",", (string[])value); + } + else if (value.GetType().IsArray) + { + var valueArray = (System.Array)value; + var valueTextArray = new string[valueArray.Length]; + for (var i = 0; i < valueArray.Length; i++) + { + valueTextArray[i] = ConvertToString(valueArray.GetValue(i), cultureInfo); + } + return string.Join(",", valueTextArray); + } + + var result = System.Convert.ToString(value, cultureInfo); + return result == null ? "" : result; + } + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Body + { + /// + /// Authentication method: SMS + /// + [Newtonsoft.Json.JsonProperty("method", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] + public BodyMethod Method { get; set; } + + /// + /// Phone number in E.164 format (e.g., +1234567890) + /// + [Newtonsoft.Json.JsonProperty("phone", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Phone { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Body2 + { + /// + /// Authentication method: SMS + /// + [Newtonsoft.Json.JsonProperty("method", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] + public Body2Method Method { get; set; } + + /// + /// Phone number that received the code + /// + [Newtonsoft.Json.JsonProperty("phone", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Phone { get; set; } + + /// + /// Verification code received via SMS + /// + [Newtonsoft.Json.JsonProperty("code", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Code { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + /// + /// Request body for linking an additional authentication method or external wallet to the currently authenticated user. + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Body3 + { + /// + /// Authentication token for the account that should be linked to the currently authenticated wallet. + /// + [Newtonsoft.Json.JsonProperty("accountAuthTokenToConnect", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public string AccountAuthTokenToConnect { get; set; } + + } + + /// + /// Request body for unlinking an authentication provider or wallet from the currently authenticated user. + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Body4 + { + /// + /// Authentication provider type to disconnect + /// + [Newtonsoft.Json.JsonProperty("type", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] + public Body4Type Type { get; set; } + + /// + /// Identifiers for the provider profile that should be disconnected + /// + [Newtonsoft.Json.JsonProperty("details", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Details Details { get; set; } = new Details(); + + /// + /// If true, allows the account to be deleted when unlinking removes the last authentication method. Defaults to false when omitted. + /// + [Newtonsoft.Json.JsonProperty("allowAccountDeletion", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public bool AllowAccountDeletion { get; set; } = false; + + } + + /// + /// The OAuth provider to use + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public enum Provider + { + + [System.Runtime.Serialization.EnumMember(Value = @"google")] + Google = 0, + + [System.Runtime.Serialization.EnumMember(Value = @"apple")] + Apple = 1, + + [System.Runtime.Serialization.EnumMember(Value = @"facebook")] + Facebook = 2, + + [System.Runtime.Serialization.EnumMember(Value = @"discord")] + Discord = 3, + + [System.Runtime.Serialization.EnumMember(Value = @"farcaster")] + Farcaster = 4, + + [System.Runtime.Serialization.EnumMember(Value = @"telegram")] + Telegram = 5, + + [System.Runtime.Serialization.EnumMember(Value = @"line")] + Line = 6, + + [System.Runtime.Serialization.EnumMember(Value = @"x")] + X = 7, + + [System.Runtime.Serialization.EnumMember(Value = @"coinbase")] + Coinbase = 8, + + [System.Runtime.Serialization.EnumMember(Value = @"github")] + Github = 9, + + [System.Runtime.Serialization.EnumMember(Value = @"twitch")] + Twitch = 10, + + [System.Runtime.Serialization.EnumMember(Value = @"steam")] + Steam = 11, + + [System.Runtime.Serialization.EnumMember(Value = @"tiktok")] + Tiktok = 12, + + [System.Runtime.Serialization.EnumMember(Value = @"epic")] + Epic = 13, + + } + + /// + /// Request body for pre-generating a wallet + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Body5 + { + [Newtonsoft.Json.JsonProperty("type", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] + public Body5Type Type { get; set; } + + /// + /// A valid Ethereum address (0x-prefixed hex string) or ENS name (e.g., vitalik.eth). + /// + [Newtonsoft.Json.JsonProperty("walletAddress", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string WalletAddress { get; set; } + + [Newtonsoft.Json.JsonProperty("email", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Email { get; set; } + + [Newtonsoft.Json.JsonProperty("phone", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Phone { get; set; } + + [Newtonsoft.Json.JsonProperty("userId", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string UserId { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + /// + /// Request body for creating a wallet + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Body6 + { + /// + /// Unique identifier for wallet creation or retrieval. Can be user ID, email, or any unique string. The same identifier will always return the same wallet. + /// + [Newtonsoft.Json.JsonProperty("identifier", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public string Identifier { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + /// + /// Sort order: 'asc' for ascending, 'desc' for descending + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public enum SortOrder + { + + [System.Runtime.Serialization.EnumMember(Value = @"asc")] + Asc = 0, + + [System.Runtime.Serialization.EnumMember(Value = @"desc")] + Desc = 1, + + } + + /// + /// Whether to include token metadata (default: true). + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public enum Metadata + { + + [System.Runtime.Serialization.EnumMember(Value = @"true")] + True = 0, + + [System.Runtime.Serialization.EnumMember(Value = @"false")] + False = 1, + + } + + /// + /// Whether to resolve metadata links to fetch additional token information (default: true). + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public enum ResolveMetadataLinks + { + + [System.Runtime.Serialization.EnumMember(Value = @"true")] + True = 0, + + [System.Runtime.Serialization.EnumMember(Value = @"false")] + False = 1, + + } + + /// + /// Whether to include tokens marked as spam (default: false). + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public enum IncludeSpam + { + + [System.Runtime.Serialization.EnumMember(Value = @"true")] + True = 0, + + [System.Runtime.Serialization.EnumMember(Value = @"false")] + False = 1, + + } + + /// + /// Whether to include native tokens (e.g., ETH, MATIC) in the results (default: true). + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public enum IncludeNative + { + + [System.Runtime.Serialization.EnumMember(Value = @"true")] + True = 0, + + [System.Runtime.Serialization.EnumMember(Value = @"false")] + False = 1, + + } + + /// + /// Field to sort tokens by: 'balance' for token balance, 'token_address' for token address, 'token_price' for token price, 'usd_value' for USD value (default: usd_value). + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public enum SortBy + { + + [System.Runtime.Serialization.EnumMember(Value = @"balance")] + Balance = 0, + + [System.Runtime.Serialization.EnumMember(Value = @"token_address")] + Token_address = 1, + + [System.Runtime.Serialization.EnumMember(Value = @"token_price")] + Token_price = 2, + + [System.Runtime.Serialization.EnumMember(Value = @"usd_value")] + Usd_value = 3, + + } + + /// + /// Sort order: 'asc' for ascending, 'desc' for descending (default: desc). + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public enum SortOrder2 + { + + [System.Runtime.Serialization.EnumMember(Value = @"asc")] + Asc = 0, + + [System.Runtime.Serialization.EnumMember(Value = @"desc")] + Desc = 1, + + } + + /// + /// Whether to include tokens without price data (default: true). + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public enum IncludeWithoutPrice + { + + [System.Runtime.Serialization.EnumMember(Value = @"true")] + True = 0, + + [System.Runtime.Serialization.EnumMember(Value = @"false")] + False = 1, + + } + + /// + /// Request body for signing a message + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Body7 + { + /// + /// The wallet address or ENS name that will sign the message. + /// + [Newtonsoft.Json.JsonProperty("from", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string From { get; set; } + + /// + /// The blockchain network identifier where the signing will occur. Common values include: 1 (Ethereum), 137 (Polygon), 56 (BSC). + /// + [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Always)] + public int ChainId { get; set; } + + /// + /// The message to be signed. Can be plain text or hexadecimal format (starting with 0x). The format is automatically detected. + /// + [Newtonsoft.Json.JsonProperty("message", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Message { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + /// + /// Request body for signing typed data + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Body8 + { + /// + /// The wallet address or ENS name that will sign the typed data. + /// + [Newtonsoft.Json.JsonProperty("from", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string From { get; set; } + + /// + /// The blockchain network identifier for EIP-712 domain separation. + /// + [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Always)] + public int ChainId { get; set; } + + /// + /// EIP-712 domain separator containing contract and chain information for signature verification. + /// + [Newtonsoft.Json.JsonProperty("domain", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Domain Domain { get; set; } = new Domain(); + + /// + /// The structured data to be signed, matching the defined types schema. + /// + [Newtonsoft.Json.JsonProperty("message", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.IDictionary Message { get; set; } = new System.Collections.Generic.Dictionary(); + + /// + /// The primary type name from the types object that defines the main structure being signed. + /// + [Newtonsoft.Json.JsonProperty("primaryType", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string PrimaryType { get; set; } + + /// + /// Type definitions for the structured data, following EIP-712 specifications. + /// + [Newtonsoft.Json.JsonProperty("types", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.IDictionary> Types { get; set; } = new System.Collections.Generic.Dictionary>(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + /// + /// Request body for sending tokens to multiple recipients. Supports native tokens, ERC20, ERC721, and ERC1155 transfers based on the provided parameters. + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Body9 + { + /// + /// The wallet address or ENS name that will send the tokens. If omitted, the project wallet will be used if available. + /// + [Newtonsoft.Json.JsonProperty("from", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string From { get; set; } + + /// + /// The blockchain network identifier where the transfer will be executed. + /// + [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Always)] + public int ChainId { get; set; } + + /// + /// Array of recipients and quantities. Maximum 100 recipients per request. + /// + [Newtonsoft.Json.JsonProperty("recipients", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + [System.ComponentModel.DataAnnotations.MinLength(1)] + [System.ComponentModel.DataAnnotations.MaxLength(100)] + public System.Collections.Generic.ICollection Recipients { get; set; } = new System.Collections.ObjectModel.Collection(); + + /// + /// The token contract address. Omit for native token (ETH, MATIC, etc.) transfers. + /// + [Newtonsoft.Json.JsonProperty("tokenAddress", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string TokenAddress { get; set; } + + /// + /// The token ID for NFT transfers (ERC721/ERC1155). Required for NFT transfers. + /// + [Newtonsoft.Json.JsonProperty("tokenId", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string TokenId { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + /// + /// Contract deployment specification for raw bytecode deployment. + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Body10 + { + /// + /// The blockchain network identifier. Common values include: 1 (Ethereum), 8453 (Base), 137 (Polygon), 56 (BSC), 43114 (Avalanche), 42161 (Arbitrum), 10 (Optimism). + /// + [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Always)] + public int ChainId { get; set; } + + /// + /// The wallet address or ENS name that will deploy the contract. If omitted, the project wallet will be used if available. + /// + [Newtonsoft.Json.JsonProperty("from", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string From { get; set; } + + /// + /// The contract bytecode as a hex string. + /// + [Newtonsoft.Json.JsonProperty("bytecode", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Bytecode { get; set; } + + /// + /// The contract ABI array. + /// + [Newtonsoft.Json.JsonProperty("abi", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.ICollection Abi { get; set; } = new System.Collections.ObjectModel.Collection(); + + /// + /// Object containing constructor parameters for the contract deployment (e.g., { param1: 'value1', param2: 123 }). + /// + [Newtonsoft.Json.JsonProperty("constructorParams", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public System.Collections.Generic.IDictionary ConstructorParams { get; set; } + + /// + /// Optional salt value for deterministic contract deployment. + /// + [Newtonsoft.Json.JsonProperty("salt", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Salt { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Body11 + { + /// + /// Array of contract method calls to execute. Each call specifies a contract address, method signature, and optional parameters. + /// + [Newtonsoft.Json.JsonProperty("calls", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + [System.ComponentModel.DataAnnotations.MinLength(1)] + public System.Collections.Generic.ICollection Calls { get; set; } = new System.Collections.ObjectModel.Collection(); + + /// + /// The blockchain network identifier. Common values include: 1 (Ethereum), 8453 (Base), 137 (Polygon), 56 (BSC), 43114 (Avalanche), 42161 (Arbitrum), 10 (Optimism). + /// + [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Always)] + public int ChainId { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Body12 + { + /// + /// Array of contract method calls to execute. Each call specifies a contract address, method signature, and optional parameters. + /// + [Newtonsoft.Json.JsonProperty("calls", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + [System.ComponentModel.DataAnnotations.MinLength(1)] + public System.Collections.Generic.ICollection Calls { get; set; } = new System.Collections.ObjectModel.Collection(); + + /// + /// The blockchain network identifier. Common values include: 1 (Ethereum), 8453 (Base), 137 (Polygon), 56 (BSC), 43114 (Avalanche), 42161 (Arbitrum), 10 (Optimism). + /// + [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Always)] + public int ChainId { get; set; } + + /// + /// The wallet address or ENS name that will send the transaction. If omitted, the project wallet will be used if available. + /// + [Newtonsoft.Json.JsonProperty("from", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string From { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + /// + /// Sort order: 'asc' for ascending, 'desc' for descending + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public enum SortOrder3 + { + + [System.Runtime.Serialization.EnumMember(Value = @"asc")] + Asc = 0, + + [System.Runtime.Serialization.EnumMember(Value = @"desc")] + Desc = 1, + + } + + /// + /// Sort order: 'asc' for ascending, 'desc' for descending + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public enum SortOrder4 + { + + [System.Runtime.Serialization.EnumMember(Value = @"asc")] + Asc = 0, + + [System.Runtime.Serialization.EnumMember(Value = @"desc")] + Desc = 1, + + } + + /// + /// Request object containing an array of encoded blockchain transactions to execute. All transactions must use the same from address and chainId. For contract calls, use /v1/contracts/write. For native token transfers, use /v1/wallets/send. + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Body13 + { + /// + /// The blockchain network identifier where all transactions will be executed. + /// + [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Always)] + public int ChainId { get; set; } + + /// + /// The wallet address or ENS name that will send the transaction. If omitted, the project wallet will be used if available. + /// + [Newtonsoft.Json.JsonProperty("from", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string From { get; set; } + + /// + /// Array of encoded blockchain transactions to execute. All transactions will use the same from address and chainId. + /// + [Newtonsoft.Json.JsonProperty("transactions", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + [System.ComponentModel.DataAnnotations.MinLength(1)] + public System.Collections.Generic.ICollection Transactions { get; set; } = new System.Collections.ObjectModel.Collection(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + /// + /// Request to create a product to be purchased. Users can purchase the product via hosted UI (link is returned), a transaction execution referencing the product ID, or embedded widgets with the product ID. + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Body14 + { + /// + /// The name of the product + /// + [Newtonsoft.Json.JsonProperty("name", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Name { get; set; } + + /// + /// The description of the product + /// + [Newtonsoft.Json.JsonProperty("description", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Description { get; set; } + + /// + /// The URL of the product image + /// + [Newtonsoft.Json.JsonProperty("imageUrl", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string ImageUrl { get; set; } + + /// + /// The token to purchase + /// + [Newtonsoft.Json.JsonProperty("token", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Token Token { get; set; } = new Token(); + + /// + /// The wallet address or ENS name that will receive the payment for the product + /// + [Newtonsoft.Json.JsonProperty("recipient", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Recipient { get; set; } + + /// + /// App specific purchase data for this payment + /// + [Newtonsoft.Json.JsonProperty("purchaseData", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public object PurchaseData { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + /// + /// Request to purchase a product. The system will automatically use your wallet balance to purchase the specified product. + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Body15 + { + /// + /// The wallet address or ENS name that will purchase the product. If omitted, the project wallet will be used if available. + /// + [Newtonsoft.Json.JsonProperty("from", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string From { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + /// + /// Request body for x402 facilitator 'verify' + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Body16 + { + [Newtonsoft.Json.JsonProperty("paymentPayload", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public PaymentPayload PaymentPayload { get; set; } = new PaymentPayload(); + + [Newtonsoft.Json.JsonProperty("paymentRequirements", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public PaymentRequirements PaymentRequirements { get; set; } = new PaymentRequirements(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + /// + /// Request body for x402 facilitator 'settle' + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Body17 + { + /// + /// Exact x402 payment payload to settle + /// + [Newtonsoft.Json.JsonProperty("paymentPayload", Required = Newtonsoft.Json.Required.Always)] + public PaymentPayload2 PaymentPayload { get; set; } + + [Newtonsoft.Json.JsonProperty("paymentRequirements", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public PaymentRequirements2 PaymentRequirements { get; set; } = new PaymentRequirements2(); + + /// + /// The event to wait for to determina a transaction confirmation. 'simulated' will only simulate the transaction (fastest), 'submitted' will wait till the transaction is submitted, and 'confirmed' will wait for the transaction to be fully confirmed on chain (slowest). Defaults to 'confirmed'. + /// + [Newtonsoft.Json.JsonProperty("waitUntil", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] + public Body17WaitUntil WaitUntil { get; set; } = Thirdweb.Api.Body17WaitUntil.Confirmed; + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + /// + /// Chain ID in CAIP-2 format (e.g., 'eip155:1' for Ethereum, 'solana:mainnet' for Solana). Also accepts legacy numeric IDs for EVM chains. + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class ChainId + { + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + /// + /// The method to use, defaults to GET + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Method + { + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + /// + /// Chain ID to use for the payment. Supports CAIP-2 strings (e.g., 'eip155:1', 'solana:mainnet') or legacy numeric EVM IDs. + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class ChainId2 + { + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public enum SortBy2 + { + + [System.Runtime.Serialization.EnumMember(Value = @"createdAt")] + CreatedAt = 0, + + [System.Runtime.Serialization.EnumMember(Value = @"totalRequests")] + TotalRequests = 1, + + [System.Runtime.Serialization.EnumMember(Value = @"totalVolume")] + TotalVolume = 2, + + [System.Runtime.Serialization.EnumMember(Value = @"price")] + Price = 3, + + [System.Runtime.Serialization.EnumMember(Value = @"uniqueBuyers")] + UniqueBuyers = 4, + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public enum SortOrder5 + { + + [System.Runtime.Serialization.EnumMember(Value = @"asc")] + Asc = 0, + + [System.Runtime.Serialization.EnumMember(Value = @"desc")] + Desc = 1, + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Body18 + { + /// + /// The URL of the resource being protected by the payment + /// + [Newtonsoft.Json.JsonProperty("resourceUrl", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public System.Uri ResourceUrl { get; set; } + + /// + /// The HTTP method used to access the resource + /// + [Newtonsoft.Json.JsonProperty("method", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public Method2 Method { get; set; } + + /// + /// The blockchain network where the payment should be processed + /// + [Newtonsoft.Json.JsonProperty("network", Required = Newtonsoft.Json.Required.Always)] + public Network Network { get; set; } + + /// + /// The price for accessing the resource - either a USD amount (e.g., '$0.10') or a specific token amount + /// + [Newtonsoft.Json.JsonProperty("price", Required = Newtonsoft.Json.Required.Always)] + public Price Price { get; set; } + + /// + /// Optional configuration for the payment middleware route + /// + [Newtonsoft.Json.JsonProperty("routeConfig", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public RouteConfig RouteConfig { get; set; } + + /// + /// Your server wallet address, defaults to the project server wallet address + /// + [Newtonsoft.Json.JsonProperty("serverWalletAddress", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string ServerWalletAddress { get; set; } + + /// + /// Optional recipient address to receive the payment if different from your facilitator server wallet address + /// + [Newtonsoft.Json.JsonProperty("recipientAddress", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string RecipientAddress { get; set; } + + /// + /// Optional extra data to be passed to in the payment requirements. + /// + [Newtonsoft.Json.JsonProperty("extraMetadata", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public System.Collections.Generic.IDictionary ExtraMetadata { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + /// + /// Request schema for creating a new ERC20 token + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Body19 + { + /// + /// The blockchain network identifier. Common values include: 1 (Ethereum), 8453 (Base), 137 (Polygon), 56 (BSC), 43114 (Avalanche), 42161 (Arbitrum), 10 (Optimism). + /// + [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Always)] + public int ChainId { get; set; } + + /// + /// Token name + /// + [Newtonsoft.Json.JsonProperty("name", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + [System.ComponentModel.DataAnnotations.StringLength(100, MinimumLength = 1)] + public string Name { get; set; } + + /// + /// Token symbol + /// + [Newtonsoft.Json.JsonProperty("symbol", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + [System.ComponentModel.DataAnnotations.StringLength(20, MinimumLength = 1)] + public string Symbol { get; set; } + + /// + /// Token description + /// + [Newtonsoft.Json.JsonProperty("description", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + [System.ComponentModel.DataAnnotations.StringLength(500, MinimumLength = 1)] + public string Description { get; set; } + + /// + /// Token image URL + /// + [Newtonsoft.Json.JsonProperty("imageUrl", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public System.Uri ImageUrl { get; set; } + + /// + /// Wallet address or ENS that will deploy the token. If omitted, the project wallet will be used if available. + /// + [Newtonsoft.Json.JsonProperty("from", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string From { get; set; } + + /// + /// The token owner address, if different from `from`. + /// + [Newtonsoft.Json.JsonProperty("owner", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Owner { get; set; } + + /// + /// A salt to deterministically generate the token address. + /// + [Newtonsoft.Json.JsonProperty("salt", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Salt { get; set; } + + /// + /// The maximum token supply. + /// + [Newtonsoft.Json.JsonProperty("maxSupply", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double MaxSupply { get; set; } = 1000000000D; + + /// + /// Setup this token for a sale. + /// + [Newtonsoft.Json.JsonProperty("sale", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public Sale Sale { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + /// + /// The fiat currency symbol + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public enum From + { + + [System.Runtime.Serialization.EnumMember(Value = @"USD")] + USD = 0, + + [System.Runtime.Serialization.EnumMember(Value = @"EUR")] + EUR = 1, + + [System.Runtime.Serialization.EnumMember(Value = @"GBP")] + GBP = 2, + + [System.Runtime.Serialization.EnumMember(Value = @"JPY")] + JPY = 3, + + [System.Runtime.Serialization.EnumMember(Value = @"KRW")] + KRW = 4, + + [System.Runtime.Serialization.EnumMember(Value = @"CNY")] + CNY = 5, + + [System.Runtime.Serialization.EnumMember(Value = @"INR")] + INR = 6, + + [System.Runtime.Serialization.EnumMember(Value = @"NOK")] + NOK = 7, + + [System.Runtime.Serialization.EnumMember(Value = @"SEK")] + SEK = 8, + + [System.Runtime.Serialization.EnumMember(Value = @"CHF")] + CHF = 9, + + [System.Runtime.Serialization.EnumMember(Value = @"AUD")] + AUD = 10, + + [System.Runtime.Serialization.EnumMember(Value = @"CAD")] + CAD = 11, + + [System.Runtime.Serialization.EnumMember(Value = @"NZD")] + NZD = 12, + + [System.Runtime.Serialization.EnumMember(Value = @"MXN")] + MXN = 13, + + [System.Runtime.Serialization.EnumMember(Value = @"BRL")] + BRL = 14, + + [System.Runtime.Serialization.EnumMember(Value = @"CLP")] + CLP = 15, + + [System.Runtime.Serialization.EnumMember(Value = @"CZK")] + CZK = 16, + + [System.Runtime.Serialization.EnumMember(Value = @"DKK")] + DKK = 17, + + [System.Runtime.Serialization.EnumMember(Value = @"HKD")] + HKD = 18, + + [System.Runtime.Serialization.EnumMember(Value = @"HUF")] + HUF = 19, + + [System.Runtime.Serialization.EnumMember(Value = @"IDR")] + IDR = 20, + + [System.Runtime.Serialization.EnumMember(Value = @"ILS")] + ILS = 21, + + [System.Runtime.Serialization.EnumMember(Value = @"ISK")] + ISK = 22, + + } + + /// + /// Request to swap tokens using the optimal route available. You can specify a tokenIn amount (if exact='input') or tokenOut amount (if exact='output'), but not both. The corresponding output or input amount will be returned as the quote. + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Body20 + { + /// + /// Whether to swap the exact input or output amount + /// + [Newtonsoft.Json.JsonProperty("exact", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] + public Body20Exact Exact { get; set; } = Thirdweb.Api.Body20Exact.Input; + + [Newtonsoft.Json.JsonProperty("tokenIn", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public TokenIn TokenIn { get; set; } = new TokenIn(); + + [Newtonsoft.Json.JsonProperty("tokenOut", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public TokenOut TokenOut { get; set; } = new TokenOut(); + + /// + /// The wallet address or ENS name that will execute the swap. If omitted, the project wallet will be used if available. + /// + [Newtonsoft.Json.JsonProperty("from", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string From { get; set; } + + /// + /// The slippage tolerance in basis points. Will be automatically calculated by default. + /// + [Newtonsoft.Json.JsonProperty("slippageToleranceBps", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double? SlippageToleranceBps { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + /// + /// Request payload for creating or fetching a Solana wallet by label. + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Body21 + { + /// + /// Unique label to identify the wallet. Used for retrieval and management. + /// + [Newtonsoft.Json.JsonProperty("label", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public string Label { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + /// + /// Request payload for signing an arbitrary Solana message. + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Body22 + { + /// + /// The Solana wallet address used for signing. + /// + [Newtonsoft.Json.JsonProperty("from", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + [System.ComponentModel.DataAnnotations.RegularExpression(@"^[1-9A-HJ-NP-Za-km-z]{32,44}$")] + public string From { get; set; } + + /// + /// Message to sign. Can be plain text or hexadecimal format (starting with 0x). The format is automatically detected. + /// + [Newtonsoft.Json.JsonProperty("message", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public string Message { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + /// + /// Request payload for signing a Solana transaction. Provide a serialized transaction or a set of instructions to be assembled server-side. + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Body23 + { + /// + /// The Solana wallet address that will sign the transaction. + /// + [Newtonsoft.Json.JsonProperty("from", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + [System.ComponentModel.DataAnnotations.RegularExpression(@"^[1-9A-HJ-NP-Za-km-z]{32,44}$")] + public string From { get; set; } + + /// + /// Solana network the transaction targets. Use solana:mainnet or solana:devnet. + /// + [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string ChainId { get; set; } + + /// + /// Base64 encoded Solana transaction to sign. + /// + [Newtonsoft.Json.JsonProperty("transaction", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.StringLength(int.MaxValue, MinimumLength = 1)] + public string Transaction { get; set; } + + /// + /// Instructions that will be assembled into a transaction before signing. + /// + [Newtonsoft.Json.JsonProperty("instructions", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.MinLength(1)] + public System.Collections.Generic.ICollection Instructions { get; set; } + + /// + /// Priority fee configuration applied via the compute budget program. + /// + [Newtonsoft.Json.JsonProperty("priorityFee", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public PriorityFee PriorityFee { get; set; } + + /// + /// Override the compute unit limit for the transaction via the compute budget program. + /// + [Newtonsoft.Json.JsonProperty("computeUnitLimit", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Range(0D, double.MaxValue)] + public int? ComputeUnitLimit { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + /// + /// Request payload for broadcasting a signed Solana transaction. Use the signedTransaction output from /v1/solana/sign-transaction. + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Body24 + { + /// + /// Solana network the signed transaction targets. Use solana:mainnet or solana:devnet. + /// + [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string ChainId { get; set; } + + /// + /// Base64 encoded signed transaction to broadcast to the Solana network. + /// + [Newtonsoft.Json.JsonProperty("signedTransaction", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public string SignedTransaction { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + /// + /// Request payload for transferring SOL or SPL tokens on Solana. + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Body25 + { + /// + /// Solana wallet address that will sign and submit the transfer. + /// + [Newtonsoft.Json.JsonProperty("from", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + [System.ComponentModel.DataAnnotations.RegularExpression(@"^[1-9A-HJ-NP-Za-km-z]{32,44}$")] + public string From { get; set; } + + /// + /// Destination Solana address. + /// + [Newtonsoft.Json.JsonProperty("to", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + [System.ComponentModel.DataAnnotations.RegularExpression(@"^[1-9A-HJ-NP-Za-km-z]{32,44}$")] + public string To { get; set; } + + /// + /// Amount to transfer expressed in base units (lamports for SOL or token decimals). + /// + [Newtonsoft.Json.JsonProperty("amount", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public string Amount { get; set; } + + /// + /// Solana network identifier in CAIP-2 format. Use "solana:mainnet" or "solana:devnet" for convenience, or full CAIP-2 format. + /// + [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string ChainId { get; set; } + + /// + /// Optional SPL token mint address. When omitted a native SOL transfer is performed. + /// + [Newtonsoft.Json.JsonProperty("tokenAddress", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.RegularExpression(@"^[1-9A-HJ-NP-Za-km-z]{32,44}$")] + public string TokenAddress { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + /// + /// Submit a Solana transaction made up of one or more instructions. + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Body26 + { + /// + /// Solana wallet address that will sign and submit the transaction. + /// + [Newtonsoft.Json.JsonProperty("from", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + [System.ComponentModel.DataAnnotations.RegularExpression(@"^[1-9A-HJ-NP-Za-km-z]{32,44}$")] + public string From { get; set; } + + /// + /// Solana network identifier in CAIP-2 format. Use "solana:mainnet" or "solana:devnet" for convenience, or full CAIP-2 format. + /// + [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string ChainId { get; set; } + + /// + /// Set of instructions executed sequentially in a single transaction. + /// + [Newtonsoft.Json.JsonProperty("instructions", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + [System.ComponentModel.DataAnnotations.MinLength(1)] + public System.Collections.Generic.ICollection Instructions { get; set; } = new System.Collections.ObjectModel.Collection(); + + /// + /// Priority fee configuration applied via the compute budget program. + /// + [Newtonsoft.Json.JsonProperty("priorityFee", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public PriorityFee2 PriorityFee { get; set; } + + /// + /// Override the compute unit limit via the compute budget program. + /// + [Newtonsoft.Json.JsonProperty("computeUnitLimit", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Range(0D, double.MaxValue)] + public int? ComputeUnitLimit { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + /// + /// Request payload for executing a token swap on Solana. The endpoint handles swap routing, transaction signing, execution, and confirmation polling. + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Body27 + { + /// + /// Solana wallet address that will execute the swap. + /// + [Newtonsoft.Json.JsonProperty("address", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + [System.ComponentModel.DataAnnotations.RegularExpression(@"^[1-9A-HJ-NP-Za-km-z]{32,44}$")] + public string Address { get; set; } + + /// + /// Input token mint address (the token being sold). + /// + [Newtonsoft.Json.JsonProperty("tokenIn", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + [System.ComponentModel.DataAnnotations.RegularExpression(@"^[1-9A-HJ-NP-Za-km-z]{32,44}$")] + public string TokenIn { get; set; } + + /// + /// Output token mint address (the token being purchased). + /// + [Newtonsoft.Json.JsonProperty("tokenOut", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + [System.ComponentModel.DataAnnotations.RegularExpression(@"^[1-9A-HJ-NP-Za-km-z]{32,44}$")] + public string TokenOut { get; set; } + + /// + /// Amount of input token to swap, expressed in the smallest unit (e.g., lamports for SOL). + /// + [Newtonsoft.Json.JsonProperty("amount", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public string Amount { get; set; } + + [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string ChainId { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + /// + /// Chat request + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Body28 + { + /// + /// Natural language query for the AI assistant + /// + [Newtonsoft.Json.JsonProperty("messages", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + [System.ComponentModel.DataAnnotations.MinLength(1)] + public System.Collections.Generic.ICollection Messages { get; set; } = new System.Collections.ObjectModel.Collection(); + + /// + /// Context for the AI assistant + /// + [Newtonsoft.Json.JsonProperty("context", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public Context Context { get; set; } + + /// + /// Enable server streaming of the AI response + /// + [Newtonsoft.Json.JsonProperty("stream", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public bool Stream { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Response + { + /// + /// Authentication method: SMS + /// + [Newtonsoft.Json.JsonProperty("method", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] + public ResponseMethod Method { get; set; } + + /// + /// Whether the SMS code was sent successfully + /// + [Newtonsoft.Json.JsonProperty("success", Required = Newtonsoft.Json.Required.Always)] + public bool Success { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + /// + /// Successful authentication response. Returns wallet address plus authentication tokens. + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Response2 + { + /// + /// Whether this is a newly created user/wallet + /// + [Newtonsoft.Json.JsonProperty("isNewUser", Required = Newtonsoft.Json.Required.Always)] + public bool IsNewUser { get; set; } + + /// + /// JWT authentication token for API access + /// + [Newtonsoft.Json.JsonProperty("token", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Token { get; set; } + + /// + /// Type of authentication completed + /// + [Newtonsoft.Json.JsonProperty("type", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Type { get; set; } + + /// + /// Unique identifier for the authenticated user + /// + [Newtonsoft.Json.JsonProperty("userId", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string UserId { get; set; } + + /// + /// The wallet address + /// + [Newtonsoft.Json.JsonProperty("walletAddress", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string WalletAddress { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + /// + /// Response returned after successfully linking an additional authentication provider. The response includes all linked profiles for the user. + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Response3 + { + /// + /// Updated list of authentication profiles linked to the wallet after the new account has been connected. + /// + [Newtonsoft.Json.JsonProperty("linkedAccounts", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.ICollection LinkedAccounts { get; set; } = new System.Collections.ObjectModel.Collection(); + + } + + /// + /// Response returned after successfully linking an additional authentication provider. The response includes all linked profiles for the user. + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Response4 + { + /// + /// Updated list of authentication profiles linked to the wallet after the new account has been connected. + /// + [Newtonsoft.Json.JsonProperty("linkedAccounts", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.ICollection LinkedAccounts { get; set; } = new System.Collections.ObjectModel.Collection(); + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Response5 + { + [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Result Result { get; set; } = new Result(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Response6 + { + [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Result2 Result { get; set; } = new Result2(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Response7 + { + [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Result3 Result { get; set; } = new Result3(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Response8 + { + [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Result4 Result { get; set; } = new Result4(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Response9 + { + [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Result5 Result { get; set; } = new Result5(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Response10 + { + [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.ICollection Result { get; set; } = new System.Collections.ObjectModel.Collection(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Response11 + { + [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Result6 Result { get; set; } = new Result6(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Response12 + { + [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Result7 Result { get; set; } = new Result7(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Response13 + { + [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Result8 Result { get; set; } = new Result8(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Response14 + { + [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Result9 Result { get; set; } = new Result9(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Response15 + { + [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Result10 Result { get; set; } = new Result10(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Response16 + { + [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Result11 Result { get; set; } = new Result11(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Response17 + { + [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Result12 Result { get; set; } = new Result12(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Response18 + { + [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Result13 Result { get; set; } = new Result13(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Response19 + { + /// + /// Array of results corresponding to each contract read call. Results are returned in the same order as the input calls. + /// + [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.ICollection Result { get; set; } = new System.Collections.ObjectModel.Collection(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Response20 + { + [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Result15 Result { get; set; } = new Result15(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + /// + /// Payment required response when user has insufficient funds. Contains a quote for completing the purchase. + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Response21 + { + [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Result16 Result { get; set; } = new Result16(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Response22 + { + [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Result17 Result { get; set; } = new Result17(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Response23 + { + [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Result18 Result { get; set; } = new Result18(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + /// + /// Contract metadata from the thirdweb contract metadata service. + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Response24 + { + [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Result19 Result { get; set; } = new Result19(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + /// + /// Contract ABI signatures in human-readable format. These signatures can be used directly with contract interaction methods. + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Response25 + { + /// + /// Array of human-readable ABI signatures including functions and events. Each signature is formatted as a string that can be used directly in contract read/write operations or event filtering. + /// + [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.ICollection Result { get; set; } = new System.Collections.ObjectModel.Collection(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Response26 + { + [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Result20 Result { get; set; } = new Result20(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Response27 + { + [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Result21 Result { get; set; } = new Result21(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Response28 + { + [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Result22 Result { get; set; } = new Result22(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + /// + /// Payment required response when user has insufficient funds. Contains a quote for completing the purchase. + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Response29 + { + [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Result23 Result { get; set; } = new Result23(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + /// + /// Successful payment creation response containing the payment ID and link to purchase the product + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Response30 + { + [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Result24 Result { get; set; } = new Result24(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Response31 + { + [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Result25 Result { get; set; } = new Result25(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + /// + /// Payment required response when user has insufficient funds. Contains a quote for completing the purchase. + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Response32 + { + [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Result26 Result { get; set; } = new Result26(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Response33 + { + /// + /// List of payments for the client + /// + [Newtonsoft.Json.JsonProperty("data", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.ICollection Data { get; set; } = new System.Collections.ObjectModel.Collection(); + + [Newtonsoft.Json.JsonProperty("meta", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Meta Meta { get; set; } = new Meta(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Response34 + { + [Newtonsoft.Json.JsonProperty("error", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Error { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Response35 + { + [Newtonsoft.Json.JsonProperty("error", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Error { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + /// + /// Response returned by x402 facilitator 'verify' + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Response36 + { + [Newtonsoft.Json.JsonProperty("isValid", Required = Newtonsoft.Json.Required.Always)] + public bool IsValid { get; set; } + + [Newtonsoft.Json.JsonProperty("invalidReason", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] + public Response36InvalidReason InvalidReason { get; set; } + + [Newtonsoft.Json.JsonProperty("payer", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public Payer Payer { get; set; } + + [Newtonsoft.Json.JsonProperty("fundWalletLink", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string FundWalletLink { get; set; } + + [Newtonsoft.Json.JsonProperty("errorMessage", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string ErrorMessage { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + /// + /// Response returned by x402 facilitator 'settle' + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Response37 + { + [Newtonsoft.Json.JsonProperty("success", Required = Newtonsoft.Json.Required.Always)] + public bool Success { get; set; } + + [Newtonsoft.Json.JsonProperty("errorReason", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] + public Response37ErrorReason ErrorReason { get; set; } + + [Newtonsoft.Json.JsonProperty("payer", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public Payer2 Payer { get; set; } + + [Newtonsoft.Json.JsonProperty("transaction", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + [System.ComponentModel.DataAnnotations.RegularExpression(@"^0x[a-fA-F0-9]{40}|[A-Za-z0-9][A-Za-z0-9-]{0,34}[A-Za-z0-9]$")] + public string Transaction { get; set; } + + [Newtonsoft.Json.JsonProperty("network", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] + public Response37Network Network { get; set; } + + [Newtonsoft.Json.JsonProperty("errorMessage", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string ErrorMessage { get; set; } + + [Newtonsoft.Json.JsonProperty("fundWalletLink", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string FundWalletLink { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + /// + /// Supported payment kinds for this facilitator + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Response38 + { + [Newtonsoft.Json.JsonProperty("kinds", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.ICollection Kinds { get; set; } = new System.Collections.ObjectModel.Collection(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + /// + /// Payment required response when user has insufficient funds. Contains a quote for completing the purchase. + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Response39 + { + [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Result27 Result { get; set; } = new Result27(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Response40 + { + [Newtonsoft.Json.JsonProperty("x402Version", Required = Newtonsoft.Json.Required.Always)] + public double X402Version { get; set; } + + [Newtonsoft.Json.JsonProperty("items", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.ICollection Items { get; set; } = new System.Collections.ObjectModel.Collection(); + + [Newtonsoft.Json.JsonProperty("pagination", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Pagination Pagination { get; set; } = new Pagination(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Response41 + { + [Newtonsoft.Json.JsonProperty("x402Version", Required = Newtonsoft.Json.Required.Always)] + public double X402Version { get; set; } + + [Newtonsoft.Json.JsonProperty("error", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Error { get; set; } + + [Newtonsoft.Json.JsonProperty("accepts", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.ICollection Accepts { get; set; } = new System.Collections.ObjectModel.Collection(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Response42 + { + [Newtonsoft.Json.JsonProperty("x402Version", Required = Newtonsoft.Json.Required.Always)] + public double X402Version { get; set; } + + [Newtonsoft.Json.JsonProperty("error", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Error { get; set; } + + [Newtonsoft.Json.JsonProperty("accepts", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.ICollection Accepts { get; set; } = new System.Collections.ObjectModel.Collection(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Response43 + { + /// + /// The in-progress deployment transaction ID. + /// + [Newtonsoft.Json.JsonProperty("transactionId", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string TransactionId { get; set; } + + /// + /// The address the token was deployed at + /// + [Newtonsoft.Json.JsonProperty("address", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Address { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Response44 + { + [Newtonsoft.Json.JsonProperty("pagination", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Pagination2 Pagination { get; set; } = new Pagination2(); + + [Newtonsoft.Json.JsonProperty("tokens", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.ICollection Tokens { get; set; } = new System.Collections.ObjectModel.Collection(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Response45 + { + [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Result28 Result { get; set; } = new Result28(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Response46 + { + /// + /// Blockchain networks that support cross-chain bridging + /// + [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.ICollection Result { get; set; } = new System.Collections.ObjectModel.Collection(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Response47 + { + [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Result30 Result { get; set; } = new Result30(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Response48 + { + /// + /// The conversion result - amount of crypto tokens for the fiat amount + /// + [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] + public double Result { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + /// + /// Successful token swap response containing executed transaction ID + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Response49 + { + [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Result31 Result { get; set; } = new Result31(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + /// + /// Payment required response when user has insufficient funds. Contains a quote for completing the purchase. + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Response50 + { + [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Result32 Result { get; set; } = new Result32(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Response51 + { + [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Result33 Result { get; set; } = new Result33(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Response52 + { + /// + /// Details for a Solana wallet in your project. + /// + [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Result34 Result { get; set; } = new Result34(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Response53 + { + /// + /// Details for a Solana wallet in your project. + /// + [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Result35 Result { get; set; } = new Result35(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Response54 + { + /// + /// Balance data for the requested Solana network. + /// + [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Result36 Result { get; set; } = new Result36(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Response55 + { + [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Result37 Result { get; set; } = new Result37(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Response56 + { + [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Result38 Result { get; set; } = new Result38(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Response57 + { + [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Result39 Result { get; set; } = new Result39(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Response58 + { + [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Result40 Result { get; set; } = new Result40(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Response59 + { + [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Result41 Result { get; set; } = new Result41(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Response60 + { + [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Result42 Result { get; set; } = new Result42(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Response61 + { + [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Result43 Result { get; set; } = new Result43(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + /// + /// Response containing the swap quote details. + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Response62 + { + [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Result44 Result { get; set; } = new Result44(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + /// + /// Response containing the confirmed swap transaction signature and swap details. + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Response63 + { + [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Result45 Result { get; set; } = new Result45(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Response64 + { + /// + /// Transaction metadata and status information. + /// + [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Result46 Result { get; set; } = new Result46(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + /// + /// Chat response + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Response65 + { + /// + /// The AI assistant's response + /// + [Newtonsoft.Json.JsonProperty("message", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Message { get; set; } + + [Newtonsoft.Json.JsonProperty("actions", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.ICollection Actions { get; set; } = new System.Collections.ObjectModel.Collection(); + + [Newtonsoft.Json.JsonProperty("session_id", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Session_id { get; set; } + + [Newtonsoft.Json.JsonProperty("request_id", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Request_id { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public enum BodyMethod + { + + [System.Runtime.Serialization.EnumMember(Value = @"sms")] + Sms = 0, + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public enum Body2Method + { + + [System.Runtime.Serialization.EnumMember(Value = @"sms")] + Sms = 0, + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public enum Body4Type + { + + [System.Runtime.Serialization.EnumMember(Value = @"apple")] + Apple = 0, + + [System.Runtime.Serialization.EnumMember(Value = @"coinbase")] + Coinbase = 1, + + [System.Runtime.Serialization.EnumMember(Value = @"discord")] + Discord = 2, + + [System.Runtime.Serialization.EnumMember(Value = @"email")] + Email = 3, + + [System.Runtime.Serialization.EnumMember(Value = @"facebook")] + Facebook = 4, + + [System.Runtime.Serialization.EnumMember(Value = @"farcaster")] + Farcaster = 5, + + [System.Runtime.Serialization.EnumMember(Value = @"github")] + Github = 6, + + [System.Runtime.Serialization.EnumMember(Value = @"google")] + Google = 7, + + [System.Runtime.Serialization.EnumMember(Value = @"guest")] + Guest = 8, + + [System.Runtime.Serialization.EnumMember(Value = @"line")] + Line = 9, + + [System.Runtime.Serialization.EnumMember(Value = @"passkey")] + Passkey = 10, + + [System.Runtime.Serialization.EnumMember(Value = @"phone")] + Phone = 11, + + [System.Runtime.Serialization.EnumMember(Value = @"siwe")] + Siwe = 12, + + [System.Runtime.Serialization.EnumMember(Value = @"steam")] + Steam = 13, + + [System.Runtime.Serialization.EnumMember(Value = @"telegram")] + Telegram = 14, + + [System.Runtime.Serialization.EnumMember(Value = @"twitch")] + Twitch = 15, + + [System.Runtime.Serialization.EnumMember(Value = @"x")] + X = 16, + + [System.Runtime.Serialization.EnumMember(Value = @"tiktok")] + Tiktok = 17, + + [System.Runtime.Serialization.EnumMember(Value = @"epic")] + Epic = 18, + + [System.Runtime.Serialization.EnumMember(Value = @"backend")] + Backend = 19, + + [System.Runtime.Serialization.EnumMember(Value = @"wallet")] + Wallet = 20, + + [System.Runtime.Serialization.EnumMember(Value = @"custom_auth_endpoint")] + Custom_auth_endpoint = 21, + + [System.Runtime.Serialization.EnumMember(Value = @"custom_jwt")] + Custom_jwt = 22, + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Details + { + [Newtonsoft.Json.JsonProperty("address", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Address { get; set; } + + /// + /// A valid Ethereum address (0x-prefixed hex string) or ENS name (e.g., vitalik.eth). + /// + [Newtonsoft.Json.JsonProperty("walletAddress", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string WalletAddress { get; set; } + + [Newtonsoft.Json.JsonProperty("email", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Email { get; set; } + + [Newtonsoft.Json.JsonProperty("phone", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Phone { get; set; } + + [Newtonsoft.Json.JsonProperty("id", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Id { get; set; } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public enum Body5Type + { + + [System.Runtime.Serialization.EnumMember(Value = @"google")] + Google = 0, + + [System.Runtime.Serialization.EnumMember(Value = @"apple")] + Apple = 1, + + [System.Runtime.Serialization.EnumMember(Value = @"facebook")] + Facebook = 2, + + [System.Runtime.Serialization.EnumMember(Value = @"discord")] + Discord = 3, + + [System.Runtime.Serialization.EnumMember(Value = @"email")] + Email = 4, + + [System.Runtime.Serialization.EnumMember(Value = @"phone")] + Phone = 5, + + [System.Runtime.Serialization.EnumMember(Value = @"custom_auth_endpoint")] + Custom_auth_endpoint = 6, + + [System.Runtime.Serialization.EnumMember(Value = @"custom_jwt")] + Custom_jwt = 7, + + [System.Runtime.Serialization.EnumMember(Value = @"siwe")] + Siwe = 8, + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Domain + { + /// + /// Chain ID as string for domain separation + /// + [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string ChainId { get; set; } + + /// + /// The domain name (e.g., token name) + /// + [Newtonsoft.Json.JsonProperty("name", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Name { get; set; } + + /// + /// Optional salt for additional entropy + /// + [Newtonsoft.Json.JsonProperty("salt", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Salt { get; set; } + + /// + /// The contract address that will verify this signature + /// + [Newtonsoft.Json.JsonProperty("verifyingContract", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string VerifyingContract { get; set; } + + /// + /// Domain version for signature compatibility + /// + [Newtonsoft.Json.JsonProperty("version", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Version { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Anonymous + { + /// + /// The field name + /// + [Newtonsoft.Json.JsonProperty("name", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Name { get; set; } + + /// + /// The Solidity type (e.g., 'address', 'uint256') + /// + [Newtonsoft.Json.JsonProperty("type", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Type { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Recipients + { + /// + /// The recipient wallet address or ENS name + /// + [Newtonsoft.Json.JsonProperty("address", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Address { get; set; } + + /// + /// The amount to send. For native tokens and ERC20: amount in wei/smallest unit. For ERC721: should be '1'. For ERC1155: the number of tokens to transfer. + /// + [Newtonsoft.Json.JsonProperty("quantity", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Quantity { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Calls + { + /// + /// The smart contract address or ENS name. + /// + [Newtonsoft.Json.JsonProperty("contractAddress", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string ContractAddress { get; set; } + + /// + /// The contract function signature to call (e.g., 'function approve(address spender, uint256 amount)' or `function balanceOf(address)`). Must start with 'function' followed by the function name and parameters as defined in the contract ABI. + /// + [Newtonsoft.Json.JsonProperty("method", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + [System.ComponentModel.DataAnnotations.RegularExpression(@"^function\s+\w+")] + public string Method { get; set; } + + /// + /// Array of parameters to pass to the contract method, in the correct order and format. + /// + [Newtonsoft.Json.JsonProperty("params", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public System.Collections.Generic.ICollection Params { get; set; } + + /// + /// Amount of native token to send with the transaction in wei. Required for payable methods. + /// + [Newtonsoft.Json.JsonProperty("value", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Value { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class calls + { + /// + /// The smart contract address or ENS name. + /// + [Newtonsoft.Json.JsonProperty("contractAddress", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string ContractAddress { get; set; } + + /// + /// The contract function signature to call (e.g., 'function approve(address spender, uint256 amount)' or `function balanceOf(address)`). Must start with 'function' followed by the function name and parameters as defined in the contract ABI. + /// + [Newtonsoft.Json.JsonProperty("method", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + [System.ComponentModel.DataAnnotations.RegularExpression(@"^function\s+\w+")] + public string Method { get; set; } + + /// + /// Array of parameters to pass to the contract method, in the correct order and format. + /// + [Newtonsoft.Json.JsonProperty("params", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public System.Collections.Generic.ICollection Params { get; set; } + + /// + /// Amount of native token to send with the transaction in wei. Required for payable methods. + /// + [Newtonsoft.Json.JsonProperty("value", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Value { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + /// + /// A blockchain transaction with pre-encoded data payload. For contract calls, use /v1/contracts/write. For native token transfers, use /v1/wallets/send. + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Transactions + { + /// + /// Transaction data in hexadecimal format for contract interactions or custom payloads. + /// + [Newtonsoft.Json.JsonProperty("data", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Data { get; set; } + + /// + /// The target address or ENS name for the transaction. + /// + [Newtonsoft.Json.JsonProperty("to", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string To { get; set; } + + /// + /// Amount of native token to send in wei (smallest unit). Use '0' or omit for non-value transactions. + /// + [Newtonsoft.Json.JsonProperty("value", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Value { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Token + { + /// + /// The token address to purchase (use 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE for native token) + /// + [Newtonsoft.Json.JsonProperty("address", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Address { get; set; } + + /// + /// The blockchain network where the token is located + /// + [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Always)] + public int ChainId { get; set; } + + /// + /// The amount of the token to purchase in wei. + /// + [Newtonsoft.Json.JsonProperty("amount", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Amount { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class PaymentPayload + { + [Newtonsoft.Json.JsonProperty("x402Version", Required = Newtonsoft.Json.Required.Always)] + public double X402Version { get; set; } + + [Newtonsoft.Json.JsonProperty("scheme", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] + public PaymentPayloadScheme Scheme { get; set; } + + /// + /// CAIP-2 blockchain identifier (e.g., 'eip155:1' for Ethereum, 'solana:4sGjMW1sUnHzSxGspuhpqLDx6wiyjNtZ' for Solana mainnet). Also accepts numeric EVM chain IDs (e.g., 1, 137) or aliases ('solana:mainnet', 'solana:devnet') for backward compatibility. + /// + [Newtonsoft.Json.JsonProperty("network", Required = Newtonsoft.Json.Required.Always)] + public Network2 Network { get; set; } + + [Newtonsoft.Json.JsonProperty("payload", Required = Newtonsoft.Json.Required.Always)] + public Payload Payload { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class PaymentRequirements + { + [Newtonsoft.Json.JsonProperty("scheme", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] + public PaymentRequirementsScheme Scheme { get; set; } + + /// + /// CAIP-2 blockchain identifier (e.g., 'eip155:1' for Ethereum, 'solana:4sGjMW1sUnHzSxGspuhpqLDx6wiyjNtZ' for Solana mainnet). Also accepts numeric EVM chain IDs (e.g., 1, 137) or aliases ('solana:mainnet', 'solana:devnet') for backward compatibility. + /// + [Newtonsoft.Json.JsonProperty("network", Required = Newtonsoft.Json.Required.Always)] + public Network3 Network { get; set; } + + [Newtonsoft.Json.JsonProperty("maxAmountRequired", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string MaxAmountRequired { get; set; } + + [Newtonsoft.Json.JsonProperty("resource", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public System.Uri Resource { get; set; } + + [Newtonsoft.Json.JsonProperty("description", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Description { get; set; } + + [Newtonsoft.Json.JsonProperty("mimeType", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string MimeType { get; set; } + + [Newtonsoft.Json.JsonProperty("outputSchema", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public System.Collections.Generic.IDictionary OutputSchema { get; set; } + + [Newtonsoft.Json.JsonProperty("payTo", Required = Newtonsoft.Json.Required.Always)] + public PayTo PayTo { get; set; } + + [Newtonsoft.Json.JsonProperty("maxTimeoutSeconds", Required = Newtonsoft.Json.Required.Always)] + public int MaxTimeoutSeconds { get; set; } + + [Newtonsoft.Json.JsonProperty("asset", Required = Newtonsoft.Json.Required.Always)] + public Asset Asset { get; set; } + + [Newtonsoft.Json.JsonProperty("extra", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public System.Collections.Generic.IDictionary Extra { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class PaymentPayload2 + { + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class PaymentRequirements2 + { + [Newtonsoft.Json.JsonProperty("scheme", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] + public PaymentRequirements2Scheme Scheme { get; set; } + + /// + /// CAIP-2 blockchain identifier (e.g., 'eip155:1' for Ethereum, 'solana:4sGjMW1sUnHzSxGspuhpqLDx6wiyjNtZ' for Solana mainnet). Also accepts numeric EVM chain IDs (e.g., 1, 137) or aliases ('solana:mainnet', 'solana:devnet') for backward compatibility. + /// + [Newtonsoft.Json.JsonProperty("network", Required = Newtonsoft.Json.Required.Always)] + public Network4 Network { get; set; } + + [Newtonsoft.Json.JsonProperty("maxAmountRequired", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string MaxAmountRequired { get; set; } + + [Newtonsoft.Json.JsonProperty("resource", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public System.Uri Resource { get; set; } + + [Newtonsoft.Json.JsonProperty("description", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Description { get; set; } + + [Newtonsoft.Json.JsonProperty("mimeType", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string MimeType { get; set; } + + [Newtonsoft.Json.JsonProperty("outputSchema", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public System.Collections.Generic.IDictionary OutputSchema { get; set; } + + [Newtonsoft.Json.JsonProperty("payTo", Required = Newtonsoft.Json.Required.Always)] + public PayTo2 PayTo { get; set; } + + [Newtonsoft.Json.JsonProperty("maxTimeoutSeconds", Required = Newtonsoft.Json.Required.Always)] + public int MaxTimeoutSeconds { get; set; } + + [Newtonsoft.Json.JsonProperty("asset", Required = Newtonsoft.Json.Required.Always)] + public Asset2 Asset { get; set; } + + [Newtonsoft.Json.JsonProperty("extra", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public System.Collections.Generic.IDictionary Extra { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public enum Body17WaitUntil + { + + [System.Runtime.Serialization.EnumMember(Value = @"simulated")] + Simulated = 0, + + [System.Runtime.Serialization.EnumMember(Value = @"submitted")] + Submitted = 1, + + [System.Runtime.Serialization.EnumMember(Value = @"confirmed")] + Confirmed = 2, + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Method2 + { + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Network + { + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Price + { + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class RouteConfig + { + [Newtonsoft.Json.JsonProperty("description", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Description { get; set; } + + [Newtonsoft.Json.JsonProperty("mimeType", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string MimeType { get; set; } + + [Newtonsoft.Json.JsonProperty("maxTimeoutSeconds", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double MaxTimeoutSeconds { get; set; } + + [Newtonsoft.Json.JsonProperty("inputSchema", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public InputSchema InputSchema { get; set; } + + [Newtonsoft.Json.JsonProperty("outputSchema", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public System.Collections.Generic.IDictionary OutputSchema { get; set; } + + [Newtonsoft.Json.JsonProperty("discoverable", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public bool Discoverable { get; set; } + + [Newtonsoft.Json.JsonProperty("customPaywallHtml", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string CustomPaywallHtml { get; set; } + + [Newtonsoft.Json.JsonProperty("resource", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public System.Uri Resource { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Sale + { + [Newtonsoft.Json.JsonProperty("type", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] + public SaleType Type { get; set; } = Thirdweb.Api.SaleType.Pool; + + /// + /// The initial token price in wei. This price is in the currency specified by `currency` (or the native token if not specified). + /// + [Newtonsoft.Json.JsonProperty("startingPrice", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string StartingPrice { get; set; } + + /// + /// The number of tokens to allocate to the sale. + /// + [Newtonsoft.Json.JsonProperty("amount", Required = Newtonsoft.Json.Required.Always)] + public double Amount { get; set; } + + /// + /// The bps fee on the token pool. + /// + [Newtonsoft.Json.JsonProperty("developerFeeBps", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double DeveloperFeeBps { get; set; } + + /// + /// The address to send the developer fee to. Defaults to the token owner. + /// + [Newtonsoft.Json.JsonProperty("developerFeeRecipient", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string DeveloperFeeRecipient { get; set; } + + /// + /// The currency to price this token sale in. Defaults to the native token. + /// + [Newtonsoft.Json.JsonProperty("currency", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Currency { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public enum Body20Exact + { + + [System.Runtime.Serialization.EnumMember(Value = @"input")] + Input = 0, + + [System.Runtime.Serialization.EnumMember(Value = @"output")] + Output = 1, + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class TokenIn + { + /// + /// The input token address to swap (use 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE for native token) + /// + [Newtonsoft.Json.JsonProperty("address", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Address { get; set; } + + /// + /// The blockchain network where the token is located + /// + [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Always)] + public int ChainId { get; set; } + + /// + /// The amount of the input token to swap in wei. + /// + [Newtonsoft.Json.JsonProperty("amount", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Amount { get; set; } + + /// + /// The maximum amount of the input token to swap in wei. + /// + [Newtonsoft.Json.JsonProperty("maxAmount", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string MaxAmount { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class TokenOut + { + /// + /// The output token address to swap (use 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE for native token) + /// + [Newtonsoft.Json.JsonProperty("address", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Address { get; set; } + + /// + /// The blockchain network where the token is located + /// + [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Always)] + public int ChainId { get; set; } + + /// + /// The amount of the output token to receive in wei. + /// + [Newtonsoft.Json.JsonProperty("amount", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Amount { get; set; } + + /// + /// The minimum amount of the output token to receive in wei. + /// + [Newtonsoft.Json.JsonProperty("minAmount", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string MinAmount { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + /// + /// Single Solana instruction that will be included in a transaction. + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Instructions + { + /// + /// Program address to invoke for this instruction. + /// + [Newtonsoft.Json.JsonProperty("programId", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + [System.ComponentModel.DataAnnotations.RegularExpression(@"^[1-9A-HJ-NP-Za-km-z]{32,44}$")] + public string ProgramId { get; set; } + + /// + /// Ordered list of accounts consumed by the instruction. + /// + [Newtonsoft.Json.JsonProperty("accounts", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + [System.ComponentModel.DataAnnotations.MinLength(1)] + public System.Collections.Generic.ICollection Accounts { get; set; } = new System.Collections.ObjectModel.Collection(); + + /// + /// Instruction data encoded using the provided encoding. + /// + [Newtonsoft.Json.JsonProperty("data", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public string Data { get; set; } + + /// + /// Encoding used for the instruction data payload. + /// + [Newtonsoft.Json.JsonProperty("encoding", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] + public InstructionsEncoding Encoding { get; set; } = Thirdweb.Api.InstructionsEncoding.Base64; + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class PriorityFee + { + [Newtonsoft.Json.JsonProperty("type", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] + public PriorityFeeType Type { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + /// + /// Single Solana instruction that will be included in a transaction. + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class instructions + { + /// + /// Program address to invoke for this instruction. + /// + [Newtonsoft.Json.JsonProperty("programId", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + [System.ComponentModel.DataAnnotations.RegularExpression(@"^[1-9A-HJ-NP-Za-km-z]{32,44}$")] + public string ProgramId { get; set; } + + /// + /// Ordered list of accounts consumed by the instruction. + /// + [Newtonsoft.Json.JsonProperty("accounts", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + [System.ComponentModel.DataAnnotations.MinLength(1)] + public System.Collections.Generic.ICollection Accounts { get; set; } = new System.Collections.ObjectModel.Collection(); + + /// + /// Instruction data encoded using the provided encoding. + /// + [Newtonsoft.Json.JsonProperty("data", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public string Data { get; set; } + + /// + /// Encoding used for the instruction data payload. + /// + [Newtonsoft.Json.JsonProperty("encoding", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] + public instructionsEncoding Encoding { get; set; } = Thirdweb.Api.instructionsEncoding.Base64; + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class PriorityFee2 + { + [Newtonsoft.Json.JsonProperty("type", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] + public PriorityFee2Type Type { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Messages + { + [Newtonsoft.Json.JsonProperty("role", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] + public MessagesRole Role { get; set; } + + [Newtonsoft.Json.JsonProperty("content", Required = Newtonsoft.Json.Required.Always)] + public Content Content { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Context + { + /// + /// Optional wallet address that will execute transactions + /// + [Newtonsoft.Json.JsonProperty("from", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string From { get; set; } + + /// + /// Optional chain IDs for context + /// + [Newtonsoft.Json.JsonProperty("chain_ids", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public System.Collections.Generic.ICollection Chain_ids { get; set; } + + /// + /// Optional session ID for conversation continuity. If not provided, a new session will be created + /// + [Newtonsoft.Json.JsonProperty("session_id", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Session_id { get; set; } + + /// + /// Whether to automatically execute transactions. If not provided, the default is false + /// + [Newtonsoft.Json.JsonProperty("auto_execute_transactions", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public bool Auto_execute_transactions { get; set; } = false; + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public enum ResponseMethod + { + + [System.Runtime.Serialization.EnumMember(Value = @"sms")] + Sms = 0, + + } + + /// + /// Authentication provider details with type-based discrimination + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class LinkedAccounts + { + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + /// + /// Authentication provider details with type-based discrimination + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class linkedAccounts + { + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Result + { + /// + /// Unique identifier for the user wallet within the thirdweb auth system. + /// + [Newtonsoft.Json.JsonProperty("userId", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string UserId { get; set; } + + /// + /// The EOA (Externally Owned Wallet) address of the wallet. This is the traditional wallet address. + /// + [Newtonsoft.Json.JsonProperty("address", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Address { get; set; } + + /// + /// The date and time the wallet was created + /// + [Newtonsoft.Json.JsonProperty("createdAt", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string CreatedAt { get; set; } + + /// + /// The profiles linked to the wallet, can be email, phone, google etc, or backend for developer created wallets + /// + [Newtonsoft.Json.JsonProperty("profiles", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.ICollection Profiles { get; set; } = new System.Collections.ObjectModel.Collection(); + + /// + /// The smart wallet address with EIP-4337 support. This address enables gasless transactions and advanced wallet features. + /// + [Newtonsoft.Json.JsonProperty("smartWalletAddress", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string SmartWalletAddress { get; set; } + + /// + /// The wallet's public key in hexadecimal format. Useful for peer-to-peer encryption and cryptographic operations. + /// + [Newtonsoft.Json.JsonProperty("publicKey", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string PublicKey { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Result2 + { + /// + /// Pagination information + /// + [Newtonsoft.Json.JsonProperty("pagination", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Pagination3 Pagination { get; set; } = new Pagination3(); + + /// + /// Array of user wallets + /// + [Newtonsoft.Json.JsonProperty("wallets", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.ICollection Wallets { get; set; } = new System.Collections.ObjectModel.Collection(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Result3 + { + /// + /// Unique identifier for the user wallet within the thirdweb auth system. + /// + [Newtonsoft.Json.JsonProperty("userId", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string UserId { get; set; } + + /// + /// The EOA (Externally Owned Wallet) address of the wallet. This is the traditional wallet address. + /// + [Newtonsoft.Json.JsonProperty("address", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Address { get; set; } + + /// + /// The date and time the wallet was created + /// + [Newtonsoft.Json.JsonProperty("createdAt", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string CreatedAt { get; set; } + + /// + /// The profiles linked to the wallet, can be email, phone, google etc, or backend for developer created wallets + /// + [Newtonsoft.Json.JsonProperty("profiles", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.ICollection Profiles { get; set; } = new System.Collections.ObjectModel.Collection(); + + /// + /// The smart wallet address with EIP-4337 support. This address enables gasless transactions and advanced wallet features. + /// + [Newtonsoft.Json.JsonProperty("smartWalletAddress", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string SmartWalletAddress { get; set; } + + /// + /// The wallet's public key in hexadecimal format. Useful for peer-to-peer encryption and cryptographic operations. + /// + [Newtonsoft.Json.JsonProperty("publicKey", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string PublicKey { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Result4 + { + /// + /// Pagination information + /// + [Newtonsoft.Json.JsonProperty("pagination", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Pagination4 Pagination { get; set; } = new Pagination4(); + + /// + /// Array of server wallets + /// + [Newtonsoft.Json.JsonProperty("wallets", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.ICollection Wallets { get; set; } = new System.Collections.ObjectModel.Collection(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Result5 + { + /// + /// Unique identifier for the user wallet within the thirdweb auth system. + /// + [Newtonsoft.Json.JsonProperty("userId", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string UserId { get; set; } + + /// + /// The EOA (Externally Owned Wallet) address of the wallet. This is the traditional wallet address. + /// + [Newtonsoft.Json.JsonProperty("address", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Address { get; set; } + + /// + /// The date and time the wallet was created + /// + [Newtonsoft.Json.JsonProperty("createdAt", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string CreatedAt { get; set; } + + /// + /// The profiles linked to the wallet, can be email, phone, google etc, or backend for developer created wallets + /// + [Newtonsoft.Json.JsonProperty("profiles", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.ICollection Profiles { get; set; } = new System.Collections.ObjectModel.Collection(); + + /// + /// The smart wallet address with EIP-4337 support. This address enables gasless transactions and advanced wallet features. + /// + [Newtonsoft.Json.JsonProperty("smartWalletAddress", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string SmartWalletAddress { get; set; } + + /// + /// The wallet's public key in hexadecimal format. Useful for peer-to-peer encryption and cryptographic operations. + /// + [Newtonsoft.Json.JsonProperty("publicKey", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string PublicKey { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class result + { + /// + /// The blockchain network ID + /// + [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Always)] + public double ChainId { get; set; } + + /// + /// Number of decimal places for the token + /// + [Newtonsoft.Json.JsonProperty("decimals", Required = Newtonsoft.Json.Required.Always)] + public double Decimals { get; set; } + + /// + /// Human-readable balance formatted with appropriate decimal places + /// + [Newtonsoft.Json.JsonProperty("displayValue", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string DisplayValue { get; set; } + + /// + /// The token name (e.g., 'Ether', 'USD Coin') + /// + [Newtonsoft.Json.JsonProperty("name", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Name { get; set; } + + /// + /// The token symbol (e.g., 'ETH', 'USDC') + /// + [Newtonsoft.Json.JsonProperty("symbol", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Symbol { get; set; } + + /// + /// The token contract address. Returns zero address (0x0...0) for native tokens. + /// + [Newtonsoft.Json.JsonProperty("tokenAddress", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string TokenAddress { get; set; } + + /// + /// Raw balance value as string in smallest unit (wei for ETH, etc.) + /// + [Newtonsoft.Json.JsonProperty("value", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Value { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Result6 + { + [Newtonsoft.Json.JsonProperty("pagination", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Pagination5 Pagination { get; set; } = new Pagination5(); + + /// + /// Array of wallet transactions. + /// + [Newtonsoft.Json.JsonProperty("transactions", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.ICollection Transactions { get; set; } = new System.Collections.ObjectModel.Collection(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Result7 + { + [Newtonsoft.Json.JsonProperty("pagination", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Pagination6 Pagination { get; set; } = new Pagination6(); + + /// + /// Array of wallet tokens. + /// + [Newtonsoft.Json.JsonProperty("tokens", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.ICollection Tokens { get; set; } = new System.Collections.ObjectModel.Collection(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Result8 + { + /// + /// Array of wallet NFTs. + /// + [Newtonsoft.Json.JsonProperty("nfts", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.ICollection Nfts { get; set; } = new System.Collections.ObjectModel.Collection(); + + [Newtonsoft.Json.JsonProperty("pagination", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Pagination7 Pagination { get; set; } = new Pagination7(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Result9 + { + /// + /// The cryptographic signature in hexadecimal format. This can be used for verification and authentication purposes. + /// + [Newtonsoft.Json.JsonProperty("signature", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Signature { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Result10 + { + /// + /// The cryptographic signature in hexadecimal format. This can be used for verification and authentication purposes. + /// + [Newtonsoft.Json.JsonProperty("signature", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Signature { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Result11 + { + /// + /// Array of transaction IDs for the submitted transfers. One ID per recipient. + /// + [Newtonsoft.Json.JsonProperty("transactionIds", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.ICollection TransactionIds { get; set; } = new System.Collections.ObjectModel.Collection(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Result12 + { + /// + /// Array of contracts imported by the client. + /// + [Newtonsoft.Json.JsonProperty("contracts", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.ICollection Contracts { get; set; } = new System.Collections.ObjectModel.Collection(); + + [Newtonsoft.Json.JsonProperty("pagination", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Pagination8 Pagination { get; set; } = new Pagination8(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Result13 + { + /// + /// The deployed contract address. + /// + [Newtonsoft.Json.JsonProperty("address", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Address { get; set; } + + /// + /// The chain ID where the contract was deployed. + /// + [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Always)] + public double ChainId { get; set; } + + /// + /// The unique identifier for the transaction that deployed the contract. Will not be returned if the contract was already deployed at the predicted address. + /// + [Newtonsoft.Json.JsonProperty("transactionId", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string TransactionId { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Result14 + { + /// + /// The result of the contract read operation. The type and format depend on the method's return value as defined in the contract ABI. + /// + [Newtonsoft.Json.JsonProperty("data", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public object Data { get; set; } + + /// + /// Error message if the contract read operation failed. + /// + [Newtonsoft.Json.JsonProperty("error", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Error { get; set; } + + /// + /// Indicates whether the contract read operation was successful. + /// + [Newtonsoft.Json.JsonProperty("success", Required = Newtonsoft.Json.Required.Always)] + public bool Success { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Result15 + { + /// + /// Array of unique identifiers for the submitted transactions. Use these to track transaction status. + /// + [Newtonsoft.Json.JsonProperty("transactionIds", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.ICollection TransactionIds { get; set; } = new System.Collections.ObjectModel.Collection(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Result16 + { + /// + /// Message to display to the user + /// + [Newtonsoft.Json.JsonProperty("message", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Message { get; set; } + + /// + /// Link to purchase the product + /// + [Newtonsoft.Json.JsonProperty("link", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Link { get; set; } + + /// + /// Payment ID + /// + [Newtonsoft.Json.JsonProperty("id", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Id { get; set; } + + /// + /// Bridge quote for completing the payment + /// + [Newtonsoft.Json.JsonProperty("quote", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public Quote Quote { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Result17 + { + /// + /// Array of contract transactions. + /// + [Newtonsoft.Json.JsonProperty("data", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.ICollection Data { get; set; } = new System.Collections.ObjectModel.Collection(); + + [Newtonsoft.Json.JsonProperty("pagination", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Pagination9 Pagination { get; set; } = new Pagination9(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Result18 + { + /// + /// Array of contract events. + /// + [Newtonsoft.Json.JsonProperty("events", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.ICollection Events { get; set; } = new System.Collections.ObjectModel.Collection(); + + [Newtonsoft.Json.JsonProperty("pagination", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Pagination10 Pagination { get; set; } = new Pagination10(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Result19 + { + /// + /// Compiler information including version. + /// + [Newtonsoft.Json.JsonProperty("compiler", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public Compiler Compiler { get; set; } + + /// + /// Programming language of the contract (e.g., 'Solidity'). + /// + [Newtonsoft.Json.JsonProperty("language", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Language { get; set; } + + /// + /// Compilation output including ABI and documentation. + /// + [Newtonsoft.Json.JsonProperty("output", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public Output Output { get; set; } + + /// + /// Compilation settings including optimization and target configuration. + /// + [Newtonsoft.Json.JsonProperty("settings", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public Settings Settings { get; set; } + + /// + /// Metadata format version. + /// + [Newtonsoft.Json.JsonProperty("version", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double Version { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Result20 + { + /// + /// Index within transaction batch + /// + [Newtonsoft.Json.JsonProperty("batchIndex", Required = Newtonsoft.Json.Required.Always)] + public int BatchIndex { get; set; } + + /// + /// ISO timestamp when transaction was cancelled, if applicable + /// + [Newtonsoft.Json.JsonProperty("cancelledAt", Required = Newtonsoft.Json.Required.AllowNull)] + public string CancelledAt { get; set; } + + /// + /// Blockchain network identifier as string + /// + [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string ChainId { get; set; } + + /// + /// Client identifier that initiated the transaction + /// + [Newtonsoft.Json.JsonProperty("clientId", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string ClientId { get; set; } + + /// + /// ISO timestamp when transaction was confirmed on-chain + /// + [Newtonsoft.Json.JsonProperty("confirmedAt", Required = Newtonsoft.Json.Required.AllowNull)] + public string ConfirmedAt { get; set; } + + /// + /// Block number where transaction was confirmed + /// + [Newtonsoft.Json.JsonProperty("confirmedAtBlockNumber", Required = Newtonsoft.Json.Required.AllowNull)] + public string ConfirmedAtBlockNumber { get; set; } + + /// + /// ISO timestamp when transaction was created + /// + [Newtonsoft.Json.JsonProperty("createdAt", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string CreatedAt { get; set; } + + /// + /// Additional metadata and enriched transaction information + /// + [Newtonsoft.Json.JsonProperty("enrichedData", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public object EnrichedData { get; set; } + + /// + /// Error message if transaction failed + /// + [Newtonsoft.Json.JsonProperty("errorMessage", Required = Newtonsoft.Json.Required.AllowNull)] + public string ErrorMessage { get; set; } + + /// + /// Parameters used for transaction execution + /// + [Newtonsoft.Json.JsonProperty("executionParams", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public object ExecutionParams { get; set; } + + /// + /// Result data from transaction execution + /// + [Newtonsoft.Json.JsonProperty("executionResult", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public object ExecutionResult { get; set; } + + /// + /// Sender wallet address + /// + [Newtonsoft.Json.JsonProperty("from", Required = Newtonsoft.Json.Required.AllowNull)] + public string From { get; set; } + + /// + /// Unique transaction identifier + /// + [Newtonsoft.Json.JsonProperty("id", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Id { get; set; } + + /// + /// On-chain transaction hash once confirmed + /// + [Newtonsoft.Json.JsonProperty("transactionHash", Required = Newtonsoft.Json.Required.AllowNull)] + public string TransactionHash { get; set; } + + /// + /// Original transaction parameters and data + /// + [Newtonsoft.Json.JsonProperty("transactionParams", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public object TransactionParams { get; set; } + + /// + /// Transaction status + /// + [Newtonsoft.Json.JsonProperty("status", Required = Newtonsoft.Json.Required.AllowNull)] + [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] + public Result20Status? Status { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Result21 + { + [Newtonsoft.Json.JsonProperty("pagination", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Pagination11 Pagination { get; set; } = new Pagination11(); + + [Newtonsoft.Json.JsonProperty("transactions", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.ICollection Transactions { get; set; } = new System.Collections.ObjectModel.Collection(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Result22 + { + /// + /// Array of unique identifiers for the submitted transactions. Use these to track transaction status. + /// + [Newtonsoft.Json.JsonProperty("transactionIds", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.ICollection TransactionIds { get; set; } = new System.Collections.ObjectModel.Collection(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Result23 + { + /// + /// Message to display to the user + /// + [Newtonsoft.Json.JsonProperty("message", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Message { get; set; } + + /// + /// Link to purchase the product + /// + [Newtonsoft.Json.JsonProperty("link", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Link { get; set; } + + /// + /// Payment ID + /// + [Newtonsoft.Json.JsonProperty("id", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Id { get; set; } + + /// + /// Bridge quote for completing the payment + /// + [Newtonsoft.Json.JsonProperty("quote", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public Quote2 Quote { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Result24 + { + /// + /// The payment ID + /// + [Newtonsoft.Json.JsonProperty("id", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Id { get; set; } + + /// + /// The link to purchase the product + /// + [Newtonsoft.Json.JsonProperty("link", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Link { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Result25 + { + /// + /// Transaction ID that was executed for your product purchase + /// + [Newtonsoft.Json.JsonProperty("transactionId", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string TransactionId { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Result26 + { + /// + /// Message to display to the user + /// + [Newtonsoft.Json.JsonProperty("message", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Message { get; set; } + + /// + /// Link to purchase the product + /// + [Newtonsoft.Json.JsonProperty("link", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Link { get; set; } + + /// + /// Payment ID + /// + [Newtonsoft.Json.JsonProperty("id", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Id { get; set; } + + /// + /// Bridge quote for completing the payment + /// + [Newtonsoft.Json.JsonProperty("quote", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public Quote3 Quote { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Data + { + [Newtonsoft.Json.JsonProperty("id", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Id { get; set; } + + [Newtonsoft.Json.JsonProperty("blockNumber", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.RegularExpression(@"^\d+$")] + public string BlockNumber { get; set; } + + [Newtonsoft.Json.JsonProperty("transactionId", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string TransactionId { get; set; } + + [Newtonsoft.Json.JsonProperty("onrampId", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string OnrampId { get; set; } + + [Newtonsoft.Json.JsonProperty("clientId", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string ClientId { get; set; } + + /// + /// A valid Ethereum address (0x-prefixed hex string) or ENS name (e.g., vitalik.eth). + /// + [Newtonsoft.Json.JsonProperty("sender", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Sender { get; set; } + + /// + /// A valid Ethereum address (0x-prefixed hex string) or ENS name (e.g., vitalik.eth). + /// + [Newtonsoft.Json.JsonProperty("receiver", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Receiver { get; set; } + + /// + /// A valid Ethereum address (0x-prefixed hex string) or ENS name (e.g., vitalik.eth). + /// + [Newtonsoft.Json.JsonProperty("developerFeeRecipient", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string DeveloperFeeRecipient { get; set; } + + [Newtonsoft.Json.JsonProperty("developerFeeBps", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double DeveloperFeeBps { get; set; } + + [Newtonsoft.Json.JsonProperty("transactions", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.ICollection Transactions { get; set; } = new System.Collections.ObjectModel.Collection(); + + [Newtonsoft.Json.JsonProperty("status", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] + public DataStatus Status { get; set; } + + [Newtonsoft.Json.JsonProperty("type", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] + public DataType Type { get; set; } + + [Newtonsoft.Json.JsonProperty("originAmount", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.RegularExpression(@"^\d+$")] + public string OriginAmount { get; set; } + + [Newtonsoft.Json.JsonProperty("destinationAmount", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + [System.ComponentModel.DataAnnotations.RegularExpression(@"^\d+$")] + public string DestinationAmount { get; set; } + + [Newtonsoft.Json.JsonProperty("paymentLinkId", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string PaymentLinkId { get; set; } + + [Newtonsoft.Json.JsonProperty("purchaseData", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public object PurchaseData { get; set; } + + [Newtonsoft.Json.JsonProperty("originToken", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public OriginToken OriginToken { get; set; } + + [Newtonsoft.Json.JsonProperty("destinationToken", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public DestinationToken DestinationToken { get; set; } = new DestinationToken(); + + [Newtonsoft.Json.JsonProperty("createdAt", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string CreatedAt { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Meta + { + /// + /// Total number of payments + /// + [Newtonsoft.Json.JsonProperty("totalCount", Required = Newtonsoft.Json.Required.Always)] + public double TotalCount { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public enum Response36InvalidReason + { + + [System.Runtime.Serialization.EnumMember(Value = @"insufficient_funds")] + Insufficient_funds = 0, + + [System.Runtime.Serialization.EnumMember(Value = @"invalid_exact_evm_payload_authorization_valid_after")] + Invalid_exact_evm_payload_authorization_valid_after = 1, + + [System.Runtime.Serialization.EnumMember(Value = @"invalid_exact_evm_payload_authorization_valid_before")] + Invalid_exact_evm_payload_authorization_valid_before = 2, + + [System.Runtime.Serialization.EnumMember(Value = @"invalid_exact_evm_payload_authorization_value")] + Invalid_exact_evm_payload_authorization_value = 3, + + [System.Runtime.Serialization.EnumMember(Value = @"invalid_exact_evm_payload_signature")] + Invalid_exact_evm_payload_signature = 4, + + [System.Runtime.Serialization.EnumMember(Value = @"invalid_exact_evm_payload_recipient_mismatch")] + Invalid_exact_evm_payload_recipient_mismatch = 5, + + [System.Runtime.Serialization.EnumMember(Value = @"invalid_exact_svm_payload_transaction")] + Invalid_exact_svm_payload_transaction = 6, + + [System.Runtime.Serialization.EnumMember(Value = @"invalid_exact_svm_payload_transaction_amount_mismatch")] + Invalid_exact_svm_payload_transaction_amount_mismatch = 7, + + [System.Runtime.Serialization.EnumMember(Value = @"invalid_exact_svm_payload_transaction_create_ata_instruction")] + Invalid_exact_svm_payload_transaction_create_ata_instruction = 8, + + [System.Runtime.Serialization.EnumMember(Value = @"invalid_exact_svm_payload_transaction_create_ata_instruction_incorrect_payee")] + Invalid_exact_svm_payload_transaction_create_ata_instruction_incorrect_payee = 9, + + [System.Runtime.Serialization.EnumMember(Value = @"invalid_exact_svm_payload_transaction_create_ata_instruction_incorrect_asset")] + Invalid_exact_svm_payload_transaction_create_ata_instruction_incorrect_asset = 10, + + [System.Runtime.Serialization.EnumMember(Value = @"invalid_exact_svm_payload_transaction_instructions")] + Invalid_exact_svm_payload_transaction_instructions = 11, + + [System.Runtime.Serialization.EnumMember(Value = @"invalid_exact_svm_payload_transaction_instructions_length")] + Invalid_exact_svm_payload_transaction_instructions_length = 12, + + [System.Runtime.Serialization.EnumMember(Value = @"invalid_exact_svm_payload_transaction_instructions_compute_limit_instruction")] + Invalid_exact_svm_payload_transaction_instructions_compute_limit_instruction = 13, + + [System.Runtime.Serialization.EnumMember(Value = @"invalid_exact_svm_payload_transaction_instructions_compute_price_instruction")] + Invalid_exact_svm_payload_transaction_instructions_compute_price_instruction = 14, + + [System.Runtime.Serialization.EnumMember(Value = @"invalid_exact_svm_payload_transaction_instructions_compute_price_instruction_too_high")] + Invalid_exact_svm_payload_transaction_instructions_compute_price_instruction_too_high = 15, + + [System.Runtime.Serialization.EnumMember(Value = @"invalid_exact_svm_payload_transaction_instruction_not_spl_token_transfer_checked")] + Invalid_exact_svm_payload_transaction_instruction_not_spl_token_transfer_checked = 16, + + [System.Runtime.Serialization.EnumMember(Value = @"invalid_exact_svm_payload_transaction_instruction_not_token_2022_transfer_checked")] + Invalid_exact_svm_payload_transaction_instruction_not_token_2022_transfer_checked = 17, + + [System.Runtime.Serialization.EnumMember(Value = @"invalid_exact_svm_payload_transaction_not_a_transfer_instruction")] + Invalid_exact_svm_payload_transaction_not_a_transfer_instruction = 18, + + [System.Runtime.Serialization.EnumMember(Value = @"invalid_exact_svm_payload_transaction_receiver_ata_not_found")] + Invalid_exact_svm_payload_transaction_receiver_ata_not_found = 19, + + [System.Runtime.Serialization.EnumMember(Value = @"invalid_exact_svm_payload_transaction_sender_ata_not_found")] + Invalid_exact_svm_payload_transaction_sender_ata_not_found = 20, + + [System.Runtime.Serialization.EnumMember(Value = @"invalid_exact_svm_payload_transaction_simulation_failed")] + Invalid_exact_svm_payload_transaction_simulation_failed = 21, + + [System.Runtime.Serialization.EnumMember(Value = @"invalid_exact_svm_payload_transaction_transfer_to_incorrect_ata")] + Invalid_exact_svm_payload_transaction_transfer_to_incorrect_ata = 22, + + [System.Runtime.Serialization.EnumMember(Value = @"invalid_network")] + Invalid_network = 23, + + [System.Runtime.Serialization.EnumMember(Value = @"invalid_payload")] + Invalid_payload = 24, + + [System.Runtime.Serialization.EnumMember(Value = @"invalid_payment_requirements")] + Invalid_payment_requirements = 25, + + [System.Runtime.Serialization.EnumMember(Value = @"invalid_scheme")] + Invalid_scheme = 26, + + [System.Runtime.Serialization.EnumMember(Value = @"invalid_payment")] + Invalid_payment = 27, + + [System.Runtime.Serialization.EnumMember(Value = @"payment_expired")] + Payment_expired = 28, + + [System.Runtime.Serialization.EnumMember(Value = @"unsupported_scheme")] + Unsupported_scheme = 29, + + [System.Runtime.Serialization.EnumMember(Value = @"invalid_x402_version")] + Invalid_x402_version = 30, + + [System.Runtime.Serialization.EnumMember(Value = @"invalid_transaction_state")] + Invalid_transaction_state = 31, + + [System.Runtime.Serialization.EnumMember(Value = @"settle_exact_svm_block_height_exceeded")] + Settle_exact_svm_block_height_exceeded = 32, + + [System.Runtime.Serialization.EnumMember(Value = @"settle_exact_svm_transaction_confirmation_timed_out")] + Settle_exact_svm_transaction_confirmation_timed_out = 33, + + [System.Runtime.Serialization.EnumMember(Value = @"unexpected_settle_error")] + Unexpected_settle_error = 34, + + [System.Runtime.Serialization.EnumMember(Value = @"unexpected_verify_error")] + Unexpected_verify_error = 35, + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Payer + { + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public enum Response37ErrorReason + { + + [System.Runtime.Serialization.EnumMember(Value = @"insufficient_funds")] + Insufficient_funds = 0, + + [System.Runtime.Serialization.EnumMember(Value = @"invalid_exact_evm_payload_authorization_valid_after")] + Invalid_exact_evm_payload_authorization_valid_after = 1, + + [System.Runtime.Serialization.EnumMember(Value = @"invalid_exact_evm_payload_authorization_valid_before")] + Invalid_exact_evm_payload_authorization_valid_before = 2, + + [System.Runtime.Serialization.EnumMember(Value = @"invalid_exact_evm_payload_authorization_value")] + Invalid_exact_evm_payload_authorization_value = 3, + + [System.Runtime.Serialization.EnumMember(Value = @"invalid_exact_evm_payload_signature")] + Invalid_exact_evm_payload_signature = 4, + + [System.Runtime.Serialization.EnumMember(Value = @"invalid_exact_evm_payload_recipient_mismatch")] + Invalid_exact_evm_payload_recipient_mismatch = 5, + + [System.Runtime.Serialization.EnumMember(Value = @"invalid_exact_svm_payload_transaction")] + Invalid_exact_svm_payload_transaction = 6, + + [System.Runtime.Serialization.EnumMember(Value = @"invalid_exact_svm_payload_transaction_amount_mismatch")] + Invalid_exact_svm_payload_transaction_amount_mismatch = 7, + + [System.Runtime.Serialization.EnumMember(Value = @"invalid_exact_svm_payload_transaction_create_ata_instruction")] + Invalid_exact_svm_payload_transaction_create_ata_instruction = 8, + + [System.Runtime.Serialization.EnumMember(Value = @"invalid_exact_svm_payload_transaction_create_ata_instruction_incorrect_payee")] + Invalid_exact_svm_payload_transaction_create_ata_instruction_incorrect_payee = 9, + + [System.Runtime.Serialization.EnumMember(Value = @"invalid_exact_svm_payload_transaction_create_ata_instruction_incorrect_asset")] + Invalid_exact_svm_payload_transaction_create_ata_instruction_incorrect_asset = 10, + + [System.Runtime.Serialization.EnumMember(Value = @"invalid_exact_svm_payload_transaction_instructions")] + Invalid_exact_svm_payload_transaction_instructions = 11, + + [System.Runtime.Serialization.EnumMember(Value = @"invalid_exact_svm_payload_transaction_instructions_length")] + Invalid_exact_svm_payload_transaction_instructions_length = 12, + + [System.Runtime.Serialization.EnumMember(Value = @"invalid_exact_svm_payload_transaction_instructions_compute_limit_instruction")] + Invalid_exact_svm_payload_transaction_instructions_compute_limit_instruction = 13, + + [System.Runtime.Serialization.EnumMember(Value = @"invalid_exact_svm_payload_transaction_instructions_compute_price_instruction")] + Invalid_exact_svm_payload_transaction_instructions_compute_price_instruction = 14, + + [System.Runtime.Serialization.EnumMember(Value = @"invalid_exact_svm_payload_transaction_instructions_compute_price_instruction_too_high")] + Invalid_exact_svm_payload_transaction_instructions_compute_price_instruction_too_high = 15, + + [System.Runtime.Serialization.EnumMember(Value = @"invalid_exact_svm_payload_transaction_instruction_not_spl_token_transfer_checked")] + Invalid_exact_svm_payload_transaction_instruction_not_spl_token_transfer_checked = 16, + + [System.Runtime.Serialization.EnumMember(Value = @"invalid_exact_svm_payload_transaction_instruction_not_token_2022_transfer_checked")] + Invalid_exact_svm_payload_transaction_instruction_not_token_2022_transfer_checked = 17, + + [System.Runtime.Serialization.EnumMember(Value = @"invalid_exact_svm_payload_transaction_not_a_transfer_instruction")] + Invalid_exact_svm_payload_transaction_not_a_transfer_instruction = 18, + + [System.Runtime.Serialization.EnumMember(Value = @"invalid_exact_svm_payload_transaction_receiver_ata_not_found")] + Invalid_exact_svm_payload_transaction_receiver_ata_not_found = 19, + + [System.Runtime.Serialization.EnumMember(Value = @"invalid_exact_svm_payload_transaction_sender_ata_not_found")] + Invalid_exact_svm_payload_transaction_sender_ata_not_found = 20, + + [System.Runtime.Serialization.EnumMember(Value = @"invalid_exact_svm_payload_transaction_simulation_failed")] + Invalid_exact_svm_payload_transaction_simulation_failed = 21, + + [System.Runtime.Serialization.EnumMember(Value = @"invalid_exact_svm_payload_transaction_transfer_to_incorrect_ata")] + Invalid_exact_svm_payload_transaction_transfer_to_incorrect_ata = 22, + + [System.Runtime.Serialization.EnumMember(Value = @"invalid_network")] + Invalid_network = 23, + + [System.Runtime.Serialization.EnumMember(Value = @"invalid_payload")] + Invalid_payload = 24, + + [System.Runtime.Serialization.EnumMember(Value = @"invalid_payment_requirements")] + Invalid_payment_requirements = 25, + + [System.Runtime.Serialization.EnumMember(Value = @"invalid_scheme")] + Invalid_scheme = 26, + + [System.Runtime.Serialization.EnumMember(Value = @"invalid_payment")] + Invalid_payment = 27, + + [System.Runtime.Serialization.EnumMember(Value = @"payment_expired")] + Payment_expired = 28, + + [System.Runtime.Serialization.EnumMember(Value = @"unsupported_scheme")] + Unsupported_scheme = 29, + + [System.Runtime.Serialization.EnumMember(Value = @"invalid_x402_version")] + Invalid_x402_version = 30, + + [System.Runtime.Serialization.EnumMember(Value = @"invalid_transaction_state")] + Invalid_transaction_state = 31, + + [System.Runtime.Serialization.EnumMember(Value = @"settle_exact_svm_block_height_exceeded")] + Settle_exact_svm_block_height_exceeded = 32, + + [System.Runtime.Serialization.EnumMember(Value = @"settle_exact_svm_transaction_confirmation_timed_out")] + Settle_exact_svm_transaction_confirmation_timed_out = 33, + + [System.Runtime.Serialization.EnumMember(Value = @"unexpected_settle_error")] + Unexpected_settle_error = 34, + + [System.Runtime.Serialization.EnumMember(Value = @"unexpected_verify_error")] + Unexpected_verify_error = 35, + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Payer2 + { + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public enum Response37Network + { + + [System.Runtime.Serialization.EnumMember(Value = @"base-sepolia")] + BaseSepolia = 0, + + [System.Runtime.Serialization.EnumMember(Value = @"base")] + Base = 1, + + [System.Runtime.Serialization.EnumMember(Value = @"avalanche-fuji")] + AvalancheFuji = 2, + + [System.Runtime.Serialization.EnumMember(Value = @"avalanche")] + Avalanche = 3, + + [System.Runtime.Serialization.EnumMember(Value = @"iotex")] + Iotex = 4, + + [System.Runtime.Serialization.EnumMember(Value = @"solana-devnet")] + SolanaDevnet = 5, + + [System.Runtime.Serialization.EnumMember(Value = @"solana")] + Solana = 6, + + [System.Runtime.Serialization.EnumMember(Value = @"sei")] + Sei = 7, + + [System.Runtime.Serialization.EnumMember(Value = @"sei-testnet")] + SeiTestnet = 8, + + [System.Runtime.Serialization.EnumMember(Value = @"polygon")] + Polygon = 9, + + [System.Runtime.Serialization.EnumMember(Value = @"polygon-amoy")] + PolygonAmoy = 10, + + [System.Runtime.Serialization.EnumMember(Value = @"peaq")] + Peaq = 11, + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Kinds + { + [Newtonsoft.Json.JsonProperty("x402Version", Required = Newtonsoft.Json.Required.Always)] + public double X402Version { get; set; } + + [Newtonsoft.Json.JsonProperty("scheme", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] + public KindsScheme Scheme { get; set; } + + /// + /// CAIP-2 blockchain identifier (e.g., 'eip155:1' for Ethereum, 'solana:4sGjMW1sUnHzSxGspuhpqLDx6wiyjNtZ' for Solana mainnet). Also accepts numeric EVM chain IDs (e.g., 1, 137) or aliases ('solana:mainnet', 'solana:devnet') for backward compatibility. + /// + [Newtonsoft.Json.JsonProperty("network", Required = Newtonsoft.Json.Required.Always)] + public Network5 Network { get; set; } + + [Newtonsoft.Json.JsonProperty("extra", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public Extra Extra { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Result27 + { + /// + /// Message to display to the user + /// + [Newtonsoft.Json.JsonProperty("message", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Message { get; set; } + + /// + /// Link to purchase the product + /// + [Newtonsoft.Json.JsonProperty("link", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Link { get; set; } + + /// + /// Payment ID + /// + [Newtonsoft.Json.JsonProperty("id", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Id { get; set; } + + /// + /// Bridge quote for completing the payment + /// + [Newtonsoft.Json.JsonProperty("quote", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public Quote4 Quote { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Items + { + [Newtonsoft.Json.JsonProperty("resource", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Resource { get; set; } + + [Newtonsoft.Json.JsonProperty("type", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] + public ItemsType Type { get; set; } + + [Newtonsoft.Json.JsonProperty("x402Version", Required = Newtonsoft.Json.Required.Always)] + public double X402Version { get; set; } + + [Newtonsoft.Json.JsonProperty("accepts", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.ICollection Accepts { get; set; } = new System.Collections.ObjectModel.Collection(); + + [Newtonsoft.Json.JsonProperty("lastUpdated", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string LastUpdated { get; set; } + + [Newtonsoft.Json.JsonProperty("metadata", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public System.Collections.Generic.IDictionary Metadata { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Pagination + { + [Newtonsoft.Json.JsonProperty("limit", Required = Newtonsoft.Json.Required.Always)] + public double Limit { get; set; } + + [Newtonsoft.Json.JsonProperty("offset", Required = Newtonsoft.Json.Required.Always)] + public double Offset { get; set; } + + [Newtonsoft.Json.JsonProperty("total", Required = Newtonsoft.Json.Required.Always)] + public double Total { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Accepts + { + [Newtonsoft.Json.JsonProperty("scheme", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] + public AcceptsScheme Scheme { get; set; } + + /// + /// CAIP-2 blockchain identifier (e.g., 'eip155:1' for Ethereum, 'solana:4sGjMW1sUnHzSxGspuhpqLDx6wiyjNtZ' for Solana mainnet). Also accepts numeric EVM chain IDs (e.g., 1, 137) or aliases ('solana:mainnet', 'solana:devnet') for backward compatibility. + /// + [Newtonsoft.Json.JsonProperty("network", Required = Newtonsoft.Json.Required.Always)] + public Network6 Network { get; set; } + + [Newtonsoft.Json.JsonProperty("maxAmountRequired", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string MaxAmountRequired { get; set; } + + [Newtonsoft.Json.JsonProperty("resource", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public System.Uri Resource { get; set; } + + [Newtonsoft.Json.JsonProperty("description", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Description { get; set; } + + [Newtonsoft.Json.JsonProperty("mimeType", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string MimeType { get; set; } + + [Newtonsoft.Json.JsonProperty("outputSchema", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public System.Collections.Generic.IDictionary OutputSchema { get; set; } + + [Newtonsoft.Json.JsonProperty("payTo", Required = Newtonsoft.Json.Required.Always)] + public PayTo3 PayTo { get; set; } + + [Newtonsoft.Json.JsonProperty("maxTimeoutSeconds", Required = Newtonsoft.Json.Required.Always)] + public int MaxTimeoutSeconds { get; set; } + + [Newtonsoft.Json.JsonProperty("asset", Required = Newtonsoft.Json.Required.Always)] + public Asset3 Asset { get; set; } + + [Newtonsoft.Json.JsonProperty("extra", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public System.Collections.Generic.IDictionary Extra { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class accepts + { + [Newtonsoft.Json.JsonProperty("scheme", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] + public acceptsScheme Scheme { get; set; } + + /// + /// CAIP-2 blockchain identifier (e.g., 'eip155:1' for Ethereum, 'solana:4sGjMW1sUnHzSxGspuhpqLDx6wiyjNtZ' for Solana mainnet). Also accepts numeric EVM chain IDs (e.g., 1, 137) or aliases ('solana:mainnet', 'solana:devnet') for backward compatibility. + /// + [Newtonsoft.Json.JsonProperty("network", Required = Newtonsoft.Json.Required.Always)] + public Network7 Network { get; set; } + + [Newtonsoft.Json.JsonProperty("maxAmountRequired", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string MaxAmountRequired { get; set; } + + [Newtonsoft.Json.JsonProperty("resource", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public System.Uri Resource { get; set; } + + [Newtonsoft.Json.JsonProperty("description", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Description { get; set; } + + [Newtonsoft.Json.JsonProperty("mimeType", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string MimeType { get; set; } + + [Newtonsoft.Json.JsonProperty("outputSchema", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public System.Collections.Generic.IDictionary OutputSchema { get; set; } + + [Newtonsoft.Json.JsonProperty("payTo", Required = Newtonsoft.Json.Required.Always)] + public PayTo4 PayTo { get; set; } + + [Newtonsoft.Json.JsonProperty("maxTimeoutSeconds", Required = Newtonsoft.Json.Required.Always)] + public int MaxTimeoutSeconds { get; set; } + + [Newtonsoft.Json.JsonProperty("asset", Required = Newtonsoft.Json.Required.Always)] + public Asset4 Asset { get; set; } + + [Newtonsoft.Json.JsonProperty("extra", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public System.Collections.Generic.IDictionary Extra { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Pagination2 + { + /// + /// Whether there are more items available + /// + [Newtonsoft.Json.JsonProperty("hasMore", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public bool HasMore { get; set; } + + /// + /// Number of items per page + /// + [Newtonsoft.Json.JsonProperty("limit", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double? Limit { get; set; } = 20D; + + /// + /// Current page number + /// + [Newtonsoft.Json.JsonProperty("page", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double? Page { get; set; } = 1D; + + /// + /// Total number of items available + /// + [Newtonsoft.Json.JsonProperty("totalCount", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double? TotalCount { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Tokens + { + /// + /// The blockchain network identifier. Common values include: 1 (Ethereum), 8453 (Base), 137 (Polygon), 56 (BSC), 43114 (Avalanche), 42161 (Arbitrum), 10 (Optimism). + /// + [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Always)] + public int ChainId { get; set; } + + /// + /// A valid Ethereum address (0x-prefixed hex string) or ENS name (e.g., vitalik.eth). + /// + [Newtonsoft.Json.JsonProperty("address", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Address { get; set; } + + [Newtonsoft.Json.JsonProperty("decimals", Required = Newtonsoft.Json.Required.Always)] + public double Decimals { get; set; } + + [Newtonsoft.Json.JsonProperty("symbol", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Symbol { get; set; } + + [Newtonsoft.Json.JsonProperty("iconUri", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string IconUri { get; set; } + + /// + /// Token price in different FIAT currencies. + /// + [Newtonsoft.Json.JsonProperty("prices", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.IDictionary Prices { get; set; } = new System.Collections.Generic.Dictionary(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Result28 + { + /// + /// Array of token owners with amounts. + /// + [Newtonsoft.Json.JsonProperty("owners", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.ICollection Owners { get; set; } = new System.Collections.ObjectModel.Collection(); + + [Newtonsoft.Json.JsonProperty("pagination", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Pagination12 Pagination { get; set; } = new Pagination12(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Result29 + { + /// + /// The chain ID of the chain + /// + [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Always)] + public double ChainId { get; set; } + + /// + /// The name of the chain + /// + [Newtonsoft.Json.JsonProperty("name", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Name { get; set; } + + /// + /// The URL of the chain's icon + /// + [Newtonsoft.Json.JsonProperty("icon", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Icon { get; set; } + + /// + /// Information about the native currency of the chain + /// + [Newtonsoft.Json.JsonProperty("nativeCurrency", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public NativeCurrency NativeCurrency { get; set; } = new NativeCurrency(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Result30 + { + /// + /// Supported bridge routes that match the provided filters. + /// + [Newtonsoft.Json.JsonProperty("routes", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.ICollection Routes { get; set; } = new System.Collections.ObjectModel.Collection(); + + /// + /// Pagination details for the returned routes. + /// + [Newtonsoft.Json.JsonProperty("pagination", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Pagination13 Pagination { get; set; } = new Pagination13(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Result31 + { + /// + /// Payment transaction ID that was executed + /// + [Newtonsoft.Json.JsonProperty("transactionId", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string TransactionId { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Result32 + { + /// + /// Message to display to the user + /// + [Newtonsoft.Json.JsonProperty("message", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Message { get; set; } + + /// + /// Link to purchase the product + /// + [Newtonsoft.Json.JsonProperty("link", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Link { get; set; } + + /// + /// Payment ID + /// + [Newtonsoft.Json.JsonProperty("id", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Id { get; set; } + + /// + /// Bridge quote for completing the payment + /// + [Newtonsoft.Json.JsonProperty("quote", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public Quote5 Quote { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Result33 + { + /// + /// Array of Solana wallets created for your project. + /// + [Newtonsoft.Json.JsonProperty("wallets", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.ICollection Wallets { get; set; } = new System.Collections.ObjectModel.Collection(); + + /// + /// Pagination details for the wallet list. + /// + [Newtonsoft.Json.JsonProperty("pagination", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Pagination14 Pagination { get; set; } = new Pagination14(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Result34 + { + /// + /// Base58 encoded Solana address. + /// + [Newtonsoft.Json.JsonProperty("address", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + [System.ComponentModel.DataAnnotations.RegularExpression(@"^[1-9A-HJ-NP-Za-km-z]{32,44}$")] + public string Address { get; set; } + + /// + /// Optional label associated with the wallet. + /// + [Newtonsoft.Json.JsonProperty("label", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Label { get; set; } + + /// + /// ISO 8601 timestamp indicating when the wallet was created. + /// + [Newtonsoft.Json.JsonProperty("createdAt", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string CreatedAt { get; set; } + + /// + /// ISO 8601 timestamp indicating when the wallet was last updated. + /// + [Newtonsoft.Json.JsonProperty("updatedAt", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string UpdatedAt { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Result35 + { + /// + /// Base58 encoded Solana address. + /// + [Newtonsoft.Json.JsonProperty("address", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + [System.ComponentModel.DataAnnotations.RegularExpression(@"^[1-9A-HJ-NP-Za-km-z]{32,44}$")] + public string Address { get; set; } + + /// + /// Optional label associated with the wallet. + /// + [Newtonsoft.Json.JsonProperty("label", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Label { get; set; } + + /// + /// ISO 8601 timestamp indicating when the wallet was created. + /// + [Newtonsoft.Json.JsonProperty("createdAt", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string CreatedAt { get; set; } + + /// + /// ISO 8601 timestamp indicating when the wallet was last updated. + /// + [Newtonsoft.Json.JsonProperty("updatedAt", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string UpdatedAt { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Result36 + { + /// + /// Requested Solana network. + /// + [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string ChainId { get; set; } + + /// + /// Number of decimals used by the token. + /// + [Newtonsoft.Json.JsonProperty("decimals", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Range(0, int.MaxValue)] + public int Decimals { get; set; } + + /// + /// Human-readable balance formatted using token decimals. + /// + [Newtonsoft.Json.JsonProperty("displayValue", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string DisplayValue { get; set; } + + /// + /// Raw balance value expressed in base units (lamports). + /// + [Newtonsoft.Json.JsonProperty("value", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Value { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Result37 + { + /// + /// Base58 encoded signature returned from the signer. + /// + [Newtonsoft.Json.JsonProperty("signature", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public string Signature { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Result38 + { + /// + /// Base58 encoded signature for the provided transaction. + /// + [Newtonsoft.Json.JsonProperty("signature", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public string Signature { get; set; } + + /// + /// Base64 encoded signed transaction that can be broadcast to the Solana network. + /// + [Newtonsoft.Json.JsonProperty("signedTransaction", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public string SignedTransaction { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Result39 + { + /// + /// Transaction signature returned by the Solana network. + /// + [Newtonsoft.Json.JsonProperty("signature", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public string Signature { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Result40 + { + /// + /// Idempotency key assigned to the queued transaction. + /// + [Newtonsoft.Json.JsonProperty("transactionId", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string TransactionId { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Result41 + { + /// + /// Idempotency key assigned to the queued transaction. + /// + [Newtonsoft.Json.JsonProperty("transactionId", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string TransactionId { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Result42 + { + /// + /// Idempotency key assigned to the queued transaction. + /// + [Newtonsoft.Json.JsonProperty("transactionId", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string TransactionId { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Result43 + { + /// + /// Idempotency key assigned to the queued transaction. + /// + [Newtonsoft.Json.JsonProperty("transactionId", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string TransactionId { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Result44 + { + /// + /// Input token mint address. + /// + [Newtonsoft.Json.JsonProperty("inputMint", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string InputMint { get; set; } + + /// + /// Output token mint address. + /// + [Newtonsoft.Json.JsonProperty("outputMint", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string OutputMint { get; set; } + + /// + /// Amount of input token to swap. + /// + [Newtonsoft.Json.JsonProperty("inputAmount", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string InputAmount { get; set; } + + /// + /// Expected amount of output token to receive. + /// + [Newtonsoft.Json.JsonProperty("outputAmount", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string OutputAmount { get; set; } + + /// + /// USD value of the input amount. + /// + [Newtonsoft.Json.JsonProperty("inputUsdValue", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double InputUsdValue { get; set; } + + /// + /// USD value of the output amount. + /// + [Newtonsoft.Json.JsonProperty("outputUsdValue", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double OutputUsdValue { get; set; } + + /// + /// Slippage tolerance in basis points (1 bps = 0.01%). + /// + [Newtonsoft.Json.JsonProperty("slippageBps", Required = Newtonsoft.Json.Required.Always)] + public double SlippageBps { get; set; } + + /// + /// Quote request ID for executing the swap. + /// + [Newtonsoft.Json.JsonProperty("requestId", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string RequestId { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Result45 + { + /// + /// Transaction signature for the confirmed swap on the Solana network. + /// + [Newtonsoft.Json.JsonProperty("signature", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public string Signature { get; set; } + + /// + /// Input token mint address. + /// + [Newtonsoft.Json.JsonProperty("inputMint", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string InputMint { get; set; } + + /// + /// Output token mint address. + /// + [Newtonsoft.Json.JsonProperty("outputMint", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string OutputMint { get; set; } + + /// + /// Amount of input token swapped. + /// + [Newtonsoft.Json.JsonProperty("inputAmount", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string InputAmount { get; set; } + + /// + /// Amount of output token received. + /// + [Newtonsoft.Json.JsonProperty("outputAmount", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string OutputAmount { get; set; } + + /// + /// USD value of the input amount. + /// + [Newtonsoft.Json.JsonProperty("inputUsdValue", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double InputUsdValue { get; set; } + + /// + /// USD value of the output amount. + /// + [Newtonsoft.Json.JsonProperty("outputUsdValue", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double OutputUsdValue { get; set; } + + /// + /// Request ID for this swap. + /// + [Newtonsoft.Json.JsonProperty("requestId", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string RequestId { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Result46 + { + /// + /// Unique identifier for the transaction. + /// + [Newtonsoft.Json.JsonProperty("id", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Id { get; set; } + + /// + /// Solana network identifier in CAIP-2 format. Use "solana:mainnet" or "solana:devnet" for convenience, or full CAIP-2 format. + /// + [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string ChainId { get; set; } + + /// + /// Signer address used on submission. + /// + [Newtonsoft.Json.JsonProperty("from", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + [System.ComponentModel.DataAnnotations.RegularExpression(@"^[1-9A-HJ-NP-Za-km-z]{32,44}$")] + public string From { get; set; } + + /// + /// Signature recorded on-chain once available. + /// + [Newtonsoft.Json.JsonProperty("signature", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Signature { get; set; } + + /// + /// Current status of the transaction in the processing pipeline. + /// + [Newtonsoft.Json.JsonProperty("status", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] + public Result46Status? Status { get; set; } + + /// + /// Timestamp when the transaction reached the reported status. + /// + [Newtonsoft.Json.JsonProperty("confirmedAt", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string ConfirmedAt { get; set; } + + /// + /// Slot where the transaction was confirmed, if available. + /// + [Newtonsoft.Json.JsonProperty("confirmedAtSlot", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string ConfirmedAtSlot { get; set; } + + /// + /// Unix timestamp of the processed block. + /// + [Newtonsoft.Json.JsonProperty("blockTime", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public int? BlockTime { get; set; } + + /// + /// ISO 8601 timestamp when the transaction was queued. + /// + [Newtonsoft.Json.JsonProperty("createdAt", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string CreatedAt { get; set; } + + /// + /// Error message if the transaction failed. + /// + [Newtonsoft.Json.JsonProperty("errorMessage", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string ErrorMessage { get; set; } + + /// + /// Resolved execution parameters used for the transaction. + /// + [Newtonsoft.Json.JsonProperty("executionParams", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public object ExecutionParams { get; set; } + + /// + /// Raw execution result payload, if present. + /// + [Newtonsoft.Json.JsonProperty("executionResult", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public object ExecutionResult { get; set; } + + /// + /// Original instruction payload submitted. + /// + [Newtonsoft.Json.JsonProperty("transactionParams", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public object TransactionParams { get; set; } + + /// + /// Project client identifier. + /// + [Newtonsoft.Json.JsonProperty("clientId", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string ClientId { get; set; } + + [Newtonsoft.Json.JsonProperty("enrichedData", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public object EnrichedData { get; set; } + + [Newtonsoft.Json.JsonProperty("cancelledAt", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string CancelledAt { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + /// + /// Sign a transaction + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Actions + { + [Newtonsoft.Json.JsonProperty("session_id", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Session_id { get; set; } + + [Newtonsoft.Json.JsonProperty("request_id", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Request_id { get; set; } + + [Newtonsoft.Json.JsonProperty("source", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Source { get; set; } = "model"; + + [Newtonsoft.Json.JsonProperty("type", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] + public ActionsType Type { get; set; } + + [Newtonsoft.Json.JsonProperty("data", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Data2 Data { get; set; } = new Data2(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public enum PaymentPayloadScheme + { + + [System.Runtime.Serialization.EnumMember(Value = @"exact")] + Exact = 0, + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Network2 + { + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Payload + { + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public enum PaymentRequirementsScheme + { + + [System.Runtime.Serialization.EnumMember(Value = @"exact")] + Exact = 0, + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Network3 + { + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class PayTo + { + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Asset + { + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public enum PaymentRequirements2Scheme + { + + [System.Runtime.Serialization.EnumMember(Value = @"exact")] + Exact = 0, + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Network4 + { + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class PayTo2 + { + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Asset2 + { + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class InputSchema + { + [Newtonsoft.Json.JsonProperty("queryParams", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public System.Collections.Generic.IDictionary QueryParams { get; set; } + + [Newtonsoft.Json.JsonProperty("bodyType", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] + public InputSchemaBodyType BodyType { get; set; } + + [Newtonsoft.Json.JsonProperty("bodyFields", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public System.Collections.Generic.IDictionary BodyFields { get; set; } + + [Newtonsoft.Json.JsonProperty("headerFields", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public System.Collections.Generic.IDictionary HeaderFields { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public enum SaleType + { + + [System.Runtime.Serialization.EnumMember(Value = @"pool")] + Pool = 0, + + } + + /// + /// Account metadata required for executing an instruction. + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Accounts + { + /// + /// Public key for the account. + /// + [Newtonsoft.Json.JsonProperty("address", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + [System.ComponentModel.DataAnnotations.RegularExpression(@"^[1-9A-HJ-NP-Za-km-z]{32,44}$")] + public string Address { get; set; } + + /// + /// Whether this account must sign the transaction. + /// + [Newtonsoft.Json.JsonProperty("isSigner", Required = Newtonsoft.Json.Required.Always)] + public bool IsSigner { get; set; } + + /// + /// Whether this account can be modified by the instruction. + /// + [Newtonsoft.Json.JsonProperty("isWritable", Required = Newtonsoft.Json.Required.Always)] + public bool IsWritable { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public enum InstructionsEncoding + { + + [System.Runtime.Serialization.EnumMember(Value = @"hex")] + Hex = 0, + + [System.Runtime.Serialization.EnumMember(Value = @"base64")] + Base64 = 1, + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public enum PriorityFeeType + { + + [System.Runtime.Serialization.EnumMember(Value = @"auto")] + Auto = 0, + + } + + /// + /// Account metadata required for executing an instruction. + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class accounts + { + /// + /// Public key for the account. + /// + [Newtonsoft.Json.JsonProperty("address", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + [System.ComponentModel.DataAnnotations.RegularExpression(@"^[1-9A-HJ-NP-Za-km-z]{32,44}$")] + public string Address { get; set; } + + /// + /// Whether this account must sign the transaction. + /// + [Newtonsoft.Json.JsonProperty("isSigner", Required = Newtonsoft.Json.Required.Always)] + public bool IsSigner { get; set; } + + /// + /// Whether this account can be modified by the instruction. + /// + [Newtonsoft.Json.JsonProperty("isWritable", Required = Newtonsoft.Json.Required.Always)] + public bool IsWritable { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public enum instructionsEncoding + { + + [System.Runtime.Serialization.EnumMember(Value = @"hex")] + Hex = 0, + + [System.Runtime.Serialization.EnumMember(Value = @"base64")] + Base64 = 1, + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public enum PriorityFee2Type + { + + [System.Runtime.Serialization.EnumMember(Value = @"auto")] + Auto = 0, + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public enum MessagesRole + { + + [System.Runtime.Serialization.EnumMember(Value = @"user")] + User = 0, + + [System.Runtime.Serialization.EnumMember(Value = @"assistant")] + Assistant = 1, + + [System.Runtime.Serialization.EnumMember(Value = @"system")] + System = 2, + + [System.Runtime.Serialization.EnumMember(Value = @"tool")] + Tool = 3, + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Content + { + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + /// + /// Authentication provider details with type-based discrimination + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Profiles + { + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Pagination3 + { + /// + /// Whether there are more items available + /// + [Newtonsoft.Json.JsonProperty("hasMore", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public bool HasMore { get; set; } + + /// + /// Number of items per page + /// + [Newtonsoft.Json.JsonProperty("limit", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double? Limit { get; set; } = 20D; + + /// + /// Current page number + /// + [Newtonsoft.Json.JsonProperty("page", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double? Page { get; set; } = 1D; + + /// + /// Total number of items available + /// + [Newtonsoft.Json.JsonProperty("totalCount", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double? TotalCount { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Wallets + { + /// + /// Unique identifier for the user wallet within the thirdweb auth system. + /// + [Newtonsoft.Json.JsonProperty("userId", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string UserId { get; set; } + + /// + /// The EOA (Externally Owned Wallet) address of the wallet. This is the traditional wallet address. + /// + [Newtonsoft.Json.JsonProperty("address", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Address { get; set; } + + /// + /// The date and time the wallet was created + /// + [Newtonsoft.Json.JsonProperty("createdAt", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string CreatedAt { get; set; } + + /// + /// The profiles linked to the wallet, can be email, phone, google etc, or backend for developer created wallets + /// + [Newtonsoft.Json.JsonProperty("profiles", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.ICollection Profiles { get; set; } = new System.Collections.ObjectModel.Collection(); + + /// + /// The smart wallet address with EIP-4337 support. This address enables gasless transactions and advanced wallet features. + /// + [Newtonsoft.Json.JsonProperty("smartWalletAddress", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string SmartWalletAddress { get; set; } + + /// + /// The wallet's public key in hexadecimal format. Useful for peer-to-peer encryption and cryptographic operations. + /// + [Newtonsoft.Json.JsonProperty("publicKey", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string PublicKey { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + /// + /// Authentication provider details with type-based discrimination + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class profiles + { + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Pagination4 + { + /// + /// Whether there are more items available + /// + [Newtonsoft.Json.JsonProperty("hasMore", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public bool HasMore { get; set; } + + /// + /// Number of items per page + /// + [Newtonsoft.Json.JsonProperty("limit", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double? Limit { get; set; } = 20D; + + /// + /// Current page number + /// + [Newtonsoft.Json.JsonProperty("page", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double? Page { get; set; } = 1D; + + /// + /// Total number of items available + /// + [Newtonsoft.Json.JsonProperty("totalCount", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double? TotalCount { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class wallets + { + /// + /// Unique identifier for the user wallet within the thirdweb auth system. + /// + [Newtonsoft.Json.JsonProperty("userId", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string UserId { get; set; } + + /// + /// The EOA (Externally Owned Wallet) address of the wallet. This is the traditional wallet address. + /// + [Newtonsoft.Json.JsonProperty("address", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Address { get; set; } + + /// + /// The date and time the wallet was created + /// + [Newtonsoft.Json.JsonProperty("createdAt", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string CreatedAt { get; set; } + + /// + /// The profiles linked to the wallet, can be email, phone, google etc, or backend for developer created wallets + /// + [Newtonsoft.Json.JsonProperty("profiles", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.ICollection Profiles { get; set; } = new System.Collections.ObjectModel.Collection(); + + /// + /// The smart wallet address with EIP-4337 support. This address enables gasless transactions and advanced wallet features. + /// + [Newtonsoft.Json.JsonProperty("smartWalletAddress", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string SmartWalletAddress { get; set; } + + /// + /// The wallet's public key in hexadecimal format. Useful for peer-to-peer encryption and cryptographic operations. + /// + [Newtonsoft.Json.JsonProperty("publicKey", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string PublicKey { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + /// + /// Authentication provider details with type-based discrimination + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Profiles2 + { + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Pagination5 + { + /// + /// Whether there are more items available + /// + [Newtonsoft.Json.JsonProperty("hasMore", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public bool HasMore { get; set; } + + /// + /// Number of items per page + /// + [Newtonsoft.Json.JsonProperty("limit", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double? Limit { get; set; } = 20D; + + /// + /// Current page number + /// + [Newtonsoft.Json.JsonProperty("page", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double? Page { get; set; } = 1D; + + /// + /// Total number of items available + /// + [Newtonsoft.Json.JsonProperty("totalCount", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double? TotalCount { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class transactions + { + /// + /// The hash of the block containing this transaction. + /// + [Newtonsoft.Json.JsonProperty("blockHash", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string BlockHash { get; set; } + + /// + /// The block number containing this transaction. + /// + [Newtonsoft.Json.JsonProperty("blockNumber", Required = Newtonsoft.Json.Required.Always)] + public double BlockNumber { get; set; } + + /// + /// The timestamp of the block (Unix timestamp). + /// + [Newtonsoft.Json.JsonProperty("blockTimestamp", Required = Newtonsoft.Json.Required.Always)] + public double BlockTimestamp { get; set; } + + /// + /// The chain ID where the transaction occurred. + /// + [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string ChainId { get; set; } + + /// + /// Contract address created if this was a contract creation transaction. + /// + [Newtonsoft.Json.JsonProperty("contractAddress", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string ContractAddress { get; set; } + + /// + /// Total gas used by all transactions in this block up to and including this one. + /// + [Newtonsoft.Json.JsonProperty("cumulativeGasUsed", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double CumulativeGasUsed { get; set; } + + /// + /// The transaction input data. + /// + [Newtonsoft.Json.JsonProperty("data", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Data { get; set; } + + /// + /// Decoded transaction data (included when ABI is available). + /// + [Newtonsoft.Json.JsonProperty("decoded", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public Decoded Decoded { get; set; } + + /// + /// The effective gas price paid (in wei as string). + /// + [Newtonsoft.Json.JsonProperty("effectiveGasPrice", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string EffectiveGasPrice { get; set; } + + /// + /// The address that initiated the transaction. + /// + [Newtonsoft.Json.JsonProperty("fromAddress", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string FromAddress { get; set; } + + /// + /// The function selector (first 4 bytes of the transaction data). + /// + [Newtonsoft.Json.JsonProperty("functionSelector", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string FunctionSelector { get; set; } + + /// + /// The gas limit for the transaction. + /// + [Newtonsoft.Json.JsonProperty("gas", Required = Newtonsoft.Json.Required.Always)] + public double Gas { get; set; } + + /// + /// The gas price used for the transaction (in wei as string). + /// + [Newtonsoft.Json.JsonProperty("gasPrice", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string GasPrice { get; set; } + + /// + /// The amount of gas used by the transaction. + /// + [Newtonsoft.Json.JsonProperty("gasUsed", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double GasUsed { get; set; } + + /// + /// The transaction hash. + /// + [Newtonsoft.Json.JsonProperty("hash", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Hash { get; set; } + + /// + /// Maximum fee per gas (EIP-1559). + /// + [Newtonsoft.Json.JsonProperty("maxFeePerGas", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string MaxFeePerGas { get; set; } + + /// + /// Maximum priority fee per gas (EIP-1559). + /// + [Newtonsoft.Json.JsonProperty("maxPriorityFeePerGas", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string MaxPriorityFeePerGas { get; set; } + + /// + /// The transaction nonce. + /// + [Newtonsoft.Json.JsonProperty("nonce", Required = Newtonsoft.Json.Required.Always)] + public double Nonce { get; set; } + + /// + /// The transaction status (1 for success, 0 for failure). + /// + [Newtonsoft.Json.JsonProperty("status", Required = Newtonsoft.Json.Required.Always)] + public double Status { get; set; } + + /// + /// The address that received the transaction. + /// + [Newtonsoft.Json.JsonProperty("toAddress", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string ToAddress { get; set; } + + /// + /// The index of the transaction within the block. + /// + [Newtonsoft.Json.JsonProperty("transactionIndex", Required = Newtonsoft.Json.Required.Always)] + public double TransactionIndex { get; set; } + + /// + /// The transaction type (0=legacy, 1=EIP-2930, 2=EIP-1559). + /// + [Newtonsoft.Json.JsonProperty("transactionType", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double TransactionType { get; set; } + + /// + /// The value transferred in the transaction (in wei as string). + /// + [Newtonsoft.Json.JsonProperty("value", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Value { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Pagination6 + { + /// + /// Whether there are more items available + /// + [Newtonsoft.Json.JsonProperty("hasMore", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public bool HasMore { get; set; } + + /// + /// Number of items per page + /// + [Newtonsoft.Json.JsonProperty("limit", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double? Limit { get; set; } = 20D; + + /// + /// Current page number + /// + [Newtonsoft.Json.JsonProperty("page", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double? Page { get; set; } = 1D; + + /// + /// Total number of items available + /// + [Newtonsoft.Json.JsonProperty("totalCount", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double? TotalCount { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class tokens + { + /// + /// The token balance as a string + /// + [Newtonsoft.Json.JsonProperty("balance", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Balance { get; set; } + + /// + /// The chain ID of the token + /// + [Newtonsoft.Json.JsonProperty("chain_id", Required = Newtonsoft.Json.Required.Always)] + public double Chain_id { get; set; } + + /// + /// The number of decimal places + /// + [Newtonsoft.Json.JsonProperty("decimals", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double Decimals { get; set; } + + /// + /// The token name + /// + [Newtonsoft.Json.JsonProperty("name", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Name { get; set; } + + /// + /// The token icon URI + /// + [Newtonsoft.Json.JsonProperty("icon_uri", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Icon_uri { get; set; } + + /// + /// Price data + /// + [Newtonsoft.Json.JsonProperty("prices", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public System.Collections.Generic.IDictionary Prices { get; set; } + + /// + /// Price data for the token + /// + [Newtonsoft.Json.JsonProperty("price_data", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public Price_data Price_data { get; set; } + + /// + /// The token symbol + /// + [Newtonsoft.Json.JsonProperty("symbol", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Symbol { get; set; } + + /// + /// The contract address of the token + /// + [Newtonsoft.Json.JsonProperty("token_address", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Token_address { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Nfts + { + /// + /// The animation URL of the NFT + /// + [Newtonsoft.Json.JsonProperty("animation_url", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Animation_url { get; set; } + + /// + /// The attributes/traits of the NFT + /// + [Newtonsoft.Json.JsonProperty("attributes", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public System.Collections.Generic.ICollection Attributes { get; set; } + + /// + /// The chain ID of the NFT + /// + [Newtonsoft.Json.JsonProperty("chain_id", Required = Newtonsoft.Json.Required.Always)] + public double Chain_id { get; set; } + + /// + /// Collection information + /// + [Newtonsoft.Json.JsonProperty("collection", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public Collection Collection { get; set; } + + /// + /// The description of the NFT + /// + [Newtonsoft.Json.JsonProperty("description", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Description { get; set; } + + /// + /// The external URL of the NFT + /// + [Newtonsoft.Json.JsonProperty("external_url", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string External_url { get; set; } + + /// + /// The image URL of the NFT + /// + [Newtonsoft.Json.JsonProperty("image_url", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Image_url { get; set; } + + /// + /// Additional metadata for the NFT + /// + [Newtonsoft.Json.JsonProperty("metadata", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public System.Collections.Generic.IDictionary Metadata { get; set; } + + /// + /// The name of the NFT + /// + [Newtonsoft.Json.JsonProperty("name", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Name { get; set; } + + /// + /// The contract address of the NFT collection + /// + [Newtonsoft.Json.JsonProperty("token_address", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Token_address { get; set; } + + /// + /// The token ID of the NFT + /// + [Newtonsoft.Json.JsonProperty("token_id", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Token_id { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Pagination7 + { + /// + /// Whether there are more items available + /// + [Newtonsoft.Json.JsonProperty("hasMore", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public bool HasMore { get; set; } + + /// + /// Number of items per page + /// + [Newtonsoft.Json.JsonProperty("limit", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double? Limit { get; set; } = 20D; + + /// + /// Current page number + /// + [Newtonsoft.Json.JsonProperty("page", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double? Page { get; set; } = 1D; + + /// + /// Total number of items available + /// + [Newtonsoft.Json.JsonProperty("totalCount", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double? TotalCount { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + /// + /// Contract details enriched with additional project information from the API server. + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Contracts + { + /// + /// The contract address. + /// + [Newtonsoft.Json.JsonProperty("address", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Address { get; set; } + + /// + /// The chain ID where the contract is deployed. + /// + [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string ChainId { get; set; } + + /// + /// The date when the contract was deployed. + /// + [Newtonsoft.Json.JsonProperty("deployedAt", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string DeployedAt { get; set; } + + /// + /// The contract ID. + /// + [Newtonsoft.Json.JsonProperty("id", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Id { get; set; } + + /// + /// The date when the contract was imported to the dashboard. + /// + [Newtonsoft.Json.JsonProperty("importedAt", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string ImportedAt { get; set; } + + /// + /// The contract name, if available. + /// + [Newtonsoft.Json.JsonProperty("name", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Name { get; set; } + + /// + /// The contract symbol, if available. + /// + [Newtonsoft.Json.JsonProperty("symbol", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Symbol { get; set; } + + /// + /// The contract type (e.g., ERC20, ERC721, etc.). + /// + [Newtonsoft.Json.JsonProperty("type", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Type { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Pagination8 + { + /// + /// Whether there are more items available + /// + [Newtonsoft.Json.JsonProperty("hasMore", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public bool HasMore { get; set; } + + /// + /// Number of items per page + /// + [Newtonsoft.Json.JsonProperty("limit", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double? Limit { get; set; } = 20D; + + /// + /// Current page number + /// + [Newtonsoft.Json.JsonProperty("page", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double? Page { get; set; } = 1D; + + /// + /// Total number of items available + /// + [Newtonsoft.Json.JsonProperty("totalCount", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double? TotalCount { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Quote + { + /// + /// Block number when quote was generated + /// + [Newtonsoft.Json.JsonProperty("blockNumber", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string BlockNumber { get; set; } + + /// + /// Destination amount in wei + /// + [Newtonsoft.Json.JsonProperty("destinationAmount", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string DestinationAmount { get; set; } + + /// + /// Estimated execution time in milliseconds + /// + [Newtonsoft.Json.JsonProperty("estimatedExecutionTimeMs", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double EstimatedExecutionTimeMs { get; set; } + + /// + /// Quote intent details + /// + [Newtonsoft.Json.JsonProperty("intent", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Intent Intent { get; set; } = new Intent(); + + /// + /// Origin amount in wei + /// + [Newtonsoft.Json.JsonProperty("originAmount", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string OriginAmount { get; set; } + + /// + /// Array of steps to complete the bridge operation + /// + [Newtonsoft.Json.JsonProperty("steps", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.ICollection Steps { get; set; } = new System.Collections.ObjectModel.Collection(); + + /// + /// Quote timestamp + /// + [Newtonsoft.Json.JsonProperty("timestamp", Required = Newtonsoft.Json.Required.Always)] + public double Timestamp { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class data + { + /// + /// The hash of the block containing this transaction. + /// + [Newtonsoft.Json.JsonProperty("blockHash", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string BlockHash { get; set; } + + /// + /// The block number containing this transaction. + /// + [Newtonsoft.Json.JsonProperty("blockNumber", Required = Newtonsoft.Json.Required.Always)] + public double BlockNumber { get; set; } + + /// + /// The timestamp of the block (Unix timestamp). + /// + [Newtonsoft.Json.JsonProperty("blockTimestamp", Required = Newtonsoft.Json.Required.Always)] + public double BlockTimestamp { get; set; } + + /// + /// The chain ID where the transaction occurred. + /// + [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string ChainId { get; set; } + + /// + /// Contract address created if this was a contract creation transaction. + /// + [Newtonsoft.Json.JsonProperty("contractAddress", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string ContractAddress { get; set; } + + /// + /// Total gas used by all transactions in this block up to and including this one. + /// + [Newtonsoft.Json.JsonProperty("cumulativeGasUsed", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double CumulativeGasUsed { get; set; } + + /// + /// The transaction input data. + /// + [Newtonsoft.Json.JsonProperty("data", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Data { get; set; } + + /// + /// Decoded transaction data (included when ABI is available). + /// + [Newtonsoft.Json.JsonProperty("decoded", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public Decoded2 Decoded { get; set; } + + /// + /// The effective gas price paid (in wei as string). + /// + [Newtonsoft.Json.JsonProperty("effectiveGasPrice", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string EffectiveGasPrice { get; set; } + + /// + /// The address that initiated the transaction. + /// + [Newtonsoft.Json.JsonProperty("fromAddress", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string FromAddress { get; set; } + + /// + /// The function selector (first 4 bytes of the transaction data). + /// + [Newtonsoft.Json.JsonProperty("functionSelector", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string FunctionSelector { get; set; } + + /// + /// The gas limit for the transaction. + /// + [Newtonsoft.Json.JsonProperty("gas", Required = Newtonsoft.Json.Required.Always)] + public double Gas { get; set; } + + /// + /// The gas price used for the transaction (in wei as string). + /// + [Newtonsoft.Json.JsonProperty("gasPrice", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string GasPrice { get; set; } + + /// + /// The amount of gas used by the transaction. + /// + [Newtonsoft.Json.JsonProperty("gasUsed", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double GasUsed { get; set; } + + /// + /// The transaction hash. + /// + [Newtonsoft.Json.JsonProperty("hash", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Hash { get; set; } + + /// + /// Maximum fee per gas (EIP-1559). + /// + [Newtonsoft.Json.JsonProperty("maxFeePerGas", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string MaxFeePerGas { get; set; } + + /// + /// Maximum priority fee per gas (EIP-1559). + /// + [Newtonsoft.Json.JsonProperty("maxPriorityFeePerGas", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string MaxPriorityFeePerGas { get; set; } + + /// + /// The transaction nonce. + /// + [Newtonsoft.Json.JsonProperty("nonce", Required = Newtonsoft.Json.Required.Always)] + public double Nonce { get; set; } + + /// + /// The transaction status (1 for success, 0 for failure). + /// + [Newtonsoft.Json.JsonProperty("status", Required = Newtonsoft.Json.Required.Always)] + public double Status { get; set; } + + /// + /// The address that received the transaction. + /// + [Newtonsoft.Json.JsonProperty("toAddress", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string ToAddress { get; set; } + + /// + /// The index of the transaction within the block. + /// + [Newtonsoft.Json.JsonProperty("transactionIndex", Required = Newtonsoft.Json.Required.Always)] + public double TransactionIndex { get; set; } + + /// + /// The transaction type (0=legacy, 1=EIP-2930, 2=EIP-1559). + /// + [Newtonsoft.Json.JsonProperty("transactionType", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double TransactionType { get; set; } + + /// + /// The value transferred in the transaction (in wei as string). + /// + [Newtonsoft.Json.JsonProperty("value", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Value { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Pagination9 + { + /// + /// Whether there are more items available + /// + [Newtonsoft.Json.JsonProperty("hasMore", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public bool HasMore { get; set; } + + /// + /// Number of items per page + /// + [Newtonsoft.Json.JsonProperty("limit", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double? Limit { get; set; } = 20D; + + /// + /// Current page number + /// + [Newtonsoft.Json.JsonProperty("page", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double? Page { get; set; } = 1D; + + /// + /// Total number of items available + /// + [Newtonsoft.Json.JsonProperty("totalCount", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double? TotalCount { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Events + { + /// + /// The contract address that emitted the event. + /// + [Newtonsoft.Json.JsonProperty("address", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Address { get; set; } + + /// + /// The hash of the block containing this event. + /// + [Newtonsoft.Json.JsonProperty("blockHash", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string BlockHash { get; set; } + + /// + /// The block number where the event was emitted. + /// + [Newtonsoft.Json.JsonProperty("blockNumber", Required = Newtonsoft.Json.Required.Always)] + public double BlockNumber { get; set; } + + /// + /// The timestamp of the block (Unix timestamp). + /// + [Newtonsoft.Json.JsonProperty("blockTimestamp", Required = Newtonsoft.Json.Required.Always)] + public double BlockTimestamp { get; set; } + + /// + /// The chain ID where the event occurred. + /// + [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string ChainId { get; set; } + + /// + /// The non-indexed event data as a hex string. + /// + [Newtonsoft.Json.JsonProperty("data", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Data { get; set; } + + /// + /// Decoded event data (included when ABI is available). + /// + [Newtonsoft.Json.JsonProperty("decoded", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public Decoded3 Decoded { get; set; } + + /// + /// The index of the log within the transaction. + /// + [Newtonsoft.Json.JsonProperty("logIndex", Required = Newtonsoft.Json.Required.Always)] + public double LogIndex { get; set; } + + /// + /// Array of indexed event topics (including event signature). + /// + [Newtonsoft.Json.JsonProperty("topics", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.ICollection Topics { get; set; } = new System.Collections.ObjectModel.Collection(); + + /// + /// The hash of the transaction containing this event. + /// + [Newtonsoft.Json.JsonProperty("transactionHash", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string TransactionHash { get; set; } + + /// + /// The index of the transaction within the block. + /// + [Newtonsoft.Json.JsonProperty("transactionIndex", Required = Newtonsoft.Json.Required.Always)] + public double TransactionIndex { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Pagination10 + { + /// + /// Whether there are more items available + /// + [Newtonsoft.Json.JsonProperty("hasMore", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public bool HasMore { get; set; } + + /// + /// Number of items per page + /// + [Newtonsoft.Json.JsonProperty("limit", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double? Limit { get; set; } = 20D; + + /// + /// Current page number + /// + [Newtonsoft.Json.JsonProperty("page", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double? Page { get; set; } = 1D; + + /// + /// Total number of items available + /// + [Newtonsoft.Json.JsonProperty("totalCount", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double? TotalCount { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Compiler + { + /// + /// Solidity compiler version used to compile the contract. + /// + [Newtonsoft.Json.JsonProperty("version", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Version { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Output + { + /// + /// Contract ABI (Application Binary Interface) as an array of function/event/error definitions. + /// + [Newtonsoft.Json.JsonProperty("abi", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public System.Collections.Generic.ICollection Abi { get; set; } + + /// + /// Developer documentation extracted from contract comments. + /// + [Newtonsoft.Json.JsonProperty("devdoc", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public System.Collections.Generic.IDictionary Devdoc { get; set; } + + /// + /// User documentation extracted from contract comments. + /// + [Newtonsoft.Json.JsonProperty("userdoc", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public System.Collections.Generic.IDictionary Userdoc { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Settings + { + /// + /// Compilation target mapping source file names to contract names. + /// + [Newtonsoft.Json.JsonProperty("compilationTarget", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public System.Collections.Generic.IDictionary CompilationTarget { get; set; } + + /// + /// EVM version target for compilation. + /// + [Newtonsoft.Json.JsonProperty("evmVersion", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string EvmVersion { get; set; } + + /// + /// Library addresses for linking. + /// + [Newtonsoft.Json.JsonProperty("libraries", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public System.Collections.Generic.IDictionary Libraries { get; set; } + + /// + /// Metadata settings for compilation. + /// + [Newtonsoft.Json.JsonProperty("metadata", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public Metadata2 Metadata { get; set; } + + /// + /// Optimizer settings used during compilation. + /// + [Newtonsoft.Json.JsonProperty("optimizer", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public Optimizer Optimizer { get; set; } + + /// + /// Import remappings used during compilation. + /// + [Newtonsoft.Json.JsonProperty("remappings", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public System.Collections.Generic.ICollection Remappings { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public enum Result20Status + { + + [System.Runtime.Serialization.EnumMember(Value = @"QUEUED")] + QUEUED = 0, + + [System.Runtime.Serialization.EnumMember(Value = @"SUBMITTED")] + SUBMITTED = 1, + + [System.Runtime.Serialization.EnumMember(Value = @"CONFIRMED")] + CONFIRMED = 2, + + [System.Runtime.Serialization.EnumMember(Value = @"FAILED")] + FAILED = 3, + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Pagination11 + { + /// + /// Whether there are more items available + /// + [Newtonsoft.Json.JsonProperty("hasMore", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public bool HasMore { get; set; } + + /// + /// Number of items per page + /// + [Newtonsoft.Json.JsonProperty("limit", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double? Limit { get; set; } = 20D; + + /// + /// Current page number + /// + [Newtonsoft.Json.JsonProperty("page", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double? Page { get; set; } = 1D; + + /// + /// Total number of items available + /// + [Newtonsoft.Json.JsonProperty("totalCount", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double? TotalCount { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Transactions2 + { + /// + /// Index within transaction batch + /// + [Newtonsoft.Json.JsonProperty("batchIndex", Required = Newtonsoft.Json.Required.Always)] + public int BatchIndex { get; set; } + + /// + /// ISO timestamp when transaction was cancelled, if applicable + /// + [Newtonsoft.Json.JsonProperty("cancelledAt", Required = Newtonsoft.Json.Required.AllowNull)] + public string CancelledAt { get; set; } + + /// + /// Blockchain network identifier as string + /// + [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string ChainId { get; set; } + + /// + /// Client identifier that initiated the transaction + /// + [Newtonsoft.Json.JsonProperty("clientId", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string ClientId { get; set; } + + /// + /// ISO timestamp when transaction was confirmed on-chain + /// + [Newtonsoft.Json.JsonProperty("confirmedAt", Required = Newtonsoft.Json.Required.AllowNull)] + public string ConfirmedAt { get; set; } + + /// + /// Block number where transaction was confirmed + /// + [Newtonsoft.Json.JsonProperty("confirmedAtBlockNumber", Required = Newtonsoft.Json.Required.AllowNull)] + public string ConfirmedAtBlockNumber { get; set; } + + /// + /// ISO timestamp when transaction was created + /// + [Newtonsoft.Json.JsonProperty("createdAt", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string CreatedAt { get; set; } + + /// + /// Additional metadata and enriched transaction information + /// + [Newtonsoft.Json.JsonProperty("enrichedData", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public object EnrichedData { get; set; } + + /// + /// Error message if transaction failed + /// + [Newtonsoft.Json.JsonProperty("errorMessage", Required = Newtonsoft.Json.Required.AllowNull)] + public string ErrorMessage { get; set; } + + /// + /// Parameters used for transaction execution + /// + [Newtonsoft.Json.JsonProperty("executionParams", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public object ExecutionParams { get; set; } + + /// + /// Result data from transaction execution + /// + [Newtonsoft.Json.JsonProperty("executionResult", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public object ExecutionResult { get; set; } + + /// + /// Sender wallet address + /// + [Newtonsoft.Json.JsonProperty("from", Required = Newtonsoft.Json.Required.AllowNull)] + public string From { get; set; } + + /// + /// Unique transaction identifier + /// + [Newtonsoft.Json.JsonProperty("id", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Id { get; set; } + + /// + /// On-chain transaction hash once confirmed + /// + [Newtonsoft.Json.JsonProperty("transactionHash", Required = Newtonsoft.Json.Required.AllowNull)] + public string TransactionHash { get; set; } + + /// + /// Original transaction parameters and data + /// + [Newtonsoft.Json.JsonProperty("transactionParams", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public object TransactionParams { get; set; } + + /// + /// Transaction status + /// + [Newtonsoft.Json.JsonProperty("status", Required = Newtonsoft.Json.Required.AllowNull)] + [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] + public Transactions2Status? Status { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Quote2 + { + /// + /// Block number when quote was generated + /// + [Newtonsoft.Json.JsonProperty("blockNumber", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string BlockNumber { get; set; } + + /// + /// Destination amount in wei + /// + [Newtonsoft.Json.JsonProperty("destinationAmount", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string DestinationAmount { get; set; } + + /// + /// Estimated execution time in milliseconds + /// + [Newtonsoft.Json.JsonProperty("estimatedExecutionTimeMs", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double EstimatedExecutionTimeMs { get; set; } + + /// + /// Quote intent details + /// + [Newtonsoft.Json.JsonProperty("intent", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Intent2 Intent { get; set; } = new Intent2(); + + /// + /// Origin amount in wei + /// + [Newtonsoft.Json.JsonProperty("originAmount", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string OriginAmount { get; set; } + + /// + /// Array of steps to complete the bridge operation + /// + [Newtonsoft.Json.JsonProperty("steps", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.ICollection Steps { get; set; } = new System.Collections.ObjectModel.Collection(); + + /// + /// Quote timestamp + /// + [Newtonsoft.Json.JsonProperty("timestamp", Required = Newtonsoft.Json.Required.Always)] + public double Timestamp { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Quote3 + { + /// + /// Block number when quote was generated + /// + [Newtonsoft.Json.JsonProperty("blockNumber", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string BlockNumber { get; set; } + + /// + /// Destination amount in wei + /// + [Newtonsoft.Json.JsonProperty("destinationAmount", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string DestinationAmount { get; set; } + + /// + /// Estimated execution time in milliseconds + /// + [Newtonsoft.Json.JsonProperty("estimatedExecutionTimeMs", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double EstimatedExecutionTimeMs { get; set; } + + /// + /// Quote intent details + /// + [Newtonsoft.Json.JsonProperty("intent", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Intent3 Intent { get; set; } = new Intent3(); + + /// + /// Origin amount in wei + /// + [Newtonsoft.Json.JsonProperty("originAmount", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string OriginAmount { get; set; } + + /// + /// Array of steps to complete the bridge operation + /// + [Newtonsoft.Json.JsonProperty("steps", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.ICollection Steps { get; set; } = new System.Collections.ObjectModel.Collection(); + + /// + /// Quote timestamp + /// + [Newtonsoft.Json.JsonProperty("timestamp", Required = Newtonsoft.Json.Required.Always)] + public double Timestamp { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Transactions3 + { + [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Always)] + public int ChainId { get; set; } + + [Newtonsoft.Json.JsonProperty("transactionHash", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string TransactionHash { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public enum DataStatus + { + + [System.Runtime.Serialization.EnumMember(Value = @"PENDING")] + PENDING = 0, + + [System.Runtime.Serialization.EnumMember(Value = @"COMPLETED")] + COMPLETED = 1, + + [System.Runtime.Serialization.EnumMember(Value = @"FAILED")] + FAILED = 2, + + [System.Runtime.Serialization.EnumMember(Value = @"NOT_FOUND")] + NOT_FOUND = 3, + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public enum DataType + { + + [System.Runtime.Serialization.EnumMember(Value = @"buy")] + Buy = 0, + + [System.Runtime.Serialization.EnumMember(Value = @"sell")] + Sell = 1, + + [System.Runtime.Serialization.EnumMember(Value = @"transfer")] + Transfer = 2, + + [System.Runtime.Serialization.EnumMember(Value = @"onramp")] + Onramp = 3, + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class OriginToken + { + [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Always)] + public int ChainId { get; set; } + + /// + /// A valid Ethereum address (0x-prefixed hex string) or ENS name (e.g., vitalik.eth). + /// + [Newtonsoft.Json.JsonProperty("address", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Address { get; set; } + + [Newtonsoft.Json.JsonProperty("symbol", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Symbol { get; set; } + + [Newtonsoft.Json.JsonProperty("name", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Name { get; set; } + + [Newtonsoft.Json.JsonProperty("decimals", Required = Newtonsoft.Json.Required.Always)] + public int Decimals { get; set; } + + [Newtonsoft.Json.JsonProperty("iconUri", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string IconUri { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class DestinationToken + { + [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Always)] + public int ChainId { get; set; } + + /// + /// A valid Ethereum address (0x-prefixed hex string) or ENS name (e.g., vitalik.eth). + /// + [Newtonsoft.Json.JsonProperty("address", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Address { get; set; } + + [Newtonsoft.Json.JsonProperty("symbol", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Symbol { get; set; } + + [Newtonsoft.Json.JsonProperty("name", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Name { get; set; } + + [Newtonsoft.Json.JsonProperty("decimals", Required = Newtonsoft.Json.Required.Always)] + public int Decimals { get; set; } + + [Newtonsoft.Json.JsonProperty("iconUri", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string IconUri { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public enum KindsScheme + { + + [System.Runtime.Serialization.EnumMember(Value = @"exact")] + Exact = 0, + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Network5 + { + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Extra + { + [Newtonsoft.Json.JsonProperty("defaultAsset", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public DefaultAsset DefaultAsset { get; set; } + + [Newtonsoft.Json.JsonProperty("supportedAssets", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public System.Collections.Generic.ICollection SupportedAssets { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Quote4 + { + /// + /// Block number when quote was generated + /// + [Newtonsoft.Json.JsonProperty("blockNumber", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string BlockNumber { get; set; } + + /// + /// Destination amount in wei + /// + [Newtonsoft.Json.JsonProperty("destinationAmount", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string DestinationAmount { get; set; } + + /// + /// Estimated execution time in milliseconds + /// + [Newtonsoft.Json.JsonProperty("estimatedExecutionTimeMs", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double EstimatedExecutionTimeMs { get; set; } + + /// + /// Quote intent details + /// + [Newtonsoft.Json.JsonProperty("intent", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Intent4 Intent { get; set; } = new Intent4(); + + /// + /// Origin amount in wei + /// + [Newtonsoft.Json.JsonProperty("originAmount", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string OriginAmount { get; set; } + + /// + /// Array of steps to complete the bridge operation + /// + [Newtonsoft.Json.JsonProperty("steps", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.ICollection Steps { get; set; } = new System.Collections.ObjectModel.Collection(); + + /// + /// Quote timestamp + /// + [Newtonsoft.Json.JsonProperty("timestamp", Required = Newtonsoft.Json.Required.Always)] + public double Timestamp { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public enum ItemsType + { + + [System.Runtime.Serialization.EnumMember(Value = @"http")] + Http = 0, + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Accepts2 + { + [Newtonsoft.Json.JsonProperty("scheme", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] + public Accepts2Scheme Scheme { get; set; } + + /// + /// CAIP-2 blockchain identifier (e.g., 'eip155:1' for Ethereum, 'solana:4sGjMW1sUnHzSxGspuhpqLDx6wiyjNtZ' for Solana mainnet). Also accepts numeric EVM chain IDs (e.g., 1, 137) or aliases ('solana:mainnet', 'solana:devnet') for backward compatibility. + /// + [Newtonsoft.Json.JsonProperty("network", Required = Newtonsoft.Json.Required.Always)] + public Network8 Network { get; set; } + + [Newtonsoft.Json.JsonProperty("maxAmountRequired", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string MaxAmountRequired { get; set; } + + [Newtonsoft.Json.JsonProperty("resource", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public System.Uri Resource { get; set; } + + [Newtonsoft.Json.JsonProperty("description", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Description { get; set; } + + [Newtonsoft.Json.JsonProperty("mimeType", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string MimeType { get; set; } + + [Newtonsoft.Json.JsonProperty("outputSchema", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public System.Collections.Generic.IDictionary OutputSchema { get; set; } + + [Newtonsoft.Json.JsonProperty("payTo", Required = Newtonsoft.Json.Required.Always)] + public PayTo5 PayTo { get; set; } + + [Newtonsoft.Json.JsonProperty("maxTimeoutSeconds", Required = Newtonsoft.Json.Required.Always)] + public int MaxTimeoutSeconds { get; set; } + + [Newtonsoft.Json.JsonProperty("asset", Required = Newtonsoft.Json.Required.Always)] + public Asset5 Asset { get; set; } + + [Newtonsoft.Json.JsonProperty("extra", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public System.Collections.Generic.IDictionary Extra { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public enum AcceptsScheme + { + + [System.Runtime.Serialization.EnumMember(Value = @"exact")] + Exact = 0, + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Network6 + { + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class PayTo3 + { + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Asset3 + { + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public enum acceptsScheme + { + + [System.Runtime.Serialization.EnumMember(Value = @"exact")] + Exact = 0, + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Network7 + { + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class PayTo4 + { + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Asset4 + { + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Owners + { + /// + /// Owner wallet address + /// + [Newtonsoft.Json.JsonProperty("address", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Address { get; set; } + + /// + /// Token amount owned as a string + /// + [Newtonsoft.Json.JsonProperty("amount", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Amount { get; set; } + + /// + /// Token ID for NFTs + /// + [Newtonsoft.Json.JsonProperty("tokenId", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string TokenId { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Pagination12 + { + /// + /// Whether there are more items available + /// + [Newtonsoft.Json.JsonProperty("hasMore", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public bool HasMore { get; set; } + + /// + /// Number of items per page + /// + [Newtonsoft.Json.JsonProperty("limit", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double? Limit { get; set; } = 20D; + + /// + /// Current page number + /// + [Newtonsoft.Json.JsonProperty("page", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double? Page { get; set; } = 1D; + + /// + /// Total number of items available + /// + [Newtonsoft.Json.JsonProperty("totalCount", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double? TotalCount { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class NativeCurrency + { + /// + /// The name of the native currency + /// + [Newtonsoft.Json.JsonProperty("name", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Name { get; set; } + + /// + /// The symbol of the native currency + /// + [Newtonsoft.Json.JsonProperty("symbol", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Symbol { get; set; } + + /// + /// The number of decimals used by the native currency + /// + [Newtonsoft.Json.JsonProperty("decimals", Required = Newtonsoft.Json.Required.Always)] + public double Decimals { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + /// + /// Represents a supported bridge route between an origin and destination token. + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Routes + { + [Newtonsoft.Json.JsonProperty("originToken", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public OriginToken2 OriginToken { get; set; } = new OriginToken2(); + + [Newtonsoft.Json.JsonProperty("destinationToken", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public DestinationToken2 DestinationToken { get; set; } = new DestinationToken2(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Pagination13 + { + /// + /// Whether there are more items available + /// + [Newtonsoft.Json.JsonProperty("hasMore", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public bool HasMore { get; set; } + + /// + /// Number of items per page + /// + [Newtonsoft.Json.JsonProperty("limit", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double? Limit { get; set; } = 20D; + + /// + /// Current page number + /// + [Newtonsoft.Json.JsonProperty("page", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double? Page { get; set; } = 1D; + + /// + /// Total number of items available + /// + [Newtonsoft.Json.JsonProperty("totalCount", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double? TotalCount { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Quote5 + { + /// + /// Block number when quote was generated + /// + [Newtonsoft.Json.JsonProperty("blockNumber", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string BlockNumber { get; set; } + + /// + /// Destination amount in wei + /// + [Newtonsoft.Json.JsonProperty("destinationAmount", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string DestinationAmount { get; set; } + + /// + /// Estimated execution time in milliseconds + /// + [Newtonsoft.Json.JsonProperty("estimatedExecutionTimeMs", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double EstimatedExecutionTimeMs { get; set; } + + /// + /// Quote intent details + /// + [Newtonsoft.Json.JsonProperty("intent", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Intent5 Intent { get; set; } = new Intent5(); + + /// + /// Origin amount in wei + /// + [Newtonsoft.Json.JsonProperty("originAmount", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string OriginAmount { get; set; } + + /// + /// Array of steps to complete the bridge operation + /// + [Newtonsoft.Json.JsonProperty("steps", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.ICollection Steps { get; set; } = new System.Collections.ObjectModel.Collection(); + + /// + /// Quote timestamp + /// + [Newtonsoft.Json.JsonProperty("timestamp", Required = Newtonsoft.Json.Required.Always)] + public double Timestamp { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + /// + /// Details for a Solana wallet in your project. + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Wallets2 + { + /// + /// Base58 encoded Solana address. + /// + [Newtonsoft.Json.JsonProperty("address", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + [System.ComponentModel.DataAnnotations.RegularExpression(@"^[1-9A-HJ-NP-Za-km-z]{32,44}$")] + public string Address { get; set; } + + /// + /// Optional label associated with the wallet. + /// + [Newtonsoft.Json.JsonProperty("label", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Label { get; set; } + + /// + /// ISO 8601 timestamp indicating when the wallet was created. + /// + [Newtonsoft.Json.JsonProperty("createdAt", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string CreatedAt { get; set; } + + /// + /// ISO 8601 timestamp indicating when the wallet was last updated. + /// + [Newtonsoft.Json.JsonProperty("updatedAt", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string UpdatedAt { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Pagination14 + { + /// + /// Total number of wallets available. + /// + [Newtonsoft.Json.JsonProperty("totalCount", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Range(0D, double.MaxValue)] + public double TotalCount { get; set; } + + /// + /// Current page number. + /// + [Newtonsoft.Json.JsonProperty("page", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Range(0, int.MaxValue)] + public int Page { get; set; } + + /// + /// Number of wallets returned per page. + /// + [Newtonsoft.Json.JsonProperty("limit", Required = Newtonsoft.Json.Required.Always)] + public int Limit { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public enum Result46Status + { + + [System.Runtime.Serialization.EnumMember(Value = @"QUEUED")] + QUEUED = 0, + + [System.Runtime.Serialization.EnumMember(Value = @"SUBMITTED")] + SUBMITTED = 1, + + [System.Runtime.Serialization.EnumMember(Value = @"CONFIRMED")] + CONFIRMED = 2, + + [System.Runtime.Serialization.EnumMember(Value = @"FAILED")] + FAILED = 3, + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public enum ActionsType + { + + [System.Runtime.Serialization.EnumMember(Value = @"sign_transaction")] + Sign_transaction = 0, + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Data2 + { + [Newtonsoft.Json.JsonProperty("chain_id", Required = Newtonsoft.Json.Required.Always)] + public double Chain_id { get; set; } + + [Newtonsoft.Json.JsonProperty("function", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Function { get; set; } + + [Newtonsoft.Json.JsonProperty("to", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string To { get; set; } + + [Newtonsoft.Json.JsonProperty("value", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Value { get; set; } + + [Newtonsoft.Json.JsonProperty("data", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Data { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public enum InputSchemaBodyType + { + + [System.Runtime.Serialization.EnumMember(Value = @"json")] + Json = 0, + + [System.Runtime.Serialization.EnumMember(Value = @"form-data")] + FormData = 1, + + [System.Runtime.Serialization.EnumMember(Value = @"multipart-form-data")] + MultipartFormData = 2, + + [System.Runtime.Serialization.EnumMember(Value = @"text")] + Text = 3, + + [System.Runtime.Serialization.EnumMember(Value = @"binary")] + Binary = 4, + + } + + /// + /// Authentication provider details with type-based discrimination + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Profiles3 + { + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + /// + /// Authentication provider details with type-based discrimination + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Profiles4 + { + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Decoded + { + /// + /// Object containing decoded function parameters. + /// + [Newtonsoft.Json.JsonProperty("inputs", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.IDictionary Inputs { get; set; } = new System.Collections.Generic.Dictionary(); + + /// + /// The function name. + /// + [Newtonsoft.Json.JsonProperty("name", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Name { get; set; } + + /// + /// The function signature. + /// + [Newtonsoft.Json.JsonProperty("signature", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Signature { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Price_data + { + /// + /// The circulating supply of the token + /// + [Newtonsoft.Json.JsonProperty("circulating_supply", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double Circulating_supply { get; set; } + + /// + /// The market cap of the token in USD + /// + [Newtonsoft.Json.JsonProperty("market_cap_usd", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double Market_cap_usd { get; set; } + + /// + /// The percentage change of the token in the last 24 hours + /// + [Newtonsoft.Json.JsonProperty("percent_change_24h", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double Percent_change_24h { get; set; } + + /// + /// The timestamp of the latest price update + /// + [Newtonsoft.Json.JsonProperty("price_timestamp", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Price_timestamp { get; set; } + + /// + /// The price of the token in USD + /// + [Newtonsoft.Json.JsonProperty("price_usd", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double Price_usd { get; set; } + + /// + /// The total supply of the token + /// + [Newtonsoft.Json.JsonProperty("total_supply", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double Total_supply { get; set; } + + /// + /// The value of the token balance in USD + /// + [Newtonsoft.Json.JsonProperty("usd_value", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double Usd_value { get; set; } + + /// + /// The volume of the token in USD + /// + [Newtonsoft.Json.JsonProperty("volume_24h_usd", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double Volume_24h_usd { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Attributes + { + /// + /// The display type + /// + [Newtonsoft.Json.JsonProperty("display_type", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Display_type { get; set; } + + /// + /// The trait type + /// + [Newtonsoft.Json.JsonProperty("trait_type", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Trait_type { get; set; } + + /// + /// The trait value + /// + [Newtonsoft.Json.JsonProperty("value", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public Value Value { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Collection + { + /// + /// The collection description + /// + [Newtonsoft.Json.JsonProperty("description", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Description { get; set; } + + /// + /// The collection external URL + /// + [Newtonsoft.Json.JsonProperty("external_url", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string External_url { get; set; } + + /// + /// The collection image URL + /// + [Newtonsoft.Json.JsonProperty("image", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Image { get; set; } + + /// + /// The collection name + /// + [Newtonsoft.Json.JsonProperty("name", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Name { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Intent + { + /// + /// The amount in wei + /// + [Newtonsoft.Json.JsonProperty("amount", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Amount { get; set; } + + /// + /// Destination chain ID + /// + [Newtonsoft.Json.JsonProperty("destinationChainId", Required = Newtonsoft.Json.Required.Always)] + public int DestinationChainId { get; set; } + + /// + /// Destination token address + /// + [Newtonsoft.Json.JsonProperty("destinationTokenAddress", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string DestinationTokenAddress { get; set; } + + /// + /// Origin chain ID + /// + [Newtonsoft.Json.JsonProperty("originChainId", Required = Newtonsoft.Json.Required.Always)] + public int OriginChainId { get; set; } + + /// + /// Origin token address + /// + [Newtonsoft.Json.JsonProperty("originTokenAddress", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string OriginTokenAddress { get; set; } + + /// + /// Receiver address + /// + [Newtonsoft.Json.JsonProperty("receiver", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Receiver { get; set; } + + /// + /// Sender address + /// + [Newtonsoft.Json.JsonProperty("sender", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Sender { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Steps + { + /// + /// Origin token information + /// + [Newtonsoft.Json.JsonProperty("originToken", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public OriginToken3 OriginToken { get; set; } = new OriginToken3(); + + /// + /// Destination token information + /// + [Newtonsoft.Json.JsonProperty("destinationToken", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public DestinationToken3 DestinationToken { get; set; } = new DestinationToken3(); + + /// + /// Array of transactions for this step + /// + [Newtonsoft.Json.JsonProperty("transactions", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.ICollection Transactions { get; set; } = new System.Collections.ObjectModel.Collection(); + + /// + /// Origin amount in wei + /// + [Newtonsoft.Json.JsonProperty("originAmount", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string OriginAmount { get; set; } + + /// + /// Destination amount in wei + /// + [Newtonsoft.Json.JsonProperty("destinationAmount", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string DestinationAmount { get; set; } + + /// + /// Estimated execution time in milliseconds + /// + [Newtonsoft.Json.JsonProperty("estimatedExecutionTimeMs", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double EstimatedExecutionTimeMs { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Decoded2 + { + /// + /// Object containing decoded function parameters. + /// + [Newtonsoft.Json.JsonProperty("inputs", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.IDictionary Inputs { get; set; } = new System.Collections.Generic.Dictionary(); + + /// + /// The function name. + /// + [Newtonsoft.Json.JsonProperty("name", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Name { get; set; } + + /// + /// The function signature. + /// + [Newtonsoft.Json.JsonProperty("signature", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Signature { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Decoded3 + { + /// + /// The event name. + /// + [Newtonsoft.Json.JsonProperty("name", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Name { get; set; } + + /// + /// Object containing decoded parameters. + /// + [Newtonsoft.Json.JsonProperty("params", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.IDictionary Params { get; set; } = new System.Collections.Generic.Dictionary(); + + /// + /// The event signature. + /// + [Newtonsoft.Json.JsonProperty("signature", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Signature { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Metadata2 + { + /// + /// Hash method used for bytecode metadata. + /// + [Newtonsoft.Json.JsonProperty("bytecodeHash", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string BytecodeHash { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Optimizer + { + /// + /// Whether optimizer is enabled. + /// + [Newtonsoft.Json.JsonProperty("enabled", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public bool Enabled { get; set; } + + /// + /// Number of optimizer runs. + /// + [Newtonsoft.Json.JsonProperty("runs", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double Runs { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public enum Transactions2Status + { + + [System.Runtime.Serialization.EnumMember(Value = @"QUEUED")] + QUEUED = 0, + + [System.Runtime.Serialization.EnumMember(Value = @"SUBMITTED")] + SUBMITTED = 1, + + [System.Runtime.Serialization.EnumMember(Value = @"CONFIRMED")] + CONFIRMED = 2, + + [System.Runtime.Serialization.EnumMember(Value = @"FAILED")] + FAILED = 3, + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Intent2 + { + /// + /// The amount in wei + /// + [Newtonsoft.Json.JsonProperty("amount", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Amount { get; set; } + + /// + /// Destination chain ID + /// + [Newtonsoft.Json.JsonProperty("destinationChainId", Required = Newtonsoft.Json.Required.Always)] + public int DestinationChainId { get; set; } + + /// + /// Destination token address + /// + [Newtonsoft.Json.JsonProperty("destinationTokenAddress", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string DestinationTokenAddress { get; set; } + + /// + /// Origin chain ID + /// + [Newtonsoft.Json.JsonProperty("originChainId", Required = Newtonsoft.Json.Required.Always)] + public int OriginChainId { get; set; } + + /// + /// Origin token address + /// + [Newtonsoft.Json.JsonProperty("originTokenAddress", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string OriginTokenAddress { get; set; } + + /// + /// Receiver address + /// + [Newtonsoft.Json.JsonProperty("receiver", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Receiver { get; set; } + + /// + /// Sender address + /// + [Newtonsoft.Json.JsonProperty("sender", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Sender { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class steps + { + /// + /// Origin token information + /// + [Newtonsoft.Json.JsonProperty("originToken", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public OriginToken4 OriginToken { get; set; } = new OriginToken4(); + + /// + /// Destination token information + /// + [Newtonsoft.Json.JsonProperty("destinationToken", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public DestinationToken4 DestinationToken { get; set; } = new DestinationToken4(); + + /// + /// Array of transactions for this step + /// + [Newtonsoft.Json.JsonProperty("transactions", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.ICollection Transactions { get; set; } = new System.Collections.ObjectModel.Collection(); + + /// + /// Origin amount in wei + /// + [Newtonsoft.Json.JsonProperty("originAmount", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string OriginAmount { get; set; } + + /// + /// Destination amount in wei + /// + [Newtonsoft.Json.JsonProperty("destinationAmount", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string DestinationAmount { get; set; } + + /// + /// Estimated execution time in milliseconds + /// + [Newtonsoft.Json.JsonProperty("estimatedExecutionTimeMs", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double EstimatedExecutionTimeMs { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Intent3 + { + /// + /// The amount in wei + /// + [Newtonsoft.Json.JsonProperty("amount", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Amount { get; set; } + + /// + /// Destination chain ID + /// + [Newtonsoft.Json.JsonProperty("destinationChainId", Required = Newtonsoft.Json.Required.Always)] + public int DestinationChainId { get; set; } + + /// + /// Destination token address + /// + [Newtonsoft.Json.JsonProperty("destinationTokenAddress", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string DestinationTokenAddress { get; set; } + + /// + /// Origin chain ID + /// + [Newtonsoft.Json.JsonProperty("originChainId", Required = Newtonsoft.Json.Required.Always)] + public int OriginChainId { get; set; } + + /// + /// Origin token address + /// + [Newtonsoft.Json.JsonProperty("originTokenAddress", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string OriginTokenAddress { get; set; } + + /// + /// Receiver address + /// + [Newtonsoft.Json.JsonProperty("receiver", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Receiver { get; set; } + + /// + /// Sender address + /// + [Newtonsoft.Json.JsonProperty("sender", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Sender { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Steps2 + { + /// + /// Origin token information + /// + [Newtonsoft.Json.JsonProperty("originToken", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public OriginToken5 OriginToken { get; set; } = new OriginToken5(); + + /// + /// Destination token information + /// + [Newtonsoft.Json.JsonProperty("destinationToken", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public DestinationToken5 DestinationToken { get; set; } = new DestinationToken5(); + + /// + /// Array of transactions for this step + /// + [Newtonsoft.Json.JsonProperty("transactions", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.ICollection Transactions { get; set; } = new System.Collections.ObjectModel.Collection(); + + /// + /// Origin amount in wei + /// + [Newtonsoft.Json.JsonProperty("originAmount", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string OriginAmount { get; set; } + + /// + /// Destination amount in wei + /// + [Newtonsoft.Json.JsonProperty("destinationAmount", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string DestinationAmount { get; set; } + + /// + /// Estimated execution time in milliseconds + /// + [Newtonsoft.Json.JsonProperty("estimatedExecutionTimeMs", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double EstimatedExecutionTimeMs { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class DefaultAsset + { + /// + /// A valid Ethereum address (0x-prefixed hex string) or ENS name (e.g., vitalik.eth). + /// + [Newtonsoft.Json.JsonProperty("address", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Address { get; set; } + + [Newtonsoft.Json.JsonProperty("decimals", Required = Newtonsoft.Json.Required.Always)] + public double Decimals { get; set; } + + [Newtonsoft.Json.JsonProperty("eip712", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Eip712 Eip712 { get; set; } = new Eip712(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class SupportedAssets + { + /// + /// A valid Ethereum address (0x-prefixed hex string) or ENS name (e.g., vitalik.eth). + /// + [Newtonsoft.Json.JsonProperty("address", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Address { get; set; } + + [Newtonsoft.Json.JsonProperty("decimals", Required = Newtonsoft.Json.Required.Always)] + public double Decimals { get; set; } + + [Newtonsoft.Json.JsonProperty("eip712", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Eip7122 Eip712 { get; set; } = new Eip7122(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Intent4 + { + /// + /// The amount in wei + /// + [Newtonsoft.Json.JsonProperty("amount", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Amount { get; set; } + + /// + /// Destination chain ID + /// + [Newtonsoft.Json.JsonProperty("destinationChainId", Required = Newtonsoft.Json.Required.Always)] + public int DestinationChainId { get; set; } + + /// + /// Destination token address + /// + [Newtonsoft.Json.JsonProperty("destinationTokenAddress", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string DestinationTokenAddress { get; set; } + + /// + /// Origin chain ID + /// + [Newtonsoft.Json.JsonProperty("originChainId", Required = Newtonsoft.Json.Required.Always)] + public int OriginChainId { get; set; } + + /// + /// Origin token address + /// + [Newtonsoft.Json.JsonProperty("originTokenAddress", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string OriginTokenAddress { get; set; } + + /// + /// Receiver address + /// + [Newtonsoft.Json.JsonProperty("receiver", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Receiver { get; set; } + + /// + /// Sender address + /// + [Newtonsoft.Json.JsonProperty("sender", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Sender { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Steps3 + { + /// + /// Origin token information + /// + [Newtonsoft.Json.JsonProperty("originToken", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public OriginToken6 OriginToken { get; set; } = new OriginToken6(); + + /// + /// Destination token information + /// + [Newtonsoft.Json.JsonProperty("destinationToken", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public DestinationToken6 DestinationToken { get; set; } = new DestinationToken6(); + + /// + /// Array of transactions for this step + /// + [Newtonsoft.Json.JsonProperty("transactions", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.ICollection Transactions { get; set; } = new System.Collections.ObjectModel.Collection(); + + /// + /// Origin amount in wei + /// + [Newtonsoft.Json.JsonProperty("originAmount", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string OriginAmount { get; set; } + + /// + /// Destination amount in wei + /// + [Newtonsoft.Json.JsonProperty("destinationAmount", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string DestinationAmount { get; set; } + + /// + /// Estimated execution time in milliseconds + /// + [Newtonsoft.Json.JsonProperty("estimatedExecutionTimeMs", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double EstimatedExecutionTimeMs { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public enum Accepts2Scheme + { + + [System.Runtime.Serialization.EnumMember(Value = @"exact")] + Exact = 0, + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Network8 + { + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class PayTo5 + { + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Asset5 + { + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class OriginToken2 + { + /// + /// Chain identifier for the token + /// + [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Always)] + public int ChainId { get; set; } + + /// + /// Token contract address + /// + [Newtonsoft.Json.JsonProperty("address", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Address { get; set; } + + /// + /// Token symbol + /// + [Newtonsoft.Json.JsonProperty("symbol", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Symbol { get; set; } + + /// + /// Token name + /// + [Newtonsoft.Json.JsonProperty("name", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Name { get; set; } + + /// + /// Number of decimals the token uses + /// + [Newtonsoft.Json.JsonProperty("decimals", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Range(0, int.MaxValue)] + public int Decimals { get; set; } + + /// + /// Optional icon URL for the token + /// + [Newtonsoft.Json.JsonProperty("iconUri", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public System.Uri IconUri { get; set; } + + /// + /// 24h market capitalization in USD when available + /// + [Newtonsoft.Json.JsonProperty("marketCapUsd", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Range(0D, double.MaxValue)] + public double MarketCapUsd { get; set; } + + /// + /// 24h trading volume in USD when available + /// + [Newtonsoft.Json.JsonProperty("volume24hUsd", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Range(0D, double.MaxValue)] + public double Volume24hUsd { get; set; } + + /// + /// Token price quotes keyed by fiat currency code + /// + [Newtonsoft.Json.JsonProperty("prices", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public System.Collections.Generic.IDictionary Prices { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class DestinationToken2 + { + /// + /// Chain identifier for the token + /// + [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Always)] + public int ChainId { get; set; } + + /// + /// Token contract address + /// + [Newtonsoft.Json.JsonProperty("address", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Address { get; set; } + + /// + /// Token symbol + /// + [Newtonsoft.Json.JsonProperty("symbol", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Symbol { get; set; } + + /// + /// Token name + /// + [Newtonsoft.Json.JsonProperty("name", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Name { get; set; } + + /// + /// Number of decimals the token uses + /// + [Newtonsoft.Json.JsonProperty("decimals", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Range(0, int.MaxValue)] + public int Decimals { get; set; } + + /// + /// Optional icon URL for the token + /// + [Newtonsoft.Json.JsonProperty("iconUri", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public System.Uri IconUri { get; set; } + + /// + /// 24h market capitalization in USD when available + /// + [Newtonsoft.Json.JsonProperty("marketCapUsd", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Range(0D, double.MaxValue)] + public double MarketCapUsd { get; set; } + + /// + /// 24h trading volume in USD when available + /// + [Newtonsoft.Json.JsonProperty("volume24hUsd", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Range(0D, double.MaxValue)] + public double Volume24hUsd { get; set; } + + /// + /// Token price quotes keyed by fiat currency code + /// + [Newtonsoft.Json.JsonProperty("prices", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public System.Collections.Generic.IDictionary Prices { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Intent5 + { + /// + /// The amount in wei + /// + [Newtonsoft.Json.JsonProperty("amount", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Amount { get; set; } + + /// + /// Destination chain ID + /// + [Newtonsoft.Json.JsonProperty("destinationChainId", Required = Newtonsoft.Json.Required.Always)] + public int DestinationChainId { get; set; } + + /// + /// Destination token address + /// + [Newtonsoft.Json.JsonProperty("destinationTokenAddress", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string DestinationTokenAddress { get; set; } + + /// + /// Origin chain ID + /// + [Newtonsoft.Json.JsonProperty("originChainId", Required = Newtonsoft.Json.Required.Always)] + public int OriginChainId { get; set; } + + /// + /// Origin token address + /// + [Newtonsoft.Json.JsonProperty("originTokenAddress", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string OriginTokenAddress { get; set; } + + /// + /// Receiver address + /// + [Newtonsoft.Json.JsonProperty("receiver", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Receiver { get; set; } + + /// + /// Sender address + /// + [Newtonsoft.Json.JsonProperty("sender", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Sender { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Steps4 + { + /// + /// Origin token information + /// + [Newtonsoft.Json.JsonProperty("originToken", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public OriginToken7 OriginToken { get; set; } = new OriginToken7(); + + /// + /// Destination token information + /// + [Newtonsoft.Json.JsonProperty("destinationToken", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public DestinationToken7 DestinationToken { get; set; } = new DestinationToken7(); + + /// + /// Array of transactions for this step + /// + [Newtonsoft.Json.JsonProperty("transactions", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.ICollection Transactions { get; set; } = new System.Collections.ObjectModel.Collection(); + + /// + /// Origin amount in wei + /// + [Newtonsoft.Json.JsonProperty("originAmount", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string OriginAmount { get; set; } + + /// + /// Destination amount in wei + /// + [Newtonsoft.Json.JsonProperty("destinationAmount", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string DestinationAmount { get; set; } + + /// + /// Estimated execution time in milliseconds + /// + [Newtonsoft.Json.JsonProperty("estimatedExecutionTimeMs", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double EstimatedExecutionTimeMs { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Value + { + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class OriginToken3 + { + /// + /// The blockchain network identifier. Common values include: 1 (Ethereum), 8453 (Base), 137 (Polygon), 56 (BSC), 43114 (Avalanche), 42161 (Arbitrum), 10 (Optimism). + /// + [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Always)] + public int ChainId { get; set; } + + /// + /// A valid Ethereum address (0x-prefixed hex string) or ENS name (e.g., vitalik.eth). + /// + [Newtonsoft.Json.JsonProperty("address", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Address { get; set; } + + [Newtonsoft.Json.JsonProperty("decimals", Required = Newtonsoft.Json.Required.Always)] + public double Decimals { get; set; } + + [Newtonsoft.Json.JsonProperty("symbol", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Symbol { get; set; } + + [Newtonsoft.Json.JsonProperty("iconUri", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string IconUri { get; set; } + + /// + /// Token price in different FIAT currencies. + /// + [Newtonsoft.Json.JsonProperty("prices", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.IDictionary Prices { get; set; } = new System.Collections.Generic.Dictionary(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class DestinationToken3 + { + /// + /// The blockchain network identifier. Common values include: 1 (Ethereum), 8453 (Base), 137 (Polygon), 56 (BSC), 43114 (Avalanche), 42161 (Arbitrum), 10 (Optimism). + /// + [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Always)] + public int ChainId { get; set; } + + /// + /// A valid Ethereum address (0x-prefixed hex string) or ENS name (e.g., vitalik.eth). + /// + [Newtonsoft.Json.JsonProperty("address", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Address { get; set; } + + [Newtonsoft.Json.JsonProperty("decimals", Required = Newtonsoft.Json.Required.Always)] + public double Decimals { get; set; } + + [Newtonsoft.Json.JsonProperty("symbol", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Symbol { get; set; } + + [Newtonsoft.Json.JsonProperty("iconUri", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string IconUri { get; set; } + + /// + /// Token price in different FIAT currencies. + /// + [Newtonsoft.Json.JsonProperty("prices", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.IDictionary Prices { get; set; } = new System.Collections.Generic.Dictionary(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Transactions4 + { + /// + /// Blockchain network identifier + /// + [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Always)] + public int ChainId { get; set; } + + /// + /// Transaction recipient address + /// + [Newtonsoft.Json.JsonProperty("to", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string To { get; set; } + + /// + /// Transaction data payload + /// + [Newtonsoft.Json.JsonProperty("data", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Data { get; set; } + + /// + /// Type of action this transaction performs + /// + [Newtonsoft.Json.JsonProperty("action", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] + public Transactions4Action Action { get; set; } + + /// + /// Transaction sender address + /// + [Newtonsoft.Json.JsonProperty("from", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string From { get; set; } + + /// + /// Spender address for approval transactions + /// + [Newtonsoft.Json.JsonProperty("spender", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Spender { get; set; } + + /// + /// Transaction value in wei + /// + [Newtonsoft.Json.JsonProperty("value", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Value { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class OriginToken4 + { + /// + /// The blockchain network identifier. Common values include: 1 (Ethereum), 8453 (Base), 137 (Polygon), 56 (BSC), 43114 (Avalanche), 42161 (Arbitrum), 10 (Optimism). + /// + [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Always)] + public int ChainId { get; set; } + + /// + /// A valid Ethereum address (0x-prefixed hex string) or ENS name (e.g., vitalik.eth). + /// + [Newtonsoft.Json.JsonProperty("address", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Address { get; set; } + + [Newtonsoft.Json.JsonProperty("decimals", Required = Newtonsoft.Json.Required.Always)] + public double Decimals { get; set; } + + [Newtonsoft.Json.JsonProperty("symbol", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Symbol { get; set; } + + [Newtonsoft.Json.JsonProperty("iconUri", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string IconUri { get; set; } + + /// + /// Token price in different FIAT currencies. + /// + [Newtonsoft.Json.JsonProperty("prices", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.IDictionary Prices { get; set; } = new System.Collections.Generic.Dictionary(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class DestinationToken4 + { + /// + /// The blockchain network identifier. Common values include: 1 (Ethereum), 8453 (Base), 137 (Polygon), 56 (BSC), 43114 (Avalanche), 42161 (Arbitrum), 10 (Optimism). + /// + [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Always)] + public int ChainId { get; set; } + + /// + /// A valid Ethereum address (0x-prefixed hex string) or ENS name (e.g., vitalik.eth). + /// + [Newtonsoft.Json.JsonProperty("address", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Address { get; set; } + + [Newtonsoft.Json.JsonProperty("decimals", Required = Newtonsoft.Json.Required.Always)] + public double Decimals { get; set; } + + [Newtonsoft.Json.JsonProperty("symbol", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Symbol { get; set; } + + [Newtonsoft.Json.JsonProperty("iconUri", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string IconUri { get; set; } + + /// + /// Token price in different FIAT currencies. + /// + [Newtonsoft.Json.JsonProperty("prices", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.IDictionary Prices { get; set; } = new System.Collections.Generic.Dictionary(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Transactions5 + { + /// + /// Blockchain network identifier + /// + [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Always)] + public int ChainId { get; set; } + + /// + /// Transaction recipient address + /// + [Newtonsoft.Json.JsonProperty("to", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string To { get; set; } + + /// + /// Transaction data payload + /// + [Newtonsoft.Json.JsonProperty("data", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Data { get; set; } + + /// + /// Type of action this transaction performs + /// + [Newtonsoft.Json.JsonProperty("action", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] + public Transactions5Action Action { get; set; } + + /// + /// Transaction sender address + /// + [Newtonsoft.Json.JsonProperty("from", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string From { get; set; } + + /// + /// Spender address for approval transactions + /// + [Newtonsoft.Json.JsonProperty("spender", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Spender { get; set; } + + /// + /// Transaction value in wei + /// + [Newtonsoft.Json.JsonProperty("value", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Value { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class OriginToken5 + { + /// + /// The blockchain network identifier. Common values include: 1 (Ethereum), 8453 (Base), 137 (Polygon), 56 (BSC), 43114 (Avalanche), 42161 (Arbitrum), 10 (Optimism). + /// + [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Always)] + public int ChainId { get; set; } + + /// + /// A valid Ethereum address (0x-prefixed hex string) or ENS name (e.g., vitalik.eth). + /// + [Newtonsoft.Json.JsonProperty("address", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Address { get; set; } + + [Newtonsoft.Json.JsonProperty("decimals", Required = Newtonsoft.Json.Required.Always)] + public double Decimals { get; set; } + + [Newtonsoft.Json.JsonProperty("symbol", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Symbol { get; set; } + + [Newtonsoft.Json.JsonProperty("iconUri", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string IconUri { get; set; } + + /// + /// Token price in different FIAT currencies. + /// + [Newtonsoft.Json.JsonProperty("prices", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.IDictionary Prices { get; set; } = new System.Collections.Generic.Dictionary(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class DestinationToken5 + { + /// + /// The blockchain network identifier. Common values include: 1 (Ethereum), 8453 (Base), 137 (Polygon), 56 (BSC), 43114 (Avalanche), 42161 (Arbitrum), 10 (Optimism). + /// + [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Always)] + public int ChainId { get; set; } + + /// + /// A valid Ethereum address (0x-prefixed hex string) or ENS name (e.g., vitalik.eth). + /// + [Newtonsoft.Json.JsonProperty("address", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Address { get; set; } + + [Newtonsoft.Json.JsonProperty("decimals", Required = Newtonsoft.Json.Required.Always)] + public double Decimals { get; set; } + + [Newtonsoft.Json.JsonProperty("symbol", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Symbol { get; set; } + + [Newtonsoft.Json.JsonProperty("iconUri", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string IconUri { get; set; } + + /// + /// Token price in different FIAT currencies. + /// + [Newtonsoft.Json.JsonProperty("prices", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.IDictionary Prices { get; set; } = new System.Collections.Generic.Dictionary(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Transactions6 + { + /// + /// Blockchain network identifier + /// + [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Always)] + public int ChainId { get; set; } + + /// + /// Transaction recipient address + /// + [Newtonsoft.Json.JsonProperty("to", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string To { get; set; } + + /// + /// Transaction data payload + /// + [Newtonsoft.Json.JsonProperty("data", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Data { get; set; } + + /// + /// Type of action this transaction performs + /// + [Newtonsoft.Json.JsonProperty("action", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] + public Transactions6Action Action { get; set; } + + /// + /// Transaction sender address + /// + [Newtonsoft.Json.JsonProperty("from", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string From { get; set; } + + /// + /// Spender address for approval transactions + /// + [Newtonsoft.Json.JsonProperty("spender", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Spender { get; set; } + + /// + /// Transaction value in wei + /// + [Newtonsoft.Json.JsonProperty("value", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Value { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Eip712 + { + [Newtonsoft.Json.JsonProperty("name", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Name { get; set; } + + [Newtonsoft.Json.JsonProperty("version", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Version { get; set; } + + [Newtonsoft.Json.JsonProperty("primaryType", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] + public Eip712PrimaryType PrimaryType { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Eip7122 + { + [Newtonsoft.Json.JsonProperty("name", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Name { get; set; } + + [Newtonsoft.Json.JsonProperty("version", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Version { get; set; } + + [Newtonsoft.Json.JsonProperty("primaryType", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] + public Eip7122PrimaryType PrimaryType { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class OriginToken6 + { + /// + /// The blockchain network identifier. Common values include: 1 (Ethereum), 8453 (Base), 137 (Polygon), 56 (BSC), 43114 (Avalanche), 42161 (Arbitrum), 10 (Optimism). + /// + [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Always)] + public int ChainId { get; set; } + + /// + /// A valid Ethereum address (0x-prefixed hex string) or ENS name (e.g., vitalik.eth). + /// + [Newtonsoft.Json.JsonProperty("address", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Address { get; set; } + + [Newtonsoft.Json.JsonProperty("decimals", Required = Newtonsoft.Json.Required.Always)] + public double Decimals { get; set; } + + [Newtonsoft.Json.JsonProperty("symbol", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Symbol { get; set; } + + [Newtonsoft.Json.JsonProperty("iconUri", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string IconUri { get; set; } + + /// + /// Token price in different FIAT currencies. + /// + [Newtonsoft.Json.JsonProperty("prices", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.IDictionary Prices { get; set; } = new System.Collections.Generic.Dictionary(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class DestinationToken6 + { + /// + /// The blockchain network identifier. Common values include: 1 (Ethereum), 8453 (Base), 137 (Polygon), 56 (BSC), 43114 (Avalanche), 42161 (Arbitrum), 10 (Optimism). + /// + [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Always)] + public int ChainId { get; set; } + + /// + /// A valid Ethereum address (0x-prefixed hex string) or ENS name (e.g., vitalik.eth). + /// + [Newtonsoft.Json.JsonProperty("address", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Address { get; set; } + + [Newtonsoft.Json.JsonProperty("decimals", Required = Newtonsoft.Json.Required.Always)] + public double Decimals { get; set; } + + [Newtonsoft.Json.JsonProperty("symbol", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Symbol { get; set; } + + [Newtonsoft.Json.JsonProperty("iconUri", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string IconUri { get; set; } + + /// + /// Token price in different FIAT currencies. + /// + [Newtonsoft.Json.JsonProperty("prices", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.IDictionary Prices { get; set; } = new System.Collections.Generic.Dictionary(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Transactions7 + { + /// + /// Blockchain network identifier + /// + [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Always)] + public int ChainId { get; set; } + + /// + /// Transaction recipient address + /// + [Newtonsoft.Json.JsonProperty("to", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string To { get; set; } + + /// + /// Transaction data payload + /// + [Newtonsoft.Json.JsonProperty("data", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Data { get; set; } + + /// + /// Type of action this transaction performs + /// + [Newtonsoft.Json.JsonProperty("action", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] + public Transactions7Action Action { get; set; } + + /// + /// Transaction sender address + /// + [Newtonsoft.Json.JsonProperty("from", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string From { get; set; } + + /// + /// Spender address for approval transactions + /// + [Newtonsoft.Json.JsonProperty("spender", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Spender { get; set; } + + /// + /// Transaction value in wei + /// + [Newtonsoft.Json.JsonProperty("value", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Value { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class OriginToken7 + { + /// + /// The blockchain network identifier. Common values include: 1 (Ethereum), 8453 (Base), 137 (Polygon), 56 (BSC), 43114 (Avalanche), 42161 (Arbitrum), 10 (Optimism). + /// + [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Always)] + public int ChainId { get; set; } + + /// + /// A valid Ethereum address (0x-prefixed hex string) or ENS name (e.g., vitalik.eth). + /// + [Newtonsoft.Json.JsonProperty("address", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Address { get; set; } + + [Newtonsoft.Json.JsonProperty("decimals", Required = Newtonsoft.Json.Required.Always)] + public double Decimals { get; set; } + + [Newtonsoft.Json.JsonProperty("symbol", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Symbol { get; set; } + + [Newtonsoft.Json.JsonProperty("iconUri", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string IconUri { get; set; } + + /// + /// Token price in different FIAT currencies. + /// + [Newtonsoft.Json.JsonProperty("prices", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.IDictionary Prices { get; set; } = new System.Collections.Generic.Dictionary(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class DestinationToken7 + { + /// + /// The blockchain network identifier. Common values include: 1 (Ethereum), 8453 (Base), 137 (Polygon), 56 (BSC), 43114 (Avalanche), 42161 (Arbitrum), 10 (Optimism). + /// + [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Always)] + public int ChainId { get; set; } + + /// + /// A valid Ethereum address (0x-prefixed hex string) or ENS name (e.g., vitalik.eth). + /// + [Newtonsoft.Json.JsonProperty("address", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Address { get; set; } + + [Newtonsoft.Json.JsonProperty("decimals", Required = Newtonsoft.Json.Required.Always)] + public double Decimals { get; set; } + + [Newtonsoft.Json.JsonProperty("symbol", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Symbol { get; set; } + + [Newtonsoft.Json.JsonProperty("iconUri", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string IconUri { get; set; } + + /// + /// Token price in different FIAT currencies. + /// + [Newtonsoft.Json.JsonProperty("prices", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.IDictionary Prices { get; set; } = new System.Collections.Generic.Dictionary(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Transactions8 + { + /// + /// Blockchain network identifier + /// + [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Always)] + public int ChainId { get; set; } + + /// + /// Transaction recipient address + /// + [Newtonsoft.Json.JsonProperty("to", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string To { get; set; } + + /// + /// Transaction data payload + /// + [Newtonsoft.Json.JsonProperty("data", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Data { get; set; } + + /// + /// Type of action this transaction performs + /// + [Newtonsoft.Json.JsonProperty("action", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] + public Transactions8Action Action { get; set; } + + /// + /// Transaction sender address + /// + [Newtonsoft.Json.JsonProperty("from", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string From { get; set; } + + /// + /// Spender address for approval transactions + /// + [Newtonsoft.Json.JsonProperty("spender", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Spender { get; set; } + + /// + /// Transaction value in wei + /// + [Newtonsoft.Json.JsonProperty("value", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Value { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public enum Transactions4Action + { + + [System.Runtime.Serialization.EnumMember(Value = @"approval")] + Approval = 0, + + [System.Runtime.Serialization.EnumMember(Value = @"transfer")] + Transfer = 1, + + [System.Runtime.Serialization.EnumMember(Value = @"buy")] + Buy = 2, + + [System.Runtime.Serialization.EnumMember(Value = @"sell")] + Sell = 3, + + [System.Runtime.Serialization.EnumMember(Value = @"fee")] + Fee = 4, + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public enum Transactions5Action + { + + [System.Runtime.Serialization.EnumMember(Value = @"approval")] + Approval = 0, + + [System.Runtime.Serialization.EnumMember(Value = @"transfer")] + Transfer = 1, + + [System.Runtime.Serialization.EnumMember(Value = @"buy")] + Buy = 2, + + [System.Runtime.Serialization.EnumMember(Value = @"sell")] + Sell = 3, + + [System.Runtime.Serialization.EnumMember(Value = @"fee")] + Fee = 4, + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public enum Transactions6Action + { + + [System.Runtime.Serialization.EnumMember(Value = @"approval")] + Approval = 0, + + [System.Runtime.Serialization.EnumMember(Value = @"transfer")] + Transfer = 1, + + [System.Runtime.Serialization.EnumMember(Value = @"buy")] + Buy = 2, + + [System.Runtime.Serialization.EnumMember(Value = @"sell")] + Sell = 3, + + [System.Runtime.Serialization.EnumMember(Value = @"fee")] + Fee = 4, + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public enum Eip712PrimaryType + { + + [System.Runtime.Serialization.EnumMember(Value = @"TransferWithAuthorization")] + TransferWithAuthorization = 0, + + [System.Runtime.Serialization.EnumMember(Value = @"Permit")] + Permit = 1, + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public enum Eip7122PrimaryType + { + + [System.Runtime.Serialization.EnumMember(Value = @"TransferWithAuthorization")] + TransferWithAuthorization = 0, + + [System.Runtime.Serialization.EnumMember(Value = @"Permit")] + Permit = 1, + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public enum Transactions7Action + { + + [System.Runtime.Serialization.EnumMember(Value = @"approval")] + Approval = 0, + + [System.Runtime.Serialization.EnumMember(Value = @"transfer")] + Transfer = 1, + + [System.Runtime.Serialization.EnumMember(Value = @"buy")] + Buy = 2, + + [System.Runtime.Serialization.EnumMember(Value = @"sell")] + Sell = 3, + + [System.Runtime.Serialization.EnumMember(Value = @"fee")] + Fee = 4, + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public enum Transactions8Action + { + + [System.Runtime.Serialization.EnumMember(Value = @"approval")] + Approval = 0, + + [System.Runtime.Serialization.EnumMember(Value = @"transfer")] + Transfer = 1, + + [System.Runtime.Serialization.EnumMember(Value = @"buy")] + Buy = 2, + + [System.Runtime.Serialization.EnumMember(Value = @"sell")] + Sell = 3, + + [System.Runtime.Serialization.EnumMember(Value = @"fee")] + Fee = 4, + + } + + + + [System.CodeDom.Compiler.GeneratedCode("NSwag", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class ApiException : System.Exception + { + public int StatusCode { get; private set; } + + public string Response { get; private set; } + + public System.Collections.Generic.IReadOnlyDictionary> Headers { get; private set; } + + public ApiException(string message, int statusCode, string response, System.Collections.Generic.IReadOnlyDictionary> headers, System.Exception innerException) + : base(message + "\n\nStatus: " + statusCode + "\nResponse: \n" + ((response == null) ? "(null)" : response.Substring(0, response.Length >= 512 ? 512 : response.Length)), innerException) + { + StatusCode = statusCode; + Response = response; + Headers = headers; + } + + public override string ToString() + { + return string.Format("HTTP Response: \n\n{0}\n\n{1}", Response, base.ToString()); + } + } + + [System.CodeDom.Compiler.GeneratedCode("NSwag", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class ApiException : ApiException + { + public TResult Result { get; private set; } + + public ApiException(string message, int statusCode, string response, System.Collections.Generic.IReadOnlyDictionary> headers, TResult result, System.Exception innerException) + : base(message, statusCode, response, headers, innerException) + { + Result = result; + } + } + +} + +#pragma warning restore 108 +#pragma warning restore 114 +#pragma warning restore 472 +#pragma warning restore 612 +#pragma warning restore 1573 +#pragma warning restore 1591 +#pragma warning restore 8073 +#pragma warning restore 3016 +#pragma warning restore 8600 +#pragma warning restore 8602 +#pragma warning restore 8603 +#pragma warning restore 8604 +#pragma warning restore 8625 \ No newline at end of file diff --git a/Thirdweb/Thirdweb.Api/ThirdwebHttpClientWrapper.cs b/Thirdweb/Thirdweb.Api/ThirdwebHttpClientWrapper.cs new file mode 100644 index 00000000..6b8b2ccc --- /dev/null +++ b/Thirdweb/Thirdweb.Api/ThirdwebHttpClientWrapper.cs @@ -0,0 +1,50 @@ +namespace Thirdweb.Api; + +/// +/// Wrapper class that adapts IThirdwebHttpClient to work with System.Net.Http.HttpClient expectations +/// +public class ThirdwebHttpClientWrapper : HttpClient +{ + private readonly IThirdwebHttpClient _thirdwebClient; + + public ThirdwebHttpClientWrapper(IThirdwebHttpClient thirdwebClient) + { + this._thirdwebClient = thirdwebClient ?? throw new ArgumentNullException(nameof(thirdwebClient)); + } + + public override async Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) + { + return await this.SendAsync(request, HttpCompletionOption.ResponseContentRead, cancellationToken); + } + + public new async Task SendAsync(HttpRequestMessage request, HttpCompletionOption completionOption, CancellationToken cancellationToken) + { + _ = completionOption; + + var content = request.Content; + + ThirdwebHttpResponseMessage thirdwebResponse; + + switch (request.Method.Method.ToUpperInvariant()) + { + case "GET": + thirdwebResponse = await this._thirdwebClient.GetAsync(request.RequestUri.ToString(), cancellationToken); + break; + case "POST": + thirdwebResponse = await this._thirdwebClient.PostAsync(request.RequestUri.ToString(), content, cancellationToken); + break; + case "PUT": + thirdwebResponse = await this._thirdwebClient.PutAsync(request.RequestUri.ToString(), content, cancellationToken); + break; + case "DELETE": + thirdwebResponse = await this._thirdwebClient.DeleteAsync(request.RequestUri.ToString(), cancellationToken); + break; + default: + throw new NotSupportedException($"HTTP method {request.Method} is not supported"); + } + + var response = new HttpResponseMessage((System.Net.HttpStatusCode)thirdwebResponse.StatusCode) { Content = new StringContent(await thirdwebResponse.Content.ReadAsStringAsync()) }; + + return response; + } +} diff --git a/Thirdweb/Thirdweb.Client/ITimeoutOptions.cs b/Thirdweb/Thirdweb.Client/ITimeoutOptions.cs deleted file mode 100644 index 4846911d..00000000 --- a/Thirdweb/Thirdweb.Client/ITimeoutOptions.cs +++ /dev/null @@ -1,16 +0,0 @@ -namespace Thirdweb -{ - /// - /// Interface for defining timeout options for different types of operations. - /// - public interface ITimeoutOptions - { - /// - /// Gets the timeout value for the specified operation type. - /// - /// The type of operation. - /// The fallback timeout value if none is specified. - /// The timeout value for the specified operation type. - int GetTimeout(TimeoutType type, int fallback = Constants.DEFAULT_FETCH_TIMEOUT); - } -} diff --git a/Thirdweb/Thirdweb.Client/ThirdwebClient.Types.cs b/Thirdweb/Thirdweb.Client/ThirdwebClient.Types.cs new file mode 100644 index 00000000..797a2516 --- /dev/null +++ b/Thirdweb/Thirdweb.Client/ThirdwebClient.Types.cs @@ -0,0 +1,55 @@ +namespace Thirdweb; + +/// +/// Represents the timeout options for different types of operations. +/// +/// +/// Initializes a new instance of the class. +/// +/// The timeout for storage operations (optional). +/// The timeout for RPC operations (optional). +/// The timeout for other operations (optional). +public class TimeoutOptions(int? storage = null, int? rpc = null, int? other = null) +{ + internal int? Storage { get; private set; } = storage; + internal int? Rpc { get; private set; } = rpc; + internal int? Other { get; private set; } = other; + + /// + /// Gets the timeout value for the specified operation type. + /// + /// The type of operation. + /// The fallback timeout value if none is specified (default is ). + /// The timeout value for the specified operation type. + public int GetTimeout(TimeoutType type, int fallback = Constants.DEFAULT_FETCH_TIMEOUT) + { + return type switch + { + TimeoutType.Storage => this.Storage ?? fallback, + TimeoutType.Rpc => this.Rpc ?? fallback, + TimeoutType.Other => this.Other ?? fallback, + _ => fallback, + }; + } +} + +/// +/// Specifies the type of timeout for various operations. +/// +public enum TimeoutType +{ + /// + /// Timeout for storage operations. + /// + Storage, + + /// + /// Timeout for RPC operations. + /// + Rpc, + + /// + /// Timeout for other types of operations. + /// + Other, +} diff --git a/Thirdweb/Thirdweb.Client/ThirdwebClient.cs b/Thirdweb/Thirdweb.Client/ThirdwebClient.cs index 4d0998d7..3c0398a6 100644 --- a/Thirdweb/Thirdweb.Client/ThirdwebClient.cs +++ b/Thirdweb/Thirdweb.Client/ThirdwebClient.cs @@ -1,91 +1,121 @@ -[assembly: System.Runtime.CompilerServices.InternalsVisibleTo("Thirdweb.Tests")] +using System.Numerics; +using Thirdweb.Api; -namespace Thirdweb +[assembly: System.Runtime.CompilerServices.InternalsVisibleTo("Thirdweb.Tests")] + +namespace Thirdweb; + +/// +/// Represents a client for interacting with the Thirdweb API. +/// +public class ThirdwebClient { /// - /// Represents a client for interacting with the Thirdweb API. + /// Gets the HTTP client used by the Thirdweb client. /// - public class ThirdwebClient - { - /// - /// Gets the HTTP client used by the Thirdweb client. - /// - public IThirdwebHttpClient HttpClient { get; } - - /// - /// Gets the client ID. - /// - public string ClientId { get; } + public IThirdwebHttpClient HttpClient { get; } - internal string SecretKey { get; } - internal string BundleId { get; } - internal ITimeoutOptions FetchTimeoutOptions { get; } + /// + /// Gets the client ID. + /// + public string ClientId { get; } - private ThirdwebClient( - string clientId = null, - string secretKey = null, - string bundleId = null, - ITimeoutOptions fetchTimeoutOptions = null, - IThirdwebHttpClient httpClient = null, - Dictionary headers = null - ) - { - if (string.IsNullOrEmpty(clientId) && string.IsNullOrEmpty(secretKey)) - { - throw new InvalidOperationException("ClientId or SecretKey must be provided"); - } + /// + /// Low-level interaction with https://api.thirdweb.com + /// Used in some places to enhance the core SDK functionality, or even extend it + /// + public ThirdwebApiClient Api { get; internal set; } - if (!string.IsNullOrEmpty(secretKey)) - { - ClientId = Utils.ComputeClientIdFromSecretKey(secretKey); - SecretKey = secretKey; - } - else - { - ClientId = clientId; - } + internal string SecretKey { get; } + internal string BundleId { get; } + internal TimeoutOptions FetchTimeoutOptions { get; } + internal Dictionary RpcOverrides { get; } - BundleId = bundleId; + private ThirdwebClient( + string clientId = null, + string secretKey = null, + string bundleId = null, + TimeoutOptions fetchTimeoutOptions = null, + IThirdwebHttpClient httpClient = null, + string sdkName = null, + string sdkOs = null, + string sdkPlatform = null, + string sdkVersion = null, + Dictionary rpcOverrides = null + ) + { + if (string.IsNullOrEmpty(clientId) && string.IsNullOrEmpty(secretKey)) + { + throw new InvalidOperationException("ClientId or SecretKey must be provided"); + } - FetchTimeoutOptions = fetchTimeoutOptions ?? new TimeoutOptions(); + // Respects provided clientId if any, otherwise computes it from secretKey + this.ClientId = !string.IsNullOrEmpty(clientId) ? clientId : (string.IsNullOrEmpty(secretKey) ? null : Utils.ComputeClientIdFromSecretKey(secretKey)); + this.SecretKey = secretKey; + this.BundleId = bundleId; - HttpClient = httpClient ?? new ThirdwebHttpClient(); + this.FetchTimeoutOptions = fetchTimeoutOptions ?? new TimeoutOptions(); - HttpClient.SetHeaders( - headers - ?? new Dictionary - { - { "x-sdk-name", "Thirdweb.NET" }, - { "x-sdk-os", System.Runtime.InteropServices.RuntimeInformation.OSDescription }, - { "x-sdk-platform", "dotnet" }, - { "x-sdk-version", Constants.VERSION }, - { "x-client-id", ClientId }, - { "x-secret-key", SecretKey }, - { "x-bundle-id", BundleId } - } - ); + var defaultHeaders = new Dictionary + { + { "x-sdk-name", sdkName ?? "Thirdweb.NET" }, + { "x-sdk-os", sdkOs ?? System.Runtime.InteropServices.RuntimeInformation.OSDescription }, + { "x-sdk-platform", sdkPlatform ?? "dotnet" }, + { "x-sdk-version", sdkVersion ?? Constants.VERSION }, + { "x-client-id", this.ClientId }, + }; + if (!string.IsNullOrEmpty(this.BundleId)) + { + defaultHeaders.Add("x-bundle-id", this.BundleId); } - - /// - /// Creates a new instance of . - /// - /// The client ID (optional). - /// The secret key (optional). - /// The bundle ID (optional). - /// The fetch timeout options (optional). - /// The HTTP client (optional). - /// The headers to set on the HTTP client (optional). - /// A new instance of . - public static ThirdwebClient Create( - string clientId = null, - string secretKey = null, - string bundleId = null, - ITimeoutOptions fetchTimeoutOptions = null, - IThirdwebHttpClient httpClient = null, - Dictionary headers = null - ) + if (!string.IsNullOrEmpty(this.SecretKey)) { - return new ThirdwebClient(clientId, secretKey, bundleId, fetchTimeoutOptions, httpClient, headers); + defaultHeaders.Add("x-secret-key", this.SecretKey); } + + this.HttpClient = httpClient ?? new ThirdwebHttpClient(); + this.HttpClient.SetHeaders(defaultHeaders); + + this.RpcOverrides = rpcOverrides; + + // Initialize the API client with the wrapped HTTP client + var wrappedHttpClient = new ThirdwebHttpClientWrapper(this.HttpClient); + this.Api = new ThirdwebApiClient(wrappedHttpClient); + } + + /// + /// Creates a new instance of . + /// + /// The client ID (optional). + /// The secret key (optional). + /// The bundle ID (optional). + /// The fetch timeout options (optional). + /// The HTTP client (optional). + /// The SDK name (optional). + /// The SDK OS (optional). + /// The SDK platform (optional). + /// The SDK version (optional). + /// Mapping of chain id to your custom rpc for that chain id (optional, defaults to thirdweb RPC). + /// A new instance of . + public static ThirdwebClient Create( + string clientId = null, + string secretKey = null, + string bundleId = null, + TimeoutOptions fetchTimeoutOptions = null, + IThirdwebHttpClient httpClient = null, + string sdkName = null, + string sdkOs = null, + string sdkPlatform = null, + string sdkVersion = null, + Dictionary rpcOverrides = null + ) + { + return new ThirdwebClient(clientId, secretKey, bundleId, fetchTimeoutOptions, httpClient, sdkName, sdkOs, sdkPlatform, sdkVersion, rpcOverrides); + } + + internal void UpdateApiClient(IThirdwebHttpClient httpClient) + { + var wrappedHttpClient = new ThirdwebHttpClientWrapper(httpClient); + this.Api = new ThirdwebApiClient(wrappedHttpClient); } } diff --git a/Thirdweb/Thirdweb.Client/TimeoutOptions.cs b/Thirdweb/Thirdweb.Client/TimeoutOptions.cs deleted file mode 100644 index 8ce6485d..00000000 --- a/Thirdweb/Thirdweb.Client/TimeoutOptions.cs +++ /dev/null @@ -1,42 +0,0 @@ -namespace Thirdweb -{ - /// - /// Represents the timeout options for different types of operations. - /// - public class TimeoutOptions : ITimeoutOptions - { - internal int? Storage { get; private set; } - internal int? Rpc { get; private set; } - internal int? Other { get; private set; } - - /// - /// Initializes a new instance of the class. - /// - /// The timeout for storage operations (optional). - /// The timeout for RPC operations (optional). - /// The timeout for other operations (optional). - public TimeoutOptions(int? storage = null, int? rpc = null, int? other = null) - { - Storage = storage; - Rpc = rpc; - Other = other; - } - - /// - /// Gets the timeout value for the specified operation type. - /// - /// The type of operation. - /// The fallback timeout value if none is specified (default is ). - /// The timeout value for the specified operation type. - public int GetTimeout(TimeoutType type, int fallback = Constants.DEFAULT_FETCH_TIMEOUT) - { - return type switch - { - TimeoutType.Storage => Storage ?? fallback, - TimeoutType.Rpc => Rpc ?? fallback, - TimeoutType.Other => Other ?? fallback, - _ => fallback, - }; - } - } -} diff --git a/Thirdweb/Thirdweb.Client/TimeoutType.cs b/Thirdweb/Thirdweb.Client/TimeoutType.cs deleted file mode 100644 index e3cb409f..00000000 --- a/Thirdweb/Thirdweb.Client/TimeoutType.cs +++ /dev/null @@ -1,23 +0,0 @@ -namespace Thirdweb -{ - /// - /// Specifies the type of timeout for various operations. - /// - public enum TimeoutType - { - /// - /// Timeout for storage operations. - /// - Storage, - - /// - /// Timeout for RPC operations. - /// - Rpc, - - /// - /// Timeout for other types of operations. - /// - Other, - } -} diff --git a/Thirdweb/Thirdweb.Contracts/ThirdwebContract.cs b/Thirdweb/Thirdweb.Contracts/ThirdwebContract.cs index 401e5ae6..87c6c588 100644 --- a/Thirdweb/Thirdweb.Contracts/ThirdwebContract.cs +++ b/Thirdweb/Thirdweb.Contracts/ThirdwebContract.cs @@ -1,175 +1,375 @@ using System.Numerics; +using Nethereum.ABI.FunctionEncoding; +using Nethereum.ABI.Model; using Nethereum.Contracts; -using Nethereum.Hex.HexTypes; +using Newtonsoft.Json; -namespace Thirdweb +namespace Thirdweb; + +/// +/// Represents a Thirdweb contract. +/// +public class ThirdwebContract { + public ThirdwebClient Client { get; private set; } + public string Address { get; private set; } + public BigInteger Chain { get; private set; } + public string Abi { get; private set; } + + private static readonly Dictionary _contractAbiCache = new(); + private static readonly object _cacheLock = new(); + + private ThirdwebContract(ThirdwebClient client, string address, BigInteger chain, string abi) + { + this.Client = client; + this.Address = address; + this.Chain = chain; + this.Abi = abi; + } + /// - /// Represents a Thirdweb contract. + /// Deploys a new contract on the specified chain. /// - public class ThirdwebContract + /// The Thirdweb client. + /// The chain ID. + /// The server wallet address. + /// The bytecode of the contract. + /// The ABI of the contract. + /// The constructor parameters (optional). + /// The salt for the contract deployment (optional). + /// The cancellation token. + /// The contract address of the fully deployed contract. + /// + /// This method deploys a new contract using a server wallet, create one via the ServerWallet class or api.thirdweb.com, or the dashboard. + /// + /// Thrown if any of the required parameters are null. + /// Thrown if any of the required parameters are invalid. + /// Thrown if the chain ID is too large. + /// Thrown if the deployment fails or the API response is invalid. + /// Thrown if the ABI JSON cannot be parsed. + public static async Task Deploy( + ThirdwebClient client, + BigInteger chainId, + string serverWalletAddress, + string bytecode, + string abi, + Dictionary constructorParams = null, + string salt = null, + CancellationToken cancellationToken = default + ) { - internal ThirdwebClient Client { get; private set; } - internal string Address { get; private set; } - internal BigInteger Chain { get; private set; } - internal string Abi { get; private set; } - - private static Dictionary _contractAbiCache = new(); - private static readonly object _cacheLock = new object(); - - private ThirdwebContract(ThirdwebClient client, string address, BigInteger chain, string abi) - { - Client = client; - Address = address; - Chain = chain; - Abi = abi; - } - - /// - /// Creates a new instance of . - /// - /// The Thirdweb client. - /// The contract address. - /// The chain ID. - /// The contract ABI (optional). - /// A new instance of . - /// Thrown if any of the required parameters are missing. - public static async Task Create(ThirdwebClient client, string address, BigInteger chain, string abi = null) - { - if (client == null) - { - throw new ArgumentException("Client must be provided"); - } + // Input validation + if (client == null) + { + throw new ArgumentNullException(nameof(client)); + } + + if (chainId <= 0) + { + throw new ArgumentException("Chain ID must be greater than 0.", nameof(chainId)); + } + + if (string.IsNullOrEmpty(serverWalletAddress)) + { + throw new ArgumentException("Server wallet address cannot be null or empty.", nameof(serverWalletAddress)); + } - if (string.IsNullOrEmpty(address)) + if (string.IsNullOrEmpty(bytecode)) + { + throw new ArgumentException("Bytecode cannot be null or empty.", nameof(bytecode)); + } + + if (string.IsNullOrEmpty(abi)) + { + throw new ArgumentException("ABI cannot be null or empty.", nameof(abi)); + } + + // Perform checked cast to int + // TODO: Remove this when generated client supports BigInteger for chainId + int chainIdInt; + try + { + chainIdInt = checked((int)chainId); + } + catch (OverflowException) + { + throw new OverflowException($"Chain ID {chainId} is too large; ThirdwebContract.Deploy currently only supports chain IDs up to {int.MaxValue}."); + } + + // Parse ABI with error handling + List parsedAbi; + try + { + parsedAbi = JsonConvert.DeserializeObject>(abi); + if (parsedAbi == null) { - throw new ArgumentException("Address must be provided"); + throw new InvalidOperationException("ABI deserialization returned null."); } + } + catch (JsonException ex) + { + throw new ArgumentException($"Failed to parse ABI JSON: {ex.Message}", nameof(abi), ex); + } - if (chain == 0) + var response = + await client + .Api.DeployContractAsync( + new Api.Body10() + { + ChainId = chainIdInt, + From = serverWalletAddress, + Bytecode = bytecode, + Abi = parsedAbi, + ConstructorParams = constructorParams, + Salt = salt, + }, + cancellationToken + ) + .ConfigureAwait(false) ?? throw new InvalidOperationException("Failed to deploy contract: API response was null."); + + if (response.Result is null) + { + throw new InvalidOperationException("Failed to deploy contract: API response result was null."); + } + + var contractAddress = response.Result.Address; + if (string.IsNullOrEmpty(contractAddress)) + { + throw new InvalidOperationException("Failed to deploy contract: Could not compute contract address."); + } + + var transactionId = response.Result.TransactionId; + if (string.IsNullOrEmpty(transactionId)) + { + throw new InvalidOperationException("Failed to deploy contract: Transaction ID is empty."); + } + + var hash = await ThirdwebTransaction.WaitForTransactionHash(client, transactionId, cancellationToken).ConfigureAwait(false); + if (string.IsNullOrEmpty(hash)) + { + throw new InvalidOperationException("Failed to deploy contract: Transaction hash is empty."); + } + + _ = await ThirdwebTransaction.WaitForTransactionReceipt(client, chainId, hash, cancellationToken).ConfigureAwait(false); + return contractAddress; + } + + /// + /// Creates a new instance of . + /// + /// The Thirdweb client. + /// The contract address. + /// The chain ID. + /// The contract ABI (optional). + /// A new instance of . + /// Thrown if any of the required parameters are missing. + public static async Task Create(ThirdwebClient client, string address, BigInteger chain, string abi = null) + { + if (client == null) + { + throw new ArgumentException("Client must be provided"); + } + + if (string.IsNullOrEmpty(address)) + { + throw new ArgumentException("Address must be provided"); + } + + if (chain == 0) + { + throw new ArgumentException("Chain must be provided"); + } + + abi ??= await FetchAbi(client, address, chain).ConfigureAwait(false); + return new ThirdwebContract(client, address, chain, abi); + } + + /// + /// Fetches the ABI for the specified contract. + /// + /// The Thirdweb client. + /// The contract address. + /// The chain ID. + /// The contract ABI. + public static async Task FetchAbi(ThirdwebClient client, string address, BigInteger chainId) + { + var cacheKey = $"{address}:{chainId}"; + + lock (_cacheLock) + { + if (_contractAbiCache.TryGetValue(cacheKey, out var cachedAbi)) { - throw new ArgumentException("Chain must be provided"); + return cachedAbi; } + } + + var url = $"https://contract.thirdweb.com/abi/{chainId}/{address}"; + var httpClient = client.HttpClient; + var response = await httpClient.GetAsync(url).ConfigureAwait(false); + _ = response.EnsureSuccessStatusCode(); + var abi = await response.Content.ReadAsStringAsync().ConfigureAwait(false); - abi ??= await FetchAbi(client, address, chain).ConfigureAwait(false); - return new ThirdwebContract(client, address, chain, abi); + lock (_cacheLock) + { + _contractAbiCache[cacheKey] = abi; } - /// - /// Fetches the ABI for the specified contract. - /// - /// The Thirdweb client. - /// The contract address. - /// The chain ID. - /// The contract ABI. - public static async Task FetchAbi(ThirdwebClient client, string address, BigInteger chainId) + return abi; + } + + /// + /// Reads data from the contract using the specified method. + /// + /// The type of the return value. + /// The contract instance. + /// The method to call. + /// The parameters for the method. + /// The result of the method call. + public static async Task Read(ThirdwebContract contract, string method, params object[] parameters) + { + var rpc = ThirdwebRPC.GetRpcInstance(contract.Client, contract.Chain); + (var data, var function) = EncodeFunctionCall(contract, method, parameters); + var resultData = await rpc.SendRequestAsync("eth_call", new { to = contract.Address, data }, "latest").ConfigureAwait(false); + + if ((typeof(T).IsGenericType && typeof(T).GetGenericTypeDefinition() == typeof(List<>)) || typeof(T).IsArray) { - var cacheKey = $"{address}:{chainId}"; + var contractRaw = new Contract(null, contract.Abi, contract.Address); + var functionAbi = contractRaw.ContractBuilder.ContractABI.FindFunctionABIFromInputData(data); + var decoder = new FunctionCallDecoder(); + var outputList = new FunctionCallDecoder().DecodeDefaultData(resultData.HexToBytes(), functionAbi.OutputParameters); + var resultList = outputList.Select(x => x.Result).ToList(); - lock (_cacheLock) + if (typeof(T) == typeof(List)) { - if (_contractAbiCache.TryGetValue(cacheKey, out var cachedAbi)) - { - return cachedAbi; - } + return (T)(object)resultList; } - var url = $"https://contract.thirdweb.com/abi/{chainId}/{address}"; - var httpClient = client.HttpClient; - var response = await httpClient.GetAsync(url).ConfigureAwait(false); - _ = response.EnsureSuccessStatusCode(); - var abi = await response.Content.ReadAsStringAsync().ConfigureAwait(false); - - lock (_cacheLock) + if (typeof(T) == typeof(object[])) { - _contractAbiCache[cacheKey] = abi; + return (T)(object)resultList.ToArray(); } - return abi; + try + { + var json = JsonConvert.SerializeObject(resultList); + return JsonConvert.DeserializeObject(json); + } + catch (Exception) + { + var dict = outputList.ConvertToObjectDictionary(); + var ser = JsonConvert.SerializeObject(dict.First().Value); + return JsonConvert.DeserializeObject(ser); + } } - - /// - /// Reads data from the contract using the specified method. - /// - /// The type of the return value. - /// The contract instance. - /// The method to call. - /// The parameters for the method. - /// The result of the method call. - public static async Task Read(ThirdwebContract contract, string method, params object[] parameters) + else { - var rpc = ThirdwebRPC.GetRpcInstance(contract.Client, contract.Chain); + return function.DecodeTypeOutput(resultData); + } + } - var contractRaw = new Contract(null, contract.Abi, contract.Address); - var function = GetFunctionMatchSignature(contractRaw, method, parameters); - var data = function.GetData(parameters); + /// + /// Prepares a transaction for the specified method and parameters. + /// + /// The wallet instance. + /// The contract instance. + /// The method to call. + /// The value in wei to send. + /// The parameters for the method. + /// A prepared transaction. + public static async Task Prepare(IThirdwebWallet wallet, ThirdwebContract contract, string method, BigInteger weiValue, params object[] parameters) + { + var data = contract.CreateCallData(method, parameters); + var transaction = new ThirdwebTransactionInput(chainId: contract.Chain, to: contract.Address, data: data, value: weiValue); + return await ThirdwebTransaction.Create(wallet, transaction).ConfigureAwait(false); + } + + /// + /// Writes data to the contract using the specified method and parameters. + /// + /// The wallet instance. + /// The contract instance. + /// The method to call. + /// The value in wei to send. + /// The parameters for the method. + /// A transaction receipt. + public static async Task Write(IThirdwebWallet wallet, ThirdwebContract contract, string method, BigInteger weiValue, params object[] parameters) + { + var thirdwebTx = await Prepare(wallet, contract, method, weiValue, parameters).ConfigureAwait(false); + return await ThirdwebTransaction.SendAndWaitForTransactionReceipt(thirdwebTx).ConfigureAwait(false); + } - var resultData = await rpc.SendRequestAsync("eth_call", new { to = contract.Address, data = data }, "latest").ConfigureAwait(false); + internal static (string callData, Function function) EncodeFunctionCall(ThirdwebContract contract, string method, params object[] parameters) + { + var contractRaw = new Contract(null, contract.Abi, contract.Address); + var function = GetFunctionMatchSignature(contractRaw, method, parameters); + return (function.GetData(parameters), function); + } - return function.DecodeTypeOutput(resultData); + /// + /// Gets a function matching the specified signature from the contract. + /// + /// The contract instance. + /// The name of the function. + /// The arguments for the function. + /// The matching function, or null if no match is found. + private static Function GetFunctionMatchSignature(Contract contract, string functionName, params object[] args) + { + if (functionName.StartsWith("0x")) + { + return contract.GetFunctionBySignature(functionName); } - /// - /// Prepares a transaction for the specified method and parameters. - /// - /// The wallet instance. - /// The contract instance. - /// The method to call. - /// The value in wei to send. - /// The parameters for the method. - /// A prepared transaction. - public static async Task Prepare(IThirdwebWallet wallet, ThirdwebContract contract, string method, BigInteger weiValue, params object[] parameters) + var abi = contract.ContractBuilder.ContractABI; + var functions = abi.Functions; + var paramsCount = args?.Length ?? 0; + foreach (var function in functions) { - var contractRaw = new Contract(null, contract.Abi, contract.Address); - var function = GetFunctionMatchSignature(contractRaw, method, parameters); - var data = function.GetData(parameters); - var transaction = new ThirdwebTransactionInput - { - From = await wallet.GetAddress().ConfigureAwait(false), - To = contract.Address, - Data = data, - Value = new HexBigInteger(weiValue), - }; - - return await ThirdwebTransaction.Create(wallet, transaction, contract.Chain).ConfigureAwait(false); - } - - /// - /// Writes data to the contract using the specified method and parameters. - /// - /// The wallet instance. - /// The contract instance. - /// The method to call. - /// The value in wei to send. - /// The parameters for the method. - /// A transaction receipt. - public static async Task Write(IThirdwebWallet wallet, ThirdwebContract contract, string method, BigInteger weiValue, params object[] parameters) - { - var thirdwebTx = await Prepare(wallet, contract, method, weiValue, parameters).ConfigureAwait(false); - return await ThirdwebTransaction.SendAndWaitForTransactionReceipt(thirdwebTx).ConfigureAwait(false); - } - - /// - /// Gets a function matching the specified signature from the contract. - /// - /// The contract instance. - /// The name of the function. - /// The arguments for the function. - /// The matching function, or null if no match is found. - private static Function GetFunctionMatchSignature(Contract contract, string functionName, params object[] args) - { - var abi = contract.ContractBuilder.ContractABI; - var functions = abi.Functions; - var paramsCount = args?.Length ?? 0; - foreach (var function in functions) + if (function.Name == functionName && function.InputParameters.Length == paramsCount) { - if (function.Name == functionName && function.InputParameters.Length == paramsCount) - { - var sha = function.Sha3Signature; - return contract.GetFunctionBySignature(sha); - } + var sha = function.Sha3Signature; + return contract.GetFunctionBySignature(sha); } - return null; } + + if (functionName.Contains('(')) + { + var canonicalSignature = ExtractCanonicalSignature(functionName); + var selector = Utils.HashMessage(canonicalSignature)[..8]; + return contract.GetFunctionBySignature(selector); + } + else + { + throw new ArgumentException("Method signature not found in contract ABI."); + } + } + + /// + /// Extracts the canonical signature from the specified method. + /// + /// The method to extract the signature from. + /// The canonical signature. + /// + private static string ExtractCanonicalSignature(string method) + { + method = method.Split("returns")[0]; + var startOfParameters = method.IndexOf('('); + if (startOfParameters == -1) + { + throw new ArgumentException("Invalid function signature: Missing opening parenthesis."); + } + + var endOfParameters = method.LastIndexOf(')'); + if (endOfParameters == -1) + { + throw new ArgumentException("Invalid function signature: Missing closing parenthesis."); + } + + var functionName = method[..startOfParameters].Trim().Split(' ').Last(); // Get the last part after any spaces (in case of "function name(...)") + var parameters = method.Substring(startOfParameters + 1, endOfParameters - startOfParameters - 1); + + var paramTypes = parameters.Split(',').Select(param => param.Trim().Split(' ')[0]).ToArray(); + + var canonicalSignature = $"{functionName}({string.Join(",", paramTypes)})"; + return canonicalSignature; } } diff --git a/Thirdweb/Thirdweb.Extensions/ExtensionTypes.cs b/Thirdweb/Thirdweb.Extensions/ExtensionTypes.cs deleted file mode 100644 index f347d825..00000000 --- a/Thirdweb/Thirdweb.Extensions/ExtensionTypes.cs +++ /dev/null @@ -1,551 +0,0 @@ -using System.Numerics; -using Nethereum.ABI.FunctionEncoding.Attributes; -using Newtonsoft.Json; - -namespace Thirdweb -{ - #region Common - - /// - /// Represents the result of a verification operation. - /// - [FunctionOutput] - public class VerifyResult - { - /// - /// Gets or sets a value indicating whether the verification is valid. - /// - [Parameter("bool", "", 1)] - [JsonProperty("isValid")] - public bool IsValid { get; set; } - - /// - /// Gets or sets the address of the signer. - /// - [Parameter("address", "", 2)] - [JsonProperty("signer")] - public string Signer { get; set; } - } - - /// - /// Represents the royalty information result. - /// - [FunctionOutput] - public class RoyaltyInfoResult - { - /// - /// Gets or sets the recipient address. - /// - [Parameter("address", "", 1)] - [JsonProperty("recipient")] - public string Recipient { get; set; } - - /// - /// Gets or sets the basis points (bps) for royalty. - /// - [Parameter("uint256", "", 2)] - [JsonProperty("bps")] - public BigInteger Bps { get; set; } - } - - /// - /// Represents the metadata of a contract. - /// - public class ContractMetadata - { - /// - /// Gets or sets the name of the contract. - /// - [JsonProperty("name")] - public string Name { get; set; } - - /// - /// Gets or sets the symbol of the contract. - /// - [JsonProperty("symbol")] - public string Symbol { get; set; } - - /// - /// Gets or sets the description of the contract. - /// - [JsonProperty("description")] - public string Description { get; set; } - - /// - /// Gets or sets the image URL of the contract. - /// - [JsonProperty("image")] - public string Image { get; set; } - } - - #endregion - - #region Forwarder - - /// - /// Represents a forward request for a forwarder. - /// - [Struct("ForwardRequest")] - public class Forwarder_ForwardRequest - { - /// - /// Gets or sets the address of the sender. - /// - [Parameter("address", "from", 1)] - [JsonProperty("from")] - public string From { get; set; } - - /// - /// Gets or sets the address of the recipient. - /// - [Parameter("address", "to", 2)] - [JsonProperty("to")] - public string To { get; set; } - - /// - /// Gets or sets the value to be transferred. - /// - [Parameter("uint256", "value", 3)] - [JsonProperty("value")] - public BigInteger Value { get; set; } - - /// - /// Gets or sets the gas limit for the transaction. - /// - [Parameter("uint256", "gas", 4)] - [JsonProperty("gas")] - public BigInteger Gas { get; set; } - - /// - /// Gets or sets the nonce for the transaction. - /// - [Parameter("uint256", "nonce", 5)] - [JsonProperty("nonce")] - public BigInteger Nonce { get; set; } - - /// - /// Gets or sets the data to be sent with the transaction. - /// - [Parameter("bytes", "data", 6)] - [JsonProperty("data")] - public string Data { get; set; } - } - - #endregion - - #region NFT - - /// - /// Represents the type of an NFT. - /// - [Serializable] - public enum NFTType - { - ERC721, - ERC1155 - } - - /// - /// Represents an NFT with metadata, owner, type, and supply information. - /// - [Serializable] - public struct NFT - { - /// - /// Gets or sets the metadata of the NFT. - /// - public NFTMetadata Metadata { get; set; } - - /// - /// Gets or sets the owner address of the NFT. - /// - public string Owner { get; set; } - - /// - /// Gets or sets the type of the NFT. - /// - public NFTType Type { get; set; } - - /// - /// Gets or sets the supply of the NFT. - /// - public BigInteger? Supply { get; set; } - - /// - /// Gets or sets the quantity owned by the user. - /// - public BigInteger? QuantityOwned { get; set; } - } - - /// - /// Represents the metadata of an NFT. - /// - [Serializable] - public struct NFTMetadata - { - /// - /// Gets or sets the ID of the NFT. - /// - [JsonProperty("id")] - public string Id { get; set; } - - /// - /// Gets or sets the URI of the NFT. - /// - [JsonProperty("uri")] - public string Uri { get; set; } - - /// - /// Gets or sets the description of the NFT. - /// - [JsonProperty("description")] - public string Description { get; set; } - - /// - /// Gets or sets the image URL of the NFT. - /// - [JsonProperty("image")] - public string Image { get; set; } - - /// - /// Gets or sets the name of the NFT. - /// - [JsonProperty("name")] - public string Name { get; set; } - - /// - /// Gets or sets the animation URL of the NFT. - /// - [JsonProperty("animation_url")] - public string AnimationUrl { get; set; } - - /// - /// Gets or sets the external URL of the NFT. - /// - [JsonProperty("external_url")] - public string ExternalUrl { get; set; } - - /// - /// Gets or sets the background color of the NFT. - /// - [JsonProperty("background_color")] - public string BackgroundColor { get; set; } - - /// - /// Gets or sets the attributes of the NFT. - /// - [JsonProperty("attributes")] - public object Attributes { get; set; } - } - - #endregion - - #region Drop - - /// - /// Represents a claim condition for a drop. - /// - public class Drop_ClaimCondition - { - /// - /// Gets or sets the start timestamp of the claim condition. - /// - [Parameter("uint256", "startTimestamp", 1)] - [JsonProperty("startTimestamp")] - public BigInteger StartTimestamp { get; set; } - - /// - /// Gets or sets the maximum claimable supply. - /// - [Parameter("uint256", "maxClaimableSupply", 2)] - [JsonProperty("maxClaimableSupply")] - public BigInteger MaxClaimableSupply { get; set; } - - /// - /// Gets or sets the supply claimed so far. - /// - [Parameter("uint256", "supplyClaimed", 3)] - [JsonProperty("supplyClaimed")] - public BigInteger SupplyClaimed { get; set; } - - /// - /// Gets or sets the quantity limit per wallet. - /// - [Parameter("uint256", "quantityLimitPerWallet", 4)] - [JsonProperty("quantityLimitPerWallet")] - public BigInteger QuantityLimitPerWallet { get; set; } - - /// - /// Gets or sets the Merkle root for the claim condition. - /// - [Parameter("bytes32", "merkleRoot", 5)] - [JsonProperty("merkleRoot")] - public byte[] MerkleRoot { get; set; } - - /// - /// Gets or sets the price per token for the claim condition. - /// - [Parameter("uint256", "pricePerToken", 6)] - [JsonProperty("pricePerToken")] - public BigInteger PricePerToken { get; set; } - - /// - /// Gets or sets the currency address for the claim condition. - /// - [Parameter("address", "currency", 7)] - [JsonProperty("currency")] - public string Currency { get; set; } - - /// - /// Gets or sets the metadata for the claim condition. - /// - [Parameter("string", "metadata", 8)] - [JsonProperty("metadata")] - public string Metadata { get; set; } - } - - #endregion - - #region TokenERC20 - - /// - /// Represents a mint request for an ERC20 token. - /// - [Struct("MintRequest")] - public class TokenERC20_MintRequest - { - /// - /// Gets or sets the address to mint the tokens to. - /// - [Parameter("address", "to", 1)] - [JsonProperty("to")] - public string To { get; set; } - - /// - /// Gets or sets the primary sale recipient address. - /// - [Parameter("address", "primarySaleRecipient", 2)] - [JsonProperty("primarySaleRecipient")] - public string PrimarySaleRecipient { get; set; } - - /// - /// Gets or sets the quantity of tokens to mint. - /// - [Parameter("uint256", "quantity", 3)] - [JsonProperty("quantity")] - public BigInteger Quantity { get; set; } - - /// - /// Gets or sets the price of the tokens. - /// - [Parameter("uint256", "price", 4)] - [JsonProperty("price")] - public BigInteger Price { get; set; } - - /// - /// Gets or sets the currency address. - /// - [Parameter("address", "currency", 5)] - [JsonProperty("currency")] - public string Currency { get; set; } - - /// - /// Gets or sets the validity start timestamp. - /// - [Parameter("uint128", "validityStartTimestamp", 6)] - [JsonProperty("validityStartTimestamp")] - public BigInteger ValidityStartTimestamp { get; set; } - - /// - /// Gets or sets the validity end timestamp. - /// - [Parameter("uint128", "validityEndTimestamp", 7)] - [JsonProperty("validityEndTimestamp")] - public BigInteger ValidityEndTimestamp { get; set; } - - /// - /// Gets or sets the unique identifier for the mint request. - /// - [Parameter("bytes32", "uid", 8)] - [JsonProperty("uid")] - public byte[] Uid { get; set; } - } - - #endregion - - #region TokenERC721 - - /// - /// Represents a mint request for an ERC721 token. - /// - [Struct("MintRequest")] - public class TokenERC721_MintRequest - { - /// - /// Gets or sets the address to mint the token to. - /// - [Parameter("address", "to", 1)] - [JsonProperty("to")] - public string To { get; set; } - - /// - /// Gets or sets the royalty recipient address. - /// - [Parameter("address", "royaltyRecipient", 2)] - [JsonProperty("royaltyRecipient")] - public string RoyaltyRecipient { get; set; } - - /// - /// Gets or sets the royalty basis points. - /// - [Parameter("uint256", "royaltyBps", 3)] - [JsonProperty("royaltyBps")] - public BigInteger RoyaltyBps { get; set; } - - /// - /// Gets or sets the primary sale recipient address. - /// - [Parameter("address", "primarySaleRecipient", 4)] - [JsonProperty("primarySaleRecipient")] - public string PrimarySaleRecipient { get; set; } - - /// - /// Gets or sets the URI of the token. - /// - [Parameter("string", "uri", 5)] - [JsonProperty("uri")] - public string Uri { get; set; } - - /// - /// Gets or sets the price of the token. - /// - [Parameter("uint256", "price", 6)] - [JsonProperty("price")] - public BigInteger Price { get; set; } - - /// - /// Gets or sets the currency address. - /// - [Parameter("address", "currency", 7)] - [JsonProperty("currency")] - public string Currency { get; set; } - - /// - /// Gets or sets the validity start timestamp. - /// - [Parameter("uint128", "validityStartTimestamp", 8)] - [JsonProperty("validityStartTimestamp")] - public BigInteger ValidityStartTimestamp { get; set; } - - /// - /// Gets or sets the validity end timestamp. - /// - [Parameter("uint128", "validityEndTimestamp", 9)] - [JsonProperty("validityEndTimestamp")] - public BigInteger ValidityEndTimestamp { get; set; } - - /// - /// Gets or sets the unique identifier for the mint request. - /// - [Parameter("bytes32", "uid", 10)] - [JsonProperty("uid")] - public byte[] Uid { get; set; } - } - - #endregion - - #region TokenERC1155 - - /// - /// Represents a mint request for an ERC1155 token. - /// - [Struct("MintRequest")] - public class TokenERC1155_MintRequest - { - /// - /// Gets or sets the address to mint the token to. - /// - [Parameter("address", "to", 1)] - [JsonProperty("to")] - public string To { get; set; } - - /// - /// Gets or sets the royalty recipient address. - /// - [Parameter("address", "royaltyRecipient", 2)] - [JsonProperty("royaltyRecipient")] - public string RoyaltyRecipient { get; set; } - - /// - /// Gets or sets the royalty basis points. - /// - [Parameter("uint256", "royaltyBps", 3)] - [JsonProperty("royaltyBps")] - public BigInteger RoyaltyBps { get; set; } - - /// - /// Gets or sets the primary sale recipient address. - /// - [Parameter("address", "primarySaleRecipient", 4)] - [JsonProperty("primarySaleRecipient")] - public string PrimarySaleRecipient { get; set; } - - /// - /// Gets or sets the token ID. - /// - [Parameter("uint256", "tokenId", 5)] - [JsonProperty("tokenId")] - public BigInteger? TokenId { get; set; } - - /// - /// Gets or sets the URI of the token. - /// - [Parameter("string", "uri", 6)] - [JsonProperty("uri")] - public string Uri { get; set; } - - /// - /// Gets or sets the quantity of tokens to mint. - /// - [Parameter("uint256", "quantity", 7)] - [JsonProperty("quantity")] - public BigInteger Quantity { get; set; } - - /// - /// Gets or sets the price per token. - /// - [Parameter("uint256", "pricePerToken", 8)] - [JsonProperty("pricePerToken")] - public BigInteger PricePerToken { get; set; } - - /// - /// Gets or sets the currency address. - /// - [Parameter("address", "currency", 9)] - [JsonProperty("currency")] - public string Currency { get; set; } - - /// - /// Gets or sets the validity start timestamp. - /// - [Parameter("uint128", "validityStartTimestamp", 10)] - [JsonProperty("validityStartTimestamp")] - public BigInteger ValidityStartTimestamp { get; set; } - - /// - /// Gets or sets the validity end timestamp. - /// - [Parameter("uint128", "validityEndTimestamp", 11)] - [JsonProperty("validityEndTimestamp")] - public BigInteger ValidityEndTimestamp { get; set; } - - /// - /// Gets or sets the unique identifier for the mint request. - /// - [Parameter("bytes32", "uid", 12)] - [JsonProperty("uid")] - public byte[] Uid { get; set; } - } - - #endregion -} diff --git a/Thirdweb/Thirdweb.Extensions/ThirdwebExtensions.Types.cs b/Thirdweb/Thirdweb.Extensions/ThirdwebExtensions.Types.cs new file mode 100644 index 00000000..e0a34cb1 --- /dev/null +++ b/Thirdweb/Thirdweb.Extensions/ThirdwebExtensions.Types.cs @@ -0,0 +1,511 @@ +using System.Numerics; +using Nethereum.ABI.FunctionEncoding.Attributes; +using Newtonsoft.Json; + +namespace Thirdweb; + +#region Common + +/// +/// Represents the result of a verification operation. +/// +[FunctionOutput] +public class VerifyResult +{ + /// + /// Gets or sets a value indicating whether the verification is valid. + /// + [Parameter("bool", "", 1)] + [JsonProperty("isValid")] + public bool IsValid { get; set; } + + /// + /// Gets or sets the address of the signer. + /// + [Parameter("address", "", 2)] + [JsonProperty("signer")] + public string Signer { get; set; } +} + +/// +/// Represents the royalty information result. +/// +[FunctionOutput] +public class RoyaltyInfoResult +{ + /// + /// Gets or sets the recipient address. + /// + [Parameter("address", "", 1)] + [JsonProperty("recipient")] + public string Recipient { get; set; } + + /// + /// Gets or sets the basis points (bps) for royalty. + /// + [Parameter("uint256", "", 2)] + [JsonProperty("bps")] + public BigInteger Bps { get; set; } +} + +/// +/// Represents the metadata of a contract. +/// +public class ContractMetadata +{ + /// + /// Gets or sets the name of the contract. + /// + [JsonProperty("name")] + public string Name { get; set; } + + /// + /// Gets or sets the symbol of the contract. + /// + [JsonProperty("symbol")] + public string Symbol { get; set; } + + /// + /// Gets or sets the description of the contract. + /// + [JsonProperty("description")] + public string Description { get; set; } + + /// + /// Gets or sets the image URL of the contract. + /// + [JsonProperty("image")] + public string Image { get; set; } +} + +#endregion + +#region NFT + +/// +/// Represents the type of an NFT. +/// +[Serializable] +public enum NFTType +{ + ERC721, + ERC1155, +} + +/// +/// Represents an NFT with metadata, owner, type, and supply information. +/// +[Serializable] +[JsonObject(ItemNullValueHandling = NullValueHandling.Ignore)] +public struct NFT +{ + /// + /// Gets or sets the metadata of the NFT. + /// + public NFTMetadata Metadata { get; set; } + + /// + /// Gets or sets the owner address of the NFT. This is only applicable for ERC721 tokens. + /// + public string Owner { get; set; } + + /// + /// Gets or sets the type of the NFT. + /// + public NFTType Type { get; set; } + + /// + /// Gets or sets the supply of the NFT. + /// + public BigInteger? Supply { get; set; } + + /// + /// Gets or sets the quantity owned by the user. This is only applicable for ERC1155 tokens. + /// + public BigInteger? QuantityOwned { get; set; } +} + +/// +/// Represents the metadata of an NFT. +/// +[Serializable] +[JsonObject(ItemNullValueHandling = NullValueHandling.Ignore)] +public struct NFTMetadata +{ + /// + /// Gets or sets the ID of the NFT. + /// + [JsonProperty("id")] + public string Id { get; set; } + + /// + /// Gets or sets the URI of the NFT. + /// + [JsonProperty("uri")] + public string Uri { get; set; } + + /// + /// Gets or sets the description of the NFT. + /// + [JsonProperty("description")] + public string Description { get; set; } + + /// + /// Gets or sets the image URL of the NFT. + /// + [JsonProperty("image")] + public string Image { get; set; } + + /// + /// Gets or sets the name of the NFT. + /// + [JsonProperty("name")] + public string Name { get; set; } + + /// + /// Gets or sets the video URL of the NFT. + /// + [JsonProperty("video_url")] + public string VideoUrl { get; set; } + + /// + /// Gets or sets the animation URL of the NFT. + /// + [JsonProperty("animation_url")] + public string AnimationUrl { get; set; } + + /// + /// Gets or sets the external URL of the NFT. + /// + [JsonProperty("external_url")] + public string ExternalUrl { get; set; } + + /// + /// Gets or sets the background color of the NFT. + /// + [JsonProperty("background_color")] + public string BackgroundColor { get; set; } + + /// + /// Gets or sets the attributes of the NFT. + /// + [JsonProperty("attributes")] + public object Attributes { get; set; } + + /// + /// Gets or sets the properties of the NFT. + /// + [JsonProperty("properties")] + public object Properties { get; set; } +} + +#endregion + +#region Drop + +/// +/// Represents a claim condition for a drop. +/// +public class Drop_ClaimCondition +{ + /// + /// Gets or sets the start timestamp of the claim condition. + /// + [Parameter("uint256", "startTimestamp", 1)] + [JsonProperty("startTimestamp")] + public BigInteger StartTimestamp { get; set; } + + /// + /// Gets or sets the maximum claimable supply. + /// + [Parameter("uint256", "maxClaimableSupply", 2)] + [JsonProperty("maxClaimableSupply")] + public BigInteger MaxClaimableSupply { get; set; } + + /// + /// Gets or sets the supply claimed so far. + /// + [Parameter("uint256", "supplyClaimed", 3)] + [JsonProperty("supplyClaimed")] + public BigInteger SupplyClaimed { get; set; } + + /// + /// Gets or sets the quantity limit per wallet. + /// + [Parameter("uint256", "quantityLimitPerWallet", 4)] + [JsonProperty("quantityLimitPerWallet")] + public BigInteger QuantityLimitPerWallet { get; set; } + + /// + /// Gets or sets the Merkle root for the claim condition. + /// + [Parameter("bytes32", "merkleRoot", 5)] + [JsonProperty("merkleRoot")] + public byte[] MerkleRoot { get; set; } + + /// + /// Gets or sets the price per token for the claim condition. + /// + [Parameter("uint256", "pricePerToken", 6)] + [JsonProperty("pricePerToken")] + public BigInteger PricePerToken { get; set; } + + /// + /// Gets or sets the currency address for the claim condition. + /// + [Parameter("address", "currency", 7)] + [JsonProperty("currency")] + public string Currency { get; set; } + + /// + /// Gets or sets the metadata for the claim condition. + /// + [Parameter("string", "metadata", 8)] + [JsonProperty("metadata")] + public string Metadata { get; set; } +} + +#endregion + +#region TokenERC20 + +/// +/// Represents a mint request for an ERC20 token. +/// +[Struct("MintRequest")] +public class TokenERC20_MintRequest +{ + /// + /// Gets or sets the address to mint the tokens to. + /// + [Parameter("address", "to", 1)] + [JsonProperty("to")] + public string To { get; set; } + + /// + /// Gets or sets the primary sale recipient address. + /// + [Parameter("address", "primarySaleRecipient", 2)] + [JsonProperty("primarySaleRecipient")] + public string PrimarySaleRecipient { get; set; } + + /// + /// Gets or sets the quantity of tokens to mint. + /// + [Parameter("uint256", "quantity", 3)] + [JsonProperty("quantity")] + public BigInteger Quantity { get; set; } + + /// + /// Gets or sets the price of the tokens. + /// + [Parameter("uint256", "price", 4)] + [JsonProperty("price")] + public BigInteger Price { get; set; } + + /// + /// Gets or sets the currency address. + /// + [Parameter("address", "currency", 5)] + [JsonProperty("currency")] + public string Currency { get; set; } + + /// + /// Gets or sets the validity start timestamp. + /// + [Parameter("uint128", "validityStartTimestamp", 6)] + [JsonProperty("validityStartTimestamp")] + public BigInteger ValidityStartTimestamp { get; set; } + + /// + /// Gets or sets the validity end timestamp. + /// + [Parameter("uint128", "validityEndTimestamp", 7)] + [JsonProperty("validityEndTimestamp")] + public BigInteger ValidityEndTimestamp { get; set; } + + /// + /// Gets or sets the unique identifier for the mint request. + /// + [Parameter("bytes32", "uid", 8)] + [JsonProperty("uid")] + public byte[] Uid { get; set; } +} + +#endregion + +#region TokenERC721 + +/// +/// Represents a mint request for an ERC721 token. +/// +[Struct("MintRequest")] +public class TokenERC721_MintRequest +{ + /// + /// Gets or sets the address to mint the token to. + /// + [Parameter("address", "to", 1)] + [JsonProperty("to")] + public string To { get; set; } + + /// + /// Gets or sets the royalty recipient address. + /// + [Parameter("address", "royaltyRecipient", 2)] + [JsonProperty("royaltyRecipient")] + public string RoyaltyRecipient { get; set; } + + /// + /// Gets or sets the royalty basis points. + /// + [Parameter("uint256", "royaltyBps", 3)] + [JsonProperty("royaltyBps")] + public BigInteger RoyaltyBps { get; set; } + + /// + /// Gets or sets the primary sale recipient address. + /// + [Parameter("address", "primarySaleRecipient", 4)] + [JsonProperty("primarySaleRecipient")] + public string PrimarySaleRecipient { get; set; } + + /// + /// Gets or sets the URI of the token. + /// + [Parameter("string", "uri", 5)] + [JsonProperty("uri")] + public string Uri { get; set; } + + /// + /// Gets or sets the price of the token. + /// + [Parameter("uint256", "price", 6)] + [JsonProperty("price")] + public BigInteger Price { get; set; } + + /// + /// Gets or sets the currency address. + /// + [Parameter("address", "currency", 7)] + [JsonProperty("currency")] + public string Currency { get; set; } + + /// + /// Gets or sets the validity start timestamp. + /// + [Parameter("uint128", "validityStartTimestamp", 8)] + [JsonProperty("validityStartTimestamp")] + public BigInteger ValidityStartTimestamp { get; set; } + + /// + /// Gets or sets the validity end timestamp. + /// + [Parameter("uint128", "validityEndTimestamp", 9)] + [JsonProperty("validityEndTimestamp")] + public BigInteger ValidityEndTimestamp { get; set; } + + /// + /// Gets or sets the unique identifier for the mint request. + /// + [Parameter("bytes32", "uid", 10)] + [JsonProperty("uid")] + public byte[] Uid { get; set; } +} + +#endregion + +#region TokenERC1155 + +/// +/// Represents a mint request for an ERC1155 token. +/// +[Struct("MintRequest")] +public class TokenERC1155_MintRequest +{ + /// + /// Gets or sets the address to mint the token to. + /// + [Parameter("address", "to", 1)] + [JsonProperty("to")] + public string To { get; set; } + + /// + /// Gets or sets the royalty recipient address. + /// + [Parameter("address", "royaltyRecipient", 2)] + [JsonProperty("royaltyRecipient")] + public string RoyaltyRecipient { get; set; } + + /// + /// Gets or sets the royalty basis points. + /// + [Parameter("uint256", "royaltyBps", 3)] + [JsonProperty("royaltyBps")] + public BigInteger RoyaltyBps { get; set; } + + /// + /// Gets or sets the primary sale recipient address. + /// + [Parameter("address", "primarySaleRecipient", 4)] + [JsonProperty("primarySaleRecipient")] + public string PrimarySaleRecipient { get; set; } + + /// + /// Gets or sets the token ID. + /// + [Parameter("uint256", "tokenId", 5)] + [JsonProperty("tokenId")] + public BigInteger? TokenId { get; set; } + + /// + /// Gets or sets the URI of the token. + /// + [Parameter("string", "uri", 6)] + [JsonProperty("uri")] + public string Uri { get; set; } + + /// + /// Gets or sets the quantity of tokens to mint. + /// + [Parameter("uint256", "quantity", 7)] + [JsonProperty("quantity")] + public BigInteger Quantity { get; set; } + + /// + /// Gets or sets the price per token. + /// + [Parameter("uint256", "pricePerToken", 8)] + [JsonProperty("pricePerToken")] + public BigInteger PricePerToken { get; set; } + + /// + /// Gets or sets the currency address. + /// + [Parameter("address", "currency", 9)] + [JsonProperty("currency")] + public string Currency { get; set; } + + /// + /// Gets or sets the validity start timestamp. + /// + [Parameter("uint128", "validityStartTimestamp", 10)] + [JsonProperty("validityStartTimestamp")] + public BigInteger ValidityStartTimestamp { get; set; } + + /// + /// Gets or sets the validity end timestamp. + /// + [Parameter("uint128", "validityEndTimestamp", 11)] + [JsonProperty("validityEndTimestamp")] + public BigInteger ValidityEndTimestamp { get; set; } + + /// + /// Gets or sets the unique identifier for the mint request. + /// + [Parameter("bytes32", "uid", 12)] + [JsonProperty("uid")] + public byte[] Uid { get; set; } +} + +#endregion diff --git a/Thirdweb/Thirdweb.Extensions/ThirdwebExtensions.cs b/Thirdweb/Thirdweb.Extensions/ThirdwebExtensions.cs index ebfc1dcc..869344c0 100644 --- a/Thirdweb/Thirdweb.Extensions/ThirdwebExtensions.cs +++ b/Thirdweb/Thirdweb.Extensions/ThirdwebExtensions.cs @@ -1,1155 +1,1368 @@ using System.Numerics; -using Nethereum.Hex.HexTypes; using Nethereum.Util; using Newtonsoft.Json; -namespace Thirdweb +namespace Thirdweb; + +public static class ThirdwebExtensions { - public static class ThirdwebExtensions + #region Common + + /// + /// Returns whether the contract supports the specified interface. + /// + /// The contract instance. + /// The interface ID to check. + /// A task that represents the asynchronous operation. The task result contains a boolean indicating whether the contract supports the interface. + /// + public static async Task SupportsInterface(this ThirdwebContract contract, string interfaceId) { - #region Common - - /// - /// Retrieves the metadata of the specified contract. - /// - /// The contract to retrieve metadata for. - /// A task that represents the asynchronous operation. The task result contains the contract metadata. - /// Thrown when the contract is null. - public static async Task GetMetadata(this ThirdwebContract contract) + if (contract == null) { - if (contract == null) - { - throw new ArgumentNullException(nameof(contract)); - } + throw new ArgumentNullException(nameof(contract)); + } - var contractUri = await ThirdwebContract.Read(contract, "contractURI"); + return await ThirdwebContract.Read(contract, "supportsInterface", interfaceId.HexToBytes()); + } - return await ThirdwebStorage.Download(contract.Client, contractUri); - } + /// + /// Encodes the function call for the specified method and parameters. + /// + /// The contract instance. + /// The method to call. + /// The parameters for the method. + /// The generated calldata. + public static string CreateCallData(this ThirdwebContract contract, string method, params object[] parameters) + { + (var data, _) = ThirdwebContract.EncodeFunctionCall(contract, method, parameters); + return data; + } - /// - /// Retrieves the image bytes of the specified NFT. - /// - /// The NFT to retrieve the image bytes for. - /// The client used to download the image bytes. - /// A task that represents the asynchronous operation. The task result contains the image bytes. - /// Thrown when the client is null. - public static async Task GetNFTImageBytes(this NFT nft, ThirdwebClient client) - { - if (client == null) - { - throw new ArgumentNullException(nameof(client)); - } + /// + /// Sends the transaction. + /// + /// The transaction. + /// The transaction hash. + public static async Task Send(this ThirdwebTransaction transaction) + { + return await ThirdwebTransaction.Send(transaction); + } - return string.IsNullOrEmpty(nft.Metadata.Image) ? new byte[] { } : await ThirdwebStorage.Download(client, nft.Metadata.Image).ConfigureAwait(false); - } + /// + /// Sends the transaction and waits for the transaction receipt. + /// + /// The transaction. + /// The transaction receipt. + public static async Task SendAndWaitForTransactionReceipt(this ThirdwebTransaction transaction) + { + return await ThirdwebTransaction.SendAndWaitForTransactionReceipt(transaction); + } - /// - /// Retrieves the default royalty information of the specified contract. - /// - /// The contract to retrieve the default royalty information for. - /// A task that represents the asynchronous operation. The task result contains the royalty information. - /// Thrown when the contract is null. - public static async Task GetDefaultRoyaltyInfo(this ThirdwebContract contract) - { - if (contract == null) - { - throw new ArgumentNullException(nameof(contract)); - } + /// + /// Reads data from the contract using the specified method. + /// + /// The type of the return value. + /// The contract instance. + /// The method to call. + /// The parameters for the method. + /// The result of the method call. + public static async Task Read(this ThirdwebContract contract, string method, params object[] parameters) + { + return await ThirdwebContract.Read(contract, method, parameters); + } - return await ThirdwebContract.Read(contract, "getDefaultRoyaltyInfo"); - } + /// + /// Writes data to the contract using the specified method and parameters. + /// + /// The contract instance. + /// The wallet instance. + /// The method to call. + /// The value in wei to send. + /// The parameters for the method. + /// A transaction receipt. + public static async Task Write(this ThirdwebContract contract, IThirdwebWallet wallet, string method, BigInteger weiValue, params object[] parameters) + { + return await ThirdwebContract.Write(wallet, contract, method, weiValue, parameters); + } - /// - /// Retrieves the primary sale recipient address of the specified contract. - /// - /// The contract to retrieve the primary sale recipient address for. - /// A task that represents the asynchronous operation. The task result contains the primary sale recipient address. - /// Thrown when the contract is null. - public static async Task GetPrimarySaleRecipient(this ThirdwebContract contract) - { - if (contract == null) - { - throw new ArgumentNullException(nameof(contract)); - } + /// + /// Prepares a transaction for the specified method and parameters. + /// + /// The contract instance. + /// The wallet instance. + /// The method to call. + /// The value in wei to send. + /// The parameters for the method. + /// A prepared transaction. + public static async Task Prepare(this ThirdwebContract contract, IThirdwebWallet wallet, string method, BigInteger weiValue, params object[] parameters) + { + return await ThirdwebContract.Prepare(wallet, contract, method, weiValue, parameters); + } - return await ThirdwebContract.Read(contract, "primarySaleRecipient"); + /// + /// Retrieves the metadata of the specified contract. + /// + /// The contract to retrieve metadata for. + /// A task that represents the asynchronous operation. The task result contains the contract metadata. + /// Thrown when the contract is null. + public static async Task GetMetadata(this ThirdwebContract contract) + { + if (contract == null) + { + throw new ArgumentNullException(nameof(contract)); } - /// - /// Retrieves the balance of the specified address on the specified chain. - /// - /// The client used to retrieve the balance. - /// The chain ID to retrieve the balance from. - /// The address to retrieve the balance for. - /// The optional ERC20 contract address to retrieve the balance from. - /// A task that represents the asynchronous operation. The task result contains the balance in Wei. - /// Thrown when the client is null. - /// Thrown when the chain ID is less than or equal to 0. - /// Thrown when the address is null or empty. - public static async Task GetBalanceRaw(ThirdwebClient client, BigInteger chainId, string address, string erc20ContractAddress = null) - { - if (client == null) - { - throw new ArgumentNullException(nameof(client)); - } + var contractUri = await ThirdwebContract.Read(contract, "contractURI"); - if (chainId <= 0) - { - throw new ArgumentOutOfRangeException(nameof(chainId), "Chain ID must be greater than 0."); - } + return await ThirdwebStorage.Download(contract.Client, contractUri); + } - if (string.IsNullOrEmpty(address)) - { - throw new ArgumentException("Address must be provided"); - } + /// + /// Retrieves the image bytes of the specified NFT. + /// + /// The NFT to retrieve the image bytes for. + /// The client used to download the image bytes. + /// A task that represents the asynchronous operation. The task result contains the image bytes. + /// Thrown when the client is null. + public static async Task GetNFTImageBytes(this NFT nft, ThirdwebClient client) + { + return client == null ? throw new ArgumentNullException(nameof(client)) + : string.IsNullOrEmpty(nft.Metadata.Image) ? Array.Empty() + : await ThirdwebStorage.Download(client, nft.Metadata.Image).ConfigureAwait(false); + } - if (erc20ContractAddress != null) - { - var erc20Contract = await ThirdwebContract.Create(client, erc20ContractAddress, chainId).ConfigureAwait(false); - return await erc20Contract.ERC20_BalanceOf(address).ConfigureAwait(false); - } + /// + /// Retrieves the default royalty information of the specified contract. + /// + /// The contract to retrieve the default royalty information for. + /// A task that represents the asynchronous operation. The task result contains the royalty information. + /// Thrown when the contract is null. + public static async Task GetDefaultRoyaltyInfo(this ThirdwebContract contract) + { + return contract == null ? throw new ArgumentNullException(nameof(contract)) : await ThirdwebContract.Read(contract, "getDefaultRoyaltyInfo"); + } + + /// + /// Retrieves the primary sale recipient address of the specified contract. + /// + /// The contract to retrieve the primary sale recipient address for. + /// A task that represents the asynchronous operation. The task result contains the primary sale recipient address. + /// Thrown when the contract is null. + public static async Task GetPrimarySaleRecipient(this ThirdwebContract contract) + { + return contract == null ? throw new ArgumentNullException(nameof(contract)) : await ThirdwebContract.Read(contract, "primarySaleRecipient"); + } - var rpc = ThirdwebRPC.GetRpcInstance(client, chainId); - var balanceHex = await rpc.SendRequestAsync("eth_getBalance", address, "latest").ConfigureAwait(false); - return new HexBigInteger(balanceHex).Value; + /// + /// Retrieves the balance of the specified address on the specified chain. + /// + /// The client used to retrieve the balance. + /// The chain ID to retrieve the balance from. + /// The address to retrieve the balance for. + /// The optional ERC20 contract address to retrieve the balance from. + /// A task that represents the asynchronous operation. The task result contains the balance in Wei. + /// Thrown when the client is null. + /// Thrown when the chain ID is less than or equal to 0. + /// Thrown when the address is null or empty. + public static async Task GetBalanceRaw(ThirdwebClient client, BigInteger chainId, string address, string erc20ContractAddress = null) + { + if (client == null) + { + throw new ArgumentNullException(nameof(client)); } - /// - /// Retrieves the balance of the specified contract. - /// - /// The contract to retrieve the balance for. - /// The optional ERC20 contract address to retrieve the balance from. - /// A task that represents the asynchronous operation. The task result contains the balance in Wei. - /// Thrown when the contract is null. - public static async Task GetBalance(this ThirdwebContract contract, string erc20ContractAddress = null) + if (chainId <= 0) { - if (contract == null) - { - throw new ArgumentNullException(nameof(contract)); - } + throw new ArgumentOutOfRangeException(nameof(chainId), "Chain ID must be greater than 0."); + } - return await GetBalanceRaw(contract.Client, contract.Chain, contract.Address, erc20ContractAddress).ConfigureAwait(false); + if (string.IsNullOrEmpty(address)) + { + throw new ArgumentException("Address must be provided"); } - /// - /// Retrieves the balance of the specified wallet on the specified chain. - /// - /// The wallet to retrieve the balance for. - /// The chain ID to retrieve the balance from. - /// The optional ERC20 contract address to retrieve the balance from. - /// A task that represents the asynchronous operation. The task result contains the balance in Wei. - /// Thrown when the wallet is null. - /// Thrown when the chain ID is less than or equal to 0. - public static async Task GetBalance(this IThirdwebWallet wallet, BigInteger chainId, string erc20ContractAddress = null) + if (erc20ContractAddress != null) { - if (wallet == null) - { - throw new ArgumentNullException(nameof(wallet)); - } + var erc20Contract = await ThirdwebContract.Create(client, erc20ContractAddress, chainId).ConfigureAwait(false); + return await erc20Contract.ERC20_BalanceOf(address).ConfigureAwait(false); + } - if (chainId <= 0) - { - throw new ArgumentOutOfRangeException(nameof(chainId), "Chain ID must be greater than 0."); - } + var rpc = ThirdwebRPC.GetRpcInstance(client, chainId); + var balanceHex = await rpc.SendRequestAsync("eth_getBalance", address, "latest").ConfigureAwait(false); + return balanceHex.HexToNumber(); + } - var address = await wallet.GetAddress().ConfigureAwait(false); + /// + /// Retrieves the balance of the specified contract. + /// + /// The contract to retrieve the balance for. + /// The optional ERC20 contract address to retrieve the balance from. + /// A task that represents the asynchronous operation. The task result contains the balance in Wei. + /// Thrown when the contract is null. + public static async Task GetBalance(this ThirdwebContract contract, string erc20ContractAddress = null) + { + return contract == null + ? throw new ArgumentNullException(nameof(contract)) + : await GetBalanceRaw(contract.Client, contract.Chain, contract.Address, erc20ContractAddress).ConfigureAwait(false); + } - return await GetBalanceRaw(wallet.Client, chainId, address, erc20ContractAddress).ConfigureAwait(false); + /// + /// Retrieves the balance of the specified wallet on the specified chain. + /// + /// The wallet to retrieve the balance for. + /// The chain ID to retrieve the balance from. + /// The optional ERC20 contract address to retrieve the balance from. + /// A task that represents the asynchronous operation. The task result contains the balance in Wei. + /// Thrown when the wallet is null. + /// Thrown when the chain ID is less than or equal to 0. + public static async Task GetBalance(this IThirdwebWallet wallet, BigInteger chainId, string erc20ContractAddress = null) + { + if (wallet == null) + { + throw new ArgumentNullException(nameof(wallet)); } - /// - /// Transfers the specified amount of Wei to the specified address. - /// - /// The wallet to transfer from. - /// The chain ID to transfer on. - /// The address to transfer to. - /// The amount of Wei to transfer. - /// A task that represents the asynchronous operation. The task result contains the transaction receipt. - /// Thrown when the wallet is null. - /// Thrown when the chain ID is less than or equal to 0. - /// Thrown when the recipient address is null or empty. - public static async Task Transfer(this IThirdwebWallet wallet, BigInteger chainId, string toAddress, BigInteger weiAmount) + if (chainId <= 0) { - if (wallet == null) - { - throw new ArgumentNullException(nameof(wallet)); - } + throw new ArgumentOutOfRangeException(nameof(chainId), "Chain ID must be greater than 0."); + } - if (chainId <= 0) - { - throw new ArgumentOutOfRangeException(nameof(chainId), "Chain ID must be greater than 0."); - } + var address = await wallet.GetAddress().ConfigureAwait(false); + return await GetBalanceRaw(wallet.Client, chainId, address, erc20ContractAddress).ConfigureAwait(false); + } - if (string.IsNullOrEmpty(toAddress)) - { - throw new ArgumentException(nameof(toAddress), "Recipient address cannot be null or empty."); - } + /// + /// Retrieves the transaction count (i.e. nonce) of the specified address on the specified chain. + /// + /// The client used to retrieve the transaction count. + /// The chain ID to retrieve the transaction count from. + /// The address to retrieve the transaction count for. + /// The block tag to retrieve the transaction count at. Defaults to "pending". + /// A task that represents the asynchronous operation. The task result contains the transaction count. + /// Thrown when the client is null. + /// Thrown when the chain ID is less than or equal to 0. + /// Thrown when the address is null or empty. + public static async Task GetTransactionCountRaw(ThirdwebClient client, BigInteger chainId, string address, string blocktag = "pending") + { + if (client == null) + { + throw new ArgumentNullException(nameof(client)); + } - if (weiAmount < 0) - { - throw new ArgumentOutOfRangeException(nameof(weiAmount), "Amount must be 0 or greater."); - } + if (chainId <= 0) + { + throw new ArgumentOutOfRangeException(nameof(chainId), "Chain ID must be greater than 0."); + } - var txInput = new ThirdwebTransactionInput() - { - From = await wallet.GetAddress().ConfigureAwait(false), - To = toAddress, - Value = new HexBigInteger(weiAmount) - }; - var tx = await ThirdwebTransaction.Create(wallet, txInput, chainId).ConfigureAwait(false); - return await ThirdwebTransaction.SendAndWaitForTransactionReceipt(tx).ConfigureAwait(false); + if (string.IsNullOrEmpty(address)) + { + throw new ArgumentException("Address must be provided"); } - #endregion + var rpc = ThirdwebRPC.GetRpcInstance(client, chainId); + var balanceHex = await rpc.SendRequestAsync("eth_getTransactionCount", address, blocktag).ConfigureAwait(false); + return balanceHex.HexToNumber(); + } + /// + /// Retrieves the transaction count (i.e. nonce) of the specified contract. + /// + /// The contract to retrieve the transaction count for. + /// The block tag to retrieve the transaction count at. Defaults to "pending". + /// A task that represents the asynchronous operation. The task result contains the transaction count. + /// Thrown when the contract is null. + public static async Task GetTransactionCount(this ThirdwebContract contract, string blocktag = "pending") + { + return contract == null ? throw new ArgumentNullException(nameof(contract)) : await GetTransactionCountRaw(contract.Client, contract.Chain, contract.Address, blocktag).ConfigureAwait(false); + } - #region ERC20 + /// + /// Retrieves the transaction count (i.e. nonce) of the specified wallet on the specified chain. + /// + /// The wallet to retrieve the transaction count for. + /// The chain ID to retrieve the transaction count from. + /// The block tag to retrieve the transaction count at. Defaults to "pending". + /// A task that represents the asynchronous operation. The task result contains the transaction count. + /// Thrown when the wallet is null. + /// Thrown when the chain ID is less than or equal to 0. + public static async Task GetTransactionCount(this IThirdwebWallet wallet, BigInteger chainId, string blocktag = "pending") + { + if (wallet == null) + { + throw new ArgumentNullException(nameof(wallet)); + } - /// - /// Check the balance of a specific address. - /// - /// The contract to interact with. - /// The address of the owner whose balance is to be checked. - /// A task representing the asynchronous operation, with a BigInteger result containing the balance. - /// Thrown when the contract is null. - /// Thrown when the owner address is null or empty. - public static async Task ERC20_BalanceOf(this ThirdwebContract contract, string ownerAddress) + if (chainId <= 0) { - if (contract == null) - { - throw new ArgumentNullException(nameof(contract)); - } + throw new ArgumentOutOfRangeException(nameof(chainId), "Chain ID must be greater than 0."); + } - if (string.IsNullOrEmpty(ownerAddress)) - { - throw new ArgumentException("Owner address must be provided"); - } + var address = await wallet.GetAddress().ConfigureAwait(false); + return await GetTransactionCountRaw(wallet.Client, chainId, address, blocktag).ConfigureAwait(false); + } - return await ThirdwebContract.Read(contract, "balanceOf", ownerAddress); + /// + /// Transfers the specified amount of Wei to the specified address. Passing tokenAddress will override this function to transfer ERC20 tokens. + /// + /// The wallet to transfer from. + /// The chain ID to transfer on. + /// The address to transfer to. + /// The amount of Wei to transfer. + /// The optional token address to transfer from. Defaults to the native token address (ETH or equivalent). + /// A task that represents the asynchronous operation. The task result contains the transaction receipt. + /// A task that represents the asynchronous operation. The task result contains the transaction receipt. + /// Thrown when the wallet is null. + /// Thrown when the chain ID is less than or equal to 0. + /// Thrown when the recipient address is null or empty. + public static async Task Transfer( + this IThirdwebWallet wallet, + BigInteger chainId, + string toAddress, + BigInteger weiAmount, + string tokenAddress = Constants.NATIVE_TOKEN_ADDRESS + ) + { + if (wallet == null) + { + throw new ArgumentNullException(nameof(wallet)); } - /// - /// Get the total supply of the token. - /// - /// The contract to interact with. - /// A task representing the asynchronous operation, with a BigInteger result containing the total supply. - /// Thrown when the contract is null. - public static async Task ERC20_TotalSupply(this ThirdwebContract contract) + if (chainId <= 0) { - if (contract == null) - { - throw new ArgumentNullException(nameof(contract)); - } - - return await ThirdwebContract.Read(contract, "totalSupply"); + throw new ArgumentOutOfRangeException(nameof(chainId), "Chain ID must be greater than 0."); } - /// - /// Get the number of decimals used by the token. - /// - /// The contract to interact with. - /// A task representing the asynchronous operation, with an int result containing the number of decimals. - /// Thrown when the contract is null. - public static async Task ERC20_Decimals(this ThirdwebContract contract) + if (string.IsNullOrEmpty(toAddress)) { - if (contract == null) - { - throw new ArgumentNullException(nameof(contract)); - } - - return await ThirdwebContract.Read(contract, "decimals"); + throw new ArgumentException(nameof(toAddress), "Recipient address cannot be null or empty."); } - /// - /// Get the symbol of the token. - /// - /// The contract to interact with. - /// A task representing the asynchronous operation, with a string result containing the symbol. - /// Thrown when the contract is null. - public static async Task ERC20_Symbol(this ThirdwebContract contract) + if (weiAmount < 0) { - if (contract == null) - { - throw new ArgumentNullException(nameof(contract)); - } - - return await ThirdwebContract.Read(contract, "symbol"); + throw new ArgumentOutOfRangeException(nameof(weiAmount), "Amount must be 0 or greater."); } - /// - /// Get the name of the token. - /// - /// The contract to interact with. - /// A task representing the asynchronous operation, with a string result containing the name. - /// Thrown when the contract is null. - public static async Task ERC20_Name(this ThirdwebContract contract) + if (tokenAddress != Constants.NATIVE_TOKEN_ADDRESS) { - if (contract == null) - { - throw new ArgumentNullException(nameof(contract)); - } - - return await ThirdwebContract.Read(contract, "name"); + var erc20Contract = await ThirdwebContract.Create(wallet.Client, tokenAddress, chainId).ConfigureAwait(false); + return await erc20Contract.ERC20_Transfer(wallet, toAddress, weiAmount).ConfigureAwait(false); } - - /// - /// Get the allowance of a spender for a specific owner. - /// - /// The contract to interact with. - /// The address of the owner. - /// The address of the spender. - /// A task representing the asynchronous operation, with a BigInteger result containing the allowance. - /// Thrown when the contract is null. - /// Thrown when the owner address or spender address is null or empty. - public static async Task ERC20_Allowance(this ThirdwebContract contract, string ownerAddress, string spenderAddress) + else { - if (contract == null) - { - throw new ArgumentNullException(nameof(contract)); - } + var txInput = new ThirdwebTransactionInput(chainId: chainId, to: toAddress, value: weiAmount); + var tx = await ThirdwebTransaction.Create(wallet, txInput).ConfigureAwait(false); + return await ThirdwebTransaction.SendAndWaitForTransactionReceipt(tx).ConfigureAwait(false); + } + } - if (string.IsNullOrEmpty(ownerAddress)) - { - throw new ArgumentException("Owner address must be provided"); - } + /// + /// Authenticates the wallet. + /// + /// The wallet that will sign the SIWE payload. + /// The authentication domain. + /// The chain ID. + /// The authentication payload path. + /// The authentication login path. + /// The HTTP client override. + /// The authentication payload method. + /// The authentication login method. + /// Whether to separate the payload and signature in the body. + /// The authentication result. + public static async Task Authenticate( + this IThirdwebWallet wallet, + string domain, + BigInteger chainId, + string authPayloadPath = "/auth/payload", + string authLoginPath = "/auth/login", + string authPayloadMethod = "GET", + string authLoginMethod = "POST", + bool separatePayloadAndSignatureInBody = false, + IThirdwebHttpClient httpClientOverride = null + ) + { + var payloadURL = domain + authPayloadPath; + var loginURL = domain + authLoginPath; - if (string.IsNullOrEmpty(spenderAddress)) - { - throw new ArgumentException("Spender address must be provided"); - } + var payloadBodyRaw = new { address = await wallet.GetAddress(), chainId = chainId.ToString() }; + var payloadBody = JsonConvert.SerializeObject(payloadBodyRaw); + + var httpClient = httpClientOverride ?? wallet.Client.HttpClient; - return await ThirdwebContract.Read(contract, "allowance", ownerAddress, spenderAddress); + var payloadContent = new StringContent(payloadBody, System.Text.Encoding.UTF8, "application/json"); + ThirdwebHttpResponseMessage payloadResponse; + if (authPayloadMethod == "GET") + { + payloadURL += "?address=" + await wallet.GetAddress() + "&chainId=" + chainId.ToString(); + payloadResponse = await httpClient.GetAsync(payloadURL); + } + else if (authPayloadMethod == "POST") + { + payloadResponse = await httpClient.PostAsync(payloadURL, payloadContent); + } + else + { + throw new Exception("Unsupported HTTP method for auth payload"); } - /// - /// Approve a spender to spend a specific amount of tokens. - /// - /// The contract to interact with. - /// The wallet to use for the transaction. - /// The address of the spender. - /// The amount of tokens to approve. - /// A task representing the asynchronous operation, with a ThirdwebTransactionReceipt result. - /// Thrown when the contract or wallet is null. - /// Thrown when the spender address is null or empty. - public static async Task ERC20_Approve(this ThirdwebContract contract, IThirdwebWallet wallet, string spenderAddress, BigInteger amount) + _ = payloadResponse.EnsureSuccessStatusCode(); + var payloadString = await payloadResponse.Content.ReadAsStringAsync(); + + var loginBodyRaw = JsonConvert.DeserializeObject(payloadString); + if (loginBodyRaw.Payload == null) { - if (contract == null) - { - throw new ArgumentNullException(nameof(contract)); - } + var payloadDataRaw = JsonConvert.DeserializeObject(payloadString); + loginBodyRaw.Payload = payloadDataRaw; + } - if (wallet == null) - { - throw new ArgumentNullException(nameof(wallet)); - } + var payloadToSign = Utils.GenerateSIWE(loginBodyRaw.Payload); + loginBodyRaw.Signature = await wallet.PersonalSign(payloadToSign); - if (string.IsNullOrEmpty(spenderAddress)) - { - throw new ArgumentException("Spender address must be provided"); - } + var loginBody = JsonConvert.SerializeObject(separatePayloadAndSignatureInBody ? new { payload = loginBodyRaw.Payload, signature = loginBodyRaw.Signature } : new { payload = loginBodyRaw }); - return await ThirdwebContract.Write(wallet, contract, "approve", 0, spenderAddress, amount); + var loginContent = new StringContent(loginBody, System.Text.Encoding.UTF8, "application/json"); + ThirdwebHttpResponseMessage loginResponse; + if (authLoginMethod == "GET") + { + loginURL = loginURL + "?payload=" + JsonConvert.SerializeObject(loginBodyRaw); + loginResponse = await httpClient.GetAsync(loginURL); } - - /// - /// Transfer tokens to a specific address. - /// - /// The contract to interact with. - /// The wallet to use for the transaction. - /// The address of the recipient. - /// The amount of tokens to transfer. - /// A task representing the asynchronous operation, with a ThirdwebTransactionReceipt result. - /// Thrown when the contract or wallet is null. - /// Thrown when the recipient address is null or empty. - public static async Task ERC20_Transfer(this ThirdwebContract contract, IThirdwebWallet wallet, string toAddress, BigInteger amount) + else if (authLoginMethod == "POST") { - if (contract == null) - { - throw new ArgumentNullException(nameof(contract)); - } + loginResponse = await httpClient.PostAsync(loginURL, loginContent); + } + else + { + throw new Exception("Unsupported HTTP method for auth login"); + } + _ = loginResponse.EnsureSuccessStatusCode(); - if (wallet == null) - { - throw new ArgumentNullException(nameof(wallet)); - } + if (typeof(T) == typeof(byte[])) + { + return (T)(object)await loginResponse.Content.ReadAsByteArrayAsync().ConfigureAwait(false); + } + else if (typeof(T) == typeof(string)) + { + return (T)(object)await loginResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + } + else + { + var content = await loginResponse.Content.ReadAsByteArrayAsync().ConfigureAwait(false); + return JsonConvert.DeserializeObject(System.Text.Encoding.UTF8.GetString(content)); + } + } - if (string.IsNullOrEmpty(toAddress)) - { - throw new ArgumentException("Recipient address must be provided"); - } + #endregion - return await ThirdwebContract.Write(wallet, contract, "transfer", 0, toAddress, amount); - } + #region ERC20 - /// - /// Transfer tokens from one address to another. - /// - /// The contract to interact with. - /// The wallet to use for the transaction. - /// The address of the sender. - /// The address of the recipient. - /// The amount of tokens to transfer. - /// A task representing the asynchronous operation, with a ThirdwebTransactionReceipt result. - /// Thrown when the contract or wallet is null. - /// Thrown when the sender address or recipient address is null or empty. - public static async Task ERC20_TransferFrom(this ThirdwebContract contract, IThirdwebWallet wallet, string fromAddress, string toAddress, BigInteger amount) + /// + /// Check the balance of a specific address. + /// + /// The contract to interact with. + /// The address of the owner whose balance is to be checked. + /// A task representing the asynchronous operation, with a BigInteger result containing the balance. + /// Thrown when the contract is null. + /// Thrown when the owner address is null or empty. + public static async Task ERC20_BalanceOf(this ThirdwebContract contract, string ownerAddress) + { + if (contract == null) { - if (contract == null) - { - throw new ArgumentNullException(nameof(contract)); - } - - if (wallet == null) - { - throw new ArgumentNullException(nameof(wallet)); - } + throw new ArgumentNullException(nameof(contract)); + } - if (string.IsNullOrEmpty(fromAddress)) - { - throw new ArgumentException("Sender address must be provided"); - } + return string.IsNullOrEmpty(ownerAddress) ? throw new ArgumentException("Owner address must be provided") : await ThirdwebContract.Read(contract, "balanceOf", ownerAddress); + } - if (string.IsNullOrEmpty(toAddress)) - { - throw new ArgumentException("Recipient address must be provided"); - } + /// + /// Get the total supply of the token. + /// + /// The contract to interact with. + /// A task representing the asynchronous operation, with a BigInteger result containing the total supply. + /// Thrown when the contract is null. + public static async Task ERC20_TotalSupply(this ThirdwebContract contract) + { + return contract == null ? throw new ArgumentNullException(nameof(contract)) : await ThirdwebContract.Read(contract, "totalSupply"); + } - return await ThirdwebContract.Write(wallet, contract, "transferFrom", 0, fromAddress, toAddress, amount); - } + /// + /// Get the number of decimals used by the token. + /// + /// The contract to interact with. + /// A task representing the asynchronous operation, with an int result containing the number of decimals. + /// Thrown when the contract is null. + public static async Task ERC20_Decimals(this ThirdwebContract contract) + { + return contract == null ? throw new ArgumentNullException(nameof(contract)) : await ThirdwebContract.Read(contract, "decimals"); + } - #endregion + /// + /// Get the symbol of the token. + /// + /// The contract to interact with. + /// A task representing the asynchronous operation, with a string result containing the symbol. + /// Thrown when the contract is null. + public static async Task ERC20_Symbol(this ThirdwebContract contract) + { + return contract == null ? throw new ArgumentNullException(nameof(contract)) : await ThirdwebContract.Read(contract, "symbol"); + } - #region ERC721 + /// + /// Get the name of the token. + /// + /// The contract to interact with. + /// A task representing the asynchronous operation, with a string result containing the name. + /// Thrown when the contract is null. + public static async Task ERC20_Name(this ThirdwebContract contract) + { + return contract == null ? throw new ArgumentNullException(nameof(contract)) : await ThirdwebContract.Read(contract, "name"); + } - /// - /// Get the total supply of the token. - /// - /// The contract to interact with. - /// A task representing the asynchronous operation, with a BigInteger result containing the total supply. - /// Thrown when the contract is null. - public static async Task ERC721_TotalSupply(this ThirdwebContract contract) + /// + /// Get the allowance of a spender for a specific owner. + /// + /// The contract to interact with. + /// The address of the owner. + /// The address of the spender. + /// A task representing the asynchronous operation, with a BigInteger result containing the allowance. + /// Thrown when the contract is null. + /// Thrown when the owner address or spender address is null or empty. + public static async Task ERC20_Allowance(this ThirdwebContract contract, string ownerAddress, string spenderAddress) + { + if (contract == null) { - if (contract == null) - { - throw new ArgumentNullException(nameof(contract)); - } - - return await ThirdwebContract.Read(contract, "totalSupply"); + throw new ArgumentNullException(nameof(contract)); } - /// - /// Get the token ID of a specific owner by index. - /// - /// The contract to interact with. - /// The address of the owner. - /// The index of the token. - /// A task representing the asynchronous operation, with a BigInteger result containing the token ID. - /// Thrown when the contract is null. - /// Thrown when the owner address is null or empty. - public static async Task ERC721_TokenOfOwnerByIndex(this ThirdwebContract contract, string ownerAddress, BigInteger index) + if (string.IsNullOrEmpty(ownerAddress)) { - if (contract == null) - { - throw new ArgumentNullException(nameof(contract)); - } - - if (string.IsNullOrEmpty(ownerAddress)) - { - throw new ArgumentException("Owner address must be provided"); - } - - return await ThirdwebContract.Read(contract, "tokenOfOwnerByIndex", ownerAddress, index); + throw new ArgumentException("Owner address must be provided"); } - /// - /// Get the token ID of a specific token by index. - /// - /// The contract to interact with. - /// The index of the token. - /// A task representing the asynchronous operation, with a BigInteger result containing the token ID. - /// Thrown when the contract is null. - public static async Task ERC721_TokenByIndex(this ThirdwebContract contract, BigInteger index) - { - if (contract == null) - { - throw new ArgumentNullException(nameof(contract)); - } + return string.IsNullOrEmpty(spenderAddress) + ? throw new ArgumentException("Spender address must be provided") + : await ThirdwebContract.Read(contract, "allowance", ownerAddress, spenderAddress); + } - return await ThirdwebContract.Read(contract, "tokenByIndex", index); + /// + /// Approve a spender to spend a specific amount of tokens. + /// + /// The contract to interact with. + /// The wallet to use for the transaction. + /// The address of the spender. + /// The amount of tokens to approve. + /// A task representing the asynchronous operation, with a ThirdwebTransactionReceipt result. + /// Thrown when the contract or wallet is null. + /// Thrown when the spender address is null or empty. + public static async Task ERC20_Approve(this ThirdwebContract contract, IThirdwebWallet wallet, string spenderAddress, BigInteger amount) + { + if (contract == null) + { + throw new ArgumentNullException(nameof(contract)); } - /// - /// Check the balance of a specific address. - /// - /// The contract to interact with. - /// The address of the owner whose balance is to be checked. - /// A task representing the asynchronous operation, with a BigInteger result containing the balance. - /// Thrown when the contract is null. - /// Thrown when the owner address is null or empty. - public static async Task ERC721_BalanceOf(this ThirdwebContract contract, string ownerAddress) + if (wallet == null) { - if (contract == null) - { - throw new ArgumentNullException(nameof(contract)); - } + throw new ArgumentNullException(nameof(wallet)); + } - if (string.IsNullOrEmpty(ownerAddress)) - { - throw new ArgumentException("Owner address must be provided"); - } + return string.IsNullOrEmpty(spenderAddress) + ? throw new ArgumentException("Spender address must be provided") + : await ThirdwebContract.Write(wallet, contract, "approve", 0, spenderAddress, amount); + } - return await ThirdwebContract.Read(contract, "balanceOf", ownerAddress); + /// + /// Transfer tokens to a specific address. + /// + /// The contract to interact with. + /// The wallet to use for the transaction. + /// The address of the recipient. + /// The amount of tokens to transfer. + /// A task representing the asynchronous operation, with a ThirdwebTransactionReceipt result. + /// Thrown when the contract or wallet is null. + /// Thrown when the recipient address is null or empty. + public static async Task ERC20_Transfer(this ThirdwebContract contract, IThirdwebWallet wallet, string toAddress, BigInteger amount) + { + if (contract == null) + { + throw new ArgumentNullException(nameof(contract)); } - /// - /// Get the owner of a specific token. - /// - /// The contract to interact with. - /// The ID of the token. - /// A task representing the asynchronous operation, with a string result containing the owner's address. - /// Thrown when the contract is null. - /// Thrown when the token ID is less than 0. - public static async Task ERC721_OwnerOf(this ThirdwebContract contract, BigInteger tokenId) + if (wallet == null) { - if (contract == null) - { - throw new ArgumentNullException(nameof(contract)); - } + throw new ArgumentNullException(nameof(wallet)); + } - if (tokenId < 0) - { - throw new ArgumentOutOfRangeException(nameof(tokenId), "Token ID must be equal or greater than 0"); - } + return string.IsNullOrEmpty(toAddress) ? throw new ArgumentException("Recipient address must be provided") : await ThirdwebContract.Write(wallet, contract, "transfer", 0, toAddress, amount); + } - return await ThirdwebContract.Read(contract, "ownerOf", tokenId); + /// + /// Transfer tokens from one address to another. + /// + /// The contract to interact with. + /// The wallet to use for the transaction. + /// The address of the sender. + /// The address of the recipient. + /// The amount of tokens to transfer. + /// A task representing the asynchronous operation, with a ThirdwebTransactionReceipt result. + /// Thrown when the contract or wallet is null. + /// Thrown when the sender address or recipient address is null or empty. + public static async Task ERC20_TransferFrom(this ThirdwebContract contract, IThirdwebWallet wallet, string fromAddress, string toAddress, BigInteger amount) + { + if (contract == null) + { + throw new ArgumentNullException(nameof(contract)); } - /// - /// Get the name of the token. - /// - /// The contract to interact with. - /// A task representing the asynchronous operation, with a string result containing the name. - /// Thrown when the contract is null. - public static async Task ERC721_Name(this ThirdwebContract contract) + if (wallet == null) { - if (contract == null) - { - throw new ArgumentNullException(nameof(contract)); - } - - return await ThirdwebContract.Read(contract, "name"); + throw new ArgumentNullException(nameof(wallet)); } - /// - /// Get the symbol of the token. - /// - /// The contract to interact with. - /// A task representing the asynchronous operation, with a string result containing the symbol. - /// Thrown when the contract is null. - public static async Task ERC721_Symbol(this ThirdwebContract contract) + if (string.IsNullOrEmpty(fromAddress)) { - if (contract == null) - { - throw new ArgumentNullException(nameof(contract)); - } - - return await ThirdwebContract.Read(contract, "symbol"); + throw new ArgumentException("Sender address must be provided"); } - /// - /// Get the URI of a specific token. - /// - /// The contract to interact with. - /// The ID of the token. - /// A task representing the asynchronous operation, with a string result containing the token URI. - /// Thrown when the contract is null. - /// Thrown when the token ID is less than 0. - public static async Task ERC721_TokenURI(this ThirdwebContract contract, BigInteger tokenId) - { - if (contract == null) - { - throw new ArgumentNullException(nameof(contract)); - } + return string.IsNullOrEmpty(toAddress) + ? throw new ArgumentException("Recipient address must be provided") + : await ThirdwebContract.Write(wallet, contract, "transferFrom", 0, fromAddress, toAddress, amount); + } - if (tokenId < 0) - { - throw new ArgumentOutOfRangeException(nameof(tokenId), "Token ID must be equal or greater than 0"); - } + #endregion - return await ThirdwebContract.Read(contract, "tokenURI", tokenId); - } + #region ERC721A - /// - /// Approve a specific address to transfer a specific token. - /// - /// The contract to interact with. - /// The wallet to use for the transaction. - /// The address of the recipient. - /// The ID of the token. - /// A task representing the asynchronous operation, with a ThirdwebTransactionReceipt result. - /// Thrown when the contract or wallet is null. - /// Thrown when the recipient address is null or empty. - public static async Task ERC721_Approve(this ThirdwebContract contract, IThirdwebWallet wallet, string toAddress, BigInteger tokenId) + public static async Task> ERC721A_TokensOfOwner(this ThirdwebContract contract, string ownerAddress) + { + if (contract == null) { - if (contract == null) - { - throw new ArgumentNullException(nameof(contract)); - } - - if (wallet == null) - { - throw new ArgumentNullException(nameof(wallet)); - } + throw new ArgumentNullException(nameof(contract)); + } - if (string.IsNullOrEmpty(toAddress)) - { - throw new ArgumentException("Recipient address must be provided"); - } + return string.IsNullOrEmpty(ownerAddress) + ? throw new ArgumentException("Owner address must be provided") + : await ThirdwebContract.Read>(contract, "tokensOfOwner", ownerAddress); + } - return await ThirdwebContract.Write(wallet, contract, "approve", 0, toAddress, tokenId); + public static async Task> ERC721A_TokensOfOwnerIn(this ThirdwebContract contract, string ownerAddress, BigInteger startIndex, BigInteger endIndex) + { + if (contract == null) + { + throw new ArgumentNullException(nameof(contract)); } - /// - /// Get the approved address for a specific token. - /// - /// The contract to interact with. - /// The ID of the token. - /// A task representing the asynchronous operation, with a string result containing the approved address. - /// Thrown when the contract is null. - /// Thrown when the token ID is less than 0. - public static async Task ERC721_GetApproved(this ThirdwebContract contract, BigInteger tokenId) - { - if (contract == null) - { - throw new ArgumentNullException(nameof(contract)); - } + return string.IsNullOrEmpty(ownerAddress) + ? throw new ArgumentException("Owner address must be provided") + : await ThirdwebContract.Read>(contract, "tokensOfOwnerIn", ownerAddress, startIndex, endIndex); + } - if (tokenId < 0) - { - throw new ArgumentOutOfRangeException(nameof(tokenId), "Token ID must be equal or greater than 0"); - } + #endregion - return await ThirdwebContract.Read(contract, "getApproved", tokenId); - } + #region ERC721 - /// - /// Check if an address is an operator for another address. - /// - /// The contract to interact with. - /// The address of the owner. - /// The address of the operator. - /// A task representing the asynchronous operation, with a boolean result indicating if the operator is approved for the owner. - /// Thrown when the contract is null. - /// Thrown when the owner address or operator address is null or empty. - public static async Task ERC721_IsApprovedForAll(this ThirdwebContract contract, string ownerAddress, string operatorAddress) + /// + /// Get the total supply of the token. + /// + /// The contract to interact with. + /// A task representing the asynchronous operation, with a BigInteger result containing the total supply. + /// Thrown when the contract is null. + public static async Task ERC721_TotalSupply(this ThirdwebContract contract) + { + if (contract == null) { - if (contract == null) - { - throw new ArgumentNullException(nameof(contract)); - } - - if (string.IsNullOrEmpty(ownerAddress)) - { - throw new ArgumentException("Owner address must be provided"); - } - - if (string.IsNullOrEmpty(operatorAddress)) - { - throw new ArgumentException("Operator address must be provided"); - } + throw new ArgumentNullException(nameof(contract)); + } - return await ThirdwebContract.Read(contract, "isApprovedForAll", ownerAddress, operatorAddress); + try + { + return await ThirdwebContract.Read(contract, "nextTokenIdToMint"); + } + catch + { + return await ThirdwebContract.Read(contract, "totalSupply"); } + } - /// - /// Set or unset an operator for an owner. - /// - /// The contract to interact with. - /// The wallet to use for the transaction. - /// The address of the operator. - /// A boolean indicating whether to set or unset the operator. - /// A task representing the asynchronous operation, with a ThirdwebTransactionReceipt result. - /// Thrown when the contract or wallet is null. - /// Thrown when the operator address is null or empty. - public static async Task ERC721_SetApprovalForAll(this ThirdwebContract contract, IThirdwebWallet wallet, string operatorAddress, bool approved) + /// + /// Get the token ID of a specific owner by index. + /// + /// The contract to interact with. + /// The address of the owner. + /// The index of the token. + /// A task representing the asynchronous operation, with a BigInteger result containing the token ID. + /// Thrown when the contract is null. + /// Thrown when the owner address is null or empty. + public static async Task ERC721_TokenOfOwnerByIndex(this ThirdwebContract contract, string ownerAddress, BigInteger index) + { + if (contract == null) { - if (contract == null) - { - throw new ArgumentNullException(nameof(contract)); - } + throw new ArgumentNullException(nameof(contract)); + } - if (wallet == null) - { - throw new ArgumentNullException(nameof(wallet)); - } + return string.IsNullOrEmpty(ownerAddress) + ? throw new ArgumentException("Owner address must be provided") + : await ThirdwebContract.Read(contract, "tokenOfOwnerByIndex", ownerAddress, index); + } - if (string.IsNullOrEmpty(operatorAddress)) - { - throw new ArgumentException("Operator address must be provided"); - } + /// + /// Get the token ID of a specific token by index. + /// + /// The contract to interact with. + /// The index of the token. + /// A task representing the asynchronous operation, with a BigInteger result containing the token ID. + /// Thrown when the contract is null. + public static async Task ERC721_TokenByIndex(this ThirdwebContract contract, BigInteger index) + { + return contract == null ? throw new ArgumentNullException(nameof(contract)) : await ThirdwebContract.Read(contract, "tokenByIndex", index); + } - return await ThirdwebContract.Write(wallet, contract, "setApprovalForAll", 0, operatorAddress, approved); + /// + /// Check the balance of a specific address. + /// + /// The contract to interact with. + /// The address of the owner whose balance is to be checked. + /// A task representing the asynchronous operation, with a BigInteger result containing the balance. + /// Thrown when the contract is null. + /// Thrown when the owner address is null or empty. + public static async Task ERC721_BalanceOf(this ThirdwebContract contract, string ownerAddress) + { + if (contract == null) + { + throw new ArgumentNullException(nameof(contract)); } - /// - /// Transfer a specific token from one address to another. - /// - /// The contract to interact with. - /// The wallet to use for the transaction. - /// The address of the sender. - /// The address of the recipient. - /// The ID of the token. - /// A task representing the asynchronous operation, with a ThirdwebTransactionReceipt result. - /// Thrown when the contract or wallet is null. - /// Thrown when the sender address or recipient address is null or empty. - public static async Task ERC721_TransferFrom(this ThirdwebContract contract, IThirdwebWallet wallet, string fromAddress, string toAddress, BigInteger tokenId) + return string.IsNullOrEmpty(ownerAddress) ? throw new ArgumentException("Owner address must be provided") : await ThirdwebContract.Read(contract, "balanceOf", ownerAddress); + } + + /// + /// Get the owner of a specific token. + /// + /// The contract to interact with. + /// The ID of the token. + /// A task representing the asynchronous operation, with a string result containing the owner's address. + /// Thrown when the contract is null. + /// Thrown when the token ID is less than 0. + public static async Task ERC721_OwnerOf(this ThirdwebContract contract, BigInteger tokenId) + { + if (contract == null) { - if (contract == null) - { - throw new ArgumentNullException(nameof(contract)); - } + throw new ArgumentNullException(nameof(contract)); + } - if (wallet == null) - { - throw new ArgumentNullException(nameof(wallet)); - } + return tokenId < 0 ? throw new ArgumentOutOfRangeException(nameof(tokenId), "Token ID must be equal or greater than 0") : await ThirdwebContract.Read(contract, "ownerOf", tokenId); + } - if (string.IsNullOrEmpty(fromAddress)) - { - throw new ArgumentException("Sender address must be provided"); - } + /// + /// Get the name of the token. + /// + /// The contract to interact with. + /// A task representing the asynchronous operation, with a string result containing the name. + /// Thrown when the contract is null. + public static async Task ERC721_Name(this ThirdwebContract contract) + { + return contract == null ? throw new ArgumentNullException(nameof(contract)) : await ThirdwebContract.Read(contract, "name"); + } - if (string.IsNullOrEmpty(toAddress)) - { - throw new ArgumentException("Recipient address must be provided"); - } + /// + /// Get the symbol of the token. + /// + /// The contract to interact with. + /// A task representing the asynchronous operation, with a string result containing the symbol. + /// Thrown when the contract is null. + public static async Task ERC721_Symbol(this ThirdwebContract contract) + { + return contract == null ? throw new ArgumentNullException(nameof(contract)) : await ThirdwebContract.Read(contract, "symbol"); + } + + /// + /// Get the URI of a specific token. + /// + /// The contract to interact with. + /// The ID of the token. + /// A task representing the asynchronous operation, with a string result containing the token URI. + /// Thrown when the contract is null. + /// Thrown when the token ID is less than 0. + public static async Task ERC721_TokenURI(this ThirdwebContract contract, BigInteger tokenId) + { + if (contract == null) + { + throw new ArgumentNullException(nameof(contract)); + } + + return tokenId < 0 ? throw new ArgumentOutOfRangeException(nameof(tokenId), "Token ID must be equal or greater than 0") : await ThirdwebContract.Read(contract, "tokenURI", tokenId); + } - return await ThirdwebContract.Write(wallet, contract, "transferFrom", 0, fromAddress, toAddress, tokenId); + /// + /// Approve a specific address to transfer a specific token. + /// + /// The contract to interact with. + /// The wallet to use for the transaction. + /// The address of the recipient. + /// The ID of the token. + /// A task representing the asynchronous operation, with a ThirdwebTransactionReceipt result. + /// Thrown when the contract or wallet is null. + /// Thrown when the recipient address is null or empty. + public static async Task ERC721_Approve(this ThirdwebContract contract, IThirdwebWallet wallet, string toAddress, BigInteger tokenId) + { + if (contract == null) + { + throw new ArgumentNullException(nameof(contract)); } - /// - /// Safely transfer a specific token from one address to another. - /// - /// The contract to interact with. - /// The wallet to use for the transaction. - /// The address of the sender. - /// The address of the recipient. - /// The ID of the token. - /// A task representing the asynchronous operation, with a ThirdwebTransactionReceipt result. - /// Thrown when the contract or wallet is null. - /// Thrown when the sender address or recipient address is null or empty. - public static async Task ERC721_SafeTransferFrom(this ThirdwebContract contract, IThirdwebWallet wallet, string fromAddress, string toAddress, BigInteger tokenId) + if (wallet == null) { - if (contract == null) - { - throw new ArgumentNullException(nameof(contract)); - } + throw new ArgumentNullException(nameof(wallet)); + } - if (wallet == null) - { - throw new ArgumentNullException(nameof(wallet)); - } + return string.IsNullOrEmpty(toAddress) ? throw new ArgumentException("Recipient address must be provided") : await ThirdwebContract.Write(wallet, contract, "approve", 0, toAddress, tokenId); + } - if (string.IsNullOrEmpty(fromAddress)) - { - throw new ArgumentException("Sender address must be provided"); - } + /// + /// Get the approved address for a specific token. + /// + /// The contract to interact with. + /// The ID of the token. + /// A task representing the asynchronous operation, with a string result containing the approved address. + /// Thrown when the contract is null. + /// Thrown when the token ID is less than 0. + public static async Task ERC721_GetApproved(this ThirdwebContract contract, BigInteger tokenId) + { + if (contract == null) + { + throw new ArgumentNullException(nameof(contract)); + } - if (string.IsNullOrEmpty(toAddress)) - { - throw new ArgumentException("Recipient address must be provided"); - } + return tokenId < 0 ? throw new ArgumentOutOfRangeException(nameof(tokenId), "Token ID must be equal or greater than 0") : await ThirdwebContract.Read(contract, "getApproved", tokenId); + } - return await ThirdwebContract.Write(wallet, contract, "safeTransferFrom", 0, fromAddress, toAddress, tokenId); + /// + /// Check if an address is an operator for another address. + /// + /// The contract to interact with. + /// The address of the owner. + /// The address of the operator. + /// A task representing the asynchronous operation, with a boolean result indicating if the operator is approved for the owner. + /// Thrown when the contract is null. + /// Thrown when the owner address or operator address is null or empty. + public static async Task ERC721_IsApprovedForAll(this ThirdwebContract contract, string ownerAddress, string operatorAddress) + { + if (contract == null) + { + throw new ArgumentNullException(nameof(contract)); } - #endregion + if (string.IsNullOrEmpty(ownerAddress)) + { + throw new ArgumentException("Owner address must be provided"); + } - #region ERC1155 + return string.IsNullOrEmpty(operatorAddress) + ? throw new ArgumentException("Operator address must be provided") + : await ThirdwebContract.Read(contract, "isApprovedForAll", ownerAddress, operatorAddress); + } - /// - /// Check the balance of a specific token for a specific address. - /// - /// The contract to interact with. - /// The address of the owner whose balance is to be checked. - /// The ID of the token. - /// A task representing the asynchronous operation, with a BigInteger result containing the balance. - /// Thrown when the contract is null. - /// Thrown when the owner address is null or empty. - /// Thrown when the token ID is less than 0. - public static async Task ERC1155_BalanceOf(this ThirdwebContract contract, string ownerAddress, BigInteger tokenId) + /// + /// Set or unset an operator for an owner. + /// + /// The contract to interact with. + /// The wallet to use for the transaction. + /// The address of the operator. + /// A boolean indicating whether to set or unset the operator. + /// A task representing the asynchronous operation, with a ThirdwebTransactionReceipt result. + /// Thrown when the contract or wallet is null. + /// Thrown when the operator address is null or empty. + public static async Task ERC721_SetApprovalForAll(this ThirdwebContract contract, IThirdwebWallet wallet, string operatorAddress, bool approved) + { + if (contract == null) { - if (contract == null) - { - throw new ArgumentNullException(nameof(contract)); - } + throw new ArgumentNullException(nameof(contract)); + } - if (string.IsNullOrEmpty(ownerAddress)) - { - throw new ArgumentException("Owner address must be provided"); - } + if (wallet == null) + { + throw new ArgumentNullException(nameof(wallet)); + } - if (tokenId < 0) - { - throw new ArgumentOutOfRangeException(nameof(tokenId), "Token ID must be equal or greater than 0"); - } + return string.IsNullOrEmpty(operatorAddress) + ? throw new ArgumentException("Operator address must be provided") + : await ThirdwebContract.Write(wallet, contract, "setApprovalForAll", 0, operatorAddress, approved); + } - return await ThirdwebContract.Read(contract, "balanceOf", ownerAddress, tokenId); + /// + /// Transfer a specific token from one address to another. + /// + /// The contract to interact with. + /// The wallet to use for the transaction. + /// The address of the sender. + /// The address of the recipient. + /// The ID of the token. + /// A task representing the asynchronous operation, with a ThirdwebTransactionReceipt result. + /// Thrown when the contract or wallet is null. + /// Thrown when the sender address or recipient address is null or empty. + public static async Task ERC721_TransferFrom(this ThirdwebContract contract, IThirdwebWallet wallet, string fromAddress, string toAddress, BigInteger tokenId) + { + if (contract == null) + { + throw new ArgumentNullException(nameof(contract)); } - /// - /// Check the balance of multiple tokens for multiple addresses. - /// - /// The contract to interact with. - /// The array of owner addresses. - /// The array of token IDs. - /// A task representing the asynchronous operation, with a list of BigInteger results containing the balances. - /// Thrown when the contract is null. - /// Thrown when the owner addresses or token IDs are null. - public static async Task> ERC1155_BalanceOfBatch(this ThirdwebContract contract, string[] ownerAddresses, BigInteger[] tokenIds) + if (wallet == null) { - if (contract == null) - { - throw new ArgumentNullException(nameof(contract)); - } + throw new ArgumentNullException(nameof(wallet)); + } - if (ownerAddresses == null || tokenIds == null) - { - throw new ArgumentException("Owner addresses and token IDs must be provided"); - } + if (string.IsNullOrEmpty(fromAddress)) + { + throw new ArgumentException("Sender address must be provided"); + } - return await ThirdwebContract.Read>(contract, "balanceOfBatch", ownerAddresses, tokenIds); + return string.IsNullOrEmpty(toAddress) + ? throw new ArgumentException("Recipient address must be provided") + : await ThirdwebContract.Write(wallet, contract, "transferFrom", 0, fromAddress, toAddress, tokenId); + } + + /// + /// Safely transfer a specific token from one address to another. + /// + /// The contract to interact with. + /// The wallet to use for the transaction. + /// The address of the sender. + /// The address of the recipient. + /// The ID of the token. + /// A task representing the asynchronous operation, with a ThirdwebTransactionReceipt result. + /// Thrown when the contract or wallet is null. + /// Thrown when the sender address or recipient address is null or empty. + public static async Task ERC721_SafeTransferFrom(this ThirdwebContract contract, IThirdwebWallet wallet, string fromAddress, string toAddress, BigInteger tokenId) + { + if (contract == null) + { + throw new ArgumentNullException(nameof(contract)); } - /// - /// Approve a specific address to transfer specific tokens. - /// - /// The contract to interact with. - /// The wallet to use for the transaction. - /// The address of the operator. - /// A boolean indicating whether to approve or revoke approval. - /// A task representing the asynchronous operation, with a ThirdwebTransactionReceipt result. - /// Thrown when the contract or wallet is null. - /// Thrown when the operator address is null or empty. - public static async Task ERC1155_SetApprovalForAll(this ThirdwebContract contract, IThirdwebWallet wallet, string operatorAddress, bool approved) + if (wallet == null) { - if (contract == null) - { - throw new ArgumentNullException(nameof(contract)); - } + throw new ArgumentNullException(nameof(wallet)); + } - if (wallet == null) - { - throw new ArgumentNullException(nameof(wallet)); - } + if (string.IsNullOrEmpty(fromAddress)) + { + throw new ArgumentException("Sender address must be provided"); + } - if (string.IsNullOrEmpty(operatorAddress)) - { - throw new ArgumentException("Operator address must be provided"); - } + return string.IsNullOrEmpty(toAddress) + ? throw new ArgumentException("Recipient address must be provided") + : await ThirdwebContract.Write(wallet, contract, "safeTransferFrom", 0, fromAddress, toAddress, tokenId); + } - return await ThirdwebContract.Write(wallet, contract, "setApprovalForAll", 0, operatorAddress, approved); + #endregion + + #region ERC1155 + + /// + /// Check the balance of a specific token for a specific address. + /// + /// The contract to interact with. + /// The address of the owner whose balance is to be checked. + /// The ID of the token. + /// A task representing the asynchronous operation, with a BigInteger result containing the balance. + /// Thrown when the contract is null. + /// Thrown when the owner address is null or empty. + /// Thrown when the token ID is less than 0. + public static async Task ERC1155_BalanceOf(this ThirdwebContract contract, string ownerAddress, BigInteger tokenId) + { + if (contract == null) + { + throw new ArgumentNullException(nameof(contract)); } - /// - /// Check if an address is approved to transfer specific tokens. - /// - /// The contract to interact with. - /// The address of the owner. - /// The address of the operator. - /// A task representing the asynchronous operation, with a boolean result indicating if the operator is approved for the owner. - /// Thrown when the contract is null. - /// Thrown when the owner address or operator address is null or empty. - public static async Task ERC1155_IsApprovedForAll(this ThirdwebContract contract, string ownerAddress, string operatorAddress) + if (string.IsNullOrEmpty(ownerAddress)) { - if (contract == null) - { - throw new ArgumentNullException(nameof(contract)); - } + throw new ArgumentException("Owner address must be provided"); + } - if (string.IsNullOrEmpty(ownerAddress)) - { - throw new ArgumentException("Owner address must be provided"); - } + return tokenId < 0 + ? throw new ArgumentOutOfRangeException(nameof(tokenId), "Token ID must be equal or greater than 0") + : await ThirdwebContract.Read(contract, "balanceOf", ownerAddress, tokenId); + } - if (string.IsNullOrEmpty(operatorAddress)) - { - throw new ArgumentException("Operator address must be provided"); - } + /// + /// Check the balance of multiple tokens for multiple addresses. + /// + /// The contract to interact with. + /// The array of owner addresses. + /// The array of token IDs. + /// A task representing the asynchronous operation, with a list of BigInteger results containing the balances. + /// Thrown when the contract is null. + /// Thrown when the owner addresses or token IDs are null. + public static async Task> ERC1155_BalanceOfBatch(this ThirdwebContract contract, string[] ownerAddresses, BigInteger[] tokenIds) + { + if (contract == null) + { + throw new ArgumentNullException(nameof(contract)); + } - return await ThirdwebContract.Read(contract, "isApprovedForAll", ownerAddress, operatorAddress); - } - - /// - /// Transfer specific tokens from one address to another. - /// - /// The contract to interact with. - /// The wallet to use for the transaction. - /// The address of the sender. - /// The address of the recipient. - /// The ID of the token. - /// The amount of tokens to transfer. - /// Additional data with no specified format. - /// A task representing the asynchronous operation, with a ThirdwebTransactionReceipt result. - /// Thrown when the contract or wallet is null. - /// Thrown when the sender address or recipient address is null or empty. - /// Thrown when the token ID is less than 0. - public static async Task ERC1155_SafeTransferFrom( - this ThirdwebContract contract, - IThirdwebWallet wallet, - string fromAddress, - string toAddress, - BigInteger tokenId, - BigInteger amount, - byte[] data - ) - { - if (contract == null) - { - throw new ArgumentNullException(nameof(contract)); - } + if (ownerAddresses == null || tokenIds == null) + { + throw new ArgumentException("Owner addresses and token IDs must be provided"); + } - if (wallet == null) - { - throw new ArgumentNullException(nameof(wallet)); - } + if (ownerAddresses.Length != tokenIds.Length) + { + throw new ArgumentException("Owner addresses and token IDs must have the same length"); + } - if (string.IsNullOrEmpty(fromAddress)) - { - throw new ArgumentException("Sender address must be provided"); - } + return await ThirdwebContract.Read>(contract, "balanceOfBatch", ownerAddresses, tokenIds); + } - if (string.IsNullOrEmpty(toAddress)) - { - throw new ArgumentException("Recipient address must be provided"); - } + /// + /// Approve a specific address to transfer specific tokens. + /// + /// The contract to interact with. + /// The wallet to use for the transaction. + /// The address of the operator. + /// A boolean indicating whether to approve or revoke approval. + /// A task representing the asynchronous operation, with a ThirdwebTransactionReceipt result. + /// Thrown when the contract or wallet is null. + /// Thrown when the operator address is null or empty. + public static async Task ERC1155_SetApprovalForAll(this ThirdwebContract contract, IThirdwebWallet wallet, string operatorAddress, bool approved) + { + if (contract == null) + { + throw new ArgumentNullException(nameof(contract)); + } - if (tokenId < 0) - { - throw new ArgumentOutOfRangeException(nameof(tokenId), "Token ID must be equal or greater than 0"); - } + if (wallet == null) + { + throw new ArgumentNullException(nameof(wallet)); + } - return await ThirdwebContract.Write(wallet, contract, "safeTransferFrom", 0, fromAddress, toAddress, tokenId, amount, data); - } - - /// - /// Transfer multiple tokens from one address to another. - /// - /// The contract to interact with. - /// The wallet to use for the transaction. - /// The address of the sender. - /// The address of the recipient. - /// The array of token IDs to transfer. - /// The array of amounts for each token ID. - /// Additional data with no specified format. - /// A task representing the asynchronous operation, with a ThirdwebTransactionReceipt result. - /// Thrown when the contract or wallet is null. - /// Thrown when the sender address, recipient address, token IDs, or amounts are null or empty. - public static async Task ERC1155_SafeBatchTransferFrom( - this ThirdwebContract contract, - IThirdwebWallet wallet, - string fromAddress, - string toAddress, - BigInteger[] tokenIds, - BigInteger[] amounts, - byte[] data - ) - { - if (contract == null) - { - throw new ArgumentNullException(nameof(contract)); - } + return string.IsNullOrEmpty(operatorAddress) + ? throw new ArgumentException("Operator address must be provided") + : await ThirdwebContract.Write(wallet, contract, "setApprovalForAll", 0, operatorAddress, approved); + } - if (wallet == null) - { - throw new ArgumentNullException(nameof(wallet)); - } + /// + /// Check if an address is approved to transfer specific tokens. + /// + /// The contract to interact with. + /// The address of the owner. + /// The address of the operator. + /// A task representing the asynchronous operation, with a boolean result indicating if the operator is approved for the owner. + /// Thrown when the contract is null. + /// Thrown when the owner address or operator address is null or empty. + public static async Task ERC1155_IsApprovedForAll(this ThirdwebContract contract, string ownerAddress, string operatorAddress) + { + if (contract == null) + { + throw new ArgumentNullException(nameof(contract)); + } - if (string.IsNullOrEmpty(fromAddress)) - { - throw new ArgumentException("Sender address must be provided"); - } + if (string.IsNullOrEmpty(ownerAddress)) + { + throw new ArgumentException("Owner address must be provided"); + } - if (string.IsNullOrEmpty(toAddress)) - { - throw new ArgumentException("Recipient address must be provided"); - } + return string.IsNullOrEmpty(operatorAddress) + ? throw new ArgumentException("Operator address must be provided") + : await ThirdwebContract.Read(contract, "isApprovedForAll", ownerAddress, operatorAddress); + } - if (tokenIds == null || amounts == null) - { - throw new ArgumentException("Token IDs and amounts must be provided"); - } + /// + /// Transfer specific tokens from one address to another. + /// + /// The contract to interact with. + /// The wallet to use for the transaction. + /// The address of the sender. + /// The address of the recipient. + /// The ID of the token. + /// The amount of tokens to transfer. + /// Additional data with no specified format. + /// A task representing the asynchronous operation, with a ThirdwebTransactionReceipt result. + /// Thrown when the contract or wallet is null. + /// Thrown when the sender address or recipient address is null or empty. + /// Thrown when the token ID is less than 0. + public static async Task ERC1155_SafeTransferFrom( + this ThirdwebContract contract, + IThirdwebWallet wallet, + string fromAddress, + string toAddress, + BigInteger tokenId, + BigInteger amount, + byte[] data = null + ) + { + if (contract == null) + { + throw new ArgumentNullException(nameof(contract)); + } + + if (wallet == null) + { + throw new ArgumentNullException(nameof(wallet)); + } - return await ThirdwebContract.Write(wallet, contract, "safeBatchTransferFrom", 0, fromAddress, toAddress, tokenIds, amounts, data); + if (string.IsNullOrEmpty(fromAddress)) + { + throw new ArgumentException("Sender address must be provided"); } - /// - /// Get the URI for a specific token. - /// - /// The contract to interact with. - /// The ID of the token. - /// A task representing the asynchronous operation, with a string result containing the URI. - /// Thrown when the contract is null. - /// Thrown when the token ID is less than 0. - public static async Task ERC1155_URI(this ThirdwebContract contract, BigInteger tokenId) + if (string.IsNullOrEmpty(toAddress)) { - if (contract == null) - { - throw new ArgumentNullException(nameof(contract)); - } + throw new ArgumentException("Recipient address must be provided"); + } - if (tokenId < 0) - { - throw new ArgumentOutOfRangeException(nameof(tokenId), "Token ID must be equal or greater than 0"); - } + return tokenId < 0 + ? throw new ArgumentOutOfRangeException(nameof(tokenId), "Token ID must be equal or greater than 0") + : await ThirdwebContract.Write(wallet, contract, "safeTransferFrom", 0, fromAddress, toAddress, tokenId, amount, data ?? Array.Empty()); + } - return await ThirdwebContract.Read(contract, "uri", tokenId); + /// + /// Transfer multiple tokens from one address to another. + /// + /// The contract to interact with. + /// The wallet to use for the transaction. + /// The address of the sender. + /// The address of the recipient. + /// The array of token IDs to transfer. + /// The array of amounts for each token ID. + /// Additional data with no specified format. + /// A task representing the asynchronous operation, with a ThirdwebTransactionReceipt result. + /// Thrown when the contract or wallet is null. + /// Thrown when the sender address, recipient address, token IDs, or amounts are null or empty. + public static async Task ERC1155_SafeBatchTransferFrom( + this ThirdwebContract contract, + IThirdwebWallet wallet, + string fromAddress, + string toAddress, + BigInteger[] tokenIds, + BigInteger[] amounts, + byte[] data = null + ) + { + if (contract == null) + { + throw new ArgumentNullException(nameof(contract)); } - /// - /// Get the total supply of a specific token. - /// - /// The contract to interact with. - /// The ID of the token. - /// A task representing the asynchronous operation, with a BigInteger result containing the total supply. - /// Thrown when the contract is null. - /// Thrown when the token ID is less than 0. - public static async Task ERC1155_TotalSupply(this ThirdwebContract contract, BigInteger tokenId) + if (wallet == null) { - if (contract == null) - { - throw new ArgumentNullException(nameof(contract)); - } + throw new ArgumentNullException(nameof(wallet)); + } - if (tokenId < 0) - { - throw new ArgumentOutOfRangeException(nameof(tokenId), "Token ID must be equal or greater than 0"); - } + if (string.IsNullOrEmpty(fromAddress)) + { + throw new ArgumentException("Sender address must be provided"); + } - return await ThirdwebContract.Read(contract, "totalSupply", tokenId); + if (string.IsNullOrEmpty(toAddress)) + { + throw new ArgumentException("Recipient address must be provided"); } - /// - /// Get the total supply of tokens. - /// - /// The contract to interact with. - /// A task representing the asynchronous operation, with a BigInteger result containing the total supply. - /// Thrown when the contract is null. - public static async Task ERC1155_TotalSupply(this ThirdwebContract contract) + return tokenIds == null || amounts == null + ? throw new ArgumentException("Token IDs and amounts must be provided") + : await ThirdwebContract.Write(wallet, contract, "safeBatchTransferFrom", 0, fromAddress, toAddress, tokenIds, amounts, data ?? Array.Empty()); + } + + /// + /// Get the URI for a specific token. + /// + /// The contract to interact with. + /// The ID of the token. + /// A task representing the asynchronous operation, with a string result containing the URI. + /// Thrown when the contract is null. + /// Thrown when the token ID is less than 0. + public static async Task ERC1155_URI(this ThirdwebContract contract, BigInteger tokenId) + { + if (contract == null) { - if (contract == null) - { - throw new ArgumentNullException(nameof(contract)); - } + throw new ArgumentNullException(nameof(contract)); + } - try - { - return await ThirdwebContract.Read(contract, "nextTokenIdToMint"); - } - catch (Exception) - { - return await ThirdwebContract.Read(contract, "totalSupply"); - } + return tokenId < 0 ? throw new ArgumentOutOfRangeException(nameof(tokenId), "Token ID must be equal or greater than 0") : await ThirdwebContract.Read(contract, "uri", tokenId); + } + + /// + /// Get the total supply of a specific token. + /// + /// The contract to interact with. + /// The ID of the token. + /// A task representing the asynchronous operation, with a BigInteger result containing the total supply. + /// Thrown when the contract is null. + /// Thrown when the token ID is less than 0. + public static async Task ERC1155_TotalSupply(this ThirdwebContract contract, BigInteger tokenId) + { + if (contract == null) + { + throw new ArgumentNullException(nameof(contract)); } - #endregion + return tokenId < 0 + ? throw new ArgumentOutOfRangeException(nameof(tokenId), "Token ID must be equal or greater than 0") + : await ThirdwebContract.Read(contract, "totalSupply", tokenId); + } - #region NFT + /// + /// Get the total supply of tokens. + /// + /// The contract to interact with. + /// A task representing the asynchronous operation, with a BigInteger result containing the total supply. + /// Thrown when the contract is null. + public static async Task ERC1155_TotalSupply(this ThirdwebContract contract) + { + if (contract == null) + { + throw new ArgumentNullException(nameof(contract)); + } - /// - /// Get the details of a specific ERC721 token. - /// - /// The contract to interact with. - /// The ID of the token. - /// A task representing the asynchronous operation, with an NFT result containing the token details. - /// Thrown when the contract is null. - public static async Task ERC721_GetNFT(this ThirdwebContract contract, BigInteger tokenId) + try { - if (contract == null) - { - throw new ArgumentNullException(nameof(contract)); - } + return await ThirdwebContract.Read(contract, "nextTokenIdToMint"); + } + catch (Exception) + { + return await ThirdwebContract.Read(contract, "totalSupply"); + } + } - var uri = await contract.ERC721_TokenURI(tokenId).ConfigureAwait(false); - var metadata = await ThirdwebStorage.Download(contract.Client, uri).ConfigureAwait(false); - metadata.Id = tokenId.ToString(); + #endregion + + #region NFT - var owner = Constants.ADDRESS_ZERO; + /// + /// Get the details of a specific ERC721 token. + /// + /// The contract to interact with. + /// The ID of the token. + /// A boolean indicating whether to fill the owner details. Defaults to true. + /// A task representing the asynchronous operation, with an NFT result containing the token details. + /// Thrown when the contract is null. + /// Thrown when the token ID is less than 0. + public static async Task ERC721_GetNFT(this ThirdwebContract contract, BigInteger tokenId, bool fillOwner = true) + { + if (contract == null) + { + throw new ArgumentNullException(nameof(contract)); + } + + if (tokenId < 0) + { + throw new ArgumentOutOfRangeException(nameof(tokenId), "Token ID must be equal or greater than 0"); + } + + var nft = new NFT + { + Owner = Constants.ADDRESS_ZERO, + Type = NFTType.ERC721, + Supply = 1, + QuantityOwned = 1, + }; + + if (fillOwner) + { try { - owner = await contract.ERC721_OwnerOf(tokenId).ConfigureAwait(false); + nft.Owner = await contract.ERC721_OwnerOf(tokenId).ConfigureAwait(false); } - catch (Exception) + catch { - owner = Constants.ADDRESS_ZERO; + nft.Owner = Constants.ADDRESS_ZERO; } + } - return new NFT - { - Metadata = metadata, - Owner = owner, - Type = NFTType.ERC721, - Supply = 1, - }; - } - - /// - /// Get a list of all ERC721 tokens within a specified range. - /// - /// The contract to interact with. - /// The starting token ID (inclusive). Defaults to 0 if not specified. - /// The ending token ID (exclusive). Defaults to the total supply if not specified. - /// A task representing the asynchronous operation, with a list of NFT results containing the token details. - /// Thrown when the contract is null. - public static async Task> ERC721_GetAllNFTs(this ThirdwebContract contract, BigInteger? startTokenIdIncluded = null, BigInteger? endTokenIdExcluded = null) - { - if (contract == null) - { - throw new ArgumentNullException(nameof(contract)); - } +#pragma warning disable IDE0059 // Unnecessary assignment of a value + var nftMetadata = new NFTMetadata(); +#pragma warning restore IDE0059 // Unnecessary assignment of a value + try + { + var uri = await contract.ERC721_TokenURI(tokenId).ConfigureAwait(false); + nftMetadata = await ThirdwebStorage.Download(contract.Client, uri).ConfigureAwait(false); + } + catch (Exception e) + { + nftMetadata.Description = $"Metadata not found: {e.Message}"; + } + finally + { + nftMetadata.Id = tokenId.ToString(); + } - if (startTokenIdIncluded == null) - { - startTokenIdIncluded = 0; - } + return nft with + { + Metadata = nftMetadata, + }; + } - if (endTokenIdExcluded == null) - { - var totalSupply = await contract.ERC721_TotalSupply().ConfigureAwait(false); - endTokenIdExcluded = totalSupply; - } + /// + /// Get a list of all ERC721 tokens within a specified range. + /// + /// The contract to interact with. + /// The starting token ID (inclusive). Defaults to 0 if not specified. + /// The number of tokens to retrieve. Defaults to 100 if not specified. + /// A boolean indicating whether to fill the owner details. Defaults to true. + /// A task representing the asynchronous operation, with a list of NFT results containing the token details. + /// Thrown when the contract is null. + public static async Task> ERC721_GetAllNFTs(this ThirdwebContract contract, int startTokenId = 0, int count = 100, bool fillOwner = true) + { + if (contract == null) + { + throw new ArgumentNullException(nameof(contract)); + } - var nftTasks = new List>(); - for (var i = startTokenIdIncluded.Value; i < endTokenIdExcluded.Value; i++) - { - nftTasks.Add(contract.ERC721_GetNFT(i)); - } + var totalSupply = await contract.ERC721_TotalSupply().ConfigureAwait(false); + count = Math.Min(count, (int)(totalSupply - startTokenId)); - var allNfts = await Task.WhenAll(nftTasks).ConfigureAwait(false); - return allNfts.ToList(); + var nftTasks = new List>(); + for (var i = startTokenId; i < startTokenId + count; i++) + { + nftTasks.Add(contract.ERC721_GetNFT(i, fillOwner)); } - /// - /// Get a list of ERC721 tokens owned by a specific address. - /// - /// The contract to interact with. - /// The address of the owner. - /// A task representing the asynchronous operation, with a list of NFT results containing the token details. - /// Thrown when the contract is null. - /// Thrown when the owner address is null or empty. - public static async Task> ERC721_GetOwnedNFTs(this ThirdwebContract contract, string owner) + var allNfts = await Task.WhenAll(nftTasks).ConfigureAwait(false); + return allNfts.ToList(); + } + + /// + /// Get a list of ERC721 tokens owned by a specific address. + /// + /// The contract to interact with. + /// The address of the owner. + /// The starting token ID (inclusive). Defaults to 0 if not specified. + /// The number of tokens to retrieve. Defaults to 100 if not specified. + /// A task representing the asynchronous operation, with a list of NFT results containing the token details. + /// ERC721AQueryable and ERC721Enumerable are supported. + /// Thrown when the contract is null. + /// Thrown when the owner address is null or empty. + public static async Task> ERC721_GetOwnedNFTs(this ThirdwebContract contract, string owner, int startTokenId = 0, int count = 100) + { + if (contract == null) { - if (contract == null) - { - throw new ArgumentNullException(nameof(contract)); - } + throw new ArgumentNullException(nameof(contract)); + } - if (string.IsNullOrEmpty(owner)) + if (string.IsNullOrEmpty(owner)) + { + throw new ArgumentException("Owner must be provided"); + } + + var totalSupply = await contract.ERC721_TotalSupply().ConfigureAwait(false); + count = Math.Min(count, (int)(totalSupply - startTokenId)); + + // ERC721AQueryable + try + { + var tokensOfOwnerIn = await contract.ERC721A_TokensOfOwnerIn(owner, startTokenId, startTokenId + count).ConfigureAwait(false); + var ownedNftTasks = new List>(); + foreach (var tokenId in tokensOfOwnerIn) { - throw new ArgumentException("Owner must be provided"); + ownedNftTasks.Add(contract.ERC721_GetNFT(tokenId)); } - + var ownedNfts = await Task.WhenAll(ownedNftTasks).ConfigureAwait(false); + return ownedNfts.ToList(); + } + catch + { + // ERC721Enumerable try { var balanceOfOwner = await contract.ERC721_BalanceOf(owner).ConfigureAwait(false); @@ -1157,14 +1370,17 @@ public static async Task> ERC721_GetOwnedNFTs(this ThirdwebContract co for (var i = 0; i < balanceOfOwner; i++) { var tokenOfOwnerByIndex = await contract.ERC721_TokenOfOwnerByIndex(owner, i).ConfigureAwait(false); - ownedNftTasks.Add(contract.ERC721_GetNFT(tokenOfOwnerByIndex)); + if (tokenOfOwnerByIndex >= startTokenId && tokenOfOwnerByIndex < startTokenId + count) + { + ownedNftTasks.Add(contract.ERC721_GetNFT(tokenOfOwnerByIndex)); + } } var ownedNfts = await Task.WhenAll(ownedNftTasks).ConfigureAwait(false); return ownedNfts.ToList(); } catch (Exception) { - var allNfts = await contract.ERC721_GetAllNFTs().ConfigureAwait(false); + var allNfts = await contract.ERC721_GetAllNFTs(startTokenId, count).ConfigureAwait(false); var ownedNfts = new List(); foreach (var nft in allNfts) { @@ -1176,26 +1392,46 @@ public static async Task> ERC721_GetOwnedNFTs(this ThirdwebContract co return ownedNfts.ToList(); } } + } - /// - /// Get the details of a specific ERC1155 token. - /// - /// The contract to interact with. - /// The ID of the token. - /// A task representing the asynchronous operation, with an NFT result containing the token details. - /// Thrown when the contract is null. - public static async Task ERC1155_GetNFT(this ThirdwebContract contract, BigInteger tokenId) + /// + /// Get the details of a specific ERC1155 token. + /// + /// The contract to interact with. + /// The ID of the token. + /// A boolean indicating whether to fill the supply. Defaults to true if not specified. + /// A task representing the asynchronous operation, with an NFT result containing the token details. + /// Thrown when the contract is null. + /// Thrown when the token ID is less than 0. + public static async Task ERC1155_GetNFT(this ThirdwebContract contract, BigInteger tokenId, bool fillSupply = true) + { + if (contract == null) { - if (contract == null) - { - throw new ArgumentNullException(nameof(contract)); - } + throw new ArgumentNullException(nameof(contract)); + } + + if (tokenId < 0) + { + throw new ArgumentOutOfRangeException(nameof(tokenId), "Token ID must be equal or greater than 0"); + } + + var uri = await contract.ERC1155_URI(tokenId).ConfigureAwait(false); + NFTMetadata metadata; + try + { + metadata = await ThirdwebStorage.Download(contract.Client, uri).ConfigureAwait(false); + } + catch (Exception e) + { +#pragma warning disable IDE0059 // Unnecessary assignment of a value + metadata = new NFTMetadata { Description = e.Message }; +#pragma warning restore IDE0059 // Unnecessary assignment of a value + } + metadata.Id = tokenId.ToString(); - var uri = await contract.ERC1155_URI(tokenId).ConfigureAwait(false); - var metadata = await ThirdwebStorage.Download(contract.Client, uri).ConfigureAwait(false); - metadata.Id = tokenId.ToString(); - var owner = string.Empty; - var supply = BigInteger.MinusOne; + var supply = BigInteger.MinusOne; + if (fillSupply) + { try { supply = await contract.ERC1155_TotalSupply(tokenId).ConfigureAwait(false); @@ -1204,1149 +1440,1305 @@ public static async Task ERC1155_GetNFT(this ThirdwebContract contract, Big { supply = BigInteger.MinusOne; } + } - return new NFT - { - Metadata = metadata, - Owner = owner, - Type = NFTType.ERC1155, - Supply = supply, - }; - } - - /// - /// Get a list of all ERC1155 tokens within a specified range. - /// - /// The contract to interact with. - /// The starting token ID (inclusive). Defaults to 0 if not specified. - /// The ending token ID (exclusive). Defaults to the total supply if not specified. - /// A task representing the asynchronous operation, with a list of NFT results containing the token details. - /// Thrown when the contract is null. - public static async Task> ERC1155_GetAllNFTs(this ThirdwebContract contract, BigInteger? startTokenIdIncluded = null, BigInteger? endTokenIdExcluded = null) - { - if (contract == null) - { - throw new ArgumentNullException(nameof(contract)); - } + return new NFT + { + Metadata = metadata, + Owner = "", + Type = NFTType.ERC1155, + Supply = supply, + }; + } - if (startTokenIdIncluded == null) - { - startTokenIdIncluded = 0; - } + /// + /// Get a list of all ERC1155 tokens within a specified range. + /// + /// The contract to interact with. + /// The starting token ID (inclusive). Defaults to 0 if not specified. + /// The number of tokens to retrieve. Defaults to the 100 if not specified. + /// A boolean indicating whether to fill the supply. Defaults to true if not specified. + /// A task representing the asynchronous operation, with a list of NFT results containing the token details. + /// Thrown when the contract is null. + public static async Task> ERC1155_GetAllNFTs(this ThirdwebContract contract, int startTokenId = 0, int count = 100, bool fillSupply = true) + { + if (contract == null) + { + throw new ArgumentNullException(nameof(contract)); + } - if (endTokenIdExcluded == null) - { - var totalSupply = await contract.ERC1155_TotalSupply().ConfigureAwait(false); - endTokenIdExcluded = totalSupply; - } + BigInteger totalCount; + try + { + // Not part of IERC1155 so we fallback just in case + totalCount = await contract.ERC1155_TotalSupply().ConfigureAwait(false); + } + catch + { + totalCount = int.MaxValue; + } + count = Math.Min(count, (int)(totalCount - startTokenId)); - var nftTasks = new List>(); - for (var i = startTokenIdIncluded.Value; i < endTokenIdExcluded.Value; i++) - { - nftTasks.Add(contract.ERC1155_GetNFT(i)); - } + var nftTasks = new List>(); + for (var i = startTokenId; i < startTokenId + count; i++) + { + nftTasks.Add(contract.ERC1155_GetNFT(i, fillSupply)); + } + + var allNfts = await Task.WhenAll(nftTasks).ConfigureAwait(false); + return allNfts.ToList(); + } - var allNfts = await Task.WhenAll(nftTasks).ConfigureAwait(false); - return allNfts.ToList(); + /// + /// Get a list of ERC1155 tokens owned by a specific address. + /// + /// The contract to interact with. + /// The address of the owner. + /// The starting token ID (inclusive). Defaults to 0 if not specified. + /// The number of tokens to retrieve. Defaults to 100 if not specified. + /// A task representing the asynchronous operation, with a list of NFT results containing the token details. + /// Thrown when the contract is null. + /// Thrown when the owner address is null or empty. + public static async Task> ERC1155_GetOwnedNFTs(this ThirdwebContract contract, string owner, int startTokenId = 0, int count = 100) + { + if (contract == null) + { + throw new ArgumentNullException(nameof(contract)); } - /// - /// Get a list of ERC1155 tokens owned by a specific address. - /// - /// The contract to interact with. - /// The address of the owner. - /// A task representing the asynchronous operation, with a list of NFT results containing the token details. - /// Thrown when the contract is null. - /// Thrown when the owner address is null or empty. - public static async Task> ERC1155_GetOwnedNFTs(this ThirdwebContract contract, string owner) + if (string.IsNullOrEmpty(owner)) { - if (contract == null) - { - throw new ArgumentNullException(nameof(contract)); - } + throw new ArgumentException("Owner must be provided"); + } - if (string.IsNullOrEmpty(owner)) - { - throw new ArgumentException("Owner must be provided"); - } + BigInteger totalSupply; + try + { + // Not part of IERC1155 so we fallback just in case + totalSupply = await contract.ERC1155_TotalSupply().ConfigureAwait(false); + } + catch + { + totalSupply = int.MaxValue; + } + count = Math.Min(count, (int)(totalSupply - startTokenId)); + + var ownerArray = new List(); + var tokenIds = new List(); + + for (var i = startTokenId; i < startTokenId + count; i++) + { + ownerArray.Add(owner); + tokenIds.Add(i); + } - var totalSupply = await contract.ERC1155_TotalSupply().ConfigureAwait(false); + var balanceOfBatch = await contract.ERC1155_BalanceOfBatch(ownerArray.ToArray(), tokenIds.ToArray()).ConfigureAwait(false); - var nfts = new List(); - for (var i = 0; i < totalSupply; i++) + var ownedNftTasks = new List>(); + var ownedBalances = new List(); + for (var i = 0; i < balanceOfBatch.Count; i++) + { + if (balanceOfBatch[i] > 0) { - var balanceOfOwner = await contract.ERC1155_BalanceOf(owner, i).ConfigureAwait(false); - if (balanceOfOwner > 0) - { - var nft = await contract.ERC1155_GetNFT(i).ConfigureAwait(false); - nft.QuantityOwned = balanceOfOwner; - nfts.Add(nft); - } + ownedNftTasks.Add(contract.ERC1155_GetNFT(tokenIds[i])); + ownedBalances.Add(balanceOfBatch[i]); } + } - return nfts; + var ownerNfts = await Task.WhenAll(ownedNftTasks).ConfigureAwait(false); + for (var i = 0; i < ownerNfts.Length; i++) + { + ownerNfts[i].QuantityOwned = ownedBalances[i]; } + return ownerNfts.ToList(); + } - #endregion + #endregion + + #region DropERC20 + + /// + /// Claim a specific amount of ERC20 tokens for a receiver. + /// + /// The contract to interact with. + /// The wallet to use for the transaction. + /// The address of the receiver. + /// The amount of tokens to claim. + /// A task representing the asynchronous operation, with a ThirdwebTransactionReceipt result. + /// Thrown when the contract or wallet is null. + /// Thrown when the receiver address or amount is null or empty. + public static async Task DropERC20_Claim(this ThirdwebContract contract, IThirdwebWallet wallet, string receiverAddress, string amount) + { + if (contract == null) + { + throw new ArgumentNullException(nameof(contract)); + } - #region DropERC20 + if (wallet == null) + { + throw new ArgumentNullException(nameof(wallet)); + } - /// - /// Claim a specific amount of ERC20 tokens for a receiver. - /// - /// The contract to interact with. - /// The wallet to use for the transaction. - /// The address of the receiver. - /// The amount of tokens to claim. - /// A task representing the asynchronous operation, with a ThirdwebTransactionReceipt result. - /// Thrown when the contract or wallet is null. - /// Thrown when the receiver address or amount is null or empty. - public static async Task DropERC20_Claim(this ThirdwebContract contract, IThirdwebWallet wallet, string receiverAddress, string amount) + if (string.IsNullOrEmpty(receiverAddress)) { - if (contract == null) - { - throw new ArgumentNullException(nameof(contract)); - } + throw new ArgumentException("Receiver address must be provided"); + } - if (wallet == null) - { - throw new ArgumentNullException(nameof(wallet)); - } + if (string.IsNullOrEmpty(amount)) + { + throw new ArgumentException("Amount must be provided"); + } - if (string.IsNullOrEmpty(receiverAddress)) - { - throw new ArgumentException("Receiver address must be provided"); - } + // TODO: Task.WhenAll - if (string.IsNullOrEmpty(amount)) - { - throw new ArgumentException("Amount must be provided"); - } + var activeClaimCondition = await contract.DropERC20_GetActiveClaimCondition(); - // TODO: Task.WhenAll + var erc20Decimals = await contract.ERC20_Decimals(); - var activeClaimCondition = await contract.DropERC20_GetActiveClaimCondition(); + var rawAmountToClaim = BigInteger.Parse(amount.ToWei()).AdjustDecimals(18, erc20Decimals); - var erc20Decimals = await contract.ERC20_Decimals(); + var isNativeToken = activeClaimCondition.Currency == Constants.NATIVE_TOKEN_ADDRESS; - var rawAmountToClaim = BigInteger.Parse(amount.ToWei()).AdjustDecimals(18, erc20Decimals); + var payableAmount = isNativeToken ? rawAmountToClaim * activeClaimCondition.PricePerToken / BigInteger.Pow(10, 18) : BigInteger.Zero; - var isNativeToken = activeClaimCondition.Currency == Constants.NATIVE_TOKEN_ADDRESS; + // TODO: Merkle + var allowlistProof = new object[] { Array.Empty(), BigInteger.Zero, BigInteger.Zero, Constants.ADDRESS_ZERO }; - var payableAmount = isNativeToken ? rawAmountToClaim * activeClaimCondition.PricePerToken : BigInteger.Zero; + var fnArgs = new object[] + { + receiverAddress, // receiver + rawAmountToClaim, // quantity + activeClaimCondition.Currency, // currency + activeClaimCondition.PricePerToken, // pricePerToken + allowlistProof, // allowlistProof + Array.Empty(), // data + }; - // TODO: Merkle - var allowlistProof = new object[] { new byte[] { }, BigInteger.Zero, BigInteger.Zero, Constants.ADDRESS_ZERO }; + return await ThirdwebContract.Write(wallet, contract, "claim", payableAmount, fnArgs); + } - var fnArgs = new object[] - { - receiverAddress, // receiver - rawAmountToClaim, // quantity - activeClaimCondition.Currency, // currency - activeClaimCondition.PricePerToken, // pricePerToken - allowlistProof, // allowlistProof - new byte[] { } // data - }; - - return await ThirdwebContract.Write(wallet, contract, "claim", payableAmount, fnArgs); - } - - /// - /// Get the active claim condition ID for the ERC20 drop. - /// - /// The contract to interact with. - /// A task representing the asynchronous operation, with a BigInteger result containing the active claim condition ID. - /// Thrown when the contract is null. - public static async Task DropERC20_GetActiveClaimConditionId(this ThirdwebContract contract) - { - if (contract == null) - { - throw new ArgumentNullException(nameof(contract)); - } + /// + /// Get the active claim condition ID for the ERC20 drop. + /// + /// The contract to interact with. + /// A task representing the asynchronous operation, with a BigInteger result containing the active claim condition ID. + /// Thrown when the contract is null. + public static async Task DropERC20_GetActiveClaimConditionId(this ThirdwebContract contract) + { + return contract == null ? throw new ArgumentNullException(nameof(contract)) : await ThirdwebContract.Read(contract, "getActiveClaimConditionId"); + } - return await ThirdwebContract.Read(contract, "getActiveClaimConditionId"); + /// + /// Get the claim condition details for a specific claim condition ID. + /// + /// The contract to interact with. + /// The ID of the claim condition. + /// A task representing the asynchronous operation, with a Drop_ClaimCondition result containing the claim condition details. + /// Thrown when the contract is null. + /// Thrown when the claim condition ID is less than 0. + public static async Task DropERC20_GetClaimConditionById(this ThirdwebContract contract, BigInteger claimConditionId) + { + if (contract == null) + { + throw new ArgumentNullException(nameof(contract)); } - /// - /// Get the claim condition details for a specific claim condition ID. - /// - /// The contract to interact with. - /// The ID of the claim condition. - /// A task representing the asynchronous operation, with a Drop_ClaimCondition result containing the claim condition details. - /// Thrown when the contract is null. - /// Thrown when the claim condition ID is less than 0. - public static async Task DropERC20_GetClaimConditionById(this ThirdwebContract contract, BigInteger claimConditionId) + return claimConditionId < 0 + ? throw new ArgumentOutOfRangeException(nameof(claimConditionId), "Claim condition ID must be equal or greater than 0") + : await ThirdwebContract.Read(contract, "getClaimConditionById", claimConditionId); + } + + /// + /// Get the details of the active claim condition for the ERC20 drop. + /// + /// The contract to interact with. + /// A task representing the asynchronous operation, with a Drop_ClaimCondition result containing the active claim condition details. + /// Thrown when the contract is null. + public static async Task DropERC20_GetActiveClaimCondition(this ThirdwebContract contract) + { + if (contract == null) { - if (contract == null) - { - throw new ArgumentNullException(nameof(contract)); - } + throw new ArgumentNullException(nameof(contract)); + } - if (claimConditionId < 0) - { - throw new ArgumentOutOfRangeException(nameof(claimConditionId), "Claim condition ID must be equal or greater than 0"); - } + var activeClaimConditionId = await contract.DropERC20_GetActiveClaimConditionId(); + return await contract.DropERC20_GetClaimConditionById(activeClaimConditionId); + } - return await ThirdwebContract.Read(contract, "getClaimConditionById", claimConditionId); + #endregion + + #region DropERC721 + + /// + /// Burn a specific ERC721 token with a given token ID. + /// + /// The contract to interact with. + /// The wallet to use for the transaction. + /// The ID of the token to burn. + /// A task representing the asynchronous operation, with a ThirdwebTransactionReceipt result. + /// Thrown when the contract or wallet is null. + /// Thrown when the token ID is less than 0. + public static async Task DropER721_Burn(this ThirdwebContract contract, IThirdwebWallet wallet, BigInteger tokenId) + { + if (contract == null) + { + throw new ArgumentNullException(nameof(contract)); } - /// - /// Get the details of the active claim condition for the ERC20 drop. - /// - /// The contract to interact with. - /// A task representing the asynchronous operation, with a Drop_ClaimCondition result containing the active claim condition details. - /// Thrown when the contract is null. - public static async Task DropERC20_GetActiveClaimCondition(this ThirdwebContract contract) + if (wallet == null) { - if (contract == null) - { - throw new ArgumentNullException(nameof(contract)); - } + throw new ArgumentNullException(nameof(wallet)); + } - var activeClaimConditionId = await contract.DropERC20_GetActiveClaimConditionId(); - return await contract.DropERC20_GetClaimConditionById(activeClaimConditionId); + if (tokenId < 0) + { + throw new ArgumentOutOfRangeException(nameof(tokenId), "Token ID must be equal or greater than 0"); } - #endregion + return await ThirdwebContract.Write(wallet, contract, "burn", 0, tokenId); + } - #region DropERC721 + /// + /// Claim a specific quantity of ERC721 tokens for a receiver. + /// + /// The contract to interact with. + /// The wallet to use for the transaction. + /// The address of the receiver. + /// The quantity of tokens to claim. + /// A task representing the asynchronous operation, with a ThirdwebTransactionReceipt result. + /// Thrown when the contract or wallet is null. + /// Thrown when the receiver address is null or empty. + /// Thrown when the quantity is less than or equal to 0. + public static async Task DropERC721_Claim(this ThirdwebContract contract, IThirdwebWallet wallet, string receiverAddress, BigInteger quantity) + { + if (contract == null) + { + throw new ArgumentNullException(nameof(contract)); + } - /// - /// Claim a specific quantity of ERC721 tokens for a receiver. - /// - /// The contract to interact with. - /// The wallet to use for the transaction. - /// The address of the receiver. - /// The quantity of tokens to claim. - /// A task representing the asynchronous operation, with a ThirdwebTransactionReceipt result. - /// Thrown when the contract or wallet is null. - /// Thrown when the receiver address is null or empty. - /// Thrown when the quantity is less than or equal to 0. - public static async Task DropERC721_Claim(this ThirdwebContract contract, IThirdwebWallet wallet, string receiverAddress, BigInteger quantity) + if (wallet == null) { - if (contract == null) - { - throw new ArgumentNullException(nameof(contract)); - } + throw new ArgumentNullException(nameof(wallet)); + } - if (wallet == null) - { - throw new ArgumentNullException(nameof(wallet)); - } + if (string.IsNullOrEmpty(receiverAddress)) + { + throw new ArgumentException("Receiver address must be provided"); + } - if (string.IsNullOrEmpty(receiverAddress)) - { - throw new ArgumentException("Receiver address must be provided"); - } + if (quantity <= 0) + { + throw new ArgumentOutOfRangeException(nameof(quantity), "Quantity must be greater than 0"); + } - if (quantity <= 0) - { - throw new ArgumentOutOfRangeException(nameof(quantity), "Quantity must be greater than 0"); - } + // TODO: Task.WhenAll - // TODO: Task.WhenAll + var activeClaimCondition = await contract.DropERC721_GetActiveClaimCondition(); - var activeClaimCondition = await contract.DropERC721_GetActiveClaimCondition(); + var isNativeToken = activeClaimCondition.Currency == Constants.NATIVE_TOKEN_ADDRESS; - var isNativeToken = activeClaimCondition.Currency == Constants.NATIVE_TOKEN_ADDRESS; + var payableAmount = isNativeToken ? quantity * activeClaimCondition.PricePerToken : BigInteger.Zero; - var payableAmount = isNativeToken ? quantity * activeClaimCondition.PricePerToken : BigInteger.Zero; + // TODO: Merkle + var allowlistProof = new object[] { Array.Empty(), BigInteger.Zero, BigInteger.Zero, Constants.ADDRESS_ZERO }; - // TODO: Merkle - var allowlistProof = new object[] { new byte[] { }, BigInteger.Zero, BigInteger.Zero, Constants.ADDRESS_ZERO }; + var fnArgs = new object[] + { + receiverAddress, // receiver + quantity, // quantity + activeClaimCondition.Currency, // currency + activeClaimCondition.PricePerToken, // pricePerToken + allowlistProof, // allowlistProof + Array.Empty(), // data + }; - var fnArgs = new object[] - { - receiverAddress, // receiver - quantity, // quantity - activeClaimCondition.Currency, // currency - activeClaimCondition.PricePerToken, // pricePerToken - allowlistProof, // allowlistProof - new byte[] { } // data - }; - - return await ThirdwebContract.Write(wallet, contract, "claim", payableAmount, fnArgs); - } - - /// - /// Get the active claim condition ID for the ERC721 drop. - /// - /// The contract to interact with. - /// A task representing the asynchronous operation, with a BigInteger result containing the active claim condition ID. - /// Thrown when the contract is null. - public static async Task DropERC721_GetActiveClaimConditionId(this ThirdwebContract contract) - { - if (contract == null) - { - throw new ArgumentNullException(nameof(contract)); - } + return await ThirdwebContract.Write(wallet, contract, "claim", payableAmount, fnArgs); + } + + /// + /// Get the active claim condition ID for the ERC721 drop. + /// + /// The contract to interact with. + /// A task representing the asynchronous operation, with a BigInteger result containing the active claim condition ID. + /// Thrown when the contract is null. + public static async Task DropERC721_GetActiveClaimConditionId(this ThirdwebContract contract) + { + return contract == null ? throw new ArgumentNullException(nameof(contract)) : await ThirdwebContract.Read(contract, "getActiveClaimConditionId"); + } - return await ThirdwebContract.Read(contract, "getActiveClaimConditionId"); + /// + /// Get the claim condition details for a specific claim condition ID. + /// + /// The contract to interact with. + /// The ID of the claim condition. + /// A task representing the asynchronous operation, with a Drop_ClaimCondition result containing the claim condition details. + /// Thrown when the contract is null. + /// Thrown when the claim condition ID is less than 0. + public static async Task DropERC721_GetClaimConditionById(this ThirdwebContract contract, BigInteger claimConditionId) + { + if (contract == null) + { + throw new ArgumentNullException(nameof(contract)); } - /// - /// Get the claim condition details for a specific claim condition ID. - /// - /// The contract to interact with. - /// The ID of the claim condition. - /// A task representing the asynchronous operation, with a Drop_ClaimCondition result containing the claim condition details. - /// Thrown when the contract is null. - /// Thrown when the claim condition ID is less than 0. - public static async Task DropERC721_GetClaimConditionById(this ThirdwebContract contract, BigInteger claimConditionId) + return claimConditionId < 0 + ? throw new ArgumentOutOfRangeException(nameof(claimConditionId), "Claim condition ID must be equal or greater than 0") + : await ThirdwebContract.Read(contract, "getClaimConditionById", claimConditionId); + } + + /// + /// Get the details of the active claim condition for the ERC721 drop. + /// + /// The contract to interact with. + /// A task representing the asynchronous operation, with a Drop_ClaimCondition result containing the active claim condition details. + /// Thrown when the contract is null. + public static async Task DropERC721_GetActiveClaimCondition(this ThirdwebContract contract) + { + if (contract == null) { - if (contract == null) - { - throw new ArgumentNullException(nameof(contract)); - } + throw new ArgumentNullException(nameof(contract)); + } - if (claimConditionId < 0) - { - throw new ArgumentOutOfRangeException(nameof(claimConditionId), "Claim condition ID must be equal or greater than 0"); - } + var activeClaimConditionId = await contract.DropERC721_GetActiveClaimConditionId(); + return await contract.DropERC20_GetClaimConditionById(activeClaimConditionId); + } - return await ThirdwebContract.Read(contract, "getClaimConditionById", claimConditionId); + #endregion + + #region DropERC1155 + + /// + /// Burn a specific quantity of ERC1155 tokens for a specific account with given token IDs and amounts to burn. + /// + /// The contract to interact with. + /// The wallet to use for the transaction. + /// The address of the account to burn the tokens from. + /// The IDs of the tokens to burn. + /// The amounts of tokens to burn. + /// A task representing the asynchronous operation, with a ThirdwebTransactionReceipt result. + /// Thrown when the contract, wallet, or account is null. + /// Thrown when the account is null or empty, or the token IDs or amounts are null or empty, or the token IDs and amounts have different lengths. + /// Thrown when the token IDs or amounts have a length less than or equal to 0. + /// Thrown when the token IDs and amounts have different lengths. + public static async Task DropERC1155_BurnBatch(this ThirdwebContract contract, IThirdwebWallet wallet, string account, BigInteger[] tokenIds, BigInteger[] amounts) + { + if (contract == null) + { + throw new ArgumentNullException(nameof(contract)); } - /// - /// Get the details of the active claim condition for the ERC721 drop. - /// - /// The contract to interact with. - /// A task representing the asynchronous operation, with a Drop_ClaimCondition result containing the active claim condition details. - /// Thrown when the contract is null. - public static async Task DropERC721_GetActiveClaimCondition(this ThirdwebContract contract) + if (wallet == null) { - if (contract == null) - { - throw new ArgumentNullException(nameof(contract)); - } + throw new ArgumentNullException(nameof(wallet)); + } - var activeClaimConditionId = await contract.DropERC721_GetActiveClaimConditionId(); - return await contract.DropERC20_GetClaimConditionById(activeClaimConditionId); + if (string.IsNullOrEmpty(account)) + { + throw new ArgumentException("Account must be provided"); } - #endregion + if (tokenIds == null || tokenIds.Length == 0) + { + throw new ArgumentException("Token IDs must be provided"); + } - #region DropERC1155 + if (amounts == null || amounts.Length == 0) + { + throw new ArgumentException("Amounts must be provided"); + } - /// - /// Claim a specific quantity of ERC1155 tokens for a receiver. - /// - /// The contract to interact with. - /// The wallet to use for the transaction. - /// The address of the receiver. - /// The ID of the token. - /// The quantity of tokens to claim. - /// A task representing the asynchronous operation, with a ThirdwebTransactionReceipt result. - /// Thrown when the contract or wallet is null. - /// Thrown when the receiver address is null or empty. - /// Thrown when the token ID is less than 0 or the quantity is less than or equal to 0. - public static async Task DropERC1155_Claim(this ThirdwebContract contract, IThirdwebWallet wallet, string receiverAddress, BigInteger tokenId, BigInteger quantity) + if (tokenIds.Length != amounts.Length) { - if (contract == null) - { - throw new ArgumentNullException(nameof(contract)); - } + throw new ArgumentException("Token IDs and amounts must have the same length"); + } - if (wallet == null) - { - throw new ArgumentNullException(nameof(wallet)); - } + return await ThirdwebContract.Write(wallet, contract, "burnBatch", 0, account, tokenIds, amounts); + } - if (string.IsNullOrEmpty(receiverAddress)) - { - throw new ArgumentException("Receiver address must be provided"); - } + /// + /// Claim a specific quantity of ERC1155 tokens for a receiver. + /// + /// The contract to interact with. + /// The wallet to use for the transaction. + /// The address of the receiver. + /// The ID of the token. + /// The quantity of tokens to claim. + /// A task representing the asynchronous operation, with a ThirdwebTransactionReceipt result. + /// Thrown when the contract or wallet is null. + /// Thrown when the receiver address is null or empty. + /// Thrown when the token ID is less than 0 or the quantity is less than or equal to 0. + public static async Task DropERC1155_Claim(this ThirdwebContract contract, IThirdwebWallet wallet, string receiverAddress, BigInteger tokenId, BigInteger quantity) + { + if (contract == null) + { + throw new ArgumentNullException(nameof(contract)); + } - if (tokenId < 0) - { - throw new ArgumentOutOfRangeException(nameof(tokenId), "Token ID must be equal or greater than 0"); - } + if (wallet == null) + { + throw new ArgumentNullException(nameof(wallet)); + } - if (quantity <= 0) - { - throw new ArgumentOutOfRangeException(nameof(quantity), "Quantity must be greater than 0"); - } + if (string.IsNullOrEmpty(receiverAddress)) + { + throw new ArgumentException("Receiver address must be provided"); + } - // TODO: Task.WhenAll + if (tokenId < 0) + { + throw new ArgumentOutOfRangeException(nameof(tokenId), "Token ID must be equal or greater than 0"); + } - var activeClaimCondition = await contract.DropERC1155_GetActiveClaimCondition(tokenId); + if (quantity <= 0) + { + throw new ArgumentOutOfRangeException(nameof(quantity), "Quantity must be greater than 0"); + } - var isNativeToken = activeClaimCondition.Currency == Constants.NATIVE_TOKEN_ADDRESS; + // TODO: Task.WhenAll - var payableAmount = isNativeToken ? quantity * activeClaimCondition.PricePerToken : BigInteger.Zero; + var activeClaimCondition = await contract.DropERC1155_GetActiveClaimCondition(tokenId); - // TODO: Merkle - var allowlistProof = new object[] { new byte[] { }, BigInteger.Zero, BigInteger.Zero, Constants.ADDRESS_ZERO }; + var isNativeToken = activeClaimCondition.Currency == Constants.NATIVE_TOKEN_ADDRESS; - var fnArgs = new object[] - { - receiverAddress, // receiver - tokenId, // tokenId - quantity, // quantity - activeClaimCondition.Currency, // currency - activeClaimCondition.PricePerToken, // pricePerToken - allowlistProof, // allowlistProof - new byte[] { } // data - }; - - return await ThirdwebContract.Write(wallet, contract, "claim", payableAmount, fnArgs); - } - - /// - /// Get the active claim condition ID for a specific ERC1155 token. - /// - /// The contract to interact with. - /// The ID of the token. - /// A task representing the asynchronous operation, with a BigInteger result containing the active claim condition ID. - /// Thrown when the contract is null. - /// Thrown when the token ID is less than 0. - public static async Task DropERC1155_GetActiveClaimConditionId(this ThirdwebContract contract, BigInteger tokenId) - { - if (contract == null) - { - throw new ArgumentNullException(nameof(contract)); - } + var payableAmount = isNativeToken ? quantity * activeClaimCondition.PricePerToken : BigInteger.Zero; - if (tokenId < 0) - { - throw new ArgumentOutOfRangeException(nameof(tokenId), "Token ID must be equal or greater than 0"); - } + // TODO: Merkle + var allowlistProof = new object[] { Array.Empty(), BigInteger.Zero, BigInteger.Zero, Constants.ADDRESS_ZERO }; - return await ThirdwebContract.Read(contract, "getActiveClaimConditionId", tokenId); + var fnArgs = new object[] + { + receiverAddress, // receiver + tokenId, // tokenId + quantity, // quantity + activeClaimCondition.Currency, // currency + activeClaimCondition.PricePerToken, // pricePerToken + allowlistProof, // allowlistProof + Array.Empty(), // data + }; + + return await ThirdwebContract.Write(wallet, contract, "claim", payableAmount, fnArgs); + } + + /// + /// Get the active claim condition ID for a specific ERC1155 token. + /// + /// The contract to interact with. + /// The ID of the token. + /// A task representing the asynchronous operation, with a BigInteger result containing the active claim condition ID. + /// Thrown when the contract is null. + /// Thrown when the token ID is less than 0. + public static async Task DropERC1155_GetActiveClaimConditionId(this ThirdwebContract contract, BigInteger tokenId) + { + if (contract == null) + { + throw new ArgumentNullException(nameof(contract)); } - /// - /// Get the claim condition details for a specific claim condition ID of a specific ERC1155 token. - /// - /// The contract to interact with. - /// The ID of the token. - /// The ID of the claim condition. - /// A task representing the asynchronous operation, with a Drop_ClaimCondition result containing the claim condition details. - /// Thrown when the contract is null. - /// Thrown when the token ID or claim condition ID is less than 0. - public static async Task DropERC1155_GetClaimConditionById(this ThirdwebContract contract, BigInteger tokenId, BigInteger claimConditionId) + return tokenId < 0 + ? throw new ArgumentOutOfRangeException(nameof(tokenId), "Token ID must be equal or greater than 0") + : await ThirdwebContract.Read(contract, "getActiveClaimConditionId", tokenId); + } + + /// + /// Get the claim condition details for a specific claim condition ID of a specific ERC1155 token. + /// + /// The contract to interact with. + /// The ID of the token. + /// The ID of the claim condition. + /// A task representing the asynchronous operation, with a Drop_ClaimCondition result containing the claim condition details. + /// Thrown when the contract is null. + /// Thrown when the token ID or claim condition ID is less than 0. + public static async Task DropERC1155_GetClaimConditionById(this ThirdwebContract contract, BigInteger tokenId, BigInteger claimConditionId) + { + if (contract == null) { - if (contract == null) - { - throw new ArgumentNullException(nameof(contract)); - } + throw new ArgumentNullException(nameof(contract)); + } - if (tokenId < 0) - { - throw new ArgumentOutOfRangeException(nameof(tokenId), "Token ID must be equal or greater than 0"); - } + if (tokenId < 0) + { + throw new ArgumentOutOfRangeException(nameof(tokenId), "Token ID must be equal or greater than 0"); + } - if (claimConditionId < 0) - { - throw new ArgumentOutOfRangeException(nameof(claimConditionId), "Claim condition ID must be equal or greater than 0"); - } + return claimConditionId < 0 + ? throw new ArgumentOutOfRangeException(nameof(claimConditionId), "Claim condition ID must be equal or greater than 0") + : await ThirdwebContract.Read(contract, "getClaimConditionById", tokenId, claimConditionId); + } - return await ThirdwebContract.Read(contract, "getClaimConditionById", tokenId, claimConditionId); + /// + /// Get the details of the active claim condition for a specific ERC1155 token. + /// + /// The contract to interact with. + /// The ID of the token. + /// A task representing the asynchronous operation, with a Drop_ClaimCondition result containing the active claim condition details. + /// Thrown when the contract is null. + /// Thrown when the token ID is less than 0. + public static async Task DropERC1155_GetActiveClaimCondition(this ThirdwebContract contract, BigInteger tokenId) + { + if (contract == null) + { + throw new ArgumentNullException(nameof(contract)); } - /// - /// Get the details of the active claim condition for a specific ERC1155 token. - /// - /// The contract to interact with. - /// The ID of the token. - /// A task representing the asynchronous operation, with a Drop_ClaimCondition result containing the active claim condition details. - /// Thrown when the contract is null. - /// Thrown when the token ID is less than 0. - public static async Task DropERC1155_GetActiveClaimCondition(this ThirdwebContract contract, BigInteger tokenId) + if (tokenId < 0) { - if (contract == null) - { - throw new ArgumentNullException(nameof(contract)); - } + throw new ArgumentOutOfRangeException(nameof(tokenId), "Token ID must be equal or greater than 0"); + } - if (tokenId < 0) - { - throw new ArgumentOutOfRangeException(nameof(tokenId), "Token ID must be equal or greater than 0"); - } + var activeClaimConditionId = await contract.DropERC1155_GetActiveClaimConditionId(tokenId); + return await contract.DropERC1155_GetClaimConditionById(tokenId, activeClaimConditionId); + } - var activeClaimConditionId = await contract.DropERC1155_GetActiveClaimConditionId(tokenId); - return await contract.DropERC1155_GetClaimConditionById(tokenId, activeClaimConditionId); + #endregion + + #region TokenERC20 + + /// + /// Mint a specific amount of ERC20 tokens to a receiver address. + /// + /// The contract to interact with. + /// The wallet to use for the transaction. + /// The address of the receiver. + /// The amount of tokens to mint. + /// A task representing the asynchronous operation, with a ThirdwebTransactionReceipt result. + /// Thrown when the contract or wallet is null. + /// Thrown when the receiver address or amount is null or empty. + public static async Task TokenERC20_MintTo(this ThirdwebContract contract, IThirdwebWallet wallet, string receiverAddress, string amount) + { + if (contract == null) + { + throw new ArgumentNullException(nameof(contract)); } - #endregion + if (wallet == null) + { + throw new ArgumentNullException(nameof(wallet)); + } - #region TokenERC20 + if (string.IsNullOrEmpty(receiverAddress)) + { + throw new ArgumentException("Receiver address must be provided"); + } - /// - /// Mint a specific amount of ERC20 tokens to a receiver address. - /// - /// The contract to interact with. - /// The wallet to use for the transaction. - /// The address of the receiver. - /// The amount of tokens to mint. - /// A task representing the asynchronous operation, with a ThirdwebTransactionReceipt result. - /// Thrown when the contract or wallet is null. - /// Thrown when the receiver address or amount is null or empty. - public static async Task TokenERC20_MintTo(this ThirdwebContract contract, IThirdwebWallet wallet, string receiverAddress, string amount) + if (string.IsNullOrEmpty(amount)) { - if (contract == null) - { - throw new ArgumentNullException(nameof(contract)); - } + throw new ArgumentException("Amount must be provided"); + } - if (wallet == null) - { - throw new ArgumentNullException(nameof(wallet)); - } + var erc20Decimals = await contract.ERC20_Decimals(); - if (string.IsNullOrEmpty(receiverAddress)) - { - throw new ArgumentException("Receiver address must be provided"); - } + var rawAmountToMint = BigInteger.Parse(amount.ToWei()).AdjustDecimals(18, erc20Decimals); - if (string.IsNullOrEmpty(amount)) - { - throw new ArgumentException("Amount must be provided"); - } + return await ThirdwebContract.Write(wallet, contract, "mintTo", 0, receiverAddress, rawAmountToMint); + } - var erc20Decimals = await contract.ERC20_Decimals(); + /// + /// Mint ERC20 tokens with a signature. + /// + /// The contract to interact with. + /// The wallet to use for the transaction. + /// The mint request containing the minting details. + /// The signature to authorize the minting. + /// A task representing the asynchronous operation, with a ThirdwebTransactionReceipt result. + /// Thrown when the contract, wallet, or mint request is null. + /// Thrown when the signature is null or empty. + public static async Task TokenERC20_MintWithSignature(this ThirdwebContract contract, IThirdwebWallet wallet, TokenERC20_MintRequest mintRequest, string signature) + { + if (contract == null) + { + throw new ArgumentNullException(nameof(contract)); + } - var rawAmountToMint = BigInteger.Parse(amount.ToWei()).AdjustDecimals(18, erc20Decimals); + if (wallet == null) + { + throw new ArgumentNullException(nameof(wallet)); + } - return await ThirdwebContract.Write(wallet, contract, "mintTo", 0, receiverAddress, rawAmountToMint); + if (mintRequest == null) + { + throw new ArgumentNullException(nameof(mintRequest)); } - /// - /// Mint ERC20 tokens with a signature. - /// - /// The contract to interact with. - /// The wallet to use for the transaction. - /// The mint request containing the minting details. - /// The signature to authorize the minting. - /// A task representing the asynchronous operation, with a ThirdwebTransactionReceipt result. - /// Thrown when the contract, wallet, or mint request is null. - /// Thrown when the signature is null or empty. - public static async Task TokenERC20_MintWithSignature(this ThirdwebContract contract, IThirdwebWallet wallet, TokenERC20_MintRequest mintRequest, string signature) + if (string.IsNullOrEmpty(signature)) { - if (contract == null) - { - throw new ArgumentNullException(nameof(contract)); - } + throw new ArgumentException("Signature must be provided"); + } - if (wallet == null) - { - throw new ArgumentNullException(nameof(wallet)); - } + var isNativeToken = mintRequest.Currency == Constants.NATIVE_TOKEN_ADDRESS; - if (mintRequest == null) - { - throw new ArgumentNullException(nameof(mintRequest)); - } + var payableAmount = isNativeToken ? mintRequest.Quantity * mintRequest.Price : BigInteger.Zero; - if (string.IsNullOrEmpty(signature)) - { - throw new ArgumentException("Signature must be provided"); - } + return await ThirdwebContract.Write(wallet, contract, "mintWithSignature", payableAmount, mintRequest, signature.HexToBytes()); + } - var isNativeToken = mintRequest.Currency == Constants.NATIVE_TOKEN_ADDRESS; + /// + /// Generate a mint signature for ERC20 tokens. + /// + /// The contract to interact with. + /// The wallet to use for generating the signature. + /// The mint request containing the minting details. + /// A task representing the asynchronous operation, with a tuple containing the mint request and the generated signature. + /// Thrown when the contract, wallet, or mint request is null. + public static async Task<(TokenERC20_MintRequest, string)> TokenERC20_GenerateMintSignature(this ThirdwebContract contract, IThirdwebWallet wallet, TokenERC20_MintRequest mintRequest) + { + if (contract == null) + { + throw new ArgumentNullException(nameof(contract)); + } - var payableAmount = isNativeToken ? mintRequest.Quantity * mintRequest.Price : BigInteger.Zero; + if (wallet == null) + { + throw new ArgumentNullException(nameof(wallet)); + } - return await ThirdwebContract.Write(wallet, contract, "mintWithSignature", payableAmount, mintRequest, signature); + if (mintRequest == null) + { + throw new ArgumentNullException(nameof(mintRequest)); } - /// - /// Generate a mint signature for ERC20 tokens. - /// - /// The contract to interact with. - /// The wallet to use for generating the signature. - /// The mint request containing the minting details. - /// A task representing the asynchronous operation, with a tuple containing the mint request and the generated signature. - /// Thrown when the contract, wallet, or mint request is null. - public static async Task<(TokenERC20_MintRequest, string)> TokenERC20_GenerateMintSignature(this ThirdwebContract contract, IThirdwebWallet wallet, TokenERC20_MintRequest mintRequest) + mintRequest = new TokenERC20_MintRequest { - if (contract == null) - { - throw new ArgumentNullException(nameof(contract)); - } + To = mintRequest.To ?? throw new ArgumentNullException(nameof(mintRequest.To)), + PrimarySaleRecipient = mintRequest.PrimarySaleRecipient ?? await contract.GetPrimarySaleRecipient(), + Quantity = mintRequest.Quantity > 0 ? mintRequest.Quantity : 1, + Price = mintRequest.Price, + Currency = mintRequest.Currency ?? Constants.NATIVE_TOKEN_ADDRESS, + ValidityStartTimestamp = mintRequest.ValidityStartTimestamp, + ValidityEndTimestamp = mintRequest.ValidityEndTimestamp > 0 ? mintRequest.ValidityEndTimestamp : Utils.GetUnixTimeStampIn10Years(), + Uid = mintRequest.Uid ?? Guid.NewGuid().ToByteArray().PadTo32Bytes(), + }; - if (wallet == null) - { - throw new ArgumentNullException(nameof(wallet)); - } + var contractMetadata = await contract.GetMetadata(); - if (mintRequest == null) - { - throw new ArgumentNullException(nameof(mintRequest)); - } + var signature = await EIP712.GenerateSignature_TokenERC20( + domainName: contractMetadata.Name, + version: "1", + chainId: contract.Chain, + verifyingContract: contract.Address, + mintRequest: mintRequest, + signer: wallet + ); - mintRequest = new TokenERC20_MintRequest - { - To = mintRequest.To ?? throw new ArgumentNullException(nameof(mintRequest.To)), - PrimarySaleRecipient = mintRequest.PrimarySaleRecipient ?? await contract.GetPrimarySaleRecipient(), - Quantity = mintRequest.Quantity > 0 ? mintRequest.Quantity : 1, - Price = mintRequest.Price, - Currency = mintRequest.Currency ?? Constants.NATIVE_TOKEN_ADDRESS, - ValidityStartTimestamp = mintRequest.ValidityStartTimestamp, - ValidityEndTimestamp = mintRequest.ValidityEndTimestamp > 0 ? mintRequest.ValidityEndTimestamp : Utils.GetUnixTimeStampIn10Years(), - Uid = mintRequest.Uid ?? Guid.NewGuid().ToByteArray().PadTo32Bytes() - }; - - var contractMetadata = await contract.GetMetadata(); - - var signature = await EIP712.GenerateSignature_TokenERC20( - domainName: contractMetadata.Name, - version: "1", - chainId: contract.Chain, - verifyingContract: contract.Address, - mintRequest: mintRequest, - signer: wallet - ); - - return (mintRequest, signature); - } - - /// - /// Verify a mint signature for ERC20 tokens. - /// - /// The contract to interact with. - /// The mint request containing the minting details. - /// The signature to verify. - /// A task representing the asynchronous operation, with a VerifyResult result containing the verification details. - /// Thrown when the contract or mint request is null. - /// Thrown when the signature is null or empty. - public static async Task TokenERC20_VerifyMintSignature(this ThirdwebContract contract, TokenERC20_MintRequest mintRequest, string signature) - { - if (contract == null) - { - throw new ArgumentNullException(nameof(contract)); - } + return (mintRequest, signature); + } - if (mintRequest == null) - { - throw new ArgumentNullException(nameof(mintRequest)); - } + /// + /// Verify a mint signature for ERC20 tokens. + /// + /// The contract to interact with. + /// The mint request containing the minting details. + /// The signature to verify. + /// A task representing the asynchronous operation, with a VerifyResult result containing the verification details. + /// Thrown when the contract or mint request is null. + /// Thrown when the signature is null or empty. + public static async Task TokenERC20_VerifyMintSignature(this ThirdwebContract contract, TokenERC20_MintRequest mintRequest, string signature) + { + if (contract == null) + { + throw new ArgumentNullException(nameof(contract)); + } - if (string.IsNullOrEmpty(signature)) - { - throw new ArgumentException("Signature must be provided"); - } + if (mintRequest == null) + { + throw new ArgumentNullException(nameof(mintRequest)); + } + + return string.IsNullOrEmpty(signature) + ? throw new ArgumentException("Signature must be provided") + : await ThirdwebContract.Read(contract, "verify", mintRequest, signature.HexToBytes()); + } + + #endregion + + #region TokenERC721 + + /// + /// Burn a specific ERC721 token with a given token ID. + /// + /// The contract to interact with. + /// The wallet to use for the transaction. + /// The ID of the token to burn. + /// A task representing the asynchronous operation, with a ThirdwebTransactionReceipt result. + /// Thrown when the contract or wallet is null. + /// Thrown when the token ID is less than 0. + public static async Task TokenERC721_Burn(this ThirdwebContract contract, IThirdwebWallet wallet, BigInteger tokenId) + { + if (contract == null) + { + throw new ArgumentNullException(nameof(contract)); + } - return await ThirdwebContract.Read(contract, "verify", mintRequest, signature.HexToBytes()); + if (wallet == null) + { + throw new ArgumentNullException(nameof(wallet)); } - #endregion + if (tokenId < 0) + { + throw new ArgumentOutOfRangeException(nameof(tokenId), "Token ID must be equal or greater than 0"); + } - #region TokenERC721 + return await ThirdwebContract.Write(wallet, contract, "burn", 0, tokenId); + } - /// - /// Mint a specific ERC721 token to a receiver address with a given URI. - /// - /// The contract to interact with. - /// The wallet to use for the transaction. - /// The address of the receiver. - /// The ID of the token. - /// The URI of the token metadata. - /// A task representing the asynchronous operation, with a ThirdwebTransactionReceipt result. - /// Thrown when the contract or wallet is null. - /// Thrown when the receiver address or URI is null or empty. - /// Thrown when the token ID is less than 0. - public static async Task TokenERC721_MintTo(this ThirdwebContract contract, IThirdwebWallet wallet, string receiverAddress, BigInteger tokenId, string uri) + /// + /// Mint a specific ERC721 token to a receiver address with a given URI. + /// + /// The contract to interact with. + /// The wallet to use for the transaction. + /// The address of the receiver. + /// The URI of the token metadata. + /// A task representing the asynchronous operation, with a ThirdwebTransactionReceipt result. + /// Thrown when the contract or wallet is null. + /// Thrown when the receiver address or URI is null or empty. + /// Thrown when the token ID is less than 0. + public static async Task TokenERC721_MintTo(this ThirdwebContract contract, IThirdwebWallet wallet, string receiverAddress, string uri) + { + if (contract == null) { - if (contract == null) - { - throw new ArgumentNullException(nameof(contract)); - } + throw new ArgumentNullException(nameof(contract)); + } - if (wallet == null) - { - throw new ArgumentNullException(nameof(wallet)); - } + if (wallet == null) + { + throw new ArgumentNullException(nameof(wallet)); + } - if (string.IsNullOrEmpty(receiverAddress)) - { - throw new ArgumentException("Receiver address must be provided"); - } + if (string.IsNullOrEmpty(receiverAddress)) + { + throw new ArgumentException("Receiver address must be provided"); + } - if (tokenId < 0) - { - throw new ArgumentOutOfRangeException(nameof(tokenId), "Token ID must be equal or greater than 0"); - } + return uri == null ? throw new ArgumentException("URI must be provided") : await ThirdwebContract.Write(wallet, contract, "mintTo", 0, receiverAddress, uri); + } - if (uri == null) // allow empty string uri - { - throw new ArgumentException("URI must be provided"); - } + /// + /// Mint a specific ERC721 token to a receiver address with metadata. + /// + /// The contract to interact with. + /// The wallet to use for the transaction. + /// The address of the receiver. + /// The metadata of the token. + /// A task representing the asynchronous operation, with a ThirdwebTransactionReceipt result. + /// Thrown when the contract or wallet is null. + /// Thrown when the receiver address is null or empty. + /// Thrown when the token ID is less than 0. + public static async Task TokenERC721_MintTo(this ThirdwebContract contract, IThirdwebWallet wallet, string receiverAddress, NFTMetadata metadata) + { + if (contract == null) + { + throw new ArgumentNullException(nameof(contract)); + } - return await ThirdwebContract.Write(wallet, contract, "mintTo", 0, receiverAddress, tokenId, uri); - } - - /// - /// Mint a specific ERC721 token to a receiver address with metadata. - /// - /// The contract to interact with. - /// The wallet to use for the transaction. - /// The address of the receiver. - /// The ID of the token. - /// The metadata of the token. - /// A task representing the asynchronous operation, with a ThirdwebTransactionReceipt result. - /// Thrown when the contract or wallet is null. - /// Thrown when the receiver address is null or empty. - /// Thrown when the token ID is less than 0. - public static async Task TokenERC721_MintTo( - this ThirdwebContract contract, - IThirdwebWallet wallet, - string receiverAddress, - BigInteger tokenId, - NFTMetadata metadata - ) - { - if (contract == null) - { - throw new ArgumentNullException(nameof(contract)); - } + if (wallet == null) + { + throw new ArgumentNullException(nameof(wallet)); + } - if (wallet == null) - { - throw new ArgumentNullException(nameof(wallet)); - } + if (string.IsNullOrEmpty(receiverAddress)) + { + throw new ArgumentException("Receiver address must be provided"); + } - if (string.IsNullOrEmpty(receiverAddress)) - { - throw new ArgumentException("Receiver address must be provided"); - } + var json = JsonConvert.SerializeObject(metadata); - if (tokenId < 0) - { - throw new ArgumentOutOfRangeException(nameof(tokenId), "Token ID must be equal or greater than 0"); - } + var jsonBytes = System.Text.Encoding.UTF8.GetBytes(json); - var json = JsonConvert.SerializeObject(metadata); + var ipfsResult = await ThirdwebStorage.UploadRaw(contract.Client, jsonBytes); - var jsonBytes = System.Text.Encoding.UTF8.GetBytes(json); + return await ThirdwebContract.Write(wallet, contract, "mintTo", 0, receiverAddress, $"ipfs://{ipfsResult.IpfsHash}"); + } - var ipfsResult = await ThirdwebStorage.UploadRaw(contract.Client, jsonBytes); + /// + /// Mint ERC721 tokens with a signature. + /// + /// The contract to interact with. + /// The wallet to use for the transaction. + /// The mint request containing the minting details. + /// The signature to authorize the minting. + /// A task representing the asynchronous operation, with a ThirdwebTransactionReceipt result. + /// Thrown when the contract, wallet, or mint request is null. + /// Thrown when the signature is null or empty. + public static async Task TokenERC721_MintWithSignature(this ThirdwebContract contract, IThirdwebWallet wallet, TokenERC721_MintRequest mintRequest, string signature) + { + if (contract == null) + { + throw new ArgumentNullException(nameof(contract)); + } - return await ThirdwebContract.Write(wallet, contract, "mintTo", 0, receiverAddress, tokenId, $"ipfs://{ipfsResult.IpfsHash}"); + if (wallet == null) + { + throw new ArgumentNullException(nameof(wallet)); } - /// - /// Mint ERC721 tokens with a signature. - /// - /// The contract to interact with. - /// The wallet to use for the transaction. - /// The mint request containing the minting details. - /// The signature to authorize the minting. - /// A task representing the asynchronous operation, with a ThirdwebTransactionReceipt result. - /// Thrown when the contract, wallet, or mint request is null. - /// Thrown when the signature is null or empty. - public static async Task TokenERC721_MintWithSignature( - this ThirdwebContract contract, - IThirdwebWallet wallet, - TokenERC721_MintRequest mintRequest, - string signature - ) + if (mintRequest == null) { - if (contract == null) - { - throw new ArgumentNullException(nameof(contract)); - } + throw new ArgumentNullException(nameof(mintRequest)); + } - if (wallet == null) - { - throw new ArgumentNullException(nameof(wallet)); - } + if (string.IsNullOrEmpty(signature)) + { + throw new ArgumentException("Signature must be provided"); + } - if (mintRequest == null) - { - throw new ArgumentNullException(nameof(mintRequest)); - } + var isNativeToken = mintRequest.Currency == Constants.NATIVE_TOKEN_ADDRESS; - if (string.IsNullOrEmpty(signature)) - { - throw new ArgumentException("Signature must be provided"); - } + var payableAmount = isNativeToken ? mintRequest.Price : BigInteger.Zero; - var isNativeToken = mintRequest.Currency == Constants.NATIVE_TOKEN_ADDRESS; + return await ThirdwebContract.Write(wallet, contract, "mintWithSignature", payableAmount, mintRequest, signature.HexToBytes()); + } - var payableAmount = isNativeToken ? mintRequest.Price : BigInteger.Zero; + /// + /// Generate a mint signature for ERC721 tokens. + /// + /// The contract to interact with. + /// The wallet to use for generating the signature. + /// The mint request containing the minting details. + /// Optional metadata override for the token. + /// A task representing the asynchronous operation, with a tuple containing the mint request and the generated signature. + /// Thrown when the contract, wallet, or mint request is null. + public static async Task<(TokenERC721_MintRequest, string)> TokenERC721_GenerateMintSignature( + this ThirdwebContract contract, + IThirdwebWallet wallet, + TokenERC721_MintRequest mintRequest, + NFTMetadata? metadataOverride = null + ) + { + if (contract == null) + { + throw new ArgumentNullException(nameof(contract)); + } - return await ThirdwebContract.Write(wallet, contract, "mintWithSignature", payableAmount, mintRequest, signature); + if (wallet == null) + { + throw new ArgumentNullException(nameof(wallet)); } - /// - /// Generate a mint signature for ERC721 tokens. - /// - /// The contract to interact with. - /// The wallet to use for generating the signature. - /// The mint request containing the minting details. - /// Optional metadata override for the token. - /// A task representing the asynchronous operation, with a tuple containing the mint request and the generated signature. - /// Thrown when the contract, wallet, or mint request is null. - public static async Task<(TokenERC721_MintRequest, string)> TokenERC721_GenerateMintSignature( - this ThirdwebContract contract, - IThirdwebWallet wallet, - TokenERC721_MintRequest mintRequest, - NFTMetadata? metadataOverride = null - ) + if (mintRequest == null) { - if (contract == null) - { - throw new ArgumentNullException(nameof(contract)); - } + throw new ArgumentNullException(nameof(mintRequest)); + } - if (wallet == null) + var finalUri = mintRequest.Uri; + + if (finalUri == null) // allow empty string uri + { + if (metadataOverride != null) { - throw new ArgumentNullException(nameof(wallet)); - } + var json = JsonConvert.SerializeObject(metadataOverride); + + var jsonBytes = System.Text.Encoding.UTF8.GetBytes(json); - if (mintRequest == null) + var ipfsResult = await ThirdwebStorage.UploadRaw(contract.Client, jsonBytes); + + finalUri = $"ipfs://{ipfsResult.IpfsHash}"; + } + else { - throw new ArgumentNullException(nameof(mintRequest)); + throw new ArgumentException("MintRequest URI or NFTMetadata override must be provided"); } + } - var finalUri = mintRequest.Uri; + var defaultRoyaltyInfo = await contract.GetDefaultRoyaltyInfo(); - if (finalUri == null) // allow empty string uri - { - if (metadataOverride != null) - { - var json = JsonConvert.SerializeObject(metadataOverride); + mintRequest = new TokenERC721_MintRequest + { + To = mintRequest.To ?? throw new ArgumentNullException(nameof(mintRequest.To)), + RoyaltyRecipient = defaultRoyaltyInfo.Recipient, + RoyaltyBps = defaultRoyaltyInfo.Bps, + PrimarySaleRecipient = mintRequest.PrimarySaleRecipient ?? await contract.GetPrimarySaleRecipient(), + Uri = finalUri, + Price = mintRequest.Price, + Currency = mintRequest.Currency ?? Constants.NATIVE_TOKEN_ADDRESS, + ValidityStartTimestamp = mintRequest.ValidityStartTimestamp, + ValidityEndTimestamp = mintRequest.ValidityEndTimestamp > 0 ? mintRequest.ValidityEndTimestamp : Utils.GetUnixTimeStampIn10Years(), + Uid = mintRequest.Uid ?? Guid.NewGuid().ToByteArray().PadTo32Bytes(), + }; - var jsonBytes = System.Text.Encoding.UTF8.GetBytes(json); + var signature = await EIP712.GenerateSignature_TokenERC721( + domainName: "TokenERC721", + version: "1", + chainId: contract.Chain, + verifyingContract: contract.Address, + mintRequest: mintRequest, + signer: wallet + ); - var ipfsResult = await ThirdwebStorage.UploadRaw(contract.Client, jsonBytes); + return (mintRequest, signature); + } - finalUri = $"ipfs://{ipfsResult.IpfsHash}"; - } - else - { - throw new ArgumentException("MintRequest URI or NFTMetadata override must be provided"); - } - } + /// + /// Verify a mint signature for ERC721 tokens. + /// + /// The contract to interact with. + /// The mint request containing the minting details. + /// The signature to verify. + /// A task representing the asynchronous operation, with a VerifyResult result containing the verification details. + /// Thrown when the contract or mint request is null. + /// Thrown when the signature is null or empty. + public static async Task TokenERC721_VerifyMintSignature(this ThirdwebContract contract, TokenERC721_MintRequest mintRequest, string signature) + { + if (contract == null) + { + throw new ArgumentNullException(nameof(contract)); + } - var defaultRoyaltyInfo = await contract.GetDefaultRoyaltyInfo(); + if (mintRequest == null) + { + throw new ArgumentNullException(nameof(mintRequest)); + } - mintRequest = new TokenERC721_MintRequest - { - To = mintRequest.To ?? throw new ArgumentNullException(nameof(mintRequest.To)), - RoyaltyRecipient = defaultRoyaltyInfo.Recipient, - RoyaltyBps = defaultRoyaltyInfo.Bps, - PrimarySaleRecipient = mintRequest.PrimarySaleRecipient ?? await contract.GetPrimarySaleRecipient(), - Uri = finalUri, - Price = mintRequest.Price, - Currency = mintRequest.Currency ?? Constants.NATIVE_TOKEN_ADDRESS, - ValidityStartTimestamp = mintRequest.ValidityStartTimestamp, - ValidityEndTimestamp = mintRequest.ValidityEndTimestamp > 0 ? mintRequest.ValidityEndTimestamp : Utils.GetUnixTimeStampIn10Years(), - Uid = mintRequest.Uid ?? Guid.NewGuid().ToByteArray().PadTo32Bytes() - }; - - var signature = await EIP712.GenerateSignature_TokenERC721( - domainName: "TokenERC721", - version: "1", - chainId: contract.Chain, - verifyingContract: contract.Address, - mintRequest: mintRequest, - signer: wallet - ); - - return (mintRequest, signature); - } - - /// - /// Verify a mint signature for ERC721 tokens. - /// - /// The contract to interact with. - /// The mint request containing the minting details. - /// The signature to verify. - /// A task representing the asynchronous operation, with a VerifyResult result containing the verification details. - /// Thrown when the contract or mint request is null. - /// Thrown when the signature is null or empty. - public static async Task TokenERC721_VerifyMintSignature(this ThirdwebContract contract, TokenERC721_MintRequest mintRequest, string signature) - { - if (contract == null) - { - throw new ArgumentNullException(nameof(contract)); - } + return string.IsNullOrEmpty(signature) + ? throw new ArgumentException("Signature must be provided") + : await ThirdwebContract.Read(contract, "verify", mintRequest, signature.HexToBytes()); + } - if (mintRequest == null) - { - throw new ArgumentNullException(nameof(mintRequest)); - } + #endregion + + #region TokenERC1155 + + /// + /// Burn a specific quantity of ERC1155 tokens for a specific account with a given token ID and amount to burn. + /// + /// The contract to interact with. + /// The wallet to use for the transaction. + /// The address of the account to burn the tokens from. + /// The ID of the token to burn. + /// The amount of tokens to burn. + /// A task representing the asynchronous operation, with a ThirdwebTransactionReceipt result. + /// Thrown when the contract, wallet, or account is null. + /// Thrown when the account is null or empty. + /// Thrown when the token ID is less than 0 or the amount is less than or equal to 0. + public static async Task TokenERC1155_Burn(this ThirdwebContract contract, IThirdwebWallet wallet, string account, BigInteger tokenId, BigInteger amount) + { + if (contract == null) + { + throw new ArgumentNullException(nameof(contract)); + } - if (string.IsNullOrEmpty(signature)) - { - throw new ArgumentException("Signature must be provided"); - } + if (wallet == null) + { + throw new ArgumentNullException(nameof(wallet)); + } - return await ThirdwebContract.Read(contract, "verify", mintRequest, signature.HexToBytes()); - } - - #endregion - - #region TokenERC1155 - - /// - /// Mint a specific quantity of ERC1155 tokens to a receiver address with a given URI. - /// - /// The contract to interact with. - /// The wallet to use for the transaction. - /// The address of the receiver. - /// The ID of the token. - /// The quantity of tokens to mint. - /// The URI of the token metadata. - /// A task representing the asynchronous operation, with a ThirdwebTransactionReceipt result. - /// Thrown when the contract, wallet, or URI is null. - /// Thrown when the receiver address is null or empty. - /// Thrown when the token ID is less than 0 or the quantity is less than or equal to 0. - public static async Task TokenERC1155_MintTo( - this ThirdwebContract contract, - IThirdwebWallet wallet, - string receiverAddress, - BigInteger tokenId, - BigInteger quantity, - string uri - ) - { - if (contract == null) - { - throw new ArgumentNullException(nameof(contract)); - } + if (string.IsNullOrEmpty(account)) + { + throw new ArgumentException("Account must be provided"); + } - if (wallet == null) - { - throw new ArgumentNullException(nameof(wallet)); - } + if (tokenId < 0) + { + throw new ArgumentOutOfRangeException(nameof(tokenId), "Token ID must be equal or greater than 0"); + } - if (string.IsNullOrEmpty(receiverAddress)) - { - throw new ArgumentException("Receiver address must be provided"); - } + if (amount <= 0) + { + throw new ArgumentOutOfRangeException(nameof(amount), "Amount must be greater than 0"); + } - if (tokenId < 0) - { - throw new ArgumentOutOfRangeException(nameof(tokenId), "Token ID must be equal or greater than 0"); - } + return await ThirdwebContract.Write(wallet, contract, "burn", 0, account, tokenId, amount); + } - if (quantity <= 0) - { - throw new ArgumentOutOfRangeException(nameof(quantity), "Quantity must be greater than 0"); - } + /// + /// Burn a specific quantity of ERC1155 tokens for a specific account with given token IDs and amounts to burn. + /// + /// The contract to interact with. + /// The wallet to use for the transaction. + /// The address of the account to burn the tokens from. + /// The IDs of the tokens to burn. + /// The amounts of tokens to burn. + /// A task representing the asynchronous operation, with a ThirdwebTransactionReceipt result. + /// Thrown when the contract, wallet, or account is null. + /// Thrown when the account is null or empty, or the token IDs or amounts are null or empty, or the token IDs and amounts have different lengths. + /// Thrown when the token IDs or amounts have a length less than or equal to 0. + /// Thrown when the token IDs and amounts have different lengths. + public static async Task TokenERC1155_BurnBatch(this ThirdwebContract contract, IThirdwebWallet wallet, string account, BigInteger[] tokenIds, BigInteger[] amounts) + { + if (contract == null) + { + throw new ArgumentNullException(nameof(contract)); + } - if (uri == null) // allow empty string uri - { - throw new ArgumentNullException(nameof(uri)); - } + if (wallet == null) + { + throw new ArgumentNullException(nameof(wallet)); + } - return await ThirdwebContract.Write(wallet, contract, "mintTo", 0, receiverAddress, tokenId, uri, quantity); - } - - /// - /// Mint a specific quantity of ERC1155 tokens to a receiver address with metadata. - /// - /// The contract to interact with. - /// The wallet to use for the transaction. - /// The address of the receiver. - /// The ID of the token. - /// The quantity of tokens to mint. - /// The metadata of the token. - /// A task representing the asynchronous operation, with a ThirdwebTransactionReceipt result. - /// Thrown when the contract or wallet is null. - /// Thrown when the receiver address is null or empty. - /// Thrown when the token ID is less than 0 or the quantity is less than or equal to 0. - public static async Task TokenERC1155_MintTo( - this ThirdwebContract contract, - IThirdwebWallet wallet, - string receiverAddress, - BigInteger tokenId, - BigInteger quantity, - NFTMetadata metadata - ) - { - if (contract == null) - { - throw new ArgumentNullException(nameof(contract)); - } + if (string.IsNullOrEmpty(account)) + { + throw new ArgumentException("Account must be provided"); + } - if (wallet == null) - { - throw new ArgumentNullException(nameof(wallet)); - } + if (tokenIds == null || tokenIds.Length == 0) + { + throw new ArgumentException("Token IDs must be provided"); + } - if (string.IsNullOrEmpty(receiverAddress)) - { - throw new ArgumentException("Receiver address must be provided"); - } + if (amounts == null || amounts.Length == 0) + { + throw new ArgumentException("Amounts must be provided"); + } - if (tokenId < 0) - { - throw new ArgumentOutOfRangeException(nameof(tokenId), "Token ID must be equal or greater than 0"); - } + if (tokenIds.Length != amounts.Length) + { + throw new ArgumentException("Token IDs and amounts must have the same length"); + } - if (quantity <= 0) - { - throw new ArgumentOutOfRangeException(nameof(quantity), "Quantity must be greater than 0"); - } + return await ThirdwebContract.Write(wallet, contract, "burnBatch", 0, account, tokenIds, amounts); + } - var json = JsonConvert.SerializeObject(metadata); + /// + /// Mint a specific quantity of ERC1155 tokens to a receiver address with a given URI. + /// + /// The contract to interact with. + /// The wallet to use for the transaction. + /// The address of the receiver. + /// The ID of the token. + /// The quantity of tokens to mint. + /// The URI of the token metadata. + /// A task representing the asynchronous operation, with a ThirdwebTransactionReceipt result. + /// Thrown when the contract, wallet, or URI is null. + /// Thrown when the receiver address is null or empty. + /// Thrown when the token ID is less than 0 or the quantity is less than or equal to 0. + public static async Task TokenERC1155_MintTo( + this ThirdwebContract contract, + IThirdwebWallet wallet, + string receiverAddress, + BigInteger tokenId, + BigInteger quantity, + string uri + ) + { + if (contract == null) + { + throw new ArgumentNullException(nameof(contract)); + } - var jsonBytes = System.Text.Encoding.UTF8.GetBytes(json); + if (wallet == null) + { + throw new ArgumentNullException(nameof(wallet)); + } - var ipfsResult = await ThirdwebStorage.UploadRaw(contract.Client, jsonBytes); + if (string.IsNullOrEmpty(receiverAddress)) + { + throw new ArgumentException("Receiver address must be provided"); + } - return await ThirdwebContract.Write(wallet, contract, "mintTo", 0, receiverAddress, tokenId, $"ipfs://{ipfsResult.IpfsHash}", quantity); + if (tokenId < 0) + { + throw new ArgumentOutOfRangeException(nameof(tokenId), "Token ID must be equal or greater than 0"); } - /// - /// Mint ERC1155 tokens with a signature. - /// - /// The contract to interact with. - /// The wallet to use for the transaction. - /// The mint request containing the minting details. - /// The signature to authorize the minting. - /// A task representing the asynchronous operation, with a ThirdwebTransactionReceipt result. - /// Thrown when the contract, wallet, or mint request is null. - /// Thrown when the signature is null or empty. - public static async Task TokenERC1155_MintWithSignature( - this ThirdwebContract contract, - IThirdwebWallet wallet, - TokenERC1155_MintRequest mintRequest, - string signature - ) + if (quantity <= 0) { - if (contract == null) - { - throw new ArgumentNullException(nameof(contract)); - } + throw new ArgumentOutOfRangeException(nameof(quantity), "Quantity must be greater than 0"); + } - if (wallet == null) - { - throw new ArgumentNullException(nameof(wallet)); - } + return uri == null ? throw new ArgumentNullException(nameof(uri)) : await ThirdwebContract.Write(wallet, contract, "mintTo", 0, receiverAddress, tokenId, uri, quantity); + } - if (mintRequest == null) - { - throw new ArgumentNullException(nameof(mintRequest)); - } + /// + /// Mint a specific quantity of ERC1155 tokens to a receiver address with metadata. + /// + /// The contract to interact with. + /// The wallet to use for the transaction. + /// The address of the receiver. + /// The ID of the token. + /// The quantity of tokens to mint. + /// The metadata of the token. + /// A task representing the asynchronous operation, with a ThirdwebTransactionReceipt result. + /// Thrown when the contract or wallet is null. + /// Thrown when the receiver address is null or empty. + /// Thrown when the token ID is less than 0 or the quantity is less than or equal to 0. + public static async Task TokenERC1155_MintTo( + this ThirdwebContract contract, + IThirdwebWallet wallet, + string receiverAddress, + BigInteger tokenId, + BigInteger quantity, + NFTMetadata metadata + ) + { + if (contract == null) + { + throw new ArgumentNullException(nameof(contract)); + } - if (string.IsNullOrEmpty(signature)) - { - throw new ArgumentException("Signature must be provided"); - } + if (wallet == null) + { + throw new ArgumentNullException(nameof(wallet)); + } - var isNativeToken = mintRequest.Currency == Constants.NATIVE_TOKEN_ADDRESS; + if (string.IsNullOrEmpty(receiverAddress)) + { + throw new ArgumentException("Receiver address must be provided"); + } - var payableAmount = isNativeToken ? mintRequest.Quantity * mintRequest.PricePerToken : BigInteger.Zero; + if (tokenId < 0) + { + throw new ArgumentOutOfRangeException(nameof(tokenId), "Token ID must be equal or greater than 0"); + } - return await ThirdwebContract.Write(wallet, contract, "mintWithSignature", payableAmount, mintRequest, signature); + if (quantity <= 0) + { + throw new ArgumentOutOfRangeException(nameof(quantity), "Quantity must be greater than 0"); } - /// - /// Generate a mint signature for ERC1155 tokens. - /// - /// The contract to interact with. - /// The wallet to use for generating the signature. - /// The mint request containing the minting details. - /// Optional metadata override for the token. - /// A task representing the asynchronous operation, with a tuple containing the mint request and the generated signature. - /// Thrown when the contract, wallet, or mint request is null. - /// Thrown when the MintRequest URI or NFTMetadata override is not provided. - public static async Task<(TokenERC1155_MintRequest, string)> TokenERC1155_GenerateMintSignature( - this ThirdwebContract contract, - IThirdwebWallet wallet, - TokenERC1155_MintRequest mintRequest, - NFTMetadata? metadataOverride = null - ) + var json = JsonConvert.SerializeObject(metadata); + + var jsonBytes = System.Text.Encoding.UTF8.GetBytes(json); + + var ipfsResult = await ThirdwebStorage.UploadRaw(contract.Client, jsonBytes); + + return await ThirdwebContract.Write(wallet, contract, "mintTo", 0, receiverAddress, tokenId, $"ipfs://{ipfsResult.IpfsHash}", quantity); + } + + /// + /// Mint ERC1155 tokens with a signature. + /// + /// The contract to interact with. + /// The wallet to use for the transaction. + /// The mint request containing the minting details. + /// The signature to authorize the minting. + /// A task representing the asynchronous operation, with a ThirdwebTransactionReceipt result. + /// Thrown when the contract, wallet, or mint request is null. + /// Thrown when the signature is null or empty. + public static async Task TokenERC1155_MintWithSignature(this ThirdwebContract contract, IThirdwebWallet wallet, TokenERC1155_MintRequest mintRequest, string signature) + { + if (contract == null) { - if (contract == null) - { - throw new ArgumentNullException(nameof(contract)); - } + throw new ArgumentNullException(nameof(contract)); + } - if (wallet == null) - { - throw new ArgumentNullException(nameof(wallet)); - } + if (wallet == null) + { + throw new ArgumentNullException(nameof(wallet)); + } - if (mintRequest == null) - { - throw new ArgumentNullException(nameof(mintRequest)); - } + if (mintRequest == null) + { + throw new ArgumentNullException(nameof(mintRequest)); + } - var finalUri = mintRequest.Uri; + if (string.IsNullOrEmpty(signature)) + { + throw new ArgumentException("Signature must be provided"); + } - if (finalUri == null) // allow empty string uri - { - if (metadataOverride != null) - { - var json = JsonConvert.SerializeObject(metadataOverride); + var isNativeToken = mintRequest.Currency == Constants.NATIVE_TOKEN_ADDRESS; - var jsonBytes = System.Text.Encoding.UTF8.GetBytes(json); + var payableAmount = isNativeToken ? mintRequest.Quantity * mintRequest.PricePerToken : BigInteger.Zero; - var ipfsResult = await ThirdwebStorage.UploadRaw(contract.Client, jsonBytes); + return await ThirdwebContract.Write(wallet, contract, "mintWithSignature", payableAmount, mintRequest, signature.HexToBytes()); + } - finalUri = $"ipfs://{ipfsResult.IpfsHash}"; - } - else - { - throw new ArgumentException("MintRequest URI or NFTMetadata override must be provided"); - } - } + /// + /// Generate a mint signature for ERC1155 tokens. + /// + /// The contract to interact with. + /// The wallet to use for generating the signature. + /// The mint request containing the minting details. + /// Optional metadata override for the token. + /// A task representing the asynchronous operation, with a tuple containing the mint request and the generated signature. + /// Thrown when the contract, wallet, or mint request is null. + /// Thrown when the MintRequest URI or NFTMetadata override is not provided. + public static async Task<(TokenERC1155_MintRequest, string)> TokenERC1155_GenerateMintSignature( + this ThirdwebContract contract, + IThirdwebWallet wallet, + TokenERC1155_MintRequest mintRequest, + NFTMetadata? metadataOverride = null + ) + { + if (contract == null) + { + throw new ArgumentNullException(nameof(contract)); + } - var defaultRoyaltyInfo = await contract.GetDefaultRoyaltyInfo(); + if (wallet == null) + { + throw new ArgumentNullException(nameof(wallet)); + } - mintRequest = new TokenERC1155_MintRequest - { - To = mintRequest.To ?? throw new ArgumentNullException(nameof(mintRequest.To)), - RoyaltyRecipient = defaultRoyaltyInfo.Recipient, - RoyaltyBps = defaultRoyaltyInfo.Bps, - TokenId = mintRequest.TokenId ?? await contract.ERC1155_TotalSupply(), - PrimarySaleRecipient = mintRequest.PrimarySaleRecipient ?? await contract.GetPrimarySaleRecipient(), - Uri = finalUri, - Quantity = mintRequest.Quantity > 0 ? mintRequest.Quantity : 1, - PricePerToken = mintRequest.PricePerToken, - Currency = mintRequest.Currency ?? Constants.NATIVE_TOKEN_ADDRESS, - ValidityStartTimestamp = mintRequest.ValidityStartTimestamp, - ValidityEndTimestamp = mintRequest.ValidityEndTimestamp > 0 ? mintRequest.ValidityEndTimestamp : Utils.GetUnixTimeStampIn10Years(), - Uid = mintRequest.Uid ?? Guid.NewGuid().ToByteArray().PadTo32Bytes() - }; - - var signature = await EIP712.GenerateSignature_TokenERC1155( - domainName: "TokenERC1155", - version: "1", - chainId: contract.Chain, - verifyingContract: contract.Address, - mintRequest: mintRequest, - signer: wallet - ); - - return (mintRequest, signature); - } - - /// - /// Verify a mint signature for ERC1155 tokens. - /// - /// The contract to interact with. - /// The mint request containing the minting details. - /// The signature to verify. - /// A task representing the asynchronous operation, with a VerifyResult result containing the verification details. - /// Thrown when the contract or mint request is null. - /// Thrown when the signature is null or empty. - public static async Task TokenERC1155_VerifyMintSignature(this ThirdwebContract contract, TokenERC1155_MintRequest mintRequest, string signature) - { - if (contract == null) - { - throw new ArgumentNullException(nameof(contract)); - } + if (mintRequest == null) + { + throw new ArgumentNullException(nameof(mintRequest)); + } - if (mintRequest == null) + var finalUri = mintRequest.Uri; + + if (finalUri == null) // allow empty string uri + { + if (metadataOverride != null) { - throw new ArgumentNullException(nameof(mintRequest)); - } + var json = JsonConvert.SerializeObject(metadataOverride); + + var jsonBytes = System.Text.Encoding.UTF8.GetBytes(json); + + var ipfsResult = await ThirdwebStorage.UploadRaw(contract.Client, jsonBytes); - if (string.IsNullOrEmpty(signature)) + finalUri = $"ipfs://{ipfsResult.IpfsHash}"; + } + else { - throw new ArgumentException("Signature must be provided"); + throw new ArgumentException("MintRequest URI or NFTMetadata override must be provided"); } + } + + var defaultRoyaltyInfo = await contract.GetDefaultRoyaltyInfo(); + + mintRequest = new TokenERC1155_MintRequest + { + To = mintRequest.To ?? throw new ArgumentNullException(nameof(mintRequest.To)), + RoyaltyRecipient = defaultRoyaltyInfo.Recipient, + RoyaltyBps = defaultRoyaltyInfo.Bps, + TokenId = mintRequest.TokenId ?? await contract.ERC1155_TotalSupply(), + PrimarySaleRecipient = mintRequest.PrimarySaleRecipient ?? await contract.GetPrimarySaleRecipient(), + Uri = finalUri, + Quantity = mintRequest.Quantity > 0 ? mintRequest.Quantity : 1, + PricePerToken = mintRequest.PricePerToken, + Currency = mintRequest.Currency ?? Constants.NATIVE_TOKEN_ADDRESS, + ValidityStartTimestamp = mintRequest.ValidityStartTimestamp, + ValidityEndTimestamp = mintRequest.ValidityEndTimestamp > 0 ? mintRequest.ValidityEndTimestamp : Utils.GetUnixTimeStampIn10Years(), + Uid = mintRequest.Uid ?? Guid.NewGuid().ToByteArray().PadTo32Bytes(), + }; + + var signature = await EIP712.GenerateSignature_TokenERC1155( + domainName: "TokenERC1155", + version: "1", + chainId: contract.Chain, + verifyingContract: contract.Address, + mintRequest: mintRequest, + signer: wallet + ); + + return (mintRequest, signature); + } - return await ThirdwebContract.Read(contract, "verify", mintRequest, signature.HexToBytes()); + /// + /// Verify a mint signature for ERC1155 tokens. + /// + /// The contract to interact with. + /// The mint request containing the minting details. + /// The signature to verify. + /// A task representing the asynchronous operation, with a VerifyResult result containing the verification details. + /// Thrown when the contract or mint request is null. + /// Thrown when the signature is null or empty. + public static async Task TokenERC1155_VerifyMintSignature(this ThirdwebContract contract, TokenERC1155_MintRequest mintRequest, string signature) + { + if (contract == null) + { + throw new ArgumentNullException(nameof(contract)); } - #endregion + if (mintRequest == null) + { + throw new ArgumentNullException(nameof(mintRequest)); + } + + return string.IsNullOrEmpty(signature) + ? throw new ArgumentException("Signature must be provided") + : await ThirdwebContract.Read(contract, "verify", mintRequest, signature.HexToBytes()); } + + #endregion } diff --git a/Thirdweb/Thirdweb.Http/IThirdwebHttpClient.cs b/Thirdweb/Thirdweb.Http/IThirdwebHttpClient.cs index 5565902a..fd8b8654 100644 --- a/Thirdweb/Thirdweb.Http/IThirdwebHttpClient.cs +++ b/Thirdweb/Thirdweb.Http/IThirdwebHttpClient.cs @@ -1,71 +1,70 @@ -namespace Thirdweb +namespace Thirdweb; + +/// +/// Interface for a HTTP client used in the Thirdweb SDK. +/// +public interface IThirdwebHttpClient : IDisposable { /// - /// Interface for a HTTP client used in the Thirdweb SDK. + /// Gets the headers for the HTTP client. /// - public interface IThirdwebHttpClient : IDisposable - { - /// - /// Gets the headers for the HTTP client. - /// - Dictionary Headers { get; } + public Dictionary Headers { get; } - /// - /// Sets the headers for the HTTP client. - /// - /// The headers to set. - void SetHeaders(Dictionary headers); + /// + /// Sets the headers for the HTTP client. + /// + /// The headers to set. + public void SetHeaders(Dictionary headers); - /// - /// Clears all headers from the HTTP client. - /// - void ClearHeaders(); + /// + /// Clears all headers from the HTTP client. + /// + public void ClearHeaders(); - /// - /// Adds a header to the HTTP client. - /// - /// The header key. - /// The header value. - void AddHeader(string key, string value); + /// + /// Adds a header to the HTTP client. + /// + /// The header key. + /// The header value. + public void AddHeader(string key, string value); - /// - /// Removes a header from the HTTP client. - /// - /// The header key. - void RemoveHeader(string key); + /// + /// Removes a header from the HTTP client. + /// + /// The header key. + public void RemoveHeader(string key); - /// - /// Sends a GET request to the specified URI. - /// - /// The request URI. - /// The cancellation token. - /// A task that represents the asynchronous operation. The task result contains the HTTP response message. - Task GetAsync(string requestUri, CancellationToken cancellationToken = default); + /// + /// Sends a GET request to the specified URI. + /// + /// The request URI. + /// The cancellation token. + /// A task that represents the asynchronous operation. The task result contains the HTTP response message. + public Task GetAsync(string requestUri, CancellationToken cancellationToken = default); - /// - /// Sends a POST request to the specified URI. - /// - /// The request URI. - /// The HTTP content to send. - /// The cancellation token. - /// A task that represents the asynchronous operation. The task result contains the HTTP response message. - Task PostAsync(string requestUri, HttpContent content, CancellationToken cancellationToken = default); + /// + /// Sends a POST request to the specified URI. + /// + /// The request URI. + /// The HTTP content to send. + /// The cancellation token. + /// A task that represents the asynchronous operation. The task result contains the HTTP response message. + public Task PostAsync(string requestUri, HttpContent content, CancellationToken cancellationToken = default); - /// - /// Sends a PUT request to the specified URI. - /// - /// The request URI. - /// The HTTP content to send. - /// The cancellation token. - /// A task that represents the asynchronous operation. The task result contains the HTTP response message. - Task PutAsync(string requestUri, HttpContent content, CancellationToken cancellationToken = default); + /// + /// Sends a PUT request to the specified URI. + /// + /// The request URI. + /// The HTTP content to send. + /// The cancellation token. + /// A task that represents the asynchronous operation. The task result contains the HTTP response message. + public Task PutAsync(string requestUri, HttpContent content, CancellationToken cancellationToken = default); - /// - /// Sends a DELETE request to the specified URI. - /// - /// The request URI. - /// The cancellation token. - /// A task that represents the asynchronous operation. The task result contains the HTTP response message. - Task DeleteAsync(string requestUri, CancellationToken cancellationToken = default); - } + /// + /// Sends a DELETE request to the specified URI. + /// + /// The request URI. + /// The cancellation token. + /// A task that represents the asynchronous operation. The task result contains the HTTP response message. + public Task DeleteAsync(string requestUri, CancellationToken cancellationToken = default); } diff --git a/Thirdweb/Thirdweb.Http/ThirdwebHttpClient.cs b/Thirdweb/Thirdweb.Http/ThirdwebHttpClient.cs index e24364d6..dbfd9224 100644 --- a/Thirdweb/Thirdweb.Http/ThirdwebHttpClient.cs +++ b/Thirdweb/Thirdweb.Http/ThirdwebHttpClient.cs @@ -1,152 +1,151 @@ -namespace Thirdweb +namespace Thirdweb; + +/// +/// Represents a HTTP client for the Thirdweb SDK. +/// +public class ThirdwebHttpClient : IThirdwebHttpClient { /// - /// Represents a HTTP client for the Thirdweb SDK. + /// Gets the headers for the HTTP client. /// - public class ThirdwebHttpClient : IThirdwebHttpClient - { - /// - /// Gets the headers for the HTTP client. - /// - public Dictionary Headers { get; private set; } + public Dictionary Headers { get; private set; } - private readonly HttpClient _httpClient; - private bool _disposed; + private readonly HttpClient _httpClient; + private bool _disposed; - /// - /// Initializes a new instance of the class. - /// - public ThirdwebHttpClient() - { - _httpClient = new HttpClient(); - Headers = new Dictionary(); - } + /// + /// Initializes a new instance of the class. + /// + public ThirdwebHttpClient() + { + this._httpClient = new HttpClient(); + this.Headers = new Dictionary(); + } - /// - /// Sets the headers for the HTTP client. - /// - /// The headers to set. - public void SetHeaders(Dictionary headers) - { - Headers = new Dictionary(headers); - } + /// + /// Sets the headers for the HTTP client. + /// + /// The headers to set. + public void SetHeaders(Dictionary headers) + { + this.Headers = new Dictionary(headers); + } - /// - /// Clears all headers from the HTTP client. - /// - public void ClearHeaders() - { - Headers.Clear(); - } + /// + /// Clears all headers from the HTTP client. + /// + public void ClearHeaders() + { + this.Headers.Clear(); + } - /// - /// Adds a header to the HTTP client. - /// - /// The header key. - /// The header value. - public void AddHeader(string key, string value) - { - Headers.Add(key, value); - } + /// + /// Adds a header to the HTTP client. + /// + /// The header key. + /// The header value. + public void AddHeader(string key, string value) + { + this.Headers.Add(key, value); + } - /// - /// Removes a header from the HTTP client. - /// - /// The header key. - public void RemoveHeader(string key) - { - _ = Headers.Remove(key); - } + /// + /// Removes a header from the HTTP client. + /// + /// The header key. + public void RemoveHeader(string key) + { + _ = this.Headers.Remove(key); + } - private void AddHeaders(HttpRequestMessage request) + private void AddHeaders(HttpRequestMessage request) + { + foreach (var header in this.Headers) { - foreach (var header in Headers) - { - _ = request.Headers.TryAddWithoutValidation(header.Key, header.Value); - } + _ = request.Headers.TryAddWithoutValidation(header.Key, header.Value); } + } - /// - /// Sends a GET request to the specified URI. - /// - /// The request URI. - /// The cancellation token. - /// A task that represents the asynchronous operation. The task result contains the HTTP response message. - public async Task GetAsync(string requestUri, CancellationToken cancellationToken = default) - { - var request = new HttpRequestMessage(HttpMethod.Get, requestUri); - AddHeaders(request); - var result = await _httpClient.SendAsync(request, cancellationToken).ConfigureAwait(false); + /// + /// Sends a GET request to the specified URI. + /// + /// The request URI. + /// The cancellation token. + /// A task that represents the asynchronous operation. The task result contains the HTTP response message. + public async Task GetAsync(string requestUri, CancellationToken cancellationToken = default) + { + var request = new HttpRequestMessage(HttpMethod.Get, requestUri); + this.AddHeaders(request); + var result = await this._httpClient.SendAsync(request, cancellationToken).ConfigureAwait(false); #pragma warning disable CA2016 // Forward the 'CancellationToken' parameter to methods - var resultContent = new ThirdwebHttpContent(await result.Content.ReadAsByteArrayAsync().ConfigureAwait(false)); + var resultContent = new ThirdwebHttpContent(await result.Content.ReadAsByteArrayAsync().ConfigureAwait(false)); #pragma warning restore CA2016 // Forward the 'CancellationToken' parameter to methods - return new ThirdwebHttpResponseMessage((long)result.StatusCode, resultContent, result.IsSuccessStatusCode); - } + return new ThirdwebHttpResponseMessage((long)result.StatusCode, resultContent, result.IsSuccessStatusCode); + } - /// - /// Sends a POST request to the specified URI. - /// - /// The request URI. - /// The HTTP content to send. - /// The cancellation token. - /// A task that represents the asynchronous operation. The task result contains the HTTP response message. - public async Task PostAsync(string requestUri, HttpContent content, CancellationToken cancellationToken = default) - { - var request = new HttpRequestMessage(HttpMethod.Post, requestUri) { Content = content }; - AddHeaders(request); - var result = await _httpClient.SendAsync(request, cancellationToken).ConfigureAwait(false); + /// + /// Sends a POST request to the specified URI. + /// + /// The request URI. + /// The HTTP content to send. + /// The cancellation token. + /// A task that represents the asynchronous operation. The task result contains the HTTP response message. + public async Task PostAsync(string requestUri, HttpContent content, CancellationToken cancellationToken = default) + { + var request = new HttpRequestMessage(HttpMethod.Post, requestUri) { Content = content }; + this.AddHeaders(request); + var result = await this._httpClient.SendAsync(request, cancellationToken).ConfigureAwait(false); #pragma warning disable CA2016 // Forward the 'CancellationToken' parameter to methods - var resultContent = new ThirdwebHttpContent(await result.Content.ReadAsByteArrayAsync().ConfigureAwait(false)); + var resultContent = new ThirdwebHttpContent(await result.Content.ReadAsByteArrayAsync().ConfigureAwait(false)); #pragma warning restore CA2016 // Forward the 'CancellationToken' parameter to methods - return new ThirdwebHttpResponseMessage((long)result.StatusCode, resultContent, result.IsSuccessStatusCode); - } + return new ThirdwebHttpResponseMessage((long)result.StatusCode, resultContent, result.IsSuccessStatusCode); + } - /// - /// Sends a PUT request to the specified URI. - /// - /// The request URI. - /// The HTTP content to send. - /// The cancellation token. - /// A task that represents the asynchronous operation. The task result contains the HTTP response message. - public Task PutAsync(string requestUri, HttpContent content, CancellationToken cancellationToken = default) - { - throw new NotImplementedException(); - } + /// + /// Sends a PUT request to the specified URI. + /// + /// The request URI. + /// The HTTP content to send. + /// The cancellation token. + /// A task that represents the asynchronous operation. The task result contains the HTTP response message. + public Task PutAsync(string requestUri, HttpContent content, CancellationToken cancellationToken = default) + { + throw new NotImplementedException(); + } - /// - /// Sends a DELETE request to the specified URI. - /// - /// The request URI. - /// The cancellation token. - /// A task that represents the asynchronous operation. The task result contains the HTTP response message. - public Task DeleteAsync(string requestUri, CancellationToken cancellationToken = default) - { - throw new NotImplementedException(); - } + /// + /// Sends a DELETE request to the specified URI. + /// + /// The request URI. + /// The cancellation token. + /// A task that represents the asynchronous operation. The task result contains the HTTP response message. + public Task DeleteAsync(string requestUri, CancellationToken cancellationToken = default) + { + throw new NotImplementedException(); + } - /// - /// Disposes the HTTP client. - /// - /// Whether the client is being disposed. - protected virtual void Dispose(bool disposing) + /// + /// Disposes the HTTP client. + /// + /// Whether the client is being disposed. + protected virtual void Dispose(bool disposing) + { + if (!this._disposed) { - if (!_disposed) + if (disposing) { - if (disposing) - { - _httpClient.Dispose(); - } - _disposed = true; + this._httpClient.Dispose(); } + this._disposed = true; } + } - /// - /// Disposes the HTTP client. - /// - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } + /// + /// Disposes the HTTP client. + /// + public void Dispose() + { + this.Dispose(true); + GC.SuppressFinalize(this); } } diff --git a/Thirdweb/Thirdweb.Http/ThirdwebHttpContent.cs b/Thirdweb/Thirdweb.Http/ThirdwebHttpContent.cs index 5c6b09d2..8f0340e8 100644 --- a/Thirdweb/Thirdweb.Http/ThirdwebHttpContent.cs +++ b/Thirdweb/Thirdweb.Http/ThirdwebHttpContent.cs @@ -1,89 +1,81 @@ using System.Text; -namespace Thirdweb +namespace Thirdweb; + +/// +/// Represents HTTP content used in the Thirdweb SDK. +/// +public class ThirdwebHttpContent { + private readonly byte[] _content; + /// - /// Represents HTTP content used in the Thirdweb SDK. + /// Initializes a new instance of the class from a string. /// - public class ThirdwebHttpContent + /// The content string. + /// Thrown if the content is null. + public ThirdwebHttpContent(string content) { - private readonly byte[] content; - - /// - /// Initializes a new instance of the class from a string. - /// - /// The content string. - /// Thrown if the content is null. - public ThirdwebHttpContent(string content) + if (content == null) { - if (content == null) - { - throw new ArgumentNullException(nameof(content)); - } - - this.content = Encoding.UTF8.GetBytes(content); + throw new ArgumentNullException(nameof(content)); } - /// - /// Initializes a new instance of the class from a byte array. - /// - /// The content byte array. - /// Thrown if the content is null. - public ThirdwebHttpContent(byte[] content) - { - if (content == null) - { - throw new ArgumentNullException(nameof(content)); - } + this._content = Encoding.UTF8.GetBytes(content); + } - this.content = content; - } + /// + /// Initializes a new instance of the class from a byte array. + /// + /// The content byte array. + /// Thrown if the content is null. + public ThirdwebHttpContent(byte[] content) + { + this._content = content ?? throw new ArgumentNullException(nameof(content)); + } - /// - /// Initializes a new instance of the class from a stream. - /// - /// The content stream. - /// Thrown if the content is null. - public ThirdwebHttpContent(Stream content) + /// + /// Initializes a new instance of the class from a stream. + /// + /// The content stream. + /// Thrown if the content is null. + public ThirdwebHttpContent(Stream content) + { + if (content == null) { - if (content == null) - { - throw new ArgumentNullException(nameof(content)); - } - - using (var memoryStream = new MemoryStream()) - { - content.CopyTo(memoryStream); - this.content = memoryStream.ToArray(); - } + throw new ArgumentNullException(nameof(content)); } - /// - /// Reads the content as a string. - /// - /// A task that represents the asynchronous operation. The task result contains the content string. - public Task ReadAsStringAsync() - { - return Task.FromResult(Encoding.UTF8.GetString(content)); - } + using var memoryStream = new MemoryStream(); + content.CopyTo(memoryStream); + this._content = memoryStream.ToArray(); + } - /// - /// Reads the content as a byte array. - /// - /// A task that represents the asynchronous operation. The task result contains the content byte array. - public Task ReadAsByteArrayAsync() - { - return Task.FromResult(content); - } + /// + /// Reads the content as a string. + /// + /// A task that represents the asynchronous operation. The task result contains the content string. + public Task ReadAsStringAsync() + { + return Task.FromResult(Encoding.UTF8.GetString(this._content)); + } - /// - /// Reads the content as a stream. - /// - /// A task that represents the asynchronous operation. The task result contains the content stream. - public Task ReadAsStreamAsync() - { - var stream = new MemoryStream(content); - return Task.FromResult(stream); - } + /// + /// Reads the content as a byte array. + /// + /// A task that represents the asynchronous operation. The task result contains the content byte array. + public Task ReadAsByteArrayAsync() + { + return Task.FromResult(this._content); + } + + /// + /// Reads the content as a stream. + /// + /// A task that represents the asynchronous operation. The task result contains the content stream. + public Task ReadAsStreamAsync() + { + var stream = new MemoryStream(this._content); + return Task.FromResult(stream); } } diff --git a/Thirdweb/Thirdweb.Http/ThirdwebHttpResponseMessage.cs b/Thirdweb/Thirdweb.Http/ThirdwebHttpResponseMessage.cs index 337bf208..7604f72c 100644 --- a/Thirdweb/Thirdweb.Http/ThirdwebHttpResponseMessage.cs +++ b/Thirdweb/Thirdweb.Http/ThirdwebHttpResponseMessage.cs @@ -1,51 +1,43 @@ -namespace Thirdweb +namespace Thirdweb; + +/// +/// Represents an HTTP response message used in the Thirdweb SDK. +/// +/// +/// Initializes a new instance of the class. +/// +/// The status code of the HTTP response. +/// The content of the HTTP response. +/// A value indicating whether the HTTP response is successful. +public class ThirdwebHttpResponseMessage(long statusCode, ThirdwebHttpContent content, bool isSuccessStatusCode) { /// - /// Represents an HTTP response message used in the Thirdweb SDK. + /// Gets or sets the status code of the HTTP response. /// - public class ThirdwebHttpResponseMessage - { - /// - /// Gets or sets the status code of the HTTP response. - /// - public long StatusCode { get; set; } - - /// - /// Gets or sets the content of the HTTP response. - /// - public ThirdwebHttpContent Content { get; set; } + public long StatusCode { get; set; } = statusCode; - /// - /// Gets or sets a value indicating whether the HTTP response is successful. - /// - public bool IsSuccessStatusCode { get; set; } + /// + /// Gets or sets the content of the HTTP response. + /// + public ThirdwebHttpContent Content { get; set; } = content; - /// - /// Initializes a new instance of the class. - /// - /// The status code of the HTTP response. - /// The content of the HTTP response. - /// A value indicating whether the HTTP response is successful. - public ThirdwebHttpResponseMessage(long statusCode, ThirdwebHttpContent content, bool isSuccessStatusCode) - { - StatusCode = statusCode; - Content = content; - IsSuccessStatusCode = isSuccessStatusCode; - } + /// + /// Gets or sets a value indicating whether the HTTP response is successful. + /// + public bool IsSuccessStatusCode { get; set; } = isSuccessStatusCode; - /// - /// Ensures that the HTTP response was successful. - /// - /// The instance. - /// Thrown if the HTTP response was not successful. - public ThirdwebHttpResponseMessage EnsureSuccessStatusCode() + /// + /// Ensures that the HTTP response was successful. + /// + /// The instance. + /// Thrown if the HTTP response was not successful. + public ThirdwebHttpResponseMessage EnsureSuccessStatusCode() + { + if (!this.IsSuccessStatusCode) { - if (!IsSuccessStatusCode) - { - // TODO: Custom exception - throw new Exception($"Request failed with status code {StatusCode} and content: {Content.ReadAsStringAsync().Result}"); - } - return this; + // TODO: Custom exception + throw new Exception($"Request failed with status code {this.StatusCode} and content: {this.Content.ReadAsStringAsync().Result}"); } + return this; } } diff --git a/Thirdweb/Thirdweb.Pay/Constants.cs b/Thirdweb/Thirdweb.Pay/Constants.cs deleted file mode 100644 index 3990ea38..00000000 --- a/Thirdweb/Thirdweb.Pay/Constants.cs +++ /dev/null @@ -1,17 +0,0 @@ -namespace Thirdweb.Pay -{ - public static class Constants - { - public const string THIRDWEB_PAY_BASE_URL = "https://pay.thirdweb.com"; - - public const string THIRDWEB_PAY_CRYPTO_QUOTE_ENDPOINT = THIRDWEB_PAY_BASE_URL + "/buy-with-crypto/quote/v1"; - public const string THIRDWEB_PAY_CRYPTO_STATUS_ENDPOINT = THIRDWEB_PAY_BASE_URL + "/buy-with-crypto/status/v1"; - - public const string THIRDWEB_PAY_FIAT_QUOTE_ENDPOINT = THIRDWEB_PAY_BASE_URL + "/buy-with-fiat/quote/v1"; - public const string THIRDWEB_PAY_FIAT_STATUS_ENDPOINT = THIRDWEB_PAY_BASE_URL + "/buy-with-fiat/status/v1"; - - public const string THIRDWEB_PAY_FIAT_CURRENCIES_ENDPOINT = THIRDWEB_PAY_BASE_URL + "/buy-with-fiat/currency/v1"; - - public const string THIRDWEB_PAY_HISTORY_ENDPOINT = THIRDWEB_PAY_BASE_URL + "/wallet/history/v1"; - } -} diff --git a/Thirdweb/Thirdweb.Pay/ThirdwebPay.BuyWithCrypto.cs b/Thirdweb/Thirdweb.Pay/ThirdwebPay.BuyWithCrypto.cs deleted file mode 100644 index b39f6e26..00000000 --- a/Thirdweb/Thirdweb.Pay/ThirdwebPay.BuyWithCrypto.cs +++ /dev/null @@ -1,46 +0,0 @@ -using System.Numerics; -using Nethereum.Hex.HexTypes; - -namespace Thirdweb.Pay -{ - /// - /// Provides methods for processing payments with cryptocurrency. - /// - public partial class ThirdwebPay - { - /// - /// Initiates a cryptocurrency purchase using the provided wallet and quote. - /// - /// The wallet to use for the purchase. - /// The quote result containing transaction details. - /// A task that represents the asynchronous operation. The task result contains the transaction hash. - public static async Task BuyWithCrypto(IThirdwebWallet wallet, BuyWithCryptoQuoteResult buyWithCryptoQuote) - { - if (buyWithCryptoQuote.Approval != null) - { - var erc20ToApprove = await ThirdwebContract.Create(wallet.Client, buyWithCryptoQuote.Approval.TokenAddress, buyWithCryptoQuote.Approval.ChainId); - var currentAllowance = await erc20ToApprove.ERC20_Allowance(await wallet.GetAddress(), buyWithCryptoQuote.Approval.SpenderAddress); - if (currentAllowance < BigInteger.Parse(buyWithCryptoQuote.Approval.AmountWei)) - { - _ = await erc20ToApprove.ERC20_Approve(wallet, buyWithCryptoQuote.Approval.SpenderAddress, BigInteger.Parse(buyWithCryptoQuote.Approval.AmountWei)); - } - } - - var txInput = new ThirdwebTransactionInput() - { - From = buyWithCryptoQuote.TransactionRequest.From, - To = buyWithCryptoQuote.TransactionRequest.To, - Data = buyWithCryptoQuote.TransactionRequest.Data, - Value = new HexBigInteger(BigInteger.Parse(buyWithCryptoQuote.TransactionRequest.Value)), - Gas = new HexBigInteger(BigInteger.Parse(buyWithCryptoQuote.TransactionRequest.GasLimit)), - GasPrice = new HexBigInteger(BigInteger.Parse(buyWithCryptoQuote.TransactionRequest.GasPrice)), - }; - - var tx = await ThirdwebTransaction.Create(wallet, txInput, buyWithCryptoQuote.TransactionRequest.ChainId); - - var hash = await ThirdwebTransaction.Send(tx); - - return hash; - } - } -} diff --git a/Thirdweb/Thirdweb.Pay/ThirdwebPay.BuyWithFiat.cs b/Thirdweb/Thirdweb.Pay/ThirdwebPay.BuyWithFiat.cs deleted file mode 100644 index 2214a50e..00000000 --- a/Thirdweb/Thirdweb.Pay/ThirdwebPay.BuyWithFiat.cs +++ /dev/null @@ -1,26 +0,0 @@ -namespace Thirdweb.Pay -{ - /// - /// Provides methods for processing payments with cryptocurrency and fiat. - /// - public partial class ThirdwebPay - { - /// - /// Initiates a purchase using fiat currency through an on-ramp service. - /// - /// The quote result containing the on-ramp link. - /// The on-ramp link for the fiat purchase. - /// Thrown if the on-ramp link is null or empty. - public static string BuyWithFiat(BuyWithFiatQuoteResult buyWithFiatQuote) - { - if (string.IsNullOrEmpty(buyWithFiatQuote.OnRampLink)) - { - throw new ArgumentException("On-ramp link cannot be null or empty."); - } - - var onRampLink = buyWithFiatQuote.OnRampLink; - - return onRampLink; - } - } -} diff --git a/Thirdweb/Thirdweb.Pay/ThirdwebPay.GetBuyHistory.cs b/Thirdweb/Thirdweb.Pay/ThirdwebPay.GetBuyHistory.cs deleted file mode 100644 index e47ee394..00000000 --- a/Thirdweb/Thirdweb.Pay/ThirdwebPay.GetBuyHistory.cs +++ /dev/null @@ -1,70 +0,0 @@ -using Newtonsoft.Json; - -namespace Thirdweb.Pay -{ - /// - /// Provides methods for processing payments with cryptocurrency and fiat. - /// - public partial class ThirdwebPay - { - /// - /// Retrieves the buy history for a specified wallet address. - /// - /// The Thirdweb client. - /// The wallet address to retrieve history for. - /// The start index for the history. - /// The number of history records to retrieve. - /// The cursor for pagination (optional). - /// The page size for pagination (optional). - /// A task that represents the asynchronous operation. The task result contains the buy history result. - /// Thrown if the HTTP response is not successful. - public static async Task GetBuyHistory(ThirdwebClient client, string walletAddress, int start, int count, string cursor = null, int? pageSize = null) - { - var queryString = new Dictionary - { - { "walletAddress", walletAddress }, - { "start", start.ToString() }, - { "count", count.ToString() }, - { "cursor", cursor }, - { "pageSize", pageSize?.ToString() } - }; - - var queryStringFormatted = string.Join("&", queryString.Where(kv => kv.Value != null).Select(kv => $"{Uri.EscapeDataString(kv.Key)}={Uri.EscapeDataString(kv.Value)}")); - var url = $"{Constants.THIRDWEB_PAY_HISTORY_ENDPOINT}?{queryStringFormatted}"; - - var getResponse = await client.HttpClient.GetAsync(url); - - var content = await getResponse.Content.ReadAsStringAsync(); - - if (!getResponse.IsSuccessStatusCode) - { - ErrorResponse error; - try - { - error = JsonConvert.DeserializeObject(content); - } - catch - { - error = new ErrorResponse - { - Error = new ErrorDetails - { - Message = "Unknown error", - Reason = "Unknown", - Code = "Unknown", - Stack = "Unknown", - StatusCode = (int)getResponse.StatusCode - } - }; - } - - throw new Exception( - $"HTTP error! Code: {error.Error.Code} Message: {error.Error.Message} Reason: {error.Error.Reason} StatusCode: {error.Error.StatusCode} Stack: {error.Error.Stack}" - ); - } - - var data = JsonConvert.DeserializeObject(content); - return data.Result; - } - } -} diff --git a/Thirdweb/Thirdweb.Pay/ThirdwebPay.GetBuyWithCryptoQuote.cs b/Thirdweb/Thirdweb.Pay/ThirdwebPay.GetBuyWithCryptoQuote.cs deleted file mode 100644 index c57436af..00000000 --- a/Thirdweb/Thirdweb.Pay/ThirdwebPay.GetBuyWithCryptoQuote.cs +++ /dev/null @@ -1,72 +0,0 @@ -using Newtonsoft.Json; - -namespace Thirdweb.Pay -{ - /// - /// Provides methods for processing payments with cryptocurrency and fiat. - /// - public partial class ThirdwebPay - { - /// - /// Retrieves a quote for buying with cryptocurrency using the provided parameters. - /// - /// The Thirdweb client. - /// The parameters for the crypto purchase. - /// A task that represents the asynchronous operation. The task result contains the quote result. - /// Thrown if the HTTP response is not successful. - public static async Task GetBuyWithCryptoQuote(ThirdwebClient client, BuyWithCryptoQuoteParams buyWithCryptoParams) - { - var queryString = new Dictionary - { - { "fromAddress", buyWithCryptoParams.FromAddress }, - { "fromChainId", buyWithCryptoParams.FromChainId?.ToString() }, - { "fromTokenAddress", buyWithCryptoParams.FromTokenAddress }, - { "fromAmount", buyWithCryptoParams.FromAmount }, - { "fromAmountWei", buyWithCryptoParams.FromAmountWei }, - { "toChainId", buyWithCryptoParams.ToChainId?.ToString() }, - { "toTokenAddress", buyWithCryptoParams.ToTokenAddress }, - { "toAmount", buyWithCryptoParams.ToAmount }, - { "toAmountWei", buyWithCryptoParams.ToAmountWei }, - { "maxSlippageBPS", buyWithCryptoParams.MaxSlippageBPS?.ToString() }, - { "intentId", buyWithCryptoParams.IntentId } - }; - - var queryStringFormatted = string.Join("&", queryString.Where(kv => kv.Value != null).Select(kv => $"{Uri.EscapeDataString(kv.Key)}={Uri.EscapeDataString(kv.Value)}")); - var url = $"{Constants.THIRDWEB_PAY_CRYPTO_QUOTE_ENDPOINT}?{queryStringFormatted}"; - - var getResponse = await client.HttpClient.GetAsync(url); - - var content = await getResponse.Content.ReadAsStringAsync(); - - if (!getResponse.IsSuccessStatusCode) - { - ErrorResponse error; - try - { - error = JsonConvert.DeserializeObject(content); - } - catch - { - error = new ErrorResponse - { - Error = new ErrorDetails - { - Message = "Unknown error", - Reason = "Unknown", - Code = "Unknown", - Stack = "Unknown", - StatusCode = (int)getResponse.StatusCode - } - }; - } - - throw new Exception( - $"HTTP error! Code: {error.Error.Code} Message: {error.Error.Message} Reason: {error.Error.Reason} StatusCode: {error.Error.StatusCode} Stack: {error.Error.Stack}" - ); - } - - var data = JsonConvert.DeserializeObject(content); - return data.Result; - } - } -} diff --git a/Thirdweb/Thirdweb.Pay/ThirdwebPay.GetBuyWithCryptoStatus.cs b/Thirdweb/Thirdweb.Pay/ThirdwebPay.GetBuyWithCryptoStatus.cs deleted file mode 100644 index 7d2e79ba..00000000 --- a/Thirdweb/Thirdweb.Pay/ThirdwebPay.GetBuyWithCryptoStatus.cs +++ /dev/null @@ -1,65 +0,0 @@ -using Newtonsoft.Json; - -namespace Thirdweb.Pay -{ - /// - /// Provides methods for processing payments with cryptocurrency and fiat. - /// - public partial class ThirdwebPay - { - /// - /// Retrieves the status of a cryptocurrency purchase using the transaction hash. - /// - /// The Thirdweb client. - /// The transaction hash to check the status of. - /// A task that represents the asynchronous operation. The task result contains the status result. - /// Thrown if the transaction hash is null or empty. - /// Thrown if the HTTP response is not successful. - public static async Task GetBuyWithCryptoStatus(ThirdwebClient client, string transactionHash) - { - if (string.IsNullOrEmpty(transactionHash)) - { - throw new ArgumentException(nameof(transactionHash), "Transaction hash cannot be null or empty."); - } - - var queryString = new Dictionary { { "transactionHash", transactionHash } }; - - var queryStringFormatted = string.Join("&", queryString.Where(kv => kv.Value != null).Select(kv => $"{Uri.EscapeDataString(kv.Key)}={Uri.EscapeDataString(kv.Value)}")); - var url = $"{Constants.THIRDWEB_PAY_CRYPTO_STATUS_ENDPOINT}?{queryStringFormatted}"; - - var getResponse = await client.HttpClient.GetAsync(url); - - var content = await getResponse.Content.ReadAsStringAsync(); - - if (!getResponse.IsSuccessStatusCode) - { - ErrorResponse error; - try - { - error = JsonConvert.DeserializeObject(content); - } - catch - { - error = new ErrorResponse - { - Error = new ErrorDetails - { - Message = "Unknown error", - Reason = "Unknown", - Code = "Unknown", - Stack = "Unknown", - StatusCode = (int)getResponse.StatusCode - } - }; - } - - throw new Exception( - $"HTTP error! Code: {error.Error.Code} Message: {error.Error.Message} Reason: {error.Error.Reason} StatusCode: {error.Error.StatusCode} Stack: {error.Error.Stack}" - ); - } - - var data = JsonConvert.DeserializeObject(content); - return data.Result; - } - } -} diff --git a/Thirdweb/Thirdweb.Pay/ThirdwebPay.GetBuyWithFiatCurrencies.cs b/Thirdweb/Thirdweb.Pay/ThirdwebPay.GetBuyWithFiatCurrencies.cs deleted file mode 100644 index 598d7046..00000000 --- a/Thirdweb/Thirdweb.Pay/ThirdwebPay.GetBuyWithFiatCurrencies.cs +++ /dev/null @@ -1,55 +0,0 @@ -using Newtonsoft.Json; - -namespace Thirdweb.Pay -{ - /// - /// Provides methods for processing payments with cryptocurrency and fiat. - /// - public partial class ThirdwebPay - { - /// - /// Retrieves the list of supported fiat currencies for buying with fiat. - /// - /// The Thirdweb client. - /// A task that represents the asynchronous operation. The task result contains the list of supported fiat currencies. - /// Thrown if the HTTP response is not successful. - public static async Task> GetBuyWithFiatCurrencies(ThirdwebClient client) - { - var url = $"{Constants.THIRDWEB_PAY_FIAT_CURRENCIES_ENDPOINT}"; - - var getResponse = await client.HttpClient.GetAsync(url); - - var content = await getResponse.Content.ReadAsStringAsync(); - - if (!getResponse.IsSuccessStatusCode) - { - ErrorResponse error; - try - { - error = JsonConvert.DeserializeObject(content); - } - catch - { - error = new ErrorResponse - { - Error = new ErrorDetails - { - Message = "Unknown error", - Reason = "Unknown", - Code = "Unknown", - Stack = "Unknown", - StatusCode = (int)getResponse.StatusCode - } - }; - } - - throw new Exception( - $"HTTP error! Code: {error.Error.Code} Message: {error.Error.Message} Reason: {error.Error.Reason} StatusCode: {error.Error.StatusCode} Stack: {error.Error.Stack}" - ); - } - - var data = JsonConvert.DeserializeObject(content); - return data.Result.FiatCurrencies; - } - } -} diff --git a/Thirdweb/Thirdweb.Pay/ThirdwebPay.GetBuyWithFiatQuote.cs b/Thirdweb/Thirdweb.Pay/ThirdwebPay.GetBuyWithFiatQuote.cs deleted file mode 100644 index f6bd74bc..00000000 --- a/Thirdweb/Thirdweb.Pay/ThirdwebPay.GetBuyWithFiatQuote.cs +++ /dev/null @@ -1,71 +0,0 @@ -using Newtonsoft.Json; - -namespace Thirdweb.Pay -{ - /// - /// Provides methods for processing payments with cryptocurrency and fiat. - /// - public partial class ThirdwebPay - { - /// - /// Retrieves a quote for buying with fiat using the provided parameters. - /// - /// The Thirdweb client. - /// The parameters for the fiat purchase. - /// A task that represents the asynchronous operation. The task result contains the quote result. - /// Thrown if the HTTP response is not successful. - public static async Task GetBuyWithFiatQuote(ThirdwebClient client, BuyWithFiatQuoteParams buyWithFiatParams) - { - var queryString = new Dictionary - { - { "fromCurrencySymbol", buyWithFiatParams.FromCurrencySymbol }, - { "fromAmount", buyWithFiatParams.FromAmount }, - { "fromAmountUnits", buyWithFiatParams.FromAmountUnits }, - { "toAddress", buyWithFiatParams.ToAddress }, - { "toChainId", buyWithFiatParams.ToChainId }, - { "toTokenAddress", buyWithFiatParams.ToTokenAddress }, - { "toAmount", buyWithFiatParams.ToAmount }, - { "toAmountWei", buyWithFiatParams.ToAmountWei }, - { "maxSlippageBPS", buyWithFiatParams.MaxSlippageBPS?.ToString() } - }; - - var queryStringFormatted = string.Join("&", queryString.Where(kv => kv.Value != null).Select(kv => $"{Uri.EscapeDataString(kv.Key)}={Uri.EscapeDataString(kv.Value)}")); - var url = $"{Constants.THIRDWEB_PAY_FIAT_QUOTE_ENDPOINT}?{queryStringFormatted}"; - url += buyWithFiatParams.IsTestMode ? "&isTestMode=true" : "&isTestMode=false"; - - var getResponse = await client.HttpClient.GetAsync(url); - - var content = await getResponse.Content.ReadAsStringAsync(); - - if (!getResponse.IsSuccessStatusCode) - { - ErrorResponse error; - try - { - error = JsonConvert.DeserializeObject(content); - } - catch - { - error = new ErrorResponse - { - Error = new ErrorDetails - { - Message = "Unknown error", - Reason = "Unknown", - Code = "Unknown", - Stack = "Unknown", - StatusCode = (int)getResponse.StatusCode - } - }; - } - - throw new Exception( - $"HTTP error! Code: {error.Error.Code} Message: {error.Error.Message} Reason: {error.Error.Reason} StatusCode: {error.Error.StatusCode} Stack: {error.Error.Stack}" - ); - } - - var data = JsonConvert.DeserializeObject(content); - return data.Result; - } - } -} diff --git a/Thirdweb/Thirdweb.Pay/ThirdwebPay.GetBuyWithFiatStatus.cs b/Thirdweb/Thirdweb.Pay/ThirdwebPay.GetBuyWithFiatStatus.cs deleted file mode 100644 index 88fb162a..00000000 --- a/Thirdweb/Thirdweb.Pay/ThirdwebPay.GetBuyWithFiatStatus.cs +++ /dev/null @@ -1,65 +0,0 @@ -using Newtonsoft.Json; - -namespace Thirdweb.Pay -{ - /// - /// Provides methods for processing payments with cryptocurrency and fiat. - /// - public partial class ThirdwebPay - { - /// - /// Retrieves the status of a fiat purchase using the intent ID. - /// - /// The Thirdweb client. - /// The intent ID to check the status of. - /// A task that represents the asynchronous operation. The task result contains the status result. - /// Thrown if the intent ID is null or empty. - /// Thrown if the HTTP response is not successful. - public static async Task GetBuyWithFiatStatus(ThirdwebClient client, string intentId) - { - if (string.IsNullOrEmpty(intentId)) - { - throw new ArgumentException(nameof(intentId), "Intent ID cannot be null or empty."); - } - - var queryString = new Dictionary { { "intentId", intentId } }; - - var queryStringFormatted = string.Join("&", queryString.Where(kv => kv.Value != null).Select(kv => $"{Uri.EscapeDataString(kv.Key)}={Uri.EscapeDataString(kv.Value)}")); - var url = $"{Constants.THIRDWEB_PAY_FIAT_STATUS_ENDPOINT}?{queryStringFormatted}"; - - var getResponse = await client.HttpClient.GetAsync(url); - - var content = await getResponse.Content.ReadAsStringAsync(); - - if (!getResponse.IsSuccessStatusCode) - { - ErrorResponse error; - try - { - error = JsonConvert.DeserializeObject(content); - } - catch - { - error = new ErrorResponse - { - Error = new ErrorDetails - { - Message = "Unknown error", - Reason = "Unknown", - Code = "Unknown", - Stack = "Unknown", - StatusCode = (int)getResponse.StatusCode - } - }; - } - - throw new Exception( - $"HTTP error! Code: {error.Error.Code} Message: {error.Error.Message} Reason: {error.Error.Reason} StatusCode: {error.Error.StatusCode} Stack: {error.Error.Stack}" - ); - } - - var data = JsonConvert.DeserializeObject(content); - return data.Result; - } - } -} diff --git a/Thirdweb/Thirdweb.Pay/Types.GetBuyHistory.cs b/Thirdweb/Thirdweb.Pay/Types.GetBuyHistory.cs deleted file mode 100644 index e6773aec..00000000 --- a/Thirdweb/Thirdweb.Pay/Types.GetBuyHistory.cs +++ /dev/null @@ -1,64 +0,0 @@ -using Newtonsoft.Json; - -namespace Thirdweb.Pay -{ - /// - /// Represents the response for buy history. - /// - public class BuyHistoryResponse - { - /// - /// Gets or sets the result of the buy history. - /// - [JsonProperty("result")] - public BuyHistoryResult Result { get; set; } - } - - /// - /// Represents the result of the buy history. - /// - public class BuyHistoryResult - { - /// - /// Gets or sets the wallet address. - /// - [JsonProperty("walletAddress")] - public string WalletAddress { get; set; } - - /// - /// Gets or sets the list of history pages. - /// - [JsonProperty("page")] - public List Page { get; set; } - - /// - /// Gets or sets the next cursor for pagination. - /// - [JsonProperty("nextCursor")] - public string NextCursor { get; set; } - - /// - /// Gets or sets the page size. - /// - [JsonProperty("pageSize")] - public int PageSize { get; set; } - } - - /// - /// Represents a page in the buy history. - /// - public class HistoryPage - { - /// - /// Gets or sets the status of the buy with crypto transaction. - /// - [JsonProperty("buyWithCryptoStatus")] - public BuyWithCryptoStatusResult BuyWithCryptoStatus; - - /// - /// Gets or sets the status of the buy with fiat transaction. - /// - [JsonProperty("buyWithFiatStatus")] - public BuyWithFiatStatusResult BuyWithFiatStatus; - } -} diff --git a/Thirdweb/Thirdweb.Pay/Types.GetBuyWithCryptoQuote.cs b/Thirdweb/Thirdweb.Pay/Types.GetBuyWithCryptoQuote.cs deleted file mode 100644 index b0de99e1..00000000 --- a/Thirdweb/Thirdweb.Pay/Types.GetBuyWithCryptoQuote.cs +++ /dev/null @@ -1,371 +0,0 @@ -using System.Numerics; -using Newtonsoft.Json; - -namespace Thirdweb.Pay -{ - /// - /// Parameters for getting a quote for buying with cryptocurrency. - /// - public class BuyWithCryptoQuoteParams - { - /// - /// The address from which the payment is made. - /// - [JsonProperty("fromAddress")] - public string FromAddress { get; set; } - - /// - /// The chain ID of the source token. - /// - [JsonProperty("fromChainId")] - public BigInteger? FromChainId { get; set; } - - /// - /// The address of the source token. - /// - [JsonProperty("fromTokenAddress")] - public string FromTokenAddress { get; set; } - - /// - /// The amount of the source token. - /// - [JsonProperty("fromAmount")] - public string FromAmount { get; set; } - - /// - /// The amount of the source token in wei. - /// - [JsonProperty("fromAmountWei")] - public string FromAmountWei { get; set; } - - /// - /// The chain ID of the destination token. - /// - [JsonProperty("toChainId")] - public BigInteger? ToChainId { get; set; } - - /// - /// The address of the destination token. - /// - [JsonProperty("toTokenAddress")] - public string ToTokenAddress { get; set; } - - /// - /// The amount of the destination token. - /// - [JsonProperty("toAmount")] - public string ToAmount { get; set; } - - /// - /// The amount of the destination token in wei. - /// - [JsonProperty("toAmountWei")] - public string ToAmountWei { get; set; } - - /// - /// The maximum slippage in basis points. - /// - [JsonProperty("maxSlippageBPS")] - public double? MaxSlippageBPS { get; set; } - - /// - /// The intent ID for the transaction. - /// - [JsonProperty("intentId")] - public string IntentId { get; set; } - - /// - /// Initializes a new instance of the class. - /// - public BuyWithCryptoQuoteParams( - string fromAddress, - BigInteger? fromChainId, - string fromTokenAddress, - string toTokenAddress, - string fromAmount = null, - string fromAmountWei = null, - BigInteger? toChainId = null, - string toAmount = null, - string toAmountWei = null, - double? maxSlippageBPS = null, - string intentId = null - ) - { - FromAddress = fromAddress; - FromChainId = fromChainId; - FromTokenAddress = fromTokenAddress; - FromAmount = fromAmount; - FromAmountWei = fromAmountWei; - ToChainId = toChainId; - ToTokenAddress = toTokenAddress; - ToAmount = toAmount; - ToAmountWei = toAmountWei; - MaxSlippageBPS = maxSlippageBPS; - IntentId = intentId; - } - } - - /// - /// Represents a transaction request. - /// - public class TransactionRequest - { - /// - /// Gets or sets the data of the transaction. - /// - [JsonProperty("data")] - public string Data { get; set; } - - /// - /// Gets or sets the recipient address of the transaction. - /// - [JsonProperty("to")] - public string To { get; set; } - - /// - /// Gets or sets the value of the transaction. - /// - [JsonProperty("value")] - public string Value { get; set; } - - /// - /// Gets or sets the sender address of the transaction. - /// - [JsonProperty("from")] - public string From { get; set; } - - /// - /// Gets or sets the chain ID of the transaction. - /// - [JsonProperty("chainId")] - public BigInteger ChainId { get; set; } - - /// - /// Gets or sets the gas price of the transaction. - /// - [JsonProperty("gasPrice")] - public string GasPrice { get; set; } - - /// - /// Gets or sets the gas limit of the transaction. - /// - [JsonProperty("gasLimit")] - public string GasLimit { get; set; } - } - - /// - /// Represents an approval request. - /// - public class Approval - { - /// - /// Gets or sets the chain ID of the approval request. - /// - [JsonProperty("chainId")] - public BigInteger ChainId { get; set; } - - /// - /// Gets or sets the token address for the approval request. - /// - [JsonProperty("tokenAddress")] - public string TokenAddress { get; set; } - - /// - /// Gets or sets the spender address for the approval request. - /// - [JsonProperty("spenderAddress")] - public string SpenderAddress { get; set; } - - /// - /// Gets or sets the amount in wei for the approval request. - /// - [JsonProperty("amountWei")] - public string AmountWei { get; set; } - } - - /// - /// Represents a payment token. - /// - public class PaymentToken - { - /// - /// Gets or sets the token details. - /// - [JsonProperty("token")] - public Token Token { get; set; } - - /// - /// Gets or sets the amount in wei. - /// - [JsonProperty("amountWei")] - public string AmountWei { get; set; } - - /// - /// Gets or sets the amount. - /// - [JsonProperty("amount")] - public string Amount { get; set; } - - /// - /// Gets or sets the amount in USD cents. - /// - [JsonProperty("amountUSDCents")] - public double AmountUSDCents { get; set; } - } - - /// - /// Represents a processing fee. - /// - public class ProcessingFee - { - /// - /// Gets or sets the token details. - /// - [JsonProperty("token")] - public Token Token { get; set; } - - /// - /// Gets or sets the amount in wei. - /// - [JsonProperty("amountWei")] - public string AmountWei { get; set; } - - /// - /// Gets or sets the amount. - /// - [JsonProperty("amount")] - public string Amount { get; set; } - - /// - /// Gets or sets the amount in USD cents. - /// - [JsonProperty("amountUSDCents")] - public double AmountUSDCents { get; set; } - } - - /// - /// Represents the result of a quote for buying with cryptocurrency. - /// - public class BuyWithCryptoQuoteResult - { - /// - /// Gets or sets the quote ID. - /// - [JsonProperty("quoteId")] - public string QuoteId { get; set; } - - /// - /// Gets or sets the transaction request. - /// - [JsonProperty("transactionRequest")] - public TransactionRequest TransactionRequest { get; set; } - - /// - /// Gets or sets the approval details. - /// - [JsonProperty("approval")] - public Approval Approval { get; set; } - - /// - /// Gets or sets the address from which the payment is made. - /// - [JsonProperty("fromAddress")] - public string FromAddress { get; set; } - - /// - /// Gets or sets the recipient address. - /// - [JsonProperty("toAddress")] - public string ToAddress { get; set; } - - /// - /// Gets or sets the details of the source token. - /// - [JsonProperty("fromToken")] - public Token FromToken { get; set; } - - /// - /// Gets or sets the details of the destination token. - /// - [JsonProperty("toToken")] - public Token ToToken { get; set; } - - /// - /// Gets or sets the amount of the source token in wei. - /// - [JsonProperty("fromAmountWei")] - public string FromAmountWei { get; set; } - - /// - /// Gets or sets the amount of the source token. - /// - [JsonProperty("fromAmount")] - public string FromAmount { get; set; } - - /// - /// Gets or sets the minimum amount of the destination token in wei. - /// - [JsonProperty("toAmountMinWei")] - public string ToAmountMinWei { get; set; } - - /// - /// Gets or sets the minimum amount of the destination token. - /// - [JsonProperty("toAmountMin")] - public string ToAmountMin { get; set; } - - /// - /// Gets or sets the amount of the destination token in wei. - /// - [JsonProperty("toAmountWei")] - public string ToAmountWei { get; set; } - - /// - /// Gets or sets the amount of the destination token. - /// - [JsonProperty("toAmount")] - public string ToAmount { get; set; } - - /// - /// Gets or sets the list of payment tokens. - /// - [JsonProperty("paymentTokens")] - public List PaymentTokens { get; set; } - - /// - /// Gets or sets the list of processing fees. - /// - [JsonProperty("processingFees")] - public List ProcessingFees { get; set; } - - /// - /// Gets or sets the estimated details. - /// - [JsonProperty("estimated")] - public Estimated Estimated { get; set; } - - /// - /// Gets or sets the maximum slippage in basis points. - /// - [JsonProperty("maxSlippageBPS")] - public double MaxSlippageBPS { get; set; } - - /// - /// Gets or sets the bridge details. - /// - [JsonProperty("bridge")] - public string Bridge { get; set; } - } - - /// - /// Represents the response for getting a swap quote. - /// - public class GetSwapQuoteResponse - { - /// - /// Gets or sets the result of the swap quote. - /// - [JsonProperty("result")] - public BuyWithCryptoQuoteResult Result { get; set; } - } -} diff --git a/Thirdweb/Thirdweb.Pay/Types.GetBuyWithCryptoStatus.cs b/Thirdweb/Thirdweb.Pay/Types.GetBuyWithCryptoStatus.cs deleted file mode 100644 index a477e23d..00000000 --- a/Thirdweb/Thirdweb.Pay/Types.GetBuyWithCryptoStatus.cs +++ /dev/null @@ -1,263 +0,0 @@ -using Newtonsoft.Json; - -namespace Thirdweb.Pay -{ - /// - /// Represents the response for a swap status. - /// - public class SwapStatusResponse - { - /// - /// Gets or sets the result of the swap status. - /// - [JsonProperty("result")] - public BuyWithCryptoStatusResult Result { get; set; } - } - - /// - /// Represents the status result of buying with cryptocurrency. - /// - public class BuyWithCryptoStatusResult - { - /// - /// Gets or sets the swap quote details. - /// - [JsonProperty("quote")] - public SwapQuote Quote { get; set; } - - /// - /// Gets or sets the type of swap. - /// - [JsonProperty("swapType")] - public string SwapType { get; set; } - - /// - /// Gets or sets the source transaction details. - /// - [JsonProperty("source")] - public TransactionDetails Source { get; set; } - - /// - /// Gets or sets the destination transaction details. - /// - [JsonProperty("destination")] - public TransactionDetails Destination { get; set; } - - /// - /// Gets or sets the status of the swap. - /// - [JsonProperty("status")] - public string Status { get; set; } - - /// - /// Gets or sets the sub-status of the swap. - /// - [JsonProperty("subStatus")] - public string SubStatus { get; set; } - - /// - /// Gets or sets the address from which the swap is initiated. - /// - [JsonProperty("fromAddress")] - public string FromAddress { get; set; } - - /// - /// Gets or sets the recipient address. - /// - [JsonProperty("toAddress")] - public string ToAddress { get; set; } - - /// - /// Gets or sets the failure message if the swap fails. - /// - [JsonProperty("failureMessage")] - public string FailureMessage { get; set; } - - /// - /// Gets or sets the bridge details. - /// - [JsonProperty("bridge")] - public string Bridge { get; set; } - } - - /// - /// Represents the transaction details. - /// - public class TransactionDetails - { - /// - /// Gets or sets the transaction hash. - /// - [JsonProperty("transactionHash")] - public string TransactionHash { get; set; } - - /// - /// Gets or sets the token details. - /// - [JsonProperty("token")] - public Token Token { get; set; } - - /// - /// Gets or sets the amount of the token. - /// - [JsonProperty("amount")] - public string Amount { get; set; } - - /// - /// Gets or sets the amount of the token in wei. - /// - [JsonProperty("amountWei")] - public string AmountWei { get; set; } - - /// - /// Gets or sets the amount in USD cents. - /// - [JsonProperty("amountUSDCents")] - public double AmountUSDCents { get; set; } - - /// - /// Gets or sets the completion date of the transaction. - /// - [JsonProperty("completedAt")] - public DateTime CompletedAt { get; set; } - - /// - /// Gets or sets the explorer link for the transaction. - /// - [JsonProperty("explorerLink")] - public string ExplorerLink { get; set; } - } - - /// - /// Represents a swap quote. - /// - public class SwapQuote - { - /// - /// Gets or sets the source token details. - /// - [JsonProperty("fromToken")] - public Token FromToken { get; set; } - - /// - /// Gets or sets the destination token details. - /// - [JsonProperty("toToken")] - public Token ToToken { get; set; } - - /// - /// Gets or sets the amount of the source token in wei. - /// - [JsonProperty("fromAmountWei")] - public string FromAmountWei { get; set; } - - /// - /// Gets or sets the amount of the source token. - /// - [JsonProperty("fromAmount")] - public string FromAmount { get; set; } - - /// - /// Gets or sets the amount of the destination token in wei. - /// - [JsonProperty("toAmountWei")] - public string ToAmountWei { get; set; } - - /// - /// Gets or sets the amount of the destination token. - /// - [JsonProperty("toAmount")] - public string ToAmount { get; set; } - - /// - /// Gets or sets the minimum amount of the destination token. - /// - [JsonProperty("toAmountMin")] - public string ToAmountMin { get; set; } - - /// - /// Gets or sets the minimum amount of the destination token in wei. - /// - [JsonProperty("toAmountMinWei")] - public string ToAmountMinWei { get; set; } - - /// - /// Gets or sets the estimated details. - /// - [JsonProperty("estimated")] - public Estimated Estimated { get; set; } - - /// - /// Gets or sets the creation date of the swap quote. - /// - [JsonProperty("createdAt")] - public DateTime CreatedAt { get; set; } - } - - /// - /// Represents the swap status. - /// - public enum SwapStatus - { - /// - /// Status when the swap is not found. - /// - NOT_FOUND, - - /// - /// Status when there is no swap. - /// - NONE, - - /// - /// Status when the swap is pending. - /// - PENDING, - - /// - /// Status when the swap has failed. - /// - FAILED, - - /// - /// Status when the swap is completed. - /// - COMPLETED - } - - /// - /// Represents the swap sub-status. - /// - public enum SwapSubStatus - { - /// - /// Sub-status when there is no specific sub-status. - /// - NONE, - - /// - /// Sub-status when waiting for the bridge. - /// - WAITING_BRIDGE, - - /// - /// Sub-status when the swap is reverted on chain. - /// - REVERTED_ON_CHAIN, - - /// - /// Sub-status when the swap is successful. - /// - SUCCESS, - - /// - /// Sub-status when the swap is partially successful. - /// - PARTIAL_SUCCESS, - - /// - /// Sub-status when there is an unknown error. - /// - UNKNOWN_ERROR - } -} diff --git a/Thirdweb/Thirdweb.Pay/Types.GetBuyWithFiatCurrencies.cs b/Thirdweb/Thirdweb.Pay/Types.GetBuyWithFiatCurrencies.cs deleted file mode 100644 index 7b91adff..00000000 --- a/Thirdweb/Thirdweb.Pay/Types.GetBuyWithFiatCurrencies.cs +++ /dev/null @@ -1,28 +0,0 @@ -using Newtonsoft.Json; - -namespace Thirdweb.Pay -{ - /// - /// Represents the response for fiat currencies. - /// - public class FiatCurrenciesResponse - { - /// - /// Gets or sets the result of the fiat currencies response. - /// - [JsonProperty("result")] - public FiatCurrenciesResult Result { get; set; } - } - - /// - /// Represents the result containing the list of fiat currencies. - /// - public class FiatCurrenciesResult - { - /// - /// Gets or sets the list of fiat currencies. - /// - [JsonProperty("fiatCurrencies")] - public List FiatCurrencies { get; set; } - } -} diff --git a/Thirdweb/Thirdweb.Pay/Types.GetBuyWithFiatQuote.cs b/Thirdweb/Thirdweb.Pay/Types.GetBuyWithFiatQuote.cs deleted file mode 100644 index 41142415..00000000 --- a/Thirdweb/Thirdweb.Pay/Types.GetBuyWithFiatQuote.cs +++ /dev/null @@ -1,254 +0,0 @@ -using Newtonsoft.Json; - -namespace Thirdweb.Pay -{ - /// - /// Parameters for getting a quote for buying with fiat. - /// - public class BuyWithFiatQuoteParams - { - /// - /// The symbol of the currency to be used for the purchase. - /// - [JsonProperty("fromCurrencySymbol")] - public string FromCurrencySymbol { get; set; } - - /// - /// The amount of the currency to be used for the purchase. - /// - [JsonProperty("fromAmount")] - public string FromAmount { get; set; } - - /// - /// The units of the currency amount. - /// - [JsonProperty("fromAmountUnits")] - public string FromAmountUnits { get; set; } - - /// - /// The address to receive the purchased tokens. - /// - [JsonProperty("toAddress")] - public string ToAddress { get; set; } - - /// - /// The chain ID of the destination token. - /// - [JsonProperty("toChainId")] - public string ToChainId { get; set; } - - /// - /// The address of the destination token. - /// - [JsonProperty("toTokenAddress")] - public string ToTokenAddress { get; set; } - - /// - /// The amount of the destination token. - /// - [JsonProperty("toAmount")] - public string ToAmount { get; set; } - - /// - /// The amount of the destination token in wei. - /// - [JsonProperty("toAmountWei")] - public string ToAmountWei { get; set; } - - /// - /// The maximum slippage in basis points. - /// - [JsonProperty("maxSlippageBPS")] - public double? MaxSlippageBPS { get; set; } - - /// - /// Indicates whether the transaction is in test mode. - /// - [JsonProperty("isTestMode")] - public bool IsTestMode { get; set; } - - /// - /// Initializes a new instance of the class. - /// - public BuyWithFiatQuoteParams( - string fromCurrencySymbol, - string toAddress, - string toChainId, - string toTokenAddress, - string fromAmount = null, - string fromAmountUnits = null, - string toAmount = null, - string toAmountWei = null, - double? maxSlippageBPS = null, - bool isTestMode = false - ) - { - FromCurrencySymbol = fromCurrencySymbol; - FromAmount = fromAmount; - FromAmountUnits = fromAmountUnits; - ToAddress = toAddress; - ToChainId = toChainId; - ToTokenAddress = toTokenAddress; - ToAmount = toAmount; - ToAmountWei = toAmountWei; - MaxSlippageBPS = maxSlippageBPS; - IsTestMode = isTestMode; - } - } - - /// - /// Represents the result of a quote for buying with fiat. - /// - public class BuyWithFiatQuoteResult - { - /// - /// Gets or sets the intent ID of the quote. - /// - [JsonProperty("intentId")] - public string IntentId { get; set; } - - /// - /// Gets or sets the recipient address. - /// - [JsonProperty("toAddress")] - public string ToAddress { get; set; } - - /// - /// Gets or sets the details of the source currency. - /// - [JsonProperty("fromCurrency")] - public OnRampCurrency FromCurrency { get; set; } - - /// - /// Gets or sets the details of the source currency including fees. - /// - [JsonProperty("fromCurrencyWithFees")] - public OnRampCurrency FromCurrencyWithFees { get; set; } - - /// - /// Gets or sets the on-ramp token details. - /// - [JsonProperty("onRampToken")] - public OnRampToken OnRampToken { get; set; } - - /// - /// Gets or sets the details of the destination token. - /// - [JsonProperty("toToken")] - public Token ToToken { get; set; } - - /// - /// Gets or sets the estimated minimum amount of the destination token in wei. - /// - [JsonProperty("estimatedToAmountMinWei")] - public string EstimatedToAmountMinWei { get; set; } - - /// - /// Gets or sets the estimated minimum amount of the destination token. - /// - [JsonProperty("estimatedToAmountMin")] - public string EstimatedToAmountMin { get; set; } - - /// - /// Gets or sets the list of processing fees. - /// - [JsonProperty("processingFees")] - public List ProcessingFees { get; set; } - - /// - /// Gets or sets the estimated duration of the transaction in seconds. - /// - [JsonProperty("estimatedDurationSeconds")] - public string EstimatedDurationSeconds { get; set; } - - /// - /// Gets or sets the maximum slippage in basis points. - /// - [JsonProperty("maxSlippageBPS")] - public double MaxSlippageBPS { get; set; } - - /// - /// Gets or sets the on-ramp link for the transaction. - /// - [JsonProperty("onRampLink")] - public string OnRampLink { get; set; } - } - - /// - /// Represents an on-ramp token. - /// - public class OnRampToken - { - /// - /// Gets or sets the token details. - /// - [JsonProperty("token")] - public Token Token { get; set; } - - /// - /// Gets or sets the amount in wei. - /// - [JsonProperty("amountWei")] - public string AmountWei { get; set; } - - /// - /// Gets or sets the amount. - /// - [JsonProperty("amount")] - public string Amount { get; set; } - - /// - /// Gets or sets the amount in USD cents. - /// - [JsonProperty("amountUSDCents")] - public double AmountUSDCents { get; set; } - } - - /// - /// Represents on-ramp fees. - /// - public class OnRampFees - { - /// - /// Gets or sets the fee amount. - /// - [JsonProperty("amount")] - public string Amount { get; set; } - - /// - /// Gets or sets the units of the fee amount. - /// - [JsonProperty("amountUnits")] - public string AmountUnits { get; set; } - - /// - /// Gets or sets the number of decimals for the fee amount. - /// - [JsonProperty("decimals")] - public int Decimals { get; set; } - - /// - /// Gets or sets the currency symbol for the fee. - /// - [JsonProperty("currencySymbol")] - public string CurrencySymbol { get; set; } - - /// - /// Gets or sets the type of the fee. - /// - [JsonProperty("feeType")] - public string FeeType { get; set; } - } - - /// - /// Represents the response for getting a fiat quote. - /// - public class GetFiatQuoteResponse - { - /// - /// Gets or sets the result of the fiat quote. - /// - [JsonProperty("result")] - public BuyWithFiatQuoteResult Result { get; set; } - } -} diff --git a/Thirdweb/Thirdweb.Pay/Types.GetBuyWithFiatStatus.cs b/Thirdweb/Thirdweb.Pay/Types.GetBuyWithFiatStatus.cs deleted file mode 100644 index 9c5272b5..00000000 --- a/Thirdweb/Thirdweb.Pay/Types.GetBuyWithFiatStatus.cs +++ /dev/null @@ -1,196 +0,0 @@ -using Newtonsoft.Json; - -namespace Thirdweb.Pay -{ - /// - /// Represents the response for an on-ramp status. - /// - public class OnRampStatusResponse - { - /// - /// Gets or sets the result of the on-ramp status. - /// - [JsonProperty("result")] - public BuyWithFiatStatusResult Result { get; set; } - } - - /// - /// Represents the status result of buying with fiat. - /// - public class BuyWithFiatStatusResult - { - /// - /// Gets or sets the intent ID of the transaction. - /// - [JsonProperty("intentId")] - public string IntentId { get; set; } - - /// - /// Gets or sets the status of the transaction. - /// - [JsonProperty("status")] - public string Status { get; set; } - - /// - /// Gets or sets the recipient address. - /// - [JsonProperty("toAddress")] - public string ToAddress { get; set; } - - /// - /// Gets or sets the quote details for the on-ramp transaction. - /// - [JsonProperty("quote")] - public OnRampQuote Quote { get; set; } - - /// - /// Gets or sets the source transaction details. - /// - [JsonProperty("source")] - public TransactionDetails Source { get; set; } - - /// - /// Gets or sets the destination transaction details. - /// - [JsonProperty("destination")] - public TransactionDetails Destination { get; set; } - - /// - /// Gets or sets the failure message if the transaction fails. - /// - [JsonProperty("failureMessage")] - public string FailureMessage { get; set; } - } - - /// - /// Represents a quote for an on-ramp transaction. - /// - public class OnRampQuote - { - /// - /// Gets or sets the creation date of the quote. - /// - [JsonProperty("createdAt")] - public string CreatedAt { get; set; } - - /// - /// Gets or sets the estimated amount for the on-ramp transaction in wei. - /// - [JsonProperty("estimatedOnRampAmountWei")] - public string EstimatedOnRampAmountWei { get; set; } - - /// - /// Gets or sets the estimated amount for the on-ramp transaction. - /// - [JsonProperty("estimatedOnRampAmount")] - public string EstimatedOnRampAmount { get; set; } - - /// - /// Gets or sets the estimated amount of the destination token. - /// - [JsonProperty("estimatedToTokenAmount")] - public string EstimatedToTokenAmount { get; set; } - - /// - /// Gets or sets the estimated amount of the destination token in wei. - /// - [JsonProperty("estimatedToTokenAmountWei")] - public string EstimatedToTokenAmountWei { get; set; } - - /// - /// Gets or sets the details of the source currency. - /// - [JsonProperty("fromCurrency")] - public OnRampCurrency FromCurrency { get; set; } - - /// - /// Gets or sets the details of the source currency including fees. - /// - [JsonProperty("fromCurrencyWithFees")] - public OnRampCurrency FromCurrencyWithFees { get; set; } - - /// - /// Gets or sets the on-ramp token details. - /// - [JsonProperty("onRampToken")] - public Token OnRampToken { get; set; } - - /// - /// Gets or sets the details of the destination token. - /// - [JsonProperty("toToken")] - public Token ToToken { get; set; } - - /// - /// Gets or sets the estimated duration of the transaction in seconds. - /// - [JsonProperty("estimatedDurationSeconds")] - public long EstimatedDurationSeconds { get; set; } - } - - /// - /// Represents the various statuses of an on-ramp transaction. - /// - public enum OnRampStatus - { - /// - /// No status. - /// - NONE, - - /// - /// Payment is pending. - /// - PENDING_PAYMENT, - - /// - /// Payment has failed. - /// - PAYMENT_FAILED, - - /// - /// Pending on-ramp transfer. - /// - PENDING_ON_RAMP_TRANSFER, - - /// - /// On-ramp transfer is in progress. - /// - ON_RAMP_TRANSFER_IN_PROGRESS, - - /// - /// On-ramp transfer is completed. - /// - ON_RAMP_TRANSFER_COMPLETED, - - /// - /// On-ramp transfer has failed. - /// - ON_RAMP_TRANSFER_FAILED, - - /// - /// Crypto swap is required. - /// - CRYPTO_SWAP_REQUIRED, - - /// - /// Crypto swap is completed. - /// - CRYPTO_SWAP_COMPLETED, - - /// - /// Crypto swap fallback. - /// - CRYPTO_SWAP_FALLBACK, - - /// - /// Crypto swap is in progress. - /// - CRYPTO_SWAP_IN_PROGRESS, - - /// - /// Crypto swap has failed. - /// - CRYPTO_SWAP_FAILED, - } -} diff --git a/Thirdweb/Thirdweb.Pay/Types.Shared.cs b/Thirdweb/Thirdweb.Pay/Types.Shared.cs deleted file mode 100644 index e15673d3..00000000 --- a/Thirdweb/Thirdweb.Pay/Types.Shared.cs +++ /dev/null @@ -1,194 +0,0 @@ -using System.Numerics; -using Newtonsoft.Json; - -namespace Thirdweb.Pay -{ - /// - /// Represents the error response. - /// - public class ErrorResponse - { - /// - /// Gets or sets the error details. - /// - [JsonProperty("error")] - public ErrorDetails Error { get; set; } - } - - /// - /// Represents the details of an error. - /// - public class ErrorDetails - { - /// - /// Gets or sets the error message. - /// - [JsonProperty("message")] - public string Message { get; set; } - - /// - /// Gets or sets the reason for the error. - /// - [JsonProperty("reason")] - public string Reason { get; set; } - - /// - /// Gets or sets the error code. - /// - [JsonProperty("code")] - public string Code { get; set; } - - /// - /// Gets or sets the error stack trace. - /// - [JsonProperty("stack")] - public string Stack { get; set; } - - /// - /// Gets or sets the status code of the error. - /// - [JsonProperty("statusCode")] - public int StatusCode { get; set; } - } - - /// - /// Represents a token. - /// - public class Token - { - /// - /// Gets or sets the chain ID of the token. - /// - [JsonProperty("chainId")] - public BigInteger ChainId { get; set; } - - /// - /// Gets or sets the address of the token. - /// - [JsonProperty("tokenAddress")] - public string TokenAddress { get; set; } - - /// - /// Gets or sets the number of decimals of the token. - /// - [JsonProperty("decimals")] - public int Decimals { get; set; } - - /// - /// Gets or sets the price of the token in USD cents. - /// - [JsonProperty("priceUSDCents")] - public int PriceUSDCents { get; set; } - - /// - /// Gets or sets the name of the token. - /// - [JsonProperty("name")] - public string Name { get; set; } - - /// - /// Gets or sets the symbol of the token. - /// - [JsonProperty("symbol")] - public string Symbol { get; set; } - } - - /// - /// Represents the estimated details for a transaction. - /// - public class Estimated - { - /// - /// Gets or sets the amount in USD cents for the source token. - /// - [JsonProperty("fromAmountUSDCents")] - public double FromAmountUSDCents { get; set; } - - /// - /// Gets or sets the minimum amount in USD cents for the destination token. - /// - [JsonProperty("toAmountMinUSDCents")] - public double ToAmountMinUSDCents { get; set; } - - /// - /// Gets or sets the amount in USD cents for the destination token. - /// - [JsonProperty("toAmountUSDCents")] - public double ToAmountUSDCents { get; set; } - - /// - /// Gets or sets the slippage in basis points. - /// - [JsonProperty("slippageBPS")] - public int SlippageBPS { get; set; } - - /// - /// Gets or sets the fees in USD cents. - /// - [JsonProperty("feesUSDCents")] - public double FeesUSDCents { get; set; } - - /// - /// Gets or sets the gas cost in USD cents. - /// - [JsonProperty("gasCostUSDCents")] - public double GasCostUSDCents { get; set; } - - /// - /// Gets or sets the duration of the transaction in seconds. - /// - [JsonProperty("durationSeconds")] - public int DurationSeconds { get; set; } - } - - /// - /// Represents the currency details for an on-ramp transaction. - /// - public class OnRampCurrency - { - /// - /// Gets or sets the amount of the currency. - /// - [JsonProperty("amount")] - public string Amount { get; set; } - - /// - /// Gets or sets the units of the currency amount. - /// - [JsonProperty("amountUnits")] - public string AmountUnits { get; set; } - - /// - /// Gets or sets the number of decimals for the currency. - /// - [JsonProperty("decimals")] - public int Decimals { get; set; } - - /// - /// Gets or sets the symbol of the currency. - /// - [JsonProperty("currencySymbol")] - public string CurrencySymbol { get; set; } - } - - /// - /// Represents the different types of swaps. - /// - public enum SwapType - { - /// - /// Swap on the same chain. - /// - SAME_CHAIN, - - /// - /// Swap across different chains. - /// - CROSS_CHAIN, - - /// - /// On-ramp swap. - /// - ON_RAMP - } -} diff --git a/Thirdweb/Thirdweb.RPC/RpcError.cs b/Thirdweb/Thirdweb.RPC/RpcError.cs deleted file mode 100644 index eb982666..00000000 --- a/Thirdweb/Thirdweb.RPC/RpcError.cs +++ /dev/null @@ -1,28 +0,0 @@ -using Newtonsoft.Json; - -namespace Thirdweb -{ - /// - /// Represents an error returned from an RPC call. - /// - public class RpcError - { - /// - /// Gets or sets the error code. - /// - [JsonProperty("code")] - public int Code { get; set; } - - /// - /// Gets or sets the error message. - /// - [JsonProperty("message")] - public string Message { get; set; } - - /// - /// Gets or sets additional data about the error. - /// - [JsonProperty("data")] - public string Data { get; set; } - } -} diff --git a/Thirdweb/Thirdweb.RPC/RpcRequest.cs b/Thirdweb/Thirdweb.RPC/RpcRequest.cs deleted file mode 100644 index d39c7d4a..00000000 --- a/Thirdweb/Thirdweb.RPC/RpcRequest.cs +++ /dev/null @@ -1,34 +0,0 @@ -using Newtonsoft.Json; - -namespace Thirdweb -{ - /// - /// Represents an RPC request. - /// - public class RpcRequest - { - /// - /// Gets or sets the JSON-RPC version. - /// - [JsonProperty("jsonrpc")] - public string Jsonrpc { get; set; } = "2.0"; - - /// - /// Gets or sets the method name for the RPC request. - /// - [JsonProperty("method")] - public string Method { get; set; } - - /// - /// Gets or sets the parameters for the RPC request. - /// - [JsonProperty("params")] - public object[] Params { get; set; } - - /// - /// Gets or sets the ID of the RPC request. - /// - [JsonProperty("id")] - public int Id { get; set; } - } -} diff --git a/Thirdweb/Thirdweb.RPC/RpcResponse.cs b/Thirdweb/Thirdweb.RPC/RpcResponse.cs deleted file mode 100644 index a9f74391..00000000 --- a/Thirdweb/Thirdweb.RPC/RpcResponse.cs +++ /dev/null @@ -1,35 +0,0 @@ -using Newtonsoft.Json; - -namespace Thirdweb -{ - /// - /// Represents a response from an RPC call. - /// - /// The type of the result. - public class RpcResponse - { - /// - /// Gets or sets the JSON-RPC version. - /// - [JsonProperty("jsonrpc")] - public string Jsonrpc { get; set; } - - /// - /// Gets or sets the ID of the RPC request. - /// - [JsonProperty("id")] - public int Id { get; set; } - - /// - /// Gets or sets the result of the RPC call. - /// - [JsonProperty("result")] - public T Result { get; set; } - - /// - /// Gets or sets the error details if the RPC call fails. - /// - [JsonProperty("error")] - public RpcError Error { get; set; } - } -} diff --git a/Thirdweb/Thirdweb.RPC/ThirdwebRPC.Types.cs b/Thirdweb/Thirdweb.RPC/ThirdwebRPC.Types.cs new file mode 100644 index 00000000..98f4b1dc --- /dev/null +++ b/Thirdweb/Thirdweb.RPC/ThirdwebRPC.Types.cs @@ -0,0 +1,147 @@ +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; + +namespace Thirdweb; + +[JsonObject] +public class RpcError +{ + [JsonConstructor] + private RpcError() { } + + [JsonProperty("code")] + public int Code { get; private set; } + + [JsonProperty("message")] + public string Message { get; private set; } + + [JsonProperty("data")] + public JToken Data { get; private set; } +} + +[JsonObject] +public class RpcResponseMessage +{ + [JsonProperty("id")] + public object Id { get; private set; } + + [JsonProperty("jsonrpc")] + public string JsonRpcVersion { get; private set; } + + [JsonProperty("result")] + public JToken Result { get; private set; } + + [JsonProperty("error")] + public RpcError Error { get; protected set; } + + [JsonIgnore] + public bool HasError => this.Error != null; +} + +public class RpcResponse +{ + [JsonProperty("jsonrpc")] + public string Jsonrpc { get; set; } + + [JsonProperty("id")] + public int Id { get; set; } + + [JsonProperty("result")] + public T Result { get; set; } + + [JsonProperty("error")] + public RpcError Error { get; set; } +} + +public class RpcRequest +{ + [JsonProperty("jsonrpc")] + public string Jsonrpc { get; set; } = "2.0"; + + [JsonProperty("method")] + public string Method { get; set; } + + [JsonProperty("params")] + public object[] Params { get; set; } + + [JsonProperty("id")] + public int Id { get; set; } +} + +[JsonObject] +public class RpcRequestMessage +{ + [JsonConstructor] + private RpcRequestMessage() { } + + public RpcRequestMessage(object id, string method, params object[] parameterList) + { + this.Id = id; + this.JsonRpcVersion = "2.0"; + this.Method = method; + this.RawParameters = parameterList; + } + + [JsonProperty("id")] + public object Id { get; set; } + + [JsonProperty("jsonrpc")] + public string JsonRpcVersion { get; private set; } + + [JsonProperty("method")] + public string Method { get; private set; } + + [JsonProperty("params")] + [JsonConverter(typeof(RpcParameterJsonConverter))] + public object RawParameters { get; private set; } +} + +public class RpcParameterJsonConverter : JsonConverter +{ + public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + { + serializer.Serialize(writer, value); + } + + public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + { + switch (reader.TokenType) + { + case JsonToken.StartObject: + try + { + var jObject = JObject.Load(reader); + return jObject.ToObject>(); + } + catch (Exception) + { + throw new Exception("Request parameters can only be an associative array, list or null."); + } + case JsonToken.StartArray: + return JArray.Load(reader).ToObject(serializer); + case JsonToken.Null: + case JsonToken.None: + case JsonToken.StartConstructor: + case JsonToken.PropertyName: + case JsonToken.Comment: + case JsonToken.Raw: + case JsonToken.Integer: + case JsonToken.Float: + case JsonToken.String: + case JsonToken.Boolean: + case JsonToken.Undefined: + case JsonToken.EndObject: + case JsonToken.EndArray: + case JsonToken.EndConstructor: + case JsonToken.Date: + case JsonToken.Bytes: + default: + throw new Exception("Request parameters can only be an associative array, list or null."); + } + } + + public override bool CanConvert(Type objectType) + { + return true; + } +} diff --git a/Thirdweb/Thirdweb.RPC/ThirdwebRPC.cs b/Thirdweb/Thirdweb.RPC/ThirdwebRPC.cs index db1bc22c..b0dda211 100644 --- a/Thirdweb/Thirdweb.RPC/ThirdwebRPC.cs +++ b/Thirdweb/Thirdweb.RPC/ThirdwebRPC.cs @@ -1,265 +1,309 @@ -using System.Numerics; +using System.Collections.Concurrent; +using System.Numerics; using System.Text; using Newtonsoft.Json; +using Newtonsoft.Json.Linq; -namespace Thirdweb +[assembly: System.Runtime.CompilerServices.InternalsVisibleTo("Thirdweb.Tests")] + +namespace Thirdweb; + +/// +/// Represents the Thirdweb RPC client for sending requests and handling responses. +/// +public class ThirdwebRPC : IDisposable { + internal Uri RpcUrl { get; } + + private const int BatchSizeLimit = 100; + private readonly TimeSpan _batchInterval = TimeSpan.FromMilliseconds(50); + + private readonly TimeSpan _rpcTimeout; + private readonly Dictionary _cache = new(); + private readonly TimeSpan _cacheDuration = TimeSpan.FromMilliseconds(25); + private readonly ConcurrentQueue _pendingRequests = new(); + private readonly Dictionary> _responseCompletionSources = new(); + private readonly object _responseLock = new(); + private readonly object _cacheLock = new(); + private readonly CancellationTokenSource _cancellationTokenSource = new(); + + private int _requestIdCounter = 1; + + private static readonly Dictionary _rpcs = new(); + + private readonly IThirdwebHttpClient _httpClient; + /// - /// Represents the Thirdweb RPC client for sending requests and handling responses. + /// Gets an instance of the ThirdwebRPC client for the specified ThirdwebClient and chain ID. /// - public class ThirdwebRPC + /// The Thirdweb client. + /// The chain ID. + /// An instance of the ThirdwebRPC client. + /// Thrown if the client is null. + /// Thrown if the chain ID is invalid. + public static ThirdwebRPC GetRpcInstance(ThirdwebClient client, BigInteger chainId) { - private const int _batchSizeLimit = 100; - private readonly TimeSpan _batchInterval = TimeSpan.FromMilliseconds(100); - - private readonly Uri _rpcUrl; - private readonly TimeSpan _rpcTimeout; - private readonly Dictionary _cache = new(); - private readonly TimeSpan _cacheDuration = TimeSpan.FromMilliseconds(250); - private readonly List _pendingBatch = new(); - private readonly Dictionary> _responseCompletionSources = new(); - private readonly object _batchLock = new(); - private readonly object _responseLock = new(); - private readonly object _cacheLock = new(); - private readonly ThirdwebRPCTimer _batchTimer; - - private int _requestIdCounter = 1; - - private static readonly Dictionary _rpcs = new(); - - private readonly IThirdwebHttpClient _httpClient; - - /// - /// Gets an instance of the ThirdwebRPC client for the specified ThirdwebClient and chain ID. - /// - /// The Thirdweb client. - /// The chain ID. - /// An instance of the ThirdwebRPC client. - /// Thrown if the client is null. - /// Thrown if the chain ID is invalid. - public static ThirdwebRPC GetRpcInstance(ThirdwebClient client, BigInteger chainId) + if (client == null) { - if (client == null) - { - throw new ArgumentNullException(nameof(client)); - } - - if (chainId == 0) - { - throw new ArgumentException("Invalid Chain ID"); - } - - var key = $"{client.ClientId}_{chainId}_{client.FetchTimeoutOptions.GetTimeout(TimeoutType.Rpc)}"; + throw new ArgumentNullException(nameof(client)); + } - if (!_rpcs.ContainsKey(key)) - { - lock (_rpcs) - { - if (!_rpcs.ContainsKey(key)) - { - _rpcs[key] = new ThirdwebRPC(client, chainId); - } - } - } + if (chainId == 0) + { + throw new ArgumentException("Invalid Chain ID"); + } - return _rpcs[key]; + string key; + if (client.RpcOverrides != null && client.RpcOverrides.TryGetValue(chainId, out var rpcOverride)) + { + key = $"{client.ClientId}_{chainId}_{rpcOverride}_{client.FetchTimeoutOptions.GetTimeout(TimeoutType.Rpc)}"; + } + else + { + key = $"{client.ClientId}_{chainId}_{client.FetchTimeoutOptions.GetTimeout(TimeoutType.Rpc)}"; } - /// - /// Sends an RPC request asynchronously and returns the response. - /// - /// The type of the response. - /// The RPC method name. - /// The parameters for the RPC request. - /// The RPC response. - /// Thrown if the response cannot be deserialized. - public async Task SendRequestAsync(string method, params object[] parameters) + if (!_rpcs.ContainsKey(key)) { - lock (_cacheLock) + lock (_rpcs) { - var cacheKey = GetCacheKey(method, parameters); - if (_cache.TryGetValue(cacheKey, out var cachedItem) && (DateTime.Now - cachedItem.Timestamp) < _cacheDuration) + if (!_rpcs.ContainsKey(key)) { - return (TResponse)cachedItem.Response; + _rpcs[key] = new ThirdwebRPC(client, chainId); } } + } - var tcs = new TaskCompletionSource(); - int requestId; - - lock (_batchLock) - { - requestId = _requestIdCounter++; - _pendingBatch.Add( - new RpcRequest - { - Method = method, - Params = parameters, - Id = requestId - } - ); - lock (_responseLock) - { - _responseCompletionSources.Add(requestId, tcs); - } - - if (_pendingBatch.Count >= _batchSizeLimit) - { - SendBatchNow(); - } - } + return _rpcs[key]; + } - var result = await tcs.Task.ConfigureAwait(false); - if (result is TResponse response) + /// + /// Sends an RPC request asynchronously and returns the response. + /// + /// The type of the response. + /// The RPC method name. + /// The parameters for the RPC request. + /// The RPC response. + /// Thrown if the response cannot be deserialized. + public async Task SendRequestAsync(string method, params object[] parameters) + { + lock (this._cacheLock) + { + var cacheKey = GetCacheKey(this.RpcUrl.ToString(), method, parameters); + if (this._cache.TryGetValue(cacheKey, out var cachedItem) && (DateTime.Now - cachedItem.Timestamp) < this._cacheDuration) { - lock (_cacheLock) + if (cachedItem.Response is TResponse cachedResponse) { - var cacheKey = GetCacheKey(method, parameters); - _cache[cacheKey] = (response, DateTime.Now); + return cachedResponse; } - return response; - } - else - { - try + else { - var deserializedResponse = JsonConvert.DeserializeObject(JsonConvert.SerializeObject(result)); - lock (_cacheLock) + try { - var cacheKey = GetCacheKey(method, parameters); - _cache[cacheKey] = (deserializedResponse, DateTime.Now); + var deserializedResponse = JsonConvert.DeserializeObject(JsonConvert.SerializeObject(cachedItem.Response)); + this._cache[cacheKey] = (deserializedResponse, DateTime.Now); + return deserializedResponse; + } + catch (Exception ex) + { + throw new InvalidOperationException("Failed to deserialize RPC response.", ex); } - return deserializedResponse; - } - catch (Exception ex) - { - throw new InvalidOperationException("Failed to deserialize RPC response.", ex); } } } - private ThirdwebRPC(ThirdwebClient client, BigInteger chainId) + var tcs = new TaskCompletionSource(); + var requestId = Interlocked.Increment(ref this._requestIdCounter); + var rpcRequest = new RpcRequest { - _httpClient = client.HttpClient; - _rpcUrl = new Uri($"https://{chainId}.rpc.thirdweb.com/"); - _rpcTimeout = TimeSpan.FromMilliseconds(client.FetchTimeoutOptions.GetTimeout(TimeoutType.Rpc)); - _batchTimer = new ThirdwebRPCTimer(_batchInterval); - _batchTimer.Elapsed += SendBatchNow; - _batchTimer.Start(); + Method = method, + Params = parameters, + Id = requestId, + }; + + lock (this._responseLock) + { + this._responseCompletionSources.Add(requestId, tcs); } - private void SendBatchNow() + this._pendingRequests.Enqueue(rpcRequest); + + var result = await tcs.Task.ConfigureAwait(false); + if (result is TResponse response) { - List batchToSend; - lock (_batchLock) + lock (this._cacheLock) { - if (_pendingBatch.Count == 0) + var cacheKey = GetCacheKey(this.RpcUrl.ToString(), method, parameters); + this._cache[cacheKey] = (response, DateTime.Now); + } + return response; + } + else + { + try + { + var deserializedResponse = JsonConvert.DeserializeObject(JsonConvert.SerializeObject(result)); + lock (this._cacheLock) { - return; + var cacheKey = GetCacheKey(this.RpcUrl.ToString(), method, parameters); + this._cache[cacheKey] = (deserializedResponse, DateTime.Now); } - - batchToSend = new List(_pendingBatch); - _pendingBatch.Clear(); + return deserializedResponse; + } + catch (Exception ex) + { + throw new InvalidOperationException("Failed to deserialize RPC response.", ex); } - - _ = SendBatchAsync(batchToSend); } + } - private async Task SendBatchAsync(List batch) + private ThirdwebRPC(ThirdwebClient client, BigInteger chainId) + { + this._httpClient = client.HttpClient; + var rpcOverride = client.RpcOverrides?.FirstOrDefault(r => r.Key == chainId); + this.RpcUrl = new Uri(rpcOverride?.Value ?? $"https://{chainId}.rpc.thirdweb.com/{client.ClientId}"); + this._rpcTimeout = TimeSpan.FromMilliseconds(client.FetchTimeoutOptions.GetTimeout(TimeoutType.Rpc)); + _ = this.StartBackgroundFlushAsync(); + } + + private async Task SendBatchAsync(List batch) + { + var batchJson = JsonConvert.SerializeObject(batch); + var content = new StringContent(batchJson, Encoding.UTF8, "application/json"); + + try { - var batchJson = JsonConvert.SerializeObject(batch); - var content = new StringContent(batchJson, Encoding.UTF8, "application/json"); + using var cts = new CancellationTokenSource(this._rpcTimeout); + var response = await this._httpClient.PostAsync(this.RpcUrl.ToString(), content, cts.Token).ConfigureAwait(false); - try + if (!response.IsSuccessStatusCode) { - using var cts = new CancellationTokenSource(_rpcTimeout); - var response = await _httpClient.PostAsync(_rpcUrl.ToString(), content, cts.Token).ConfigureAwait(false); - - if (!response.IsSuccessStatusCode) - { - var errorDetail = $"Batch request failed with HTTP status code: {response.StatusCode}"; - throw new HttpRequestException(errorDetail); - } + var errorDetail = $"Batch request failed with HTTP status code: {response.StatusCode}"; + throw new HttpRequestException(errorDetail); + } - var responseJson = await response.Content.ReadAsStringAsync().ConfigureAwait(false); - var responses = JsonConvert.DeserializeObject>>(responseJson); + var responseContent = await response.Content.ReadAsStringAsync().ConfigureAwait(false); + if (responseContent.Equals("Unauthorized", StringComparison.OrdinalIgnoreCase)) + { + throw new HttpRequestException("Unauthorized"); + } + var responses = JsonConvert.DeserializeObject>>(responseContent); - foreach (var rpcResponse in responses) + foreach (var rpcResponse in responses) + { + lock (this._responseLock) { - lock (_responseLock) + if (this._responseCompletionSources.TryGetValue(rpcResponse.Id, out var tcs)) { - if (_responseCompletionSources.TryGetValue(rpcResponse.Id, out var tcs)) + if (rpcResponse.Error != null) { - if (rpcResponse.Error != null) + var revertMsg = ""; + if (rpcResponse.Error.Data != null) { - var revertMsg = ""; - if (rpcResponse.Error.Data != null) + try { - try - { - revertMsg = new Nethereum.ABI.FunctionEncoding.FunctionCallDecoder().DecodeFunctionErrorMessage(rpcResponse.Error.Data); - revertMsg = string.IsNullOrWhiteSpace(revertMsg) ? rpcResponse.Error.Data : revertMsg; - } - catch - { - revertMsg = rpcResponse.Error.Data; - } + revertMsg = new Nethereum.ABI.FunctionEncoding.FunctionCallDecoder().DecodeFunctionErrorMessage(rpcResponse.Error.Data.ToString()); + revertMsg = string.IsNullOrWhiteSpace(revertMsg) ? rpcResponse.Error.Data.ToString() : revertMsg; + } + catch + { + revertMsg = rpcResponse.Error.Data.Type == JTokenType.String ? rpcResponse.Error.Data.ToString() : JsonConvert.SerializeObject(rpcResponse.Error.Data); } - tcs.SetException(new Exception($"RPC Error for request {rpcResponse.Id}: {rpcResponse.Error.Message} {revertMsg}")); - } - else - { - tcs.SetResult(rpcResponse.Result); } - - _responseCompletionSources.Remove(rpcResponse.Id); + tcs.SetException(new Exception($"RPC Error for request {rpcResponse.Id}: {rpcResponse.Error.Message} {revertMsg}")); } + else + { + tcs.SetResult(rpcResponse.Result); + } + + _ = this._responseCompletionSources.Remove(rpcResponse.Id); } } } - catch (TaskCanceledException ex) - { - var timeoutErrorDetail = $"Batch request timed out. Timeout duration: {_rpcTimeout} ms."; - var timeoutException = new TimeoutException(timeoutErrorDetail, ex); + } + catch (TaskCanceledException ex) + { + var timeoutErrorDetail = $"Batch request timed out. Timeout duration: {this._rpcTimeout} ms."; + var timeoutException = new TimeoutException(timeoutErrorDetail, ex); - foreach (var requestId in batch.Select(b => b.Id)) + foreach (var requestId in batch.Select(b => b.Id)) + { + lock (this._responseLock) { - lock (_responseLock) + if (this._responseCompletionSources.TryGetValue(requestId, out var tcs)) { - if (_responseCompletionSources.TryGetValue(requestId, out var tcs)) - { - _ = tcs.TrySetException(timeoutException); - _responseCompletionSources.Remove(requestId); - } + _ = tcs.TrySetException(timeoutException); + _ = this._responseCompletionSources.Remove(requestId); } } - - throw timeoutException; } - catch (Exception ex) + } + catch (Exception ex) + { + lock (this._responseLock) { - lock (_responseLock) + foreach (var requestId in batch.Select(b => b.Id)) { - foreach (var kvp in _responseCompletionSources) + if (this._responseCompletionSources.TryGetValue(requestId, out var tcs)) { - _ = kvp.Value.TrySetException(ex); + _ = tcs.TrySetException(ex); + _ = this._responseCompletionSources.Remove(requestId); } } } } + } + + private static string GetCacheKey(string rpcUrl, string method, params object[] parameters) + { + var keyBuilder = new StringBuilder(); + + _ = keyBuilder.Append(rpcUrl); - private string GetCacheKey(string method, params object[] parameters) + _ = keyBuilder.Append(method); + + foreach (var param in parameters) { - var keyBuilder = new StringBuilder(); + _ = keyBuilder.Append(param?.ToString()); + } - _ = keyBuilder.Append(method); + return keyBuilder.ToString(); + } - foreach (var param in parameters) + private async Task StartBackgroundFlushAsync() + { + while (!this._cancellationTokenSource.Token.IsCancellationRequested) + { + if (this._pendingRequests.IsEmpty) { - _ = keyBuilder.Append(param?.ToString()); + await ThirdwebTask.Delay(this._batchInterval.Milliseconds, this._cancellationTokenSource.Token).ConfigureAwait(false); + continue; + } + + var batchToSend = new List(); + for (var i = 0; i < BatchSizeLimit; i++) + { + if (this._pendingRequests.TryDequeue(out var request)) + { + batchToSend.Add(request); + } + else + { + break; + } } - return keyBuilder.ToString(); + if (batchToSend.Count > 0) + { + await this.SendBatchAsync(batchToSend); + } } } + + public void Dispose() + { + this._cancellationTokenSource.Cancel(); + this._cancellationTokenSource.Dispose(); + } } diff --git a/Thirdweb/Thirdweb.RPC/ThirdwebRPCTimer.cs b/Thirdweb/Thirdweb.RPC/ThirdwebRPCTimer.cs deleted file mode 100644 index 1ba6aab7..00000000 --- a/Thirdweb/Thirdweb.RPC/ThirdwebRPCTimer.cs +++ /dev/null @@ -1,86 +0,0 @@ -namespace Thirdweb -{ - /// - /// Represents a timer for RPC batching. - /// - public class ThirdwebRPCTimer : IDisposable - { - private readonly TimeSpan _interval; - private bool _isRunning; - private readonly object _lock = new object(); - - /// - /// Occurs when the timer interval has elapsed. - /// - public event Action Elapsed; - - /// - /// Initializes a new instance of the class with the specified interval. - /// - /// The interval at which the timer elapses. - public ThirdwebRPCTimer(TimeSpan interval) - { - _interval = interval; - _isRunning = false; - } - - /// - /// Starts the timer. - /// - public void Start() - { - lock (_lock) - { - if (_isRunning) - { - return; - } - - _isRunning = true; - RunTimer(); - } - } - - /// - /// Stops the timer. - /// - public void Stop() - { - lock (_lock) - { - if (!_isRunning) - { - return; - } - - _isRunning = false; - } - } - - /// - /// Disposes the timer, stopping its execution. - /// - public void Dispose() - { - _isRunning = false; - } - - private async void RunTimer() - { - while (_isRunning) - { - var startTime = DateTime.UtcNow; - while ((DateTime.UtcNow - startTime) < _interval) - { - if (!_isRunning) - { - return; - } - - await Task.Delay(10).ConfigureAwait(false); - } - Elapsed?.Invoke(); - } - } - } -} diff --git a/Thirdweb/Thirdweb.Storage/StorageTypes.cs b/Thirdweb/Thirdweb.Storage/StorageTypes.cs deleted file mode 100644 index 4584d729..00000000 --- a/Thirdweb/Thirdweb.Storage/StorageTypes.cs +++ /dev/null @@ -1,29 +0,0 @@ -namespace Thirdweb -{ - /// - /// Represents the result of an IPFS upload. - /// - [Serializable] - public struct IPFSUploadResult - { - /// - /// Gets or sets the IPFS hash of the uploaded content. - /// - public string IpfsHash; - - /// - /// Gets or sets the size of the pinned content. - /// - public string PinSize; - - /// - /// Gets or sets the timestamp of the upload. - /// - public string Timestamp; - - /// - /// Gets or sets the preview URL of the uploaded content. - /// - public string PreviewUrl; - } -} diff --git a/Thirdweb/Thirdweb.Storage/ThirdwebStorage.Types.cs b/Thirdweb/Thirdweb.Storage/ThirdwebStorage.Types.cs new file mode 100644 index 00000000..c4b3846b --- /dev/null +++ b/Thirdweb/Thirdweb.Storage/ThirdwebStorage.Types.cs @@ -0,0 +1,28 @@ +namespace Thirdweb; + +/// +/// Represents the result of an IPFS upload. +/// +[Serializable] +public struct IPFSUploadResult +{ + /// + /// Gets or sets the IPFS hash of the uploaded content. + /// + public string IpfsHash { get; set; } + + /// + /// Gets or sets the size of the pinned content. + /// + public string PinSize { get; set; } + + /// + /// Gets or sets the timestamp of the upload. + /// + public string Timestamp { get; set; } + + /// + /// Gets or sets the preview URL of the uploaded content. + /// + public string PreviewUrl { get; set; } +} diff --git a/Thirdweb/Thirdweb.Storage/ThirdwebStorage.cs b/Thirdweb/Thirdweb.Storage/ThirdwebStorage.cs index 9cc5a744..82c9393a 100644 --- a/Thirdweb/Thirdweb.Storage/ThirdwebStorage.cs +++ b/Thirdweb/Thirdweb.Storage/ThirdwebStorage.cs @@ -1,105 +1,106 @@ using Newtonsoft.Json; -namespace Thirdweb +namespace Thirdweb; + +/// +/// Provides methods for downloading and uploading data to Thirdweb storage. +/// +public static class ThirdwebStorage { /// - /// Provides methods for downloading and uploading data to Thirdweb storage. + /// Downloads data from the specified URI. /// - public static class ThirdwebStorage + /// The type of data to download. + /// The Thirdweb client. + /// The URI to download from. + /// The optional request timeout in milliseconds. + /// The downloaded data. + /// Thrown if the URI is null or empty. + /// Thrown if the download fails. + public static async Task Download(ThirdwebClient client, string uri, int? requestTimeout = null) { - /// - /// Downloads data from the specified URI. - /// - /// The type of data to download. - /// The Thirdweb client. - /// The URI to download from. - /// The optional request timeout in milliseconds. - /// The downloaded data. - /// Thrown if the URI is null or empty. - /// Thrown if the download fails. - public static async Task Download(ThirdwebClient client, string uri, int? requestTimeout = null) + if (string.IsNullOrEmpty(uri)) { - if (string.IsNullOrEmpty(uri)) - { - throw new ArgumentNullException(nameof(uri)); - } - - uri = uri.ReplaceIPFS($"https://{client.ClientId}.ipfscdn.io/ipfs/"); - - using var cts = new CancellationTokenSource(requestTimeout ?? client.FetchTimeoutOptions.GetTimeout(TimeoutType.Storage)); - - var httpClient = client.HttpClient; - - var response = await httpClient.GetAsync(uri, cts.Token).ConfigureAwait(false); - - if (!response.IsSuccessStatusCode) - { - throw new Exception($"Failed to download {uri}: {response.StatusCode} | {await response.Content.ReadAsStringAsync().ConfigureAwait(false)}"); - } - - if (typeof(T) == typeof(byte[])) - { - return (T)(object)await response.Content.ReadAsByteArrayAsync().ConfigureAwait(false); - } - else if (typeof(T) == typeof(string)) - { - return (T)(object)await response.Content.ReadAsStringAsync().ConfigureAwait(false); - } - else - { - var content = await response.Content.ReadAsByteArrayAsync().ConfigureAwait(false); - return JsonConvert.DeserializeObject(System.Text.Encoding.UTF8.GetString(content)); - } + throw new ArgumentNullException(nameof(uri)); } - /// - /// Uploads raw byte data to Thirdweb storage. - /// - /// The Thirdweb client. - /// The raw byte data to upload. - /// The result of the upload. - /// Thrown if the raw byte data is null or empty. - /// Thrown if the upload fails. - public static async Task UploadRaw(ThirdwebClient client, byte[] rawBytes) + if (uri.StartsWith("data:application/json;base64,")) { - if (rawBytes == null || rawBytes.Length == 0) - { - throw new ArgumentNullException(nameof(rawBytes)); - } + var base64Data = uri["data:application/json;base64,".Length..]; + var jsonData = System.Text.Encoding.UTF8.GetString(Convert.FromBase64String(base64Data)); + return JsonConvert.DeserializeObject(jsonData); + } - using var form = new MultipartFormDataContent { { new ByteArrayContent(rawBytes), "file", "file" } }; + uri = uri.ReplaceIPFS($"https://{client.ClientId}.ipfscdn.io/ipfs/"); - var httpClient = client.HttpClient; + using var cts = new CancellationTokenSource(requestTimeout ?? client.FetchTimeoutOptions.GetTimeout(TimeoutType.Storage)); - var response = await httpClient.PostAsync(Constants.PIN_URI, form).ConfigureAwait(false); + var httpClient = client.HttpClient; - if (!response.IsSuccessStatusCode) - { - throw new Exception($"Failed to upload raw bytes: {response.StatusCode} | {await response.Content.ReadAsStringAsync().ConfigureAwait(false)}"); - } + var response = await httpClient.GetAsync(uri, cts.Token).ConfigureAwait(false); - var result = await response.Content.ReadAsStringAsync().ConfigureAwait(false); + if (!response.IsSuccessStatusCode) + { + throw new Exception($"Failed to download {uri}: {response.StatusCode} | {await response.Content.ReadAsStringAsync().ConfigureAwait(false)}"); + } - var res = JsonConvert.DeserializeObject(result); - res.PreviewUrl = $"https://{client.ClientId}.ipfscdn.io/ipfs/{res.IpfsHash}"; - return res; + if (typeof(T) == typeof(byte[])) + { + return (T)(object)await response.Content.ReadAsByteArrayAsync().ConfigureAwait(false); + } + else if (typeof(T) == typeof(string)) + { + return (T)(object)await response.Content.ReadAsStringAsync().ConfigureAwait(false); } + else + { + var content = await response.Content.ReadAsByteArrayAsync().ConfigureAwait(false); + return JsonConvert.DeserializeObject(System.Text.Encoding.UTF8.GetString(content)); + } + } - /// - /// Uploads a file to Thirdweb storage from the specified path. - /// - /// The Thirdweb client. - /// The path to the file. - /// The result of the upload. - /// Thrown if the path is null or empty. - public static async Task Upload(ThirdwebClient client, string path) + /// + /// Uploads raw byte data to Thirdweb storage. + /// + /// The Thirdweb client. + /// The raw byte data to upload. + /// The result of the upload. + /// Thrown if the raw byte data is null or empty. + /// Thrown if the upload fails. + public static async Task UploadRaw(ThirdwebClient client, byte[] rawBytes) + { + if (rawBytes == null || rawBytes.Length == 0) { - if (string.IsNullOrEmpty(path)) - { - throw new ArgumentNullException(nameof(path)); - } + throw new ArgumentNullException(nameof(rawBytes)); + } + + using var form = new MultipartFormDataContent { { new ByteArrayContent(rawBytes), "file", "file" } }; + + var httpClient = client.HttpClient; - return await UploadRaw(client, File.ReadAllBytes(path)).ConfigureAwait(false); + var response = await httpClient.PostAsync(Constants.PIN_URI, form).ConfigureAwait(false); + + if (!response.IsSuccessStatusCode) + { + throw new Exception($"Failed to upload raw bytes: {response.StatusCode} | {await response.Content.ReadAsStringAsync().ConfigureAwait(false)}"); } + + var result = await response.Content.ReadAsStringAsync().ConfigureAwait(false); + + var res = JsonConvert.DeserializeObject(result); + res.PreviewUrl = $"https://{client.ClientId}.ipfscdn.io/ipfs/{res.IpfsHash}"; + return res; + } + + /// + /// Uploads a file to Thirdweb storage from the specified path. + /// + /// The Thirdweb client. + /// The path to the file. + /// The result of the upload. + /// Thrown if the path is null or empty. + public static async Task Upload(ThirdwebClient client, string path) + { + return string.IsNullOrEmpty(path) ? throw new ArgumentNullException(nameof(path)) : await UploadRaw(client, await File.ReadAllBytesAsync(path).ConfigureAwait(false)).ConfigureAwait(false); } } diff --git a/Thirdweb/Thirdweb.Transactions/ThirdwebTransaction.Types.cs b/Thirdweb/Thirdweb.Transactions/ThirdwebTransaction.Types.cs new file mode 100644 index 00000000..e8eb5582 --- /dev/null +++ b/Thirdweb/Thirdweb.Transactions/ThirdwebTransaction.Types.cs @@ -0,0 +1,323 @@ +using System.Numerics; +using Nethereum.Hex.HexConvertors.Extensions; +using Nethereum.Hex.HexTypes; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; + +namespace Thirdweb; + +/// +/// Represents the input parameters for a Thirdweb transaction. +/// +public class ThirdwebTransactionInput +{ + internal ThirdwebTransactionInput() { } + + public ThirdwebTransactionInput(BigInteger chainId) + { + this.ChainId = chainId > 0 ? new HexBigInteger(chainId) : throw new ArgumentException("Invalid Chain ID"); + } + + public ThirdwebTransactionInput( + BigInteger chainId, + string from = null, + string to = null, + BigInteger? nonce = null, + BigInteger? gas = null, + BigInteger? gasPrice = null, + BigInteger? value = null, + string data = null, + BigInteger? maxFeePerGas = null, + BigInteger? maxPriorityFeePerGas = null, + ZkSyncOptions? zkSync = null, + EIP7702Authorization? authorization = null + ) + { + this.ChainId = chainId > 0 ? new HexBigInteger(chainId) : throw new ArgumentException("Invalid Chain ID"); + this.From = string.IsNullOrEmpty(from) ? Constants.ADDRESS_ZERO : from; + this.To = string.IsNullOrEmpty(to) ? Constants.ADDRESS_ZERO : to; + this.Nonce = nonce == null ? null : new HexBigInteger(nonce.Value); + this.Gas = gas == null ? null : new HexBigInteger(gas.Value); + this.GasPrice = gasPrice == null ? null : new HexBigInteger(gasPrice.Value); + this.Value = value == null ? null : new HexBigInteger(value.Value); + this.Data = string.IsNullOrEmpty(data) ? "0x" : data; + this.MaxFeePerGas = maxFeePerGas == null ? null : new HexBigInteger(maxFeePerGas.Value); + this.MaxPriorityFeePerGas = maxPriorityFeePerGas == null ? null : new HexBigInteger(maxPriorityFeePerGas.Value); + this.ZkSync = zkSync; + this.AuthorizationList = authorization == null ? null : new List { authorization.Value }; + } + + /// + /// Gets or sets the nonce of the transaction. + /// + [JsonProperty(PropertyName = "nonce")] + public HexBigInteger Nonce { get; set; } + + private string _from; + private string _to; + private string _data; + + /// + /// Gets or sets the sender address of the transaction. + /// + [JsonProperty(PropertyName = "from")] + public string From + { + get => this._from.EnsureHexPrefix(); + set => this._from = value; + } + + /// + /// Gets or sets the recipient address of the transaction. + /// + [JsonProperty(PropertyName = "to")] + public string To + { + get => this._to.EnsureHexPrefix(); + set => this._to = value; + } + + /// + /// Gets or sets the gas limit for the transaction. + /// + [JsonProperty(PropertyName = "gas")] + public HexBigInteger Gas { get; set; } + + /// + /// Gets or sets the gas price for the transaction. + /// + [JsonProperty(PropertyName = "gasPrice")] + public HexBigInteger GasPrice { get; set; } + + /// + /// Gets or sets the value to be transferred in the transaction. + /// + [JsonProperty(PropertyName = "value")] + public HexBigInteger Value { get; set; } + + /// + /// Gets or sets the data to be sent with the transaction. + /// + [JsonProperty(PropertyName = "data")] + public string Data + { + get => this._data.EnsureHexPrefix(); + set => this._data = value; + } + + /// + /// Gets or sets the maximum fee per gas for the transaction. + /// + [JsonProperty(PropertyName = "maxFeePerGas")] + public HexBigInteger MaxFeePerGas { get; set; } + + /// + /// Gets or sets the maximum priority fee per gas for the transaction. + /// + [JsonProperty(PropertyName = "maxPriorityFeePerGas")] + public HexBigInteger MaxPriorityFeePerGas { get; set; } + + /// + /// Gets or sets the chain ID for the transaction. + /// + [JsonProperty(PropertyName = "chainId")] + public HexBigInteger ChainId { get; set; } + + /// + /// Gets or sets the zkSync options for the transaction. + /// + [JsonProperty(PropertyName = "zkSyncOptions", NullValueHandling = NullValueHandling.Ignore)] + public ZkSyncOptions? ZkSync { get; set; } + +#nullable enable + [JsonProperty(PropertyName = "authorizationList", NullValueHandling = NullValueHandling.Ignore)] + public List? AuthorizationList { get; set; } +#nullable disable +} + +/// +/// Represents the zkSync options for a transaction. +/// +public struct ZkSyncOptions +{ + /// + /// Gets or sets the gas limit per pubdata byte. + /// + [JsonProperty(PropertyName = "gasPerPubdataByteLimit")] + public BigInteger? GasPerPubdataByteLimit { get; set; } + + /// + /// Gets or sets the factory dependencies. + /// + [JsonProperty(PropertyName = "factoryDeps")] + public List FactoryDeps { get; set; } + + /// + /// Gets or sets the paymaster. + /// + [JsonProperty(PropertyName = "paymaster")] + public BigInteger Paymaster { get; set; } + + /// + /// Gets or sets the paymaster input data. + /// + [JsonProperty(PropertyName = "paymasterInput")] + public byte[] PaymasterInput { get; set; } + + /// + /// Initializes a new instance of the struct. + /// + /// The paymaster. + /// The paymaster input data. + /// The gas limit per pubdata byte. + /// The factory dependencies. + public ZkSyncOptions(string paymaster = null, string paymasterInput = null, BigInteger? gasPerPubdataByteLimit = null, List factoryDeps = null) + { + if (string.IsNullOrEmpty(paymaster) || string.IsNullOrEmpty(paymasterInput)) + { + this.Paymaster = 0; + this.PaymasterInput = Array.Empty(); + this.GasPerPubdataByteLimit = gasPerPubdataByteLimit; + this.FactoryDeps = factoryDeps ?? new List(); + } + else + { + this.Paymaster = new HexBigInteger(paymaster).Value; + this.PaymasterInput = paymasterInput.HexToByteArray(); + this.GasPerPubdataByteLimit = gasPerPubdataByteLimit; + this.FactoryDeps = factoryDeps ?? new List(); + } + } +} + +public struct EIP7702Authorization +{ + [JsonProperty(PropertyName = "chainId")] + public string ChainId { get; set; } + + [JsonProperty(PropertyName = "address")] + public string Address { get; set; } + + [JsonProperty(PropertyName = "nonce")] + public string Nonce { get; set; } + + [JsonProperty(PropertyName = "yParity")] + public string YParity { get; set; } + + [JsonProperty(PropertyName = "r")] + public string R { get; set; } + + [JsonProperty(PropertyName = "s")] + public string S { get; set; } + + public EIP7702Authorization(BigInteger chainId, string address, BigInteger nonce, byte[] yParity, byte[] r, byte[] s) + { + this.ChainId = new HexBigInteger(chainId).HexValue; + this.Address = address; + this.Nonce = new HexBigInteger(nonce).HexValue; + this.YParity = yParity.BytesToHex() == "0x00" ? "0x0" : "0x1"; + this.R = r.BytesToHex(); + this.S = s.BytesToHex(); + } +} + +/// +/// Represents the receipt of a transaction. +/// +public class ThirdwebTransactionReceipt +{ + /// + /// Gets or sets the transaction hash. + /// + [JsonProperty(PropertyName = "transactionHash")] + public string TransactionHash { get; set; } + + /// + /// Gets or sets the transaction index within the block. + /// + [JsonProperty(PropertyName = "transactionIndex")] + public HexBigInteger TransactionIndex { get; set; } + + /// + /// Gets or sets the hash of the block containing the transaction. + /// + [JsonProperty(PropertyName = "blockHash")] + public string BlockHash { get; set; } + + /// + /// Gets or sets the number of the block containing the transaction. + /// + [JsonProperty(PropertyName = "blockNumber")] + public HexBigInteger BlockNumber { get; set; } + + /// + /// Gets or sets the address of the sender. + /// + [JsonProperty(PropertyName = "from")] + public string From { get; set; } + + /// + /// Gets or sets the address of the recipient. + /// + [JsonProperty(PropertyName = "to")] + public string To { get; set; } + + /// + /// Gets or sets the cumulative gas used by the transaction. + /// + [JsonProperty(PropertyName = "cumulativeGasUsed")] + public HexBigInteger CumulativeGasUsed { get; set; } + + /// + /// Gets or sets the gas used by the transaction. + /// + [JsonProperty(PropertyName = "gasUsed")] + public HexBigInteger GasUsed { get; set; } + + /// + /// Gets or sets the effective gas price for the transaction. + /// + [JsonProperty(PropertyName = "effectiveGasPrice")] + public HexBigInteger EffectiveGasPrice { get; set; } + + /// + /// Gets or sets the contract address created by the transaction, if applicable. + /// + [JsonProperty(PropertyName = "contractAddress")] + public string ContractAddress { get; set; } + + /// + /// Gets or sets the status of the transaction. + /// + [JsonProperty(PropertyName = "status")] + public HexBigInteger Status { get; set; } + + /// + /// Gets or sets the logs generated by the transaction. + /// + [JsonProperty(PropertyName = "logs")] + public JArray Logs { get; set; } + + /// + /// Gets or sets the transaction type. + /// + [JsonProperty(PropertyName = "type")] + public HexBigInteger Type { get; set; } + + /// + /// Gets or sets the logs bloom filter. + /// + [JsonProperty(PropertyName = "logsBloom")] + public string LogsBloom { get; set; } + + /// + /// Gets or sets the root of the transaction. + /// + [JsonProperty(PropertyName = "root")] + public string Root { get; set; } + + public override string ToString() + { + return JsonConvert.SerializeObject(this, Formatting.Indented); + } +} diff --git a/Thirdweb/Thirdweb.Transactions/ThirdwebTransaction.cs b/Thirdweb/Thirdweb.Transactions/ThirdwebTransaction.cs index 7c541b8b..935abb6c 100644 --- a/Thirdweb/Thirdweb.Transactions/ThirdwebTransaction.cs +++ b/Thirdweb/Thirdweb.Transactions/ThirdwebTransaction.cs @@ -1,518 +1,520 @@ using System.Numerics; -using Nethereum.Hex.HexConvertors.Extensions; using Nethereum.Hex.HexTypes; using Newtonsoft.Json; -using Nethereum.ABI.FunctionEncoding; using Newtonsoft.Json.Linq; -namespace Thirdweb +namespace Thirdweb; + +/// +/// Represents the total costs in ether and wei. +/// +public struct TotalCosts { /// - /// Represents the total costs in ether and wei. + /// The cost in ether. + /// + public string Ether { get; set; } + + /// + /// The cost in wei. /// - public struct TotalCosts + public BigInteger Wei { get; set; } +} + +/// +/// Represents a Thirdweb transaction. +/// +public class ThirdwebTransaction +{ + public ThirdwebTransactionInput Input { get; set; } + + internal readonly IThirdwebWallet Wallet; + + private ThirdwebTransaction(IThirdwebWallet wallet, ThirdwebTransactionInput txInput) { - /// - /// The cost in ether. - /// - public string ether; - - /// - /// The cost in wei. - /// - public BigInteger wei; + this.Input = txInput; + this.Wallet = wallet; } /// - /// Represents a Thirdweb transaction. + /// Creates a new Thirdweb transaction. /// - public class ThirdwebTransaction + /// The wallet to use for the transaction. + /// The transaction input. + /// A new Thirdweb transaction. + public static async Task Create(IThirdwebWallet wallet, ThirdwebTransactionInput txInput) { - internal ThirdwebTransactionInput Input { get; } - - private readonly IThirdwebWallet _wallet; - - private ThirdwebTransaction(IThirdwebWallet wallet, ThirdwebTransactionInput txInput, BigInteger chainId) + if (wallet == null) { - Input = txInput; - _wallet = wallet; - Input.ChainId = chainId.ToHexBigInteger(); + throw new ArgumentException("Wallet must be provided", nameof(wallet)); } - /// - /// Creates a new Thirdweb transaction. - /// - /// The wallet to use for the transaction. - /// The transaction input. - /// The chain ID. - /// A new Thirdweb transaction. - public static async Task Create(IThirdwebWallet wallet, ThirdwebTransactionInput txInput, BigInteger chainId) + if (txInput.To == null) { - if (wallet == null) - { - throw new ArgumentException("Wallet must be provided", nameof(wallet)); - } + throw new ArgumentException("Transaction recipient (to) must be provided", nameof(txInput)); + } - if (chainId == 0) - { - throw new ArgumentException("Invalid Chain ID", nameof(chainId)); - } + txInput.From = await wallet.GetAddress().ConfigureAwait(false); + txInput.Data ??= "0x"; + txInput.Value ??= new HexBigInteger(0); - if (txInput.To == null) - { - throw new ArgumentException("Transaction recipient (to) must be provided", nameof(txInput)); - } + return new ThirdwebTransaction(wallet, txInput); + } - var address = await wallet.GetAddress().ConfigureAwait(false); - txInput.From ??= address; - txInput.Data ??= "0x"; + /// + /// Converts the transaction input to a JSON string. + /// + /// A JSON string representation of the transaction input. + public override string ToString() + { + return JsonConvert.SerializeObject(this.Input); + } - if (address != txInput.From) - { - throw new ArgumentException("Transaction sender (from) must match wallet address", nameof(txInput)); - } + /// + /// Sets the recipient address of the transaction. + /// + /// The recipient address. + /// The updated transaction. + public ThirdwebTransaction SetTo(string to) + { + this.Input.To = to; + return this; + } - return new ThirdwebTransaction(wallet, txInput, chainId); - } + /// + /// Sets the data for the transaction. + /// + /// The data. + /// The updated transaction. + public ThirdwebTransaction SetData(string data) + { + this.Input.Data = data; + return this; + } - /// - /// Converts the transaction input to a JSON string. - /// - /// A JSON string representation of the transaction input. - public override string ToString() - { - return JsonConvert.SerializeObject(Input); - } + /// + /// Sets the value to be transferred in the transaction. + /// + /// The value in wei. + /// The updated transaction. + public ThirdwebTransaction SetValue(BigInteger weiValue) + { + this.Input.Value = weiValue.ToHexBigInteger(); + return this; + } - /// - /// Sets the recipient address of the transaction. - /// - /// The recipient address. - /// The updated transaction. - public ThirdwebTransaction SetTo(string to) - { - Input.To = to; - return this; - } + /// + /// Sets the gas limit for the transaction. + /// + /// The gas limit. + /// The updated transaction. + public ThirdwebTransaction SetGasLimit(BigInteger gas) + { + this.Input.Gas = gas.ToHexBigInteger(); + return this; + } - /// - /// Sets the data for the transaction. - /// - /// The data. - /// The updated transaction. - public ThirdwebTransaction SetData(string data) - { - Input.Data = data; - return this; - } + /// + /// Sets the gas price for the transaction. + /// + /// The gas price. + /// The updated transaction. + public ThirdwebTransaction SetGasPrice(BigInteger gasPrice) + { + this.Input.GasPrice = gasPrice.ToHexBigInteger(); + return this; + } - /// - /// Sets the value to be transferred in the transaction. - /// - /// The value in wei. - /// The updated transaction. - public ThirdwebTransaction SetValue(BigInteger weiValue) - { - Input.Value = weiValue.ToHexBigInteger(); - return this; - } + /// + /// Sets the nonce for the transaction. + /// + /// The nonce. + /// The updated transaction. + public ThirdwebTransaction SetNonce(BigInteger nonce) + { + this.Input.Nonce = nonce.ToHexBigInteger(); + return this; + } - /// - /// Sets the gas limit for the transaction. - /// - /// The gas limit. - /// The updated transaction. - public ThirdwebTransaction SetGasLimit(BigInteger gas) - { - Input.Gas = gas.ToHexBigInteger(); - return this; - } + /// + /// Sets the maximum fee per gas for the transaction. + /// + /// The maximum fee per gas. + /// The updated transaction. + public ThirdwebTransaction SetMaxFeePerGas(BigInteger maxFeePerGas) + { + this.Input.MaxFeePerGas = maxFeePerGas.ToHexBigInteger(); + return this; + } - /// - /// Sets the gas price for the transaction. - /// - /// The gas price. - /// The updated transaction. - public ThirdwebTransaction SetGasPrice(BigInteger gasPrice) - { - Input.GasPrice = gasPrice.ToHexBigInteger(); - return this; - } + /// + /// Sets the maximum priority fee per gas for the transaction. + /// + /// The maximum priority fee per gas. + /// The updated transaction. + public ThirdwebTransaction SetMaxPriorityFeePerGas(BigInteger maxPriorityFeePerGas) + { + this.Input.MaxPriorityFeePerGas = maxPriorityFeePerGas.ToHexBigInteger(); + return this; + } - /// - /// Sets the nonce for the transaction. - /// - /// The nonce. - /// The updated transaction. - public ThirdwebTransaction SetNonce(BigInteger nonce) - { - Input.Nonce = nonce.ToHexBigInteger(); - return this; - } + /// + /// Sets the chain ID for the transaction. + /// + /// The chain ID. + /// The updated transaction. + public ThirdwebTransaction SetChainId(BigInteger chainId) + { + this.Input.ChainId = chainId.ToHexBigInteger(); + return this; + } - /// - /// Sets the maximum fee per gas for the transaction. - /// - /// The maximum fee per gas. - /// The updated transaction. - public ThirdwebTransaction SetMaxFeePerGas(BigInteger maxFeePerGas) - { - Input.MaxFeePerGas = maxFeePerGas.ToHexBigInteger(); - return this; - } + /// + /// Sets the zkSync options for the transaction. + /// + /// The zkSync options. + /// The updated transaction. + public ThirdwebTransaction SetZkSyncOptions(ZkSyncOptions zkSyncOptions) + { + this.Input.ZkSync = zkSyncOptions; + return this; + } - /// - /// Sets the maximum priority fee per gas for the transaction. - /// - /// The maximum priority fee per gas. - /// The updated transaction. - public ThirdwebTransaction SetMaxPriorityFeePerGas(BigInteger maxPriorityFeePerGas) - { - Input.MaxPriorityFeePerGas = maxPriorityFeePerGas.ToHexBigInteger(); - return this; - } + /// + /// Estimates the gas costs for the transaction. + /// + /// The transaction. + /// The estimated gas costs. + public static async Task EstimateGasCosts(ThirdwebTransaction transaction) + { + var gasPrice = transaction.Input.GasPrice?.Value ?? await EstimateGasPrice(transaction).ConfigureAwait(false); + var gasLimit = transaction.Input.Gas?.Value ?? await EstimateGasLimit(transaction).ConfigureAwait(false); + var gasCost = BigInteger.Multiply(gasLimit, gasPrice); + return new TotalCosts { Ether = gasCost.ToString().ToEth(18, false), Wei = gasCost }; + } - /// - /// Sets the chain ID for the transaction. - /// - /// The chain ID. - /// The updated transaction. - public ThirdwebTransaction SetChainId(BigInteger chainId) + /// + /// Estimates the total costs for the transaction. + /// + /// The transaction. + /// The estimated total costs. + public static async Task EstimateTotalCosts(ThirdwebTransaction transaction) + { + var gasCosts = await EstimateGasCosts(transaction).ConfigureAwait(false); + var value = transaction.Input.Value?.Value ?? 0; + return new TotalCosts { Ether = (value + gasCosts.Wei).ToString().ToEth(18, false), Wei = value + gasCosts.Wei }; + } + + /// + /// Estimates the gas price for the transaction. + /// + /// The transaction. + /// Whether to include a bump in the gas price. + /// The estimated gas price. + public static async Task EstimateGasPrice(ThirdwebTransaction transaction, bool withBump = true) + { + return await Utils.FetchGasPrice(transaction.Wallet.Client, transaction.Input.ChainId.Value, withBump).ConfigureAwait(false); + } + + /// + /// Estimates the gas fees for the transaction. + /// + /// The transaction. + /// Whether to include a bump in the gas fees. + /// The estimated maximum fee per gas and maximum priority fee per gas. + public static async Task<(BigInteger maxFeePerGas, BigInteger maxPriorityFeePerGas)> EstimateGasFees(ThirdwebTransaction transaction, bool withBump = true) + { + var rpc = ThirdwebRPC.GetRpcInstance(transaction.Wallet.Client, transaction.Input.ChainId.Value); + var chainId = transaction.Input.ChainId.Value; + + if (await Utils.IsZkSync(transaction.Wallet.Client, transaction.Input.ChainId.Value).ConfigureAwait(false)) { - Input.ChainId = chainId.ToHexBigInteger(); - return this; + var fees = await rpc.SendRequestAsync("zks_estimateFee", transaction.Input).ConfigureAwait(false); + var maxFee = fees["max_fee_per_gas"].ToObject().Value; + var maxPriorityFee = fees["max_priority_fee_per_gas"].ToObject().Value; + return withBump ? (maxFee * 10 / 5, maxPriorityFee * 10 / 5) : (maxFee, maxPriorityFee); } - - /// - /// Sets the zkSync options for the transaction. - /// - /// The zkSync options. - /// The updated transaction. - public ThirdwebTransaction SetZkSyncOptions(ZkSyncOptions zkSyncOptions) + else { - Input.ZkSync = zkSyncOptions; - return this; + return await Utils.FetchGasFees(transaction.Wallet.Client, chainId, withBump).ConfigureAwait(false); } + } + + /// + /// Simulates the transaction. + /// + /// The transaction. + /// The result of the simulation. + public static async Task Simulate(ThirdwebTransaction transaction) + { + var rpc = ThirdwebRPC.GetRpcInstance(transaction.Wallet.Client, transaction.Input.ChainId.Value); + return await rpc.SendRequestAsync("eth_call", transaction.Input, "latest"); + } - /// - /// Estimates the gas costs for the transaction. - /// - /// The transaction. - /// The estimated gas costs. - public static async Task EstimateGasCosts(ThirdwebTransaction transaction) + /// + /// Estimates the gas limit for the transaction. + /// + /// The transaction. + /// The estimated gas limit. + public static async Task EstimateGasLimit(ThirdwebTransaction transaction) + { + var rpc = ThirdwebRPC.GetRpcInstance(transaction.Wallet.Client, transaction.Input.ChainId.Value); + var isZkSync = await Utils.IsZkSync(transaction.Wallet.Client, transaction.Input.ChainId.Value).ConfigureAwait(false); + BigInteger divider = + isZkSync ? 7 + : transaction.Input.AuthorizationList == null ? 5 + : 3; + BigInteger baseGas; + if (isZkSync) { - var gasPrice = transaction.Input.GasPrice?.Value ?? await EstimateGasPrice(transaction).ConfigureAwait(false); - var gasLimit = transaction.Input.Gas?.Value ?? await EstimateGasLimit(transaction).ConfigureAwait(false); - var gasCost = BigInteger.Multiply(gasLimit, gasPrice); - return new TotalCosts { ether = gasCost.ToString().ToEth(18, false), wei = gasCost }; + var hex = (await rpc.SendRequestAsync("zks_estimateFee", transaction.Input).ConfigureAwait(false))["gas_limit"].ToString(); + baseGas = hex.HexToNumber(); } - - /// - /// Estimates the total costs for the transaction. - /// - /// The transaction. - /// The estimated total costs. - public static async Task EstimateTotalCosts(ThirdwebTransaction transaction) + else { - var gasCosts = await EstimateGasCosts(transaction).ConfigureAwait(false); - var value = transaction.Input.Value?.Value ?? 0; - return new TotalCosts { ether = (value + gasCosts.wei).ToString().ToEth(18, false), wei = value + gasCosts.wei }; + var hex = await rpc.SendRequestAsync("eth_estimateGas", transaction.Input).ConfigureAwait(false); + baseGas = hex.HexToNumber(); } + return baseGas * 10 / divider; + } + + /// + /// Gets the nonce for the transaction. + /// + /// The transaction. + /// The nonce. + public static async Task GetNonce(ThirdwebTransaction transaction) + { + return await transaction.Wallet.GetTransactionCount(chainId: transaction.Input.ChainId, blocktag: "pending").ConfigureAwait(false); + } + + private static async Task GetGasPerPubData(ThirdwebTransaction transaction) + { + var rpc = ThirdwebRPC.GetRpcInstance(transaction.Wallet.Client, transaction.Input.ChainId.Value); + var hex = (await rpc.SendRequestAsync("zks_estimateFee", transaction.Input).ConfigureAwait(false))["gas_per_pubdata_limit"].ToString(); + var finalGasPerPubData = new HexBigInteger(hex).Value * 10 / 5; + return finalGasPerPubData < 10000 ? 10000 : finalGasPerPubData; + } - /// - /// Estimates the gas price for the transaction. - /// - /// The transaction. - /// Whether to include a bump in the gas price. - /// The estimated gas price. - public static async Task EstimateGasPrice(ThirdwebTransaction transaction, bool withBump = true) + /// + /// Signs the transaction. + /// + /// The transaction. + /// The signed transaction. + public static async Task Sign(ThirdwebTransaction transaction) + { + return await transaction.Wallet.SignTransaction(transaction.Input).ConfigureAwait(false); + } + + /// + /// Populates the transaction and prepares it for sending. + /// + /// The transaction. + /// The populated transaction. + /// + public static async Task Prepare(ThirdwebTransaction transaction) + { + if (transaction.Input.To == null) { - var rpc = ThirdwebRPC.GetRpcInstance(transaction._wallet.Client, transaction.Input.ChainId.Value); - var hex = new HexBigInteger(await rpc.SendRequestAsync("eth_gasPrice").ConfigureAwait(false)); - return withBump ? hex.Value * 10 / 9 : hex.Value; + throw new InvalidOperationException("Transaction recipient (to) must be provided"); } - /// - /// Estimates the gas fees for the transaction. - /// - /// The transaction. - /// Whether to include a bump in the gas fees. - /// The estimated maximum fee per gas and maximum priority fee per gas. - public static async Task<(BigInteger, BigInteger)> EstimateGasFees(ThirdwebTransaction transaction, bool withBump = true) + if (transaction.Input.GasPrice != null && (transaction.Input.MaxFeePerGas != null || transaction.Input.MaxPriorityFeePerGas != null)) { - var rpc = ThirdwebRPC.GetRpcInstance(transaction._wallet.Client, transaction.Input.ChainId.Value); - var chainId = transaction.Input.ChainId.Value; - - if (Utils.IsZkSync(transaction.Input.ChainId.Value)) - { - var fees = await rpc.SendRequestAsync("zks_estimateFee", transaction.Input, "latest").ConfigureAwait(false); - var maxFee = fees["max_fee_per_gas"].ToObject().Value; - var maxPriorityFee = fees["max_priority_fee_per_gas"].ToObject().Value; - return withBump ? (maxFee * 10 / 5, maxPriorityFee * 10 / 5) : (maxFee, maxPriorityFee); - } + throw new InvalidOperationException("Transaction GasPrice and MaxFeePerGas/MaxPriorityFeePerGas cannot be set at the same time"); + } - var gasPrice = await EstimateGasPrice(transaction, withBump).ConfigureAwait(false); + transaction.Input.Nonce ??= new HexBigInteger(await GetNonce(transaction).ConfigureAwait(false)); + transaction.Input.Value ??= new HexBigInteger(0); + transaction.Input.Data ??= "0x"; + transaction.Input.Gas ??= new HexBigInteger(await EstimateGasLimit(transaction).ConfigureAwait(false)); - // Polygon Mainnet & Amoy - if (chainId == 137 || chainId == 80002) + var supports1559 = Utils.IsEip1559Supported(transaction.Input.ChainId.Value.ToString()); + if (supports1559) + { + if (transaction.Input.GasPrice == null) { - return (gasPrice * 3 / 2, gasPrice * 4 / 3); + var (maxFeePerGas, maxPriorityFeePerGas) = await EstimateGasFees(transaction).ConfigureAwait(false); + transaction.Input.MaxFeePerGas ??= new HexBigInteger(maxFeePerGas); + transaction.Input.MaxPriorityFeePerGas ??= new HexBigInteger(maxPriorityFeePerGas); } - - // Celo Mainnet, Alfajores & Baklava - if (chainId == 42220 || chainId == 44787 || chainId == 62320) + } + else + { + if (transaction.Input.MaxFeePerGas == null && transaction.Input.MaxPriorityFeePerGas == null) { - return (gasPrice, gasPrice); + transaction.Input.GasPrice ??= new HexBigInteger(await EstimateGasPrice(transaction).ConfigureAwait(false)); } + } - try - { - var block = await rpc.SendRequestAsync("eth_getBlockByNumber", "latest", true).ConfigureAwait(false); - var baseBlockFee = block["baseFeePerGas"]?.ToObject(); - var maxFeePerGas = baseBlockFee.Value * 2; - var maxPriorityFeePerGas = ((await rpc.SendRequestAsync("eth_maxPriorityFeePerGas").ConfigureAwait(false))?.Value) ?? maxFeePerGas / 2; + return transaction; + } - if (maxPriorityFeePerGas > maxFeePerGas) - { - maxPriorityFeePerGas = maxFeePerGas / 2; - } + /// + /// Sends the transaction. + /// + /// The transaction. + /// The transaction hash. + public static async Task Send(ThirdwebTransaction transaction) + { + transaction = await Prepare(transaction).ConfigureAwait(false); - return (maxFeePerGas + maxPriorityFeePerGas * 10 / 9, maxPriorityFeePerGas * 10 / 9); - } - catch - { - return (gasPrice, gasPrice); - } - } + var rpc = ThirdwebRPC.GetRpcInstance(transaction.Wallet.Client, transaction.Input.ChainId.Value); + string hash; - /// - /// Simulates the transaction. - /// - /// The transaction. - /// The result of the simulation. - public static async Task Simulate(ThirdwebTransaction transaction) + if (await Utils.IsZkSync(transaction.Wallet.Client, transaction.Input.ChainId.Value).ConfigureAwait(false) && transaction.Input.ZkSync.HasValue) { - var rpc = ThirdwebRPC.GetRpcInstance(transaction._wallet.Client, transaction.Input.ChainId.Value); - return await rpc.SendRequestAsync("eth_call", transaction.Input, "latest"); + var zkTx = await ConvertToZkSyncTransaction(transaction).ConfigureAwait(false); + var zkTxSigned = await EIP712.GenerateSignature_ZkSyncTransaction("zkSync", "2", transaction.Input.ChainId.Value, zkTx, transaction.Wallet).ConfigureAwait(false); + hash = await rpc.SendRequestAsync("eth_sendRawTransaction", zkTxSigned).ConfigureAwait(false); } - - /// - /// Estimates the gas limit for the transaction. - /// - /// The transaction. - /// The estimated gas limit. - public static async Task EstimateGasLimit(ThirdwebTransaction transaction) + else { - var rpc = ThirdwebRPC.GetRpcInstance(transaction._wallet.Client, transaction.Input.ChainId.Value); - - if (Utils.IsZkSync(transaction.Input.ChainId.Value)) + switch (transaction.Wallet.AccountType) { - var hex = (await rpc.SendRequestAsync("zks_estimateFee", transaction.Input, "latest").ConfigureAwait(false))["gas_limit"].ToString(); - return new HexBigInteger(hex).Value * 10 / 5; - } - - if (transaction._wallet.AccountType == ThirdwebAccountType.SmartAccount) - { - var smartAccount = transaction._wallet as SmartWallet; - return await smartAccount.EstimateUserOperationGas(transaction.Input, transaction.Input.ChainId.Value).ConfigureAwait(false); - } - else - { - var hex = await rpc.SendRequestAsync("eth_estimateGas", transaction.Input, "latest").ConfigureAwait(false); - return new HexBigInteger(hex).Value * 10 / 7; + case ThirdwebAccountType.PrivateKeyAccount: + var signedTx = await Sign(transaction); + hash = await rpc.SendRequestAsync("eth_sendRawTransaction", signedTx).ConfigureAwait(false); + break; + case ThirdwebAccountType.SmartAccount: + case ThirdwebAccountType.ExternalAccount: + hash = await transaction.Wallet.SendTransaction(transaction.Input).ConfigureAwait(false); + break; + default: + throw new NotImplementedException("Account type not supported"); } } + Utils.TrackTransaction(transaction, hash); + return hash; + } - /// - /// Gets the nonce for the transaction. - /// - /// The transaction. - /// The nonce. - public static async Task GetNonce(ThirdwebTransaction transaction) - { - var rpc = ThirdwebRPC.GetRpcInstance(transaction._wallet.Client, transaction.Input.ChainId.Value); - return new HexBigInteger(await rpc.SendRequestAsync("eth_getTransactionCount", transaction.Input.From, "pending").ConfigureAwait(false)).Value; - } + /// + /// Sends the transaction and waits for the transaction receipt. + /// + /// The transaction. + /// The transaction receipt. + public static async Task SendAndWaitForTransactionReceipt(ThirdwebTransaction transaction) + { + var txHash = await Send(transaction).ConfigureAwait(false); + return await WaitForTransactionReceipt(transaction.Wallet.Client, transaction.Input.ChainId.Value, txHash).ConfigureAwait(false); + } - private static async Task GetGasPerPubData(ThirdwebTransaction transaction) - { - var rpc = ThirdwebRPC.GetRpcInstance(transaction._wallet.Client, transaction.Input.ChainId.Value); - var hex = (await rpc.SendRequestAsync("zks_estimateFee", transaction.Input, "latest").ConfigureAwait(false))["gas_per_pubdata_limit"].ToString(); - var finalGasPerPubData = new HexBigInteger(hex).Value * 10 / 5; - return finalGasPerPubData < 10000 ? 10000 : finalGasPerPubData; - } + /// + /// Waits for the transaction receipt. + /// + /// The Thirdweb client. + /// The chain ID. + /// The transaction hash. + /// The cancellation token. + /// The transaction receipt. + public static async Task WaitForTransactionReceipt(ThirdwebClient client, BigInteger chainId, string txHash, CancellationToken cancellationToken = default) + { + using var cts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken); + cts.CancelAfter(client.FetchTimeoutOptions.GetTimeout(TimeoutType.Other)); - /// - /// Signs the transaction. - /// - /// The transaction. - /// The signed transaction. - public static async Task Sign(ThirdwebTransaction transaction) - { - return await transaction._wallet.SignTransaction(transaction.Input); - } + var rpc = ThirdwebRPC.GetRpcInstance(client, chainId); + ThirdwebTransactionReceipt receipt = null; - /// - /// Sends the transaction. - /// - /// The transaction. - /// The transaction hash. - public static async Task Send(ThirdwebTransaction transaction) + try { - if (transaction.Input.To == null) - { - throw new InvalidOperationException("Transaction recipient (to) must be provided"); - } - - if (transaction.Input.GasPrice != null && (transaction.Input.MaxFeePerGas != null || transaction.Input.MaxPriorityFeePerGas != null)) + do { - throw new InvalidOperationException("Transaction GasPrice and MaxFeePerGas/MaxPriorityFeePerGas cannot be set at the same time"); - } + receipt = await rpc.SendRequestAsync("eth_getTransactionReceipt", txHash).ConfigureAwait(false); + if (receipt == null) + { + await ThirdwebTask.Delay(100, cts.Token).ConfigureAwait(false); + } + } while (receipt == null && !cts.Token.IsCancellationRequested); - transaction.Input.From ??= await transaction._wallet.GetAddress().ConfigureAwait(false); - transaction.Input.Value ??= new HexBigInteger(0); - transaction.Input.Data ??= "0x"; - transaction.Input.Gas ??= new HexBigInteger(await EstimateGasLimit(transaction).ConfigureAwait(false)); - if (transaction.Input.GasPrice == null) + if (receipt == null) { - var (maxFeePerGas, maxPriorityFeePerGas) = await EstimateGasFees(transaction).ConfigureAwait(false); - transaction.Input.MaxFeePerGas ??= maxFeePerGas.ToHexBigInteger(); - transaction.Input.MaxPriorityFeePerGas ??= maxPriorityFeePerGas.ToHexBigInteger(); - } - else - { - transaction.Input.MaxFeePerGas = null; - transaction.Input.MaxPriorityFeePerGas = null; + throw new Exception($"Transaction {txHash} not found within the timeout period."); } - var rpc = ThirdwebRPC.GetRpcInstance(transaction._wallet.Client, transaction.Input.ChainId.Value); - string hash; - if ( - Utils.IsZkSync(transaction.Input.ChainId.Value) - && transaction.Input.ZkSync.HasValue - && transaction.Input.ZkSync.Value.Paymaster != 0 - && transaction.Input.ZkSync.Value.PaymasterInput != null - ) - { - var zkTx = await ConvertToZkSyncTransaction(transaction).ConfigureAwait(false); - var zkTxSigned = await EIP712.GenerateSignature_ZkSyncTransaction("zkSync", "2", transaction.Input.ChainId.Value, zkTx, transaction._wallet).ConfigureAwait(false); - hash = await rpc.SendRequestAsync("eth_sendRawTransaction", zkTxSigned).ConfigureAwait(false); - } - else + if (receipt.Status != null && receipt.Status.Value == 0) { - switch (transaction._wallet.AccountType) - { - case ThirdwebAccountType.PrivateKeyAccount: - transaction.Input.Nonce ??= new HexBigInteger(await GetNonce(transaction).ConfigureAwait(false)); - var signedTx = await Sign(transaction); - hash = await rpc.SendRequestAsync("eth_sendRawTransaction", signedTx).ConfigureAwait(false); - break; - case ThirdwebAccountType.SmartAccount: - case ThirdwebAccountType.ExternalAccount: - hash = await transaction._wallet.SendTransaction(transaction.Input).ConfigureAwait(false); - break; - default: - throw new NotImplementedException("Account type not supported"); - } + throw new Exception($"Transaction {txHash} execution reverted."); } - return hash; } + catch (OperationCanceledException) + { + throw new Exception($"Transaction receipt polling for hash {txHash} was cancelled."); + } + + return receipt; + } - /// - /// Sends the transaction and waits for the transaction receipt. - /// - /// The transaction. - /// The transaction receipt. - public static async Task SendAndWaitForTransactionReceipt(ThirdwebTransaction transaction) + /// + /// Waits for the transaction hash given a thirdweb transaction id. Use WaitForTransactionReceipt if you have a transaction hash. + /// + /// The Thirdweb client. + /// The thirdweb transaction id. + /// The cancellation token. + /// The transaction hash. + public static async Task WaitForTransactionHash(ThirdwebClient client, string txId, CancellationToken cancellationToken = default) + { + if (client == null) { - var txHash = await Send(transaction).ConfigureAwait(false); - return await WaitForTransactionReceipt(transaction._wallet.Client, transaction.Input.ChainId.Value, txHash).ConfigureAwait(false); + throw new ArgumentNullException(nameof(client)); } - /// - /// Waits for the transaction receipt. - /// - /// The Thirdweb client. - /// The chain ID. - /// The transaction hash. - /// The cancellation token. - /// The transaction receipt. - public static async Task WaitForTransactionReceipt(ThirdwebClient client, BigInteger chainId, string txHash, CancellationToken cancellationToken = default) + if (string.IsNullOrEmpty(txId)) { - using var cts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken); - cts.CancelAfter(client.FetchTimeoutOptions.GetTimeout(TimeoutType.Other)); + throw new ArgumentException("Transaction id cannot be null or empty.", nameof(txId)); + } + using var cts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken); + cts.CancelAfter(client.FetchTimeoutOptions.GetTimeout(TimeoutType.Other)); - var rpc = ThirdwebRPC.GetRpcInstance(client, chainId); - ThirdwebTransactionReceipt receipt = null; + var api = client.Api; + string hash = null; - try + try + { + do { - do - { - receipt = await rpc.SendRequestAsync("eth_getTransactionReceipt", txHash).ConfigureAwait(false); - if (receipt == null) - { - await Task.Delay(1000, cts.Token).ConfigureAwait(false); - } - } while (receipt == null && !cts.Token.IsCancellationRequested); - - if (receipt == null) - { - throw new Exception($"Transaction {txHash} not found within the timeout period."); - } - - if (receipt.Status != null && receipt.Status.Value == 0) + var resp = await api.GetTransactionByIdAsync(txId, cts.Token).ConfigureAwait(false); + hash = resp?.Result?.TransactionHash; + if (hash == null) { - throw new Exception($"Transaction {txHash} execution reverted."); + await ThirdwebTask.Delay(100, cts.Token).ConfigureAwait(false); } + } while (hash == null && !cts.Token.IsCancellationRequested); - var userOpEvent = receipt.DecodeAllEvents(); - if (userOpEvent != null && userOpEvent.Count > 0 && !userOpEvent[0].Event.Success) - { - var revertReasonEvent = receipt.DecodeAllEvents(); - if (revertReasonEvent != null && revertReasonEvent.Count > 0) - { - var revertReason = revertReasonEvent[0].Event.RevertReason; - var revertReasonString = new FunctionCallDecoder().DecodeFunctionErrorMessage(revertReason.ToHex(true)); - throw new Exception($"Transaction {txHash} execution silently reverted: {revertReasonString}"); - } - else - { - throw new Exception($"Transaction {txHash} execution silently reverted with no reason string"); - } - } - } - catch (OperationCanceledException) + if (hash == null) { - throw new Exception($"Transaction receipt polling for hash {txHash} was cancelled."); + throw new Exception($"Transaction {txId} not found within the timeout period."); } - - return receipt; } - - /// - /// Converts the transaction to a zkSync transaction. - /// - /// The transaction. - /// The zkSync transaction. - public static async Task ConvertToZkSyncTransaction(ThirdwebTransaction transaction) + catch (OperationCanceledException) { - return new AccountAbstraction.ZkSyncAATransaction - { - TxType = 0x71, - From = new HexBigInteger(transaction.Input.From).Value, - To = new HexBigInteger(transaction.Input.To).Value, - GasLimit = transaction.Input.Gas.Value, - GasPerPubdataByteLimit = transaction.Input.ZkSync?.GasPerPubdataByteLimit ?? await GetGasPerPubData(transaction).ConfigureAwait(false), - MaxFeePerGas = transaction.Input.MaxFeePerGas?.Value ?? transaction.Input.GasPrice.Value, - MaxPriorityFeePerGas = transaction.Input.MaxPriorityFeePerGas?.Value ?? 0, - Paymaster = transaction.Input.ZkSync.Value.Paymaster, - Nonce = transaction.Input.Nonce ?? new HexBigInteger(await GetNonce(transaction).ConfigureAwait(false)), - Value = transaction.Input.Value?.Value ?? 0, - Data = transaction.Input.Data?.HexToByteArray() ?? new byte[0], - FactoryDeps = transaction.Input.ZkSync.Value.FactoryDeps, - PaymasterInput = transaction.Input.ZkSync.Value.PaymasterInput - }; + throw new Exception($"Transaction hash polling for id {txId} was cancelled."); } + + return hash; + } + + /// + /// Converts the transaction to a zkSync transaction. + /// + /// The transaction. + /// The zkSync transaction. + public static async Task ConvertToZkSyncTransaction(ThirdwebTransaction transaction) + { + return new AccountAbstraction.ZkSyncAATransaction + { + TxType = 0x71, + From = new HexBigInteger(transaction.Input.From).Value, + To = new HexBigInteger(transaction.Input.To).Value, + GasLimit = transaction.Input.Gas.Value, + GasPerPubdataByteLimit = transaction.Input.ZkSync?.GasPerPubdataByteLimit ?? await GetGasPerPubData(transaction).ConfigureAwait(false), + MaxFeePerGas = transaction.Input.MaxFeePerGas?.Value ?? transaction.Input.GasPrice.Value, + MaxPriorityFeePerGas = transaction.Input.MaxPriorityFeePerGas?.Value ?? 0, + Paymaster = transaction.Input.ZkSync.Value.Paymaster, + Nonce = transaction.Input.Nonce ?? new HexBigInteger(await GetNonce(transaction).ConfigureAwait(false)), + Value = transaction.Input.Value?.Value ?? 0, + Data = transaction.Input.Data?.HexToBytes() ?? Array.Empty(), + FactoryDeps = transaction.Input.ZkSync.Value.FactoryDeps, + PaymasterInput = transaction.Input.ZkSync.Value.PaymasterInput, + }; } } diff --git a/Thirdweb/Thirdweb.Transactions/ThirdwebTransactionInput.cs b/Thirdweb/Thirdweb.Transactions/ThirdwebTransactionInput.cs deleted file mode 100644 index 678db113..00000000 --- a/Thirdweb/Thirdweb.Transactions/ThirdwebTransactionInput.cs +++ /dev/null @@ -1,150 +0,0 @@ -using System.Numerics; -using Nethereum.Hex.HexConvertors.Extensions; -using Nethereum.Hex.HexTypes; -using Newtonsoft.Json; - -namespace Thirdweb -{ - /// - /// Represents the input parameters for a Thirdweb transaction. - /// - public class ThirdwebTransactionInput - { - public ThirdwebTransactionInput() { } - - /// - /// Gets or sets the nonce of the transaction. - /// - [JsonProperty(PropertyName = "nonce")] - public HexBigInteger Nonce { get; set; } - - private string _from; - private string _to; - private string _data; - - /// - /// Gets or sets the sender address of the transaction. - /// - [JsonProperty(PropertyName = "from")] - public string From - { - get => _from.EnsureHexPrefix(); - set => _from = value; - } - - /// - /// Gets or sets the recipient address of the transaction. - /// - [JsonProperty(PropertyName = "to")] - public string To - { - get => _to.EnsureHexPrefix(); - set => _to = value; - } - - /// - /// Gets or sets the gas limit for the transaction. - /// - [JsonProperty(PropertyName = "gas")] - public HexBigInteger Gas { get; set; } - - /// - /// Gets or sets the gas price for the transaction. - /// - [JsonProperty(PropertyName = "gasPrice")] - public HexBigInteger GasPrice { get; set; } - - /// - /// Gets or sets the value to be transferred in the transaction. - /// - [JsonProperty(PropertyName = "value")] - public HexBigInteger Value { get; set; } - - /// - /// Gets or sets the data to be sent with the transaction. - /// - [JsonProperty(PropertyName = "data")] - public string Data - { - get => _data.EnsureHexPrefix(); - set => _data = value; - } - - /// - /// Gets or sets the maximum fee per gas for the transaction. - /// - [JsonProperty(PropertyName = "maxFeePerGas")] - public HexBigInteger MaxFeePerGas { get; set; } - - /// - /// Gets or sets the maximum priority fee per gas for the transaction. - /// - [JsonProperty(PropertyName = "maxPriorityFeePerGas")] - public HexBigInteger MaxPriorityFeePerGas { get; set; } - - /// - /// Gets or sets the chain ID for the transaction. - /// - [JsonProperty(PropertyName = "chainId")] - public HexBigInteger ChainId { get; set; } - - /// - /// Gets or sets the zkSync options for the transaction. - /// - [JsonProperty(PropertyName = "zkSyncOptions", NullValueHandling = NullValueHandling.Ignore)] - public ZkSyncOptions? ZkSync { get; set; } - } - - /// - /// Represents the zkSync options for a transaction. - /// - public struct ZkSyncOptions - { - /// - /// Gets or sets the gas limit per pubdata byte. - /// - [JsonProperty(PropertyName = "gasPerPubdataByteLimit")] - public BigInteger? GasPerPubdataByteLimit { get; set; } - - /// - /// Gets or sets the factory dependencies. - /// - [JsonProperty(PropertyName = "factoryDeps")] - public List FactoryDeps { get; set; } - - /// - /// Gets or sets the paymaster. - /// - [JsonProperty(PropertyName = "paymaster")] - public BigInteger Paymaster { get; set; } - - /// - /// Gets or sets the paymaster input data. - /// - [JsonProperty(PropertyName = "paymasterInput")] - public byte[] PaymasterInput { get; set; } - - /// - /// Initializes a new instance of the struct. - /// - /// The paymaster. - /// The paymaster input data. - /// The gas limit per pubdata byte. - /// The factory dependencies. - public ZkSyncOptions(string paymaster, string paymasterInput, BigInteger? gasPerPubdataByteLimit = null, List factoryDeps = null) - { - if (string.IsNullOrEmpty(paymaster) || string.IsNullOrEmpty(paymasterInput)) - { - Paymaster = 0; - PaymasterInput = null; - } - else - { - Paymaster = new HexBigInteger(paymaster).Value; - PaymasterInput = paymasterInput.HexToByteArray(); - GasPerPubdataByteLimit = gasPerPubdataByteLimit; - FactoryDeps = factoryDeps ?? new List(); - } - } - } -} diff --git a/Thirdweb/Thirdweb.Transactions/ThirdwebTransactionReceipt.cs b/Thirdweb/Thirdweb.Transactions/ThirdwebTransactionReceipt.cs deleted file mode 100644 index 8d675c31..00000000 --- a/Thirdweb/Thirdweb.Transactions/ThirdwebTransactionReceipt.cs +++ /dev/null @@ -1,102 +0,0 @@ -using Nethereum.Hex.HexTypes; -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; - -namespace Thirdweb -{ - /// - /// Represents the receipt of a transaction. - /// - public class ThirdwebTransactionReceipt - { - /// - /// Gets or sets the transaction hash. - /// - [JsonProperty(PropertyName = "transactionHash")] - public string TransactionHash { get; set; } - - /// - /// Gets or sets the transaction index within the block. - /// - [JsonProperty(PropertyName = "transactionIndex")] - public HexBigInteger TransactionIndex { get; set; } - - /// - /// Gets or sets the hash of the block containing the transaction. - /// - [JsonProperty(PropertyName = "blockHash")] - public string BlockHash { get; set; } - - /// - /// Gets or sets the number of the block containing the transaction. - /// - [JsonProperty(PropertyName = "blockNumber")] - public HexBigInteger BlockNumber { get; set; } - - /// - /// Gets or sets the address of the sender. - /// - [JsonProperty(PropertyName = "from")] - public string From { get; set; } - - /// - /// Gets or sets the address of the recipient. - /// - [JsonProperty(PropertyName = "to")] - public string To { get; set; } - - /// - /// Gets or sets the cumulative gas used by the transaction. - /// - [JsonProperty(PropertyName = "cumulativeGasUsed")] - public HexBigInteger CumulativeGasUsed { get; set; } - - /// - /// Gets or sets the gas used by the transaction. - /// - [JsonProperty(PropertyName = "gasUsed")] - public HexBigInteger GasUsed { get; set; } - - /// - /// Gets or sets the effective gas price for the transaction. - /// - [JsonProperty(PropertyName = "effectiveGasPrice")] - public HexBigInteger EffectiveGasPrice { get; set; } - - /// - /// Gets or sets the contract address created by the transaction, if applicable. - /// - [JsonProperty(PropertyName = "contractAddress")] - public string ContractAddress { get; set; } - - /// - /// Gets or sets the status of the transaction. - /// - [JsonProperty(PropertyName = "status")] - public HexBigInteger Status { get; set; } - - /// - /// Gets or sets the logs generated by the transaction. - /// - [JsonProperty(PropertyName = "logs")] - public JArray Logs { get; set; } - - /// - /// Gets or sets the transaction type. - /// - [JsonProperty(PropertyName = "type")] - public HexBigInteger Type { get; set; } - - /// - /// Gets or sets the logs bloom filter. - /// - [JsonProperty(PropertyName = "logsBloom")] - public string LogsBloom { get; set; } - - /// - /// Gets or sets the root of the transaction. - /// - [JsonProperty(PropertyName = "root")] - public string Root { get; set; } - } -} diff --git a/Thirdweb/Thirdweb.Utils/Constants.cs b/Thirdweb/Thirdweb.Utils/Constants.cs index a20182bd..08267613 100644 --- a/Thirdweb/Thirdweb.Utils/Constants.cs +++ b/Thirdweb/Thirdweb.Utils/Constants.cs @@ -1,19 +1,55 @@ -namespace Thirdweb +namespace Thirdweb; + +public static class Constants { - public static class Constants - { - public const string ADDRESS_ZERO = "0x0000000000000000000000000000000000000000"; - public const string NATIVE_TOKEN_ADDRESS = "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE"; - public const double DECIMALS_18 = 1000000000000000000; - - internal const string VERSION = "0.4.0"; - internal const int DEFAULT_FETCH_TIMEOUT = 60000; - internal const string DEFAULT_ENTRYPOINT_ADDRESS = "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789"; // v0.6 - internal const string DEFAULT_FACTORY_ADDRESS = "0x85e23b94e7F5E9cC1fF78BCe78cfb15B81f0DF00"; // v0.6 - internal const string DUMMY_SIG = "0xfffffffffffffffffffffffffffffff0000000000000000000000000000000007aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa1c"; - internal const string DUMMY_PAYMASTER_AND_DATA_HEX = - "0x0101010101010101010101010101010101010101000000000000000000000000000000000000000000000000000001010101010100000000000000000000000000000000000000000000000000000000000000000101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101"; - internal const string FALLBACK_IPFS_GATEWAY = "https://ipfs.io/ipfs/"; - internal const string PIN_URI = "https://storage.thirdweb.com/ipfs/upload"; - } + public const string VERSION = "3.1.1"; + + internal const string SOCIAL_API_URL = "https://social.thirdweb.com"; + internal const string PIN_URI = "https://storage.thirdweb.com/ipfs/upload"; + internal const string FALLBACK_IPFS_GATEWAY = "https://ipfs.io/ipfs/"; + internal const string ENGINE_API_URL = "https://engine.thirdweb.com"; + internal const int DEFAULT_FETCH_TIMEOUT = 120000; + + public const string ADDRESS_ZERO = "0x0000000000000000000000000000000000000000"; + public const string NATIVE_TOKEN_ADDRESS = "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE"; + public const double DECIMALS_18 = 1000000000000000000; + + public const string IERC20_INTERFACE_ID = "0x36372b07"; + public const string IERC721_INTERFACE_ID = "0x80ac58cd"; + public const string IERC1155_INTERFACE_ID = "0xd9b67a26"; + + public const string ENTRYPOINT_ADDRESS_V06 = "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789"; + public const string ENTRYPOINT_ADDRESS_V07 = "0x0000000071727De22E5E9d8BAf0edAc6f37da032"; + + public const string DEFAULT_FACTORY_ADDRESS_V06 = "0x85e23b94e7F5E9cC1fF78BCe78cfb15B81f0DF00"; + public const string DEFAULT_FACTORY_ADDRESS_V07 = "0x4bE0ddfebcA9A5A4a617dee4DeCe99E7c862dceb"; + + public const string EIP_1271_MAGIC_VALUE = "0x1626ba7e00000000000000000000000000000000000000000000000000000000"; + public const string ERC_6492_MAGIC_VALUE = "0x6492649264926492649264926492649264926492649264926492649264926492"; + + internal const string DUMMY_SIG = "0xfffffffffffffffffffffffffffffff0000000000000000000000000000000007aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa1c"; + internal const string DUMMY_PAYMASTER_AND_DATA_HEX = + "0x0101010101010101010101010101010101010101000000000000000000000000000000000000000000000000000001010101010100000000000000000000000000000000000000000000000000000000000000000101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101"; + internal const string ENS_REGISTRY_ADDRESS = "0xce01f8eee7E479C928F8919abD53E553a36CeF67"; + + public const string MINIMAL_ACCOUNT_7702_ABI = + "[{\"inputs\": [{\"internalType\": \"uint256\",\"name\": \"allowanceUsage\",\"type\": \"uint256\"},{\"internalType\": \"uint256\",\"name\": \"limit\",\"type\": \"uint256\"},{\"internalType\": \"uint64\",\"name\": \"period\",\"type\": \"uint64\"}],\"name\": \"AllowanceExceeded\",\"type\": \"error\"},{\"inputs\": [{\"internalType\": \"address\",\"name\": \"target\",\"type\": \"address\"},{\"internalType\": \"bytes4\",\"name\": \"selector\",\"type\": \"bytes4\"}],\"name\": \"CallPolicyViolated\",\"type\": \"error\"},{\"inputs\": [{\"internalType\": \"bytes32\",\"name\": \"param\",\"type\": \"bytes32\"},{\"internalType\": \"bytes32\",\"name\": \"refValue\",\"type\": \"bytes32\"},{\"internalType\": \"uint8\",\"name\": \"condition\",\"type\": \"uint8\"}],\"name\": \"ConditionFailed\",\"type\": \"error\"},{\"inputs\": [{\"internalType\": \"uint256\",\"name\": \"actualLength\",\"type\": \"uint256\"},{\"internalType\": \"uint256\",\"name\": \"expectedLength\",\"type\": \"uint256\"}],\"name\": \"InvalidDataLength\",\"type\": \"error\"},{\"inputs\": [{\"internalType\": \"address\",\"name\": \"msgSender\",\"type\": \"address\"},{\"internalType\": \"address\",\"name\": \"thisAddress\",\"type\": \"address\"}],\"name\": \"InvalidSignature\",\"type\": \"error\"},{\"inputs\": [{\"internalType\": \"uint256\",\"name\": \"lifetimeUsage\",\"type\": \"uint256\"},{\"internalType\": \"uint256\",\"name\": \"limit\",\"type\": \"uint256\"}],\"name\": \"LifetimeUsageExceeded\",\"type\": \"error\"},{\"inputs\": [{\"internalType\": \"uint256\",\"name\": \"value\",\"type\": \"uint256\"},{\"internalType\": \"uint256\",\"name\": \"maxValuePerUse\",\"type\": \"uint256\"}],\"name\": \"MaxValueExceeded\",\"type\": \"error\"},{\"inputs\": [],\"name\": \"NoCallsToExecute\",\"type\": \"error\"},{\"inputs\": [],\"name\": \"SessionExpired\",\"type\": \"error\"},{\"inputs\": [],\"name\": \"SessionExpiresTooSoon\",\"type\": \"error\"},{\"inputs\": [],\"name\": \"SessionZeroSigner\",\"type\": \"error\"},{\"inputs\": [{\"internalType\": \"address\",\"name\": \"target\",\"type\": \"address\"}],\"name\": \"TransferPolicyViolated\",\"type\": \"error\"},{\"inputs\": [],\"name\": \"UIDAlreadyProcessed\",\"type\": \"error\"},{\"anonymous\": false,\"inputs\": [{\"indexed\": true,\"internalType\": \"address\",\"name\": \"user\",\"type\": \"address\"},{\"indexed\": true,\"internalType\": \"address\",\"name\": \"signer\",\"type\": \"address\"},{\"indexed\": true,\"internalType\": \"address\",\"name\": \"executor\",\"type\": \"address\"},{\"indexed\": false,\"internalType\": \"uint256\",\"name\": \"batchSize\",\"type\": \"uint256\"}],\"name\": \"Executed\",\"type\": \"event\"},{\"anonymous\": false,\"inputs\": [{\"indexed\": true,\"internalType\": \"address\",\"name\": \"user\",\"type\": \"address\"},{\"indexed\": true,\"internalType\": \"address\",\"name\": \"newSigner\",\"type\": \"address\"},{\"components\": [{\"internalType\": \"address\",\"name\": \"signer\",\"type\": \"address\"},{\"internalType\": \"bool\",\"name\": \"isWildcard\",\"type\": \"bool\"},{\"internalType\": \"uint256\",\"name\": \"expiresAt\",\"type\": \"uint256\"},{\"components\": [{\"internalType\": \"address\",\"name\": \"target\",\"type\": \"address\"},{\"internalType\": \"bytes4\",\"name\": \"selector\",\"type\": \"bytes4\"},{\"internalType\": \"uint256\",\"name\": \"maxValuePerUse\",\"type\": \"uint256\"},{\"components\": [{\"internalType\": \"enum SessionLib.LimitType\",\"name\": \"limitType\",\"type\": \"uint8\"},{\"internalType\": \"uint256\",\"name\": \"limit\",\"type\": \"uint256\"},{\"internalType\": \"uint256\",\"name\": \"period\",\"type\": \"uint256\"}],\"internalType\": \"struct SessionLib.UsageLimit\",\"name\": \"valueLimit\",\"type\": \"tuple\"},{\"components\": [{\"internalType\": \"enum SessionLib.Condition\",\"name\": \"condition\",\"type\": \"uint8\"},{\"internalType\": \"uint64\",\"name\": \"index\",\"type\": \"uint64\"},{\"internalType\": \"bytes32\",\"name\": \"refValue\",\"type\": \"bytes32\"},{\"components\": [{\"internalType\": \"enum SessionLib.LimitType\",\"name\": \"limitType\",\"type\": \"uint8\"},{\"internalType\": \"uint256\",\"name\": \"limit\",\"type\": \"uint256\"},{\"internalType\": \"uint256\",\"name\": \"period\",\"type\": \"uint256\"}],\"internalType\": \"struct SessionLib.UsageLimit\",\"name\": \"limit\",\"type\": \"tuple\"}],\"internalType\": \"struct SessionLib.Constraint[]\",\"name\": \"constraints\",\"type\": \"tuple[]\"}],\"internalType\": \"struct SessionLib.CallSpec[]\",\"name\": \"callPolicies\",\"type\": \"tuple[]\"},{\"components\": [{\"internalType\": \"address\",\"name\": \"target\",\"type\": \"address\"},{\"internalType\": \"uint256\",\"name\": \"maxValuePerUse\",\"type\": \"uint256\"},{\"components\": [{\"internalType\": \"enum SessionLib.LimitType\",\"name\": \"limitType\",\"type\": \"uint8\"},{\"internalType\": \"uint256\",\"name\": \"limit\",\"type\": \"uint256\"},{\"internalType\": \"uint256\",\"name\": \"period\",\"type\": \"uint256\"}],\"internalType\": \"struct SessionLib.UsageLimit\",\"name\": \"valueLimit\",\"type\": \"tuple\"}],\"internalType\": \"struct SessionLib.TransferSpec[]\",\"name\": \"transferPolicies\",\"type\": \"tuple[]\"},{\"internalType\": \"bytes32\",\"name\": \"uid\",\"type\": \"bytes32\"}],\"indexed\": false,\"internalType\": \"struct SessionLib.SessionSpec\",\"name\": \"sessionSpec\",\"type\": \"tuple\"}],\"name\": \"SessionCreated\",\"type\": \"event\"},{\"anonymous\": false,\"inputs\": [{\"indexed\": true,\"internalType\": \"address\",\"name\": \"user\",\"type\": \"address\"},{\"indexed\": true,\"internalType\": \"address\",\"name\": \"from\",\"type\": \"address\"},{\"indexed\": false,\"internalType\": \"uint256\",\"name\": \"value\",\"type\": \"uint256\"}],\"name\": \"ValueReceived\",\"type\": \"event\"},{\"inputs\": [{\"components\": [{\"internalType\": \"address\",\"name\": \"signer\",\"type\": \"address\"},{\"internalType\": \"bool\",\"name\": \"isWildcard\",\"type\": \"bool\"},{\"internalType\": \"uint256\",\"name\": \"expiresAt\",\"type\": \"uint256\"},{\"components\": [{\"internalType\": \"address\",\"name\": \"target\",\"type\": \"address\"},{\"internalType\": \"bytes4\",\"name\": \"selector\",\"type\": \"bytes4\"},{\"internalType\": \"uint256\",\"name\": \"maxValuePerUse\",\"type\": \"uint256\"},{\"components\": [{\"internalType\": \"enum SessionLib.LimitType\",\"name\": \"limitType\",\"type\": \"uint8\"},{\"internalType\": \"uint256\",\"name\": \"limit\",\"type\": \"uint256\"},{\"internalType\": \"uint256\",\"name\": \"period\",\"type\": \"uint256\"}],\"internalType\": \"struct SessionLib.UsageLimit\",\"name\": \"valueLimit\",\"type\": \"tuple\"},{\"components\": [{\"internalType\": \"enum SessionLib.Condition\",\"name\": \"condition\",\"type\": \"uint8\"},{\"internalType\": \"uint64\",\"name\": \"index\",\"type\": \"uint64\"},{\"internalType\": \"bytes32\",\"name\": \"refValue\",\"type\": \"bytes32\"},{\"components\": [{\"internalType\": \"enum SessionLib.LimitType\",\"name\": \"limitType\",\"type\": \"uint8\"},{\"internalType\": \"uint256\",\"name\": \"limit\",\"type\": \"uint256\"},{\"internalType\": \"uint256\",\"name\": \"period\",\"type\": \"uint256\"}],\"internalType\": \"struct SessionLib.UsageLimit\",\"name\": \"limit\",\"type\": \"tuple\"}],\"internalType\": \"struct SessionLib.Constraint[]\",\"name\": \"constraints\",\"type\": \"tuple[]\"}],\"internalType\": \"struct SessionLib.CallSpec[]\",\"name\": \"callPolicies\",\"type\": \"tuple[]\"},{\"components\": [{\"internalType\": \"address\",\"name\": \"target\",\"type\": \"address\"},{\"internalType\": \"uint256\",\"name\": \"maxValuePerUse\",\"type\": \"uint256\"},{\"components\": [{\"internalType\": \"enum SessionLib.LimitType\",\"name\": \"limitType\",\"type\": \"uint8\"},{\"internalType\": \"uint256\",\"name\": \"limit\",\"type\": \"uint256\"},{\"internalType\": \"uint256\",\"name\": \"period\",\"type\": \"uint256\"}],\"internalType\": \"struct SessionLib.UsageLimit\",\"name\": \"valueLimit\",\"type\": \"tuple\"}],\"internalType\": \"struct SessionLib.TransferSpec[]\",\"name\": \"transferPolicies\",\"type\": \"tuple[]\"},{\"internalType\": \"bytes32\",\"name\": \"uid\",\"type\": \"bytes32\"}],\"internalType\": \"struct SessionLib.SessionSpec\",\"name\": \"sessionSpec\",\"type\": \"tuple\"},{\"internalType\": \"bytes\",\"name\": \"signature\",\"type\": \"bytes\"}],\"name\": \"createSessionWithSig\",\"outputs\": [],\"stateMutability\": \"nonpayable\",\"type\": \"function\"},{\"inputs\": [],\"name\": \"eip712Domain\",\"outputs\": [{\"internalType\": \"bytes1\",\"name\": \"fields\",\"type\": \"bytes1\"},{\"internalType\": \"string\",\"name\": \"name\",\"type\": \"string\"},{\"internalType\": \"string\",\"name\": \"version\",\"type\": \"string\"},{\"internalType\": \"uint256\",\"name\": \"chainId\",\"type\": \"uint256\"},{\"internalType\": \"address\",\"name\": \"verifyingContract\",\"type\": \"address\"},{\"internalType\": \"bytes32\",\"name\": \"salt\",\"type\": \"bytes32\"},{\"internalType\": \"uint256[]\",\"name\": \"extensions\",\"type\": \"uint256[]\"}],\"stateMutability\": \"view\",\"type\": \"function\"},{\"inputs\": [{\"components\": [{\"internalType\": \"address\",\"name\": \"target\",\"type\": \"address\"},{\"internalType\": \"uint256\",\"name\": \"value\",\"type\": \"uint256\"},{\"internalType\": \"bytes\",\"name\": \"data\",\"type\": \"bytes\"}],\"internalType\": \"struct Call[]\",\"name\": \"calls\",\"type\": \"tuple[]\"}],\"name\": \"execute\",\"outputs\": [],\"stateMutability\": \"payable\",\"type\": \"function\"},{\"inputs\": [{\"components\": [{\"components\": [{\"internalType\": \"address\",\"name\": \"target\",\"type\": \"address\"},{\"internalType\": \"uint256\",\"name\": \"value\",\"type\": \"uint256\"},{\"internalType\": \"bytes\",\"name\": \"data\",\"type\": \"bytes\"}],\"internalType\": \"struct Call[]\",\"name\": \"calls\",\"type\": \"tuple[]\"},{\"internalType\": \"bytes32\",\"name\": \"uid\",\"type\": \"bytes32\"}],\"internalType\": \"struct WrappedCalls\",\"name\": \"wrappedCalls\",\"type\": \"tuple\"},{\"internalType\": \"bytes\",\"name\": \"signature\",\"type\": \"bytes\"}],\"name\": \"executeWithSig\",\"outputs\": [],\"stateMutability\": \"payable\",\"type\": \"function\"},{\"inputs\": [{\"internalType\": \"address\",\"name\": \"signer\",\"type\": \"address\"}],\"name\": \"getCallPoliciesForSigner\",\"outputs\": [{\"components\": [{\"internalType\": \"address\",\"name\": \"target\",\"type\": \"address\"},{\"internalType\": \"bytes4\",\"name\": \"selector\",\"type\": \"bytes4\"},{\"internalType\": \"uint256\",\"name\": \"maxValuePerUse\",\"type\": \"uint256\"},{\"components\": [{\"internalType\": \"enum SessionLib.LimitType\",\"name\": \"limitType\",\"type\": \"uint8\"},{\"internalType\": \"uint256\",\"name\": \"limit\",\"type\": \"uint256\"},{\"internalType\": \"uint256\",\"name\": \"period\",\"type\": \"uint256\"}],\"internalType\": \"struct SessionLib.UsageLimit\",\"name\": \"valueLimit\",\"type\": \"tuple\"},{\"components\": [{\"internalType\": \"enum SessionLib.Condition\",\"name\": \"condition\",\"type\": \"uint8\"},{\"internalType\": \"uint64\",\"name\": \"index\",\"type\": \"uint64\"},{\"internalType\": \"bytes32\",\"name\": \"refValue\",\"type\": \"bytes32\"},{\"components\": [{\"internalType\": \"enum SessionLib.LimitType\",\"name\": \"limitType\",\"type\": \"uint8\"},{\"internalType\": \"uint256\",\"name\": \"limit\",\"type\": \"uint256\"},{\"internalType\": \"uint256\",\"name\": \"period\",\"type\": \"uint256\"}],\"internalType\": \"struct SessionLib.UsageLimit\",\"name\": \"limit\",\"type\": \"tuple\"}],\"internalType\": \"struct SessionLib.Constraint[]\",\"name\": \"constraints\",\"type\": \"tuple[]\"}],\"internalType\": \"struct SessionLib.CallSpec[]\",\"name\": \"\",\"type\": \"tuple[]\"}],\"stateMutability\": \"view\",\"type\": \"function\"},{\"inputs\": [{\"internalType\": \"address\",\"name\": \"signer\",\"type\": \"address\"}],\"name\": \"getSessionExpirationForSigner\",\"outputs\": [{\"internalType\": \"uint256\",\"name\": \"\",\"type\": \"uint256\"}],\"stateMutability\": \"view\",\"type\": \"function\"},{\"inputs\": [{\"internalType\": \"address\",\"name\": \"signer\",\"type\": \"address\"}],\"name\": \"getSessionStateForSigner\",\"outputs\": [{\"components\": [{\"components\": [{\"internalType\": \"uint256\",\"name\": \"remaining\",\"type\": \"uint256\"},{\"internalType\": \"address\",\"name\": \"target\",\"type\": \"address\"},{\"internalType\": \"bytes4\",\"name\": \"selector\",\"type\": \"bytes4\"},{\"internalType\": \"uint256\",\"name\": \"index\",\"type\": \"uint256\"}],\"internalType\": \"struct SessionLib.LimitState[]\",\"name\": \"transferValue\",\"type\": \"tuple[]\"},{\"components\": [{\"internalType\": \"uint256\",\"name\": \"remaining\",\"type\": \"uint256\"},{\"internalType\": \"address\",\"name\": \"target\",\"type\": \"address\"},{\"internalType\": \"bytes4\",\"name\": \"selector\",\"type\": \"bytes4\"},{\"internalType\": \"uint256\",\"name\": \"index\",\"type\": \"uint256\"}],\"internalType\": \"struct SessionLib.LimitState[]\",\"name\": \"callValue\",\"type\": \"tuple[]\"},{\"components\": [{\"internalType\": \"uint256\",\"name\": \"remaining\",\"type\": \"uint256\"},{\"internalType\": \"address\",\"name\": \"target\",\"type\": \"address\"},{\"internalType\": \"bytes4\",\"name\": \"selector\",\"type\": \"bytes4\"},{\"internalType\": \"uint256\",\"name\": \"index\",\"type\": \"uint256\"}],\"internalType\": \"struct SessionLib.LimitState[]\",\"name\": \"callParams\",\"type\": \"tuple[]\"}],\"internalType\": \"struct SessionLib.SessionState\",\"name\": \"\",\"type\": \"tuple\"}],\"stateMutability\": \"view\",\"type\": \"function\"},{\"inputs\": [{\"internalType\": \"address\",\"name\": \"signer\",\"type\": \"address\"}],\"name\": \"getTransferPoliciesForSigner\",\"outputs\": [{\"components\": [{\"internalType\": \"address\",\"name\": \"target\",\"type\": \"address\"},{\"internalType\": \"uint256\",\"name\": \"maxValuePerUse\",\"type\": \"uint256\"},{\"components\": [{\"internalType\": \"enum SessionLib.LimitType\",\"name\": \"limitType\",\"type\": \"uint8\"},{\"internalType\": \"uint256\",\"name\": \"limit\",\"type\": \"uint256\"},{\"internalType\": \"uint256\",\"name\": \"period\",\"type\": \"uint256\"}],\"internalType\": \"struct SessionLib.UsageLimit\",\"name\": \"valueLimit\",\"type\": \"tuple\"}],\"internalType\": \"struct SessionLib.TransferSpec[]\",\"name\": \"\",\"type\": \"tuple[]\"}],\"stateMutability\": \"view\",\"type\": \"function\"},{\"inputs\": [{\"internalType\": \"address\",\"name\": \"signer\",\"type\": \"address\"}],\"name\": \"isWildcardSigner\",\"outputs\": [{\"internalType\": \"bool\",\"name\": \"\",\"type\": \"bool\"}],\"stateMutability\": \"view\",\"type\": \"function\"},{\"inputs\": [{\"internalType\": \"address\",\"name\": \"\",\"type\": \"address\"},{\"internalType\": \"address\",\"name\": \"\",\"type\": \"address\"},{\"internalType\": \"uint256[]\",\"name\": \"\",\"type\": \"uint256[]\"},{\"internalType\": \"uint256[]\",\"name\": \"\",\"type\": \"uint256[]\"},{\"internalType\": \"bytes\",\"name\": \"\",\"type\": \"bytes\"}],\"name\": \"onERC1155BatchReceived\",\"outputs\": [{\"internalType\": \"bytes4\",\"name\": \"\",\"type\": \"bytes4\"}],\"stateMutability\": \"nonpayable\",\"type\": \"function\"},{\"inputs\": [{\"internalType\": \"address\",\"name\": \"\",\"type\": \"address\"},{\"internalType\": \"address\",\"name\": \"\",\"type\": \"address\"},{\"internalType\": \"uint256\",\"name\": \"\",\"type\": \"uint256\"},{\"internalType\": \"uint256\",\"name\": \"\",\"type\": \"uint256\"},{\"internalType\": \"bytes\",\"name\": \"\",\"type\": \"bytes\"}],\"name\": \"onERC1155Received\",\"outputs\": [{\"internalType\": \"bytes4\",\"name\": \"\",\"type\": \"bytes4\"}],\"stateMutability\": \"nonpayable\",\"type\": \"function\"},{\"inputs\": [{\"internalType\": \"address\",\"name\": \"\",\"type\": \"address\"},{\"internalType\": \"address\",\"name\": \"\",\"type\": \"address\"},{\"internalType\": \"uint256\",\"name\": \"\",\"type\": \"uint256\"},{\"internalType\": \"bytes\",\"name\": \"\",\"type\": \"bytes\"}],\"name\": \"onERC721Received\",\"outputs\": [{\"internalType\": \"bytes4\",\"name\": \"\",\"type\": \"bytes4\"}],\"stateMutability\": \"nonpayable\",\"type\": \"function\"},{\"inputs\": [{\"internalType\": \"bytes4\",\"name\": \"interfaceId\",\"type\": \"bytes4\"}],\"name\": \"supportsInterface\",\"outputs\": [{\"internalType\": \"bool\",\"name\": \"\",\"type\": \"bool\"}],\"stateMutability\": \"view\",\"type\": \"function\"},{\"stateMutability\": \"payable\",\"type\": \"receive\"}]"; + + public const string MULTICALL3_ADDRESS = "0xcA11bde05977b3631167028862bE2a173976CA11"; + public const string MULTICALL3_ABI = + "[{\"type\":\"function\",\"stateMutability\":\"payable\",\"outputs\":[{\"type\":\"uint256\",\"name\":\"blockNumber\",\"internalType\":\"uint256\"},{\"type\":\"bytes[]\",\"name\":\"returnData\",\"internalType\":\"bytes[]\"}],\"name\":\"aggregate\",\"inputs\":[{\"type\":\"tuple[]\",\"name\":\"calls\",\"internalType\":\"struct Multicall3.Call[]\",\"components\":[{\"type\":\"address\",\"name\":\"target\",\"internalType\":\"address\"},{\"type\":\"bytes\",\"name\":\"callData\",\"internalType\":\"bytes\"}]}]},{\"type\":\"function\",\"stateMutability\":\"payable\",\"outputs\":[{\"type\":\"tuple[]\",\"name\":\"returnData\",\"internalType\":\"struct Multicall3.Result[]\",\"components\":[{\"type\":\"bool\",\"name\":\"success\",\"internalType\":\"bool\"},{\"type\":\"bytes\",\"name\":\"returnData\",\"internalType\":\"bytes\"}]}],\"name\":\"aggregate3\",\"inputs\":[{\"type\":\"tuple[]\",\"name\":\"calls\",\"internalType\":\"struct Multicall3.Call3[]\",\"components\":[{\"type\":\"address\",\"name\":\"target\",\"internalType\":\"address\"},{\"type\":\"bool\",\"name\":\"allowFailure\",\"internalType\":\"bool\"},{\"type\":\"bytes\",\"name\":\"callData\",\"internalType\":\"bytes\"}]}]},{\"type\":\"function\",\"stateMutability\":\"payable\",\"outputs\":[{\"type\":\"tuple[]\",\"name\":\"returnData\",\"internalType\":\"struct Multicall3.Result[]\",\"components\":[{\"type\":\"bool\",\"name\":\"success\",\"internalType\":\"bool\"},{\"type\":\"bytes\",\"name\":\"returnData\",\"internalType\":\"bytes\"}]}],\"name\":\"aggregate3Value\",\"inputs\":[{\"type\":\"tuple[]\",\"name\":\"calls\",\"internalType\":\"struct Multicall3.Call3Value[]\",\"components\":[{\"type\":\"address\",\"name\":\"target\",\"internalType\":\"address\"},{\"type\":\"bool\",\"name\":\"allowFailure\",\"internalType\":\"bool\"},{\"type\":\"uint256\",\"name\":\"value\",\"internalType\":\"uint256\"},{\"type\":\"bytes\",\"name\":\"callData\",\"internalType\":\"bytes\"}]}]},{\"type\":\"function\",\"stateMutability\":\"payable\",\"outputs\":[{\"type\":\"uint256\",\"name\":\"blockNumber\",\"internalType\":\"uint256\"},{\"type\":\"bytes32\",\"name\":\"blockHash\",\"internalType\":\"bytes32\"},{\"type\":\"tuple[]\",\"name\":\"returnData\",\"internalType\":\"struct Multicall3.Result[]\",\"components\":[{\"type\":\"bool\",\"name\":\"success\",\"internalType\":\"bool\"},{\"type\":\"bytes\",\"name\":\"returnData\",\"internalType\":\"bytes\"}]}],\"name\":\"blockAndAggregate\",\"inputs\":[{\"type\":\"tuple[]\",\"name\":\"calls\",\"internalType\":\"struct Multicall3.Call[]\",\"components\":[{\"type\":\"address\",\"name\":\"target\",\"internalType\":\"address\"},{\"type\":\"bytes\",\"name\":\"callData\",\"internalType\":\"bytes\"}]}]},{\"type\":\"function\",\"stateMutability\":\"view\",\"outputs\":[{\"type\":\"uint256\",\"name\":\"basefee\",\"internalType\":\"uint256\"}],\"name\":\"getBasefee\",\"inputs\":[]},{\"type\":\"function\",\"stateMutability\":\"view\",\"outputs\":[{\"type\":\"bytes32\",\"name\":\"blockHash\",\"internalType\":\"bytes32\"}],\"name\":\"getBlockHash\",\"inputs\":[{\"type\":\"uint256\",\"name\":\"blockNumber\",\"internalType\":\"uint256\"}]},{\"type\":\"function\",\"stateMutability\":\"view\",\"outputs\":[{\"type\":\"uint256\",\"name\":\"blockNumber\",\"internalType\":\"uint256\"}],\"name\":\"getBlockNumber\",\"inputs\":[]},{\"type\":\"function\",\"stateMutability\":\"view\",\"outputs\":[{\"type\":\"uint256\",\"name\":\"chainid\",\"internalType\":\"uint256\"}],\"name\":\"getChainId\",\"inputs\":[]},{\"type\":\"function\",\"stateMutability\":\"view\",\"outputs\":[{\"type\":\"address\",\"name\":\"coinbase\",\"internalType\":\"address\"}],\"name\":\"getCurrentBlockCoinbase\",\"inputs\":[]},{\"type\":\"function\",\"stateMutability\":\"view\",\"outputs\":[{\"type\":\"uint256\",\"name\":\"difficulty\",\"internalType\":\"uint256\"}],\"name\":\"getCurrentBlockDifficulty\",\"inputs\":[]},{\"type\":\"function\",\"stateMutability\":\"view\",\"outputs\":[{\"type\":\"uint256\",\"name\":\"gaslimit\",\"internalType\":\"uint256\"}],\"name\":\"getCurrentBlockGasLimit\",\"inputs\":[]},{\"type\":\"function\",\"stateMutability\":\"view\",\"outputs\":[{\"type\":\"uint256\",\"name\":\"timestamp\",\"internalType\":\"uint256\"}],\"name\":\"getCurrentBlockTimestamp\",\"inputs\":[]},{\"type\":\"function\",\"stateMutability\":\"view\",\"outputs\":[{\"type\":\"uint256\",\"name\":\"balance\",\"internalType\":\"uint256\"}],\"name\":\"getEthBalance\",\"inputs\":[{\"type\":\"address\",\"name\":\"addr\",\"internalType\":\"address\"}]},{\"type\":\"function\",\"stateMutability\":\"view\",\"outputs\":[{\"type\":\"bytes32\",\"name\":\"blockHash\",\"internalType\":\"bytes32\"}],\"name\":\"getLastBlockHash\",\"inputs\":[]},{\"type\":\"function\",\"stateMutability\":\"payable\",\"outputs\":[{\"type\":\"tuple[]\",\"name\":\"returnData\",\"internalType\":\"struct Multicall3.Result[]\",\"components\":[{\"type\":\"bool\",\"name\":\"success\",\"internalType\":\"bool\"},{\"type\":\"bytes\",\"name\":\"returnData\",\"internalType\":\"bytes\"}]}],\"name\":\"tryAggregate\",\"inputs\":[{\"type\":\"bool\",\"name\":\"requireSuccess\",\"internalType\":\"bool\"},{\"type\":\"tuple[]\",\"name\":\"calls\",\"internalType\":\"struct Multicall3.Call[]\",\"components\":[{\"type\":\"address\",\"name\":\"target\",\"internalType\":\"address\"},{\"type\":\"bytes\",\"name\":\"callData\",\"internalType\":\"bytes\"}]}]},{\"type\":\"function\",\"stateMutability\":\"payable\",\"outputs\":[{\"type\":\"uint256\",\"name\":\"blockNumber\",\"internalType\":\"uint256\"},{\"type\":\"bytes32\",\"name\":\"blockHash\",\"internalType\":\"bytes32\"},{\"type\":\"tuple[]\",\"name\":\"returnData\",\"internalType\":\"struct Multicall3.Result[]\",\"components\":[{\"type\":\"bool\",\"name\":\"success\",\"internalType\":\"bool\"},{\"type\":\"bytes\",\"name\":\"returnData\",\"internalType\":\"bytes\"}]}],\"name\":\"tryBlockAndAggregate\",\"inputs\":[{\"type\":\"bool\",\"name\":\"requireSuccess\",\"internalType\":\"bool\"},{\"type\":\"tuple[]\",\"name\":\"calls\",\"internalType\":\"struct Multicall3.Call[]\",\"components\":[{\"type\":\"address\",\"name\":\"target\",\"internalType\":\"address\"},{\"type\":\"bytes\",\"name\":\"callData\",\"internalType\":\"bytes\"}]}]}]"; + public const string REDIRECT_HTML = + "

Authentication Complete!

You may close this tab now and return to the game

"; + + internal const string ENTRYPOINT_V06_ABI = + "[{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"preOpGas\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"paid\",\"type\":\"uint256\"},{\"internalType\":\"uint48\",\"name\":\"validAfter\",\"type\":\"uint48\"},{\"internalType\":\"uint48\",\"name\":\"validUntil\",\"type\":\"uint48\"},{\"internalType\":\"bool\",\"name\":\"targetSuccess\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"targetResult\",\"type\":\"bytes\"}],\"name\":\"ExecutionResult\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"opIndex\",\"type\":\"uint256\"},{\"internalType\":\"string\",\"name\":\"reason\",\"type\":\"string\"}],\"name\":\"FailedOp\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"SenderAddressResult\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"aggregator\",\"type\":\"address\"}],\"name\":\"SignatureValidationFailed\",\"type\":\"error\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"preOpGas\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"prefund\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sigFailed\",\"type\":\"bool\"},{\"internalType\":\"uint48\",\"name\":\"validAfter\",\"type\":\"uint48\"},{\"internalType\":\"uint48\",\"name\":\"validUntil\",\"type\":\"uint48\"},{\"internalType\":\"bytes\",\"name\":\"paymasterContext\",\"type\":\"bytes\"}],\"internalType\":\"struct IEntryPoint.ReturnInfo\",\"name\":\"returnInfo\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"stake\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"unstakeDelaySec\",\"type\":\"uint256\"}],\"internalType\":\"struct IStakeManager.StakeInfo\",\"name\":\"senderInfo\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"stake\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"unstakeDelaySec\",\"type\":\"uint256\"}],\"internalType\":\"struct IStakeManager.StakeInfo\",\"name\":\"factoryInfo\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"stake\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"unstakeDelaySec\",\"type\":\"uint256\"}],\"internalType\":\"struct IStakeManager.StakeInfo\",\"name\":\"paymasterInfo\",\"type\":\"tuple\"}],\"name\":\"ValidationResult\",\"type\":\"error\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"preOpGas\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"prefund\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sigFailed\",\"type\":\"bool\"},{\"internalType\":\"uint48\",\"name\":\"validAfter\",\"type\":\"uint48\"},{\"internalType\":\"uint48\",\"name\":\"validUntil\",\"type\":\"uint48\"},{\"internalType\":\"bytes\",\"name\":\"paymasterContext\",\"type\":\"bytes\"}],\"internalType\":\"struct IEntryPoint.ReturnInfo\",\"name\":\"returnInfo\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"stake\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"unstakeDelaySec\",\"type\":\"uint256\"}],\"internalType\":\"struct IStakeManager.StakeInfo\",\"name\":\"senderInfo\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"stake\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"unstakeDelaySec\",\"type\":\"uint256\"}],\"internalType\":\"struct IStakeManager.StakeInfo\",\"name\":\"factoryInfo\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"stake\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"unstakeDelaySec\",\"type\":\"uint256\"}],\"internalType\":\"struct IStakeManager.StakeInfo\",\"name\":\"paymasterInfo\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"aggregator\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"stake\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"unstakeDelaySec\",\"type\":\"uint256\"}],\"internalType\":\"struct IStakeManager.StakeInfo\",\"name\":\"stakeInfo\",\"type\":\"tuple\"}],\"internalType\":\"struct IEntryPoint.AggregatorStakeInfo\",\"name\":\"aggregatorInfo\",\"type\":\"tuple\"}],\"name\":\"ValidationResultWithAggregation\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"userOpHash\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"factory\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"paymaster\",\"type\":\"address\"}],\"name\":\"AccountDeployed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[],\"name\":\"BeforeExecution\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"totalDeposit\",\"type\":\"uint256\"}],\"name\":\"Deposited\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"aggregator\",\"type\":\"address\"}],\"name\":\"SignatureAggregatorChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"totalStaked\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"unstakeDelaySec\",\"type\":\"uint256\"}],\"name\":\"StakeLocked\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"withdrawTime\",\"type\":\"uint256\"}],\"name\":\"StakeUnlocked\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"withdrawAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"StakeWithdrawn\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"userOpHash\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"paymaster\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"success\",\"type\":\"bool\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"actualGasCost\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"actualGasUsed\",\"type\":\"uint256\"}],\"name\":\"UserOperationEvent\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"userOpHash\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"revertReason\",\"type\":\"bytes\"}],\"name\":\"UserOperationRevertReason\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"withdrawAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"Withdrawn\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"SIG_VALIDATION_FAILED\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"initCode\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"paymasterAndData\",\"type\":\"bytes\"}],\"name\":\"_validateSenderAndPaymaster\",\"outputs\":[],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"unstakeDelaySec\",\"type\":\"uint32\"}],\"name\":\"addStake\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"balanceOf\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"depositTo\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"deposits\",\"outputs\":[{\"internalType\":\"uint112\",\"name\":\"deposit\",\"type\":\"uint112\"},{\"internalType\":\"bool\",\"name\":\"staked\",\"type\":\"bool\"},{\"internalType\":\"uint112\",\"name\":\"stake\",\"type\":\"uint112\"},{\"internalType\":\"uint32\",\"name\":\"unstakeDelaySec\",\"type\":\"uint32\"},{\"internalType\":\"uint48\",\"name\":\"withdrawTime\",\"type\":\"uint48\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"getDepositInfo\",\"outputs\":[{\"components\":[{\"internalType\":\"uint112\",\"name\":\"deposit\",\"type\":\"uint112\"},{\"internalType\":\"bool\",\"name\":\"staked\",\"type\":\"bool\"},{\"internalType\":\"uint112\",\"name\":\"stake\",\"type\":\"uint112\"},{\"internalType\":\"uint32\",\"name\":\"unstakeDelaySec\",\"type\":\"uint32\"},{\"internalType\":\"uint48\",\"name\":\"withdrawTime\",\"type\":\"uint48\"}],\"internalType\":\"struct IStakeManager.DepositInfo\",\"name\":\"info\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"uint192\",\"name\":\"key\",\"type\":\"uint192\"}],\"name\":\"getNonce\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"initCode\",\"type\":\"bytes\"}],\"name\":\"getSenderAddress\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"initCode\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"callData\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"callGasLimit\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"verificationGasLimit\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"preVerificationGas\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxFeePerGas\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxPriorityFeePerGas\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"paymasterAndData\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"signature\",\"type\":\"bytes\"}],\"internalType\":\"struct UserOperation\",\"name\":\"userOp\",\"type\":\"tuple\"}],\"name\":\"getUserOpHash\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"initCode\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"callData\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"callGasLimit\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"verificationGasLimit\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"preVerificationGas\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxFeePerGas\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxPriorityFeePerGas\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"paymasterAndData\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"signature\",\"type\":\"bytes\"}],\"internalType\":\"struct UserOperation[]\",\"name\":\"userOps\",\"type\":\"tuple[]\"},{\"internalType\":\"contract IAggregator\",\"name\":\"aggregator\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"signature\",\"type\":\"bytes\"}],\"internalType\":\"struct IEntryPoint.UserOpsPerAggregator[]\",\"name\":\"opsPerAggregator\",\"type\":\"tuple[]\"},{\"internalType\":\"address payable\",\"name\":\"beneficiary\",\"type\":\"address\"}],\"name\":\"handleAggregatedOps\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"initCode\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"callData\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"callGasLimit\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"verificationGasLimit\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"preVerificationGas\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxFeePerGas\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxPriorityFeePerGas\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"paymasterAndData\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"signature\",\"type\":\"bytes\"}],\"internalType\":\"struct UserOperation[]\",\"name\":\"ops\",\"type\":\"tuple[]\"},{\"internalType\":\"address payable\",\"name\":\"beneficiary\",\"type\":\"address\"}],\"name\":\"handleOps\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint192\",\"name\":\"key\",\"type\":\"uint192\"}],\"name\":\"incrementNonce\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"callData\",\"type\":\"bytes\"},{\"components\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"callGasLimit\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"verificationGasLimit\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"preVerificationGas\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"paymaster\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"maxFeePerGas\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxPriorityFeePerGas\",\"type\":\"uint256\"}],\"internalType\":\"struct EntryPoint.MemoryUserOp\",\"name\":\"mUserOp\",\"type\":\"tuple\"},{\"internalType\":\"bytes32\",\"name\":\"userOpHash\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"prefund\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"contextOffset\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"preOpGas\",\"type\":\"uint256\"}],\"internalType\":\"struct EntryPoint.UserOpInfo\",\"name\":\"opInfo\",\"type\":\"tuple\"},{\"internalType\":\"bytes\",\"name\":\"context\",\"type\":\"bytes\"}],\"name\":\"innerHandleOp\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"actualGasCost\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint192\",\"name\":\"\",\"type\":\"uint192\"}],\"name\":\"nonceSequenceNumber\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"initCode\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"callData\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"callGasLimit\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"verificationGasLimit\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"preVerificationGas\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxFeePerGas\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxPriorityFeePerGas\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"paymasterAndData\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"signature\",\"type\":\"bytes\"}],\"internalType\":\"struct UserOperation\",\"name\":\"op\",\"type\":\"tuple\"},{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"targetCallData\",\"type\":\"bytes\"}],\"name\":\"simulateHandleOp\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"initCode\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"callData\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"callGasLimit\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"verificationGasLimit\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"preVerificationGas\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxFeePerGas\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxPriorityFeePerGas\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"paymasterAndData\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"signature\",\"type\":\"bytes\"}],\"internalType\":\"struct UserOperation\",\"name\":\"userOp\",\"type\":\"tuple\"}],\"name\":\"simulateValidation\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"unlockStake\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address payable\",\"name\":\"withdrawAddress\",\"type\":\"address\"}],\"name\":\"withdrawStake\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address payable\",\"name\":\"withdrawAddress\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"withdrawAmount\",\"type\":\"uint256\"}],\"name\":\"withdrawTo\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}]"; + internal const string ENTRYPOINT_V07_ABI = + "[{\"type\": \"error\",\"name\": \"DelegateAndRevert\",\"inputs\": [{\"type\": \"bool\",\"name\": \"success\",\"internalType\": \"bool\"},{\"type\": \"bytes\",\"name\": \"ret\",\"internalType\": \"bytes\"}],\"outputs\": []},{\"type\": \"error\",\"name\": \"FailedOp\",\"inputs\": [{\"type\": \"uint256\",\"name\": \"opIndex\",\"internalType\": \"uint256\"},{\"type\": \"string\",\"name\": \"reason\",\"internalType\": \"string\"}],\"outputs\": []},{\"type\": \"error\",\"name\": \"FailedOpWithRevert\",\"inputs\": [{\"type\": \"uint256\",\"name\": \"opIndex\",\"internalType\": \"uint256\"},{\"type\": \"string\",\"name\": \"reason\",\"internalType\": \"string\"},{\"type\": \"bytes\",\"name\": \"inner\",\"internalType\": \"bytes\"}],\"outputs\": []},{\"type\": \"error\",\"name\": \"PostOpReverted\",\"inputs\": [{\"type\": \"bytes\",\"name\": \"returnData\",\"internalType\": \"bytes\"}],\"outputs\": []},{\"type\": \"error\",\"name\": \"ReentrancyGuardReentrantCall\",\"inputs\": [],\"outputs\": []},{\"type\": \"error\",\"name\": \"SenderAddressResult\",\"inputs\": [{\"type\": \"address\",\"name\": \"sender\",\"internalType\": \"address\"}],\"outputs\": []},{\"type\": \"error\",\"name\": \"SignatureValidationFailed\",\"inputs\": [{\"type\": \"address\",\"name\": \"aggregator\",\"internalType\": \"address\"}],\"outputs\": []},{\"type\": \"event\",\"name\": \"AccountDeployed\",\"inputs\": [{\"type\": \"bytes32\",\"name\": \"userOpHash\",\"indexed\": true,\"internalType\": \"bytes32\"},{\"type\": \"address\",\"name\": \"sender\",\"indexed\": true,\"internalType\": \"address\"},{\"type\": \"address\",\"name\": \"factory\",\"indexed\": false,\"internalType\": \"address\"},{\"type\": \"address\",\"name\": \"paymaster\",\"indexed\": false,\"internalType\": \"address\"}],\"outputs\": [],\"anonymous\": false},{\"type\": \"event\",\"name\": \"BeforeExecution\",\"inputs\": [],\"outputs\": [],\"anonymous\": false},{\"type\": \"event\",\"name\": \"Deposited\",\"inputs\": [{\"type\": \"address\",\"name\": \"account\",\"indexed\": true,\"internalType\": \"address\"},{\"type\": \"uint256\",\"name\": \"totalDeposit\",\"indexed\": false,\"internalType\": \"uint256\"}],\"outputs\": [],\"anonymous\": false},{\"type\": \"event\",\"name\": \"PostOpRevertReason\",\"inputs\": [{\"type\": \"bytes32\",\"name\": \"userOpHash\",\"indexed\": true,\"internalType\": \"bytes32\"},{\"type\": \"address\",\"name\": \"sender\",\"indexed\": true,\"internalType\": \"address\"},{\"type\": \"uint256\",\"name\": \"nonce\",\"indexed\": false,\"internalType\": \"uint256\"},{\"type\": \"bytes\",\"name\": \"revertReason\",\"indexed\": false,\"internalType\": \"bytes\"}],\"outputs\": [],\"anonymous\": false},{\"type\": \"event\",\"name\": \"SignatureAggregatorChanged\",\"inputs\": [{\"type\": \"address\",\"name\": \"aggregator\",\"indexed\": true,\"internalType\": \"address\"}],\"outputs\": [],\"anonymous\": false},{\"type\": \"event\",\"name\": \"StakeLocked\",\"inputs\": [{\"type\": \"address\",\"name\": \"account\",\"indexed\": true,\"internalType\": \"address\"},{\"type\": \"uint256\",\"name\": \"totalStaked\",\"indexed\": false,\"internalType\": \"uint256\"},{\"type\": \"uint256\",\"name\": \"unstakeDelaySec\",\"indexed\": false,\"internalType\": \"uint256\"}],\"outputs\": [],\"anonymous\": false},{\"type\": \"event\",\"name\": \"StakeUnlocked\",\"inputs\": [{\"type\": \"address\",\"name\": \"account\",\"indexed\": true,\"internalType\": \"address\"},{\"type\": \"uint256\",\"name\": \"withdrawTime\",\"indexed\": false,\"internalType\": \"uint256\"}],\"outputs\": [],\"anonymous\": false},{\"type\": \"event\",\"name\": \"StakeWithdrawn\",\"inputs\": [{\"type\": \"address\",\"name\": \"account\",\"indexed\": true,\"internalType\": \"address\"},{\"type\": \"address\",\"name\": \"withdrawAddress\",\"indexed\": false,\"internalType\": \"address\"},{\"type\": \"uint256\",\"name\": \"amount\",\"indexed\": false,\"internalType\": \"uint256\"}],\"outputs\": [],\"anonymous\": false},{\"type\": \"event\",\"name\": \"UserOperationEvent\",\"inputs\": [{\"type\": \"bytes32\",\"name\": \"userOpHash\",\"indexed\": true,\"internalType\": \"bytes32\"},{\"type\": \"address\",\"name\": \"sender\",\"indexed\": true,\"internalType\": \"address\"},{\"type\": \"address\",\"name\": \"paymaster\",\"indexed\": true,\"internalType\": \"address\"},{\"type\": \"uint256\",\"name\": \"nonce\",\"indexed\": false,\"internalType\": \"uint256\"},{\"type\": \"bool\",\"name\": \"success\",\"indexed\": false,\"internalType\": \"bool\"},{\"type\": \"uint256\",\"name\": \"actualGasCost\",\"indexed\": false,\"internalType\": \"uint256\"},{\"type\": \"uint256\",\"name\": \"actualGasUsed\",\"indexed\": false,\"internalType\": \"uint256\"}],\"outputs\": [],\"anonymous\": false},{\"type\": \"event\",\"name\": \"UserOperationPrefundTooLow\",\"inputs\": [{\"type\": \"bytes32\",\"name\": \"userOpHash\",\"indexed\": true,\"internalType\": \"bytes32\"},{\"type\": \"address\",\"name\": \"sender\",\"indexed\": true,\"internalType\": \"address\"},{\"type\": \"uint256\",\"name\": \"nonce\",\"indexed\": false,\"internalType\": \"uint256\"}],\"outputs\": [],\"anonymous\": false},{\"type\": \"event\",\"name\": \"UserOperationRevertReason\",\"inputs\": [{\"type\": \"bytes32\",\"name\": \"userOpHash\",\"indexed\": true,\"internalType\": \"bytes32\"},{\"type\": \"address\",\"name\": \"sender\",\"indexed\": true,\"internalType\": \"address\"},{\"type\": \"uint256\",\"name\": \"nonce\",\"indexed\": false,\"internalType\": \"uint256\"},{\"type\": \"bytes\",\"name\": \"revertReason\",\"indexed\": false,\"internalType\": \"bytes\"}],\"outputs\": [],\"anonymous\": false},{\"type\": \"event\",\"name\": \"Withdrawn\",\"inputs\": [{\"type\": \"address\",\"name\": \"account\",\"indexed\": true,\"internalType\": \"address\"},{\"type\": \"address\",\"name\": \"withdrawAddress\",\"indexed\": false,\"internalType\": \"address\"},{\"type\": \"uint256\",\"name\": \"amount\",\"indexed\": false,\"internalType\": \"uint256\"}],\"outputs\": [],\"anonymous\": false},{\"type\": \"function\",\"name\": \"addStake\",\"inputs\": [{\"type\": \"uint32\",\"name\": \"unstakeDelaySec\",\"internalType\": \"uint32\"}],\"outputs\": [],\"stateMutability\": \"payable\"},{\"type\": \"function\",\"name\": \"balanceOf\",\"inputs\": [{\"type\": \"address\",\"name\": \"account\",\"internalType\": \"address\"}],\"outputs\": [{\"type\": \"uint256\",\"name\": \"\",\"internalType\": \"uint256\"}],\"stateMutability\": \"view\"},{\"type\": \"function\",\"name\": \"delegateAndRevert\",\"inputs\": [{\"type\": \"address\",\"name\": \"target\",\"internalType\": \"address\"},{\"type\": \"bytes\",\"name\": \"data\",\"internalType\": \"bytes\"}],\"outputs\": [],\"stateMutability\": \"nonpayable\"},{\"type\": \"function\",\"name\": \"depositTo\",\"inputs\": [{\"type\": \"address\",\"name\": \"account\",\"internalType\": \"address\"}],\"outputs\": [],\"stateMutability\": \"payable\"},{\"type\": \"function\",\"name\": \"deposits\",\"inputs\": [{\"type\": \"address\",\"name\": \"\",\"internalType\": \"address\"}],\"outputs\": [{\"type\": \"uint256\",\"name\": \"deposit\",\"internalType\": \"uint256\"},{\"type\": \"bool\",\"name\": \"staked\",\"internalType\": \"bool\"},{\"type\": \"uint112\",\"name\": \"stake\",\"internalType\": \"uint112\"},{\"type\": \"uint32\",\"name\": \"unstakeDelaySec\",\"internalType\": \"uint32\"},{\"type\": \"uint48\",\"name\": \"withdrawTime\",\"internalType\": \"uint48\"}],\"stateMutability\": \"view\"},{\"type\": \"function\",\"name\": \"getDepositInfo\",\"inputs\": [{\"type\": \"address\",\"name\": \"account\",\"internalType\": \"address\"}],\"outputs\": [{\"type\": \"tuple\",\"name\": \"info\",\"components\": [{\"type\": \"uint256\",\"name\": \"deposit\",\"internalType\": \"uint256\"},{\"type\": \"bool\",\"name\": \"staked\",\"internalType\": \"bool\"},{\"type\": \"uint112\",\"name\": \"stake\",\"internalType\": \"uint112\"},{\"type\": \"uint32\",\"name\": \"unstakeDelaySec\",\"internalType\": \"uint32\"},{\"type\": \"uint48\",\"name\": \"withdrawTime\",\"internalType\": \"uint48\"}],\"internalType\": \"struct IStakeManager.DepositInfo\"}],\"stateMutability\": \"view\"},{\"type\": \"function\",\"name\": \"getNonce\",\"inputs\": [{\"type\": \"address\",\"name\": \"sender\",\"internalType\": \"address\"},{\"type\": \"uint192\",\"name\": \"key\",\"internalType\": \"uint192\"}],\"outputs\": [{\"type\": \"uint256\",\"name\": \"nonce\",\"internalType\": \"uint256\"}],\"stateMutability\": \"view\"},{\"type\": \"function\",\"name\": \"getSenderAddress\",\"inputs\": [{\"type\": \"bytes\",\"name\": \"initCode\",\"internalType\": \"bytes\"}],\"outputs\": [],\"stateMutability\": \"nonpayable\"},{\"type\": \"function\",\"name\": \"getUserOpHash\",\"inputs\": [{\"type\": \"tuple\",\"name\": \"userOp\",\"components\": [{\"type\": \"address\",\"name\": \"sender\",\"internalType\": \"address\"},{\"type\": \"uint256\",\"name\": \"nonce\",\"internalType\": \"uint256\"},{\"type\": \"bytes\",\"name\": \"initCode\",\"internalType\": \"bytes\"},{\"type\": \"bytes\",\"name\": \"callData\",\"internalType\": \"bytes\"},{\"type\": \"bytes32\",\"name\": \"accountGasLimits\",\"internalType\": \"bytes32\"},{\"type\": \"uint256\",\"name\": \"preVerificationGas\",\"internalType\": \"uint256\"},{\"type\": \"bytes32\",\"name\": \"gasFees\",\"internalType\": \"bytes32\"},{\"type\": \"bytes\",\"name\": \"paymasterAndData\",\"internalType\": \"bytes\"},{\"type\": \"bytes\",\"name\": \"signature\",\"internalType\": \"bytes\"}],\"internalType\": \"struct PackedUserOperation\"}],\"outputs\": [{\"type\": \"bytes32\",\"name\": \"\",\"internalType\": \"bytes32\"}],\"stateMutability\": \"view\"},{\"type\": \"function\",\"name\": \"handleAggregatedOps\",\"inputs\": [{\"type\": \"tuple[]\",\"name\": \"opsPerAggregator\",\"components\": [{\"type\": \"tuple[]\",\"name\": \"userOps\",\"components\": [{\"internalType\": \"address\",\"name\": \"sender\",\"type\": \"address\"},{\"internalType\": \"uint256\",\"name\": \"nonce\",\"type\": \"uint256\"},{\"internalType\": \"bytes\",\"name\": \"initCode\",\"type\": \"bytes\"},{\"internalType\": \"bytes\",\"name\": \"callData\",\"type\": \"bytes\"},{\"internalType\": \"bytes32\",\"name\": \"accountGasLimits\",\"type\": \"bytes32\"},{\"internalType\": \"uint256\",\"name\": \"preVerificationGas\",\"type\": \"uint256\"},{\"internalType\": \"bytes32\",\"name\": \"gasFees\",\"type\": \"bytes32\"},{\"internalType\": \"bytes\",\"name\": \"paymasterAndData\",\"type\": \"bytes\"},{\"internalType\": \"bytes\",\"name\": \"signature\",\"type\": \"bytes\"}],\"internalType\": \"struct PackedUserOperation[]\"},{\"type\": \"address\",\"name\": \"aggregator\",\"internalType\": \"contract IAggregator\"},{\"type\": \"bytes\",\"name\": \"signature\",\"internalType\": \"bytes\"}],\"internalType\": \"struct IEntryPoint.UserOpsPerAggregator[]\"},{\"type\": \"address\",\"name\": \"beneficiary\",\"internalType\": \"address payable\"}],\"outputs\": [],\"stateMutability\": \"nonpayable\"},{\"type\": \"function\",\"name\": \"handleOps\",\"inputs\": [{\"type\": \"tuple[]\",\"name\": \"ops\",\"components\": [{\"type\": \"address\",\"name\": \"sender\",\"internalType\": \"address\"},{\"type\": \"uint256\",\"name\": \"nonce\",\"internalType\": \"uint256\"},{\"type\": \"bytes\",\"name\": \"initCode\",\"internalType\": \"bytes\"},{\"type\": \"bytes\",\"name\": \"callData\",\"internalType\": \"bytes\"},{\"type\": \"bytes32\",\"name\": \"accountGasLimits\",\"internalType\": \"bytes32\"},{\"type\": \"uint256\",\"name\": \"preVerificationGas\",\"internalType\": \"uint256\"},{\"type\": \"bytes32\",\"name\": \"gasFees\",\"internalType\": \"bytes32\"},{\"type\": \"bytes\",\"name\": \"paymasterAndData\",\"internalType\": \"bytes\"},{\"type\": \"bytes\",\"name\": \"signature\",\"internalType\": \"bytes\"}],\"internalType\": \"struct PackedUserOperation[]\"},{\"type\": \"address\",\"name\": \"beneficiary\",\"internalType\": \"address payable\"}],\"outputs\": [],\"stateMutability\": \"nonpayable\"},{\"type\": \"function\",\"name\": \"incrementNonce\",\"inputs\": [{\"type\": \"uint192\",\"name\": \"key\",\"internalType\": \"uint192\"}],\"outputs\": [],\"stateMutability\": \"nonpayable\"},{\"type\": \"function\",\"name\": \"innerHandleOp\",\"inputs\": [{\"type\": \"bytes\",\"name\": \"callData\",\"internalType\": \"bytes\"},{\"type\": \"tuple\",\"name\": \"opInfo\",\"components\": [{\"type\": \"tuple\",\"name\": \"mUserOp\",\"components\": [{\"internalType\": \"address\",\"name\": \"sender\",\"type\": \"address\"},{\"internalType\": \"uint256\",\"name\": \"nonce\",\"type\": \"uint256\"},{\"internalType\": \"uint256\",\"name\": \"verificationGasLimit\",\"type\": \"uint256\"},{\"internalType\": \"uint256\",\"name\": \"callGasLimit\",\"type\": \"uint256\"},{\"internalType\": \"uint256\",\"name\": \"paymasterVerificationGasLimit\",\"type\": \"uint256\"},{\"internalType\": \"uint256\",\"name\": \"paymasterPostOpGasLimit\",\"type\": \"uint256\"},{\"internalType\": \"uint256\",\"name\": \"preVerificationGas\",\"type\": \"uint256\"},{\"internalType\": \"address\",\"name\": \"paymaster\",\"type\": \"address\"},{\"internalType\": \"uint256\",\"name\": \"maxFeePerGas\",\"type\": \"uint256\"},{\"internalType\": \"uint256\",\"name\": \"maxPriorityFeePerGas\",\"type\": \"uint256\"}],\"internalType\": \"struct EntryPoint.MemoryUserOp\"},{\"type\": \"bytes32\",\"name\": \"userOpHash\",\"internalType\": \"bytes32\"},{\"type\": \"uint256\",\"name\": \"prefund\",\"internalType\": \"uint256\"},{\"type\": \"uint256\",\"name\": \"contextOffset\",\"internalType\": \"uint256\"},{\"type\": \"uint256\",\"name\": \"preOpGas\",\"internalType\": \"uint256\"}],\"internalType\": \"struct EntryPoint.UserOpInfo\"},{\"type\": \"bytes\",\"name\": \"context\",\"internalType\": \"bytes\"}],\"outputs\": [{\"type\": \"uint256\",\"name\": \"actualGasCost\",\"internalType\": \"uint256\"}],\"stateMutability\": \"nonpayable\"},{\"type\": \"function\",\"name\": \"nonceSequenceNumber\",\"inputs\": [{\"type\": \"address\",\"name\": \"\",\"internalType\": \"address\"},{\"type\": \"uint192\",\"name\": \"\",\"internalType\": \"uint192\"}],\"outputs\": [{\"type\": \"uint256\",\"name\": \"\",\"internalType\": \"uint256\"}],\"stateMutability\": \"view\"},{\"type\": \"function\",\"name\": \"supportsInterface\",\"inputs\": [{\"type\": \"bytes4\",\"name\": \"interfaceId\",\"internalType\": \"bytes4\"}],\"outputs\": [{\"type\": \"bool\",\"name\": \"\",\"internalType\": \"bool\"}],\"stateMutability\": \"view\"},{\"type\": \"function\",\"name\": \"unlockStake\",\"inputs\": [],\"outputs\": [],\"stateMutability\": \"nonpayable\"},{\"type\": \"function\",\"name\": \"withdrawStake\",\"inputs\": [{\"type\": \"address\",\"name\": \"withdrawAddress\",\"internalType\": \"address payable\"}],\"outputs\": [],\"stateMutability\": \"nonpayable\"},{\"type\": \"function\",\"name\": \"withdrawTo\",\"inputs\": [{\"type\": \"address\",\"name\": \"withdrawAddress\",\"internalType\": \"address payable\"},{\"type\": \"uint256\",\"name\": \"withdrawAmount\",\"internalType\": \"uint256\"}],\"outputs\": [],\"stateMutability\": \"nonpayable\"},{\"type\": \"receive\",\"name\": \"\",\"inputs\": [],\"outputs\": [],\"stateMutability\": \"payable\"}]"; + + internal const string FACTORY_V06_ABI = + "[{\"type\": \"constructor\",\"name\": \"\",\"inputs\": [{\"type\": \"address\",\"name\": \"_defaultAdmin\",\"internalType\": \"address\"},{\"type\": \"address\",\"name\": \"_entrypoint\",\"internalType\": \"contract IEntryPoint\"},{\"type\": \"tuple[]\",\"name\": \"_defaultExtensions\",\"components\": [{\"type\": \"tuple\",\"name\": \"metadata\",\"components\": [{\"internalType\": \"string\",\"name\": \"name\",\"type\": \"string\"},{\"internalType\": \"string\",\"name\": \"metadataURI\",\"type\": \"string\"},{\"internalType\": \"address\",\"name\": \"implementation\",\"type\": \"address\"}],\"internalType\": \"struct IExtension.ExtensionMetadata\"},{\"type\": \"tuple[]\",\"name\": \"functions\",\"components\": [{\"internalType\": \"bytes4\",\"name\": \"functionSelector\",\"type\": \"bytes4\"},{\"internalType\": \"string\",\"name\": \"functionSignature\",\"type\": \"string\"}],\"internalType\": \"struct IExtension.ExtensionFunction[]\"}],\"internalType\": \"struct IExtension.Extension[]\"}],\"outputs\": [],\"stateMutability\": \"nonpayable\"},{\"type\": \"error\",\"name\": \"InvalidCodeAtRange\",\"inputs\": [{\"type\": \"uint256\",\"name\": \"_size\",\"internalType\": \"uint256\"},{\"type\": \"uint256\",\"name\": \"_start\",\"internalType\": \"uint256\"},{\"type\": \"uint256\",\"name\": \"_end\",\"internalType\": \"uint256\"}],\"outputs\": []},{\"type\": \"error\",\"name\": \"WriteError\",\"inputs\": [],\"outputs\": []},{\"type\": \"event\",\"name\": \"AccountCreated\",\"inputs\": [{\"type\": \"address\",\"name\": \"account\",\"indexed\": true,\"internalType\": \"address\"},{\"type\": \"address\",\"name\": \"accountAdmin\",\"indexed\": true,\"internalType\": \"address\"}],\"outputs\": [],\"anonymous\": false},{\"type\": \"event\",\"name\": \"ContractURIUpdated\",\"inputs\": [{\"type\": \"string\",\"name\": \"prevURI\",\"indexed\": false,\"internalType\": \"string\"},{\"type\": \"string\",\"name\": \"newURI\",\"indexed\": false,\"internalType\": \"string\"}],\"outputs\": [],\"anonymous\": false},{\"type\": \"event\",\"name\": \"ExtensionAdded\",\"inputs\": [{\"type\": \"string\",\"name\": \"name\",\"indexed\": true,\"internalType\": \"string\"},{\"type\": \"address\",\"name\": \"implementation\",\"indexed\": true,\"internalType\": \"address\"},{\"type\": \"tuple\",\"name\": \"extension\",\"components\": [{\"type\": \"tuple\",\"name\": \"metadata\",\"components\": [{\"internalType\": \"string\",\"name\": \"name\",\"type\": \"string\"},{\"internalType\": \"string\",\"name\": \"metadataURI\",\"type\": \"string\"},{\"internalType\": \"address\",\"name\": \"implementation\",\"type\": \"address\"}],\"internalType\": \"struct IExtension.ExtensionMetadata\"},{\"type\": \"tuple[]\",\"name\": \"functions\",\"components\": [{\"internalType\": \"bytes4\",\"name\": \"functionSelector\",\"type\": \"bytes4\"},{\"internalType\": \"string\",\"name\": \"functionSignature\",\"type\": \"string\"}],\"internalType\": \"struct IExtension.ExtensionFunction[]\"}],\"indexed\": false,\"internalType\": \"struct IExtension.Extension\"}],\"outputs\": [],\"anonymous\": false},{\"type\": \"event\",\"name\": \"ExtensionRemoved\",\"inputs\": [{\"type\": \"string\",\"name\": \"name\",\"indexed\": true,\"internalType\": \"string\"},{\"type\": \"tuple\",\"name\": \"extension\",\"components\": [{\"type\": \"tuple\",\"name\": \"metadata\",\"components\": [{\"internalType\": \"string\",\"name\": \"name\",\"type\": \"string\"},{\"internalType\": \"string\",\"name\": \"metadataURI\",\"type\": \"string\"},{\"internalType\": \"address\",\"name\": \"implementation\",\"type\": \"address\"}],\"internalType\": \"struct IExtension.ExtensionMetadata\"},{\"type\": \"tuple[]\",\"name\": \"functions\",\"components\": [{\"internalType\": \"bytes4\",\"name\": \"functionSelector\",\"type\": \"bytes4\"},{\"internalType\": \"string\",\"name\": \"functionSignature\",\"type\": \"string\"}],\"internalType\": \"struct IExtension.ExtensionFunction[]\"}],\"indexed\": false,\"internalType\": \"struct IExtension.Extension\"}],\"outputs\": [],\"anonymous\": false},{\"type\": \"event\",\"name\": \"ExtensionReplaced\",\"inputs\": [{\"type\": \"string\",\"name\": \"name\",\"indexed\": true,\"internalType\": \"string\"},{\"type\": \"address\",\"name\": \"implementation\",\"indexed\": true,\"internalType\": \"address\"},{\"type\": \"tuple\",\"name\": \"extension\",\"components\": [{\"type\": \"tuple\",\"name\": \"metadata\",\"components\": [{\"internalType\": \"string\",\"name\": \"name\",\"type\": \"string\"},{\"internalType\": \"string\",\"name\": \"metadataURI\",\"type\": \"string\"},{\"internalType\": \"address\",\"name\": \"implementation\",\"type\": \"address\"}],\"internalType\": \"struct IExtension.ExtensionMetadata\"},{\"type\": \"tuple[]\",\"name\": \"functions\",\"components\": [{\"internalType\": \"bytes4\",\"name\": \"functionSelector\",\"type\": \"bytes4\"},{\"internalType\": \"string\",\"name\": \"functionSignature\",\"type\": \"string\"}],\"internalType\": \"struct IExtension.ExtensionFunction[]\"}],\"indexed\": false,\"internalType\": \"struct IExtension.Extension\"}],\"outputs\": [],\"anonymous\": false},{\"type\": \"event\",\"name\": \"FunctionDisabled\",\"inputs\": [{\"type\": \"string\",\"name\": \"name\",\"indexed\": true,\"internalType\": \"string\"},{\"type\": \"bytes4\",\"name\": \"functionSelector\",\"indexed\": true,\"internalType\": \"bytes4\"},{\"type\": \"tuple\",\"name\": \"extMetadata\",\"components\": [{\"type\": \"string\",\"name\": \"name\",\"internalType\": \"string\"},{\"type\": \"string\",\"name\": \"metadataURI\",\"internalType\": \"string\"},{\"type\": \"address\",\"name\": \"implementation\",\"internalType\": \"address\"}],\"indexed\": false,\"internalType\": \"struct IExtension.ExtensionMetadata\"}],\"outputs\": [],\"anonymous\": false},{\"type\": \"event\",\"name\": \"FunctionEnabled\",\"inputs\": [{\"type\": \"string\",\"name\": \"name\",\"indexed\": true,\"internalType\": \"string\"},{\"type\": \"bytes4\",\"name\": \"functionSelector\",\"indexed\": true,\"internalType\": \"bytes4\"},{\"type\": \"tuple\",\"name\": \"extFunction\",\"components\": [{\"type\": \"bytes4\",\"name\": \"functionSelector\",\"internalType\": \"bytes4\"},{\"type\": \"string\",\"name\": \"functionSignature\",\"internalType\": \"string\"}],\"indexed\": false,\"internalType\": \"struct IExtension.ExtensionFunction\"},{\"type\": \"tuple\",\"name\": \"extMetadata\",\"components\": [{\"type\": \"string\",\"name\": \"name\",\"internalType\": \"string\"},{\"type\": \"string\",\"name\": \"metadataURI\",\"internalType\": \"string\"},{\"type\": \"address\",\"name\": \"implementation\",\"internalType\": \"address\"}],\"indexed\": false,\"internalType\": \"struct IExtension.ExtensionMetadata\"}],\"outputs\": [],\"anonymous\": false},{\"type\": \"event\",\"name\": \"RoleAdminChanged\",\"inputs\": [{\"type\": \"bytes32\",\"name\": \"role\",\"indexed\": true,\"internalType\": \"bytes32\"},{\"type\": \"bytes32\",\"name\": \"previousAdminRole\",\"indexed\": true,\"internalType\": \"bytes32\"},{\"type\": \"bytes32\",\"name\": \"newAdminRole\",\"indexed\": true,\"internalType\": \"bytes32\"}],\"outputs\": [],\"anonymous\": false},{\"type\": \"event\",\"name\": \"RoleGranted\",\"inputs\": [{\"type\": \"bytes32\",\"name\": \"role\",\"indexed\": true,\"internalType\": \"bytes32\"},{\"type\": \"address\",\"name\": \"account\",\"indexed\": true,\"internalType\": \"address\"},{\"type\": \"address\",\"name\": \"sender\",\"indexed\": true,\"internalType\": \"address\"}],\"outputs\": [],\"anonymous\": false},{\"type\": \"event\",\"name\": \"RoleRevoked\",\"inputs\": [{\"type\": \"bytes32\",\"name\": \"role\",\"indexed\": true,\"internalType\": \"bytes32\"},{\"type\": \"address\",\"name\": \"account\",\"indexed\": true,\"internalType\": \"address\"},{\"type\": \"address\",\"name\": \"sender\",\"indexed\": true,\"internalType\": \"address\"}],\"outputs\": [],\"anonymous\": false},{\"type\": \"event\",\"name\": \"SignerAdded\",\"inputs\": [{\"type\": \"address\",\"name\": \"account\",\"indexed\": true,\"internalType\": \"address\"},{\"type\": \"address\",\"name\": \"signer\",\"indexed\": true,\"internalType\": \"address\"}],\"outputs\": [],\"anonymous\": false},{\"type\": \"event\",\"name\": \"SignerRemoved\",\"inputs\": [{\"type\": \"address\",\"name\": \"account\",\"indexed\": true,\"internalType\": \"address\"},{\"type\": \"address\",\"name\": \"signer\",\"indexed\": true,\"internalType\": \"address\"}],\"outputs\": [],\"anonymous\": false},{\"type\": \"fallback\",\"name\": \"\",\"inputs\": [],\"outputs\": [],\"stateMutability\": \"payable\"},{\"type\": \"function\",\"name\": \"DEFAULT_ADMIN_ROLE\",\"inputs\": [],\"outputs\": [{\"type\": \"bytes32\",\"name\": \"\",\"internalType\": \"bytes32\"}],\"stateMutability\": \"view\"},{\"type\": \"function\",\"name\": \"_disableFunctionInExtension\",\"inputs\": [{\"type\": \"string\",\"name\": \"_extensionName\",\"internalType\": \"string\"},{\"type\": \"bytes4\",\"name\": \"_functionSelector\",\"internalType\": \"bytes4\"}],\"outputs\": [],\"stateMutability\": \"nonpayable\"},{\"type\": \"function\",\"name\": \"accountImplementation\",\"inputs\": [],\"outputs\": [{\"type\": \"address\",\"name\": \"\",\"internalType\": \"address\"}],\"stateMutability\": \"view\"},{\"type\": \"function\",\"name\": \"addExtension\",\"inputs\": [{\"type\": \"tuple\",\"name\": \"_extension\",\"components\": [{\"type\": \"tuple\",\"name\": \"metadata\",\"components\": [{\"internalType\": \"string\",\"name\": \"name\",\"type\": \"string\"},{\"internalType\": \"string\",\"name\": \"metadataURI\",\"type\": \"string\"},{\"internalType\": \"address\",\"name\": \"implementation\",\"type\": \"address\"}],\"internalType\": \"struct IExtension.ExtensionMetadata\"},{\"type\": \"tuple[]\",\"name\": \"functions\",\"components\": [{\"internalType\": \"bytes4\",\"name\": \"functionSelector\",\"type\": \"bytes4\"},{\"internalType\": \"string\",\"name\": \"functionSignature\",\"type\": \"string\"}],\"internalType\": \"struct IExtension.ExtensionFunction[]\"}],\"internalType\": \"struct IExtension.Extension\"}],\"outputs\": [],\"stateMutability\": \"nonpayable\"},{\"type\": \"function\",\"name\": \"contractURI\",\"inputs\": [],\"outputs\": [{\"type\": \"string\",\"name\": \"\",\"internalType\": \"string\"}],\"stateMutability\": \"view\"},{\"type\": \"function\",\"name\": \"createAccount\",\"inputs\": [{\"type\": \"address\",\"name\": \"_admin\",\"internalType\": \"address\"},{\"type\": \"bytes\",\"name\": \"_data\",\"internalType\": \"bytes\"}],\"outputs\": [{\"type\": \"address\",\"name\": \"\",\"internalType\": \"address\"}],\"stateMutability\": \"nonpayable\"},{\"type\": \"function\",\"name\": \"defaultExtensions\",\"inputs\": [],\"outputs\": [{\"type\": \"address\",\"name\": \"\",\"internalType\": \"address\"}],\"stateMutability\": \"view\"},{\"type\": \"function\",\"name\": \"disableFunctionInExtension\",\"inputs\": [{\"type\": \"string\",\"name\": \"_extensionName\",\"internalType\": \"string\"},{\"type\": \"bytes4\",\"name\": \"_functionSelector\",\"internalType\": \"bytes4\"}],\"outputs\": [],\"stateMutability\": \"nonpayable\"},{\"type\": \"function\",\"name\": \"enableFunctionInExtension\",\"inputs\": [{\"type\": \"string\",\"name\": \"_extensionName\",\"internalType\": \"string\"},{\"type\": \"tuple\",\"name\": \"_function\",\"components\": [{\"type\": \"bytes4\",\"name\": \"functionSelector\",\"internalType\": \"bytes4\"},{\"type\": \"string\",\"name\": \"functionSignature\",\"internalType\": \"string\"}],\"internalType\": \"struct IExtension.ExtensionFunction\"}],\"outputs\": [],\"stateMutability\": \"nonpayable\"},{\"type\": \"function\",\"name\": \"entrypoint\",\"inputs\": [],\"outputs\": [{\"type\": \"address\",\"name\": \"\",\"internalType\": \"address\"}],\"stateMutability\": \"view\"},{\"type\": \"function\",\"name\": \"getAccounts\",\"inputs\": [{\"type\": \"uint256\",\"name\": \"_start\",\"internalType\": \"uint256\"},{\"type\": \"uint256\",\"name\": \"_end\",\"internalType\": \"uint256\"}],\"outputs\": [{\"type\": \"address[]\",\"name\": \"accounts\",\"internalType\": \"address[]\"}],\"stateMutability\": \"view\"},{\"type\": \"function\",\"name\": \"getAccountsOfSigner\",\"inputs\": [{\"type\": \"address\",\"name\": \"signer\",\"internalType\": \"address\"}],\"outputs\": [{\"type\": \"address[]\",\"name\": \"accounts\",\"internalType\": \"address[]\"}],\"stateMutability\": \"view\"},{\"type\": \"function\",\"name\": \"getAddress\",\"inputs\": [{\"type\": \"address\",\"name\": \"_adminSigner\",\"internalType\": \"address\"},{\"type\": \"bytes\",\"name\": \"_data\",\"internalType\": \"bytes\"}],\"outputs\": [{\"type\": \"address\",\"name\": \"\",\"internalType\": \"address\"}],\"stateMutability\": \"view\"},{\"type\": \"function\",\"name\": \"getAllAccounts\",\"inputs\": [],\"outputs\": [{\"type\": \"address[]\",\"name\": \"\",\"internalType\": \"address[]\"}],\"stateMutability\": \"view\"},{\"type\": \"function\",\"name\": \"getAllExtensions\",\"inputs\": [],\"outputs\": [{\"type\": \"tuple[]\",\"name\": \"allExtensions\",\"components\": [{\"type\": \"tuple\",\"name\": \"metadata\",\"components\": [{\"internalType\": \"string\",\"name\": \"name\",\"type\": \"string\"},{\"internalType\": \"string\",\"name\": \"metadataURI\",\"type\": \"string\"},{\"internalType\": \"address\",\"name\": \"implementation\",\"type\": \"address\"}],\"internalType\": \"struct IExtension.ExtensionMetadata\"},{\"type\": \"tuple[]\",\"name\": \"functions\",\"components\": [{\"internalType\": \"bytes4\",\"name\": \"functionSelector\",\"type\": \"bytes4\"},{\"internalType\": \"string\",\"name\": \"functionSignature\",\"type\": \"string\"}],\"internalType\": \"struct IExtension.ExtensionFunction[]\"}],\"internalType\": \"struct IExtension.Extension[]\"}],\"stateMutability\": \"view\"},{\"type\": \"function\",\"name\": \"getExtension\",\"inputs\": [{\"type\": \"string\",\"name\": \"extensionName\",\"internalType\": \"string\"}],\"outputs\": [{\"type\": \"tuple\",\"name\": \"\",\"components\": [{\"type\": \"tuple\",\"name\": \"metadata\",\"components\": [{\"internalType\": \"string\",\"name\": \"name\",\"type\": \"string\"},{\"internalType\": \"string\",\"name\": \"metadataURI\",\"type\": \"string\"},{\"internalType\": \"address\",\"name\": \"implementation\",\"type\": \"address\"}],\"internalType\": \"struct IExtension.ExtensionMetadata\"},{\"type\": \"tuple[]\",\"name\": \"functions\",\"components\": [{\"internalType\": \"bytes4\",\"name\": \"functionSelector\",\"type\": \"bytes4\"},{\"internalType\": \"string\",\"name\": \"functionSignature\",\"type\": \"string\"}],\"internalType\": \"struct IExtension.ExtensionFunction[]\"}],\"internalType\": \"struct IExtension.Extension\"}],\"stateMutability\": \"view\"},{\"type\": \"function\",\"name\": \"getImplementationForFunction\",\"inputs\": [{\"type\": \"bytes4\",\"name\": \"_functionSelector\",\"internalType\": \"bytes4\"}],\"outputs\": [{\"type\": \"address\",\"name\": \"\",\"internalType\": \"address\"}],\"stateMutability\": \"view\"},{\"type\": \"function\",\"name\": \"getMetadataForFunction\",\"inputs\": [{\"type\": \"bytes4\",\"name\": \"functionSelector\",\"internalType\": \"bytes4\"}],\"outputs\": [{\"type\": \"tuple\",\"name\": \"\",\"components\": [{\"type\": \"string\",\"name\": \"name\",\"internalType\": \"string\"},{\"type\": \"string\",\"name\": \"metadataURI\",\"internalType\": \"string\"},{\"type\": \"address\",\"name\": \"implementation\",\"internalType\": \"address\"}],\"internalType\": \"struct IExtension.ExtensionMetadata\"}],\"stateMutability\": \"view\"},{\"type\": \"function\",\"name\": \"getRoleAdmin\",\"inputs\": [{\"type\": \"bytes32\",\"name\": \"role\",\"internalType\": \"bytes32\"}],\"outputs\": [{\"type\": \"bytes32\",\"name\": \"\",\"internalType\": \"bytes32\"}],\"stateMutability\": \"view\"},{\"type\": \"function\",\"name\": \"getRoleMember\",\"inputs\": [{\"type\": \"bytes32\",\"name\": \"role\",\"internalType\": \"bytes32\"},{\"type\": \"uint256\",\"name\": \"index\",\"internalType\": \"uint256\"}],\"outputs\": [{\"type\": \"address\",\"name\": \"member\",\"internalType\": \"address\"}],\"stateMutability\": \"view\"},{\"type\": \"function\",\"name\": \"getRoleMemberCount\",\"inputs\": [{\"type\": \"bytes32\",\"name\": \"role\",\"internalType\": \"bytes32\"}],\"outputs\": [{\"type\": \"uint256\",\"name\": \"count\",\"internalType\": \"uint256\"}],\"stateMutability\": \"view\"},{\"type\": \"function\",\"name\": \"grantRole\",\"inputs\": [{\"type\": \"bytes32\",\"name\": \"role\",\"internalType\": \"bytes32\"},{\"type\": \"address\",\"name\": \"account\",\"internalType\": \"address\"}],\"outputs\": [],\"stateMutability\": \"nonpayable\"},{\"type\": \"function\",\"name\": \"hasRole\",\"inputs\": [{\"type\": \"bytes32\",\"name\": \"role\",\"internalType\": \"bytes32\"},{\"type\": \"address\",\"name\": \"account\",\"internalType\": \"address\"}],\"outputs\": [{\"type\": \"bool\",\"name\": \"\",\"internalType\": \"bool\"}],\"stateMutability\": \"view\"},{\"type\": \"function\",\"name\": \"hasRoleWithSwitch\",\"inputs\": [{\"type\": \"bytes32\",\"name\": \"role\",\"internalType\": \"bytes32\"},{\"type\": \"address\",\"name\": \"account\",\"internalType\": \"address\"}],\"outputs\": [{\"type\": \"bool\",\"name\": \"\",\"internalType\": \"bool\"}],\"stateMutability\": \"view\"},{\"type\": \"function\",\"name\": \"isRegistered\",\"inputs\": [{\"type\": \"address\",\"name\": \"_account\",\"internalType\": \"address\"}],\"outputs\": [{\"type\": \"bool\",\"name\": \"\",\"internalType\": \"bool\"}],\"stateMutability\": \"view\"},{\"type\": \"function\",\"name\": \"multicall\",\"inputs\": [{\"type\": \"bytes[]\",\"name\": \"data\",\"internalType\": \"bytes[]\"}],\"outputs\": [{\"type\": \"bytes[]\",\"name\": \"results\",\"internalType\": \"bytes[]\"}],\"stateMutability\": \"nonpayable\"},{\"type\": \"function\",\"name\": \"onRegister\",\"inputs\": [{\"type\": \"bytes32\",\"name\": \"_salt\",\"internalType\": \"bytes32\"}],\"outputs\": [],\"stateMutability\": \"nonpayable\"},{\"type\": \"function\",\"name\": \"onSignerAdded\",\"inputs\": [{\"type\": \"address\",\"name\": \"_signer\",\"internalType\": \"address\"},{\"type\": \"bytes32\",\"name\": \"_salt\",\"internalType\": \"bytes32\"}],\"outputs\": [],\"stateMutability\": \"nonpayable\"},{\"type\": \"function\",\"name\": \"onSignerRemoved\",\"inputs\": [{\"type\": \"address\",\"name\": \"_signer\",\"internalType\": \"address\"},{\"type\": \"bytes32\",\"name\": \"_salt\",\"internalType\": \"bytes32\"}],\"outputs\": [],\"stateMutability\": \"nonpayable\"},{\"type\": \"function\",\"name\": \"removeExtension\",\"inputs\": [{\"type\": \"string\",\"name\": \"_extensionName\",\"internalType\": \"string\"}],\"outputs\": [],\"stateMutability\": \"nonpayable\"},{\"type\": \"function\",\"name\": \"renounceRole\",\"inputs\": [{\"type\": \"bytes32\",\"name\": \"role\",\"internalType\": \"bytes32\"},{\"type\": \"address\",\"name\": \"account\",\"internalType\": \"address\"}],\"outputs\": [],\"stateMutability\": \"nonpayable\"},{\"type\": \"function\",\"name\": \"replaceExtension\",\"inputs\": [{\"type\": \"tuple\",\"name\": \"_extension\",\"components\": [{\"type\": \"tuple\",\"name\": \"metadata\",\"components\": [{\"internalType\": \"string\",\"name\": \"name\",\"type\": \"string\"},{\"internalType\": \"string\",\"name\": \"metadataURI\",\"type\": \"string\"},{\"internalType\": \"address\",\"name\": \"implementation\",\"type\": \"address\"}],\"internalType\": \"struct IExtension.ExtensionMetadata\"},{\"type\": \"tuple[]\",\"name\": \"functions\",\"components\": [{\"internalType\": \"bytes4\",\"name\": \"functionSelector\",\"type\": \"bytes4\"},{\"internalType\": \"string\",\"name\": \"functionSignature\",\"type\": \"string\"}],\"internalType\": \"struct IExtension.ExtensionFunction[]\"}],\"internalType\": \"struct IExtension.Extension\"}],\"outputs\": [],\"stateMutability\": \"nonpayable\"},{\"type\": \"function\",\"name\": \"revokeRole\",\"inputs\": [{\"type\": \"bytes32\",\"name\": \"role\",\"internalType\": \"bytes32\"},{\"type\": \"address\",\"name\": \"account\",\"internalType\": \"address\"}],\"outputs\": [],\"stateMutability\": \"nonpayable\"},{\"type\": \"function\",\"name\": \"setContractURI\",\"inputs\": [{\"type\": \"string\",\"name\": \"_uri\",\"internalType\": \"string\"}],\"outputs\": [],\"stateMutability\": \"nonpayable\"},{\"type\": \"function\",\"name\": \"totalAccounts\",\"inputs\": [],\"outputs\": [{\"type\": \"uint256\",\"name\": \"\",\"internalType\": \"uint256\"}],\"stateMutability\": \"view\"}]"; + internal const string FACTORY_V07_ABI = FACTORY_V06_ABI; + internal const string ACCOUNT_V06_ABI = + "[{type: \"constructor\",inputs: [{name: \"_entrypoint\",type: \"address\",internalType: \"contract IEntryPoint\",},{ name: \"_factory\", type: \"address\", internalType: \"address\" },],stateMutability: \"nonpayable\",},{ type: \"receive\", stateMutability: \"payable\" },{type: \"function\",name: \"addDeposit\",inputs: [],outputs: [],stateMutability: \"payable\",},{type: \"function\",name: \"contractURI\",inputs: [],outputs: [{ name: \"\", type: \"string\", internalType: \"string\" }],stateMutability: \"view\",},{type: \"function\",name: \"entryPoint\",inputs: [],outputs: [{ name: \"\", type: \"address\", internalType: \"contract IEntryPoint\" },],stateMutability: \"view\",},{type: \"function\",name: \"execute\",inputs: [{ name: \"_target\", type: \"address\", internalType: \"address\" },{ name: \"_value\", type: \"uint256\", internalType: \"uint256\" },{ name: \"_calldata\", type: \"bytes\", internalType: \"bytes\" },],outputs: [],stateMutability: \"nonpayable\",},{type: \"function\",name: \"executeBatch\",inputs: [{ name: \"_target\", type: \"address[]\", internalType: \"address[]\" },{ name: \"_value\", type: \"uint256[]\", internalType: \"uint256[]\" },{ name: \"_calldata\", type: \"bytes[]\", internalType: \"bytes[]\" },],outputs: [],stateMutability: \"nonpayable\",},{type: \"function\",name: \"factory\",inputs: [],outputs: [{ name: \"\", type: \"address\", internalType: \"address\" }],stateMutability: \"view\",},{type: \"function\",name: \"getAllActiveSigners\",inputs: [],outputs: [{name: \"signers\",type: \"tuple[]\",internalType: \"struct IAccountPermissions.SignerPermissions[]\",components: [{ name: \"signer\", type: \"address\", internalType: \"address\" },{name: \"approvedTargets\",type: \"address[]\",internalType: \"address[]\",},{name: \"nativeTokenLimitPerTransaction\",type: \"uint256\",internalType: \"uint256\",},{ name: \"startTimestamp\", type: \"uint128\", internalType: \"uint128\" },{ name: \"endTimestamp\", type: \"uint128\", internalType: \"uint128\" },],},],stateMutability: \"view\",},{type: \"function\",name: \"getAllAdmins\",inputs: [],outputs: [{ name: \"\", type: \"address[]\", internalType: \"address[]\" }],stateMutability: \"view\",},{type: \"function\",name: \"getAllSigners\",inputs: [],outputs: [{name: \"signers\",type: \"tuple[]\",internalType: \"struct IAccountPermissions.SignerPermissions[]\",components: [{ name: \"signer\", type: \"address\", internalType: \"address\" },{name: \"approvedTargets\",type: \"address[]\",internalType: \"address[]\",},{name: \"nativeTokenLimitPerTransaction\",type: \"uint256\",internalType: \"uint256\",},{ name: \"startTimestamp\", type: \"uint128\", internalType: \"uint128\" },{ name: \"endTimestamp\", type: \"uint128\", internalType: \"uint128\" },],},],stateMutability: \"view\",},{type: \"function\",name: \"getMessageHash\",inputs: [{ name: \"_hash\", type: \"bytes32\", internalType: \"bytes32\" }],outputs: [{ name: \"\", type: \"bytes32\", internalType: \"bytes32\" }],stateMutability: \"view\",},{type: \"function\",name: \"getNonce\",inputs: [],outputs: [{ name: \"\", type: \"uint256\", internalType: \"uint256\" }],stateMutability: \"view\",},{type: \"function\",name: \"getPermissionsForSigner\",inputs: [{ name: \"signer\", type: \"address\", internalType: \"address\" }],outputs: [{name: \"\",type: \"tuple\",internalType: \"struct IAccountPermissions.SignerPermissions\",components: [{ name: \"signer\", type: \"address\", internalType: \"address\" },{name: \"approvedTargets\",type: \"address[]\",internalType: \"address[]\",},{name: \"nativeTokenLimitPerTransaction\",type: \"uint256\",internalType: \"uint256\",},{ name: \"startTimestamp\", type: \"uint128\", internalType: \"uint128\" },{ name: \"endTimestamp\", type: \"uint128\", internalType: \"uint128\" },],},],stateMutability: \"view\",},{type: \"function\",name: \"initialize\",inputs: [{ name: \"_defaultAdmin\", type: \"address\", internalType: \"address\" },{ name: \"_data\", type: \"bytes\", internalType: \"bytes\" },],outputs: [],stateMutability: \"nonpayable\",},{type: \"function\",name: \"isActiveSigner\",inputs: [{ name: \"signer\", type: \"address\", internalType: \"address\" }],outputs: [{ name: \"\", type: \"bool\", internalType: \"bool\" }],stateMutability: \"view\",},{type: \"function\",name: \"isAdmin\",inputs: [{ name: \"_account\", type: \"address\", internalType: \"address\" }],outputs: [{ name: \"\", type: \"bool\", internalType: \"bool\" }],stateMutability: \"view\",},{type: \"function\",name: \"isValidSignature\",inputs: [{ name: \"_hash\", type: \"bytes32\", internalType: \"bytes32\" },{ name: \"_signature\", type: \"bytes\", internalType: \"bytes\" },],outputs: [{ name: \"magicValue\", type: \"bytes4\", internalType: \"bytes4\" }],stateMutability: \"view\",},{type: \"function\",name: \"isValidSigner\",inputs: [{ name: \"_signer\", type: \"address\", internalType: \"address\" },{name: \"_userOp\",type: \"tuple\",internalType: \"struct UserOperation\",components: [{ name: \"sender\", type: \"address\", internalType: \"address\" },{ name: \"nonce\", type: \"uint256\", internalType: \"uint256\" },{ name: \"initCode\", type: \"bytes\", internalType: \"bytes\" },{ name: \"callData\", type: \"bytes\", internalType: \"bytes\" },{ name: \"callGasLimit\", type: \"uint256\", internalType: \"uint256\" },{name: \"verificationGasLimit\",type: \"uint256\",internalType: \"uint256\",},{name: \"preVerificationGas\",type: \"uint256\",internalType: \"uint256\",},{ name: \"maxFeePerGas\", type: \"uint256\", internalType: \"uint256\" },{name: \"maxPriorityFeePerGas\",type: \"uint256\",internalType: \"uint256\",},{ name: \"paymasterAndData\", type: \"bytes\", internalType: \"bytes\" },{ name: \"signature\", type: \"bytes\", internalType: \"bytes\" },],},],outputs: [{ name: \"\", type: \"bool\", internalType: \"bool\" }],stateMutability: \"view\",},{type: \"function\",name: \"multicall\",inputs: [{ name: \"data\", type: \"bytes[]\", internalType: \"bytes[]\" }],outputs: [{ name: \"results\", type: \"bytes[]\", internalType: \"bytes[]\" }],stateMutability: \"nonpayable\",},{type: \"function\",name: \"onERC1155BatchReceived\",inputs: [{ name: \"\", type: \"address\", internalType: \"address\" },{ name: \"\", type: \"address\", internalType: \"address\" },{ name: \"\", type: \"uint256[]\", internalType: \"uint256[]\" },{ name: \"\", type: \"uint256[]\", internalType: \"uint256[]\" },{ name: \"\", type: \"bytes\", internalType: \"bytes\" },],outputs: [{ name: \"\", type: \"bytes4\", internalType: \"bytes4\" }],stateMutability: \"nonpayable\",},{type: \"function\",name: \"onERC1155Received\",inputs: [{ name: \"\", type: \"address\", internalType: \"address\" },{ name: \"\", type: \"address\", internalType: \"address\" },{ name: \"\", type: \"uint256\", internalType: \"uint256\" },{ name: \"\", type: \"uint256\", internalType: \"uint256\" },{ name: \"\", type: \"bytes\", internalType: \"bytes\" },],outputs: [{ name: \"\", type: \"bytes4\", internalType: \"bytes4\" }],stateMutability: \"nonpayable\",},{type: \"function\",name: \"onERC721Received\",inputs: [{ name: \"\", type: \"address\", internalType: \"address\" },{ name: \"\", type: \"address\", internalType: \"address\" },{ name: \"\", type: \"uint256\", internalType: \"uint256\" },{ name: \"\", type: \"bytes\", internalType: \"bytes\" },],outputs: [{ name: \"\", type: \"bytes4\", internalType: \"bytes4\" }],stateMutability: \"nonpayable\",},{type: \"function\",name: \"setContractURI\",inputs: [{ name: \"_uri\", type: \"string\", internalType: \"string\" }],outputs: [],stateMutability: \"nonpayable\",},{type: \"function\",name: \"setEntrypointOverride\",inputs: [{name: \"_entrypointOverride\",type: \"address\",internalType: \"contract IEntryPoint\",},],outputs: [],stateMutability: \"nonpayable\",},{type: \"function\",name: \"setPermissionsForSigner\",inputs: [{name: \"_req\",type: \"tuple\",internalType: \"struct IAccountPermissions.SignerPermissionRequest\",components: [{ name: \"signer\", type: \"address\", internalType: \"address\" },{ name: \"isAdmin\", type: \"uint8\", internalType: \"uint8\" },{name: \"approvedTargets\",type: \"address[]\",internalType: \"address[]\",},{name: \"nativeTokenLimitPerTransaction\",type: \"uint256\",internalType: \"uint256\",},{name: \"permissionStartTimestamp\",type: \"uint128\",internalType: \"uint128\",},{name: \"permissionEndTimestamp\",type: \"uint128\",internalType: \"uint128\",},{name: \"reqValidityStartTimestamp\",type: \"uint128\",internalType: \"uint128\",},{name: \"reqValidityEndTimestamp\",type: \"uint128\",internalType: \"uint128\",},{ name: \"uid\", type: \"bytes32\", internalType: \"bytes32\" },],},{ name: \"_signature\", type: \"bytes\", internalType: \"bytes\" },],outputs: [],stateMutability: \"nonpayable\",},{type: \"function\",name: \"supportsInterface\",inputs: [{ name: \"interfaceId\", type: \"bytes4\", internalType: \"bytes4\" }],outputs: [{ name: \"\", type: \"bool\", internalType: \"bool\" }],stateMutability: \"view\",},{type: \"function\",name: \"validateUserOp\",inputs: [{name: \"userOp\",type: \"tuple\",internalType: \"struct UserOperation\",components: [{ name: \"sender\", type: \"address\", internalType: \"address\" },{ name: \"nonce\", type: \"uint256\", internalType: \"uint256\" },{ name: \"initCode\", type: \"bytes\", internalType: \"bytes\" },{ name: \"callData\", type: \"bytes\", internalType: \"bytes\" },{ name: \"callGasLimit\", type: \"uint256\", internalType: \"uint256\" },{name: \"verificationGasLimit\",type: \"uint256\",internalType: \"uint256\",},{name: \"preVerificationGas\",type: \"uint256\",internalType: \"uint256\",},{ name: \"maxFeePerGas\", type: \"uint256\", internalType: \"uint256\" },{name: \"maxPriorityFeePerGas\",type: \"uint256\",internalType: \"uint256\",},{ name: \"paymasterAndData\", type: \"bytes\", internalType: \"bytes\" },{ name: \"signature\", type: \"bytes\", internalType: \"bytes\" },],},{ name: \"userOpHash\", type: \"bytes32\", internalType: \"bytes32\" },{ name: \"missingAccountFunds\", type: \"uint256\", internalType: \"uint256\" },],outputs: [{ name: \"validationData\", type: \"uint256\", internalType: \"uint256\" },],stateMutability: \"nonpayable\",},{type: \"function\",name: \"verifySignerPermissionRequest\",inputs: [{name: \"req\",type: \"tuple\",internalType: \"struct IAccountPermissions.SignerPermissionRequest\",components: [{ name: \"signer\", type: \"address\", internalType: \"address\" },{ name: \"isAdmin\", type: \"uint8\", internalType: \"uint8\" },{name: \"approvedTargets\",type: \"address[]\",internalType: \"address[]\",},{name: \"nativeTokenLimitPerTransaction\",type: \"uint256\",internalType: \"uint256\",},{name: \"permissionStartTimestamp\",type: \"uint128\",internalType: \"uint128\",},{name: \"permissionEndTimestamp\",type: \"uint128\",internalType: \"uint128\",},{name: \"reqValidityStartTimestamp\",type: \"uint128\",internalType: \"uint128\",},{name: \"reqValidityEndTimestamp\",type: \"uint128\",internalType: \"uint128\",},{ name: \"uid\", type: \"bytes32\", internalType: \"bytes32\" },],},{ name: \"signature\", type: \"bytes\", internalType: \"bytes\" },],outputs: [{ name: \"success\", type: \"bool\", internalType: \"bool\" },{ name: \"signer\", type: \"address\", internalType: \"address\" },],stateMutability: \"view\",},{type: \"function\",name: \"withdrawDepositTo\",inputs: [{name: \"withdrawAddress\",type: \"address\",internalType: \"address payable\",},{ name: \"amount\", type: \"uint256\", internalType: \"uint256\" },],outputs: [],stateMutability: \"nonpayable\",},{type: \"event\",name: \"AdminUpdated\",inputs: [{name: \"signer\",type: \"address\",indexed: true,internalType: \"address\",},{ name: \"isAdmin\", type: \"bool\", indexed: false, internalType: \"bool\" },],anonymous: false,},{type: \"event\",name: \"ContractURIUpdated\",inputs: [{name: \"prevURI\",type: \"string\",indexed: false,internalType: \"string\",},{name: \"newURI\",type: \"string\",indexed: false,internalType: \"string\",},],anonymous: false,},{type: \"event\",name: \"Initialized\",inputs: [{ name: \"version\", type: \"uint8\", indexed: false, internalType: \"uint8\" },],anonymous: false,},{type: \"event\",name: \"SignerPermissionsUpdated\",inputs: [{name: \"authorizingSigner\",type: \"address\",indexed: true,internalType: \"address\",},{name: \"targetSigner\",type: \"address\",indexed: true,internalType: \"address\",},{name: \"permissions\",type: \"tuple\",indexed: false,internalType: \"struct IAccountPermissions.SignerPermissionRequest\",components: [{ name: \"signer\", type: \"address\", internalType: \"address\" },{ name: \"isAdmin\", type: \"uint8\", internalType: \"uint8\" },{name: \"approvedTargets\",type: \"address[]\",internalType: \"address[]\",},{name: \"nativeTokenLimitPerTransaction\",type: \"uint256\",internalType: \"uint256\",},{name: \"permissionStartTimestamp\",type: \"uint128\",internalType: \"uint128\",},{name: \"permissionEndTimestamp\",type: \"uint128\",internalType: \"uint128\",},{name: \"reqValidityStartTimestamp\",type: \"uint128\",internalType: \"uint128\",},{name: \"reqValidityEndTimestamp\",type: \"uint128\",internalType: \"uint128\",},{ name: \"uid\", type: \"bytes32\", internalType: \"bytes32\" },],},],anonymous: false,},]"; + internal const string ACCOUNT_V07_ABI = ACCOUNT_V06_ABI; } diff --git a/Thirdweb/Thirdweb.Utils/EIP712.cs b/Thirdweb/Thirdweb.Utils/EIP712.cs new file mode 100644 index 00000000..dcd8e466 --- /dev/null +++ b/Thirdweb/Thirdweb.Utils/EIP712.cs @@ -0,0 +1,448 @@ +using System.Numerics; +using Nethereum.ABI.EIP712; +using Nethereum.Model; +using Nethereum.Signer; + +namespace Thirdweb; + +/// +/// Provides methods for generating and signing EIP712 compliant messages and transactions. +/// +public static class EIP712 +{ + #region Generation + + /// + /// Generates a signature for a 7702 smart account wrapped calls request. + /// + /// The domain name. + /// The version. + /// The chain ID. + /// The verifying contract. + /// The wrapped calls request. + /// The wallet signer. + public static async Task GenerateSignature_SmartAccount_7702_WrappedCalls( + string domainName, + string version, + BigInteger chainId, + string verifyingContract, + AccountAbstraction.WrappedCalls wrappedCalls, + IThirdwebWallet signer + ) + { + var typedData = GetTypedDefinition_SmartAccount_7702_WrappedCalls(domainName, version, chainId, verifyingContract); + return await signer.SignTypedDataV4(wrappedCalls, typedData); + } + + /// + /// Generates a signature for a 7702 smart account session key. + /// + /// The domain name. + /// The version. + /// The chain ID. + /// The verifying contract. + /// The session key request. + /// The wallet signer. + /// The generated signature. + public static async Task GenerateSignature_SmartAccount_7702( + string domainName, + string version, + BigInteger chainId, + string verifyingContract, + AccountAbstraction.SessionSpec sessionKeyParams, + IThirdwebWallet signer + ) + { + var typedData = GetTypedDefinition_SmartAccount_7702(domainName, version, chainId, verifyingContract); + return await signer.SignTypedDataV4(sessionKeyParams, typedData); + } + + /// + /// Generates a signature for a smart account permission request. + /// + /// The domain name. + /// The version. + /// The chain ID. + /// The verifying contract. + /// The signer permission request. + /// The wallet signer. + /// The generated signature. + public static async Task GenerateSignature_SmartAccount( + string domainName, + string version, + BigInteger chainId, + string verifyingContract, + AccountAbstraction.SignerPermissionRequest signerPermissionRequest, + IThirdwebWallet signer + ) + { + var typedData = GetTypedDefinition_SmartAccount(domainName, version, chainId, verifyingContract); + return await signer.SignTypedDataV4(signerPermissionRequest, typedData); + } + + /// + /// Generates a signature for a smart account message. + /// + /// The domain name. + /// The version. + /// The chain ID. + /// The verifying contract. + /// The message to sign. + /// The wallet signer. + /// The generated signature. + public static async Task GenerateSignature_SmartAccount_AccountMessage( + string domainName, + string version, + BigInteger chainId, + string verifyingContract, + byte[] message, + IThirdwebWallet signer + ) + { + var typedData = GetTypedDefinition_SmartAccount_AccountMessage(domainName, version, chainId, verifyingContract); + var accountMessage = new AccountAbstraction.AccountMessage { Message = message }; + return await signer.SignTypedDataV4(accountMessage, typedData); + } + + /// + /// Generates a signature for a zkSync transaction. + /// + /// The domain name. + /// The version. + /// The chain ID. + /// The zkSync transaction. + /// The wallet signer. + /// The generated signature. + public static async Task GenerateSignature_ZkSyncTransaction( + string domainName, + string version, + BigInteger chainId, + AccountAbstraction.ZkSyncAATransaction transaction, + IThirdwebWallet signer + ) + { + var typedData = GetTypedDefinition_ZkSyncTransaction(domainName, version, chainId); + var signatureHex = await signer.SignTypedDataV4(transaction, typedData); + var signatureRaw = EthECDSASignatureFactory.ExtractECDSASignature(signatureHex); + return SerializeEip712(transaction, signatureRaw, chainId); + } + + /// + /// Generates a signature for an ERC20 token mint request. + /// + /// The domain name. + /// The version. + /// The chain ID. + /// The verifying contract. + /// The mint request. + /// The wallet signer. + /// The generated signature. + public static async Task GenerateSignature_TokenERC20( + string domainName, + string version, + BigInteger chainId, + string verifyingContract, + TokenERC20_MintRequest mintRequest, + IThirdwebWallet signer + ) + { + var typedData = GetTypedDefinition_TokenERC20(domainName, version, chainId, verifyingContract); + return await signer.SignTypedDataV4(mintRequest, typedData); + } + + /// + /// Generates a signature for an ERC721 token mint request. + /// + /// The domain name. + /// The version. + /// The chain ID. + /// The verifying contract. + /// The mint request. + /// The wallet signer. + /// The generated signature. + public static async Task GenerateSignature_TokenERC721( + string domainName, + string version, + BigInteger chainId, + string verifyingContract, + TokenERC721_MintRequest mintRequest, + IThirdwebWallet signer + ) + { + var typedData = GetTypedDefinition_TokenERC721(domainName, version, chainId, verifyingContract); + return await signer.SignTypedDataV4(mintRequest, typedData); + } + + /// + /// Generates a signature for an ERC1155 token mint request. + /// + /// The domain name. + /// The version. + /// The chain ID. + /// The verifying contract. + /// The mint request. + /// The wallet signer. + /// The generated signature. + public static async Task GenerateSignature_TokenERC1155( + string domainName, + string version, + BigInteger chainId, + string verifyingContract, + TokenERC1155_MintRequest mintRequest, + IThirdwebWallet signer + ) + { + var typedData = GetTypedDefinition_TokenERC1155(domainName, version, chainId, verifyingContract); + return await signer.SignTypedDataV4(mintRequest, typedData); + } + + #endregion + + #region Typed Definitions + + /// + /// Gets the typed data definition for a 7702 smart account wrapped calls request. + /// + /// The domain name. + /// The version. + /// The chain ID. + /// The verifying contract. + /// The typed data definition. + public static TypedData GetTypedDefinition_SmartAccount_7702_WrappedCalls(string domainName, string version, BigInteger chainId, string verifyingContract) + { + return new TypedData + { + Domain = new Domain + { + Name = domainName, + Version = version, + ChainId = chainId, + VerifyingContract = verifyingContract, + }, + Types = MemberDescriptionFactory.GetTypesMemberDescription(typeof(Domain), typeof(AccountAbstraction.WrappedCalls), typeof(AccountAbstraction.Call)), + PrimaryType = "WrappedCalls", + }; + } + + /// + /// Gets the typed data definition for a 7702 smart account session key. + /// + /// The domain name. + /// The version. + /// The chain ID. + /// The verifying contract. + /// The typed data definition. + public static TypedData GetTypedDefinition_SmartAccount_7702(string domainName, string version, BigInteger chainId, string verifyingContract) + { + return new TypedData + { + Domain = new Domain + { + Name = domainName, + Version = version, + ChainId = chainId, + VerifyingContract = verifyingContract, + }, + Types = MemberDescriptionFactory.GetTypesMemberDescription( + typeof(Domain), + typeof(AccountAbstraction.SessionSpec), + typeof(AccountAbstraction.CallSpec), + typeof(AccountAbstraction.Constraint), + typeof(AccountAbstraction.TransferSpec), + typeof(AccountAbstraction.UsageLimit) + ), + PrimaryType = "SessionSpec", + }; + } + + /// + /// Gets the typed data definition for a smart account permission request. + /// + /// The domain name. + /// The version. + /// The chain ID. + /// The verifying contract. + /// The typed data definition. + public static TypedData GetTypedDefinition_SmartAccount(string domainName, string version, BigInteger chainId, string verifyingContract) + { + return new TypedData + { + Domain = new Domain + { + Name = domainName, + Version = version, + ChainId = chainId, + VerifyingContract = verifyingContract, + }, + Types = MemberDescriptionFactory.GetTypesMemberDescription(typeof(Domain), typeof(AccountAbstraction.SignerPermissionRequest)), + PrimaryType = "SignerPermissionRequest", + }; + } + + /// + /// Gets the typed data definition for a smart account message. + /// + /// The domain name. + /// The version. + /// The chain ID. + /// The verifying contract. + /// The typed data definition. + public static TypedData GetTypedDefinition_SmartAccount_AccountMessage(string domainName, string version, BigInteger chainId, string verifyingContract) + { + return new TypedData + { + Domain = new Domain + { + Name = domainName, + Version = version, + ChainId = chainId, + VerifyingContract = verifyingContract, + }, + Types = MemberDescriptionFactory.GetTypesMemberDescription(typeof(Domain), typeof(AccountAbstraction.AccountMessage)), + PrimaryType = "AccountMessage", + }; + } + + /// + /// Gets the typed data definition for a zkSync transaction. + /// + /// The domain name. + /// The version. + /// The chain ID. + /// The typed data definition. + public static TypedData GetTypedDefinition_ZkSyncTransaction(string domainName, string version, BigInteger chainId) + { + return new TypedData + { + Domain = new DomainWithNameVersionAndChainId + { + Name = domainName, + Version = version, + ChainId = chainId, + }, + Types = MemberDescriptionFactory.GetTypesMemberDescription(typeof(DomainWithNameVersionAndChainId), typeof(AccountAbstraction.ZkSyncAATransaction)), + PrimaryType = "Transaction", + }; + } + + /// + /// Gets the typed data definition for a TokenERC20 mint request. + /// + /// The domain name. + /// The version. + /// The chain ID. + /// The verifying contract. + /// The typed data definition. + public static TypedData GetTypedDefinition_TokenERC20(string domainName, string version, BigInteger chainId, string verifyingContract) + { + return new TypedData + { + Domain = new Domain + { + Name = domainName, + Version = version, + ChainId = chainId, + VerifyingContract = verifyingContract, + }, + Types = MemberDescriptionFactory.GetTypesMemberDescription(typeof(Domain), typeof(TokenERC20_MintRequest)), + PrimaryType = "MintRequest", + }; + } + + /// + /// Gets the typed data definition for a TokenERC721 mint request. + /// + /// The domain name. + /// The version. + /// The chain ID. + /// The verifying contract. + /// The typed data definition. + public static TypedData GetTypedDefinition_TokenERC721(string domainName, string version, BigInteger chainId, string verifyingContract) + { + return new TypedData + { + Domain = new Domain + { + Name = domainName, + Version = version, + ChainId = chainId, + VerifyingContract = verifyingContract, + }, + Types = MemberDescriptionFactory.GetTypesMemberDescription(typeof(Domain), typeof(TokenERC721_MintRequest)), + PrimaryType = "MintRequest", + }; + } + + /// + /// Gets the typed data definition for a TokenERC1155 mint request. + /// + /// The domain name. + /// The version. + /// The chain ID. + /// The verifying contract. + /// The typed data definition. + public static TypedData GetTypedDefinition_TokenERC1155(string domainName, string version, BigInteger chainId, string verifyingContract) + { + return new TypedData + { + Domain = new Domain + { + Name = domainName, + Version = version, + ChainId = chainId, + VerifyingContract = verifyingContract, + }, + Types = MemberDescriptionFactory.GetTypesMemberDescription(typeof(Domain), typeof(TokenERC1155_MintRequest)), + PrimaryType = "MintRequest", + }; + } + + #endregion + + #region Helpers + + private static readonly int[] _indexOfListDataItems = new int[] { 13, 15 }; + + /// + /// Serializes an EIP712 zkSync transaction. + /// + /// The transaction. + /// The ECDSA signature. + /// The chain ID. + /// The serialized transaction. + private static string SerializeEip712(AccountAbstraction.ZkSyncAATransaction transaction, EthECDSASignature signature, BigInteger chainId) + { + if (chainId == 0) + { + throw new ArgumentException("Chain ID must be provided for EIP712 transactions!"); + } + + var fields = new List + { + transaction.Nonce == 0 ? Array.Empty() : transaction.Nonce.ToByteArray(isUnsigned: true, isBigEndian: true), + transaction.MaxPriorityFeePerGas == 0 ? Array.Empty() : transaction.MaxPriorityFeePerGas.ToByteArray(isUnsigned: true, isBigEndian: true), + transaction.MaxFeePerGas.ToByteArray(isUnsigned: true, isBigEndian: true), + transaction.GasLimit.ToByteArray(isUnsigned: true, isBigEndian: true), + transaction.To.ToByteArray(isUnsigned: true, isBigEndian: true), + transaction.Value == 0 ? Array.Empty() : transaction.Value.ToByteArray(isUnsigned: true, isBigEndian: true), + transaction.Data ?? Array.Empty(), + signature.IsVSignedForYParity() ? new byte[] { 0x1b } : new byte[] { 0x1c }, + signature.R, + signature.S, + chainId.ToByteArray(isUnsigned: true, isBigEndian: true), + transaction.From.ToByteArray(isUnsigned: true, isBigEndian: true), + // Add meta + transaction.GasPerPubdataByteLimit.ToByteArray(isUnsigned: true, isBigEndian: true), + Array.Empty(), // TODO: FactoryDeps + signature.CreateStringSignature().HexToBytes(), + // add array of rlp encoded paymaster/paymasterinput + transaction.Paymaster != 0 + ? RLP.EncodeElement(transaction.Paymaster.ToByteArray(isUnsigned: true, isBigEndian: true)).Concat(RLP.EncodeElement(transaction.PaymasterInput)).ToArray() + : new byte[] { 0xc0 }, + }; + + return "0x71" + RLP.EncodeDataItemsAsElementOrListAndCombineAsList(fields.ToArray(), _indexOfListDataItems).BytesToHex(false); + } + + #endregion +} diff --git a/Thirdweb/Thirdweb.Utils/EIP712Encoder.cs b/Thirdweb/Thirdweb.Utils/EIP712Encoder.cs new file mode 100644 index 00000000..28027b21 --- /dev/null +++ b/Thirdweb/Thirdweb.Utils/EIP712Encoder.cs @@ -0,0 +1,278 @@ +using System.Collections; +using System.Numerics; +using System.Text; +using Nethereum.ABI; +using Nethereum.ABI.EIP712; +using Nethereum.ABI.FunctionEncoding; +using Nethereum.Util; + +namespace Thirdweb; + +public class EIP712Encoder +{ + public static EIP712Encoder Current { get; } = new EIP712Encoder(); + + private readonly ABIEncode _abiEncode = new(); + private readonly ParametersEncoder _parametersEncoder = new(); + + public byte[] EncodeTypedData(T message, TypedData typedData) + { + typedData.Message = MemberValueFactory.CreateFromMessage(message); + typedData.EnsureDomainRawValuesAreInitialised(); + return this.EncodeTypedDataRaw(typedData); + } + + public byte[] EncodeTypedData(T data, TDomain domain, string primaryTypeName) + { + var typedData = this.GenerateTypedData(data, domain, primaryTypeName); + + return this.EncodeTypedData(typedData); + } + + public byte[] EncodeTypedData(string json) + { + var typedDataRaw = TypedDataRawJsonConversion.DeserialiseJsonToRawTypedData(json); + return this.EncodeTypedDataRaw(typedDataRaw); + } + + public byte[] EncodeTypedData(string json, string messageKeySelector = "message") + { + var typedDataRaw = TypedDataRawJsonConversion.DeserialiseJsonToRawTypedData(json, messageKeySelector); + return this.EncodeTypedDataRaw(typedDataRaw); + } + + public byte[] EncodeAndHashTypedData(T message, TypedData typedData) + { + var encodedData = this.EncodeTypedData(message, typedData); + return Sha3Keccack.Current.CalculateHash(encodedData); + } + + public byte[] EncodeAndHashTypedData(TypedData typedData) + { + var encodedData = this.EncodeTypedData(typedData); + return Sha3Keccack.Current.CalculateHash(encodedData); + } + + public byte[] EncodeTypedData(TypedData typedData) + { + typedData.EnsureDomainRawValuesAreInitialised(); + return this.EncodeTypedDataRaw(typedData); + } + + public byte[] EncodeTypedDataRaw(TypedDataRaw typedData) + { + using var memoryStream = new MemoryStream(); + using var writer = new BinaryWriter(memoryStream); + writer.Write("1901".HexToBytes()); + writer.Write(this.HashStruct(typedData.Types, "EIP712Domain", typedData.DomainRawValues)); + writer.Write(this.HashStruct(typedData.Types, typedData.PrimaryType, typedData.Message)); + + writer.Flush(); + var result = memoryStream.ToArray(); + return result; + } + + public byte[] HashDomainSeparator(TypedData typedData) + { + typedData.EnsureDomainRawValuesAreInitialised(); + using var memoryStream = new MemoryStream(); + using var writer = new BinaryWriter(memoryStream); + writer.Write(this.HashStruct(typedData.Types, "EIP712Domain", typedData.DomainRawValues)); + writer.Flush(); + var result = memoryStream.ToArray(); + return result; + } + + public byte[] HashStruct(T message, string primaryType, params Type[] types) + { + var memberDescriptions = MemberDescriptionFactory.GetTypesMemberDescription(types); + var memberValue = MemberValueFactory.CreateFromMessage(message); + return this.HashStruct(memberDescriptions, primaryType, memberValue); + } + + public string GetEncodedType(string primaryType, params Type[] types) + { + var memberDescriptions = MemberDescriptionFactory.GetTypesMemberDescription(types); + return EncodeType(memberDescriptions, primaryType); + } + + public string GetEncodedTypeDomainSeparator(TypedData typedData) + { + typedData.EnsureDomainRawValuesAreInitialised(); + return EncodeType(typedData.Types, "EIP712Domain"); + } + + private byte[] HashStruct(IDictionary types, string primaryType, IEnumerable message) + { + using var memoryStream = new MemoryStream(); + using var writer = new BinaryWriter(memoryStream); + var encodedType = EncodeType(types, primaryType); + var typeHash = Sha3Keccack.Current.CalculateHash(Encoding.UTF8.GetBytes(encodedType)); + writer.Write(typeHash); + + this.EncodeData(writer, types, message); + + writer.Flush(); + return Sha3Keccack.Current.CalculateHash(memoryStream.ToArray()); + } + + private static string EncodeType(IDictionary types, string typeName) + { + var encodedTypes = EncodeTypes(types, typeName); + var encodedPrimaryType = encodedTypes.Single(x => x.Key == typeName); + var encodedReferenceTypes = encodedTypes.Where(x => x.Key != typeName).OrderBy(x => x.Key).Select(x => x.Value); + var fullyEncodedType = encodedPrimaryType.Value + string.Join(string.Empty, encodedReferenceTypes.ToArray()); + + return fullyEncodedType; + } + + private static List> EncodeTypes(IDictionary types, string currentTypeName, HashSet visited = null) + { + visited ??= new HashSet(); + + if (visited.Contains(currentTypeName)) + { + return new List>(); + } + + _ = visited.Add(currentTypeName); + + var currentTypeMembers = types[currentTypeName]; + var currentTypeMembersEncoded = currentTypeMembers.Select(x => x.Type + " " + x.Name); + var result = new List> { new(currentTypeName, currentTypeName + "(" + string.Join(",", currentTypeMembersEncoded.ToArray()) + ")") }; + + foreach (var member in currentTypeMembers) + { + var referencedType = ConvertToElementType(member.Type); + if (Utils.IsReferenceType(referencedType) && !visited.Contains(referencedType)) + { + result.AddRange(EncodeTypes(types, referencedType, visited)); + } + } + + return result; + } + + private static string ConvertToElementType(string type) + { + if (type.Contains('[')) + { + return type[..type.IndexOf('[')]; + } + return type; + } + + private void EncodeData(BinaryWriter writer, IDictionary types, IEnumerable memberValues) + { + foreach (var memberValue in memberValues) + { + switch (memberValue.TypeName) + { + case var refType when Utils.IsReferenceType(refType): + { + writer.Write(this.HashStruct(types, memberValue.TypeName, (IEnumerable)memberValue.Value)); + break; + } + case "string": + { + var value = Encoding.UTF8.GetBytes((string)memberValue.Value); + var abiValueEncoded = Sha3Keccack.Current.CalculateHash(value); + writer.Write(abiValueEncoded); + break; + } + case "bytes": + { + byte[] value; + if (memberValue.Value is string v) + { + value = v.HexToBytes(); + } + else + { + value = (byte[])memberValue.Value; + } + var abiValueEncoded = Sha3Keccack.Current.CalculateHash(value); + writer.Write(abiValueEncoded); + break; + } + default: + { + if (memberValue.TypeName.Contains('[')) + { + var items = (IList)memberValue.Value; + var itemsMemberValues = new List(); + foreach (var item in items) + { + itemsMemberValues.Add(new MemberValue() { TypeName = memberValue.TypeName[..memberValue.TypeName.LastIndexOf('[')], Value = item }); + } + using (var memoryStream = new MemoryStream()) + using (var writerItem = new BinaryWriter(memoryStream)) + { + this.EncodeData(writerItem, types, itemsMemberValues); + writerItem.Flush(); + writer.Write(Sha3Keccack.Current.CalculateHash(memoryStream.ToArray())); + } + } + else if (memberValue.TypeName.StartsWith("int") || memberValue.TypeName.StartsWith("uint")) + { + object value; + if (memberValue.Value is string) + { + BigInteger parsedOutput; + if (BigInteger.TryParse((string)memberValue.Value, out parsedOutput)) + { + value = parsedOutput; + } + else + { + value = memberValue.Value; + } + } + else + { + value = memberValue.Value; + } + var abiValue = new ABIValue(memberValue.TypeName, value); + var abiValueEncoded = this._abiEncode.GetABIEncoded(abiValue); + writer.Write(abiValueEncoded); + } + else + { + var abiValue = new ABIValue(memberValue.TypeName, memberValue.Value); + var abiValueEncoded = this._abiEncode.GetABIEncoded(abiValue); + writer.Write(abiValueEncoded); + } + break; + } + } + } + } + + public TypedData GenerateTypedData(T data, TDomain domain, string primaryTypeName) + { + var parameters = this._parametersEncoder.GetParameterAttributeValues(typeof(T), data).OrderBy(x => x.ParameterAttribute.Order); + + var typeMembers = new List(); + var typeValues = new List(); + foreach (var parameterAttributeValue in parameters) + { + typeMembers.Add(new MemberDescription { Type = parameterAttributeValue.ParameterAttribute.Type, Name = parameterAttributeValue.ParameterAttribute.Name }); + + typeValues.Add(new MemberValue { TypeName = parameterAttributeValue.ParameterAttribute.Type, Value = parameterAttributeValue.Value }); + } + + var result = new TypedData + { + PrimaryType = primaryTypeName, + Types = new Dictionary + { + [primaryTypeName] = typeMembers.ToArray(), + ["EIP712Domain"] = MemberDescriptionFactory.GetTypesMemberDescription(typeof(TDomain))["EIP712Domain"], + }, + Message = typeValues.ToArray(), + Domain = domain, + }; + + return result; + } +} diff --git a/Thirdweb/Thirdweb.Utils/RLP.cs b/Thirdweb/Thirdweb.Utils/RLP.cs new file mode 100644 index 00000000..bbe3ff75 --- /dev/null +++ b/Thirdweb/Thirdweb.Utils/RLP.cs @@ -0,0 +1,231 @@ +namespace Thirdweb; + +public class RLP +{ + /// + /// Reason for threshold according to Vitalik Buterin: + /// - 56 bytes maximizes the benefit of both options + /// - if we went with 60 then we would have only had 4 slots for long strings + /// so RLP would not have been able to store objects above 4gb + /// - if we went with 48 then RLP would be fine for 2^128 space, but that's way too much + /// - so 56 and 2^64 space seems like the right place to put the cutoff + /// - also, that's where Bitcoin's varint does the cutof + /// + private const int SIZE_THRESHOLD = 56; + + /* RLP encoding rules are defined as follows: + * For a single byte whose value is in the [0x00, 0x7f] range, that byte is + * its own RLP encoding. + */ + + /// + /// [0x80] + /// If a string is 0-55 bytes long, the RLP encoding consists of a single + /// byte with value 0x80 plus the length of the string followed by the + /// string. The range of the first byte is thus [0x80, 0xb7]. + /// + private const byte OFFSET_SHORT_ITEM = 0x80; + + /// + /// [0xb7] + /// If a string is more than 55 bytes long, the RLP encoding consists of a + /// single byte with value 0xb7 plus the length of the length of the string + /// in binary form, followed by the length of the string, followed by the + /// string. For example, a length-1024 string would be encoded as + /// \xb9\x04\x00 followed by the string. The range of the first byte is thus + /// [0xb8, 0xbf]. + /// + private const byte OFFSET_LONG_ITEM = 0xb7; + + /// + /// [0xc0] + /// If the total payload of a list (i.e. the combined length of all its + /// items) is 0-55 bytes long, the RLP encoding consists of a single byte + /// with value 0xc0 plus the length of the list followed by the concatenation + /// of the RLP encodings of the items. The range of the first byte is thus + /// [0xc0, 0xf7]. + /// + public const byte OFFSET_SHORT_LIST = 0xc0; + + /// + /// [0xf7] + /// If the total payload of a list is more than 55 bytes long, the RLP + /// encoding consists of a single byte with value 0xf7 plus the length of the + /// length of the list in binary form, followed by the length of the list, + /// followed by the concatenation of the RLP encodings of the items. The + /// range of the first byte is thus [0xf8, 0xff]. + /// + private const byte OFFSET_LONG_LIST = 0xf7; + + public static readonly byte[] EMPTY_BYTE_ARRAY = Array.Empty(); + public static readonly byte[] ZERO_BYTE_ARRAY = { 0 }; + + public static int ByteArrayToInt(byte[] bytes) + { + if (BitConverter.IsLittleEndian) + { + Array.Reverse(bytes); + } + + return BitConverter.ToInt32(bytes, 0); + } + + public static byte[] EncodeByte(byte singleByte) + { + if (singleByte == 0) + { + return new[] { OFFSET_SHORT_ITEM }; + } + + if (singleByte <= 0x7F) + { + return new[] { singleByte }; + } + + return new[] { (byte)(OFFSET_SHORT_ITEM + 1), singleByte }; + } + + public static byte[] EncodeElement(byte[] srcData) + { + // null or empty + if (srcData == null || srcData.Length == 0) + { + return new[] { OFFSET_SHORT_ITEM }; + } + + // single zero + if (srcData.Length == 1 && srcData[0] == 0) + { + return srcData; + } + + if (srcData.Length == 1 && srcData[0] < 0x80) + { + return srcData; + } + + if (srcData.Length < SIZE_THRESHOLD) + { + // length = 8X + var length = (byte)(OFFSET_SHORT_ITEM + srcData.Length); + var data = new byte[srcData.Length + 1]; + Array.Copy(srcData, 0, data, 1, srcData.Length); + data[0] = length; + + return data; + } + else + { + // length of length = BX + // prefix = [BX, [length]] + var tmpLength = srcData.Length; + byte byteNum = 0; + while (tmpLength != 0) + { + ++byteNum; + tmpLength >>= 8; + } + var lenBytes = new byte[byteNum]; + for (var i = 0; i < byteNum; ++i) + { + lenBytes[byteNum - 1 - i] = (byte)(srcData.Length >> (8 * i)); + } + // first byte = F7 + bytes.length + var data = new byte[srcData.Length + 1 + byteNum]; + Array.Copy(srcData, 0, data, 1 + byteNum, srcData.Length); + data[0] = (byte)(OFFSET_LONG_ITEM + byteNum); + Array.Copy(lenBytes, 0, data, 1, lenBytes.Length); + + return data; + } + } + + public static byte[] EncodeDataItemsAsElementOrListAndCombineAsList(byte[][] dataItems, int[] indexOfListDataItems = null) + { + if (indexOfListDataItems == null) + { + return EncodeList(dataItems.Select(EncodeElement).ToArray()); + } + + var encodedData = new List(); + + for (var i = 0; i < dataItems.Length; i++) + { + if (indexOfListDataItems.Contains(i)) + { + var item = dataItems[i]; + encodedData.Add(EncodeList(item)); + } + else + { + encodedData.Add(EncodeElement(dataItems[i])); + } + } + + return EncodeList(encodedData.ToArray()); + } + + public static byte[] EncodeList(params byte[][] items) + { + if (items == null || (items.Length == 1 && items[0] == null)) + { + return new[] { OFFSET_SHORT_LIST }; + } + + var totalLength = 0; + for (var i = 0; i < items.Length; i++) + { + totalLength += items[i].Length; + } + + byte[] data; + + int copyPos; + + if (totalLength < SIZE_THRESHOLD) + { + var dataLength = 1 + totalLength; + data = new byte[dataLength]; + + //single byte length + data[0] = (byte)(OFFSET_SHORT_LIST + totalLength); + copyPos = 1; + } + else + { + // length of length = BX + // prefix = [BX, [length]] + var tmpLength = totalLength; + byte byteNum = 0; + + while (tmpLength != 0) + { + ++byteNum; + tmpLength >>= 8; + } + + tmpLength = totalLength; + + var lenBytes = new byte[byteNum]; + for (var i = 0; i < byteNum; ++i) + { + lenBytes[byteNum - 1 - i] = (byte)(tmpLength >> (8 * i)); + } + // first byte = F7 + bytes.length + data = new byte[1 + lenBytes.Length + totalLength]; + + data[0] = (byte)(OFFSET_LONG_LIST + byteNum); + Array.Copy(lenBytes, 0, data, 1, lenBytes.Length); + + copyPos = lenBytes.Length + 1; + } + + //Combine all elements + foreach (var item in items) + { + Array.Copy(item, 0, data, copyPos, item.Length); + copyPos += item.Length; + } + return data; + } +} diff --git a/Thirdweb/Thirdweb.Utils/ThirdwebTask.cs b/Thirdweb/Thirdweb.Utils/ThirdwebTask.cs new file mode 100644 index 00000000..ca5357e3 --- /dev/null +++ b/Thirdweb/Thirdweb.Utils/ThirdwebTask.cs @@ -0,0 +1,47 @@ +using System.Diagnostics; + +namespace Thirdweb; + +public static class ThirdwebTask +{ + /// + /// Simulates a delay without using Task.Delay or System.Threading.Timer, specifically designed to avoid clashing with WebGL threading. + /// + /// The number of milliseconds to delay. + /// A cancellation token to cancel the delay. + /// A task that completes after the specified delay. + public static async Task Delay(int millisecondsDelay, CancellationToken cancellationToken = default) + { + var startTime = DateTime.UtcNow; + var endTime = startTime.AddMilliseconds(millisecondsDelay); + var currentDelay = 10; + + while (DateTime.UtcNow < endTime && !cancellationToken.IsCancellationRequested) + { + await MinimalDelay(currentDelay); + + if (DateTime.UtcNow.AddMilliseconds(currentDelay) < endTime) + { + currentDelay = Math.Min(currentDelay * 2, 100); + } + else + { + currentDelay = (int)(endTime - DateTime.UtcNow).TotalMilliseconds; + } + } + } + + /// + /// Provides a minimal delay using a manual loop with short sleeps to reduce CPU usage. + /// + /// The number of milliseconds to delay. + private static async Task MinimalDelay(int milliseconds) + { + var stopwatch = Stopwatch.StartNew(); + while (stopwatch.ElapsedMilliseconds < milliseconds) + { + Thread.Sleep(1); + await Task.Yield(); + } + } +} diff --git a/Thirdweb/Thirdweb.Utils/Utils.Types.cs b/Thirdweb/Thirdweb.Utils/Utils.Types.cs new file mode 100644 index 00000000..817dda06 --- /dev/null +++ b/Thirdweb/Thirdweb.Utils/Utils.Types.cs @@ -0,0 +1,275 @@ +using System.Numerics; +using Newtonsoft.Json; + +namespace Thirdweb; + +[JsonObject(ItemNullValueHandling = NullValueHandling.Ignore)] +public class ThirdwebChainDataResponse +{ + [JsonProperty("data")] + public ThirdwebChainData Data { get; set; } + + [JsonProperty("error")] + public object Error { get; set; } +} + +[JsonObject(ItemNullValueHandling = NullValueHandling.Ignore)] +public class ThirdwebChainData +{ + [JsonProperty("name")] + public string Name { get; set; } + + [JsonProperty("chain")] + public string Chain { get; set; } + + [JsonProperty("rpc")] + public List Rpc { get; set; } + + [JsonProperty("nativeCurrency")] + public ThirdwebChainNativeCurrency NativeCurrency { get; set; } + + [JsonProperty("shortName")] + public string ShortName { get; set; } + + [JsonProperty("chainId")] + public BigInteger ChainId { get; set; } + + [JsonProperty("networkId")] + public BigInteger NetworkId { get; set; } + + [JsonProperty("slug")] + public string Slug { get; set; } + + [JsonProperty("infoURL")] + public string InfoURL { get; set; } + + [JsonProperty("icon")] + public ThirdwebChainIcon Icon { get; set; } + + [JsonProperty("ens")] + public ThirdwebChainEns Ens { get; set; } + + [JsonProperty("explorers")] + public List Explorers { get; set; } + + [JsonProperty("testnet")] + public bool Testnet { get; set; } + + [JsonProperty("stackType")] + public string StackType { get; set; } +} + +[JsonObject(ItemNullValueHandling = NullValueHandling.Ignore)] +public class ThirdwebChainNativeCurrency +{ + [JsonProperty("name")] + public string Name { get; set; } + + [JsonProperty("symbol")] + public string Symbol { get; set; } + + [JsonProperty("decimals")] + public int Decimals { get; set; } +} + +[JsonObject(ItemNullValueHandling = NullValueHandling.Ignore)] +public class ThirdwebChainIcon +{ + [JsonProperty("url")] + public string Url { get; set; } + + [JsonProperty("width")] + public int Width { get; set; } + + [JsonProperty("height")] + public int Height { get; set; } + + [JsonProperty("format")] + public string Format { get; set; } +} + +public class ThirdwebChainEns +{ + [JsonProperty("registry")] + public string Registry { get; set; } +} + +public class ThirdwebChainExplorer +{ + [JsonProperty("name")] + public string Name { get; set; } + + [JsonProperty("url")] + public string Url { get; set; } + + [JsonProperty("standard")] + public string Standard { get; set; } + + [JsonProperty("icon")] + public ThirdwebChainIcon Icon { get; set; } +} + +[JsonObject(ItemNullValueHandling = NullValueHandling.Ignore)] +public class FarcasterProfile +{ + [JsonProperty("fid")] + public int? Fid { get; set; } + + [JsonProperty("bio")] + public string Bio { get; set; } + + [JsonProperty("pfp")] + public string Pfp { get; set; } + + [JsonProperty("display")] + public string Display { get; set; } + + [JsonProperty("username")] + public string Username { get; set; } + + [JsonProperty("custodyAddress")] + public string CustodyAddress { get; set; } + + [JsonProperty("addresses")] + public List Addresses { get; set; } +} + +[JsonObject(ItemNullValueHandling = NullValueHandling.Ignore)] +public class LensProfile +{ + [JsonProperty("name")] + public string Name { get; set; } + + [JsonProperty("bio")] + public string Bio { get; set; } + + [JsonProperty("picture")] + public string Picture { get; set; } + + [JsonProperty("coverPicture")] + public string CoverPicture { get; set; } +} + +[JsonObject(ItemNullValueHandling = NullValueHandling.Ignore)] +public class EnsProfile +{ + [JsonProperty("name")] + public string Name { get; set; } + + [JsonProperty("address")] + public string Address { get; set; } + + [JsonProperty("avatar")] + public string Avatar { get; set; } + + [JsonProperty("display")] + public string Display { get; set; } + + [JsonProperty("description")] + public string Description { get; set; } + + [JsonProperty("keywords")] + public List Keywords { get; set; } + + [JsonProperty("email")] + public string Email { get; set; } + + [JsonProperty("mail")] + public string Mail { get; set; } + + [JsonProperty("notice")] + public string Notice { get; set; } + + [JsonProperty("location")] + public string Location { get; set; } + + [JsonProperty("phone")] + public string Phone { get; set; } + + [JsonProperty("url")] + public string Url { get; set; } + + [JsonProperty("twitter")] + public string Twitter { get; set; } + + [JsonProperty("github")] + public string Github { get; set; } + + [JsonProperty("discord")] + public string Discord { get; set; } + + [JsonProperty("telegram")] + public string Telegram { get; set; } +} + +[JsonObject(ItemNullValueHandling = NullValueHandling.Ignore)] +public class SocialProfileGeneric +{ + [JsonProperty("type")] + public string Type { get; set; } + + [JsonProperty("name")] + public string Name { get; set; } + + [JsonProperty("avatar")] + public string Avatar { get; set; } + + [JsonProperty("bio")] + public string Bio { get; set; } + + [JsonProperty("metadata")] + public object Metadata { get; set; } +} + +[JsonObject(ItemNullValueHandling = NullValueHandling.Ignore)] +public class SocialProfileResponse +{ + [JsonProperty("data")] + public List Data { get; set; } + + [JsonProperty("error")] + public string Error { get; set; } +} + +/// +/// SocialProfiles object that contains all the different types of social profiles and their respective metadata. +/// +public class SocialProfiles +{ + public List EnsProfiles { get; set; } + public List FarcasterProfiles { get; set; } + public List LensProfiles { get; set; } + public List OtherProfiles { get; set; } + + public SocialProfiles(List profiles) + { + this.EnsProfiles = new List(); + this.FarcasterProfiles = new List(); + this.LensProfiles = new List(); + this.OtherProfiles = new List(); + + foreach (var profile in profiles) + { + switch (profile.Type) + { + case "ens": + this.EnsProfiles.Add(JsonConvert.DeserializeObject(JsonConvert.SerializeObject(profile.Metadata))); + break; + case "farcaster": + this.FarcasterProfiles.Add(JsonConvert.DeserializeObject(JsonConvert.SerializeObject(profile.Metadata))); + break; + case "lens": + this.LensProfiles.Add(JsonConvert.DeserializeObject(JsonConvert.SerializeObject(profile.Metadata))); + break; + default: + this.OtherProfiles.Add(profile); + break; + } + } + } + + public override string ToString() + { + return JsonConvert.SerializeObject(this, Formatting.Indented); + } +} diff --git a/Thirdweb/Thirdweb.Utils/Utils.cs b/Thirdweb/Thirdweb.Utils/Utils.cs index 8d3ceb95..d1d0651a 100644 --- a/Thirdweb/Thirdweb.Utils/Utils.cs +++ b/Thirdweb/Thirdweb.Utils/Utils.cs @@ -2,319 +2,1206 @@ using System.Numerics; using System.Security.Cryptography; using System.Text; -using Nethereum.Contracts; +using System.Text.RegularExpressions; +using ADRaffy.ENSNormalize; +using Nethereum.ABI; +using Nethereum.ABI.EIP712; +using Nethereum.ABI.FunctionEncoding; +using Nethereum.ABI.FunctionEncoding.Attributes; +using Nethereum.ABI.Model; using Nethereum.Hex.HexConvertors.Extensions; +using Nethereum.Hex.HexTypes; using Nethereum.Signer; using Nethereum.Util; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; -namespace Thirdweb +namespace Thirdweb; + +/// +/// Provides utility methods for various operations. +/// +public static partial class Utils { + private static readonly Dictionary _eip155EnforcedCache = new(); + private static readonly Dictionary _chainDataCache = new(); + private static readonly Dictionary _ensCache = new(); + private static readonly List _errorSubstringsComposite = new() { new string[] { "account", "not found!" }, new[] { "wrong", "chainid" } }; + + /// + /// Computes the client ID from the given secret key. + /// + /// The secret key. + /// The computed client ID. + public static string ComputeClientIdFromSecretKey(string secretKey) + { +#if NETSTANDARD + using var sha256 = SHA256.Create(); + var hash = sha256.ComputeHash(Encoding.UTF8.GetBytes(secretKey)); + return BitConverter.ToString(hash).Replace("-", "").ToLower()[..32]; +#else + var hash = SHA256.HashData(Encoding.UTF8.GetBytes(secretKey)); + return BitConverter.ToString(hash).Replace("-", "").ToLower()[..32]; +#endif + } + + // public static byte[] StringToSha256(string bytes) + // { + // #if NETSTANDARD + // using var sha256 = SHA256.Create(); + // return sha256.ComputeHash(bytes); + // } + /// - /// Provides utility methods for various operations. + /// Concatenates the given hex strings. /// - public static class Utils + /// The hex strings to concatenate. + /// The concatenated hex string. + public static string HexConcat(params string[] hexStrings) { - /// - /// Computes the client ID from the given secret key. - /// - /// The secret key. - /// The computed client ID. - public static string ComputeClientIdFromSecretKey(string secretKey) + var hex = new StringBuilder("0x"); + + foreach (var hexStr in hexStrings) { - using var sha256 = SHA256.Create(); - var hash = sha256.ComputeHash(Encoding.UTF8.GetBytes(secretKey)); - return BitConverter.ToString(hash).Replace("-", "").ToLower().Substring(0, 32); + _ = hex.Append(hexStr[2..]); } - /// - /// Concatenates the given hex strings. - /// - /// The hex strings to concatenate. - /// The concatenated hex string. - public static string HexConcat(params string[] hexStrings) + return hex.ToString(); + } + + /// + /// Hashes the given message bytes with a prefixed message. + /// + /// The message bytes to hash. + /// The hashed message bytes. + public static byte[] HashPrefixedMessage(this byte[] messageBytes) + { + var signer = new EthereumMessageSigner(); + return signer.HashPrefixedMessage(messageBytes); + } + + /// + /// Hashes the given message with a prefixed message. + /// + /// The message to hash. + /// The hashed message. + public static string HashPrefixedMessage(this string message) + { + return HashPrefixedMessage(Encoding.UTF8.GetBytes(message)).BytesToHex(); + } + + /// + /// Hashes the given message bytes. + /// + /// The message bytes to hash. + /// The hashed message bytes. + public static byte[] HashMessage(this byte[] messageBytes) + { + return Sha3Keccack.Current.CalculateHash(messageBytes); + } + + /// + /// Hashes the given message. + /// + /// The message to hash. + /// The hashed message. + public static string HashMessage(this string message) + { + return Sha3Keccack.Current.CalculateHash(message); + } + + /// + /// Converts the given bytes to a hex string. + /// + /// The bytes to convert. + /// Whether to add the "0x" prefix. + /// The hex string. + public static string BytesToHex(this byte[] bytes, bool addPrefix = true) + { + return bytes.ToHex(addPrefix); + } + + /// + /// Converts the given hex string to bytes. + /// + /// The hex string to convert. + /// The bytes. + public static byte[] HexToBytes(this string hex) + { + return hex.HexToByteArray(); + } + + /// + /// Converts the given hex string to a big integer. + /// + /// The hex string to convert. + /// The big integer. + [Obsolete("Use HexToNumber instead.")] + public static BigInteger HexToBigInt(this string hex) + { + return new HexBigInteger(hex).Value; + } + + /// + /// Converts the given hex string to a big integer. + /// + /// The hex string to convert. + /// The big integer. + public static BigInteger HexToNumber(this string hex) + { + return new HexBigInteger(hex).Value; + } + + /// + /// Converts the given big integer to a hex string. + /// + public static string NumberToHex(this BigInteger number) + { + return new HexBigInteger(number).HexValue; + } + + /// + /// Converts the given integer to a hex string. + /// + public static string NumberToHex(this int number) + { + return NumberToHex(new BigInteger(number)); + } + + /// + /// Converts the given long to a hex string. + /// + public static string NumberToHex(this long number) + { + return NumberToHex(new BigInteger(number)); + } + + /// + /// Converts the given string to a hex string. + /// + /// The string to convert. + /// The hex string. + public static string StringToHex(this string str) + { + return "0x" + Encoding.UTF8.GetBytes(str).ToHex(); + } + + /// + /// Converts the given hex string to a regular string. + /// + /// The hex string to convert. + /// The regular string. + public static string HexToString(this string hex) + { + var array = HexToBytes(hex); + return Encoding.UTF8.GetString(array, 0, array.Length); + } + + /// + /// Gets the current Unix timestamp. + /// + /// The current Unix timestamp. + public static long GetUnixTimeStampNow() + { + return DateTimeOffset.UtcNow.ToUnixTimeSeconds(); + } + + /// + /// Gets the Unix timestamp for 10 years from now. + /// + /// The Unix timestamp for 10 years from now. + public static long GetUnixTimeStampIn10Years() + { + return DateTimeOffset.UtcNow.ToUnixTimeSeconds() + (60 * 60 * 24 * 365 * 10); + } + + /// + /// Replaces the IPFS URI with a specified gateway. + /// + /// The URI to replace. + /// The gateway to use. + /// The replaced URI. + public static string ReplaceIPFS(this string uri, string gateway = null) + { + gateway ??= Constants.FALLBACK_IPFS_GATEWAY; + return !string.IsNullOrEmpty(uri) && uri.StartsWith("ipfs://") ? uri.Replace("ipfs://", gateway) : uri; + } + + /// + /// Converts the given ether value to wei. + /// + /// The ether value to convert. + /// The wei value. + public static string ToWei(this string eth) + { + if (!double.TryParse(eth, NumberStyles.Number, CultureInfo.InvariantCulture, out var ethDouble)) { - var hex = new StringBuilder("0x"); + throw new ArgumentException("Invalid eth value."); + } - foreach (var hexStr in hexStrings) + var wei = (BigInteger)(ethDouble * Constants.DECIMALS_18); + return wei.ToString(); + } + + /// + /// Converts the given wei value to ether. + /// + /// The wei value to convert. + /// The number of decimals to display. + /// Whether to add commas to the output. + /// The ether value. + public static string ToEth(this string wei, int decimalsToDisplay = 4, bool addCommas = false) + { + return FormatERC20(wei, decimalsToDisplay, 18, addCommas); + } + + /// + /// Formats the given ERC20 token value. + /// + /// The wei value to format. + /// The number of decimals to display. + /// The number of decimals of the token. + /// Whether to add commas to the output. + /// The formatted token value. + public static string FormatERC20(this string wei, int decimalsToDisplay = 4, int decimals = 18, bool addCommas = false) + { + if (!BigInteger.TryParse(wei, out var weiBigInt)) + { + throw new ArgumentException("Invalid wei value."); + } + + var eth = (double)weiBigInt / Math.Pow(10.0, decimals); + var format = addCommas ? "#,0" : "#0"; + if (decimalsToDisplay > 0) + { + format += "."; + format += new string('0', decimalsToDisplay); + } + + return eth.ToString(format); + } + + /// + /// Generates a Sign-In With Ethereum (SIWE) message. + /// + /// The login payload data. + /// The generated SIWE message. + public static string GenerateSIWE(LoginPayloadData loginPayloadData) + { + if (loginPayloadData == null) + { + throw new ArgumentNullException(nameof(loginPayloadData)); + } + else if (string.IsNullOrEmpty(loginPayloadData.Domain)) + { + throw new ArgumentNullException(nameof(loginPayloadData.Domain)); + } + else if (string.IsNullOrEmpty(loginPayloadData.Address)) + { + throw new ArgumentNullException(nameof(loginPayloadData.Address)); + } + else if (string.IsNullOrEmpty(loginPayloadData.Version)) + { + throw new ArgumentNullException(nameof(loginPayloadData.Version)); + } + else if (string.IsNullOrEmpty(loginPayloadData.ChainId)) + { + throw new ArgumentNullException(nameof(loginPayloadData.ChainId)); + } + else if (string.IsNullOrEmpty(loginPayloadData.Nonce)) + { + throw new ArgumentNullException(nameof(loginPayloadData.Nonce)); + } + else if (string.IsNullOrEmpty(loginPayloadData.IssuedAt)) + { + throw new ArgumentNullException(nameof(loginPayloadData.IssuedAt)); + } + + var resourcesString = loginPayloadData.Resources != null ? "\nResources:" + string.Join("", loginPayloadData.Resources.Select(r => $"\n- {r}")) : string.Empty; + var payloadToSign = + $"{loginPayloadData.Domain} wants you to sign in with your Ethereum account:" + + $"\n{loginPayloadData.Address}\n\n" + + $"{(string.IsNullOrEmpty(loginPayloadData.Statement) ? "" : $"{loginPayloadData.Statement}\n")}" + + $"{(string.IsNullOrEmpty(loginPayloadData.Uri) ? "" : $"\nURI: {loginPayloadData.Uri}")}" + + $"\nVersion: {loginPayloadData.Version}" + + $"\nChain ID: {loginPayloadData.ChainId}" + + $"\nNonce: {loginPayloadData.Nonce}" + + $"\nIssued At: {loginPayloadData.IssuedAt}" + + $"{(string.IsNullOrEmpty(loginPayloadData.ExpirationTime) ? "" : $"\nExpiration Time: {loginPayloadData.ExpirationTime}")}" + + $"{(string.IsNullOrEmpty(loginPayloadData.InvalidBefore) ? "" : $"\nNot Before: {loginPayloadData.InvalidBefore}")}" + + resourcesString; + return payloadToSign; + } + + /// + /// Checks if the chain ID corresponds to zkSync. + /// + /// The Thirdweb client. + /// The chain ID. + /// True if it is a zkSync chain ID, otherwise false. + public static async Task IsZkSync(ThirdwebClient client, BigInteger chainId) + { + if ( + chainId.Equals(324) + || chainId.Equals(300) + || chainId.Equals(302) + || chainId.Equals(11124) + || chainId.Equals(282) + || chainId.Equals(388) + || chainId.Equals(4654) + || chainId.Equals(333271) + || chainId.Equals(37111) + || chainId.Equals(978658) + || chainId.Equals(531050104) + || chainId.Equals(4457845) + || chainId.Equals(2741) + || chainId.Equals(240) + || chainId.Equals(61166) + || chainId.Equals(555271) + ) + { + return true; + } + else + { + try { - _ = hex.Append(hexStr[2..]); + var chainData = await GetChainMetadata(client, chainId).ConfigureAwait(false); + return !string.IsNullOrEmpty(chainData.StackType) && chainData.StackType.Contains("zksync", StringComparison.OrdinalIgnoreCase); } + catch + { + // Assume it is not zkSync if the chain data could not be fetched + return false; + } + } + } + + /// + /// Converts an Ethereum address to its checksum format. + /// + /// The Ethereum address. + /// The checksummed Ethereum address. + public static string ToChecksumAddress(this string address) + { + return new AddressUtil().ConvertToChecksumAddress(address); + } - return hex.ToString(); + /// + /// Adjusts the value's decimals. + /// + /// The value. + /// The original number of decimals. + /// The target number of decimals. + /// The value adjusted to the new decimals. + public static BigInteger AdjustDecimals(this BigInteger value, int fromDecimals, int toDecimals) + { + var differenceInDecimals = fromDecimals - toDecimals; + + if (differenceInDecimals > 0) + { + return value / BigInteger.Pow(10, differenceInDecimals); + } + else if (differenceInDecimals < 0) + { + return value * BigInteger.Pow(10, -differenceInDecimals); } - /// - /// Hashes the given message bytes with a prefixed message. - /// - /// The message bytes to hash. - /// The hashed message bytes. - public static byte[] HashPrefixedMessage(this byte[] messageBytes) + return value; + } + + public static async Task GetChainMetadata(ThirdwebClient client, BigInteger chainId) + { + if (_chainDataCache.TryGetValue(chainId, out var value)) { - var signer = new EthereumMessageSigner(); - return signer.HashPrefixedMessage(messageBytes); + return value; } - /// - /// Hashes the given message with a prefixed message. - /// - /// The message to hash. - /// The hashed message. - public static string HashPrefixedMessage(this string message) + if (client == null) { - var signer = new EthereumMessageSigner(); - return signer.HashPrefixedMessage(Encoding.UTF8.GetBytes(message)).ToHex(true); + throw new ArgumentNullException(nameof(client)); } - /// - /// Hashes the given message bytes. - /// - /// The message bytes to hash. - /// The hashed message bytes. - public static byte[] HashMessage(this byte[] messageBytes) + if (chainId <= 0) { - return Sha3Keccack.Current.CalculateHash(messageBytes); + throw new ArgumentException("Invalid chain ID."); } - /// - /// Hashes the given message. - /// - /// The message to hash. - /// The hashed message. - public static string HashMessage(this string message) + var url = $"https://api.thirdweb.com/v1/chains/{chainId}"; + try + { + var response = await client.HttpClient.GetAsync(url).ConfigureAwait(false); + var json = await response.Content.ReadAsStringAsync().ConfigureAwait(false); + var deserializedResponse = JsonConvert.DeserializeObject(json); + + if (deserializedResponse == null || deserializedResponse.Error != null) + { + throw new Exception($"Failed to fetch chain data for chain ID {chainId}. Error: {JsonConvert.SerializeObject(deserializedResponse?.Error)}"); + } + else + { + deserializedResponse.Data.Explorers = deserializedResponse.Data.Explorers == null || deserializedResponse.Data.Explorers.Count == 0 ? null : deserializedResponse.Data.Explorers; + _chainDataCache[chainId] = deserializedResponse.Data; + return deserializedResponse.Data; + } + } + catch (HttpRequestException httpEx) { - return Sha3Keccack.Current.CalculateHash(Encoding.UTF8.GetBytes(message)).ToHex(true); + throw new Exception($"HTTP request error while fetching chain data for chain ID {chainId}: {httpEx.Message}", httpEx); } + catch (JsonException jsonEx) + { + throw new Exception($"JSON deserialization error while fetching chain data for chain ID {chainId}: {jsonEx.Message}", jsonEx); + } + catch (Exception ex) + { + throw new Exception($"Unexpected error while fetching chain data for chain ID {chainId}: {ex.Message}", ex); + } + } - /// - /// Converts the given bytes to a hex string. - /// - /// The bytes to convert. - /// The hex string. - public static string BytesToHex(this byte[] bytes) + public static int GetEntryPointVersion(string address) + { + if (address == null) { - return bytes.ToHex(true); + return 6; // non-4337 } - /// - /// Converts the given hex string to bytes. - /// - /// The hex string to convert. - /// The bytes. - public static byte[] HexToBytes(this string hex) + address = address.ToChecksumAddress(); + return address switch { - return hex.HexToByteArray(); + Constants.ENTRYPOINT_ADDRESS_V06 => 6, + Constants.ENTRYPOINT_ADDRESS_V07 => 7, + _ => 6, + }; + } + + public static byte[] HexToBytes32(this string hex) + { + if (hex.StartsWith("0x")) + { + hex = hex[2..]; } - /// - /// Converts the given string to a hex string. - /// - /// The string to convert. - /// The hex string. - public static string StringToHex(this string str) + if (hex.Length > 64) { - return "0x" + Encoding.UTF8.GetBytes(str).ToHex(); + throw new ArgumentException("Hex string is too long to fit into 32 bytes."); } - /// - /// Converts the given hex string to a regular string. - /// - /// The hex string to convert. - /// The regular string. - public static string HexToString(this string hex) + hex = hex.PadLeft(64, '0'); + + var bytes = new byte[32]; + for (var i = 0; i < hex.Length; i += 2) { - var array = HexToBytes(hex); - return Encoding.UTF8.GetString(array, 0, array.Length); + bytes[i / 2] = byte.Parse(hex.AsSpan(i, 2), NumberStyles.HexNumber, CultureInfo.InvariantCulture); } - /// - /// Gets the current Unix timestamp. - /// - /// The current Unix timestamp. - public static long GetUnixTimeStampNow() + return bytes; + } + + public static string ToJsonExternalWalletFriendly(TypedData typedData, TMessage message) + { + typedData.EnsureDomainRawValuesAreInitialised(); + typedData.Message = MemberValueFactory.CreateFromMessage(message); + var obj = (JObject)JToken.FromObject(typedData); + var jProperty = new JProperty("domain"); + var jProperties = GetJProperties("EIP712Domain", typedData.DomainRawValues, typedData); + object[] content = jProperties.ToArray(); + jProperty.Value = new JObject(content); + obj.Add(jProperty); + var jProperty2 = new JProperty("message"); + var jProperties2 = GetJProperties(typedData.PrimaryType, typedData.Message, typedData); + content = jProperties2.ToArray(); + jProperty2.Value = new JObject(content); + obj.Add(jProperty2); + return obj.ToString(); + } + +#if NET8_0_OR_GREATER + [GeneratedRegex("bytes\\d+")] + private static partial Regex BytesRegex(); + + [GeneratedRegex("uint\\d+")] + private static partial Regex UintRegex(); + + [GeneratedRegex("int\\d+")] + private static partial Regex IntRegex(); + + internal static bool IsReferenceType(string typeName) + { + if (!BytesRegex().IsMatch(typeName)) + { + if (!UintRegex().IsMatch(typeName)) + { + if (!IntRegex().IsMatch(typeName)) + { + switch (typeName) + { + case "bytes": + case "string": + case "bool": + case "address": + break; + default: + if (typeName.Contains('[')) + { + return false; + } + return true; + } + } + } + } + return false; + } +#else + internal static bool IsReferenceType(string typeName) + { + if (!new Regex("bytes\\d+").IsMatch(typeName)) { - return DateTimeOffset.UtcNow.ToUnixTimeSeconds(); + if (!new Regex("uint\\d+").IsMatch(typeName)) + { + if (!new Regex("int\\d+").IsMatch(typeName)) + { + switch (typeName) + { + case "bytes": + case "string": + case "bool": + case "address": + break; + default: + if (typeName.Contains('[')) + { + return false; + } + return true; + } + } + } } + return false; + } +#endif - /// - /// Gets the Unix timestamp for 10 years from now. - /// - /// The Unix timestamp for 10 years from now. - public static long GetUnixTimeStampIn10Years() + private static List GetJProperties(string mainTypeName, MemberValue[] values, TypedDataRaw typedDataRaw) + { + var list = new List(); + var array = typedDataRaw.Types[mainTypeName]; + for (var i = 0; i < array.Length; i++) { - return DateTimeOffset.UtcNow.ToUnixTimeSeconds() + 60 * 60 * 24 * 365 * 10; + var type = array[i].Type; + var name = array[i].Name; + if (IsReferenceType(type)) + { + var jProperty = new JProperty(name); + if (values[i].Value != null) + { + object[] content = GetJProperties(type, (MemberValue[])values[i].Value, typedDataRaw).ToArray(); + jProperty.Value = new JObject(content); + } + else + { + jProperty.Value = null; + } + + list.Add(jProperty); + } + else if (type.StartsWith("bytes")) + { + var name2 = name; + if (values[i].Value is byte[] v) + { + var content2 = v.BytesToHex(); + list.Add(new JProperty(name2, content2)); + } + else + { + var value = values[i].Value; + list.Add(new JProperty(name2, value)); + } + } + else if (type.Contains('[')) + { + var jProperty2 = new JProperty(name); + var jArray = new JArray(); + var text = type[..type.LastIndexOf('[')]; + if (values[i].Value == null) + { + jProperty2.Value = null; + list.Add(jProperty2); + continue; + } + + if (IsReferenceType(text)) + { + foreach (var item in (List)values[i].Value) + { + object[] content = GetJProperties(text, item, typedDataRaw).ToArray(); + jArray.Add(new JObject(content)); + } + + jProperty2.Value = jArray; + list.Add(jProperty2); + continue; + } + + foreach (var item2 in (System.Collections.IList)values[i].Value) + { + jArray.Add(item2); + } + + jProperty2.Value = jArray; + list.Add(jProperty2); + } + else + { + var name3 = name; + var value2 = values[i].Value; + list.Add(new JProperty(name3, value2)); + } } - /// - /// Replaces the IPFS URI with a specified gateway. - /// - /// The URI to replace. - /// The gateway to use. - /// The replaced URI. - public static string ReplaceIPFS(this string uri, string gateway = null) + return list; + } + + public static async Task IsEip155Enforced(ThirdwebClient client, BigInteger chainId) + { + if (_eip155EnforcedCache.TryGetValue(chainId, out var value)) { - gateway ??= Constants.FALLBACK_IPFS_GATEWAY; - return !string.IsNullOrEmpty(uri) && uri.StartsWith("ipfs://") ? uri.Replace("ipfs://", gateway) : uri; + return value; } - /// - /// Converts the given ether value to wei. - /// - /// The ether value to convert. - /// The wei value. - public static string ToWei(this string eth) + var result = false; + + var isArachnidDeployed = await IsDeployed(client, chainId, "0x4e59b44847b379578588920ca78fbf26c0b4956c").ConfigureAwait(false); + if (!isArachnidDeployed) { - if (!double.TryParse(eth, NumberStyles.Number, CultureInfo.InvariantCulture, out var ethDouble)) + try + { + // Pre-155 tx that will fail + var rpc = ThirdwebRPC.GetRpcInstance(client, chainId); + var rawTransaction = + "0xf8a58085174876e800830186a08080b853604580600e600039806000f350fe7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe03601600081602082378035828234f58015156039578182fd5b8082525050506014600cf31ba02222222222222222222222222222222222222222222222222222222222222222a02222222222222222222222222222222222222222222222222222222222222222"; + _ = await rpc.SendRequestAsync("eth_sendRawTransaction", rawTransaction).ConfigureAwait(false); + } + catch (Exception e) { - throw new ArgumentException("Invalid eth value."); + var errorMsg = e.Message.ToLower(); + + var errorSubstrings = new List + { + "eip-155", + "eip155", + "protected", + "invalid chain id for signer", + "chain id none", + "chain_id mismatch", + "recovered sender mismatch", + "transaction hash mismatch", + "chainid no support", + "chainid (0)", + "chainid(0)", + "invalid sender", + }; + + if (errorSubstrings.Any(errorMsg.Contains)) + { + result = true; + } + else + { + // Check if all substrings in any of the composite substrings are present + result = _errorSubstringsComposite.Any(arr => arr.All(substring => errorMsg.Contains(substring))); + } } + } - var wei = (BigInteger)(ethDouble * Constants.DECIMALS_18); - return wei.ToString(); + _eip155EnforcedCache[chainId] = result; + + return result; + } + + public static bool IsEip1559Supported(string chainId) + { + switch (chainId) + { + // BNB Mainnet + case "56": + // BNB Testnet + case "97": + // opBNB Mainnet + case "204": + // opBNB Testnet + case "5611": + // Oasys Mainnet + case "248": + // Oasys Testnet + case "9372": + // Vanar Mainnet + case "2040": + // Vanar Testnet (Vanguard) + case "78600": + // Taraxa Mainnet + case "841": + // Taraxa Testnet + case "842": + // Odyssey Testnet + case "911867": + // Ronin Mainnet + case "2020": + // Ronin Testnet + case "2021": + return false; + default: + return true; } + } - /// - /// Converts the given wei value to ether. - /// - /// The wei value to convert. - /// The number of decimals to display. - /// Whether to add commas to the output. - /// The ether value. - public static string ToEth(this string wei, int decimalsToDisplay = 4, bool addCommas = false) +#if NET8_0_OR_GREATER + [GeneratedRegex("^\\.|\\.$")] + private static partial Regex PacketRegex(); +#endif + + public static byte[] PacketToBytes(string packet) + { +#if !NET8_0_OR_GREATER + var value = new Regex("^\\.|\\.$").Replace(packet, ""); +#else + var value = PacketRegex().Replace(packet, ""); +#endif + if (string.IsNullOrEmpty(value)) { - return FormatERC20(wei, decimalsToDisplay, 18, addCommas); + return new byte[] { 0 }; } - /// - /// Formats the given ERC20 token value. - /// - /// The wei value to format. - /// The number of decimals to display. - /// The number of decimals of the token. - /// Whether to add commas to the output. - /// The formatted token value. - public static string FormatERC20(this string wei, int decimalsToDisplay = 4, int decimals = 18, bool addCommas = false) + var labels = value.Split("."); + using var memoryStream = new MemoryStream(); + foreach (var label in labels) { - if (!BigInteger.TryParse(wei, out var weiBigInt)) + byte[] labelBytes; + + if (label.Length > 63) { - throw new ArgumentException("Invalid wei value."); + labelBytes = label.HashMessage().HexToBytes(); + } + else + { + labelBytes = Encoding.UTF8.GetBytes(label); } - var eth = (double)weiBigInt / Math.Pow(10.0, decimals); - var format = addCommas ? "#,0" : "#0"; - if (decimalsToDisplay > 0) + if (labelBytes.Length > 255) { - format += "."; - format += new string('0', decimalsToDisplay); + throw new ArgumentException("Label is too long after encoding."); } - return eth.ToString(format); + memoryStream.WriteByte((byte)labelBytes.Length); + memoryStream.Write(labelBytes, 0, labelBytes.Length); + } + + memoryStream.WriteByte(0); + return memoryStream.ToArray(); + } + + public static async Task GetENSFromAddress(ThirdwebClient client, string address) + { + if (string.IsNullOrEmpty(address)) + { + throw new ArgumentNullException(nameof(address)); } - /// - /// Generates a Sign-In With Ethereum (SIWE) message. - /// - /// The login payload data. - /// The generated SIWE message. - public static string GenerateSIWE(LoginPayloadData loginPayloadData) + if (!address.IsValidAddress()) { - if (loginPayloadData == null) + throw new ArgumentException("Invalid address."); + } + + if (_ensCache.TryGetValue(address, out var value)) + { + return value; + } + + var contract = await ThirdwebContract.Create(client: client, address: Constants.ENS_REGISTRY_ADDRESS, chain: 1).ConfigureAwait(false); + var reverseName = address.ToLower()[2..] + ".addr.reverse"; + var reverseNameBytes = PacketToBytes(reverseName); + var ensName = await contract.Read("reverse", reverseNameBytes).ConfigureAwait(false); + _ensCache[address] = ensName; + return ensName; + } + + public static async Task GetAddressFromENS(ThirdwebClient client, string ensName) + { + if (string.IsNullOrEmpty(ensName)) + { + throw new ArgumentNullException(nameof(ensName)); + } + + if (ensName.IsValidAddress()) + { + return ensName.ToChecksumAddress(); + } + + if (!ensName.Contains('.')) + { + throw new ArgumentException("Invalid ENS name."); + } + + if (_ensCache.TryGetValue(ensName, out var value)) + { + return value; + } + + var registry = await ThirdwebContract.Create(client: client, address: Constants.ENS_REGISTRY_ADDRESS, chain: 1).ConfigureAwait(false); + var functionCallEncoder = new FunctionCallEncoder(); + var encodedAddr = "addr(bytes32)" + .HashMessage() + .HexToBytes() + .Take(4) + .ToArray() + .Concat(functionCallEncoder.EncodeParameters(new Parameter[] { new("bytes32", "name") }, new object[] { NameHash(ensName).HexToBytes() })) + .ToArray(); + var result = await registry.Read("resolve(bytes name, bytes data)", PacketToBytes(ensName), encodedAddr).ConfigureAwait(false); + var address = ("0x" + result.Bytes.BytesToHex()[26..]).ToChecksumAddress(); + _ensCache[ensName] = address; + return address; + } + + public static bool IsValidAddress(this string address) + { + if (string.IsNullOrEmpty(address)) + { + return false; + } + + if (address.StartsWith("0x") && address.Length == 42 && !address.Contains('.')) + { + return true; + } + + return false; + } + + [FunctionOutput] + private class ResolveReturnType + { + [Parameter("bytes", "", 1)] + public byte[] Bytes { get; set; } + + [Parameter("address", "", 2)] + public string Address { get; set; } + } + + private static string NameHash(string name) + { + var node = "0x0000000000000000000000000000000000000000000000000000000000000000"; + if (!string.IsNullOrEmpty(name)) + { + name = ENSNormalize.ENSIP15.Normalize(name); + var labels = name.Split('.'); + for (var i = labels.Length - 1; i >= 0; i--) { - throw new ArgumentNullException(nameof(loginPayloadData)); + var byteInput = (node + labels[i].HashMessage()).HexToByteArray(); + node = byteInput.HashMessage().BytesToHex(); } - else if (string.IsNullOrEmpty(loginPayloadData.Domain)) + } + return node.EnsureHexPrefix(); + } + + public static async Task IsDeployed(ThirdwebClient client, BigInteger chainId, string address) + { + var rpc = ThirdwebRPC.GetRpcInstance(client, chainId); + var code = await rpc.SendRequestAsync("eth_getCode", address, "latest"); + return code != "0x"; + } + + public static async Task FetchGasPrice(ThirdwebClient client, BigInteger chainId, bool withBump = true) + { + var rpc = ThirdwebRPC.GetRpcInstance(client, chainId); + var hex = await rpc.SendRequestAsync("eth_gasPrice").ConfigureAwait(false); + var gasPrice = hex.HexToNumber(); + return withBump ? gasPrice * 10 / 9 : gasPrice; + } + + public static async Task<(BigInteger maxFeePerGas, BigInteger maxPriorityFeePerGas)> FetchGasFees(ThirdwebClient client, BigInteger chainId, bool withBump = true) + { + var rpc = ThirdwebRPC.GetRpcInstance(client, chainId); + + // Polygon Mainnet & Amoy + if (chainId == (BigInteger)137 || chainId == (BigInteger)80002) + { + var gasPrice = await FetchGasPrice(client, chainId, withBump).ConfigureAwait(false); + return (gasPrice * 3 / 2, gasPrice * 4 / 3); + } + + // Celo Mainnet, Alfajores & Baklava + if (chainId == (BigInteger)42220 || chainId == (BigInteger)44787 || chainId == (BigInteger)62320) + { + var gasPrice = await FetchGasPrice(client, chainId, withBump).ConfigureAwait(false); + return (gasPrice, gasPrice); + } + + // Arbitrum, Arbitrum Nova & Arbitrum Sepolia + if (chainId == (BigInteger)42161 || chainId == (BigInteger)42170 || chainId == (BigInteger)421614) + { + var gasPrice = await FetchGasPrice(client, chainId, withBump).ConfigureAwait(false); + return (gasPrice, gasPrice); + } + + try + { + var block = await rpc.SendRequestAsync("eth_getBlockByNumber", "latest", true).ConfigureAwait(false); + var baseBlockFee = block["baseFeePerGas"]?.ToObject(); + var maxFeePerGas = baseBlockFee.Value * 2; + var maxPriorityFeePerGas = ((await rpc.SendRequestAsync("eth_maxPriorityFeePerGas").ConfigureAwait(false))?.Value) ?? (maxFeePerGas / 2); + + if (maxPriorityFeePerGas > maxFeePerGas) { - throw new ArgumentNullException(nameof(loginPayloadData.Domain)); + maxPriorityFeePerGas = maxFeePerGas / 2; } - else if (string.IsNullOrEmpty(loginPayloadData.Address)) + + return (maxFeePerGas + (maxPriorityFeePerGas * 10 / 9), maxPriorityFeePerGas * 10 / 9); + } + catch + { + var gasPrice = await FetchGasPrice(client, chainId, withBump).ConfigureAwait(false); + return (gasPrice, gasPrice); + } + } + + public static IThirdwebHttpClient ReconstructHttpClient(IThirdwebHttpClient httpClient, Dictionary defaultHeaders = null) + { + var reconstructedHttpClient = httpClient.GetType().GetConstructor(Type.EmptyTypes).Invoke(null) as IThirdwebHttpClient; + if (defaultHeaders != null) + { + reconstructedHttpClient.SetHeaders(defaultHeaders ?? httpClient.Headers); + } + return reconstructedHttpClient; + } + + /// + /// Gets the social profiles for the given address or ENS. + /// + /// The Thirdweb client. + /// The wallet address or ENS. + /// A object containing the social profiles. + /// Thrown when the address or ENS is null or empty. + /// Thrown when the address or ENS is invalid. + /// Thrown when the social profiles could not be fetched. + public static async Task GetSocialProfiles(ThirdwebClient client, string addressOrEns) + { + if (string.IsNullOrEmpty(addressOrEns)) + { + throw new ArgumentNullException(nameof(addressOrEns)); + } + + if (!addressOrEns.IsValidAddress() && !addressOrEns.Contains('.')) + { + throw new ArgumentException("Invalid address or ENS."); + } + + addressOrEns = await GetAddressFromENS(client, addressOrEns).ConfigureAwait(false) ?? addressOrEns; + + var url = $"{Constants.SOCIAL_API_URL}/v1/profiles/{addressOrEns}"; + var response = await client.HttpClient.GetAsync(url).ConfigureAwait(false); + var json = await response.Content.ReadAsStringAsync().ConfigureAwait(false); + var deserializedResponse = JsonConvert.DeserializeObject(json); + if (deserializedResponse == null || deserializedResponse.Error != null) + { + throw new Exception($"Failed to fetch social profiles for address {addressOrEns}. Error: {deserializedResponse?.Error}"); + } + + return new SocialProfiles(deserializedResponse.Data); + } + + /// + /// Preprocesses the typed data JSON to stringify large numbers. + /// + /// The typed data JSON. + /// The preprocessed typed data JSON. + public static string PreprocessTypedDataJson(string json) + { + var jObject = JObject.Parse(json); + + static void StringifyLargeNumbers(JToken token) + { + if (token is JObject obj) { - throw new ArgumentNullException(nameof(loginPayloadData.Address)); + foreach (var property in obj.Properties().ToList()) + { + StringifyLargeNumbers(property.Value); + } } - else if (string.IsNullOrEmpty(loginPayloadData.Version)) + else if (token is JArray array) { - throw new ArgumentNullException(nameof(loginPayloadData.Version)); + foreach (var item in array.ToList()) + { + StringifyLargeNumbers(item); + } } - else if (string.IsNullOrEmpty(loginPayloadData.ChainId)) + else if (token is JValue value) { - throw new ArgumentNullException(nameof(loginPayloadData.ChainId)); + if (value.Type == JTokenType.Integer) + { + try + { + var bigInt = BigInteger.Parse(value.ToString()); + if (bigInt > new BigInteger(uint.MaxValue) || bigInt < BigInteger.Zero) + { + value.Replace(bigInt.ToString()); + } + } + catch (FormatException) + { + // Skip if the value isn't properly formatted as an integer + } + } } - else if (string.IsNullOrEmpty(loginPayloadData.Nonce)) + } + + StringifyLargeNumbers(jObject); + + return jObject.ToString(); + } + + /// + /// Serializes a signature for use with ERC-6492. The signature must be generated by a signer for an ERC-4337 Account Factory account with counterfactual deployment addresses. + /// + /// The ERC-4337 Account Factory address + /// Account deployment calldata (if not deployed) for counterfactual verification + /// The original signature + /// The serialized signature hex string. + public static string SerializeErc6492Signature(string address, byte[] data, byte[] signature) + { + var encoder = new ABIEncode(); + var encodedParams = encoder.GetABIEncoded(new ABIValue("address", address), new ABIValue("bytes", data), new ABIValue("bytes", signature)); + return HexConcat(encodedParams.BytesToHex(), Constants.ERC_6492_MAGIC_VALUE); + } + + /// + /// Removes leading zeroes from the given byte array. + /// + public static byte[] TrimZeroes(this byte[] bytes) + { + var trimmed = new List(); + var previousByteWasZero = true; + + for (var i = 0; i < bytes.Length; i++) + { + if (previousByteWasZero && bytes[i] == 0) { - throw new ArgumentNullException(nameof(loginPayloadData.Nonce)); + continue; } - else if (string.IsNullOrEmpty(loginPayloadData.IssuedAt)) + + previousByteWasZero = false; + trimmed.Add(bytes[i]); + } + + return trimmed.ToArray(); + } + + public static async void TrackTransaction(ThirdwebTransaction transaction, string transactionHash) + { + try + { + var wallet = transaction.Wallet; + var content = new StringContent( + JsonConvert.SerializeObject( + new + { + source = "sdk", + action = "transaction:sent", + clientId = wallet.Client.ClientId, + chainId = transaction.Input.ChainId.Value, + transactionHash, + walletAddress = await wallet.GetAddress().ConfigureAwait(false), + walletType = wallet.WalletId, + contractAddress = transaction.Input.To, + gasPrice = transaction.Input.GasPrice?.Value ?? transaction.Input.MaxFeePerGas?.Value, + } + ), + Encoding.UTF8, + "application/json" + ); + _ = await wallet.Client.HttpClient.PostAsync("https://c.thirdweb.com/event", content); + } + catch + { + // Ignore + } + } + + public static async void TrackConnection(IThirdwebWallet wallet) + { + try + { + var content = new StringContent( + JsonConvert.SerializeObject( + new + { + source = "connectWallet", + action = "connect", + walletAddress = await wallet.GetAddress().ConfigureAwait(false), + walletType = wallet.WalletId, + } + ), + Encoding.UTF8, + "application/json" + ); + _ = await wallet.Client.HttpClient.PostAsync("https://c.thirdweb.com/event", content); + } + catch + { + // Ignore + } + } + + /// + /// Waits for the transaction receipt. + /// + /// The Thirdweb client. + /// The chain ID. + /// The transaction hash. + /// The cancellation token. + /// The transaction receipt. + public static async Task WaitForTransactionReceipt(ThirdwebClient client, BigInteger chainId, string txHash, CancellationToken cancellationToken = default) + { + using var cts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken); + cts.CancelAfter(client.FetchTimeoutOptions.GetTimeout(TimeoutType.Other)); + + var rpc = ThirdwebRPC.GetRpcInstance(client, chainId); + ThirdwebTransactionReceipt receipt = null; + + try + { + do { - throw new ArgumentNullException(nameof(loginPayloadData.IssuedAt)); - } + receipt = await rpc.SendRequestAsync("eth_getTransactionReceipt", txHash).ConfigureAwait(false); + if (receipt == null) + { + await ThirdwebTask.Delay(100, cts.Token).ConfigureAwait(false); + } + } while (receipt == null && !cts.Token.IsCancellationRequested); - var resourcesString = loginPayloadData.Resources != null ? "\nResources:" + string.Join("", loginPayloadData.Resources.Select(r => $"\n- {r}")) : string.Empty; - var payloadToSign = - $"{loginPayloadData.Domain} wants you to sign in with your Ethereum account:" - + $"\n{loginPayloadData.Address}\n\n" - + $"{(string.IsNullOrEmpty(loginPayloadData.Statement) ? "" : $"{loginPayloadData.Statement}\n")}" - + $"{(string.IsNullOrEmpty(loginPayloadData.Uri) ? "" : $"\nURI: {loginPayloadData.Uri}")}" - + $"\nVersion: {loginPayloadData.Version}" - + $"\nChain ID: {loginPayloadData.ChainId}" - + $"\nNonce: {loginPayloadData.Nonce}" - + $"\nIssued At: {loginPayloadData.IssuedAt}" - + $"{(string.IsNullOrEmpty(loginPayloadData.ExpirationTime) ? "" : $"\nExpiration Time: {loginPayloadData.ExpirationTime}")}" - + $"{(string.IsNullOrEmpty(loginPayloadData.InvalidBefore) ? "" : $"\nNot Before: {loginPayloadData.InvalidBefore}")}" - + resourcesString; - return payloadToSign; - } - - /// - /// Checks if the chain ID corresponds to zkSync. - /// - /// The chain ID. - /// True if it is a zkSync chain ID, otherwise false. - public static bool IsZkSync(BigInteger chainId) - { - return chainId.Equals(324) || chainId.Equals(300) || chainId.Equals(302); - } - - /// - /// Converts an Ethereum address to its checksum format. - /// - /// The Ethereum address. - /// The checksummed Ethereum address. - public static string ToChecksumAddress(this string address) - { - return new AddressUtil().ConvertToChecksumAddress(address); - } - - /// - /// Decodes all events of the specified type from the transaction receipt logs. - /// - /// The event DTO type. - /// The transaction receipt. - /// A list of decoded events. - public static List> DecodeAllEvents(this ThirdwebTransactionReceipt transactionReceipt) - where TEventDTO : new() - { - return transactionReceipt.Logs.DecodeAllEvents(); - } - - /// - /// Adjusts the value's decimals. - /// - /// The value. - /// The original number of decimals. - /// The target number of decimals. - /// The value adjusted to the new decimals. - public static BigInteger AdjustDecimals(this BigInteger value, int fromDecimals, int toDecimals) - { - var differenceInDecimals = fromDecimals - toDecimals; - - if (differenceInDecimals > 0) + if (receipt == null) { - return value / BigInteger.Pow(10, differenceInDecimals); + throw new Exception($"Transaction {txHash} not found within the timeout period."); } - else if (differenceInDecimals < 0) + + if (receipt.Status != null && receipt.Status.Value == 0) { - return value * BigInteger.Pow(10, -differenceInDecimals); + throw new Exception($"Transaction {txHash} execution reverted."); } - - return value; } + catch (OperationCanceledException) + { + throw new Exception($"Transaction receipt polling for hash {txHash} was cancelled."); + } + + return receipt; + } + + public static async Task IsDelegatedAccount(ThirdwebClient client, BigInteger chainId, string address, string delegationContract) + { + var rpc = ThirdwebRPC.GetRpcInstance(client, chainId); + var code = await rpc.SendRequestAsync("eth_getCode", address, "latest"); + return code.Equals($"0xef0100{delegationContract[2..]}", StringComparison.OrdinalIgnoreCase); } } diff --git a/Thirdweb/Thirdweb.Wallets/EIP712.cs b/Thirdweb/Thirdweb.Wallets/EIP712.cs deleted file mode 100644 index a222704c..00000000 --- a/Thirdweb/Thirdweb.Wallets/EIP712.cs +++ /dev/null @@ -1,397 +0,0 @@ -using System.Numerics; -using Nethereum.ABI.EIP712; -using Nethereum.Hex.HexConvertors.Extensions; -using Nethereum.Model; -using Nethereum.RLP; -using Nethereum.Signer; - -namespace Thirdweb -{ - /// - /// Provides methods for generating and signing EIP712 compliant messages and transactions. - /// - public static class EIP712 - { - #region Generation - - /// - /// Generates a signature for a smart account permission request. - /// - /// The domain name. - /// The version. - /// The chain ID. - /// The verifying contract. - /// The signer permission request. - /// The wallet signer. - /// The generated signature. - public static async Task GenerateSignature_SmartAccount( - string domainName, - string version, - BigInteger chainId, - string verifyingContract, - AccountAbstraction.SignerPermissionRequest signerPermissionRequest, - IThirdwebWallet signer - ) - { - var typedData = GetTypedDefinition_SmartAccount(domainName, version, chainId, verifyingContract); - return await signer.SignTypedDataV4(signerPermissionRequest, typedData); - } - - /// - /// Generates a signature for a smart account message. - /// - /// The domain name. - /// The version. - /// The chain ID. - /// The verifying contract. - /// The message to sign. - /// The wallet signer. - /// The generated signature. - public static async Task GenerateSignature_SmartAccount_AccountMessage( - string domainName, - string version, - BigInteger chainId, - string verifyingContract, - byte[] message, - IThirdwebWallet signer - ) - { - var typedData = GetTypedDefinition_SmartAccount_AccountMessage(domainName, version, chainId, verifyingContract); - var accountMessage = new AccountAbstraction.AccountMessage { Message = message }; - return await signer.SignTypedDataV4(accountMessage, typedData); - } - - /// - /// Generates a signature for a zkSync transaction. - /// - /// The domain name. - /// The version. - /// The chain ID. - /// The zkSync transaction. - /// The wallet signer. - /// The generated signature. - public static async Task GenerateSignature_ZkSyncTransaction( - string domainName, - string version, - BigInteger chainId, - AccountAbstraction.ZkSyncAATransaction transaction, - IThirdwebWallet signer - ) - { - var typedData = GetTypedDefinition_ZkSyncTransaction(domainName, version, chainId); - var signatureHex = await signer.SignTypedDataV4(transaction, typedData); - var signatureRaw = EthECDSASignatureFactory.ExtractECDSASignature(signatureHex); - return SerializeEip712(transaction, signatureRaw, chainId); - } - - /// - /// Generates a signature for a minimal forwarder request. - /// - /// The domain name. - /// The version. - /// The chain ID. - /// The verifying contract. - /// The forward request. - /// The wallet signer. - /// The generated signature. - public static async Task GenerateSignature_MinimalForwarder( - string domainName, - string version, - BigInteger chainId, - string verifyingContract, - Forwarder_ForwardRequest forwardRequest, - IThirdwebWallet signer - ) - { - var typedData = GetTypedDefinition_MinimalForwarder(domainName, version, chainId, verifyingContract); - return await signer.SignTypedDataV4(forwardRequest, typedData); - } - - /// - /// Generates a signature for an ERC20 token mint request. - /// - /// The domain name. - /// The version. - /// The chain ID. - /// The verifying contract. - /// The mint request. - /// The wallet signer. - /// The generated signature. - public static async Task GenerateSignature_TokenERC20( - string domainName, - string version, - BigInteger chainId, - string verifyingContract, - TokenERC20_MintRequest mintRequest, - IThirdwebWallet signer - ) - { - var typedData = GetTypedDefinition_TokenERC20(domainName, version, chainId, verifyingContract); - return await signer.SignTypedDataV4(mintRequest, typedData); - } - - /// - /// Generates a signature for an ERC721 token mint request. - /// - /// The domain name. - /// The version. - /// The chain ID. - /// The verifying contract. - /// The mint request. - /// The wallet signer. - /// The generated signature. - public static async Task GenerateSignature_TokenERC721( - string domainName, - string version, - BigInteger chainId, - string verifyingContract, - TokenERC721_MintRequest mintRequest, - IThirdwebWallet signer - ) - { - var typedData = GetTypedDefinition_TokenERC721(domainName, version, chainId, verifyingContract); - return await signer.SignTypedDataV4(mintRequest, typedData); - } - - /// - /// Generates a signature for an ERC1155 token mint request. - /// - /// The domain name. - /// The version. - /// The chain ID. - /// The verifying contract. - /// The mint request. - /// The wallet signer. - /// The generated signature. - public static async Task GenerateSignature_TokenERC1155( - string domainName, - string version, - BigInteger chainId, - string verifyingContract, - TokenERC1155_MintRequest mintRequest, - IThirdwebWallet signer - ) - { - var typedData = GetTypedDefinition_TokenERC1155(domainName, version, chainId, verifyingContract); - return await signer.SignTypedDataV4(mintRequest, typedData); - } - - #endregion - - #region Typed Definitions - - /// - /// Gets the typed data definition for a smart account permission request. - /// - /// The domain name. - /// The version. - /// The chain ID. - /// The verifying contract. - /// The typed data definition. - public static TypedData GetTypedDefinition_SmartAccount(string domainName, string version, BigInteger chainId, string verifyingContract) - { - return new TypedData - { - Domain = new Domain - { - Name = domainName, - Version = version, - ChainId = chainId, - VerifyingContract = verifyingContract, - }, - Types = MemberDescriptionFactory.GetTypesMemberDescription(typeof(Domain), typeof(AccountAbstraction.SignerPermissionRequest)), - PrimaryType = "SignerPermissionRequest", - }; - } - - /// - /// Gets the typed data definition for a smart account message. - /// - /// The domain name. - /// The version. - /// The chain ID. - /// The verifying contract. - /// The typed data definition. - public static TypedData GetTypedDefinition_SmartAccount_AccountMessage(string domainName, string version, BigInteger chainId, string verifyingContract) - { - return new TypedData - { - Domain = new Domain - { - Name = domainName, - Version = version, - ChainId = chainId, - VerifyingContract = verifyingContract, - }, - Types = MemberDescriptionFactory.GetTypesMemberDescription(typeof(Domain), typeof(AccountAbstraction.AccountMessage)), - PrimaryType = "AccountMessage", - }; - } - - /// - /// Gets the typed data definition for a zkSync transaction. - /// - /// The domain name. - /// The version. - /// The chain ID. - /// The typed data definition. - public static TypedData GetTypedDefinition_ZkSyncTransaction(string domainName, string version, BigInteger chainId) - { - return new TypedData - { - Domain = new DomainWithNameVersionAndChainId - { - Name = domainName, - Version = version, - ChainId = chainId, - }, - Types = MemberDescriptionFactory.GetTypesMemberDescription(typeof(DomainWithNameVersionAndChainId), typeof(AccountAbstraction.ZkSyncAATransaction)), - PrimaryType = "Transaction", - }; - } - - /// - /// Gets the typed data definition for a TokenERC20 mint request. - /// - /// The domain name. - /// The version. - /// The chain ID. - /// The verifying contract. - /// The typed data definition. - public static TypedData GetTypedDefinition_TokenERC20(string domainName, string version, BigInteger chainId, string verifyingContract) - { - return new TypedData - { - Domain = new Domain - { - Name = domainName, - Version = version, - ChainId = chainId, - VerifyingContract = verifyingContract, - }, - Types = MemberDescriptionFactory.GetTypesMemberDescription(typeof(Domain), typeof(TokenERC20_MintRequest)), - PrimaryType = "MintRequest", - }; - } - - /// - /// Gets the typed data definition for a TokenERC721 mint request. - /// - /// The domain name. - /// The version. - /// The chain ID. - /// The verifying contract. - /// The typed data definition. - public static TypedData GetTypedDefinition_TokenERC721(string domainName, string version, BigInteger chainId, string verifyingContract) - { - return new TypedData - { - Domain = new Domain - { - Name = domainName, - Version = version, - ChainId = chainId, - VerifyingContract = verifyingContract, - }, - Types = MemberDescriptionFactory.GetTypesMemberDescription(typeof(Domain), typeof(TokenERC721_MintRequest)), - PrimaryType = "MintRequest", - }; - } - - /// - /// Gets the typed data definition for a TokenERC1155 mint request. - /// - /// The domain name. - /// The version. - /// The chain ID. - /// The verifying contract. - /// The typed data definition. - public static TypedData GetTypedDefinition_TokenERC1155(string domainName, string version, BigInteger chainId, string verifyingContract) - { - return new TypedData - { - Domain = new Domain - { - Name = domainName, - Version = version, - ChainId = chainId, - VerifyingContract = verifyingContract, - }, - Types = MemberDescriptionFactory.GetTypesMemberDescription(typeof(Domain), typeof(TokenERC1155_MintRequest)), - PrimaryType = "MintRequest", - }; - } - - /// - /// Gets the typed data definition for a minimal forwarder request. - /// - /// The domain name. - /// The version. - /// The chain ID. - /// The verifying contract. - /// The typed data definition. - public static TypedData GetTypedDefinition_MinimalForwarder(string domainName, string version, BigInteger chainId, string verifyingContract) - { - return new TypedData - { - Domain = new Domain - { - Name = domainName, - Version = version, - ChainId = chainId, - VerifyingContract = verifyingContract, - }, - Types = MemberDescriptionFactory.GetTypesMemberDescription(typeof(Domain), typeof(Forwarder_ForwardRequest)), - PrimaryType = "ForwardRequest", - }; - } - - #endregion - - #region Helpers - - /// - /// Serializes an EIP712 zkSync transaction. - /// - /// The transaction. - /// The ECDSA signature. - /// The chain ID. - /// The serialized transaction. - private static string SerializeEip712(AccountAbstraction.ZkSyncAATransaction transaction, EthECDSASignature signature, BigInteger chainId) - { - if (chainId == 0) - { - throw new ArgumentException("Chain ID must be provided for EIP712 transactions!"); - } - - var fields = new List - { - transaction.Nonce == 0 ? new byte[0] : transaction.Nonce.ToByteArray(isUnsigned: true, isBigEndian: true), - transaction.MaxPriorityFeePerGas == 0 ? new byte[0] : transaction.MaxPriorityFeePerGas.ToByteArray(isUnsigned: true, isBigEndian: true), - transaction.MaxFeePerGas.ToByteArray(isUnsigned: true, isBigEndian: true), - transaction.GasLimit.ToByteArray(isUnsigned: true, isBigEndian: true), - transaction.To.ToByteArray(isUnsigned: true, isBigEndian: true), - transaction.Value == 0 ? new byte[0] : transaction.Value.ToByteArray(isUnsigned: true, isBigEndian: true), - transaction.Data == null ? new byte[0] : transaction.Data, - }; - - fields.Add(signature.IsVSignedForYParity() ? new byte[] { 0x1b } : new byte[] { 0x1c }); - fields.Add(signature.R); - fields.Add(signature.S); - - fields.Add(chainId.ToByteArray(isUnsigned: true, isBigEndian: true)); - fields.Add(transaction.From.ToByteArray(isUnsigned: true, isBigEndian: true)); - - // Add meta - fields.Add(transaction.GasPerPubdataByteLimit.ToByteArray(isUnsigned: true, isBigEndian: true)); - fields.Add(new byte[] { }); // TODO: FactoryDeps - fields.Add(signature.CreateStringSignature().HexToByteArray()); - // add array of rlp encoded paymaster/paymasterinput - fields.Add(RLP.EncodeElement(transaction.Paymaster.ToByteArray(isUnsigned: true, isBigEndian: true)).Concat(RLP.EncodeElement(transaction.PaymasterInput)).ToArray()); - - return "0x71" + RLP.EncodeDataItemsAsElementOrListAndCombineAsList(fields.ToArray(), new int[] { 13, 15 }).ToHex(); - } - - #endregion - } -} diff --git a/Thirdweb/Thirdweb.Wallets/IThirdwebWallet.cs b/Thirdweb/Thirdweb.Wallets/IThirdwebWallet.cs index 627b12b4..390b40c9 100644 --- a/Thirdweb/Thirdweb.Wallets/IThirdwebWallet.cs +++ b/Thirdweb/Thirdweb.Wallets/IThirdwebWallet.cs @@ -1,212 +1,253 @@ -using System.Numerics; +using System.Numerics; using Nethereum.ABI.EIP712; using Newtonsoft.Json; -namespace Thirdweb +namespace Thirdweb; + +/// +/// Interface for a Thirdweb wallet. +/// +public interface IThirdwebWallet { /// - /// Interface for a Thirdweb wallet. + /// Gets the Thirdweb client associated with the wallet. /// - public interface IThirdwebWallet - { - /// - /// Gets the Thirdweb client associated with the wallet. - /// - ThirdwebClient Client { get; } - - /// - /// Gets the account type of the wallet. - /// - ThirdwebAccountType AccountType { get; } - - /// - /// Gets the address of the wallet. - /// - /// The wallet address. - Task GetAddress(); - - /// - /// Signs a raw message using Ethereum's signing method. - /// - /// The raw message to sign. - /// The signed message. - Task EthSign(byte[] rawMessage); - - /// - /// Signs a message using Ethereum's signing method. - /// - /// The message to sign. - /// The signed message. - Task EthSign(string message); - - /// - /// Signs a raw message using personal signing. - /// - /// The raw message to sign. - /// The signed message. - Task PersonalSign(byte[] rawMessage); - - /// - /// Signs a message using personal signing. - /// - /// The message to sign. - /// The signed message. - Task PersonalSign(string message); - - /// - /// Signs typed data (version 4). - /// - /// The JSON representation of the typed data. - /// The signed data. - Task SignTypedDataV4(string json); - - /// - /// Signs typed data (version 4). - /// - /// The type of the data. - /// The type of the domain. - /// The data to sign. - /// The typed data. - /// The signed data. - Task SignTypedDataV4(T data, TypedData typedData) - where TDomain : IDomain; - - /// - /// Checks if the wallet is connected. - /// - /// True if connected, otherwise false. - Task IsConnected(); - - /// - /// Signs a transaction. - /// - /// The transaction to sign. - /// The signed transaction. - Task SignTransaction(ThirdwebTransactionInput transaction); - - /// - /// Sends a transaction. - /// - /// The transaction to send. - /// The transaction hash. - Task SendTransaction(ThirdwebTransactionInput transaction); - - /// - /// Authenticates the wallet. - /// - /// The authentication domain. - /// The chain ID. - /// The authentication payload path. - /// The authentication login path. - /// The HTTP client override. - /// The authentication result. - Task Authenticate(string domain, BigInteger chainId, string authPayloadPath = "/auth/payload", string authLoginPath = "/auth/login", IThirdwebHttpClient httpClientOverride = null); - } + public ThirdwebClient Client { get; } /// - /// Enum for the types of Thirdweb accounts. + /// Gets the account type of the wallet. /// - public enum ThirdwebAccountType - { - PrivateKeyAccount, - SmartAccount, - ExternalAccount - } + public ThirdwebAccountType AccountType { get; } /// - /// Represents a login payload. + /// String identifier for the wallet to be used in analytics. /// - [Serializable] - public struct LoginPayload - { - public LoginPayloadData payload; - public string signature; - } + public string WalletId { get; } + + /// + /// Gets the address of the wallet. + /// + /// The wallet address. + public Task GetAddress(); + + /// + /// Signs a raw message using personal signing. + /// + /// The raw message to sign. + /// The signed message. + public Task PersonalSign(byte[] rawMessage); + + /// + /// Signs a message using personal signing. + /// + /// The message to sign. + /// The signed message. + public Task PersonalSign(string message); + + /// + /// Signs typed data (version 4). + /// + /// The JSON representation of the typed data. + /// The signed data. + public Task SignTypedDataV4(string json); + + /// + /// Signs typed data (version 4). + /// + /// The type of the data. + /// The type of the domain. + /// The data to sign. + /// The typed data. + /// The signed data. + public Task SignTypedDataV4(T data, TypedData typedData) + where TDomain : IDomain; + + /// + /// Checks if the wallet is connected. + /// + /// True if connected, otherwise false. + public Task IsConnected(); + + /// + /// Signs a transaction. + /// + /// The transaction to sign. + /// The signed transaction. + public Task SignTransaction(ThirdwebTransactionInput transaction); + + /// + /// Sends a transaction. + /// + /// The transaction to send. + /// The transaction hash. + public Task SendTransaction(ThirdwebTransactionInput transaction); + + /// + /// Sends a transaction and waits for its receipt. + /// + /// The transaction to execute. + /// The transaction receipt. + public Task ExecuteTransaction(ThirdwebTransactionInput transaction); + + /// + /// Disconnects the wallet (if using InAppWallet, clears session) + /// + public Task Disconnect(); + + /// + /// Links a new account (auth method) to the current wallet. The current wallet must be connected and the wallet being linked must not be fully connected ie created. + /// + /// The wallet to link. + /// The OTP code if the wallet to link is an email or phone wallet. + /// Set to true if linking OAuth on mobile. + /// The action to open the browser if linking OAuth. + /// The redirect scheme if linking OAuth on mobile. + /// The browser to use if linking OAuth. + /// The chain ID if linking an external wallet (SIWE). + /// The JWT token if linking custom JWT auth. + /// The login payload if linking custom AuthEndpoint auth. + /// The default session ID override if linking Guest auth. + /// A list of objects. + public Task> LinkAccount( + IThirdwebWallet walletToLink, + string otp = null, + bool? isMobile = null, + Action browserOpenAction = null, + string mobileRedirectScheme = "thirdweb://", + IThirdwebBrowser browser = null, + BigInteger? chainId = null, + string jwt = null, + string payload = null, + string defaultSessionIdOverride = null + ); + + /// + /// Unlinks an account (auth method) from the current wallet. + /// + /// The linked account to unlink. Same type returned by . + public Task> UnlinkAccount(LinkedAccount accountToUnlink); + + /// + /// Returns a list of linked accounts to the current wallet. + /// + /// A list of objects. + public Task> GetLinkedAccounts(); + + /// + /// Signs an EIP-7702 authorization to invoke contract functions to an externally owned account. + /// + /// The chain ID of the contract. + /// The address of the contract. + /// Set to true if the wallet will also be the executor of the transaction, otherwise false. + /// The signed authorization as an that can be used with . + public Task SignAuthorization(BigInteger chainId, string contractAddress, bool willSelfExecute); + + /// + /// Attempts to set the active network to the specified chain ID. + /// + /// The chain ID to switch to. + public Task SwitchNetwork(BigInteger chainId); +} + +/// +/// Enum for the types of Thirdweb accounts. +/// +public enum ThirdwebAccountType +{ + PrivateKeyAccount, + SmartAccount, + ExternalAccount, +} + +/// +/// Represents a login payload. +/// +[Serializable] +public struct LoginPayload +{ + public LoginPayloadData Payload { get; set; } + public string Signature { get; set; } +} + +/// +/// Represents login payload data. +/// +[Serializable] +public class LoginPayloadData +{ + /// + /// Gets or sets the domain of the login payload. + /// + [JsonProperty("domain")] + public string Domain { get; set; } + + /// + /// Gets or sets the address of the login payload. + /// + [JsonProperty("address")] + public string Address { get; set; } + + /// + /// Gets or sets the statement of the login payload. + /// + [JsonProperty("statement")] + public string Statement { get; set; } /// - /// Represents login payload data. + /// Gets or sets the URI of the login payload. /// - [Serializable] - public class LoginPayloadData + [JsonProperty("uri", NullValueHandling = NullValueHandling.Ignore)] + public string Uri { get; set; } + + /// + /// Gets or sets the version of the login payload. + /// + [JsonProperty("version", NullValueHandling = NullValueHandling.Ignore)] + public string Version { get; set; } + + /// + /// Gets or sets the chain ID of the login payload. + /// + [JsonProperty("chain_id", NullValueHandling = NullValueHandling.Ignore)] + public string ChainId { get; set; } + + /// + /// Gets or sets the nonce of the login payload. + /// + [JsonProperty("nonce", NullValueHandling = NullValueHandling.Ignore)] + public string Nonce { get; set; } + + /// + /// Gets or sets the issued at timestamp of the login payload. + /// + [JsonProperty("issued_at", NullValueHandling = NullValueHandling.Ignore)] + public string IssuedAt { get; set; } + + /// + /// Gets or sets the expiration time of the login payload. + /// + [JsonProperty("expiration_time", NullValueHandling = NullValueHandling.Ignore)] + public string ExpirationTime { get; set; } + + /// + /// Gets or sets the invalid before timestamp of the login payload. + /// + [JsonProperty("invalid_before", NullValueHandling = NullValueHandling.Ignore)] + public string InvalidBefore { get; set; } + + /// + /// Gets or sets the resources of the login payload. + /// + [JsonProperty("resources", NullValueHandling = NullValueHandling.Ignore)] + public List Resources { get; set; } + + /// + /// Initializes a new instance of the class. + /// + public LoginPayloadData() { } + + public override string ToString() { - /// - /// Gets or sets the type of the login payload. - /// - [JsonProperty("type")] - public string Type { get; set; } - - /// - /// Gets or sets the domain of the login payload. - /// - [JsonProperty("domain")] - public string Domain { get; set; } - - /// - /// Gets or sets the address of the login payload. - /// - [JsonProperty("address")] - public string Address { get; set; } - - /// - /// Gets or sets the statement of the login payload. - /// - [JsonProperty("statement")] - public string Statement { get; set; } - - /// - /// Gets or sets the URI of the login payload. - /// - [JsonProperty("uri", NullValueHandling = NullValueHandling.Ignore)] - public string Uri { get; set; } - - /// - /// Gets or sets the version of the login payload. - /// - [JsonProperty("version", NullValueHandling = NullValueHandling.Ignore)] - public string Version { get; set; } - - /// - /// Gets or sets the chain ID of the login payload. - /// - [JsonProperty("chain_id", NullValueHandling = NullValueHandling.Ignore)] - public string ChainId { get; set; } - - /// - /// Gets or sets the nonce of the login payload. - /// - [JsonProperty("nonce", NullValueHandling = NullValueHandling.Ignore)] - public string Nonce { get; set; } - - /// - /// Gets or sets the issued at timestamp of the login payload. - /// - [JsonProperty("issued_at", NullValueHandling = NullValueHandling.Ignore)] - public string IssuedAt { get; set; } - - /// - /// Gets or sets the expiration time of the login payload. - /// - [JsonProperty("expiration_time", NullValueHandling = NullValueHandling.Ignore)] - public string ExpirationTime { get; set; } - - /// - /// Gets or sets the invalid before timestamp of the login payload. - /// - [JsonProperty("invalid_before", NullValueHandling = NullValueHandling.Ignore)] - public string InvalidBefore { get; set; } - - /// - /// Gets or sets the resources of the login payload. - /// - [JsonProperty("resources", NullValueHandling = NullValueHandling.Ignore)] - public List Resources { get; set; } - - /// - /// Initializes a new instance of the class. - /// - public LoginPayloadData() - { - Type = "evm"; - } + return JsonConvert.SerializeObject(this); } } diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/EcosystemWallet/EcosystemWallet.Types.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/EcosystemWallet/EcosystemWallet.Types.cs new file mode 100644 index 00000000..a882f359 --- /dev/null +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/EcosystemWallet/EcosystemWallet.Types.cs @@ -0,0 +1,112 @@ +using System.Numerics; +using Newtonsoft.Json; + +namespace Thirdweb; + +public partial class EcosystemWallet +{ + /// + /// User linked account details. + /// + public class UserStatusResponse + { + /// + /// The user's linked accounts. + /// + [JsonProperty("linkedAccounts")] + public List LinkedAccounts { get; set; } + + /// + /// The user's wallets, generally only one wallet is returned. + /// + [JsonProperty("wallets")] + public List Wallets { get; set; } + } + + /// + /// Represents a user's embedded wallet. + /// + public class ShardedOrEnclaveWallet + { + /// + /// The public address of the wallet. + /// + [JsonProperty("address")] + public string Address { get; set; } + + /// + /// The wallet's creation date. + /// + [JsonProperty("createdAt")] + public DateTime CreatedAt { get; set; } + + [JsonProperty("type")] + internal string Type { get; set; } + } + + internal class EnclaveGenerateResponse + { + [JsonProperty("wallet")] + internal EnclaveWallet Wallet { get; set; } + } + + internal class EnclaveWallet + { + [JsonProperty("address")] + internal string Address { get; set; } + } + + internal class EnclaveSignResponse + { + [JsonProperty("r")] + internal string R { get; set; } + + [JsonProperty("s")] + internal string S { get; set; } + + [JsonProperty("v")] + internal string V { get; set; } + + [JsonProperty("signature")] + internal string Signature { get; set; } + + [JsonProperty("hash")] + internal string Hash { get; set; } + } + + public class EcosystemDetails + { + [JsonProperty("thirdwebAccountId")] + public string ThirdwebAccountId { get; set; } + + [JsonProperty("permission")] + public string Permission { get; set; } + + [JsonProperty("authOptions")] + public List AuthOptions { get; set; } + + [JsonProperty("name")] + public string Name { get; set; } + + [JsonProperty("slug")] + public string Slug { get; set; } + + [JsonProperty("imageUrl")] + public string ImageUrl { get; set; } + + [JsonProperty("smartAccountOptions")] + public EcosystemDetails_SmartAccountOptions? SmartAccountOptions { get; set; } + } + + public struct EcosystemDetails_SmartAccountOptions + { + [JsonProperty("chainIds")] + public List ChainIds { get; set; } + + [JsonProperty("sponsorGas")] + public bool SponsorGas { get; set; } + + [JsonProperty("accountFactoryAddress")] + public string AccountFactoryAddress { get; set; } + } +} diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/EcosystemWallet/EcosystemWallet.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/EcosystemWallet/EcosystemWallet.cs new file mode 100644 index 00000000..79f42f3a --- /dev/null +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/EcosystemWallet/EcosystemWallet.cs @@ -0,0 +1,1315 @@ +using System.Numerics; +using System.Text; +using System.Web; +using Nethereum.ABI.EIP712; +using Nethereum.Util; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using Thirdweb.AccountAbstraction; +using Thirdweb.EWS; + +namespace Thirdweb; + +public enum ExecutionMode +{ + EOA, + EIP7702, + EIP7702Sponsored, +} + +/// +/// Enclave based secure cross ecosystem wallet. +/// +public partial class EcosystemWallet : IThirdwebWallet +{ + public ThirdwebClient Client { get; } + public ThirdwebAccountType AccountType { get; } + public virtual string WalletId => "ecosystem"; + + internal readonly EmbeddedWallet EmbeddedWallet; + internal readonly IThirdwebHttpClient HttpClient; + internal readonly IThirdwebWallet SiweSigner; + internal readonly string Email; + internal readonly string PhoneNumber; + internal readonly string AuthProvider; + internal readonly string WalletSecret; + + internal string Address; + internal ExecutionMode ExecutionMode; + internal string DelegationContractAddress; + + private readonly string _ecosystemId; + private readonly string _ecosystemPartnerId; + + private const string EMBEDDED_WALLET_BASE_PATH = "https://embedded-wallet.thirdweb.com/api"; + private const string EMBEDDED_WALLET_PATH_2024 = $"{EMBEDDED_WALLET_BASE_PATH}/2024-05-05"; + private const string EMBEDDED_WALLET_PATH_V1 = $"{EMBEDDED_WALLET_BASE_PATH}/v1"; + private const string ENCLAVE_PATH = $"{EMBEDDED_WALLET_PATH_V1}/enclave-wallet"; + + internal EcosystemWallet( + string ecosystemId, + string ecosystemPartnerId, + ThirdwebClient client, + EmbeddedWallet embeddedWallet, + IThirdwebHttpClient httpClient, + string email, + string phoneNumber, + string authProvider, + IThirdwebWallet siweSigner, + string walletSecret, + ExecutionMode executionMode, + string delegationContractAddress + ) + { + this.Client = client; + this._ecosystemId = ecosystemId; + this._ecosystemPartnerId = ecosystemPartnerId; + this.EmbeddedWallet = embeddedWallet; + this.HttpClient = httpClient; + this.Email = email; + this.PhoneNumber = phoneNumber; + this.AuthProvider = authProvider; + this.SiweSigner = siweSigner; + this.WalletSecret = walletSecret; + this.ExecutionMode = executionMode; + this.AccountType = executionMode == ExecutionMode.EOA ? ThirdwebAccountType.PrivateKeyAccount : ThirdwebAccountType.ExternalAccount; + this.DelegationContractAddress = delegationContractAddress; + } + + #region Creation + + /// + /// Creates a new instance of the class. + /// + /// Your ecosystem ID (see thirdweb dashboard e.g. ecosystem.the-bonfire). + /// Your ecosystem partner ID (required if you are integrating someone else's ecosystem). + /// The Thirdweb client instance. + /// The email address for Email OTP authentication. + /// The phone number for Phone OTP authentication. + /// The authentication provider to use. + /// The path to the storage directory. + /// The SIWE signer wallet for SIWE authentication. + /// The wallet secret for Backend authentication. + /// The auth token to use for the session. This will automatically connect using a raw thirdweb auth token. + /// The execution mode for the wallet. EOA represents traditional direct calls, EIP7702 represents upgraded account self sponsored calls, and EIP7702Sponsored represents upgraded account calls with managed/sponsored execution. + /// A task that represents the asynchronous operation. The task result contains the created in-app wallet. + /// Thrown when required parameters are not provided. + public static async Task Create( + ThirdwebClient client, + string ecosystemId = null, + string ecosystemPartnerId = null, + string email = null, + string phoneNumber = null, + AuthProvider authProvider = Thirdweb.AuthProvider.Default, + string storageDirectoryPath = null, + IThirdwebWallet siweSigner = null, + string walletSecret = null, + string twAuthTokenOverride = null, + ExecutionMode executionMode = ExecutionMode.EOA + ) + { + if (client == null) + { + throw new ArgumentNullException(nameof(client), "Client cannot be null."); + } + + var delegationContractResponse = await ThirdwebBundler.TwGetDelegationContract(client: client, url: $"https://1.bundler.thirdweb.com", requestId: 7702); + + if (string.IsNullOrEmpty(email) && string.IsNullOrEmpty(phoneNumber) && authProvider == Thirdweb.AuthProvider.Default) + { + throw new ArgumentException("Email, Phone Number, or OAuth Provider must be provided to login."); + } + + var authproviderStr = authProvider switch + { + Thirdweb.AuthProvider.Google => "Google", + Thirdweb.AuthProvider.Apple => "Apple", + Thirdweb.AuthProvider.Facebook => "Facebook", + Thirdweb.AuthProvider.JWT => "JWT", + Thirdweb.AuthProvider.AuthEndpoint => "AuthEndpoint", + Thirdweb.AuthProvider.Discord => "Discord", + Thirdweb.AuthProvider.Farcaster => "Farcaster", + Thirdweb.AuthProvider.Telegram => "Telegram", + Thirdweb.AuthProvider.Siwe => "Siwe", + Thirdweb.AuthProvider.Line => "Line", + Thirdweb.AuthProvider.Guest => "Guest", + Thirdweb.AuthProvider.X => "X", + Thirdweb.AuthProvider.TikTok => "TikTok", + Thirdweb.AuthProvider.Epic => "Epic", + Thirdweb.AuthProvider.Coinbase => "Coinbase", + Thirdweb.AuthProvider.Github => "Github", + Thirdweb.AuthProvider.Twitch => "Twitch", + Thirdweb.AuthProvider.Steam => "Steam", + Thirdweb.AuthProvider.Backend => "Backend", + Thirdweb.AuthProvider.Default => string.IsNullOrEmpty(email) ? "Phone" : "Email", + _ => throw new ArgumentException("Invalid AuthProvider"), + }; + + var headers = client.HttpClient.Headers.ToDictionary(entry => entry.Key, entry => entry.Value); + var platform = client.HttpClient.Headers["x-sdk-platform"]; + var version = client.HttpClient.Headers["x-sdk-version"]; + if (!string.IsNullOrEmpty(client.ClientId)) + { + headers.Add("x-thirdweb-client-id", client.ClientId); + } + if (!string.IsNullOrEmpty(client.SecretKey)) + { + headers.Add("x-thirdweb-secret-key", client.SecretKey); + } + headers.Add("x-session-nonce", Guid.NewGuid().ToString()); + headers.Add("x-embedded-wallet-version", $"{platform}:{version}"); + if (!string.IsNullOrEmpty(ecosystemId)) + { + headers.Add("x-ecosystem-id", ecosystemId); + if (!string.IsNullOrEmpty(ecosystemPartnerId)) + { + headers.Add("x-ecosystem-partner-id", ecosystemPartnerId); + } + } + var enclaveHttpClient = Utils.ReconstructHttpClient(client.HttpClient, headers); + + storageDirectoryPath ??= Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "Thirdweb", "EcosystemWallet"); + var embeddedWallet = new EmbeddedWallet(client, storageDirectoryPath, ecosystemId, ecosystemPartnerId); + if (!string.IsNullOrWhiteSpace(twAuthTokenOverride)) + { + CreateEnclaveSession(embeddedWallet, twAuthTokenOverride, email, phoneNumber, authproviderStr, null); + } + + try + { + var userAddress = await ResumeEnclaveSession(enclaveHttpClient, embeddedWallet, email, phoneNumber, authproviderStr).ConfigureAwait(false); + return new EcosystemWallet( + ecosystemId, + ecosystemPartnerId, + client, + embeddedWallet, + enclaveHttpClient, + email, + phoneNumber, + authproviderStr, + siweSigner, + walletSecret, + executionMode, + delegationContractResponse.DelegationContract + ) + { + Address = userAddress, + }; + } + catch + { + enclaveHttpClient.RemoveHeader("Authorization"); + return new EcosystemWallet( + ecosystemId, + ecosystemPartnerId, + client, + embeddedWallet, + enclaveHttpClient, + email, + phoneNumber, + authproviderStr, + siweSigner, + walletSecret, + executionMode, + delegationContractResponse.DelegationContract + ) + { + Address = null, + }; + } + } + + private static async Task ResumeEnclaveSession(IThirdwebHttpClient httpClient, EmbeddedWallet embeddedWallet, string email, string phone, string authProvider) + { + email = email?.ToLower(); + + var sessionData = embeddedWallet.GetSessionData(); + + if (string.IsNullOrEmpty(sessionData.AuthToken)) + { + throw new InvalidOperationException("User is not signed in"); + } + + if (sessionData.EmailAddress != email || sessionData.PhoneNumber != phone || sessionData.AuthProvider != authProvider) + { + throw new InvalidOperationException("Saved session data does not match provided details"); + } + + httpClient.AddHeader("Authorization", $"Bearer embedded-wallet-token:{sessionData.AuthToken}"); + + var userStatus = await GetUserStatus(httpClient).ConfigureAwait(false); + if (userStatus.Wallets[0].Type == "enclave") + { + return userStatus.Wallets[0].Address.ToChecksumAddress(); + } + else + { + await embeddedWallet.SignOutAsync().ConfigureAwait(false); + throw new InvalidOperationException("Must auth again to perform migration."); + } + } + + private static void CreateEnclaveSession(EmbeddedWallet embeddedWallet, string authToken, string email, string phone, string authProvider, string authIdentifier) + { + var data = new LocalStorage.DataStorage(authToken, null, email, phone, null, authProvider, authIdentifier); + embeddedWallet.UpdateSessionData(data); + } + + private static async Task GetUserStatus(IThirdwebHttpClient httpClient) + { + var url = $"{EMBEDDED_WALLET_PATH_2024}/accounts"; + var response = await httpClient.GetAsync(url).ConfigureAwait(false); + _ = response.EnsureSuccessStatusCode(); + var content = await response.Content.ReadAsStringAsync().ConfigureAwait(false); + var userStatus = JsonConvert.DeserializeObject(content); + return userStatus; + } + + private static async Task GenerateWallet(IThirdwebHttpClient httpClient) + { + var url = $"{ENCLAVE_PATH}/generate"; + var requestContent = new StringContent("", Encoding.UTF8, "application/json"); + var response = await httpClient.PostAsync(url, requestContent).ConfigureAwait(false); + _ = response.EnsureSuccessStatusCode(); + var content = await response.Content.ReadAsStringAsync().ConfigureAwait(false); + var enclaveResponse = JsonConvert.DeserializeObject(content); + return enclaveResponse.Wallet.Address.ToChecksumAddress(); + } + + private async Task PostAuth(Server.VerifyResult result) + { + this.HttpClient.RemoveHeader("Authorization"); + this.HttpClient.AddHeader("Authorization", $"Bearer embedded-wallet-token:{result.AuthToken}"); + + string address; + if (result.IsNewUser) + { + address = await GenerateWallet(this.HttpClient).ConfigureAwait(false); + } + else + { + var userStatus = await GetUserStatus(this.HttpClient).ConfigureAwait(false); + if (userStatus.Wallets[0].Type == "enclave") + { + address = userStatus.Wallets[0].Address; + } + else + { + throw new InvalidOperationException("Existing user does not have an enclave wallet."); + } + } + + if (string.IsNullOrEmpty(address)) + { + throw new InvalidOperationException("Failed to get user address from enclave wallet."); + } + else + { + CreateEnclaveSession(this.EmbeddedWallet, result.AuthToken, this.Email, this.PhoneNumber, this.AuthProvider, result.AuthIdentifier); + this.Address = address.ToChecksumAddress(); + Utils.TrackConnection(this); + return this.Address; + } + } + + #endregion + + #region Wallet Specific + + /// + /// Gets the user details from the enclave wallet. For auth provider specific details use GetUserAuthDetails. + /// + /// A task that represents the asynchronous operation. The task result contains the user details. + public async Task GetUserDetails() + { + return await GetUserStatus(this.HttpClient).ConfigureAwait(false); + } + + /// + /// Gets the user auth details from the corresponding auth provider. For linked account details use GetUserDetails or GetLinkedAccounts. + /// + /// The user auth details as a JObject + public JObject GetUserAuthDetails() + { + var authToken = this.EmbeddedWallet.GetSessionData()?.AuthToken; + if (string.IsNullOrEmpty(authToken)) + { + throw new InvalidOperationException("Cannot get user auth details without an active session."); + } + + var parts = authToken.Split('.'); + if (parts.Length != 3) + { + throw new InvalidOperationException("Invalid JWT"); + } + + static string Base64UrlDecode(string input) + { + var paddedInput = input.Replace('-', '+').Replace('_', '/'); + switch (paddedInput.Length % 4) + { + case 2: + paddedInput += "=="; + break; + case 3: + paddedInput += "="; + break; + default: + break; + } + var decodedBytes = Convert.FromBase64String(paddedInput); + return Encoding.UTF8.GetString(decodedBytes); + } + + var payload = JObject.Parse(Base64UrlDecode(parts[1])); + var jwtToken = payload["storedToken"]?["jwtToken"]?.ToString(); + + parts = jwtToken.Split('.'); + if (parts.Length != 3) + { + throw new InvalidOperationException("Invalid JWT"); + } + + payload = JObject.Parse(Base64UrlDecode(parts[1])); + return payload; + } + + [Obsolete("Use GetUserDetails instead.")] + public string GetEmail() + { + return this.Email; + } + + [Obsolete("Use GetUserDetails instead.")] + public string GetPhoneNumber() + { + return this.PhoneNumber; + } + + /// + /// Returns Ecosystem metadata (set in thirdweb Dashboard) + /// + /// Instance of containing metadata + /// Thrown when called on an InAppWallet + public async Task GetEcosystemDetails() + { + if (this.GetType().Name.Contains("InAppWallet")) + { + throw new InvalidOperationException("Cannot get ecosystem details from an InAppWallet."); + } + var url = $"{EMBEDDED_WALLET_PATH_2024}/ecosystem-wallet"; + var response = await this.HttpClient.GetAsync(url).ConfigureAwait(false); + _ = response.EnsureSuccessStatusCode(); + var content = await response.Content.ReadAsStringAsync().ConfigureAwait(false); + return JsonConvert.DeserializeObject(content); + } + + /// + /// Returns a link that can be used to transfer the .NET wallet session to a thirdweb powered React website for seamless integration. + /// + /// The URL of your thirdweb-powered website. + /// The URL to redirect the user to. + /// Thrown when no connected session is found + public string GenerateExternalLoginLink(string redirectUrl) + { + var authProvider = HttpUtility.UrlEncode(this.AuthProvider.ToLower()); + var walletId = this.GetType().Name.Contains("InAppWallet") ? "inApp" : this._ecosystemId; + var authCookie = HttpUtility.UrlEncode(this.EmbeddedWallet.GetSessionData()?.AuthToken ?? ""); + + if (string.IsNullOrEmpty(authCookie)) + { + throw new InvalidOperationException("Cannot generate external login link without an active session."); + } + + var queryString = redirectUrl.Contains('?') ? "&" : "?" + $"walletId={walletId}&authProvider={authProvider}&authCookie={authCookie}"; + return $"{redirectUrl}{queryString}"; + } + + /// + /// Creates a session key for the user wallet. This is only supported for EIP7702 and EIP7702Sponsored execution modes. + /// + /// The chain ID for the session key. + /// The address of the signer for the session key. + /// Duration in seconds for which the session key will be valid. + /// Whether to grant full permissions to the session key. If false, only the specified call and transfer policies will be applied. + /// List of call policies to apply to the session key. If null, no call policies will be applied. + /// List of transfer policies to apply to the session key. If null, no transfer policies will be applied. + /// A unique identifier for the session key. If null, a new GUID will be generated. + /// A task that represents the asynchronous operation. The task result contains the transaction receipt for the session key creation. + /// Thrown when the execution mode is not EIP7702 or EIP7702Sponsored. + /// Thrown when the signer address is null or empty, or when the duration is less than or equal to zero. + public async Task CreateSessionKey( + BigInteger chainId, + string signerAddress, + long durationInSeconds, + bool grantFullPermissions = true, + List callPolicies = null, + List transferPolicies = null, + byte[] uid = null + ) + { + await this.Ensure7702(chainId, false); + + if (string.IsNullOrEmpty(signerAddress)) + { + throw new ArgumentException("Signer address cannot be null or empty.", nameof(signerAddress)); + } + + if (durationInSeconds <= 0) + { + throw new ArgumentException("Duration must be greater than zero.", nameof(durationInSeconds)); + } + + var sessionKeyParams = new SessionSpec() + { + Signer = signerAddress, + IsWildcard = grantFullPermissions, + ExpiresAt = Utils.GetUnixTimeStampNow() + durationInSeconds, + CallPolicies = callPolicies ?? new List(), + TransferPolicies = transferPolicies ?? new List(), + Uid = uid ?? Guid.NewGuid().ToByteArray(), + }; + + var userWalletAddress = await this.GetAddress(); + var sessionKeySig = await EIP712.GenerateSignature_SmartAccount_7702("MinimalAccount", "1", chainId, userWalletAddress, sessionKeyParams, this); + var userContract = await ThirdwebContract.Create(this.Client, userWalletAddress, chainId, Constants.MINIMAL_ACCOUNT_7702_ABI); + var sessionKeyCallData = userContract.CreateCallData("createSessionWithSig", sessionKeyParams, sessionKeySig.HexToBytes()); + return await this.ExecuteTransaction(new ThirdwebTransactionInput(chainId: chainId, to: userWalletAddress, value: 0, data: sessionKeyCallData)); + } + + /// + /// Checks if the signer has full permissions on the EIP7702 account. + /// + /// The chain ID of the EIP7702 account. + /// The address of the signer to check permissions for. + /// A task that represents the asynchronous operation. The task result contains a boolean indicating whether the signer has full permissions. + /// Thrown when the execution mode is not EIP7702 or EIP7702Sponsored. + /// Thrown when the signer address is null or empty. + public async Task SignerHasFullPermissions(BigInteger chainId, string signerAddress) + { + await this.Ensure7702(chainId, true); + + if (string.IsNullOrEmpty(signerAddress)) + { + throw new ArgumentException("Signer address cannot be null or empty.", nameof(signerAddress)); + } + + var userWalletAddress = await this.GetAddress(); + var userContract = await ThirdwebContract.Create(this.Client, userWalletAddress, chainId, Constants.MINIMAL_ACCOUNT_7702_ABI); + var isWildcard = await userContract.Read("isWildcardSigner", signerAddress); + return isWildcard; + } + + /// + /// Gets the call policies for a specific signer on the EIP7702 account. + /// + /// The chain ID of the EIP7702 account. + /// The address of the signer to get call policies for. + /// A task that represents the asynchronous operation. The task result contains a list of call policies for the signer. + /// Thrown when the execution mode is not EIP7702 or EIP7702Sponsored. + /// Thrown when the signer address is null or empty. + public async Task> GetCallPoliciesForSigner(BigInteger chainId, string signerAddress) + { + await this.Ensure7702(chainId, true); + + if (string.IsNullOrEmpty(signerAddress)) + { + throw new ArgumentException("Signer address cannot be null or empty.", nameof(signerAddress)); + } + + var userWalletAddress = await this.GetAddress(); + var userContract = await ThirdwebContract.Create(this.Client, userWalletAddress, chainId, Constants.MINIMAL_ACCOUNT_7702_ABI); + var callPolicies = await userContract.Read>("getCallPoliciesForSigner", signerAddress); + return callPolicies; + } + + /// + /// Gets the transfer policies for a specific signer on the EIP7702 account. + /// + /// The chain ID of the EIP7702 account. + /// The address of the signer to get transfer policies for. + /// A task that represents the asynchronous operation. The task result contains a list of transfer policies for the signer. + /// Thrown when the execution mode is not EIP7702 or EIP7702Sponsored. + /// Thrown when the signer address is null or empty. + public async Task> GetTransferPoliciesForSigner(BigInteger chainId, string signerAddress) + { + await this.Ensure7702(chainId, true); + + if (string.IsNullOrEmpty(signerAddress)) + { + throw new ArgumentException("Signer address cannot be null or empty.", nameof(signerAddress)); + } + + var userWalletAddress = await this.GetAddress(); + var userContract = await ThirdwebContract.Create(this.Client, userWalletAddress, chainId, Constants.MINIMAL_ACCOUNT_7702_ABI); + var transferPolicies = await userContract.Read>("getTransferPoliciesForSigner", signerAddress); + return transferPolicies; + } + + /// + /// Gets the session expiration timestamp for a specific signer on the EIP7702 account. + /// + /// The chain ID of the EIP7702 account. + /// The address of the signer to get session expiration for. + /// A task that represents the asynchronous operation. The task result contains the session expiration timestamp. + /// Thrown when the execution mode is not EIP7702 or EIP7702Sponsored. + /// Thrown when the signer address is null or empty. + public async Task GetSessionExpirationForSigner(BigInteger chainId, string signerAddress) + { + await this.Ensure7702(chainId, true); + + if (string.IsNullOrEmpty(signerAddress)) + { + throw new ArgumentException("Signer address cannot be null or empty.", nameof(signerAddress)); + } + + var userWalletAddress = await this.GetAddress(); + var userContract = await ThirdwebContract.Create(this.Client, userWalletAddress, chainId, Constants.MINIMAL_ACCOUNT_7702_ABI); + var expirationTimestamp = await userContract.Read("getSessionExpirationForSigner", signerAddress); + return expirationTimestamp; + } + + /// + /// Gets the complete session state for a specific signer on the EIP7702 account, including remaining limits and usage information. + /// + /// The chain ID of the EIP7702 account. + /// The address of the signer to get session state for. + /// A task that represents the asynchronous operation. The task result contains the session state with transfer value limits, call value limits, and call parameter limits. + /// Thrown when the execution mode is not EIP7702 or EIP7702Sponsored. + /// Thrown when the signer address is null or empty. + public async Task GetSessionStateForSigner(BigInteger chainId, string signerAddress) + { + await this.Ensure7702(chainId, true); + + if (string.IsNullOrEmpty(signerAddress)) + { + throw new ArgumentException("Signer address cannot be null or empty.", nameof(signerAddress)); + } + + var userWalletAddress = await this.GetAddress(); + var userContract = await ThirdwebContract.Create(this.Client, userWalletAddress, chainId, Constants.MINIMAL_ACCOUNT_7702_ABI); + var sessionState = await userContract.Read("getSessionStateForSigner", signerAddress); + return sessionState; + } + + #endregion + + #region Account Linking + + public async Task> UnlinkAccount(LinkedAccount accountToUnlink) + { + if (!await this.IsConnected().ConfigureAwait(false)) + { + throw new InvalidOperationException("Cannot unlink account with a wallet that is not connected. Please login to the wallet before unlinking other wallets."); + } + + var currentAccountToken = this.EmbeddedWallet.GetSessionData()?.AuthToken; + + var serverLinkedAccounts = await this.EmbeddedWallet.UnlinkAccountAsync(currentAccountToken, accountToUnlink).ConfigureAwait(false); + var linkedAccounts = new List(); + foreach (var linkedAccount in serverLinkedAccounts) + { + linkedAccounts.Add( + new LinkedAccount + { + Type = linkedAccount.Type, + Details = new LinkedAccount.LinkedAccountDetails + { + Email = linkedAccount.Details?.Email, + Address = linkedAccount.Details?.Address, + Phone = linkedAccount.Details?.Phone, + Id = linkedAccount.Details?.Id, + }, + } + ); + } + return linkedAccounts; + } + + public async Task> LinkAccount( + IThirdwebWallet walletToLink, + string otp = null, + bool? isMobile = null, + Action browserOpenAction = null, + string mobileRedirectScheme = "thirdweb://", + IThirdwebBrowser browser = null, + BigInteger? chainId = null, + string jwt = null, + string payload = null, + string defaultSessionIdOverride = null + ) + { + if (!await this.IsConnected().ConfigureAwait(false)) + { + throw new InvalidOperationException("Cannot link account with a wallet that is not connected. Please login to the wallet before linking other wallets."); + } + + if (walletToLink == null) + { + throw new ArgumentNullException(nameof(walletToLink), "Wallet to link cannot be null."); + } + + if (walletToLink is not EcosystemWallet ecosystemWallet) + { + throw new ArgumentException("Cannot link account with a non-EcosystemWallet wallet."); + } + + if (await ecosystemWallet.IsConnected().ConfigureAwait(false)) + { + throw new ArgumentException("Cannot link account with a wallet that is already created and connected."); + } + + Server.VerifyResult serverRes = null; + switch (ecosystemWallet.AuthProvider) + { + case "Email": + if (string.IsNullOrEmpty(ecosystemWallet.Email)) + { + throw new ArgumentException("Cannot link account with an email wallet that does not have an email address."); + } + serverRes = await ecosystemWallet.PreAuth_Otp(otp).ConfigureAwait(false); + break; + case "Phone": + if (string.IsNullOrEmpty(ecosystemWallet.PhoneNumber)) + { + throw new ArgumentException("Cannot link account with a phone wallet that does not have a phone number."); + } + serverRes = await ecosystemWallet.PreAuth_Otp(otp).ConfigureAwait(false); + break; + case "Siwe": + if (ecosystemWallet.SiweSigner == null || chainId == null) + { + throw new ArgumentException("Cannot link account with a Siwe wallet without a signer and chain ID."); + } + serverRes = await ecosystemWallet.PreAuth_Siwe(ecosystemWallet.SiweSigner, chainId.Value).ConfigureAwait(false); + break; + case "Backend": + if (string.IsNullOrEmpty(ecosystemWallet.WalletSecret)) + { + throw new ArgumentException("Cannot link account with a Backend wallet without a wallet secret."); + } + serverRes = await ecosystemWallet.PreAuth_Backend(ecosystemWallet.WalletSecret).ConfigureAwait(false); + break; + case "JWT": + if (string.IsNullOrEmpty(jwt)) + { + throw new ArgumentException("Cannot link account with a JWT wallet without a JWT."); + } + serverRes = await ecosystemWallet.PreAuth_JWT(jwt).ConfigureAwait(false); + break; + case "AuthEndpoint": + if (string.IsNullOrEmpty(payload)) + { + throw new ArgumentException("Cannot link account with an AuthEndpoint wallet without a payload."); + } + serverRes = await ecosystemWallet.PreAuth_AuthEndpoint(payload).ConfigureAwait(false); + break; + case "Guest": + serverRes = await ecosystemWallet.PreAuth_Guest(defaultSessionIdOverride).ConfigureAwait(false); + break; + case "Google": + case "Apple": + case "Facebook": + case "Discord": + case "Farcaster": + case "Telegram": + case "Line": + case "X": + case "TikTok": + case "Epic": + case "Coinbase": + case "Github": + case "Twitch": + case "Steam": + serverRes = await ecosystemWallet.PreAuth_OAuth(isMobile ?? false, browserOpenAction, mobileRedirectScheme, browser).ConfigureAwait(false); + break; + default: + throw new ArgumentException($"Cannot link account with an unsupported authentication provider:", ecosystemWallet.AuthProvider); + } + + var currentAccountToken = this.EmbeddedWallet.GetSessionData()?.AuthToken; + var authTokenToConnect = serverRes.AuthToken; + + var serverLinkedAccounts = await this.EmbeddedWallet.LinkAccountAsync(currentAccountToken, authTokenToConnect).ConfigureAwait(false); + var linkedAccounts = new List(); + foreach (var linkedAccount in serverLinkedAccounts) + { + linkedAccounts.Add( + new LinkedAccount + { + Type = linkedAccount.Type, + Details = new LinkedAccount.LinkedAccountDetails + { + Email = linkedAccount.Details?.Email, + Address = linkedAccount.Details?.Address, + Phone = linkedAccount.Details?.Phone, + Id = linkedAccount.Details?.Id, + }, + } + ); + } + return linkedAccounts; + } + + public async Task> GetLinkedAccounts() + { + var currentAccountToken = this.EmbeddedWallet.GetSessionData()?.AuthToken; + var serverLinkedAccounts = await this.EmbeddedWallet.GetLinkedAccountsAsync(currentAccountToken).ConfigureAwait(false); + var linkedAccounts = new List(); + foreach (var linkedAccount in serverLinkedAccounts) + { + linkedAccounts.Add( + new LinkedAccount + { + Type = linkedAccount.Type, + Details = new LinkedAccount.LinkedAccountDetails + { + Email = linkedAccount.Details?.Email, + Address = linkedAccount.Details?.Address, + Phone = linkedAccount.Details?.Phone, + Id = linkedAccount.Details?.Id, + }, + } + ); + } + return linkedAccounts; + } + + #endregion + + #region OTP Auth + + public async Task SendOTP() + { + if (string.IsNullOrEmpty(this.Email) && string.IsNullOrEmpty(this.PhoneNumber)) + { + throw new Exception("Email or Phone Number is required for OTP login"); + } + + try + { + if (this.Email == null) + { + await this.EmbeddedWallet.SendPhoneOtpAsync(this.PhoneNumber).ConfigureAwait(false); + } + else + { + await this.EmbeddedWallet.SendEmailOtpAsync(this.Email).ConfigureAwait(false); + } + } + catch (Exception e) + { + throw new Exception("Failed to send OTP", e); + } + } + + private async Task PreAuth_Otp(string otp) + { + if (string.IsNullOrEmpty(otp)) + { + throw new ArgumentNullException(nameof(otp), "OTP cannot be null or empty."); + } + + var serverRes = + string.IsNullOrEmpty(this.Email) && string.IsNullOrEmpty(this.PhoneNumber) ? throw new Exception("Email or Phone Number is required for OTP login") + : this.Email == null ? await this.EmbeddedWallet.VerifyPhoneOtpAsync(this.PhoneNumber, otp).ConfigureAwait(false) + : await this.EmbeddedWallet.VerifyEmailOtpAsync(this.Email, otp).ConfigureAwait(false); + + return serverRes; + } + + public async Task LoginWithOtp(string otp) + { + var serverRes = await this.PreAuth_Otp(otp).ConfigureAwait(false); + return await this.PostAuth(serverRes).ConfigureAwait(false); + } + + #endregion + + #region OAuth + + private async Task PreAuth_OAuth( + bool isMobile, + Action browserOpenAction, + string mobileRedirectScheme = "thirdweb://", + IThirdwebBrowser browser = null, + CancellationToken cancellationToken = default + ) + { + if (isMobile && string.IsNullOrEmpty(mobileRedirectScheme)) + { + throw new ArgumentNullException(nameof(mobileRedirectScheme), "Mobile redirect scheme cannot be null or empty on this platform."); + } + + var platform = this.HttpClient?.Headers?["x-sdk-name"] == "UnitySDK_WebGL" ? "web" : "dotnet"; + var redirectUrl = isMobile ? mobileRedirectScheme : "http://localhost:8789/"; + var loginUrl = await this.EmbeddedWallet.FetchHeadlessOauthLoginLinkAsync(this.AuthProvider, platform).ConfigureAwait(false); + loginUrl = platform == "web" ? loginUrl : $"{loginUrl}&redirectUrl={redirectUrl}&developerClientId={this.Client.ClientId}&authOption={this.AuthProvider.ToLower()}"; + if (!string.IsNullOrEmpty(this._ecosystemId)) + { + loginUrl = $"{loginUrl}&ecosystemId={this._ecosystemId}"; + if (!string.IsNullOrEmpty(this._ecosystemPartnerId)) + { + loginUrl = $"{loginUrl}&ecosystemPartnerId={this._ecosystemPartnerId}"; + } + } + + browser ??= new InAppWalletBrowser(); + var browserResult = await browser.Login(this.Client, loginUrl, redirectUrl, browserOpenAction, cancellationToken).ConfigureAwait(false); + switch (browserResult.Status) + { + case BrowserStatus.Success: + break; + case BrowserStatus.UserCanceled: + throw new TaskCanceledException(browserResult.Error ?? "LoginWithOauth was cancelled."); + case BrowserStatus.Timeout: + throw new TimeoutException(browserResult.Error ?? "LoginWithOauth timed out."); + case BrowserStatus.UnknownError: + default: + throw new Exception($"Failed to login with {this.AuthProvider}: {browserResult.Status} | {browserResult.Error}"); + } + var callbackUrl = + browserResult.Status != BrowserStatus.Success + ? throw new Exception($"Failed to login with {this.AuthProvider}: {browserResult.Status} | {browserResult.Error}") + : browserResult.CallbackUrl; + + while (string.IsNullOrEmpty(callbackUrl)) + { + if (cancellationToken.IsCancellationRequested) + { + throw new TaskCanceledException("LoginWithOauth was cancelled."); + } + await ThirdwebTask.Delay(100, cancellationToken).ConfigureAwait(false); + } + + var authResultJson = callbackUrl; + if (!authResultJson.StartsWith('{')) + { + var decodedUrl = HttpUtility.UrlDecode(callbackUrl); + Uri uri = new(decodedUrl); + var queryString = uri.Query; + var queryDict = HttpUtility.ParseQueryString(queryString); + authResultJson = queryDict["authResult"]; + } + + var serverRes = this.EmbeddedWallet.SignInWithOauthAsync(authResultJson); + return serverRes; + } + + public async Task LoginWithOauth( + bool isMobile, + Action browserOpenAction, + string mobileRedirectScheme = "thirdweb://", + IThirdwebBrowser browser = null, + CancellationToken cancellationToken = default + ) + { + var serverRes = await this.PreAuth_OAuth(isMobile, browserOpenAction, mobileRedirectScheme, browser, cancellationToken).ConfigureAwait(false); + return await this.PostAuth(serverRes).ConfigureAwait(false); + } + + #endregion + + #region Siwe + + private async Task PreAuth_Siwe(IThirdwebWallet siweSigner, BigInteger chainId) + { + if (siweSigner == null) + { + throw new ArgumentNullException(nameof(siweSigner), "SIWE Signer wallet cannot be null."); + } + + if (!await siweSigner.IsConnected().ConfigureAwait(false)) + { + throw new InvalidOperationException("SIWE Signer wallet must be connected as this operation requires it to sign a message."); + } + + var serverRes = + chainId <= 0 ? throw new ArgumentException("Chain ID must be greater than 0.", nameof(chainId)) : await this.EmbeddedWallet.SignInWithSiweAsync(siweSigner, chainId).ConfigureAwait(false); + + return serverRes; + } + + public async Task LoginWithSiwe(BigInteger chainId) + { + var serverRes = await this.PreAuth_Siwe(this.SiweSigner, chainId).ConfigureAwait(false); + return await this.PostAuth(serverRes).ConfigureAwait(false); + } + + #endregion + + #region Backend + + private async Task PreAuth_Backend(string walletSecret) + { + return string.IsNullOrEmpty(walletSecret) + ? throw new ArgumentException("Wallet secret cannot be null or empty.", nameof(walletSecret)) + : await this.EmbeddedWallet.SignInWithBackendAsync(walletSecret).ConfigureAwait(false); + } + + public async Task LoginWithBackend() + { + var serverRes = await this.PreAuth_Backend(this.WalletSecret).ConfigureAwait(false); + return await this.PostAuth(serverRes).ConfigureAwait(false); + } + + #endregion + + #region Guest + + private async Task PreAuth_Guest(string defaultSessionIdOverride = null) + { + var sessionData = this.EmbeddedWallet.GetSessionData(); + string sessionId; + if (sessionData != null && sessionData.AuthProvider == "Guest" && !string.IsNullOrEmpty(sessionData.AuthIdentifier)) + { + sessionId = sessionData.AuthIdentifier; + } + else + { + sessionId = defaultSessionIdOverride ?? Guid.NewGuid().ToString(); + } + var serverRes = await this.EmbeddedWallet.SignInWithGuestAsync(sessionId).ConfigureAwait(false); + return serverRes; + } + + public async Task LoginWithGuest(string defaultSessionIdOverride = null) + { + var serverRes = await this.PreAuth_Guest(defaultSessionIdOverride).ConfigureAwait(false); + return await this.PostAuth(serverRes).ConfigureAwait(false); + } + + #endregion + + #region JWT + + private async Task PreAuth_JWT(string jwt) + { + return string.IsNullOrEmpty(jwt) ? throw new ArgumentException("JWT cannot be null or empty.", nameof(jwt)) : await this.EmbeddedWallet.SignInWithJwtAsync(jwt).ConfigureAwait(false); + } + + public async Task LoginWithJWT(string jwt) + { + var serverRes = await this.PreAuth_JWT(jwt).ConfigureAwait(false); + return await this.PostAuth(serverRes).ConfigureAwait(false); + } + + #endregion + + #region AuthEndpoint + + private async Task PreAuth_AuthEndpoint(string payload) + { + var serverRes = string.IsNullOrEmpty(payload) + ? throw new ArgumentNullException(nameof(payload), "Payload cannot be null or empty.") + : await this.EmbeddedWallet.SignInWithAuthEndpointAsync(payload).ConfigureAwait(false); + + return serverRes; + } + + public async Task LoginWithAuthEndpoint(string payload) + { + var serverRes = await this.PreAuth_AuthEndpoint(payload).ConfigureAwait(false); + return await this.PostAuth(serverRes).ConfigureAwait(false); + } + + #endregion + + #region IThirdwebWallet + + public Task GetAddress() + { + if (!string.IsNullOrEmpty(this.Address)) + { + return Task.FromResult(this.Address.ToChecksumAddress()); + } + else + { + return Task.FromResult(this.Address); + } + } + + public async Task PersonalSign(byte[] rawMessage) + { + if (rawMessage == null) + { + throw new ArgumentNullException(nameof(rawMessage), "Message to sign cannot be null."); + } + + var url = $"{ENCLAVE_PATH}/sign-message"; + var payload = new { messagePayload = new { message = rawMessage.BytesToHex(), isRaw = true } }; + + var requestContent = new StringContent(JsonConvert.SerializeObject(payload), Encoding.UTF8, "application/json"); + + var response = await this.HttpClient.PostAsync(url, requestContent).ConfigureAwait(false); + _ = response.EnsureSuccessStatusCode(); + + var content = await response.Content.ReadAsStringAsync().ConfigureAwait(false); + var res = JsonConvert.DeserializeObject(content); + return res.Signature; + } + + public async Task PersonalSign(string message) + { + if (string.IsNullOrEmpty(message)) + { + throw new ArgumentNullException(nameof(message), "Message to sign cannot be null."); + } + + var url = $"{ENCLAVE_PATH}/sign-message"; + var payload = new { messagePayload = new { message, isRaw = false } }; + + var requestContent = new StringContent(JsonConvert.SerializeObject(payload), Encoding.UTF8, "application/json"); + + var response = await this.HttpClient.PostAsync(url, requestContent).ConfigureAwait(false); + _ = response.EnsureSuccessStatusCode(); + + var content = await response.Content.ReadAsStringAsync().ConfigureAwait(false); + var res = JsonConvert.DeserializeObject(content); + return res.Signature; + } + + public async Task SignTypedDataV4(string json) + { + if (string.IsNullOrEmpty(json)) + { + throw new ArgumentNullException(nameof(json), "Json to sign cannot be null."); + } + + var processedJson = Utils.PreprocessTypedDataJson(json); + + var url = $"{ENCLAVE_PATH}/sign-typed-data"; + + var requestContent = new StringContent(processedJson, Encoding.UTF8, "application/json"); + + var response = await this.HttpClient.PostAsync(url, requestContent).ConfigureAwait(false); + _ = response.EnsureSuccessStatusCode(); + + var content = await response.Content.ReadAsStringAsync().ConfigureAwait(false); + var res = JsonConvert.DeserializeObject(content); + return res.Signature; + } + + public async Task SignTypedDataV4(T data, TypedData typedData) + where TDomain : IDomain + { + if (data == null) + { + throw new ArgumentNullException(nameof(data), "Data to sign cannot be null."); + } + + var safeJson = Utils.ToJsonExternalWalletFriendly(typedData, data); + return await this.SignTypedDataV4(safeJson).ConfigureAwait(false); + } + + public async Task SignTransaction(ThirdwebTransactionInput transaction) + { + if (transaction == null) + { + throw new ArgumentNullException(nameof(transaction)); + } + + if (transaction.Nonce == null || transaction.Gas == null || transaction.To == null) + { + throw new ArgumentException("Nonce, Gas, and To fields are required for transaction signing."); + } + + if (transaction.GasPrice == null && (transaction.MaxFeePerGas == null || transaction.MaxPriorityFeePerGas == null)) + { + throw new ArgumentException("GasPrice or MaxFeePerGas and MaxPriorityFeePerGas are required for transaction signing."); + } + + object payload = new + { + transactionPayload = new + { + nonce = transaction.Nonce, + from = transaction.From, + to = transaction.To, + gas = transaction.Gas, + gasPrice = transaction.GasPrice, + value = transaction.Value, + data = transaction.Data, + maxFeePerGas = transaction.MaxFeePerGas, + maxPriorityFeePerGas = transaction.MaxPriorityFeePerGas, + chainId = transaction.ChainId, + authorizationList = transaction.AuthorizationList != null && transaction.AuthorizationList.Count > 0 + ? transaction + .AuthorizationList.Select(authorization => new + { + chainId = authorization.ChainId.HexToNumber(), + address = authorization.Address, + nonce = authorization.Nonce.HexToNumber().ToString(), + yParity = authorization.YParity.HexToNumber(), + r = authorization.R.HexToNumber().ToString(), + s = authorization.S.HexToNumber().ToString(), + }) + .ToArray() + : null, + }, + }; + + var url = $"{ENCLAVE_PATH}/sign-transaction"; + + var requestContent = new StringContent(JsonConvert.SerializeObject(payload), Encoding.UTF8, "application/json"); + + var response = await this.HttpClient.PostAsync(url, requestContent).ConfigureAwait(false); + _ = response.EnsureSuccessStatusCode(); + + var content = await response.Content.ReadAsStringAsync().ConfigureAwait(false); + var res = JsonConvert.DeserializeObject(content); + return res.Signature; + } + + public Task IsConnected() + { + return Task.FromResult(this.Address != null); + } + + public async Task SendTransaction(ThirdwebTransactionInput transaction) + { + var userWalletAddress = await this.GetAddress(); + var userContract = await ThirdwebContract.Create(this.Client, userWalletAddress, transaction.ChainId, Constants.MINIMAL_ACCOUNT_7702_ABI); + var needsDelegation = !await Utils.IsDelegatedAccount(this.Client, transaction.ChainId, userWalletAddress, this.DelegationContractAddress); + EIP7702Authorization? authorization = needsDelegation + ? await this.SignAuthorization(transaction.ChainId, this.DelegationContractAddress, willSelfExecute: this.ExecutionMode != ExecutionMode.EIP7702Sponsored) + : null; + + var calls = new List + { + new() + { + Target = transaction.To, + Value = transaction.Value?.Value ?? BigInteger.Zero, + Data = transaction.Data.HexToBytes(), + }, + }; + + switch (this.ExecutionMode) + { + case ExecutionMode.EOA: + throw new NotImplementedException( + "SendTransaction is not supported for Ecosystem Wallets in EOA execution mode, please use the unified Contract or ThirdwebTransaction APIs or change to EIP7702 execution mode." + ); + case ExecutionMode.EIP7702: + BigInteger totalValue = 0; + foreach (var call in calls) + { + totalValue += call.Value; + } + var finalTx = await userContract.Prepare(wallet: this, method: "execute", weiValue: totalValue, parameters: new object[] { calls }); + finalTx.Input.AuthorizationList = authorization != null ? new List() { authorization.Value } : null; + finalTx = await ThirdwebTransaction.Prepare(finalTx); + var signedTx = await this.SignTransaction(finalTx.Input); + var rpc = ThirdwebRPC.GetRpcInstance(this.Client, transaction.ChainId); + return await rpc.SendRequestAsync("eth_sendRawTransaction", signedTx).ConfigureAwait(false); + case ExecutionMode.EIP7702Sponsored: + var wrappedCalls = new WrappedCalls() { Calls = calls, Uid = Guid.NewGuid().ToByteArray().PadTo32Bytes() }; + var signature = await EIP712.GenerateSignature_SmartAccount_7702_WrappedCalls("MinimalAccount", "1", transaction.ChainId, userWalletAddress, wrappedCalls, this); + var response = await ThirdwebBundler.TwExecute( + client: this.Client, + url: $"https://{transaction.ChainId}.bundler.thirdweb.com", + requestId: 7702, + eoaAddress: userWalletAddress, + wrappedCalls: wrappedCalls, + signature: signature, + authorization: authorization != null && !await Utils.IsDelegatedAccount(this.Client, transaction.ChainId, userWalletAddress, this.DelegationContractAddress) ? authorization : null + ); + var queueId = response?.QueueId; + string txHash = null; + var ct = new CancellationTokenSource(this.Client.FetchTimeoutOptions.GetTimeout(TimeoutType.Other)); + try + { + while (txHash == null) + { + ct.Token.ThrowIfCancellationRequested(); + + var hashResponse = await ThirdwebBundler + .TwGetTransactionHash(client: this.Client, url: $"https://{transaction.ChainId}.bundler.thirdweb.com", requestId: 7702, queueId) + .ConfigureAwait(false); + + txHash = hashResponse?.TransactionHash; + await ThirdwebTask.Delay(100, ct.Token).ConfigureAwait(false); + } + return txHash; + } + catch (OperationCanceledException) + { + throw new Exception($"EIP-7702 sponsored transaction timed out with queue id: {queueId}"); + } + default: + throw new ArgumentOutOfRangeException(nameof(this.ExecutionMode), "Invalid execution mode."); + } + } + + public async Task ExecuteTransaction(ThirdwebTransactionInput transactionInput) + { + var hash = await this.SendTransaction(transactionInput); + return await Utils.WaitForTransactionReceipt(this.Client, transactionInput.ChainId, hash); + } + + public async Task Disconnect() + { + this.Address = null; + await this.EmbeddedWallet.SignOutAsync().ConfigureAwait(false); + } + + public async Task SignAuthorization(BigInteger chainId, string contractAddress, bool willSelfExecute) + { + var nonce = await this.GetTransactionCount(chainId); + + if (willSelfExecute) + { + nonce++; + } + + var url = $"{ENCLAVE_PATH}/sign-authorization"; + + var payload = new + { + address = contractAddress, + chainId, + nonce, + }; + + var requestContent = new StringContent(JsonConvert.SerializeObject(payload), Encoding.UTF8, "application/json"); + + var response = await this.HttpClient.PostAsync(url, requestContent).ConfigureAwait(false); + _ = response.EnsureSuccessStatusCode(); + + var content = await response.Content.ReadAsStringAsync().ConfigureAwait(false); + var signResponseObj = JObject.Parse(content); + + return new EIP7702Authorization( + chainId: BigInteger.Parse(signResponseObj["chainId"].ToString()), + address: signResponseObj["address"].ToString(), + nonce: BigInteger.Parse(signResponseObj["nonce"].ToString()), + yParity: BigInteger.Parse(signResponseObj["yParity"].ToString()).NumberToHex().HexToBytes(), + r: BigInteger.Parse(signResponseObj["r"].ToString()).NumberToHex().HexToBytes(), + s: BigInteger.Parse(signResponseObj["s"].ToString()).NumberToHex().HexToBytes() + ); + } + + public Task SwitchNetwork(BigInteger chainId) + { + return Task.CompletedTask; + } + + #endregion + + private async Task Ensure7702(BigInteger chainId, bool ensureDelegated) + { + if (this.ExecutionMode is not ExecutionMode.EIP7702 and not ExecutionMode.EIP7702Sponsored) + { + throw new InvalidOperationException("This operation is only supported for EIP7702 and EIP7702Sponsored execution modes."); + } + + if (!await Utils.IsDelegatedAccount(this.Client, chainId, this.Address, this.DelegationContractAddress).ConfigureAwait(false)) + { + if (ensureDelegated) + { + throw new InvalidOperationException("This operation requires a delegated account. Please ensure you have transacted at least once with the account to set up delegation."); + } + } + } +} diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Authentication/AWS.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Authentication/AWS.cs deleted file mode 100644 index 853fbc6c..00000000 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Authentication/AWS.cs +++ /dev/null @@ -1,311 +0,0 @@ -using System.Security.Cryptography; -using System.Text; -using Newtonsoft.Json; - -namespace Thirdweb.EWS -{ - internal class AWS - { - private const string awsRegion = "us-west-2"; - private const string cognitoAppClientId = "2e02ha2ce6du13ldk8pai4h3d0"; - private static readonly string cognitoIdentityPoolId = $"{awsRegion}:2ad7ab1e-f48b-48a6-adfa-ac1090689c26"; - private static readonly string cognitoUserPoolId = $"{awsRegion}_UFwLcZIpq"; - private static readonly string recoverySharePasswordLambdaFunctionName = $"arn:aws:lambda:{awsRegion}:324457261097:function:recovery-share-password-GenerateRecoverySharePassw-bbE5ZbVAToil"; - - internal static async Task SignUpCognitoUserAsync(string emailAddress, string userName, Type thirdwebHttpClientType) - { - emailAddress ??= "cognito@thirdweb.com"; - - var client = thirdwebHttpClientType.GetConstructor(Type.EmptyTypes).Invoke(null) as IThirdwebHttpClient; - var endpoint = $"https://cognito-idp.{awsRegion}.amazonaws.com/"; - var payload = new - { - ClientId = cognitoAppClientId, - Username = userName, - Password = Secrets.Random(12), - UserAttributes = new[] { new { Name = "email", Value = emailAddress } } - }; - - var content = new StringContent(JsonConvert.SerializeObject(payload), Encoding.UTF8, "application/x-amz-json-1.1"); - - client.AddHeader("X-Amz-Target", "AWSCognitoIdentityProviderService.SignUp"); - - var response = await client.PostAsync(endpoint, content).ConfigureAwait(false); - - if (!response.IsSuccessStatusCode) - { - var responseBody = await response.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new Exception($"Sign-up failed: {responseBody}"); - } - } - - internal static async Task StartCognitoUserAuth(string userName, Type thirdwebHttpClientType) - { - var client = thirdwebHttpClientType.GetConstructor(Type.EmptyTypes).Invoke(null) as IThirdwebHttpClient; - var endpoint = $"https://cognito-idp.{awsRegion}.amazonaws.com/"; - var payload = new - { - AuthFlow = "CUSTOM_AUTH", - ClientId = cognitoAppClientId, - AuthParameters = new Dictionary { { "USERNAME", userName } }, - ClientMetadata = new Dictionary() - }; - - var content = new StringContent(JsonConvert.SerializeObject(payload), Encoding.UTF8, "application/x-amz-json-1.1"); - - client.AddHeader("X-Amz-Target", "AWSCognitoIdentityProviderService.InitiateAuth"); - - var response = await client.PostAsync(endpoint, content).ConfigureAwait(false); - - var responseContent = await response.Content.ReadAsStringAsync().ConfigureAwait(false); - - if (!response.IsSuccessStatusCode) - { - var errorResponse = JsonConvert.DeserializeObject(responseContent); - if (errorResponse.Type == "UserNotFoundException") - { - return null; - } - throw new Exception($"Authentication initiation failed: {responseContent}"); - } - - var jsonResponse = JsonConvert.DeserializeObject(responseContent); - return jsonResponse.Session; - } - - internal static async Task FinishCognitoUserAuth(string userName, string otp, string sessionId, Type thirdwebHttpClientType) - { - var client = thirdwebHttpClientType.GetConstructor(Type.EmptyTypes).Invoke(null) as IThirdwebHttpClient; - var endpoint = $"https://cognito-idp.{awsRegion}.amazonaws.com/"; - var payload = new - { - ChallengeName = "CUSTOM_CHALLENGE", - ClientId = cognitoAppClientId, - ChallengeResponses = new Dictionary { { "USERNAME", userName }, { "ANSWER", otp } }, - Session = sessionId - }; - - var content = new StringContent(JsonConvert.SerializeObject(payload), Encoding.UTF8, "application/x-amz-json-1.1"); - - client.AddHeader("X-Amz-Target", "AWSCognitoIdentityProviderService.RespondToAuthChallenge"); - - var response = await client.PostAsync(endpoint, content).ConfigureAwait(false); - - var responseContent = await response.Content.ReadAsStringAsync().ConfigureAwait(false); - - if (!response.IsSuccessStatusCode) - { - var errorResponse = JsonConvert.DeserializeObject(responseContent); - if (errorResponse.Type == "NotAuthorizedException") - { - throw new VerificationException("The session expired", false); - } - if (errorResponse.Type == "UserNotFoundException") - { - throw new InvalidOperationException("The user was not found"); - } - throw new Exception($"Challenge response failed: {responseContent}"); - } - - var jsonResponse = JsonConvert.DeserializeObject(responseContent); - var result = jsonResponse.AuthenticationResult ?? throw new VerificationException("The OTP is incorrect", true); - return new TokenCollection(result.AccessToken.ToString(), result.IdToken.ToString(), result.RefreshToken.ToString()); - } - - internal static async Task InvokeRecoverySharePasswordLambdaAsync(string idToken, string invokePayload, Type thirdwebHttpClientType) - { - var credentials = await GetTemporaryCredentialsAsync(idToken, thirdwebHttpClientType).ConfigureAwait(false); - return await InvokeLambdaWithTemporaryCredentialsAsync(credentials, invokePayload, thirdwebHttpClientType).ConfigureAwait(false); - } - - private static async Task GetTemporaryCredentialsAsync(string idToken, Type thirdwebHttpClientType) - { - var client = thirdwebHttpClientType.GetConstructor(Type.EmptyTypes).Invoke(null) as IThirdwebHttpClient; - var endpoint = $"https://cognito-identity.{awsRegion}.amazonaws.com/"; - - var payloadForGetId = new { IdentityPoolId = cognitoIdentityPoolId, Logins = new Dictionary { { $"cognito-idp.{awsRegion}.amazonaws.com/{cognitoUserPoolId}", idToken } } }; - - var content = new StringContent(JsonConvert.SerializeObject(payloadForGetId), Encoding.UTF8, "application/x-amz-json-1.1"); - - client.AddHeader("X-Amz-Target", "AWSCognitoIdentityService.GetId"); - - var response = await client.PostAsync(endpoint, content).ConfigureAwait(false); - - var responseContent = await response.Content.ReadAsStringAsync().ConfigureAwait(false); - - if (!response.IsSuccessStatusCode) - { - throw new Exception($"Failed to get identity ID: {responseContent}"); - } - - var identityIdResponse = JsonConvert.DeserializeObject(responseContent); - - var payloadForGetCredentials = new - { - IdentityId = identityIdResponse.IdentityId, - Logins = new Dictionary { { $"cognito-idp.{awsRegion}.amazonaws.com/{cognitoUserPoolId}", idToken } } - }; - - content = new StringContent(JsonConvert.SerializeObject(payloadForGetCredentials), Encoding.UTF8, "application/x-amz-json-1.1"); - - client.RemoveHeader("X-Amz-Target"); - client.AddHeader("X-Amz-Target", "AWSCognitoIdentityService.GetCredentialsForIdentity"); - - response = await client.PostAsync(endpoint, content).ConfigureAwait(false); - - responseContent = await response.Content.ReadAsStringAsync().ConfigureAwait(false); - - if (!response.IsSuccessStatusCode) - { - throw new Exception($"Failed to get credentials: {responseContent}"); - } - - var credentialsResponse = JsonConvert.DeserializeObject(responseContent); - - return new AwsCredentials - { - AccessKeyId = credentialsResponse.Credentials.AccessKeyId, - SecretAccessKey = credentialsResponse.Credentials.SecretKey, - SessionToken = credentialsResponse.Credentials.SessionToken - }; - } - - private static async Task InvokeLambdaWithTemporaryCredentialsAsync(AwsCredentials credentials, string invokePayload, Type thirdwebHttpClientType) - { - var endpoint = $"https://lambda.{awsRegion}.amazonaws.com/2015-03-31/functions/{recoverySharePasswordLambdaFunctionName}/invocations"; - var requestBody = new StringContent(invokePayload, Encoding.UTF8, "application/json"); - - var client = thirdwebHttpClientType.GetConstructor(Type.EmptyTypes).Invoke(null) as IThirdwebHttpClient; - - var dateTimeNow = DateTime.UtcNow; - var dateStamp = dateTimeNow.ToString("yyyyMMdd"); - var amzDate = dateTimeNow.ToString("yyyyMMddTHHmmssZ"); - - var canonicalUri = "/2015-03-31/functions/" + Uri.EscapeDataString(recoverySharePasswordLambdaFunctionName) + "/invocations"; - var canonicalQueryString = ""; - var canonicalHeaders = $"host:lambda.{awsRegion}.amazonaws.com\nx-amz-date:{amzDate}\n"; - var signedHeaders = "host;x-amz-date"; - - using var sha256 = SHA256.Create(); - var payloadHash = ToHexString(sha256.ComputeHash(Encoding.UTF8.GetBytes(invokePayload))); - var canonicalRequest = $"POST\n{canonicalUri}\n{canonicalQueryString}\n{canonicalHeaders}\n{signedHeaders}\n{payloadHash}"; - - var algorithm = "AWS4-HMAC-SHA256"; - var credentialScope = $"{dateStamp}/{awsRegion}/lambda/aws4_request"; - var stringToSign = $"{algorithm}\n{amzDate}\n{credentialScope}\n{ToHexString(sha256.ComputeHash(Encoding.UTF8.GetBytes(canonicalRequest)))}"; - - var signingKey = GetSignatureKey(credentials.SecretAccessKey, dateStamp, awsRegion, "lambda"); - var signature = ToHexString(HMACSHA256(signingKey, stringToSign)); - - var authorizationHeader = $"{algorithm} Credential={credentials.AccessKeyId}/{credentialScope}, SignedHeaders={signedHeaders}, Signature={signature}"; - - client.AddHeader("x-amz-date", amzDate); - client.AddHeader("Authorization", authorizationHeader); - client.AddHeader("x-amz-security-token", credentials.SessionToken); - - var response = await client.PostAsync(endpoint, requestBody).ConfigureAwait(false); - - var responseContent = await response.Content.ReadAsStringAsync().ConfigureAwait(false); - - if (!response.IsSuccessStatusCode) - { - throw new Exception($"Lambda invocation failed: {responseContent}"); - } - - var memoryStream = new MemoryStream(Encoding.UTF8.GetBytes(responseContent)); - return memoryStream; - } - - private static byte[] HMACSHA256(byte[] key, string data) - { - using var hmac = new HMACSHA256(key); - return hmac.ComputeHash(Encoding.UTF8.GetBytes(data)); - } - - private static byte[] GetSignatureKey(string key, string dateStamp, string regionName, string serviceName) - { - var kDate = HMACSHA256(Encoding.UTF8.GetBytes("AWS4" + key), dateStamp); - var kRegion = HMACSHA256(kDate, regionName); - var kService = HMACSHA256(kRegion, serviceName); - var kSigning = HMACSHA256(kService, "aws4_request"); - return kSigning; - } - - private static string ToHexString(byte[] bytes) - { - var hex = new StringBuilder(bytes.Length * 2); - foreach (var b in bytes) - { - hex.AppendFormat("{0:x2}", b); - } - return hex.ToString(); - } - - internal class GetIdResponse - { - public string IdentityId { get; set; } - } - - internal class GetCredentialsForIdentityResponse - { - public Credentials Credentials { get; set; } - } - - internal class Credentials - { - public string AccessKeyId { get; set; } - public string SecretKey { get; set; } - public string SessionToken { get; set; } - } - - internal class AwsCredentials - { - public string AccessKeyId { get; set; } - public string SecretAccessKey { get; set; } - public string SessionToken { get; set; } - } - - internal class CredentialsResponse - { - public Credentials Credentials { get; set; } - } - - internal class StartAuthResponse - { - public string Session { get; set; } - } - - internal class FinishAuthResponse - { - public AuthenticationResult AuthenticationResult { get; set; } - } - - internal class AuthenticationResult - { - public string AccessToken { get; set; } - public string IdToken { get; set; } - public string RefreshToken { get; set; } - } - - internal class ErrorResponse - { - [JsonProperty("__type")] - public string Type { get; set; } - public string Message { get; set; } - } - - internal class TokenCollection - { - internal TokenCollection(string accessToken, string idToken, string refreshToken) - { - AccessToken = accessToken; - IdToken = idToken; - RefreshToken = refreshToken; - } - - public string AccessToken { get; } - public string IdToken { get; } - public string RefreshToken { get; } - } - } -} diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Authentication/Server.Types.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Authentication/Server.Types.cs deleted file mode 100644 index 3f4f39b3..00000000 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Authentication/Server.Types.cs +++ /dev/null @@ -1,293 +0,0 @@ -using System.Linq; -using System.Runtime.Serialization; - -namespace Thirdweb.EWS -{ - internal partial class Server - { - internal class VerifyResult - { - internal VerifyResult(bool isNewUser, string authToken, string walletUserId, string recoveryCode, string email) - { - IsNewUser = isNewUser; - AuthToken = authToken; - WalletUserId = walletUserId; - RecoveryCode = recoveryCode; - Email = email; - } - - internal bool IsNewUser { get; } - internal string AuthToken { get; } - internal string WalletUserId { get; } - internal string RecoveryCode { get; } - internal string Email { get; } - } - -#pragma warning disable CS0169, CS8618, IDE0051 // Deserialization will construct the following classes. - [DataContract] - private class AuthVerifiedTokenReturnType - { - [DataMember(Name = "verifiedToken")] - internal VerifiedTokenType VerifiedToken { get; set; } - - [DataMember(Name = "verifiedTokenJwtString")] - internal string VerifiedTokenJwtString { get; set; } - - [DataContract] - internal class VerifiedTokenType - { - [DataMember(Name = "authDetails")] - internal UserAuthDetails AuthDetails { get; set; } - - [DataMember] - private string authProvider; - - [DataMember] - private string developerClientId; - - [DataMember(Name = "isNewUser")] - internal bool IsNewUser { get; set; } - - [DataMember] - private string rawToken; - - [DataMember] - private string userId; - } - } - - [DataContract] - private class GetUserStatusApiReturnType - { - [DataMember] -#pragma warning disable CS0649 // Deserialization will populate this field. - private string status; -#pragma warning restore CS0649 // Field 'Server.GetUserStatusApiReturnType.status' is never assigned to, and will always have its default value null - internal UserStatus Status => (UserStatus)status.Length; - - [DataMember] - private StoredTokenType storedToken; - - [DataMember(Name = "user")] - internal UserType User { get; set; } - - [DataContract] - internal class UserType - { - [DataMember(Name = "authDetails")] - internal UserAuthDetails AuthDetails { get; set; } - - [DataMember] - private string walletAddress; - } - } - - [DataContract] - private class HttpErrorWithMessage - { - [DataMember(Name = "error")] - internal string Error { get; set; } = ""; - - [DataMember(Name = "message")] - internal string Message { get; set; } = ""; - } - - [DataContract] - private class SharesGetResponse - { - [DataMember(Name = "authShare")] - internal string AuthShare { get; set; } - - [DataMember(Name = "maybeEncryptedRecoveryShares")] - internal string[] MaybeEncryptedRecoveryShares { get; set; } - } - - [DataContract] - private class IsEmailUserOtpValidResponse - { - [DataMember(Name = "isValid")] - internal bool IsValid { get; set; } - } - - [DataContract] - private class IsEmailKmsOtpValidResponse - { - [DataMember(Name = "isOtpValid")] - internal bool IsOtpValid { get; set; } - } - - [DataContract] - private class HeadlessOauthLoginLinkResponse - { - [DataMember(Name = "googleLoginLink")] - internal string GoogleLoginLink { get; set; } - - [DataMember(Name = "platformLoginLink")] - internal string PlatformLoginLink { get; set; } - - [DataMember(Name = "oauthLoginLink")] - internal string OauthLoginLink { get; set; } - } - - [DataContract] - internal class StoredTokenType - { - [DataMember] - private string jwtToken; - - [DataMember] - private string authProvider; - - [DataMember(Name = "authDetails")] - internal UserAuthDetails AuthDetails { get; set; } - - [DataMember] - private string developerClientId; - - [DataMember] - private string cookieString; - - [DataMember] - private bool isNewUser; - } - - [DataContract] - internal class UserAuthDetails - { - [DataMember(Name = "email")] - internal string Email { get; set; } - - [DataMember(Name = "userWalletId")] - internal string WalletUserId { get; set; } - - [DataMember(Name = "recoveryShareManagement")] - internal string RecoveryShareManagement { get; set; } - - [DataMember(Name = "recoveryCode")] - internal string RecoveryCode { get; set; } - - [DataMember(Name = "backupRecoveryCodes")] - internal string[] BackupRecoveryCodes { get; set; } - } - - [DataContract] - internal class UserWallet - { - [DataMember(Name = "status")] - internal string Status { get; set; } - - [DataMember(Name = "isNewUser")] - internal bool IsNewUser { get; set; } - - [DataMember(Name = "walletUserId")] - internal string WalletUserId { get; set; } - - [DataMember(Name = "recoveryShareManagement")] - internal string RecoveryShareManagement { get; set; } - - [DataMember(Name = "storedToken")] - internal StoredTokenType StoredToken { get; set; } - } - - [DataContract] - private class IdTokenResponse - { - [DataMember(Name = "accessToken")] - internal string AccessToken { get; set; } - - [DataMember(Name = "idToken")] - internal string IdToken { get; set; } - } - - [DataContract] - private class RecoverySharePasswordResponse - { - [DataMember(Name = "body")] - internal string Body { get; set; } - - [DataMember(Name = "recoveryShareEncKey")] - internal string RecoverySharePassword { get; set; } - } - - [DataContract] - internal class RecoveryShareManagementResponse - { - internal string Value => data.oauth.FirstOrDefault()?.recovery_share_management; -#pragma warning disable CS0649 // Deserialization will populate these fields. - [DataMember] - private RecoveryShareManagementResponse data; - - [DataMember] - private RecoveryShareManagementResponse[] oauth; - - [DataMember] - private string recovery_share_management; -#pragma warning restore CS0649 // Field 'Server.RecoveryShareManagementResponse.*' is never assigned to, and will always have its default value null - } - - [DataContract] - internal class AuthResultType_OAuth - { - [DataMember(Name = "storedToken")] - internal StoredTokenType_OAuth StoredToken { get; set; } - - [DataMember(Name = "walletDetails")] - internal WalletDetailsType_OAuth WalletDetails { get; set; } - } - - [DataContract] - internal class StoredTokenType_OAuth - { - [DataMember(Name = "jwtToken")] - internal string JwtToken { get; set; } - - [DataMember(Name = "authProvider")] - internal string AuthProvider { get; set; } - - [DataMember(Name = "authDetails")] - internal AuthDetailsType_OAuth AuthDetails { get; set; } - - [DataMember(Name = "developerClientId")] - internal string DeveloperClientId { get; set; } - - [DataMember(Name = "cookieString")] - internal string CookieString { get; set; } - - [DataMember(Name = "shouldStoreCookieString")] - internal bool ShouldStoreCookieString { get; set; } - - [DataMember(Name = "isNewUser")] - internal bool IsNewUser { get; set; } - - [DataContract] - internal class AuthDetailsType_OAuth - { - [DataMember(Name = "email")] - internal string Email { get; set; } - - [DataMember(Name = "userWalletId")] - internal string UserWalletId { get; set; } - - [DataMember(Name = "recoveryCode")] - internal string RecoveryCode { get; set; } - } - } - - [DataContract] - internal class WalletDetailsType_OAuth - { - [DataMember(Name = "deviceShareStored")] - internal string DeviceShareStored { get; set; } - - [DataMember(Name = "isIframeStorageEnabled")] - internal bool IsIframeStorageEnabled { get; set; } - - [DataMember(Name = "walletAddress")] - internal string WalletAddress { get; set; } - } - -#pragma warning restore CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. -#pragma warning restore CS0169 // The field 'Server.*' is never used -#pragma warning restore IDE0051 // The field 'Server.*' is unused - } -} diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Authentication/Server.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Authentication/Server.cs deleted file mode 100644 index 178b189e..00000000 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Authentication/Server.cs +++ /dev/null @@ -1,567 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Net.Http; -using System.Net.Http.Headers; -using System.Threading.Tasks; -using Newtonsoft.Json; - -namespace Thirdweb.EWS -{ - internal abstract class ServerBase - { - internal abstract Task VerifyThirdwebClientIdAsync(string domain); - internal abstract Task FetchDeveloperWalletSettings(); - internal abstract Task FetchUserDetailsAsync(string emailAddress, string authToken); - internal abstract Task StoreAddressAndSharesAsync(string walletAddress, string authShare, string encryptedRecoveryShare, string authToken, string[] backupRecoveryShares); - - internal abstract Task<(string authShare, string recoveryShare)> FetchAuthAndRecoverySharesAsync(string authToken); - internal abstract Task FetchAuthShareAsync(string authToken); - internal abstract Task FetchHeadlessOauthLoginLinkAsync(string authProvider, string platform); - - internal abstract Task CheckIsEmailKmsOtpValidAsync(string userName, string otp); - internal abstract Task CheckIsEmailUserOtpValidAsync(string emailAddress, string otp); - - internal abstract Task SendUserOtpEmailAsync(string emailAddress); - internal abstract Task SendRecoveryCodeEmailAsync(string authToken, string recoveryCode, string email); - internal abstract Task VerifyUserOtpAsync(string emailAddress, string otp); - - internal abstract Task SendKmsOtpEmailAsync(string emailAddress); - internal abstract Task VerifyKmsOtpAsync(string emailAddress, string otp, string sessionId); - - internal abstract Task SendKmsPhoneOtpAsync(string phoneNumber); - internal abstract Task VerifyKmsPhoneOtpAsync(string phoneNumber, string otp, string sessionId); - - internal abstract Task VerifyJwtAsync(string jwtToken); - - internal abstract Task VerifyOAuthAsync(string authVerifiedToken); - - internal abstract Task VerifyAuthEndpointAsync(string payload); - } - - internal partial class Server : ServerBase - { - private const string ROOT_URL = "https://embedded-wallet.thirdweb.com"; - private const string ROOT_URL_LEGACY = "https://ews.thirdweb.com"; - private const string API_ROOT_PATH = "/api/2023-10-20"; - private const string API_ROOT_PATH_LEGACY = "/api/2022-08-12"; - - private static readonly MediaTypeHeaderValue jsonContentType = MediaTypeHeaderValue.Parse("application/json"); - private readonly IThirdwebHttpClient httpClient; - - private readonly string clientId; - - private static Type thirdwebHttpClientType = typeof(ThirdwebHttpClient); - - internal Server(ThirdwebClient client, IThirdwebHttpClient httpClient) - { - this.clientId = client.ClientId; - this.httpClient = httpClient; - - thirdwebHttpClientType = httpClient.GetType(); - } - - // embedded-wallet/verify-thirdweb-client-id - internal override async Task VerifyThirdwebClientIdAsync(string parentDomain) - { - Dictionary queryParams = new() { { "clientId", clientId }, { "parentDomain", parentDomain } }; - var uri = MakeUri("/embedded-wallet/verify-thirdweb-client-id", queryParams); - var content = MakeHttpContent(new { clientId, parentDomain }); - var response = await httpClient.PostAsync(uri.ToString(), content).ConfigureAwait(false); - await CheckStatusCodeAsync(response).ConfigureAwait(false); - var error = await DeserializeAsync(response).ConfigureAwait(false); - return error.Error; - } - - // embedded-wallet/developer-wallet-settings - internal override async Task FetchDeveloperWalletSettings() - { - try - { - Dictionary queryParams = new() { { "clientId", clientId }, }; - var uri = MakeUri("/embedded-wallet/developer-wallet-settings", queryParams); - var response = await httpClient.GetAsync(uri.ToString()).ConfigureAwait(false); - var responseContent = await DeserializeAsync(response).ConfigureAwait(false); - return responseContent.Value ?? "AWS_MANAGED"; - } - catch - { - return "AWS_MANAGED"; - } - } - - // embedded-wallet/embedded-wallet-user-details - internal override async Task FetchUserDetailsAsync(string emailAddress, string authToken) - { - Dictionary queryParams = new(); - if (emailAddress == null && authToken == null) - { - throw new InvalidOperationException("Must provide either email address or auth token"); - } - - queryParams.Add("email", emailAddress ?? "uninitialized"); - queryParams.Add("clientId", clientId); - - var uri = MakeUri("/embedded-wallet/embedded-wallet-user-details", queryParams); - var response = await SendHttpWithAuthAsync(uri, authToken ?? "").ConfigureAwait(false); - await CheckStatusCodeAsync(response).ConfigureAwait(false); - var rv = await DeserializeAsync(response).ConfigureAwait(false); - return rv; - } - - // embedded-wallet/embedded-wallet-shares POST - internal override async Task StoreAddressAndSharesAsync(string walletAddress, string authShare, string encryptedRecoveryShare, string authToken, string[] backupRecoveryShares) - { - var encryptedRecoveryShares = - backupRecoveryShares == null - ? new[] { new { share = encryptedRecoveryShare, isClientEncrypted = "true" } } - : new[] { new { share = encryptedRecoveryShare, isClientEncrypted = "true" } }.Concat(backupRecoveryShares.Select((s) => new { share = s, isClientEncrypted = "true" })).ToArray(); - - HttpRequestMessage httpRequestMessage = - new(HttpMethod.Post, MakeUri("/embedded-wallet/embedded-wallet-shares")) - { - Content = MakeHttpContent( - new - { - authShare, - maybeEncryptedRecoveryShares = encryptedRecoveryShares, - walletAddress, - } - ), - }; - var response = await SendHttpWithAuthAsync(httpRequestMessage, authToken).ConfigureAwait(false); - await CheckStatusCodeAsync(response).ConfigureAwait(false); - } - - // embedded-wallet/embedded-wallet-shares GET - internal override async Task<(string authShare, string recoveryShare)> FetchAuthAndRecoverySharesAsync(string authToken) - { - var sharesGetResponse = await FetchRemoteSharesAsync(authToken, true).ConfigureAwait(false); - var authShare = sharesGetResponse.AuthShare ?? throw new InvalidOperationException("Server failed to return auth share"); - var encryptedRecoveryShare = sharesGetResponse.MaybeEncryptedRecoveryShares?.FirstOrDefault() ?? throw new InvalidOperationException("Server failed to return recovery share"); - return (authShare, encryptedRecoveryShare); - } - - // embedded-wallet/embedded-wallet-shares GET - internal override async Task FetchAuthShareAsync(string authToken) - { - var sharesGetResponse = await FetchRemoteSharesAsync(authToken, false).ConfigureAwait(false); - return sharesGetResponse.AuthShare ?? throw new InvalidOperationException("Server failed to return auth share"); - } - - // embedded-wallet/embedded-wallet-shares GET - private async Task FetchRemoteSharesAsync(string authToken, bool wantsRecoveryShare) - { - Dictionary queryParams = - new() - { - { "getEncryptedAuthShare", "true" }, - { "getEncryptedRecoveryShare", wantsRecoveryShare ? "true" : "false" }, - { "useSealedSecret", "false" } - }; - var uri = MakeUri("/embedded-wallet/embedded-wallet-shares", queryParams); - var response = await SendHttpWithAuthAsync(uri, authToken).ConfigureAwait(false); - await CheckStatusCodeAsync(response).ConfigureAwait(false); - var rv = await DeserializeAsync(response).ConfigureAwait(false); - return rv; - } - - // embedded-wallet/cognito-id-token - private async Task FetchCognitoIdTokenAsync(string authToken) - { - var uri = MakeUri("/embedded-wallet/cognito-id-token"); - var response = await SendHttpWithAuthAsync(uri, authToken).ConfigureAwait(false); - await CheckStatusCodeAsync(response).ConfigureAwait(false); - return await DeserializeAsync(response).ConfigureAwait(false); - } - - // embedded-wallet/headless-oauth-login-link - internal override async Task FetchHeadlessOauthLoginLinkAsync(string authProvider, string platform) - { - var uri = MakeUri( - "/embedded-wallet/headless-oauth-login-link", - new Dictionary - { - { "platform", platform }, - { "authProvider", authProvider }, - { "baseUrl", "https://embedded-wallet.thirdweb.com" } - } - ); - - var response = await httpClient.GetAsync(uri.ToString()).ConfigureAwait(false); - await CheckStatusCodeAsync(response).ConfigureAwait(false); - var rv = await DeserializeAsync(response).ConfigureAwait(false); - return rv.PlatformLoginLink; - } - - // /embedded-wallet/is-cognito-otp-valid - internal override async Task CheckIsEmailKmsOtpValidAsync(string email, string otp) - { - var uri = MakeUriLegacy( - "/embedded-wallet/is-cognito-otp-valid", - new Dictionary - { - { "email", email }, - { "code", otp }, - { "clientId", clientId } - } - ); - var response = await httpClient.GetAsync(uri.ToString()).ConfigureAwait(false); - await CheckStatusCodeAsync(response).ConfigureAwait(false); - var result = await DeserializeAsync(response).ConfigureAwait(false); - return result.IsOtpValid; - } - - // embedded-wallet/is-thirdweb-email-otp-valid - internal override async Task CheckIsEmailUserOtpValidAsync(string email, string otp) - { - var uri = MakeUri("/embedded-wallet/is-thirdweb-email-otp-valid"); - var content = MakeHttpContent( - new - { - email, - otp, - clientId, - } - ); - var response = await httpClient.PostAsync(uri.ToString(), content).ConfigureAwait(false); - await CheckStatusCodeAsync(response).ConfigureAwait(false); - var result = await DeserializeAsync(response).ConfigureAwait(false); - return result.IsValid; - } - - // embedded-wallet/send-user-managed-email-otp - internal override async Task SendUserOtpEmailAsync(string emailAddress) - { - var uri = MakeUri("/embedded-wallet/send-user-managed-email-otp"); - var content = MakeHttpContent(new { clientId, email = emailAddress }); - var response = await httpClient.PostAsync(uri.ToString(), content).ConfigureAwait(false); - await CheckStatusCodeAsync(response).ConfigureAwait(false); - } - - // embedded-wallet/send-wallet-recovery-code - internal override async Task SendRecoveryCodeEmailAsync(string authToken, string recoveryCode, string email) - { - HttpRequestMessage httpRequestMessage = - new(HttpMethod.Post, MakeUri("/embedded-wallet/send-wallet-recovery-code")) - { - Content = MakeHttpContent( - new - { - strategy = "email", - clientId, - email, - recoveryCode - } - ), - }; - try - { - var response = await SendHttpWithAuthAsync(httpRequestMessage, authToken).ConfigureAwait(false); - await CheckStatusCodeAsync(response).ConfigureAwait(false); - } - catch (Exception ex) - { - throw new InvalidOperationException("Error sending recovery code email", ex); - } - } - - // embedded-wallet/validate-thirdweb-email-otp - internal override async Task VerifyUserOtpAsync(string emailAddress, string otp) - { - var uri = MakeUri("/embedded-wallet/validate-thirdweb-email-otp"); - var content = MakeHttpContent( - new - { - clientId, - email = emailAddress, - otp - } - ); - var response = await httpClient.PostAsync(uri.ToString(), content).ConfigureAwait(false); - await CheckStatusCodeAsync(response).ConfigureAwait(false); - var authVerifiedToken = await DeserializeAsync(response).ConfigureAwait(false); - return new VerifyResult( - authVerifiedToken.VerifiedToken.IsNewUser, - authVerifiedToken.VerifiedTokenJwtString, - authVerifiedToken.VerifiedToken.AuthDetails.WalletUserId, - authVerifiedToken.VerifiedToken.AuthDetails.RecoveryCode, - authVerifiedToken.VerifiedToken.AuthDetails.Email - ); - } - - // KMS Send - internal override async Task SendKmsOtpEmailAsync(string emailAddress) - { - var userName = MakeCognitoUserName(emailAddress, "email"); - var sessionId = await AWS.StartCognitoUserAuth(userName, thirdwebHttpClientType).ConfigureAwait(false); - if (sessionId == null) - { - await AWS.SignUpCognitoUserAsync(emailAddress, userName, thirdwebHttpClientType).ConfigureAwait(false); - for (var i = 0; i < 3; ++i) - { - await Task.Delay(3333 * i).ConfigureAwait(false); - sessionId = await AWS.StartCognitoUserAuth(userName, thirdwebHttpClientType).ConfigureAwait(false); - if (sessionId != null) - { - break; - } - } - if (sessionId == null) - { - throw new InvalidOperationException("Cannot find user within timeout period"); - } - } - return sessionId; - } - - // embedded-wallet/validate-cognito-email-otp - internal override async Task VerifyKmsOtpAsync(string emailAddress, string otp, string sessionId) - { - var userName = MakeCognitoUserName(emailAddress, "email"); - var tokens = await AWS.FinishCognitoUserAuth(userName, otp, sessionId, thirdwebHttpClientType).ConfigureAwait(false); - var uri = MakeUri("/embedded-wallet/validate-cognito-email-otp"); - ByteArrayContent content = MakeHttpContent( - new - { - developerClientId = clientId, - access_token = tokens.AccessToken, - id_token = tokens.IdToken, - refresh_token = tokens.RefreshToken, - otpMethod = "email", - } - ); - var response = await httpClient.PostAsync(uri.ToString(), content).ConfigureAwait(false); - await CheckStatusCodeAsync(response).ConfigureAwait(false); - var authVerifiedToken = await DeserializeAsync(response).ConfigureAwait(false); - var isNewUser = authVerifiedToken.VerifiedToken.IsNewUser; - var authToken = authVerifiedToken.VerifiedTokenJwtString; - var walletUserId = authVerifiedToken.VerifiedToken.AuthDetails.WalletUserId; - var idTokenResponse = await FetchCognitoIdTokenAsync(authToken).ConfigureAwait(false); - var idToken = idTokenResponse.IdToken; - var invokePayload = Serialize(new { accessToken = idTokenResponse.AccessToken, idToken = idTokenResponse.IdToken }); - var responsePayload = await AWS.InvokeRecoverySharePasswordLambdaAsync(idToken, invokePayload, thirdwebHttpClientType).ConfigureAwait(false); - JsonSerializer jsonSerializer = new(); - var payload = jsonSerializer.Deserialize(new JsonTextReader(new StreamReader(responsePayload))); - payload = jsonSerializer.Deserialize(new JsonTextReader(new StringReader(payload.Body))); - return new VerifyResult(isNewUser, authToken, walletUserId, payload.RecoverySharePassword, authVerifiedToken.VerifiedToken.AuthDetails.Email); - } - - internal override async Task SendKmsPhoneOtpAsync(string phoneNumber) - { - var userName = MakeCognitoUserName(phoneNumber, "sms"); - var sessionId = await AWS.StartCognitoUserAuth(userName, thirdwebHttpClientType).ConfigureAwait(false); - if (sessionId == null) - { - await AWS.SignUpCognitoUserAsync(null, userName, thirdwebHttpClientType).ConfigureAwait(false); - for (var i = 0; i < 3; ++i) - { - await Task.Delay(3333 * i).ConfigureAwait(false); - sessionId = await AWS.StartCognitoUserAuth(userName, thirdwebHttpClientType).ConfigureAwait(false); - if (sessionId != null) - { - break; - } - } - if (sessionId == null) - { - throw new InvalidOperationException("Cannot find user within timeout period"); - } - } - return sessionId; - } - - // embedded-wallet/validate-cognito-email-otp - internal override async Task VerifyKmsPhoneOtpAsync(string phoneNumber, string otp, string sessionId) - { - var userName = MakeCognitoUserName(phoneNumber, "sms"); - var tokens = await AWS.FinishCognitoUserAuth(userName, otp, sessionId, thirdwebHttpClientType).ConfigureAwait(false); - var uri = MakeUri("/embedded-wallet/validate-cognito-email-otp"); - ByteArrayContent content = MakeHttpContent( - new - { - developerClientId = clientId, - access_token = tokens.AccessToken, - id_token = tokens.IdToken, - refresh_token = tokens.RefreshToken, - otpMethod = "email", - } - ); - var response = await httpClient.PostAsync(uri.ToString(), content).ConfigureAwait(false); - await CheckStatusCodeAsync(response).ConfigureAwait(false); - var authVerifiedToken = await DeserializeAsync(response).ConfigureAwait(false); - var isNewUser = authVerifiedToken.VerifiedToken.IsNewUser; - var authToken = authVerifiedToken.VerifiedTokenJwtString; - var walletUserId = authVerifiedToken.VerifiedToken.AuthDetails.WalletUserId; - var idTokenResponse = await FetchCognitoIdTokenAsync(authToken).ConfigureAwait(false); - var idToken = idTokenResponse.IdToken; - var invokePayload = Serialize(new { accessToken = idTokenResponse.AccessToken, idToken = idTokenResponse.IdToken }); - var responsePayload = await AWS.InvokeRecoverySharePasswordLambdaAsync(idToken, invokePayload, thirdwebHttpClientType).ConfigureAwait(false); - JsonSerializer jsonSerializer = new(); - var payload = jsonSerializer.Deserialize(new JsonTextReader(new StreamReader(responsePayload))); - payload = jsonSerializer.Deserialize(new JsonTextReader(new StringReader(payload.Body))); - return new VerifyResult(isNewUser, authToken, walletUserId, payload.RecoverySharePassword, authVerifiedToken.VerifiedToken.AuthDetails.Email); - } - - // embedded-wallet/validate-custom-jwt - internal override async Task VerifyJwtAsync(string jwtToken) - { - var requestContent = new { jwt = jwtToken, developerClientId = clientId }; - var content = MakeHttpContent(requestContent); - var uri = MakeUri("/embedded-wallet/validate-custom-jwt"); - var response = await httpClient.PostAsync(uri.ToString(), content).ConfigureAwait(false); - await CheckStatusCodeAsync(response).ConfigureAwait(false); - var authVerifiedToken = await DeserializeAsync(response).ConfigureAwait(false); - var isNewUser = authVerifiedToken.VerifiedToken.IsNewUser; - var authToken = authVerifiedToken.VerifiedTokenJwtString; - var walletUserId = authVerifiedToken.VerifiedToken.AuthDetails.WalletUserId; - var email = authVerifiedToken.VerifiedToken.AuthDetails.Email; - var recoveryCode = authVerifiedToken.VerifiedToken.AuthDetails.RecoveryCode; - return new VerifyResult(isNewUser, authToken, walletUserId, recoveryCode, email); - } - - // embedded-wallet/validate-custom-auth-endpoint - internal override async Task VerifyAuthEndpointAsync(string payload) - { - var requestContent = new { payload, developerClientId = clientId }; - var content = MakeHttpContent(requestContent); - var uri = MakeUri("/embedded-wallet/validate-custom-auth-endpoint"); - var response = await httpClient.PostAsync(uri.ToString(), content).ConfigureAwait(false); - await CheckStatusCodeAsync(response).ConfigureAwait(false); - var authVerifiedToken = await DeserializeAsync(response).ConfigureAwait(false); - var isNewUser = authVerifiedToken.VerifiedToken.IsNewUser; - var authToken = authVerifiedToken.VerifiedTokenJwtString; - var walletUserId = authVerifiedToken.VerifiedToken.AuthDetails.WalletUserId; - var email = authVerifiedToken.VerifiedToken.AuthDetails.Email; - var recoveryCode = authVerifiedToken.VerifiedToken.AuthDetails.RecoveryCode; - return new VerifyResult(isNewUser, authToken, walletUserId, recoveryCode, email); - } - - internal override async Task VerifyOAuthAsync(string authResultStr) - { - var authResult = JsonConvert.DeserializeObject(authResultStr); - var isNewUser = authResult.StoredToken.IsNewUser; - var authToken = authResult.StoredToken.CookieString; - var walletUserId = authResult.StoredToken.AuthDetails.UserWalletId; - var isUserManaged = (await FetchUserDetailsAsync(authResult.StoredToken.AuthDetails.Email, authToken).ConfigureAwait(false)).RecoveryShareManagement == "USER_MANAGED"; - string recoveryCode = null; - if (!isUserManaged) - { - var idTokenResponse = await FetchCognitoIdTokenAsync(authToken).ConfigureAwait(false); - var idToken = idTokenResponse.IdToken; - var invokePayload = Serialize(new { accessToken = idTokenResponse.AccessToken, idToken = idTokenResponse.IdToken }); - var responsePayload = await AWS.InvokeRecoverySharePasswordLambdaAsync(idToken, invokePayload, thirdwebHttpClientType).ConfigureAwait(false); - JsonSerializer jsonSerializer = new(); - var payload = jsonSerializer.Deserialize(new JsonTextReader(new StreamReader(responsePayload))); - payload = jsonSerializer.Deserialize(new JsonTextReader(new StringReader(payload.Body))); - recoveryCode = payload.RecoverySharePassword; - } - return new VerifyResult(isNewUser, authToken, walletUserId, recoveryCode, authResult.StoredToken.AuthDetails.Email); - } - - #region Misc - - private async Task SendHttpWithAuthAsync(HttpRequestMessage httpRequestMessage, string authToken) - { - httpClient.AddHeader("Authorization", $"Bearer embedded-wallet-token:{authToken}"); - - try - { - if (httpRequestMessage.Method == HttpMethod.Get) - { - return await httpClient.GetAsync(httpRequestMessage.RequestUri.ToString()).ConfigureAwait(false); - } - else if (httpRequestMessage.Method == HttpMethod.Post) - { - return await httpClient.PostAsync(httpRequestMessage.RequestUri.ToString(), httpRequestMessage.Content).ConfigureAwait(false); - } - else if (httpRequestMessage.Method == HttpMethod.Put) - { - return await httpClient.PutAsync(httpRequestMessage.RequestUri.ToString(), httpRequestMessage.Content).ConfigureAwait(false); - } - else if (httpRequestMessage.Method == HttpMethod.Delete) - { - return await httpClient.DeleteAsync(httpRequestMessage.RequestUri.ToString()).ConfigureAwait(false); - } - else - { - throw new InvalidOperationException("Unsupported HTTP method"); - } - } - finally - { - httpClient.RemoveHeader("Authorization"); - } - } - - private async Task SendHttpWithAuthAsync(Uri uri, string authToken) - { - HttpRequestMessage httpRequestMessage = new(HttpMethod.Get, uri); - return await SendHttpWithAuthAsync(httpRequestMessage, authToken).ConfigureAwait(false); - } - - private static async Task CheckStatusCodeAsync(ThirdwebHttpResponseMessage response) - { - if (!response.IsSuccessStatusCode) - { - var error = await DeserializeAsync(response).ConfigureAwait(false); - throw new InvalidOperationException(string.IsNullOrEmpty(error.Error) ? error.Message : error.Error); - } - } - - private static async Task DeserializeAsync(ThirdwebHttpResponseMessage response) - { - JsonSerializer jsonSerializer = new(); - TextReader textReader = new StreamReader(await response.Content.ReadAsStreamAsync().ConfigureAwait(false)); - var rv = jsonSerializer.Deserialize(new JsonTextReader(textReader)); - return rv; - } - - private static Uri MakeUri(string path, IDictionary parameters = null) - { - UriBuilder b = new(ROOT_URL) { Path = API_ROOT_PATH + path, }; - if (parameters != null && parameters.Any()) - { - var queryString = string.Join('&', parameters.Select((p) => $"{p.Key}={Uri.EscapeDataString(p.Value)}")); - b.Query = queryString; - } - return b.Uri; - } - - private static Uri MakeUriLegacy(string path, IDictionary parameters = null) - { - UriBuilder b = new(ROOT_URL_LEGACY) { Path = API_ROOT_PATH_LEGACY + path, }; - if (parameters != null && parameters.Any()) - { - var queryString = string.Join('&', parameters.Select((p) => $"{p.Key}={Uri.EscapeDataString(p.Value)}")); - b.Query = queryString; - } - return b.Uri; - } - - private static StringContent MakeHttpContent(object data) - { - StringContent stringContent = new(Serialize(data)); - stringContent.Headers.ContentType = jsonContentType; - return stringContent; - } - - private static string Serialize(object data) - { - JsonSerializer jsonSerializer = new() { NullValueHandling = NullValueHandling.Ignore, }; - StringWriter stringWriter = new(); - jsonSerializer.Serialize(stringWriter, data); - var rv = stringWriter.ToString(); - - return rv; - } - - private string MakeCognitoUserName(string userData, string type) - { - return $"{userData}:{type}:{clientId}"; - } - - #endregion - } -} diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Encryption/EmbeddedWallet.Cryptography.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Encryption/EmbeddedWallet.Cryptography.cs deleted file mode 100644 index c4746f8d..00000000 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Encryption/EmbeddedWallet.Cryptography.cs +++ /dev/null @@ -1,145 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Security.Cryptography; -using System.Text; -using System.Threading.Tasks; -using Nethereum.Web3.Accounts; - -using Org.BouncyCastle.Crypto.Engines; -using Org.BouncyCastle.Crypto.Modes; -using Org.BouncyCastle.Crypto.Parameters; - -namespace Thirdweb.EWS -{ - internal partial class EmbeddedWallet - { - private string DecryptShare(string encryptedShare, string password) - { - var parts = encryptedShare.Split(ENCRYPTION_SEPARATOR); - var ciphertextWithTag = Convert.FromBase64String(parts[0]); - var iv = Convert.FromBase64String(parts[1]); - var salt = Convert.FromBase64String(parts[2]); - - int iterationCount; - if (parts.Length > 3 && int.TryParse(parts[3], out var parsedIterationCount)) - { - iterationCount = parsedIterationCount; - } - else - { - iterationCount = DEPRECATED_ITERATION_COUNT; - } - - var key = GetEncryptionKey(password, salt, iterationCount); - - byte[] encodedShare; - try - { - // Bouncy Castle expects the authentication tag after the ciphertext. - GcmBlockCipher cipher = new(new AesEngine()); - cipher.Init(forEncryption: false, new AeadParameters(new KeyParameter(key), 8 * TAG_SIZE, iv)); - encodedShare = new byte[cipher.GetOutputSize(ciphertextWithTag.Length)]; - var offset = cipher.ProcessBytes(ciphertextWithTag, 0, ciphertextWithTag.Length, encodedShare, 0); - cipher.DoFinal(encodedShare, offset); - } - catch - { - try - { - var ciphertextSize = ciphertextWithTag.Length - TAG_SIZE; - var ciphertext = new byte[ciphertextSize]; - Array.Copy(ciphertextWithTag, ciphertext, ciphertext.Length); - var tag = new byte[TAG_SIZE]; - Array.Copy(ciphertextWithTag, ciphertextSize, tag, 0, tag.Length); - encodedShare = new byte[ciphertext.Length]; -#if NET8_0_OR_GREATER - using AesGcm crypto = new(key, TAG_SIZE); -#else - using AesGcm crypto = new(key); -#endif - crypto.Decrypt(iv, ciphertext, tag, encodedShare); - } - catch (CryptographicException) - { - throw new VerificationException("Invalid recovery code", true); - } - } - var share = Encoding.ASCII.GetString(encodedShare); - return share; - } - - private async Task EncryptShareAsync(string share, string password) - { - const int saltSize = 16; - var salt = new byte[saltSize]; - RandomNumberGenerator.Fill(salt); - var key = GetEncryptionKey(password, salt, CURRENT_ITERATION_COUNT); - var encodedShare = Encoding.ASCII.GetBytes(share); - const int ivSize = 12; - var iv = new byte[ivSize]; - await ivGenerator.ComputeIvAsync(iv); - byte[] encryptedShare; - try - { - // Bouncy Castle includes the authentication tag after the ciphertext. - GcmBlockCipher cipher = new(new AesEngine()); - cipher.Init(forEncryption: true, new AeadParameters(new KeyParameter(key), 8 * TAG_SIZE, iv)); - encryptedShare = new byte[cipher.GetOutputSize(encodedShare.Length)]; - var offset = cipher.ProcessBytes(encodedShare, 0, encodedShare.Length, encryptedShare, 0); - cipher.DoFinal(encryptedShare, offset); - } - catch - { - var tag = new byte[TAG_SIZE]; - encryptedShare = new byte[encodedShare.Length]; -#if NET8_0_OR_GREATER - using AesGcm crypto = new(key, TAG_SIZE); -#else - using AesGcm crypto = new(key); -#endif - crypto.Encrypt(iv, encodedShare, encryptedShare, tag); - encryptedShare = encryptedShare.Concat(tag).ToArray(); - } - var rv = - $"{Convert.ToBase64String(encryptedShare)}{ENCRYPTION_SEPARATOR}{Convert.ToBase64String(iv)}{ENCRYPTION_SEPARATOR}{Convert.ToBase64String(salt)}{ENCRYPTION_SEPARATOR}{CURRENT_ITERATION_COUNT}"; - return rv; - } - - private (string deviceShare, string recoveryShare, string authShare) CreateShares(string secret) - { - Secrets secrets = new(); - secret = $"{WALLET_PRIVATE_KEY_PREFIX}{secret}"; - var encodedSecret = Secrets.GetHexString(Encoding.ASCII.GetBytes(secret)); - var shares = secrets.Share(encodedSecret, 3, 2); - return (shares[0], shares[1], shares[2]); - } - - private static byte[] GetEncryptionKey(string password, byte[] salt, int iterationCount) - { - using Rfc2898DeriveBytes pbkdf2 = new(password, salt, iterationCount, HashAlgorithmName.SHA256); - var keyMaterial = pbkdf2.GetBytes(KEY_SIZE); - return keyMaterial; - } - - private Account MakeAccountFromShares(params string[] shares) - { - Secrets secrets = new(); - var encodedSecret = secrets.Combine(shares); - var secret = Encoding.ASCII.GetString(Secrets.GetBytes(encodedSecret)); - if (!secret.StartsWith(WALLET_PRIVATE_KEY_PREFIX)) - { - throw new InvalidOperationException($"Corrupted share encountered {secret}"); - } - return new Account(secret.Split(WALLET_PRIVATE_KEY_PREFIX)[1]); - } - - private string MakeRecoveryCode() - { - const int codeSize = 16; - const string characters = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; - string recoveryCode = new(Enumerable.Range(0, codeSize).Select((_) => characters[RandomNumberGenerator.GetInt32(characters.Length)]).ToArray()); - return recoveryCode; - } - } -} diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Encryption/IvGenerator.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Encryption/IvGenerator.cs deleted file mode 100644 index b0ca8207..00000000 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Encryption/IvGenerator.cs +++ /dev/null @@ -1,66 +0,0 @@ -using System.Security.Cryptography; - -namespace Thirdweb.EWS -{ - internal abstract class IvGeneratorBase - { - internal abstract Task ComputeIvAsync(byte[] iv); - } - - internal class IvGenerator : IvGeneratorBase - { - private long prbsValue; - private readonly string ivFilePath; - private const int nPrbsBits = 48; - private const long prbsPeriod = (1L << nPrbsBits) - 1; - private static readonly long taps = new int[] { nPrbsBits, 47, 21, 20 }.Aggregate(0L, (a, b) => a + (1L << (nPrbsBits - b))); // https://docs.xilinx.com/v/u/en-US/xapp052, page 5 - - internal IvGenerator(string storageDirectoryPath = null) - { - string directory; - directory = storageDirectoryPath ?? Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData); - directory = Path.Combine(directory, "EWS"); - Directory.CreateDirectory(directory); - ivFilePath = Path.Combine(directory, "iv.txt"); - try - { - prbsValue = long.Parse(File.ReadAllText(ivFilePath)); - } - catch (Exception) - { - prbsValue = (0x434a49445a27 ^ DateTime.Now.Ticks) & prbsPeriod; - } - } - - /// - /// Compute IV using half LFSR-generated and half random bytes. - /// - /// https://crypto.stackexchange.com/questions/84357/what-are-the-rules-for-using-aes-gcm-correctly - /// The IV byte array to fill. This must be twelve bytes in size. - internal override async Task ComputeIvAsync(byte[] iv) - { - RandomNumberGenerator.Fill(iv); - prbsValue = ComputeNextPrbsValue(prbsValue); - await File.WriteAllTextAsync(ivFilePath, prbsValue.ToString()).ConfigureAwait(false); - var prbsBytes = Enumerable.Range(0, nPrbsBits / 8).Select((i) => (byte)(prbsValue >> (8 * i))).ToArray(); - Array.Copy(prbsBytes, iv, prbsBytes.Length); - } - - /// - /// Compute the next value of a PRBS using a 48-bit Galois LFSR. - /// - /// https://en.wikipedia.org/wiki/Linear-feedback_shift_register - /// The current PRBS value. - /// The next value. - private static long ComputeNextPrbsValue(long prbsValue) - { - prbsValue <<= 1; - if ((prbsValue & (1L << nPrbsBits)) != 0) - { - prbsValue ^= taps; - prbsValue &= prbsPeriod; - } - return prbsValue; - } - } -} diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Encryption/Secrets.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Encryption/Secrets.cs deleted file mode 100644 index f44b1175..00000000 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Encryption/Secrets.cs +++ /dev/null @@ -1,476 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Globalization; -using System.Linq; -using System.Security.Cryptography; -using System.Text; -using System.Text.RegularExpressions; - -namespace Thirdweb.EWS -{ - internal class Secrets - { - private Config config = new(Defaults.nBits); - private const int nHexDigitBits = 4; - private readonly Func GetRandomInt32 = (nBits) => RandomNumberGenerator.GetInt32(1, 1 << nBits); - private static readonly string padding = string.Join("", Enumerable.Repeat("0", Defaults.maxPaddingMultiple)); - private static readonly string[] nybbles = { "0000", "0001", "0010", "0011", "0100", "0101", "0110", "0111", "1000", "1001", "1010", "1011", "1100", "1101", "1110", "1111", }; - - /// - /// Reconsitute a secret from . - /// - /// - /// The return value will not be the original secret if the number of shares provided is less than the threshold - /// number of shares. - /// Duplicate shares do not count toward the threshold. - /// - /// The shares used to reconstitute the secret. - /// The reconstituted secret. - public string Combine(IReadOnlyList shares) - { - return Combine(shares, 0); - } - - /// - /// Convert a string of hexadecimal digits into a byte array. - /// - /// The string of hexadecimal digits to convert. - /// A byte array. - public static byte[] GetBytes(string s) - { - var bytes = Enumerable.Range(0, s.Length / 2).Select((i) => byte.Parse(s.Substring(i * 2, 2), NumberStyles.HexNumber)).ToArray(); - return bytes; - } - - /// - /// Convert a byte array into a string of hexadecimal digits. - /// - /// The byte array to convert. - /// A string of hexadecimal digits. - public static string GetHexString(byte[] bytes) - { - return BitConverter.ToString(bytes).Replace("-", "").ToLowerInvariant(); - } - - /// - /// Generate a new share identified as . - /// - /// - /// The return value will be invalid if the number of shares provided is less than the threshold number of shares. - /// If is the identifier of a share in and the number of shares - /// provided is at least the threshold number of shares, the return value will be the same as the identified share. - /// Duplicate shares do not count toward the threshold. - /// - /// The identifier of the share to generate. - /// The shares from which to generate the new share. - /// A hexadecimal string of the new share. - /// - /// - public string NewShare(int shareId, IReadOnlyList shares) - { - if (shareId <= 0) - { - throw new ArgumentOutOfRangeException(nameof(shareId), $"{nameof(shareId)} must be greater than zero."); - } - else if (shares == null || !shares.Any() || string.IsNullOrEmpty(shares[0])) - { - throw new ArgumentException($"{nameof(shares)} cannot be empty.", nameof(shares)); - } - var share = ExtractShareComponents(shares[0]); - return ConstructPublicShareString(share.nBits, Convert.ToString(shareId, Defaults.radix), Combine(shares, shareId)); - } - - /// - /// Generate a random value expressed as a string of hexadecimal digits that contains bytes using a - /// secure random number generator. - /// - /// The number of bytes of output. - /// A hexadecimal string of the value. - /// - public static string Random(int nBytes) - { - const int maxnBytes = (1 << 16) / 8; - if (nBytes < 1 || nBytes > maxnBytes) - { - throw new ArgumentOutOfRangeException(nameof(nBytes), $"{nameof(nBytes)} must be in the range [1, {maxnBytes}]."); - } - var bytes = new byte[nBytes]; - RandomNumberGenerator.Fill(bytes); - var rv = GetHexString(bytes); - return rv; - } - - /// - /// Divide a into - /// shares, requiring shares to - /// reconstruct the secret. Optionally, initialize with . Optionally, zero-pad the secret to a length - /// that is a multiple of (default 128) before sharing. - /// - /// A secret value expressed as a string of hexadecimal digits. - /// The number of shares to produce. - /// The number of shares required to reconstruct the secret. - /// The number of bits to use to create the shares. - /// The amount of zero-padding to apply to the secret before sharing. - /// A list of strings of hexadecimal digits. - /// - /// - public List Share(string secret, int nShares, int threshold, int nBits = 0, int paddingMultiple = 128) - { - // Initialize based on nBits if it's specified. - if (nBits != 0) - { - if (nBits < Defaults.minnBits || nBits > Defaults.maxnBits) - { - throw new ArgumentOutOfRangeException(nameof(nBits), $"{nameof(nBits)} must be in the range [{Defaults.minnBits}, {Defaults.maxnBits}]."); - } - config = new(nBits); - } - - // Validate the parameters. - if (string.IsNullOrEmpty(secret)) - { - throw new ArgumentException($"{nameof(secret)} cannot be empty.", nameof(secret)); - } - else if (!secret.All((ch) => char.IsDigit(ch) || (ch >= 'A' && ch <= 'F') || (ch >= 'a' && ch <= 'f'))) - { - throw new ArgumentException($"{nameof(secret)} must consist only of hexadecimal digits.", nameof(secret)); - } - else if (nShares < 2 || nShares > Math.Min(config.maxnShares, Defaults.maxnShares)) - { - if (nShares > Defaults.maxnShares) - { - throw new ArgumentOutOfRangeException(nameof(nShares), $"The maximum number of shares is {Defaults.maxnShares} since the maximum bit count is {Defaults.maxnBits}."); - } - else if (nShares > config.maxnShares) - { - throw new ArgumentOutOfRangeException( - nameof(nShares), - $"{nameof(nShares)} must be in the range [2, {config.maxnShares}]. To create {nShares} shares, specify at least {Math.Ceiling(Math.Log(nShares + 1, 2))} bits." - ); - } - throw new ArgumentOutOfRangeException(nameof(nShares), $"{nameof(nShares)} must be in the range [2, {config.maxnShares}]."); - } - else if (threshold < 2 || threshold > nShares) - { - throw new ArgumentOutOfRangeException(nameof(threshold), $"{nameof(threshold)} must be in the range [2, {nShares}]."); - } - else if (paddingMultiple < 0 || paddingMultiple > 1024) - { - throw new ArgumentOutOfRangeException(nameof(paddingMultiple), $"{nameof(paddingMultiple)} must be in the range [0, {Defaults.maxPaddingMultiple}]."); - } - - // Prepend a 1 as a marker to preserve the correct number of leading zeros in the secret. - secret = "1" + Hex2bin(secret); - - // Create the shares. For additional security, pad in multiples of 128 bits by default. This is a small trade-off in larger - // share size to help prevent leakage of information about small secrets and increase the difficulty of attacking them. - var l = SplitNumStringToIntArray(secret, paddingMultiple); - var x = new string[nShares]; - var y = new string[nShares]; - foreach (var value in l) - { - var subShares = GetShares(value, nShares, threshold); - for (var i = 0; i < nShares; ++i) - { - x[i] = Convert.ToString(subShares[i].x, Defaults.radix); - y[i] = PadLeft(Convert.ToString(subShares[i].y, 2), config.nBits) + (y[i] ?? ""); - } - } - for (var i = 0; i < nShares; ++i) - { - x[i] = ConstructPublicShareString(config.nBits, x[i], Bin2hex(y[i])); - } - return x.ToList(); - } - - private static string Bin2hex(string value) - { - value = PadLeft(value, nHexDigitBits); - StringBuilder sb = new(); - for (var i = 0; i < value.Length; i += nHexDigitBits) - { - var num = Convert.ToInt32(value.Substring(i, nHexDigitBits), 2); - sb.Append(Convert.ToString(num, 16)); - } - return sb.ToString(); - } - - private string Combine(IReadOnlyList shares, int shareId) - { - // Zip distinct shares. E.g. - // [ [ 193, 186, 29, 177, 196 ], - // [ 53, 105, 139, 127, 149 ], - // [ 146, 211, 249, 206, 81 ] ] - // becomes - // [ [ 193, 53, 146 ], - // [ 186, 105, 211 ], - // [ 29, 139, 249 ], - // [ 177, 127, 206 ], - // [ 196, 149, 81 ] ] - var nBits = 0; - List x = new(); - List> y = new(); - foreach (var share in shares.Select((s) => ExtractShareComponents(s))) - { - // All shares must have the same bits settings. - if (nBits == 0) - { - nBits = share.nBits; - - // Reconfigure based on the bits settings of the shares. - if (config.nBits != nBits) - { - config = new(nBits); - } - } - else if (share.nBits != nBits) - { - throw new ArgumentException("Shares are mismatched due to different bits settings.", nameof(shares)); - } - - // Spread the share across the arrays if the share.id is not already in array `x`. - if (x.IndexOf(share.id) == -1) - { - x.Add(share.id); - var splitShare = SplitNumStringToIntArray(Hex2bin(share.data)); - for (int i = 0, n = splitShare.Count; i < n; ++i) - { - if (i >= y.Count) - { - y.Add(new List()); - } - y[i].Add(splitShare[i]); - } - } - } - - // Extract the secret from the zipped share data. - StringBuilder sb = new(); - foreach (var y_ in y) - { - sb.Insert(0, PadLeft(Convert.ToString(Lagrange(shareId, x, y_), 2), nBits)); - } - var result = sb.ToString(); - - // If `shareId` is not zero, NewShare invoked Combine. In this case, return the new share data directly. Otherwise, find - // the first '1' which was added in the Share method as a padding marker and return only the data after the padding and the - // marker. Convert the binary string, which is the derived secret, to hexadecimal. - return Bin2hex(shareId >= 1 ? result : result[(result.IndexOf("1") + 1)..]); - } - - private static string ConstructPublicShareString(int nBits, string shareId, string data) - { - var id = Convert.ToInt32(shareId, Defaults.radix); - var base36Bits = char.ConvertFromUtf32(nBits > 9 ? nBits - 10 + 'A' : nBits + '0'); - var idMax = (1 << nBits) - 1; - var paddingMultiple = Convert.ToString(idMax, Defaults.radix).Length; - var hexId = PadLeft(Convert.ToString(id, Defaults.radix), paddingMultiple); - if (id < 1 || id > idMax) - { - throw new ArgumentOutOfRangeException(nameof(shareId), $"{nameof(shareId)} must be in the range [1, {idMax}]."); - } - var share = base36Bits + hexId + data; - return share; - } - - private static ShareComponents ExtractShareComponents(string share) - { - // Extract the first character which represents the number of bits in base 36. - var nBits = GetLargeBaseValue(share[0]); - if (nBits < Defaults.minnBits || nBits > Defaults.maxnBits) - { - throw new ArgumentException($"Unexpected {nBits}-bit share outside of the range [{Defaults.minnBits}, {Defaults.maxnBits}].", nameof(share)); - } - - // Calculate the maximum number of shares allowed for the given number of bits. - var maxnShares = (1 << nBits) - 1; - - // Derive the identifier length from the bit count. - var idLength = Convert.ToString(maxnShares, Defaults.radix).Length; - - // Extract all the parts now that the segment sizes are known. - var rx = new Regex("^([3-9A-Ka-k]{1})([0-9A-Fa-f]{" + idLength + "})([0-9A-Fa-f]+)$"); - var shareComponents = rx.Matches(share); - var groups = shareComponents.FirstOrDefault()?.Groups; - if (groups == null || groups.Count != 4) - { - throw new ArgumentException("Malformed share", nameof(share)); - } - - // Convert the identifier from a string of hexadecimal digits into an integer. - var id = Convert.ToInt32(groups[2].Value, Defaults.radix); - - // Return the components of the share. - ShareComponents rv = new(nBits, id, groups[3].Value); - return rv; - } - - private static int GetLargeBaseValue(char ch) - { - var rv = - ch >= 'a' - ? ch - 'a' + 10 - : ch >= 'A' - ? ch - 'A' + 10 - : ch - '0'; - return rv; - } - - private (int x, int y)[] GetShares(int secret, int nShares, int threshold) - { - var coefficients = Enumerable.Range(0, threshold - 1).Select((i) => GetRandomInt32(config.nBits)).Concat(new[] { secret }).ToArray(); - var shares = Enumerable.Range(1, nShares).Select((i) => (i, Horner(i, coefficients))).ToArray(); - return shares; - } - - private static string Hex2bin(string value) - { - StringBuilder sb = new(); - foreach (var ch in value) - { - sb.Append(nybbles[GetLargeBaseValue(ch)]); - } - return sb.ToString(); - } - - // Evaluate the polynomial at `x` using Horner's Method. - // NOTE: fx = fx * x + coefficients[i] -> exp(log(fx) + log(x)) + coefficients[i], so if fx is zero, set fx to coefficients[i] - // since using the exponential or logarithmic form will result in an incorrect value. - private int Horner(int x, IEnumerable coefficients) - { - var logx = config.logarithms[x]; - var fx = 0; - foreach (var coefficient in coefficients) - { - fx = fx == 0 ? coefficient : config.exponents[(logx + config.logarithms[fx]) % config.maxnShares] ^ coefficient; - } - return fx; - } - - // Evaluate the Lagrange interpolation polynomial at x = `shareId` using x and y arrays that are of the same length, with - // corresponding elements constituting points on the polynomial. - private int Lagrange(int shareId, IReadOnlyList x, IReadOnlyList y) - { - var sum = 0; - foreach (var i in Enumerable.Range(0, x.Count)) - { - if (i < y.Count && y[i] != 0) - { - var product = config.logarithms[y[i]]; - foreach (var j in Enumerable.Range(0, x.Count).Where((j) => i != j)) - { - if (shareId == x[j]) - { - // This happens when computing a share that is in the list of shares used to compute it. - product = -1; - break; - } - - // Ensure it's not negative. - product = (product + config.logarithms[shareId ^ x[j]] - config.logarithms[x[i] ^ x[j]] + config.maxnShares) % config.maxnShares; - } - sum = product == -1 ? sum : sum ^ config.exponents[product]; - } - } - return sum; - } - - private static string PadLeft(string value, int paddingMultiple) - { - if (paddingMultiple == 1) - { - return value; - } - else if (paddingMultiple < 2 || paddingMultiple > Defaults.maxPaddingMultiple) - { - throw new ArgumentOutOfRangeException(nameof(paddingMultiple), $"{nameof(paddingMultiple)} must be in the range [0, {Defaults.maxPaddingMultiple}]."); - } - if (value.Any()) - { - var extra = value.Length % paddingMultiple; - if (extra > 0) - { - var s = padding + value; - value = s[^(paddingMultiple - extra + value.Length)..]; - } - } - return value; - } - - private List SplitNumStringToIntArray(string value, int paddingMultiple = 0) - { - if (paddingMultiple > 0) - { - value = PadLeft(value, paddingMultiple); - } - List parts = new(); - int i; - for (i = value.Length; i > config.nBits; i -= config.nBits) - { - parts.Add(Convert.ToInt32(value.Substring(i - config.nBits, config.nBits), 2)); - } - parts.Add(Convert.ToInt32(value[..i], 2)); - return parts; - } - - private class Config - { - internal readonly int[] exponents; - internal readonly int[] logarithms; - internal readonly int maxnShares; - internal readonly int nBits; - - internal Config(int nBits) - { - // Set the scalar values. - this.nBits = nBits; - var size = 1 << nBits; - maxnShares = size - 1; - - // Construct the exponent and logarithm tables for multiplication. - var primitive = Defaults.primitivePolynomialCoefficients[nBits]; - exponents = new int[size]; - logarithms = new int[size]; - for (int x = 1, i = 0; i < size; ++i) - { - exponents[i] = x; - logarithms[x] = i; - x <<= 1; - if (x >= size) - { - x ^= primitive; - x &= maxnShares; - } - } - } - } - - private class Defaults - { - internal const int minnBits = 3; - internal const int maxnBits = 20; // up to 1,048,575 shares - internal const int maxnShares = (1 << maxnBits) - 1; - internal const int maxPaddingMultiple = 1024; - internal const int nBits = 8; - internal const int radix = 16; // hexadecimal - - // These are primitive polynomial coefficients for Galois Fields GF(2^n) for 2 <= n <= 20. The index of each term in the - // array corresponds to the n for that polynomial. - internal static readonly int[] primitivePolynomialCoefficients = { -1, -1, 1, 3, 3, 5, 3, 3, 29, 17, 9, 5, 83, 27, 43, 3, 45, 9, 39, 39, 9, }; - } - - private class ShareComponents - { - internal int nBits; - internal int id; - internal string data; - - internal ShareComponents(int nBits, int id, string data) - { - this.nBits = nBits; - this.id = id; - this.data = data; - } - } - } -} diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Exceptions/VerificationException.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Exceptions/VerificationException.cs deleted file mode 100644 index 07f4cc9e..00000000 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Exceptions/VerificationException.cs +++ /dev/null @@ -1,16 +0,0 @@ -using System; -using System.Runtime.Serialization; - -namespace Thirdweb.EWS -{ - internal class VerificationException : Exception - { - internal bool CanRetry { get; } - - public VerificationException(string message, bool canRetry) - : base(message) - { - CanRetry = canRetry; - } - } -} diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Models/User.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Models/User.cs deleted file mode 100644 index b9acd7ce..00000000 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Models/User.cs +++ /dev/null @@ -1,16 +0,0 @@ -using Nethereum.Web3.Accounts; - -namespace Thirdweb.EWS -{ - internal class User - { - internal User(Account account, string emailAddress) - { - Account = account; - EmailAddress = emailAddress; - } - - public Account Account { get; internal set; } - public string EmailAddress { get; internal set; } - } -} diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Models/UserStatus.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Models/UserStatus.cs deleted file mode 100644 index a42e6946..00000000 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Models/UserStatus.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace Thirdweb.EWS -{ - internal enum UserStatus - { - SignedOut = 10, - SignedInWalletUninitialized = 31, - SignedInNewDevice = 21, - SignedInWalletInitialized = 29, - } -} diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Storage/LocalStorage.Types.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Storage/LocalStorage.Types.cs deleted file mode 100644 index 8aa7eedf..00000000 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Storage/LocalStorage.Types.cs +++ /dev/null @@ -1,72 +0,0 @@ -using System.Runtime.Serialization; - -namespace Thirdweb.EWS -{ - internal partial class LocalStorage : LocalStorageBase - { - [DataContract] - internal class DataStorage - { - internal string AuthToken => authToken; - internal string DeviceShare => deviceShare; - internal string EmailAddress => emailAddress; - internal string WalletUserId => walletUserId; - internal string AuthProvider => authProvider; - - [DataMember] - private string authToken; - - [DataMember] - private string deviceShare; - - [DataMember] - private string emailAddress; - - [DataMember] - private string walletUserId; - - [DataMember] - private string authProvider; - - internal DataStorage(string authToken, string deviceShare, string emailAddress, string walletUserId, string authProvider) - { - this.authToken = authToken; - this.deviceShare = deviceShare; - this.emailAddress = emailAddress; - this.walletUserId = walletUserId; - this.authProvider = authProvider; - } - - internal void ClearAuthToken() => authToken = null; - } - - [DataContract] - internal class SessionStorage - { - internal string Id => id; - internal bool IsKmsWallet => isKmsWallet; - - [DataMember] - private string id; - - [DataMember] - private bool isKmsWallet; - - internal SessionStorage(string id, bool isKmsWallet) - { - this.id = id; - this.isKmsWallet = isKmsWallet; - } - } - - [DataContract] - private class Storage - { - [DataMember] - internal DataStorage Data { get; set; } - - [DataMember] - internal SessionStorage Session { get; set; } - } - } -} diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Storage/LocalStorage.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Storage/LocalStorage.cs deleted file mode 100644 index f0dd7284..00000000 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Storage/LocalStorage.cs +++ /dev/null @@ -1,96 +0,0 @@ -using System.Runtime.Serialization.Json; - -namespace Thirdweb.EWS -{ - internal abstract class LocalStorageBase - { - internal abstract LocalStorage.DataStorage Data { get; } - internal abstract LocalStorage.SessionStorage Session { get; } - - internal abstract Task RemoveAuthTokenAsync(); - internal abstract Task RemoveSessionAsync(); - internal abstract Task SaveDataAsync(LocalStorage.DataStorage data); - internal abstract Task SaveSessionAsync(string sessionId, bool isKmsWallet); - } - - internal partial class LocalStorage : LocalStorageBase - { - internal override DataStorage Data => storage.Data; - internal override SessionStorage Session => storage.Session; - private readonly Storage storage; - private readonly string filePath; - - internal LocalStorage(string clientId, string storageDirectoryPath = null) - { - string directory; - directory = storageDirectoryPath ?? Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData); - directory = Path.Combine(directory, "EWS"); - Directory.CreateDirectory(directory); - filePath = Path.Combine(directory, $"{clientId}.txt"); - try - { - byte[] json = File.ReadAllBytes(filePath); - DataContractJsonSerializer serializer = new(typeof(Storage)); - MemoryStream fin = new(json); - storage = (Storage)serializer.ReadObject(fin); - } - catch (Exception) - { - storage = new Storage(); - } - } - - internal override Task RemoveAuthTokenAsync() - { - return UpdateDataAsync(() => - { - if (storage.Data?.AuthToken != null) - { - storage.Data.ClearAuthToken(); - return true; - } - return false; - }); - } - - private async Task UpdateDataAsync(Func fn) - { - if (fn()) - { - DataContractJsonSerializer serializer = new(typeof(Storage)); - MemoryStream fout = new(); - serializer.WriteObject(fout, storage); - await File.WriteAllBytesAsync(filePath, fout.ToArray()).ConfigureAwait(false); - return true; - } - return false; - } - - internal override Task SaveDataAsync(DataStorage data) - { - return UpdateDataAsync(() => - { - storage.Data = data; - return true; - }); - } - - internal override Task SaveSessionAsync(string sessionId, bool isKmsWallet) - { - return UpdateDataAsync(() => - { - storage.Session = new SessionStorage(sessionId, isKmsWallet); - return true; - }); - } - - internal override Task RemoveSessionAsync() - { - return UpdateDataAsync(() => - { - storage.Session = null; - return true; - }); - } - } -} diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.AuthEndpoint.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.AuthEndpoint.cs deleted file mode 100644 index 8b35bde1..00000000 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.AuthEndpoint.cs +++ /dev/null @@ -1,13 +0,0 @@ -using System.Threading.Tasks; - -namespace Thirdweb.EWS -{ - internal partial class EmbeddedWallet - { - public async Task SignInWithAuthEndpointAsync(string payload, string encryptionKey, string recoveryCode) - { - Server.VerifyResult result = await server.VerifyAuthEndpointAsync(payload).ConfigureAwait(false); - return await PostAuthSetup(result, recoveryCode, encryptionKey, "AuthEndpoint").ConfigureAwait(false); - } - } -} diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.EmailOTP.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.EmailOTP.cs deleted file mode 100644 index ecd6cfd3..00000000 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.EmailOTP.cs +++ /dev/null @@ -1,61 +0,0 @@ -using System; -using System.Threading.Tasks; - -namespace Thirdweb.EWS -{ - internal partial class EmbeddedWallet - { - public async Task<(bool isNewUser, bool isNewDevice, bool needsPassword)> SendOtpEmailAsync(string emailAddress) - { - Server.UserWallet userWallet = await server.FetchUserDetailsAsync(emailAddress, null).ConfigureAwait(false); - bool isKmsWallet = userWallet.RecoveryShareManagement != "USER_MANAGED"; - string sessionId = ""; - if (isKmsWallet) - { - sessionId = await server.SendKmsOtpEmailAsync(emailAddress).ConfigureAwait(false); - } - else - { - await server.SendUserOtpEmailAsync(emailAddress); - } - await localStorage.SaveSessionAsync(sessionId, isKmsWallet).ConfigureAwait(false); - bool isNewDevice = userWallet.IsNewUser || localStorage.Data?.WalletUserId != userWallet.WalletUserId; - return (userWallet.IsNewUser, isNewDevice, !isKmsWallet); - } - - public async Task VerifyOtpAsync(string emailAddress, string otp, string recoveryCode) - { - if (localStorage.Session == null) - { - throw new InvalidOperationException($"Must first invoke {nameof(SendOtpEmailAsync)}", new NullReferenceException()); - } - try - { - if (localStorage.Session.IsKmsWallet) - { - if (!await server.CheckIsEmailKmsOtpValidAsync(emailAddress, otp)) - { - throw new VerificationException("Invalid OTP", true); - } - Server.VerifyResult result = await server.VerifyKmsOtpAsync(emailAddress, otp, localStorage.Session.Id).ConfigureAwait(false); - await localStorage.RemoveSessionAsync().ConfigureAwait(false); - return await PostAuthSetup(result, recoveryCode, null, "EmailOTP").ConfigureAwait(false); - } - else - { - if (!await server.CheckIsEmailUserOtpValidAsync(emailAddress, otp)) - { - throw new VerificationException("Invalid OTP", true); - } - Server.VerifyResult result = await server.VerifyUserOtpAsync(emailAddress, otp).ConfigureAwait(false); - await localStorage.RemoveSessionAsync().ConfigureAwait(false); - return await PostAuthSetup(result, recoveryCode, null, "EmailOTP").ConfigureAwait(false); - } - } - catch (VerificationException ex) - { - return new VerifyResult(ex.CanRetry); - } - } - } -} diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.JWT.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.JWT.cs deleted file mode 100644 index 335b1e87..00000000 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.JWT.cs +++ /dev/null @@ -1,13 +0,0 @@ -using System.Threading.Tasks; - -namespace Thirdweb.EWS -{ - internal partial class EmbeddedWallet - { - public async Task SignInWithJwtAsync(string jwt, string encryptionKey, string recoveryCode) - { - Server.VerifyResult result = await server.VerifyJwtAsync(jwt).ConfigureAwait(false); - return await PostAuthSetup(result, recoveryCode, encryptionKey, "JWT").ConfigureAwait(false); - } - } -} diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.Misc.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.Misc.cs deleted file mode 100644 index a9cee339..00000000 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.Misc.cs +++ /dev/null @@ -1,222 +0,0 @@ -using Nethereum.Web3.Accounts; - -namespace Thirdweb.EWS -{ - internal partial class EmbeddedWallet - { - public async Task VerifyThirdwebClientIdAsync(string domain) - { - var error = await server.VerifyThirdwebClientIdAsync(domain).ConfigureAwait(false); - if (error != "") - { - throw new InvalidOperationException($"Invalid thirdweb client id for domain {domain} | {error}"); - } - } - - private async Task PostAuthSetup(Server.VerifyResult result, string userRecoveryCode, string twManagedRecoveryCodeOverride, string authProvider) - { - // Define necessary variables from the result. - Account account; - var walletUserId = result.WalletUserId; - var authToken = result.AuthToken; - var emailAddress = result.Email; - var deviceShare = localStorage.Data?.DeviceShare; - - // Fetch user details from the server. - var userDetails = await server.FetchUserDetailsAsync(emailAddress, authToken).ConfigureAwait(false); - var isUserManaged = userDetails.RecoveryShareManagement == "USER_MANAGED"; - var isNewUser = userDetails.IsNewUser; - User user; - - // Initialize variables related to recovery codes and email status. - string mainRecoveryCode = null; - string[] backupRecoveryCodes = null; - bool? wasEmailed = null; - - if (!isUserManaged) - { - mainRecoveryCode = twManagedRecoveryCodeOverride ?? result.RecoveryCode; - if (mainRecoveryCode == null) - throw new InvalidOperationException("Server failed to return recovery code."); - (account, deviceShare) = result.IsNewUser - ? await CreateAccountAsync(result.AuthToken, mainRecoveryCode).ConfigureAwait(false) - : await RecoverAccountAsync(result.AuthToken, mainRecoveryCode).ConfigureAwait(false); - user = await MakeUserAsync(emailAddress, account, authToken, walletUserId, deviceShare, authProvider).ConfigureAwait(false); - return new VerifyResult(user, mainRecoveryCode, backupRecoveryCodes, wasEmailed); - } - - if (isNewUser) - { - // Create recovery code for user-managed accounts. - mainRecoveryCode = MakeRecoveryCode(); - - // Commented out section for future use: Generating multiple backup recovery codes. - /* - backupRecoveryCodes = new string[7]; - for (int i = 0; i < backupRecoveryCodes.Length; i++) - backupRecoveryCodes[i] = MakeRecoveryCode(); - */ - - // Create a new account and handle the recovery codes. - (account, deviceShare) = await CreateAccountAsync(authToken, mainRecoveryCode, backupRecoveryCodes).ConfigureAwait(false); - - // Attempt to send the recovery code via email and record the outcome. - try - { - if (emailAddress == null) - throw new ArgumentNullException(nameof(emailAddress)); - await server.SendRecoveryCodeEmailAsync(authToken, mainRecoveryCode, emailAddress).ConfigureAwait(false); - wasEmailed = true; - } - catch - { - wasEmailed = false; - } - } - else - { - // Handling for existing users. - if (userRecoveryCode == null) - { - if (deviceShare == null) - throw new ArgumentNullException(nameof(userRecoveryCode)); - - // Fetch the auth share and create an account from shares. - var authShare = await server.FetchAuthShareAsync(authToken).ConfigureAwait(false); - account = MakeAccountFromShares(authShare, deviceShare); - } - else - { - // Recover the account using the provided recovery code. - (account, deviceShare) = await RecoverAccountAsync(authToken, userRecoveryCode).ConfigureAwait(false); - } - } - - // Validate the device share returned from server operations. - if (deviceShare == null) - { - throw new InvalidOperationException("Server failed to return account"); - } - - // Construct the user object and prepare the result. - user = await MakeUserAsync(emailAddress, account, authToken, walletUserId, deviceShare, authProvider).ConfigureAwait(false); - return new VerifyResult(user, mainRecoveryCode, backupRecoveryCodes, wasEmailed); - } - - public async Task SignOutAsync() - { - user = null; - await localStorage.RemoveAuthTokenAsync().ConfigureAwait(false); - } - - public async Task GetUserAsync(string email, string authProvider) - { - if (user != null) - { - return user; - } - else if (localStorage.Data?.AuthToken == null) - { - throw new InvalidOperationException("User is not signed in"); - } - - var userWallet = await server.FetchUserDetailsAsync(null, localStorage.Data.AuthToken).ConfigureAwait(false); - switch (userWallet.Status) - { - case "Logged Out": - await SignOutAsync().ConfigureAwait(false); - throw new InvalidOperationException("User is logged out"); - case "Logged In, Wallet Uninitialized": - await SignOutAsync().ConfigureAwait(false); - throw new InvalidOperationException("User is logged in but wallet is uninitialized"); - case "Logged In, Wallet Initialized": - if (string.IsNullOrEmpty(localStorage.Data?.DeviceShare)) - { - await SignOutAsync().ConfigureAwait(false); - throw new InvalidOperationException("User is logged in but wallet is uninitialized"); - } - - var authShare = await server.FetchAuthShareAsync(localStorage.Data.AuthToken).ConfigureAwait(false); - var emailAddress = userWallet.StoredToken?.AuthDetails.Email; - - if (email != null && email != emailAddress) - { - await SignOutAsync().ConfigureAwait(false); - throw new InvalidOperationException("User email does not match"); - } - else if (email == null && localStorage.Data.AuthProvider != authProvider) - { - await SignOutAsync().ConfigureAwait(false); - throw new InvalidOperationException($"User auth provider does not match. Expected {localStorage.Data.AuthProvider}, got {authProvider}"); - } - else if (authShare == null) - { - throw new InvalidOperationException("Server failed to return auth share"); - } - user = new User(MakeAccountFromShares(new[] { authShare, localStorage.Data.DeviceShare }), emailAddress); - return user; - } - throw new InvalidOperationException($"Unexpected user status '{userWallet.Status}'"); - } - - private async Task MakeUserAsync(string emailAddress, Account account, string authToken, string walletUserId, string deviceShare, string authProvider) - { - var data = new LocalStorage.DataStorage(authToken, deviceShare, emailAddress ?? "", walletUserId, authProvider); - await localStorage.SaveDataAsync(data).ConfigureAwait(false); - user = new User(account, emailAddress ?? ""); - return user; - } - - private async Task<(Account account, string deviceShare)> CreateAccountAsync(string authToken, string recoveryCode, string[] backupRecoveryCodes = null) - { - var secret = Secrets.Random(KEY_SIZE); - (var deviceShare, var recoveryShare, var authShare) = CreateShares(secret); - var encryptedRecoveryShare = await EncryptShareAsync(recoveryShare, recoveryCode); - Account account = new(secret); - - string[] backupRecoveryShares = null; - if (backupRecoveryCodes != null) - { - backupRecoveryShares = new string[backupRecoveryCodes.Length]; - for (var i = 0; i < backupRecoveryCodes.Length; i++) - { - backupRecoveryShares[i] = await EncryptShareAsync(recoveryShare, backupRecoveryCodes[i]); - } - } - await server.StoreAddressAndSharesAsync(account.Address, authShare, encryptedRecoveryShare, authToken, backupRecoveryShares).ConfigureAwait(false); - return (account, deviceShare); - } - - private async Task<(Account account, string deviceShare)> RecoverAccountAsync(string authToken, string recoveryCode) - { - (var authShare, var encryptedRecoveryShare) = await server.FetchAuthAndRecoverySharesAsync(authToken).ConfigureAwait(false); - var recoveryShare = await Task.Run(() => DecryptShare(encryptedRecoveryShare, recoveryCode)); - var account = MakeAccountFromShares(authShare, recoveryShare); - Secrets secrets = new(); - var deviceShare = secrets.NewShare(DEVICE_SHARE_ID, new[] { authShare, recoveryShare }); - return (account, deviceShare); - } - - public class VerifyResult - { - public User User { get; } - public bool CanRetry { get; } - public string MainRecoveryCode { get; } - public string[] BackupRecoveryCodes { get; } - public bool? WasEmailed { get; } - - public VerifyResult(User user, string mainRecoveryCode, string[] backupRecoveryCodes, bool? wasEmailed) - { - User = user; - MainRecoveryCode = mainRecoveryCode; - BackupRecoveryCodes = backupRecoveryCodes; - WasEmailed = wasEmailed; - } - - public VerifyResult(bool canRetry) - { - CanRetry = canRetry; - } - } - } -} diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.OAuth.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.OAuth.cs deleted file mode 100644 index 69dcf925..00000000 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.OAuth.cs +++ /dev/null @@ -1,25 +0,0 @@ -using Newtonsoft.Json; - -namespace Thirdweb.EWS -{ - internal partial class EmbeddedWallet - { - public async Task SignInWithOauthAsync(string authProvider, string authResult, string recoveryCode) - { - Server.VerifyResult result = await server.VerifyOAuthAsync(authResult).ConfigureAwait(false); - return await PostAuthSetup(result, recoveryCode, null, authProvider).ConfigureAwait(false); - } - - public async Task FetchHeadlessOauthLoginLinkAsync(string authProvider, string platform) - { - return await server.FetchHeadlessOauthLoginLinkAsync(authProvider, platform).ConfigureAwait(false); - } - - public async Task IsRecoveryCodeNeededAsync(string authResultStr) - { - var authResult = JsonConvert.DeserializeObject(authResultStr); - Server.UserWallet userWallet = await server.FetchUserDetailsAsync(authResult.StoredToken.AuthDetails.Email, null).ConfigureAwait(false); - return userWallet.RecoveryShareManagement == "USER_MANAGED" && !userWallet.IsNewUser && localStorage.Data?.DeviceShare == null; - } - } -} diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.PhoneOTP.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.PhoneOTP.cs deleted file mode 100644 index 13121a22..00000000 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.PhoneOTP.cs +++ /dev/null @@ -1,40 +0,0 @@ -using System; -using System.Threading.Tasks; - -namespace Thirdweb.EWS -{ - internal partial class EmbeddedWallet - { - public async Task<(bool isNewUser, bool isNewDevice, bool needsPassword)> SendOtpPhoneAsync(string phoneNumber) - { - string sessionId = await server.SendKmsPhoneOtpAsync(phoneNumber).ConfigureAwait(false); - bool isKmsWallet = true; - await localStorage.SaveSessionAsync(sessionId, isKmsWallet).ConfigureAwait(false); - bool isNewUser = true; - bool isNewDevice = true; - return (isNewUser, isNewDevice, !isKmsWallet); - } - - public async Task VerifyPhoneOtpAsync(string phoneNumber, string otp, string recoveryCode) - { - if (localStorage.Session == null) - { - throw new InvalidOperationException($"Must first invoke {nameof(SendOtpPhoneAsync)}", new NullReferenceException()); - } - try - { - // if (!await server.CheckIsPhoneKmsOtpValidAsync(phoneNumber, otp)) - // { - // throw new VerificationException("Invalid OTP", true); - // } - Server.VerifyResult result = await server.VerifyKmsPhoneOtpAsync(phoneNumber, otp, localStorage.Session.Id).ConfigureAwait(false); - await localStorage.RemoveSessionAsync().ConfigureAwait(false); - return await PostAuthSetup(result, recoveryCode, null, "PhoneOTP").ConfigureAwait(false); - } - catch (VerificationException ex) - { - return new VerifyResult(ex.CanRetry); - } - } - } -} diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.cs deleted file mode 100644 index e1c9bee6..00000000 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.cs +++ /dev/null @@ -1,45 +0,0 @@ -namespace Thirdweb.EWS -{ - internal partial class EmbeddedWallet - { - private readonly LocalStorageBase localStorage; - private readonly ServerBase server; - private readonly IvGeneratorBase ivGenerator; - private User user; - - private const int DEVICE_SHARE_ID = 1; - private const int KEY_SIZE = 256 / 8; - private const int TAG_SIZE = 16; - private const int CURRENT_ITERATION_COUNT = 650_000; - private const int DEPRECATED_ITERATION_COUNT = 5_000_000; - private const string WALLET_PRIVATE_KEY_PREFIX = "thirdweb_"; - private const string ENCRYPTION_SEPARATOR = ":"; - - public EmbeddedWallet(ThirdwebClient client, string storageDirectoryPath = null) - { - localStorage = new LocalStorage(client.ClientId, storageDirectoryPath); - - // Create a new client of same type with extra needed headers for EWS - var thirdwebHttpClientType = client.HttpClient.GetType(); - var ewsHttpClient = thirdwebHttpClientType.GetConstructor(Type.EmptyTypes).Invoke(null) as IThirdwebHttpClient; - var headers = client.HttpClient.Headers.ToDictionary(entry => entry.Key, entry => entry.Value); - var platform = client.HttpClient.Headers["x-sdk-platform"]; - var version = client.HttpClient.Headers["x-sdk-version"]; - if (client.ClientId != null) - { - headers.Add("x-thirdweb-client-id", client.ClientId); - } - if (client.SecretKey != null) - { - headers.Add("x-thirdweb-secret-key", client.SecretKey); - } - headers.Add("x-session-nonce", Guid.NewGuid().ToString()); - headers.Add("x-embedded-wallet-version", $"{platform}:{version}"); - ewsHttpClient.SetHeaders(headers); - - server = new Server(client, ewsHttpClient); - - ivGenerator = new IvGenerator(storageDirectoryPath); - } - } -} diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/IThirdwebBrowser.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/IThirdwebBrowser.cs index 5374e047..15bbb399 100644 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/IThirdwebBrowser.cs +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/IThirdwebBrowser.cs @@ -1,90 +1,89 @@ -namespace Thirdweb +namespace Thirdweb; + +/// +/// Defines an interface for handling browser-based login for Thirdweb. +/// +public interface IThirdwebBrowser { /// - /// Defines an interface for handling browser-based login for Thirdweb. + /// Initiates a login process using the browser. /// - public interface IThirdwebBrowser - { - /// - /// Initiates a login process using the browser. - /// - /// The Thirdweb client instance. - /// The URL to initiate the login process. - /// The URL to redirect to after login. - /// An action to open the browser with the login URL. - /// Optional cancellation token to cancel the operation. - /// A task representing the asynchronous operation. The task result contains the login result. - Task Login(ThirdwebClient client, string loginUrl, string redirectUrl, Action browserOpenAction, CancellationToken cancellationToken = default); - } + /// The Thirdweb client instance. + /// The URL to initiate the login process. + /// The URL to redirect to after login. + /// An action to open the browser with the login URL. + /// Optional cancellation token to cancel the operation. + /// A task representing the asynchronous operation. The task result contains the login result. + Task Login(ThirdwebClient client, string loginUrl, string redirectUrl, Action browserOpenAction, CancellationToken cancellationToken = default); +} +/// +/// Enumerates the possible statuses of a browser operation. +/// +public enum BrowserStatus +{ /// - /// Enumerates the possible statuses of a browser operation. + /// The operation was successful. /// - public enum BrowserStatus - { - /// - /// The operation was successful. - /// - Success, + Success, - /// - /// The user canceled the operation. - /// - UserCanceled, + /// + /// The user canceled the operation. + /// + UserCanceled, - /// - /// The operation timed out. - /// - Timeout, + /// + /// The operation timed out. + /// + Timeout, - /// - /// An unknown error occurred during the operation. - /// - UnknownError, - } + /// + /// An unknown error occurred during the operation. + /// + UnknownError, +} +/// +/// Represents the result of a browser-based login operation. +/// +public class BrowserResult +{ /// - /// Represents the result of a browser-based login operation. + /// Gets the status of the browser operation. /// - public class BrowserResult - { - /// - /// Gets the status of the browser operation. - /// - public BrowserStatus status { get; } + public BrowserStatus Status { get; } - /// - /// Gets the callback URL returned from the browser operation. - /// - public string callbackUrl { get; } + /// + /// Gets the callback URL returned from the browser operation. + /// + public string CallbackUrl { get; } - /// - /// Gets the error message, if any, from the browser operation. - /// - public string error { get; } + /// + /// Gets the error message, if any, from the browser operation. + /// + public string Error { get; } - /// - /// Initializes a new instance of the class with the specified status and callback URL. - /// - /// The status of the browser operation. - /// The callback URL returned from the browser operation. - public BrowserResult(BrowserStatus status, string callbackUrl) - { - this.status = status; - this.callbackUrl = callbackUrl; - } + /// + /// Initializes a new instance of the class with the specified status and callback URL. + /// + /// The status of the browser operation. + /// The callback URL returned from the browser operation. + public BrowserResult(BrowserStatus status, string callbackUrl) + { + this.Status = status; + this.CallbackUrl = callbackUrl; + } - /// - /// Initializes a new instance of the class with the specified status, callback URL, and error message. - /// - /// The status of the browser operation. - /// The callback URL returned from the browser operation. - /// The error message from the browser operation. - public BrowserResult(BrowserStatus status, string callbackUrl, string error) - { - this.status = status; - this.callbackUrl = callbackUrl; - this.error = error; - } + /// + /// Initializes a new instance of the class with the specified status, callback URL, and error message. + /// + /// The status of the browser operation. + /// The callback URL returned from the browser operation. + /// The error message from the browser operation. + public BrowserResult(BrowserStatus status, string callbackUrl, string error) + { + this.Status = status; + this.CallbackUrl = callbackUrl; + this.Error = error; } } diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/InAppWallet.Types.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/InAppWallet.Types.cs new file mode 100644 index 00000000..dfe71e52 --- /dev/null +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/InAppWallet.Types.cs @@ -0,0 +1,71 @@ +using Newtonsoft.Json; + +namespace Thirdweb; + +/// +/// Specifies the authentication providers available for the in-app wallet. +/// +public enum AuthProvider +{ + Default, + Google, + Apple, + Facebook, + JWT, + AuthEndpoint, + Discord, + Farcaster, + Telegram, + Siwe, + Line, + Guest, + X, + TikTok, + Epic, + Coinbase, + Github, + Twitch, + Steam, + Backend, +} + +/// +/// Represents a linked account. +/// +public struct LinkedAccount +{ + /// + /// The auth provider method used to create or link this account. + /// + [JsonProperty("type")] + public string Type { get; set; } + + /// + /// Additional details about the linked account. + /// + [JsonProperty("details")] + public LinkedAccountDetails Details { get; set; } + + /// + /// The email, address, phone and id related to the linked account, where applicable. + /// + public struct LinkedAccountDetails + { + [JsonProperty("email")] + public string Email { get; set; } + + [JsonProperty("name")] + public string Address { get; set; } + + [JsonProperty("phone")] + public string Phone { get; set; } + + [JsonProperty("id")] + public string Id { get; set; } + } + + public override readonly string ToString() + { + return JsonConvert.SerializeObject(this); + } +} diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/InAppWallet.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/InAppWallet.cs index 86cd022a..231054a2 100644 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/InAppWallet.cs +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/InAppWallet.cs @@ -1,339 +1,72 @@ -using System.Web; -using Nethereum.Signer; using Thirdweb.EWS; -namespace Thirdweb +namespace Thirdweb; + +/// +/// Represents an in-app wallet that supports email, phone, social, SIWE and custom authentication. +/// +public class InAppWallet : EcosystemWallet { - /// - /// Specifies the authentication providers available for the in-app wallet. - /// - public enum AuthProvider + public override string WalletId => "inApp"; + + internal InAppWallet( + ThirdwebClient client, + EmbeddedWallet embeddedWallet, + IThirdwebHttpClient httpClient, + string email, + string phoneNumber, + string authProvider, + IThirdwebWallet siweSigner, + string address, + string walletSecret, + ExecutionMode executionMode, + string delegationContractAddress + ) + : base(null, null, client, embeddedWallet, httpClient, email, phoneNumber, authProvider, siweSigner, walletSecret, executionMode, delegationContractAddress) { - Default, - Google, - Apple, - Facebook, - JWT, - AuthEndpoint + this.Address = address; } /// - /// Represents an in-app wallet that extends the functionality of a private key wallet. + /// Creates a new instance of the class. /// - public class InAppWallet : PrivateKeyWallet + /// The Thirdweb client instance. + /// The email address for Email OTP authentication. + /// The phone number for Phone OTP authentication. + /// The authentication provider to use. + /// The path to the storage directory. + /// The SIWE signer wallet for SIWE authentication. + /// The wallet secret for backend authentication. + /// The auth token to use for the session. This will automatically connect using a raw thirdweb auth token. + /// The execution mode for the wallet. EOA represents traditional direct calls, EIP7702 represents upgraded account self sponsored calls, and EIP7702Sponsored represents upgraded account calls with managed/sponsored execution. + /// A task that represents the asynchronous operation. The task result contains the created in-app wallet. + /// Thrown when required parameters are not provided. + public static async Task Create( + ThirdwebClient client, + string email = null, + string phoneNumber = null, + AuthProvider authProvider = Thirdweb.AuthProvider.Default, + string storageDirectoryPath = null, + IThirdwebWallet siweSigner = null, + string walletSecret = null, + string twAuthTokenOverride = null, + ExecutionMode executionMode = ExecutionMode.EOA + ) { - internal EmbeddedWallet _embeddedWallet; - internal string _email; - internal string _phoneNumber; - internal string _authProvider; - - internal InAppWallet(ThirdwebClient client, string email, string phoneNumber, string authProvider, EmbeddedWallet embeddedWallet, EthECKey ecKey) - : base(client, ecKey) - { - _email = email; - _phoneNumber = phoneNumber; - _embeddedWallet = embeddedWallet; - _authProvider = authProvider; - } - - /// - /// Creates a new instance of the class. - /// - /// The Thirdweb client instance. - /// The email address for authentication. - /// The phone number for authentication. - /// The authentication provider to use. - /// The path to the storage directory. - /// A task that represents the asynchronous operation. The task result contains the created in-app wallet. - /// Thrown when required parameters are not provided. - public static async Task Create( - ThirdwebClient client, - string email = null, - string phoneNumber = null, - AuthProvider authprovider = AuthProvider.Default, - string storageDirectoryPath = null - ) - { - if (string.IsNullOrEmpty(email) && string.IsNullOrEmpty(phoneNumber) && authprovider == AuthProvider.Default) - { - throw new ArgumentException("Email, Phone Number, or OAuth Provider must be provided to login."); - } - - var authproviderStr = authprovider switch - { - AuthProvider.Google => "Google", - AuthProvider.Apple => "Apple", - AuthProvider.Facebook => "Facebook", - AuthProvider.JWT => "JWT", - AuthProvider.AuthEndpoint => "AuthEndpoint", - AuthProvider.Default => string.IsNullOrEmpty(email) ? "PhoneOTP" : "EmailOTP", - _ => throw new ArgumentException("Invalid AuthProvider"), - }; - - var embeddedWallet = new EmbeddedWallet(client, storageDirectoryPath); - EthECKey ecKey; - try - { - if (!string.IsNullOrEmpty(authproviderStr)) { } - var user = await embeddedWallet.GetUserAsync(email, authproviderStr); - ecKey = new EthECKey(user.Account.PrivateKey); - } - catch - { - ecKey = null; - } - return new InAppWallet(client, email, phoneNumber, authproviderStr, embeddedWallet, ecKey); - } - - /// - /// Disconnects the wallet. - /// - /// A task representing the asynchronous operation. - public override async Task Disconnect() - { - await base.Disconnect(); - await _embeddedWallet.SignOutAsync(); - } - - #region OAuth2 Flow - - /// - /// Logs in with OAuth2. - /// - /// Indicates if the login is from a mobile device. - /// The action to open the browser. - /// The mobile redirect scheme. - /// The browser instance. - /// The cancellation token. - /// A task representing the asynchronous operation. The task result contains the login result. - /// Thrown when required parameters are not provided. - /// Thrown when the operation is canceled. - /// Thrown when the operation times out. - public virtual async Task LoginWithOauth( - bool isMobile, - Action browserOpenAction, - string mobileRedirectScheme = "thirdweb://", - IThirdwebBrowser browser = null, - CancellationToken cancellationToken = default - ) - { - if (isMobile && string.IsNullOrEmpty(mobileRedirectScheme)) - { - throw new ArgumentNullException(nameof(mobileRedirectScheme), "Mobile redirect scheme cannot be null or empty on this platform."); - } - - var platform = Client.HttpClient?.Headers?["x-sdk-name"] == "UnitySDK_WebGL" ? "web" : "dotnet"; - var redirectUrl = isMobile ? mobileRedirectScheme : "http://localhost:8789/"; - var loginUrl = await _embeddedWallet.FetchHeadlessOauthLoginLinkAsync(_authProvider, platform); - loginUrl = platform == "web" ? loginUrl : $"{loginUrl}?platform={platform}&redirectUrl={redirectUrl}&developerClientId={Client.ClientId}&authOption={_authProvider}"; - - browser ??= new InAppWalletBrowser(); - var browserResult = await browser.Login(Client, loginUrl, redirectUrl, browserOpenAction, cancellationToken); - switch (browserResult.status) - { - case BrowserStatus.Success: - break; - case BrowserStatus.UserCanceled: - throw new TaskCanceledException(browserResult.error ?? "LoginWithOauth was cancelled."); - case BrowserStatus.Timeout: - throw new TimeoutException(browserResult.error ?? "LoginWithOauth timed out."); - case BrowserStatus.UnknownError: - default: - throw new Exception($"Failed to login with {_authProvider}: {browserResult.status} | {browserResult.error}"); - } - var callbackUrl = - browserResult.status != BrowserStatus.Success - ? throw new Exception($"Failed to login with {_authProvider}: {browserResult.status} | {browserResult.error}") - : browserResult.callbackUrl; - - while (string.IsNullOrEmpty(callbackUrl)) - { - if (cancellationToken.IsCancellationRequested) - { - throw new TaskCanceledException("LoginWithOauth was cancelled."); - } - await Task.Delay(100, cancellationToken); - } - - var authResultJson = callbackUrl; - if (!authResultJson.StartsWith("{")) - { - var decodedUrl = HttpUtility.UrlDecode(callbackUrl); - Uri uri = new(decodedUrl); - var queryString = uri.Query; - var queryDict = HttpUtility.ParseQueryString(queryString); - authResultJson = queryDict["authResult"]; - } - - var res = await _embeddedWallet.SignInWithOauthAsync(_authProvider, authResultJson, null); - if (res.User == null) - { - throw new Exception("Failed to login with OAuth2"); - } - _ecKey = new EthECKey(res.User.Account.PrivateKey); - return await GetAddress(); - } - - #endregion - - #region OTP Flow - - /// - /// Sends an OTP to the user's email or phone number. - /// - /// A task representing the asynchronous operation. - /// Thrown when email or phone number is not provided. - public async Task SendOTP() - { - if (string.IsNullOrEmpty(_email) && string.IsNullOrEmpty(_phoneNumber)) - { - throw new Exception("Email or Phone Number is required for OTP login"); - } - - try - { - if (_email != null) - { - (var isNewUser, var isNewDevice, var needsRecoveryCode) = await _embeddedWallet.SendOtpEmailAsync(_email); - } - else if (_phoneNumber != null) - { - (var isNewUser, var isNewDevice, var needsRecoveryCode) = await _embeddedWallet.SendOtpPhoneAsync(_phoneNumber); - } - else - { - throw new Exception("Email or Phone Number must be provided to login."); - } - } - catch (Exception e) - { - throw new Exception("Failed to send OTP email", e); - } - } - - /// - /// Submits the OTP for verification. - /// - /// The OTP to submit. - /// A task representing the asynchronous operation. The task result contains the address and a boolean indicating if retry is possible. - /// Thrown when OTP is not provided. - /// Thrown when email or phone number is not provided. - public async Task<(string, bool)> SubmitOTP(string otp) - { - if (string.IsNullOrEmpty(otp)) - { - throw new ArgumentNullException(nameof(otp), "OTP cannot be null or empty."); - } - - if (string.IsNullOrEmpty(_email) && string.IsNullOrEmpty(_phoneNumber)) - { - throw new Exception("Email or Phone Number is required for OTP login"); - } - - var res = _email == null ? await _embeddedWallet.VerifyPhoneOtpAsync(_phoneNumber, otp, null) : await _embeddedWallet.VerifyOtpAsync(_email, otp, null); - if (res.User == null) - { - return (null, res.CanRetry); - } - else - { - _ecKey = new EthECKey(res.User.Account.PrivateKey); - return (await GetAddress(), false); - } - } - - /// - /// Gets the email associated with the in-app wallet. - /// - /// A task representing the asynchronous operation. The task result contains the email address. - public Task GetEmail() - { - return Task.FromResult(_email); - } - - /// - /// Gets the phone number associated with the in-app wallet. - /// - /// A task representing the asynchronous operation. The task result contains the phone number. - public Task GetPhoneNumber() - { - return Task.FromResult(_phoneNumber); - } - - #endregion - - #region JWT Flow - - /// - /// Logs in with a JWT. - /// - /// The JWT to use for authentication. - /// The encryption key to use. - /// The optional recovery code. - /// A task representing the asynchronous operation. The task result contains the login result. - /// Thrown when JWT or encryption key is not provided. - /// Thrown when the login fails. - public async Task LoginWithJWT(string jwt, string encryptionKey, string recoveryCode = null) - { - if (string.IsNullOrEmpty(jwt)) - { - throw new ArgumentException(nameof(jwt), "JWT cannot be null or empty."); - } - - if (string.IsNullOrEmpty(encryptionKey)) - { - throw new ArgumentException(nameof(encryptionKey), "Encryption key cannot be null or empty."); - } - - var res = await _embeddedWallet.SignInWithJwtAsync(jwt, encryptionKey, recoveryCode); - - if (res.User == null) - { - throw new Exception("Failed to login with JWT"); - } - - _ecKey = new EthECKey(res.User.Account.PrivateKey); - - return await GetAddress(); - } - - #endregion - - #region Auth Endpoint Flow - - /// - /// Logs in with an authentication endpoint. - /// - /// The payload to use for authentication. - /// The encryption key to use. - /// The optional recovery code. - /// A task representing the asynchronous operation. The task result contains the login result. - /// Thrown when payload or encryption key is not provided. - /// Thrown when the login fails. - public async Task LoginWithAuthEndpoint(string payload, string encryptionKey, string recoveryCode = null) - { - if (string.IsNullOrEmpty(payload)) - { - throw new ArgumentException(nameof(payload), "Payload cannot be null or empty."); - } - - if (string.IsNullOrEmpty(encryptionKey)) - { - throw new ArgumentException(nameof(encryptionKey), "Encryption key cannot be null or empty."); - } - - var res = await _embeddedWallet.SignInWithAuthEndpointAsync(payload, encryptionKey, recoveryCode); - - if (res.User == null) - { - throw new Exception("Failed to login with Auth Endpoint"); - } - - _ecKey = new EthECKey(res.User.Account.PrivateKey); - - return await GetAddress(); - } - - #endregion + storageDirectoryPath ??= Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "Thirdweb", "InAppWallet"); + var ecoWallet = await Create(client, null, null, email, phoneNumber, authProvider, storageDirectoryPath, siweSigner, walletSecret, twAuthTokenOverride, executionMode); + return new InAppWallet( + ecoWallet.Client, + ecoWallet.EmbeddedWallet, + ecoWallet.HttpClient, + ecoWallet.Email, + ecoWallet.PhoneNumber, + ecoWallet.AuthProvider, + ecoWallet.SiweSigner, + ecoWallet.Address, + ecoWallet.WalletSecret, + ecoWallet.ExecutionMode, + ecoWallet.DelegationContractAddress + ); } } diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/InAppWalletBrowser.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/InAppWalletBrowser.cs index d00018a7..04f7e888 100644 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/InAppWalletBrowser.cs +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/InAppWalletBrowser.cs @@ -1,151 +1,121 @@ using System.Net; -namespace Thirdweb +namespace Thirdweb; + +/// +/// Represents an in-app browser for handling wallet login. +/// +public class InAppWalletBrowser : IThirdwebBrowser { + private TaskCompletionSource _taskCompletionSource; + private static readonly HttpListener _httpListener = new(); + + private readonly string _redirectHtmlOverride; + + public InAppWalletBrowser(string redirectHtmlOverride = null) + { + _httpListener.Prefixes.Add("http://localhost:8080/"); + this._redirectHtmlOverride = redirectHtmlOverride; + } + /// - /// Represents an in-app browser for handling wallet login. + /// Initiates a login process using the in-app browser. /// - public class InAppWalletBrowser : IThirdwebBrowser + /// The Thirdweb client instance. + /// The URL to initiate the login process. + /// The URL to redirect to after login. + /// An action to open the browser with the login URL. + /// Optional cancellation token to cancel the operation. + /// A task representing the asynchronous operation. The task result contains the login result. + public async Task Login(ThirdwebClient client, string loginUrl, string redirectUrl, Action browserOpenAction, CancellationToken cancellationToken = default) { - private TaskCompletionSource _taskCompletionSource; - private static readonly HttpListener httpListener = new(); - - private readonly string closePageResponse = - @" - - - - - -
- DONE! -
- You can close this tab/window now. -
-
- - "; - - /// - /// Initiates a login process using the in-app browser. - /// - /// The Thirdweb client instance. - /// The URL to initiate the login process. - /// The URL to redirect to after login. - /// An action to open the browser with the login URL. - /// Optional cancellation token to cancel the operation. - /// A task representing the asynchronous operation. The task result contains the login result. - public async Task Login(ThirdwebClient client, string loginUrl, string redirectUrl, Action browserOpenAction, CancellationToken cancellationToken = default) + this._taskCompletionSource = new TaskCompletionSource(); + + _ = cancellationToken.Register(() => { - _taskCompletionSource = new TaskCompletionSource(); + _ = (this._taskCompletionSource?.TrySetCanceled()); - cancellationToken.Register(() => - { - _taskCompletionSource?.TrySetCanceled(); - StopHttpListener(); - }); + StopHttpListener(); + }); - try - { - redirectUrl = AddForwardSlashIfNecessary(redirectUrl); - if (httpListener.Prefixes.Count == 0 || !httpListener.Prefixes.Contains(redirectUrl)) - { - httpListener.Prefixes.Clear(); - httpListener.Prefixes.Add(redirectUrl); - } - httpListener.Start(); - _ = httpListener.BeginGetContext(IncomingHttpRequest, httpListener); - - browserOpenAction.Invoke(loginUrl); - - var completedTask = await Task.WhenAny(_taskCompletionSource.Task, Task.Delay(TimeSpan.FromSeconds(60), cancellationToken)); - return completedTask == _taskCompletionSource.Task ? await _taskCompletionSource.Task : new BrowserResult(BrowserStatus.Timeout, null, "The operation timed out."); - } - catch (TaskCanceledException) - { - return new BrowserResult(BrowserStatus.UserCanceled, null, "The operation was cancelled."); - } - catch (Exception ex) - { - return new BrowserResult(BrowserStatus.UnknownError, null, $"An error occurred: {ex.Message}"); - } - finally + try + { + redirectUrl = AddForwardSlashIfNecessary(redirectUrl); + if (_httpListener.Prefixes.Count == 0 || !_httpListener.Prefixes.Contains(redirectUrl)) { - StopHttpListener(); + _httpListener.Prefixes.Clear(); + _httpListener.Prefixes.Add(redirectUrl); } + _httpListener.Start(); + _ = _httpListener.BeginGetContext(this.IncomingHttpRequest, _httpListener); + + browserOpenAction.Invoke(loginUrl); + + var completedTask = await Task.WhenAny(this._taskCompletionSource.Task, Task.Delay(TimeSpan.FromSeconds(120), cancellationToken)); + return completedTask == this._taskCompletionSource.Task ? await this._taskCompletionSource.Task : new BrowserResult(BrowserStatus.Timeout, null, "The operation timed out."); } + catch (TaskCanceledException) + { + return new BrowserResult(BrowserStatus.UserCanceled, null, "The operation was cancelled."); + } + catch (Exception ex) + { + return new BrowserResult(BrowserStatus.UnknownError, null, $"An error occurred: {ex.Message}"); + } + finally + { + StopHttpListener(); + } + } - /// - /// Stops the HTTP listener. - /// - private void StopHttpListener() + /// + /// Stops the HTTP listener. + /// + private static void StopHttpListener() + { + if (_httpListener != null && _httpListener.IsListening) { - if (httpListener != null && httpListener.IsListening) - { - httpListener.Stop(); - } + _httpListener.Stop(); } + } - /// - /// Handles incoming HTTP requests. - /// - /// The result of the asynchronous operation. - private void IncomingHttpRequest(IAsyncResult result) + /// + /// Handles incoming HTTP requests. + /// + /// The result of the asynchronous operation. + private void IncomingHttpRequest(IAsyncResult result) + { + var httpListener = (HttpListener)result.AsyncState; + if (!httpListener.IsListening) { - var httpListener = (HttpListener)result.AsyncState; - if (!httpListener.IsListening) - { - return; - } + return; + } - var httpContext = httpListener.EndGetContext(result); - var httpRequest = httpContext.Request; - var httpResponse = httpContext.Response; - var buffer = System.Text.Encoding.UTF8.GetBytes(closePageResponse); + var httpContext = httpListener.EndGetContext(result); + var httpRequest = httpContext.Request; + var httpResponse = httpContext.Response; + var buffer = System.Text.Encoding.UTF8.GetBytes(this._redirectHtmlOverride ?? Constants.REDIRECT_HTML); - httpResponse.ContentLength64 = buffer.Length; - var output = httpResponse.OutputStream; - output.Write(buffer, 0, buffer.Length); - output.Close(); + httpResponse.ContentLength64 = buffer.Length; + var output = httpResponse.OutputStream; + output.Write(buffer, 0, buffer.Length); + output.Close(); - _taskCompletionSource.SetResult(new BrowserResult(BrowserStatus.Success, httpRequest.Url.ToString())); - } + this._taskCompletionSource.SetResult(new BrowserResult(BrowserStatus.Success, httpRequest.Url.ToString())); + } - /// - /// Adds a forward slash to the URL if necessary. - /// - /// The URL to check. - /// The URL with a forward slash added if necessary. - private string AddForwardSlashIfNecessary(string url) + /// + /// Adds a forward slash to the URL if necessary. + /// + /// The URL to check. + /// The URL with a forward slash added if necessary. + private static string AddForwardSlashIfNecessary(string url) + { + var forwardSlash = "/"; + if (!url.EndsWith(forwardSlash)) { - string forwardSlash = "/"; - if (!url.EndsWith(forwardSlash)) - { - url += forwardSlash; - } - return url; + url += forwardSlash; } + return url; } } diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/Thirdweb.EWS/EmbeddedWallet.Authentication/Server.Types.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/Thirdweb.EWS/EmbeddedWallet.Authentication/Server.Types.cs new file mode 100644 index 00000000..80438380 --- /dev/null +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/Thirdweb.EWS/EmbeddedWallet.Authentication/Server.Types.cs @@ -0,0 +1,228 @@ +using System.Runtime.Serialization; + +namespace Thirdweb.EWS; + +internal partial class Server +{ + internal class VerifyResult + { + internal VerifyResult(string authProvider, bool isNewUser, string authToken, string walletUserId, string email, string phoneNumber, string authIdentifier) + { + this.AuthProvider = authProvider; + this.IsNewUser = isNewUser; + this.AuthToken = authToken; + this.WalletUserId = walletUserId; + this.Email = email; + this.PhoneNumber = phoneNumber; + this.AuthIdentifier = authIdentifier; + } + + internal string AuthProvider { get; } + internal bool IsNewUser { get; } + internal string AuthToken { get; } + internal string WalletUserId { get; } + internal string Email { get; } + internal string PhoneNumber { get; } + internal string AuthIdentifier { get; } + } + + [DataContract] + internal class AccountConnectResponse + { + [DataMember(Name = "linkedAccounts", IsRequired = true)] + public List LinkedAccounts { get; set; } + } + + [DataContract] + public class LinkedAccount + { + [DataMember(Name = "type", IsRequired = true)] + public string Type { get; set; } + + [DataMember(Name = "details", IsRequired = true)] + public LinkedAccountDetails Details { get; set; } + + [DataContract] + public class LinkedAccountDetails + { + [DataMember(Name = "email", EmitDefaultValue = false)] + public string Email { get; set; } + + [DataMember(Name = "address", EmitDefaultValue = false)] + public string Address { get; set; } + + [DataMember(Name = "phone", EmitDefaultValue = false)] + public string Phone { get; set; } + + [DataMember(Name = "id", EmitDefaultValue = false)] + public string Id { get; set; } + } + } + + [DataContract] + private class SendEmailOtpReturnType + { + [DataMember(Name = "email")] + internal string Email { get; set; } + } + + [DataContract] + private class SendPhoneOtpReturnType + { + [DataMember(Name = "phone")] + internal string Phone { get; set; } + } + +#pragma warning disable CS0169, CS8618, IDE0051 // Deserialization will construct the following classes. + [DataContract] + private class AuthVerifiedTokenReturnType + { + [DataMember(Name = "verifiedToken")] + internal VerifiedTokenType VerifiedToken { get; set; } + + [DataMember(Name = "verifiedTokenJwtString")] + internal string VerifiedTokenJwtString { get; set; } + + [DataContract] + internal class VerifiedTokenType + { + [DataMember(Name = "authDetails")] + internal AuthDetailsType AuthDetails { get; set; } + + [DataMember(Name = "authProvider")] + internal string AuthProvider { get; set; } + + [DataMember(Name = "developerClientId")] + private string _developerClientId; + + [DataMember(Name = "isNewUser")] + internal bool IsNewUser { get; set; } + + [DataMember(Name = "rawToken")] + private string _rawToken; + + [DataMember(Name = "userId")] + private string _userId; + } + } + + [DataContract] + private class HttpErrorWithMessage + { + [DataMember(Name = "error")] + internal string Error { get; set; } = ""; + + [DataMember(Name = "message")] + internal string Message { get; set; } = ""; + } + + [DataContract] + private class SharesGetResponse + { + [DataMember(Name = "authShare")] + internal string AuthShare { get; set; } + + [DataMember(Name = "maybeEncryptedRecoveryShares")] + internal string[] MaybeEncryptedRecoveryShares { get; set; } + } + + [DataContract] + internal class UserWallet + { + [DataMember(Name = "status")] + internal string Status { get; set; } + + [DataMember(Name = "isNewUser")] + internal bool IsNewUser { get; set; } + + [DataMember(Name = "walletUserId")] + internal string WalletUserId { get; set; } + + [DataMember(Name = "recoveryShareManagement")] + internal string RecoveryShareManagement { get; set; } + + [DataMember(Name = "storedToken")] + internal StoredTokenType StoredToken { get; set; } + } + + [DataContract] + internal class IdTokenResponse + { + [DataMember(Name = "token")] + internal string Token { get; set; } + + [DataMember(Name = "identityId")] + internal string IdentityId { get; set; } + + [DataMember(Name = "lambdaToken")] + internal string LambdaToken { get; set; } + } + + [DataContract] + private class RecoverySharePasswordResponse + { + [DataMember(Name = "body")] + internal string Body { get; set; } + + [DataMember(Name = "recoveryShareEncKey")] + internal string RecoverySharePassword { get; set; } + } + + [DataContract] + internal class AuthResultType + { + [DataMember(Name = "storedToken")] + internal StoredTokenType StoredToken { get; set; } + } + + [DataContract] + internal class StoredTokenType + { + [DataMember(Name = "jwtToken")] + internal string JwtToken { get; set; } + + [DataMember(Name = "authProvider")] + internal string AuthProvider { get; set; } + + [DataMember(Name = "authDetails")] + internal AuthDetailsType AuthDetails { get; set; } + + [DataMember(Name = "developerClientId")] + internal string DeveloperClientId { get; set; } + + [DataMember(Name = "cookieString")] + internal string CookieString { get; set; } + + [DataMember(Name = "shouldStoreCookieString")] + internal bool ShouldStoreCookieString { get; set; } + + [DataMember(Name = "isNewUser")] + internal bool IsNewUser { get; set; } + } + + [DataContract] + internal class AuthDetailsType + { + [DataMember(Name = "phoneNumber")] + internal string PhoneNumber { get; set; } + + [DataMember(Name = "email")] + internal string Email { get; set; } + + [DataMember(Name = "userWalletId")] + internal string UserWalletId { get; set; } + + [DataMember(Name = "authIdentifier")] + internal string AuthIdentifier { get; set; } + + [DataMember(Name = "recoveryCode")] + internal string RecoveryCode { get; set; } + + [DataMember(Name = "recoveryShareManagement")] + internal string RecoveryShareManagement { get; set; } + } + +#pragma warning restore CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. +#pragma warning restore CS0169 // The field 'Server.*' is never used +#pragma warning restore IDE0051 // The field 'Server.*' is unused +} diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/Thirdweb.EWS/EmbeddedWallet.Authentication/Server.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/Thirdweb.EWS/EmbeddedWallet.Authentication/Server.cs new file mode 100644 index 00000000..384e9b45 --- /dev/null +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/Thirdweb.EWS/EmbeddedWallet.Authentication/Server.cs @@ -0,0 +1,378 @@ +using System.Net.Http.Headers; +using Newtonsoft.Json; + +namespace Thirdweb.EWS; + +internal abstract class ServerBase +{ + internal abstract Task> UnlinkAccountAsync(string currentAccountToken, Server.LinkedAccount linkedAccount); + internal abstract Task> LinkAccountAsync(string currentAccountToken, string authTokenToConnect); + internal abstract Task> GetLinkedAccountsAsync(string currentAccountToken); + + internal abstract Task<(string authShare, string recoveryShare)> FetchAuthAndRecoverySharesAsync(string authToken); + internal abstract Task FetchAuthShareAsync(string authToken); + + internal abstract Task FetchSiwePayloadAsync(string address, string chainId); + internal abstract Task VerifySiweAsync(LoginPayloadData payload, string signature); + + internal abstract Task VerifyBackendAsync(string walletSecret); + + internal abstract Task VerifyGuestAsync(string sessionId); + + internal abstract Task SendEmailOtpAsync(string emailAddress); + internal abstract Task VerifyEmailOtpAsync(string emailAddress, string otp); + + internal abstract Task SendPhoneOtpAsync(string phoneNumber); + internal abstract Task VerifyPhoneOtpAsync(string phoneNumber, string otp); + + internal abstract Task VerifyJwtAsync(string jwtToken); + + internal abstract Task FetchHeadlessOauthLoginLinkAsync(string authProvider, string platform); + internal abstract Server.VerifyResult VerifyOAuthAsync(string authResultStr); + + internal abstract Task VerifyAuthEndpointAsync(string payload); +} + +internal partial class Server : ServerBase +{ + private const string ROOT_URL = "https://embedded-wallet.thirdweb.com"; + private const string API_ROOT_PATH_2024 = "/api/2024-05-05"; + private const string API_ROOT_PATH_2023 = "/api/2023-10-20"; + + private static readonly MediaTypeHeaderValue _jsonContentType = MediaTypeHeaderValue.Parse("application/json"); + private readonly IThirdwebHttpClient _httpClient; + + private readonly string _clientId; + + internal Server(ThirdwebClient client, IThirdwebHttpClient httpClient) + { + this._clientId = client.ClientId; + this._httpClient = httpClient; + } + + // account/disconnect + internal override async Task> UnlinkAccountAsync(string currentAccountToken, LinkedAccount linkedAccount) + { + var uri = MakeUri2024("/account/disconnect"); + var request = new HttpRequestMessage(HttpMethod.Post, uri) { Content = MakeHttpContent(linkedAccount) }; + var response = await this.SendHttpWithAuthAsync(request, currentAccountToken).ConfigureAwait(false); + await CheckStatusCodeAsync(response).ConfigureAwait(false); + + var res = await DeserializeAsync(response).ConfigureAwait(false); + return res == null || res.LinkedAccounts == null || res.LinkedAccounts.Count == 0 ? throw new InvalidOperationException("No linked accounts returned") : res.LinkedAccounts; + } + + // account/connect + internal override async Task> LinkAccountAsync(string currentAccountToken, string authTokenToConnect) + { + var uri = MakeUri2024("/account/connect"); + var request = new HttpRequestMessage(HttpMethod.Post, uri) { Content = MakeHttpContent(new { accountAuthTokenToConnect = authTokenToConnect }) }; + var response = await this.SendHttpWithAuthAsync(request, currentAccountToken).ConfigureAwait(false); + await CheckStatusCodeAsync(response).ConfigureAwait(false); + + var res = await DeserializeAsync(response).ConfigureAwait(false); + return res == null || res.LinkedAccounts == null || res.LinkedAccounts.Count == 0 ? throw new InvalidOperationException("No linked accounts returned") : res.LinkedAccounts; + } + + // accounts GET + internal override async Task> GetLinkedAccountsAsync(string currentAccountToken) + { + var uri = MakeUri2024("/accounts"); + var response = await this.SendHttpWithAuthAsync(uri, currentAccountToken).ConfigureAwait(false); + await CheckStatusCodeAsync(response).ConfigureAwait(false); + + var res = await DeserializeAsync(response).ConfigureAwait(false); + return res == null || res.LinkedAccounts == null || res.LinkedAccounts.Count == 0 ? new List() : res.LinkedAccounts; + } + + // embedded-wallet/embedded-wallet-shares GET + internal override async Task<(string authShare, string recoveryShare)> FetchAuthAndRecoverySharesAsync(string authToken) + { + var sharesGetResponse = await this.FetchRemoteSharesAsync(authToken, true).ConfigureAwait(false); + var authShare = sharesGetResponse.AuthShare ?? throw new InvalidOperationException("Server failed to return auth share"); + var encryptedRecoveryShare = sharesGetResponse.MaybeEncryptedRecoveryShares?.FirstOrDefault() ?? throw new InvalidOperationException("Server failed to return recovery share"); + return (authShare, encryptedRecoveryShare); + } + + // embedded-wallet/embedded-wallet-shares GET + internal override async Task FetchAuthShareAsync(string authToken) + { + var sharesGetResponse = await this.FetchRemoteSharesAsync(authToken, false).ConfigureAwait(false); + return sharesGetResponse.AuthShare ?? throw new InvalidOperationException("Server failed to return auth share"); + } + + // embedded-wallet/embedded-wallet-shares GET + private async Task FetchRemoteSharesAsync(string authToken, bool wantsRecoveryShare) + { + Dictionary queryParams = new() + { + { "getEncryptedAuthShare", "true" }, + { "getEncryptedRecoveryShare", wantsRecoveryShare ? "true" : "false" }, + { "useSealedSecret", "false" }, + }; + var uri = MakeUri2023("/embedded-wallet/embedded-wallet-shares", queryParams); + var response = await this.SendHttpWithAuthAsync(uri, authToken).ConfigureAwait(false); + await CheckStatusCodeAsync(response).ConfigureAwait(false); + var rv = await DeserializeAsync(response).ConfigureAwait(false); + return rv; + } + + // login/siwe + internal override async Task FetchSiwePayloadAsync(string address, string chainId) + { + var uri = MakeUri2024("/login/siwe", new Dictionary { { "address", address }, { "chainId", chainId } }); + var response = await this._httpClient.GetAsync(uri.ToString()).ConfigureAwait(false); + await CheckStatusCodeAsync(response).ConfigureAwait(false); + + return await DeserializeAsync(response).ConfigureAwait(false); + } + + internal override async Task VerifySiweAsync(LoginPayloadData payload, string signature) + { + var uri = MakeUri2024("/login/siwe/callback"); + var content = MakeHttpContent(new { signature, payload }); + ThirdwebHttpResponseMessage response; + response = await this._httpClient.PostAsync(uri.ToString(), content).ConfigureAwait(false); + await CheckStatusCodeAsync(response).ConfigureAwait(false); + + var authResult = await DeserializeAsync(response).ConfigureAwait(false); + return this.ToVerifyResult(authResult); + } + + // login/backend + internal override async Task VerifyBackendAsync(string walletSecret) + { + var uri = MakeUri2024("/login/backend"); + var content = MakeHttpContent(new { walletSecret }); + var response = await this._httpClient.PostAsync(uri.ToString(), content).ConfigureAwait(false); + await CheckStatusCodeAsync(response).ConfigureAwait(false); + + var authResult = await DeserializeAsync(response).ConfigureAwait(false); + return this.ToVerifyResult(authResult); + } + + // login/guest + internal override async Task VerifyGuestAsync(string sessionId) + { + var uri = MakeUri2024("/login/guest/callback"); + var content = MakeHttpContent(new { sessionId }); + var response = await this._httpClient.PostAsync(uri.ToString(), content).ConfigureAwait(false); + await CheckStatusCodeAsync(response).ConfigureAwait(false); + + var authResult = await DeserializeAsync(response).ConfigureAwait(false); + authResult.StoredToken.AuthDetails.AuthIdentifier = sessionId; + return this.ToVerifyResult(authResult); + } + + // login/oauthprovider + internal override Task FetchHeadlessOauthLoginLinkAsync(string authProvider, string platform) + { + return Task.FromResult(MakeUri2024($"/login/{authProvider.ToLower()}", new Dictionary { { "clientId", this._clientId }, { "platform", platform } }).ToString()); + } + + // login/email + internal override async Task SendEmailOtpAsync(string emailAddress) + { + var uri = MakeUri2024("/login/email"); + var content = MakeHttpContent(new { email = emailAddress }); + var response = await this._httpClient.PostAsync(uri.ToString(), content).ConfigureAwait(false); + await CheckStatusCodeAsync(response).ConfigureAwait(false); + + var result = await DeserializeAsync(response).ConfigureAwait(false); + return result.Email; + } + + // login/email/callback + internal override async Task VerifyEmailOtpAsync(string emailAddress, string otp) + { + var uri = MakeUri2024("/login/email/callback"); + var content = MakeHttpContent(new { email = emailAddress, code = otp }); + var response = await this._httpClient.PostAsync(uri.ToString(), content).ConfigureAwait(false); + await CheckStatusCodeAsync(response).ConfigureAwait(false); + + var authResult = await DeserializeAsync(response).ConfigureAwait(false); + return this.ToVerifyResult(authResult); + } + + // login/phone + internal override async Task SendPhoneOtpAsync(string phoneNumber) + { + var uri = MakeUri2024("/login/phone"); + var content = MakeHttpContent(new { phone = phoneNumber }); + var response = await this._httpClient.PostAsync(uri.ToString(), content).ConfigureAwait(false); + await CheckStatusCodeAsync(response).ConfigureAwait(false); + + var result = await DeserializeAsync(response).ConfigureAwait(false); + return result.Phone; + } + + // login/phone/callback + internal override async Task VerifyPhoneOtpAsync(string phoneNumber, string otp) + { + var uri = MakeUri2024("/login/phone/callback"); + var content = MakeHttpContent(new { phone = phoneNumber, code = otp }); + var response = await this._httpClient.PostAsync(uri.ToString(), content).ConfigureAwait(false); + await CheckStatusCodeAsync(response).ConfigureAwait(false); + + var authResult = await DeserializeAsync(response).ConfigureAwait(false); + return this.ToVerifyResult(authResult); + } + + // embedded-wallet/validate-custom-jwt + internal override async Task VerifyJwtAsync(string jwtToken) + { + var requestContent = new { jwt = jwtToken, developerClientId = this._clientId }; + var content = MakeHttpContent(requestContent); + var uri = MakeUri2023("/embedded-wallet/validate-custom-jwt"); + var response = await this._httpClient.PostAsync(uri.ToString(), content).ConfigureAwait(false); + await CheckStatusCodeAsync(response).ConfigureAwait(false); + + var authVerifiedToken = await DeserializeAsync(response).ConfigureAwait(false); + return new VerifyResult( + authVerifiedToken.VerifiedToken.AuthProvider, + authVerifiedToken.VerifiedToken.IsNewUser, + authVerifiedToken.VerifiedTokenJwtString, + authVerifiedToken.VerifiedToken.AuthDetails.UserWalletId, + authVerifiedToken.VerifiedToken.AuthDetails.Email, + authVerifiedToken.VerifiedToken.AuthDetails.PhoneNumber, + authVerifiedToken.VerifiedToken.AuthDetails.AuthIdentifier + ); + } + + // embedded-wallet/validate-custom-auth-endpoint + internal override async Task VerifyAuthEndpointAsync(string payload) + { + var requestContent = new { payload, developerClientId = this._clientId }; + var content = MakeHttpContent(requestContent); + var uri = MakeUri2023("/embedded-wallet/validate-custom-auth-endpoint"); + var response = await this._httpClient.PostAsync(uri.ToString(), content).ConfigureAwait(false); + await CheckStatusCodeAsync(response).ConfigureAwait(false); + + var authVerifiedToken = await DeserializeAsync(response).ConfigureAwait(false); + return new VerifyResult( + authVerifiedToken.VerifiedToken.AuthProvider, + authVerifiedToken.VerifiedToken.IsNewUser, + authVerifiedToken.VerifiedTokenJwtString, + authVerifiedToken.VerifiedToken.AuthDetails.UserWalletId, + authVerifiedToken.VerifiedToken.AuthDetails.Email, + authVerifiedToken.VerifiedToken.AuthDetails.PhoneNumber, + authVerifiedToken.VerifiedToken.AuthDetails.AuthIdentifier + ); + } + + internal override VerifyResult VerifyOAuthAsync(string authResultStr) + { + var authResult = JsonConvert.DeserializeObject(authResultStr); + return this.ToVerifyResult(authResult); + } + + #region Misc + + private VerifyResult ToVerifyResult(AuthResultType authResult) + { + return new VerifyResult( + authResult.StoredToken.AuthProvider, + authResult.StoredToken.IsNewUser, + authResult.StoredToken.CookieString, + authResult.StoredToken.AuthDetails.UserWalletId, + authResult.StoredToken.AuthDetails.Email, + authResult.StoredToken.AuthDetails.PhoneNumber, + authResult.StoredToken.AuthDetails.AuthIdentifier + ); + } + + private async Task SendHttpWithAuthAsync(HttpRequestMessage httpRequestMessage, string authToken) + { + this._httpClient.AddHeader("Authorization", $"Bearer embedded-wallet-token:{authToken}"); + + try + { + if (httpRequestMessage.Method == HttpMethod.Get) + { + return await this._httpClient.GetAsync(httpRequestMessage.RequestUri.ToString()).ConfigureAwait(false); + } + else if (httpRequestMessage.Method == HttpMethod.Post) + { + return await this._httpClient.PostAsync(httpRequestMessage.RequestUri.ToString(), httpRequestMessage.Content).ConfigureAwait(false); + } + else if (httpRequestMessage.Method == HttpMethod.Put) + { + return await this._httpClient.PutAsync(httpRequestMessage.RequestUri.ToString(), httpRequestMessage.Content).ConfigureAwait(false); + } + else + { + return httpRequestMessage.Method == HttpMethod.Delete + ? await this._httpClient.DeleteAsync(httpRequestMessage.RequestUri.ToString()).ConfigureAwait(false) + : throw new InvalidOperationException("Unsupported HTTP method"); + } + } + finally + { + this._httpClient.RemoveHeader("Authorization"); + } + } + + private async Task SendHttpWithAuthAsync(Uri uri, string authToken) + { + HttpRequestMessage httpRequestMessage = new(HttpMethod.Get, uri); + return await this.SendHttpWithAuthAsync(httpRequestMessage, authToken).ConfigureAwait(false); + } + + private static async Task CheckStatusCodeAsync(ThirdwebHttpResponseMessage response) + { + if (!response.IsSuccessStatusCode) + { + var error = await DeserializeAsync(response).ConfigureAwait(false); + throw new InvalidOperationException(string.IsNullOrEmpty(error.Error) ? error.Message : error.Error); + } + } + + private static async Task DeserializeAsync(ThirdwebHttpResponseMessage response) + { + JsonSerializer jsonSerializer = new(); + TextReader textReader = new StreamReader(await response.Content.ReadAsStreamAsync().ConfigureAwait(false)); + var rv = jsonSerializer.Deserialize(new JsonTextReader(textReader)); + return rv; + } + + private static Uri MakeUri2024(string path, IDictionary parameters = null) + { + UriBuilder b = new(ROOT_URL) { Path = API_ROOT_PATH_2024 + path }; + if (parameters != null && parameters.Any()) + { + var queryString = string.Join('&', parameters.Select((p) => $"{p.Key}={Uri.EscapeDataString(p.Value)}")); + b.Query = queryString; + } + return b.Uri; + } + + private static Uri MakeUri2023(string path, IDictionary parameters = null) + { + UriBuilder b = new(ROOT_URL) { Path = API_ROOT_PATH_2023 + path }; + if (parameters != null && parameters.Any()) + { + var queryString = string.Join('&', parameters.Select((p) => $"{p.Key}={Uri.EscapeDataString(p.Value)}")); + b.Query = queryString; + } + return b.Uri; + } + + private static StringContent MakeHttpContent(object data) + { + StringContent stringContent = new(Serialize(data)); + stringContent.Headers.ContentType = _jsonContentType; + return stringContent; + } + + private static string Serialize(object data) + { + JsonSerializer jsonSerializer = new() { NullValueHandling = NullValueHandling.Ignore }; + StringWriter stringWriter = new(); + jsonSerializer.Serialize(stringWriter, data); + var rv = stringWriter.ToString(); + + return rv; + } + + #endregion +} diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/Thirdweb.EWS/EmbeddedWallet.Storage/LocalStorage.Types.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/Thirdweb.EWS/EmbeddedWallet.Storage/LocalStorage.Types.cs new file mode 100644 index 00000000..6e0e331a --- /dev/null +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/Thirdweb.EWS/EmbeddedWallet.Storage/LocalStorage.Types.cs @@ -0,0 +1,49 @@ +using System.Runtime.Serialization; + +namespace Thirdweb.EWS; + +internal partial class LocalStorage : LocalStorageBase +{ + [DataContract] + internal class DataStorage + { + [field: DataMember(Name = "authToken")] + internal string AuthToken { get; } + + [field: DataMember(Name = "deviceShare")] + internal string DeviceShare { get; } + + [field: DataMember(Name = "emailAddress")] + internal string EmailAddress { get; } + + [field: DataMember(Name = "phoneNumber")] + internal string PhoneNumber { get; } + + [field: DataMember(Name = "walletUserId")] + internal string WalletUserId { get; } + + [field: DataMember(Name = "authProvider")] + internal string AuthProvider { get; } + + [field: DataMember(Name = "authIdentifier")] + internal string AuthIdentifier { get; } + + internal DataStorage(string authToken, string deviceShare, string emailAddress, string phoneNumber, string walletUserId, string authProvider, string authIdentifier) + { + this.AuthToken = authToken; + this.DeviceShare = deviceShare; + this.EmailAddress = emailAddress; + this.PhoneNumber = phoneNumber; + this.WalletUserId = walletUserId; + this.AuthProvider = authProvider; + this.AuthIdentifier = authIdentifier; + } + } + + [DataContract] + private class Storage + { + [DataMember] + internal DataStorage Data { get; set; } + } +} diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/Thirdweb.EWS/EmbeddedWallet.Storage/LocalStorage.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/Thirdweb.EWS/EmbeddedWallet.Storage/LocalStorage.cs new file mode 100644 index 00000000..8d396801 --- /dev/null +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/Thirdweb.EWS/EmbeddedWallet.Storage/LocalStorage.cs @@ -0,0 +1,60 @@ +using System.Runtime.Serialization.Json; + +namespace Thirdweb.EWS; + +internal abstract class LocalStorageBase +{ + internal abstract LocalStorage.DataStorage Data { get; } + + internal abstract Task SaveDataAsync(LocalStorage.DataStorage data); +} + +internal partial class LocalStorage : LocalStorageBase +{ + internal override DataStorage Data => this._storage.Data; + private readonly Storage _storage; + private readonly string _filePath; + + internal LocalStorage(string clientId, string storageDirectoryPath) + { + if (string.IsNullOrEmpty(storageDirectoryPath)) + { + throw new ArgumentException("Storage directory path is required", nameof(storageDirectoryPath)); + } + _ = Directory.CreateDirectory(storageDirectoryPath); + this._filePath = Path.Combine(storageDirectoryPath, $"{clientId}.txt"); + try + { + var json = File.ReadAllBytes(this._filePath); + DataContractJsonSerializer serializer = new(typeof(Storage)); + MemoryStream fin = new(json); + this._storage = (Storage)serializer.ReadObject(fin); + } + catch (Exception) + { + this._storage = new Storage(); + } + } + + private async Task UpdateDataAsync(Func fn) + { + if (fn()) + { + DataContractJsonSerializer serializer = new(typeof(Storage)); + MemoryStream fout = new(); + serializer.WriteObject(fout, this._storage); + await File.WriteAllBytesAsync(this._filePath, fout.ToArray()).ConfigureAwait(false); + return true; + } + return false; + } + + internal override Task SaveDataAsync(DataStorage data) + { + return this.UpdateDataAsync(() => + { + this._storage.Data = data; + return true; + }); + } +} diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/Thirdweb.EWS/EmbeddedWallet/EmbeddedWallet.AccountLinking.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/Thirdweb.EWS/EmbeddedWallet/EmbeddedWallet.AccountLinking.cs new file mode 100644 index 00000000..4cf9917c --- /dev/null +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/Thirdweb.EWS/EmbeddedWallet/EmbeddedWallet.AccountLinking.cs @@ -0,0 +1,30 @@ +namespace Thirdweb.EWS; + +internal partial class EmbeddedWallet +{ + public async Task> UnlinkAccountAsync(string currentAccountToken, LinkedAccount linkedAccount) + { + var serverLinkedAccount = new Server.LinkedAccount + { + Type = linkedAccount.Type, + Details = new Server.LinkedAccount.LinkedAccountDetails + { + Email = linkedAccount.Details.Email, + Address = linkedAccount.Details.Address, + Phone = linkedAccount.Details.Phone, + Id = linkedAccount.Details.Id, + }, + }; + return await this._server.UnlinkAccountAsync(currentAccountToken, serverLinkedAccount).ConfigureAwait(false); + } + + public async Task> LinkAccountAsync(string currentAccountToken, string authTokenToConnect) + { + return await this._server.LinkAccountAsync(currentAccountToken, authTokenToConnect).ConfigureAwait(false); + } + + public async Task> GetLinkedAccountsAsync(string currentAccountToken) + { + return await this._server.GetLinkedAccountsAsync(currentAccountToken).ConfigureAwait(false); + } +} diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/Thirdweb.EWS/EmbeddedWallet/EmbeddedWallet.AuthEndpoint.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/Thirdweb.EWS/EmbeddedWallet/EmbeddedWallet.AuthEndpoint.cs new file mode 100644 index 00000000..78cbfcf8 --- /dev/null +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/Thirdweb.EWS/EmbeddedWallet/EmbeddedWallet.AuthEndpoint.cs @@ -0,0 +1,9 @@ +namespace Thirdweb.EWS; + +internal partial class EmbeddedWallet +{ + public async Task SignInWithAuthEndpointAsync(string payload) + { + return await this._server.VerifyAuthEndpointAsync(payload).ConfigureAwait(false); + } +} diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/Thirdweb.EWS/EmbeddedWallet/EmbeddedWallet.Backend.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/Thirdweb.EWS/EmbeddedWallet/EmbeddedWallet.Backend.cs new file mode 100644 index 00000000..d31e1cd4 --- /dev/null +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/Thirdweb.EWS/EmbeddedWallet/EmbeddedWallet.Backend.cs @@ -0,0 +1,9 @@ +namespace Thirdweb.EWS; + +internal partial class EmbeddedWallet +{ + public async Task SignInWithBackendAsync(string walletSecret) + { + return await this._server.VerifyBackendAsync(walletSecret).ConfigureAwait(false); + } +} diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/Thirdweb.EWS/EmbeddedWallet/EmbeddedWallet.EmailOTP.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/Thirdweb.EWS/EmbeddedWallet/EmbeddedWallet.EmailOTP.cs new file mode 100644 index 00000000..c6d5729f --- /dev/null +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/Thirdweb.EWS/EmbeddedWallet/EmbeddedWallet.EmailOTP.cs @@ -0,0 +1,16 @@ +namespace Thirdweb.EWS; + +internal partial class EmbeddedWallet +{ + public async Task SendEmailOtpAsync(string emailAddress) + { + emailAddress = emailAddress.ToLower(); + _ = await this._server.SendEmailOtpAsync(emailAddress).ConfigureAwait(false); + } + + public async Task VerifyEmailOtpAsync(string emailAddress, string otp) + { + emailAddress = emailAddress.ToLower(); + return await this._server.VerifyEmailOtpAsync(emailAddress, otp).ConfigureAwait(false); + } +} diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/Thirdweb.EWS/EmbeddedWallet/EmbeddedWallet.Guest.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/Thirdweb.EWS/EmbeddedWallet/EmbeddedWallet.Guest.cs new file mode 100644 index 00000000..b0f12623 --- /dev/null +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/Thirdweb.EWS/EmbeddedWallet/EmbeddedWallet.Guest.cs @@ -0,0 +1,9 @@ +namespace Thirdweb.EWS; + +internal partial class EmbeddedWallet +{ + public async Task SignInWithGuestAsync(string sessionId) + { + return await this._server.VerifyGuestAsync(sessionId).ConfigureAwait(false); + } +} diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/Thirdweb.EWS/EmbeddedWallet/EmbeddedWallet.JWT.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/Thirdweb.EWS/EmbeddedWallet/EmbeddedWallet.JWT.cs new file mode 100644 index 00000000..08364544 --- /dev/null +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/Thirdweb.EWS/EmbeddedWallet/EmbeddedWallet.JWT.cs @@ -0,0 +1,9 @@ +namespace Thirdweb.EWS; + +internal partial class EmbeddedWallet +{ + public async Task SignInWithJwtAsync(string jwt) + { + return await this._server.VerifyJwtAsync(jwt).ConfigureAwait(false); + } +} diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/Thirdweb.EWS/EmbeddedWallet/EmbeddedWallet.Misc.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/Thirdweb.EWS/EmbeddedWallet/EmbeddedWallet.Misc.cs new file mode 100644 index 00000000..9a44fd73 --- /dev/null +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/Thirdweb.EWS/EmbeddedWallet/EmbeddedWallet.Misc.cs @@ -0,0 +1,19 @@ +namespace Thirdweb.EWS; + +internal partial class EmbeddedWallet +{ + internal LocalStorage.DataStorage GetSessionData() + { + return this._localStorage.Data ?? null; + } + + internal async void UpdateSessionData(LocalStorage.DataStorage data) + { + await this._localStorage.SaveDataAsync(data).ConfigureAwait(false); + } + + public async Task SignOutAsync() + { + await this._localStorage.SaveDataAsync(new LocalStorage.DataStorage(null, null, null, null, null, null, null)).ConfigureAwait(false); + } +} diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/Thirdweb.EWS/EmbeddedWallet/EmbeddedWallet.OAuth.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/Thirdweb.EWS/EmbeddedWallet/EmbeddedWallet.OAuth.cs new file mode 100644 index 00000000..49bca00f --- /dev/null +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/Thirdweb.EWS/EmbeddedWallet/EmbeddedWallet.OAuth.cs @@ -0,0 +1,14 @@ +namespace Thirdweb.EWS; + +internal partial class EmbeddedWallet +{ + public Server.VerifyResult SignInWithOauthAsync(string authResult) + { + return this._server.VerifyOAuthAsync(authResult); + } + + public async Task FetchHeadlessOauthLoginLinkAsync(string authProvider, string platform) + { + return await this._server.FetchHeadlessOauthLoginLinkAsync(authProvider, platform).ConfigureAwait(false); + } +} diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/Thirdweb.EWS/EmbeddedWallet/EmbeddedWallet.PhoneOTP.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/Thirdweb.EWS/EmbeddedWallet/EmbeddedWallet.PhoneOTP.cs new file mode 100644 index 00000000..a841bcfe --- /dev/null +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/Thirdweb.EWS/EmbeddedWallet/EmbeddedWallet.PhoneOTP.cs @@ -0,0 +1,14 @@ +namespace Thirdweb.EWS; + +internal partial class EmbeddedWallet +{ + public async Task SendPhoneOtpAsync(string phoneNumber) + { + _ = await this._server.SendPhoneOtpAsync(phoneNumber).ConfigureAwait(false); + } + + public async Task VerifyPhoneOtpAsync(string phoneNumber, string otp) + { + return await this._server.VerifyPhoneOtpAsync(phoneNumber, otp).ConfigureAwait(false); + } +} diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/Thirdweb.EWS/EmbeddedWallet/EmbeddedWallet.SIWE.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/Thirdweb.EWS/EmbeddedWallet/EmbeddedWallet.SIWE.cs new file mode 100644 index 00000000..a36d873b --- /dev/null +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/Thirdweb.EWS/EmbeddedWallet/EmbeddedWallet.SIWE.cs @@ -0,0 +1,16 @@ +using System.Numerics; + +namespace Thirdweb.EWS; + +internal partial class EmbeddedWallet +{ + public async Task SignInWithSiweAsync(IThirdwebWallet signer, BigInteger chainId) + { + var address = await signer.GetAddress().ConfigureAwait(false); + var payload = await this._server.FetchSiwePayloadAsync(address, chainId.ToString()).ConfigureAwait(false); + var payloadMsg = Utils.GenerateSIWE(payload); + var signature = await signer.PersonalSign(payloadMsg).ConfigureAwait(false); + + return await this._server.VerifySiweAsync(payload, signature).ConfigureAwait(false); + } +} diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/Thirdweb.EWS/EmbeddedWallet/EmbeddedWallet.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/Thirdweb.EWS/EmbeddedWallet/EmbeddedWallet.cs new file mode 100644 index 00000000..f32e841f --- /dev/null +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/Thirdweb.EWS/EmbeddedWallet/EmbeddedWallet.cs @@ -0,0 +1,40 @@ +namespace Thirdweb.EWS; + +internal partial class EmbeddedWallet +{ + private readonly LocalStorage _localStorage; + private readonly Server _server; + + public EmbeddedWallet(ThirdwebClient client, string storageDirectoryPath = null, string ecosystemId = null, string ecosystemPartnerId = null) + { + this._localStorage = new LocalStorage(client.ClientId, storageDirectoryPath); + + // Create a new client of same type with extra needed headers for EWS + var headers = client.HttpClient.Headers.ToDictionary(entry => entry.Key, entry => entry.Value); + var platform = client.HttpClient.Headers["x-sdk-platform"]; + var version = client.HttpClient.Headers["x-sdk-version"]; + if (!string.IsNullOrEmpty(client.ClientId)) + { + headers.Add("x-thirdweb-client-id", client.ClientId); + } + if (!string.IsNullOrEmpty(client.SecretKey)) + { + headers.Add("x-thirdweb-secret-key", client.SecretKey); + } + headers.Add("x-session-nonce", Guid.NewGuid().ToString()); + headers.Add("x-embedded-wallet-version", $"{platform}:{version}"); + if (!string.IsNullOrEmpty(ecosystemId)) + { + headers.Add("x-ecosystem-id", ecosystemId); + + if (!string.IsNullOrEmpty(ecosystemPartnerId)) + { + headers.Add("x-ecosystem-partner-id", ecosystemPartnerId); + } + } + + var ewsHttpClient = Utils.ReconstructHttpClient(client.HttpClient, headers); + + this._server = new Server(client, ewsHttpClient); + } +} diff --git a/Thirdweb/Thirdweb.Wallets/PrivateKeyWallet/PrivateKeyWallet.cs b/Thirdweb/Thirdweb.Wallets/PrivateKeyWallet/PrivateKeyWallet.cs deleted file mode 100644 index 42cff49f..00000000 --- a/Thirdweb/Thirdweb.Wallets/PrivateKeyWallet/PrivateKeyWallet.cs +++ /dev/null @@ -1,315 +0,0 @@ -using System.Numerics; -using System.Text; -using Nethereum.ABI.EIP712; -using Nethereum.Hex.HexConvertors.Extensions; -using Nethereum.Hex.HexTypes; -using Nethereum.Model; -using Nethereum.Signer; -using Nethereum.Signer.EIP712; -using Newtonsoft.Json; - -namespace Thirdweb -{ - /// - /// Represents a wallet that uses a private key for signing transactions and messages. - /// - public class PrivateKeyWallet : IThirdwebWallet - { - /// - /// Gets the Thirdweb client associated with the wallet. - /// - public ThirdwebClient Client { get; } - - /// - /// Gets the account type of the wallet. - /// - public ThirdwebAccountType AccountType => ThirdwebAccountType.PrivateKeyAccount; - - /// - /// The Ethereum EC key used by the wallet. - /// - protected EthECKey _ecKey; - - /// - /// Initializes a new instance of the class. - /// - /// The Thirdweb client. - /// The Ethereum EC key. - protected PrivateKeyWallet(ThirdwebClient client, EthECKey key) - { - Client = client; - _ecKey = key; - } - - /// - /// Creates a new instance of using the specified private key. - /// - /// The Thirdweb client. - /// The private key in hexadecimal format. - /// A task that represents the asynchronous operation. The task result contains the created . - public static Task Create(ThirdwebClient client, string privateKeyHex) - { - return string.IsNullOrEmpty(privateKeyHex) - ? throw new ArgumentNullException(nameof(privateKeyHex), "Private key cannot be null or empty.") - : Task.FromResult(new PrivateKeyWallet(client, new EthECKey(privateKeyHex))); - } - - /// - /// Generates a new instance of with a random private key. - /// - /// The Thirdweb client. - /// A task that represents the asynchronous operation. The task result contains the created . - public static Task Generate(ThirdwebClient client) - { - return Task.FromResult(new PrivateKeyWallet(client, EthECKey.GenerateKey())); - } - - /// - /// Gets the address of the wallet. - /// - /// A task that represents the asynchronous operation. The task result contains the address of the wallet. - public virtual Task GetAddress() - { - return Task.FromResult(_ecKey.GetPublicAddress().ToChecksumAddress()); - } - - /// - /// Signs a message using the wallet's private key. - /// - /// The message to sign. - /// A task that represents the asynchronous operation. The task result contains the signed message. - public virtual Task EthSign(byte[] rawMessage) - { - if (rawMessage == null) - { - throw new ArgumentNullException(nameof(rawMessage), "Message to sign cannot be null."); - } - - var signer = new MessageSigner(); - var signature = signer.Sign(rawMessage, _ecKey); - return Task.FromResult(signature); - } - - /// - /// Signs a message using the wallet's private key. - /// - /// The message to sign. - /// A task that represents the asynchronous operation. The task result contains the signed message. - public virtual Task EthSign(string message) - { - if (message == null) - { - throw new ArgumentNullException(nameof(message), "Message to sign cannot be null."); - } - - var signer = new MessageSigner(); - var signature = signer.Sign(Encoding.UTF8.GetBytes(message), _ecKey); - return Task.FromResult(signature); - } - - /// - /// Signs a message using the wallet's private key with personal sign. - /// - /// The message to sign. - /// A task that represents the asynchronous operation. The task result contains the signed message. - public virtual Task PersonalSign(byte[] rawMessage) - { - if (rawMessage == null) - { - throw new ArgumentNullException(nameof(rawMessage), "Message to sign cannot be null."); - } - - var signer = new EthereumMessageSigner(); - var signature = signer.Sign(rawMessage, _ecKey); - return Task.FromResult(signature); - } - - /// - /// Signs a message using the wallet's private key with personal sign. - /// - /// The message to sign. - /// A task that represents the asynchronous operation. The task result contains the signed message. - public virtual Task PersonalSign(string message) - { - if (string.IsNullOrEmpty(message)) - { - throw new ArgumentNullException(nameof(message), "Message to sign cannot be null."); - } - - var signer = new EthereumMessageSigner(); - var signature = signer.EncodeUTF8AndSign(message, _ecKey); - return Task.FromResult(signature); - } - - /// - /// Signs typed data (EIP-712) using the wallet's private key. - /// - /// The JSON string representing the typed data. - /// A task that represents the asynchronous operation. The task result contains the signed data. - public virtual Task SignTypedDataV4(string json) - { - if (string.IsNullOrEmpty(json)) - { - throw new ArgumentNullException(nameof(json), "Json to sign cannot be null."); - } - - var signer = new Eip712TypedDataSigner(); - var signature = signer.SignTypedDataV4(json, _ecKey); - return Task.FromResult(signature); - } - - /// - /// Signs typed data (EIP-712) using the wallet's private key. - /// - /// The type of the data to sign. - /// The type of the domain. - /// The data to sign. - /// The typed data. - /// A task that represents the asynchronous operation. The task result contains the signed data. - public virtual Task SignTypedDataV4(T data, TypedData typedData) - where TDomain : IDomain - { - if (data == null) - { - throw new ArgumentNullException(nameof(data), "Data to sign cannot be null."); - } - - var signer = new Eip712TypedDataSigner(); - var signature = signer.SignTypedDataV4(data, typedData, _ecKey); - return Task.FromResult(signature); - } - - /// - /// Signs a transaction using the wallet's private key. - /// - /// The transaction to sign. - /// A task that represents the asynchronous operation. The task result contains the signed transaction. - public virtual async Task SignTransaction(ThirdwebTransactionInput transaction) - { - if (transaction == null) - { - throw new ArgumentNullException(nameof(transaction)); - } - - if (string.IsNullOrWhiteSpace(transaction.From)) - { - transaction.From = await GetAddress(); - } - else if (transaction.From != await GetAddress()) - { - throw new Exception("Transaction 'From' address does not match the wallet address"); - } - - var nonce = transaction.Nonce ?? throw new ArgumentNullException(nameof(transaction), "Transaction nonce has not been set"); - - var gasLimit = transaction.Gas; - var value = transaction.Value ?? new HexBigInteger(0); - - string signedTransaction; - - if (transaction.GasPrice != null) - { - var gasPrice = transaction.GasPrice; - var legacySigner = new LegacyTransactionSigner(); - signedTransaction = legacySigner.SignTransaction( - _ecKey.GetPrivateKey(), - transaction.ChainId.Value, - transaction.To, - value.Value, - nonce, - gasPrice.Value, - gasLimit.Value, - transaction.Data - ); - } - else - { - if (transaction.MaxPriorityFeePerGas == null || transaction.MaxFeePerGas == null) - { - throw new InvalidOperationException("Transaction MaxPriorityFeePerGas and MaxFeePerGas must be set for EIP-1559 transactions"); - } - var maxPriorityFeePerGas = transaction.MaxPriorityFeePerGas.Value; - var maxFeePerGas = transaction.MaxFeePerGas.Value; - var transaction1559 = new Transaction1559(transaction.ChainId.Value, nonce, maxPriorityFeePerGas, maxFeePerGas, gasLimit, transaction.To, value, transaction.Data, null); - - var signer = new Transaction1559Signer(); - signer.SignTransaction(_ecKey, transaction1559); - signedTransaction = transaction1559.GetRLPEncoded().ToHex(); - } - - return "0x" + signedTransaction; - } - - /// - /// Checks if the wallet is connected. - /// - /// A task that represents the asynchronous operation. The task result indicates whether the wallet is connected. - public virtual Task IsConnected() - { - return Task.FromResult(_ecKey != null); - } - - /// - /// Disconnects the wallet. - /// - /// A task that represents the asynchronous operation. - public virtual Task Disconnect() - { - _ecKey = null; - return Task.CompletedTask; - } - - /// - /// Authenticates the user by signing a message with the wallet's private key. - /// - /// The domain for authentication. - /// The chain ID. - /// The authentication payload path. - /// The authentication login path. - /// Optional HTTP client override. - /// A task that represents the asynchronous operation. The task result contains the authentication response. - public virtual async Task Authenticate( - string domain, - BigInteger chainId, - string authPayloadPath = "/auth/payload", - string authLoginPath = "/auth/login", - IThirdwebHttpClient httpClientOverride = null - ) - { - var payloadURL = domain + authPayloadPath; - var loginURL = domain + authLoginPath; - - var payloadBodyRaw = new { address = await GetAddress(), chainId = chainId.ToString() }; - var payloadBody = JsonConvert.SerializeObject(payloadBodyRaw); - - var httpClient = httpClientOverride ?? Client.HttpClient; - - var payloadContent = new StringContent(payloadBody, Encoding.UTF8, "application/json"); - var payloadResponse = await httpClient.PostAsync(payloadURL, payloadContent); - _ = payloadResponse.EnsureSuccessStatusCode(); - var payloadString = await payloadResponse.Content.ReadAsStringAsync(); - - var loginBodyRaw = JsonConvert.DeserializeObject(payloadString); - var payloadToSign = Utils.GenerateSIWE(loginBodyRaw.payload); - - loginBodyRaw.signature = await PersonalSign(payloadToSign); - var loginBody = JsonConvert.SerializeObject(new { payload = loginBodyRaw }); - - var loginContent = new StringContent(loginBody, Encoding.UTF8, "application/json"); - var loginResponse = await httpClient.PostAsync(loginURL, loginContent); - _ = loginResponse.EnsureSuccessStatusCode(); - var responseString = await loginResponse.Content.ReadAsStringAsync(); - return responseString; - } - - /// - /// Throws an exception because sending transactions is not supported for private key wallets. - /// - /// The transaction to send. - /// Throws an InvalidOperationException. - public Task SendTransaction(ThirdwebTransactionInput transaction) - { - throw new InvalidOperationException("SendTransaction is not supported for private key wallets, please use the unified Contract or ThirdwebTransaction APIs."); - } - } -} diff --git a/Thirdweb/Thirdweb.Wallets/ServerWallet/ServerWallet.Types.cs b/Thirdweb/Thirdweb.Wallets/ServerWallet/ServerWallet.Types.cs new file mode 100644 index 00000000..711d6901 --- /dev/null +++ b/Thirdweb/Thirdweb.Wallets/ServerWallet/ServerWallet.Types.cs @@ -0,0 +1,145 @@ +using System.Numerics; +using Newtonsoft.Json; + +namespace Thirdweb; + +/// +/// Base class for execution options +/// +[JsonObject] +public class ExecutionOptions +{ + [JsonProperty("chainId")] + public BigInteger? ChainId { get; set; } = null; + + [JsonProperty("idempotencyKey")] + public string IdempotencyKey { get; set; } +} + +/// +/// Auto determine execution options +/// +[JsonObject] +public class AutoExecutionOptions : ExecutionOptions +{ + [JsonProperty("type")] + public string Type { get; set; } = "auto"; + + [JsonProperty("from")] + public string From { get; set; } +} + +/// +/// Externally Owned Account (EOA) execution options +/// +[JsonObject] +public class EIP7702ExecutionOptions : ExecutionOptions +{ + [JsonProperty("type")] + public string Type { get; set; } = "EIP7702"; + + [JsonProperty("from")] + public string From { get; set; } +} + +/// +/// Externally Owned Account (EOA) execution options +/// +[JsonObject] +public class EOAExecutionOptions : ExecutionOptions +{ + [JsonProperty("type")] + public string Type { get; set; } = "EOA"; + + [JsonProperty("from")] + public string From { get; set; } +} + +/// +/// ERC-4337 execution options +/// +[JsonObject] +public class ERC4337ExecutionOptions : ExecutionOptions +{ + [JsonProperty("type")] + public string Type { get; set; } = "ERC4337"; + + [JsonProperty("signerAddress")] + public string SignerAddress { get; set; } + + [JsonProperty("accountSalt")] + public string AccountSalt { get; set; } + + [JsonProperty("smartAccountAddress")] + public string SmartAccountAddress { get; set; } + + [JsonProperty("entrypointAddress")] + public string EntrypointAddress { get; set; } + + [JsonProperty("entrypointVersion")] + public string EntrypointVersion { get; set; } + + [JsonProperty("factoryAddress")] + public string FactoryAddress { get; set; } + + public ERC4337ExecutionOptions(BigInteger chainId, string signerAddress) + { + this.ChainId = chainId; + this.SignerAddress = signerAddress; + } +} + +/// +/// Response wrapper for queued transactions +/// +[JsonObject] +internal class QueuedTransactionResponse +{ + [JsonProperty("result")] + public QueuedTransactionResult Result { get; set; } +} + +/// +/// Result containing the transactions array +/// +[JsonObject] +internal class QueuedTransactionResult +{ + [JsonProperty("transactions")] + public QueuedTransaction[] Transactions { get; set; } +} + +/// +/// Queued transaction response +/// +[JsonObject] +internal class QueuedTransaction +{ + [JsonProperty("id")] + public string Id { get; set; } + + [JsonProperty("batchIndex")] + public long BatchIndex { get; set; } + + [JsonProperty("executionParams")] + public ExecutionOptions ExecutionParams { get; set; } + + [JsonProperty("transactionParams")] + public InnerTransaction[] TransactionParams { get; set; } +} + +/// +/// Inner transaction data +/// +[JsonObject] +internal class InnerTransaction +{ + [JsonProperty("to")] + public string To { get; set; } + + [JsonProperty("data")] + public string Data { get; set; } + + [JsonProperty("value")] + public string Value { get; set; } +} diff --git a/Thirdweb/Thirdweb.Wallets/ServerWallet/ServerWallet.cs b/Thirdweb/Thirdweb.Wallets/ServerWallet/ServerWallet.cs new file mode 100644 index 00000000..3e855dbd --- /dev/null +++ b/Thirdweb/Thirdweb.Wallets/ServerWallet/ServerWallet.cs @@ -0,0 +1,387 @@ +using System.Numerics; +using System.Text; +using Nethereum.ABI.EIP712; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; + +namespace Thirdweb; + +/// +/// Interact with vault-secured server wallets created from the Thirdweb project dashboard's Transactions tab. +/// +public partial class ServerWallet : IThirdwebWallet +{ + public ThirdwebClient Client { get; } + public ThirdwebAccountType AccountType => ThirdwebAccountType.ExternalAccount; + public string WalletId => "server"; + + private readonly string _walletAddress; + private readonly IThirdwebHttpClient _engineClient; + private readonly ExecutionOptions _executionOptions; + + private readonly JsonSerializerSettings _jsonSerializerSettings = new() { NullValueHandling = NullValueHandling.Ignore, Formatting = Formatting.Indented }; + + internal ServerWallet(ThirdwebClient client, IThirdwebHttpClient engineClient, string walletAddress, ExecutionOptions executionOptions) + { + this.Client = client; + this._walletAddress = walletAddress; + this._engineClient = engineClient; + this._executionOptions = executionOptions; + } + + #region Creation + + /// + /// Creates an instance of the ServerWallet. + /// + /// The Thirdweb client. + /// The label of your created server wallet. + /// The execution options for the server wallet, defaults to auto if not passed. + /// The vault access token for the server wallet if self-managed. + /// A new instance of the ServerWallet. + /// Thrown when client or label is null or empty. + /// Thrown when no server wallets are found or the specified label does not match any existing server wallet. + public static async Task Create(ThirdwebClient client, string label, ExecutionOptions executionOptions = null, string vaultAccessToken = null) + { + if (client == null) + { + throw new ArgumentNullException(nameof(client), "Client cannot be null."); + } + + if (string.IsNullOrEmpty(label)) + { + throw new ArgumentNullException(nameof(label), "Label cannot be null or empty."); + } + + var engineClient = Utils.ReconstructHttpClient(client.HttpClient, new Dictionary { { "X-Secret-Key", client.SecretKey } }); + if (!string.IsNullOrEmpty(vaultAccessToken)) + { + engineClient.AddHeader("X-Vault-Access-Token", vaultAccessToken); + } + var serverWalletListResponse = await engineClient.GetAsync($"{Constants.ENGINE_API_URL}/v1/accounts").ConfigureAwait(false); + _ = serverWalletListResponse.EnsureSuccessStatusCode(); + var content = await serverWalletListResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + + var responseObj = JObject.Parse(content); + var accounts = responseObj["result"]?["accounts"]?.ToObject(); // TODO: Support pagination + + if (accounts == null || accounts.Count == 0) + { + throw new InvalidOperationException("No server wallets found in the account."); + } + + var matchingAccount = + accounts.FirstOrDefault(account => account["label"]?.ToString() == label) + ?? throw new InvalidOperationException( + $"Server wallet with label '{label}' not found. Available labels: {string.Join(", ", accounts.Select(a => a["label"]?.ToString()).Where(l => !string.IsNullOrEmpty(l)))}" + ); + + var signerWalletAddress = matchingAccount["address"]?.ToString().ToChecksumAddress(); + var smartWalletAddress = executionOptions is ERC4337ExecutionOptions ? matchingAccount["smartAccountAddress"]?.ToString() : null; + if (string.IsNullOrEmpty(signerWalletAddress)) + { + throw new InvalidOperationException($"Server wallet with label '{label}' found but has no address."); + } + + executionOptions ??= new AutoExecutionOptions { IdempotencyKey = Guid.NewGuid().ToString(), From = signerWalletAddress.ToChecksumAddress() }; + if (executionOptions is ERC4337ExecutionOptions erc4337ExecutionOptions) + { + erc4337ExecutionOptions.SmartAccountAddress = smartWalletAddress; + erc4337ExecutionOptions.SignerAddress = signerWalletAddress; + } + else if (executionOptions is EIP7702ExecutionOptions eip7702ExecutionOptions) + { + eip7702ExecutionOptions.From = signerWalletAddress.ToChecksumAddress(); + } + else if (executionOptions is EOAExecutionOptions eoaExecutionOptions) + { + eoaExecutionOptions.From = signerWalletAddress.ToChecksumAddress(); + } + else if (executionOptions is AutoExecutionOptions autoExecutionOptions) + { + autoExecutionOptions.From ??= signerWalletAddress.ToChecksumAddress(); + } + else + { + throw new InvalidOperationException( + $"Unsupported execution options type: {executionOptions.GetType().Name}. Supported types are AutoExecutionOptions, EIP7702ExecutionOptions, EOAExecutionOptions, and ERC4337ExecutionOptions." + ); + } + + var wallet = new ServerWallet(client, engineClient, smartWalletAddress ?? signerWalletAddress, executionOptions); + Utils.TrackConnection(wallet); + return wallet; + } + + #endregion + + #region Wallet Specific + + public async Task WaitForTransactionHash(string txid) + { + var cancellationToken = new CancellationTokenSource(); + cancellationToken.CancelAfter(this.Client.FetchTimeoutOptions.GetTimeout(TimeoutType.Other)); + var transactionHash = string.Empty; + while (string.IsNullOrEmpty(transactionHash) && !cancellationToken.IsCancellationRequested) + { + await ThirdwebTask.Delay(100); + + var statusResponse = await this._engineClient.GetAsync($"{Constants.ENGINE_API_URL}/v1/transactions?id={txid}").ConfigureAwait(false); + var content = await statusResponse.Content.ReadAsStringAsync(); + var response = JObject.Parse(content); + var transaction = (response["result"]?["transactions"]?.FirstOrDefault()) ?? throw new Exception($"Failed to fetch transaction status for ID: {txid}"); + var errorMessage = transaction?["errorMessage"]?.ToString(); + if (!string.IsNullOrEmpty(errorMessage)) + { + throw new Exception($"Sending transaction errored: {errorMessage}"); + } + + transactionHash = transaction?["transactionHash"]?.ToString(); + } + return transactionHash; + } + + private object ToEngineTransaction(ThirdwebTransactionInput transaction) + { + if (transaction == null) + { + throw new ArgumentNullException(nameof(transaction)); + } + + this._executionOptions.ChainId = transaction.ChainId; + + return new + { + executionOptions = this._executionOptions, + @params = new[] + { + new + { + to = transaction.To, + data = transaction.Data ?? "0x", + value = transaction.Value?.HexValue ?? "0x00", + authorizationList = transaction.AuthorizationList != null && transaction.AuthorizationList.Count > 0 + ? transaction + .AuthorizationList.Select(authorization => new + { + chainId = authorization.ChainId.HexToNumber(), + address = authorization.Address, + nonce = authorization.Nonce.HexToNumber(), + yParity = authorization.YParity.HexToNumber(), + r = authorization.R, + s = authorization.S, + }) + .ToArray() + : null, + }, + }, + }; + } + + #endregion + + #region IThirdwebWallet + + public Task GetAddress() + { + if (!string.IsNullOrEmpty(this._walletAddress)) + { + return Task.FromResult(this._walletAddress.ToChecksumAddress()); + } + else + { + return Task.FromResult(this._walletAddress); + } + } + + public async Task PersonalSign(byte[] rawMessage) + { + if (rawMessage == null) + { + throw new ArgumentNullException(nameof(rawMessage), "Message to sign cannot be null."); + } + + var url = $"{Constants.ENGINE_API_URL}/v1/sign/message"; + + var address = await this.GetAddress(); + + var payload = new + { + signingOptions = new + { + type = "auto", + from = address, + chainId = this._executionOptions.ChainId, + }, + @params = new[] { new { message = rawMessage.BytesToHex(), format = "hex" } }, + }; + + var requestContent = new StringContent(JsonConvert.SerializeObject(payload, this._jsonSerializerSettings), Encoding.UTF8, "application/json"); + + var response = await this._engineClient.PostAsync(url, requestContent).ConfigureAwait(false); + _ = response.EnsureSuccessStatusCode(); + + var content = await response.Content.ReadAsStringAsync().ConfigureAwait(false); + return JObject.Parse(content)["result"]?[0]?["result"]?["signature"].Value(); + } + + public async Task PersonalSign(string message) + { + if (string.IsNullOrEmpty(message)) + { + throw new ArgumentNullException(nameof(message), "Message to sign cannot be null."); + } + + var url = $"{Constants.ENGINE_API_URL}/v1/sign/message"; + + var address = await this.GetAddress(); + + var payload = new + { + signingOptions = new + { + type = "auto", + from = address, + chainId = this._executionOptions.ChainId, + }, + @params = new[] { new { message, format = "text" } }, + }; + + var requestContent = new StringContent(JsonConvert.SerializeObject(payload, this._jsonSerializerSettings), Encoding.UTF8, "application/json"); + + var response = await this._engineClient.PostAsync(url, requestContent).ConfigureAwait(false); + _ = response.EnsureSuccessStatusCode(); + + var content = await response.Content.ReadAsStringAsync().ConfigureAwait(false); + return JObject.Parse(content)["result"]?[0]?["result"]?["signature"].Value(); + } + + public async Task SignTypedDataV4(string json) + { + if (string.IsNullOrEmpty(json)) + { + throw new ArgumentNullException(nameof(json), "Json to sign cannot be null."); + } + + var processedJson = Utils.PreprocessTypedDataJson(json); + + var url = $"{Constants.ENGINE_API_URL}/v1/sign/typed-data"; + + var address = await this.GetAddress(); + + var payload = new + { + signingOptions = new + { + type = "auto", + from = address, + chainId = BigInteger.Parse(JObject.Parse(processedJson)["domain"]?["chainId"]?.Value()), + }, + @params = new[] { processedJson }, + }; + var requestContent = new StringContent(JsonConvert.SerializeObject(payload, this._jsonSerializerSettings), Encoding.UTF8, "application/json"); + + var response = await this._engineClient.PostAsync(url, requestContent).ConfigureAwait(false); + _ = response.EnsureSuccessStatusCode(); + + var content = await response.Content.ReadAsStringAsync().ConfigureAwait(false); + return JObject.Parse(content)["result"]?[0]?["result"]?["signature"].Value(); + } + + public async Task SignTypedDataV4(T data, TypedData typedData) + where TDomain : IDomain + { + if (data == null) + { + throw new ArgumentNullException(nameof(data), "Data to sign cannot be null."); + } + + var safeJson = Utils.ToJsonExternalWalletFriendly(typedData, data); + return await this.SignTypedDataV4(safeJson).ConfigureAwait(false); + } + + public Task SignTransaction(ThirdwebTransactionInput transaction) + { + throw new NotImplementedException("SignTransaction is not implemented for ServerWallet. Use SendTransaction instead."); + } + + public Task IsConnected() + { + return Task.FromResult(this._walletAddress != null); + } + + public async Task SendTransaction(ThirdwebTransactionInput transaction) + { + if (transaction == null) + { + throw new ArgumentNullException(nameof(transaction)); + } + + var payload = this.ToEngineTransaction(transaction); + + var url = $"{Constants.ENGINE_API_URL}/v1/write/transaction"; + + var requestContent = new StringContent(JsonConvert.SerializeObject(payload, this._jsonSerializerSettings), Encoding.UTF8, "application/json"); + + var response = await this._engineClient.PostAsync(url, requestContent).ConfigureAwait(false); + _ = response.EnsureSuccessStatusCode(); + + var content = await response.Content.ReadAsStringAsync().ConfigureAwait(false); + var queuedTransactionResponse = JsonConvert.DeserializeObject(content); + var txid = queuedTransactionResponse.Result?.Transactions?.FirstOrDefault()?.Id; + if (string.IsNullOrEmpty(txid)) + { + throw new Exception("Failed to queue the transaction. No transaction ID returned."); + } + return await this.WaitForTransactionHash(txid).ConfigureAwait(false); + } + + public async Task ExecuteTransaction(ThirdwebTransactionInput transactionInput) + { + var hash = await this.SendTransaction(transactionInput); + return await ThirdwebTransaction.WaitForTransactionReceipt(this.Client, transactionInput.ChainId.Value, hash).ConfigureAwait(false); + } + + public Task Disconnect() + { + return Task.CompletedTask; + } + + public Task SignAuthorization(BigInteger chainId, string contractAddress, bool willSelfExecute) + { + throw new NotImplementedException(); + } + + public Task SwitchNetwork(BigInteger chainId) + { + return Task.CompletedTask; + } + + public Task> LinkAccount( + IThirdwebWallet walletToLink, + string otp = null, + bool? isMobile = null, + Action browserOpenAction = null, + string mobileRedirectScheme = "thirdweb://", + IThirdwebBrowser browser = null, + BigInteger? chainId = null, + string jwt = null, + string payload = null, + string defaultSessionIdOverride = null + ) + { + throw new NotImplementedException(); + } + + public Task> UnlinkAccount(LinkedAccount accountToUnlink) + { + throw new NotImplementedException(); + } + + public Task> GetLinkedAccounts() + { + throw new NotImplementedException(); + } + + #endregion +} diff --git a/Thirdweb/Thirdweb.Wallets/SmartWallet/SmartWallet.cs b/Thirdweb/Thirdweb.Wallets/SmartWallet/SmartWallet.cs index a934395f..7b2d60c0 100644 --- a/Thirdweb/Thirdweb.Wallets/SmartWallet/SmartWallet.cs +++ b/Thirdweb/Thirdweb.Wallets/SmartWallet/SmartWallet.cs @@ -1,635 +1,1218 @@ -using System.Numerics; +using System.Numerics; using System.Security.Cryptography; using System.Text; +using Nethereum.ABI; using Nethereum.ABI.EIP712; -using Nethereum.Contracts; -using Nethereum.Hex.HexConvertors.Extensions; -using Nethereum.Hex.HexTypes; +using Nethereum.Util; using Newtonsoft.Json; using Thirdweb.AccountAbstraction; -namespace Thirdweb +namespace Thirdweb; + +public enum TokenPaymaster { - public class SmartWallet : IThirdwebWallet - { - public ThirdwebClient Client { get; } - - public ThirdwebAccountType AccountType => ThirdwebAccountType.SmartAccount; - - private IThirdwebWallet _personalAccount; - private bool _gasless; - private ThirdwebContract _factoryContract; - private ThirdwebContract _accountContract; - private ThirdwebContract _entryPointContract; - private BigInteger _chainId; - private string _bundlerUrl; - private string _paymasterUrl; - private bool _isDeploying; - - protected SmartWallet( - IThirdwebWallet personalAccount, - bool gasless, - BigInteger chainId, - string bundlerUrl, - string paymasterUrl, - ThirdwebContract entryPointContract, - ThirdwebContract factoryContract, - ThirdwebContract accountContract - ) - { - Client = personalAccount.Client; - - _personalAccount = personalAccount; - _gasless = gasless; - _chainId = chainId; - _bundlerUrl = bundlerUrl; - _paymasterUrl = paymasterUrl; - _entryPointContract = entryPointContract; - _factoryContract = factoryContract; - _accountContract = accountContract; - } - - public static async Task Create( - IThirdwebWallet personalWallet, - BigInteger chainId, - bool gasless = true, - string factoryAddress = null, - string accountAddressOverride = null, - string entryPoint = null, - string bundlerUrl = null, - string paymasterUrl = null - ) - { - if (!await personalWallet.IsConnected()) - { - throw new InvalidOperationException("SmartAccount.Connect: Personal account must be connected."); - } + NONE, + BASE_USDC, + CELO_CUSD, + LISK_LSK, +} - bundlerUrl ??= $"https://{chainId}.bundler.thirdweb.com"; - paymasterUrl ??= $"https://{chainId}.bundler.thirdweb.com"; - entryPoint ??= Constants.DEFAULT_ENTRYPOINT_ADDRESS; - factoryAddress ??= Constants.DEFAULT_FACTORY_ADDRESS; +public class SmartWallet : IThirdwebWallet +{ + public ThirdwebClient Client { get; } - ThirdwebContract entryPointContract = null; - ThirdwebContract factoryContract = null; - ThirdwebContract accountContract = null; + public ThirdwebAccountType AccountType => ThirdwebAccountType.SmartAccount; - if (!Utils.IsZkSync(chainId)) - { - entryPointContract = await ThirdwebContract.Create( - personalWallet.Client, - entryPoint, - chainId, - "[{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"preOpGas\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"paid\",\"type\":\"uint256\"},{\"internalType\":\"uint48\",\"name\":\"validAfter\",\"type\":\"uint48\"},{\"internalType\":\"uint48\",\"name\":\"validUntil\",\"type\":\"uint48\"},{\"internalType\":\"bool\",\"name\":\"targetSuccess\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"targetResult\",\"type\":\"bytes\"}],\"name\":\"ExecutionResult\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"opIndex\",\"type\":\"uint256\"},{\"internalType\":\"string\",\"name\":\"reason\",\"type\":\"string\"}],\"name\":\"FailedOp\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"SenderAddressResult\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"aggregator\",\"type\":\"address\"}],\"name\":\"SignatureValidationFailed\",\"type\":\"error\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"preOpGas\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"prefund\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sigFailed\",\"type\":\"bool\"},{\"internalType\":\"uint48\",\"name\":\"validAfter\",\"type\":\"uint48\"},{\"internalType\":\"uint48\",\"name\":\"validUntil\",\"type\":\"uint48\"},{\"internalType\":\"bytes\",\"name\":\"paymasterContext\",\"type\":\"bytes\"}],\"internalType\":\"struct IEntryPoint.ReturnInfo\",\"name\":\"returnInfo\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"stake\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"unstakeDelaySec\",\"type\":\"uint256\"}],\"internalType\":\"struct IStakeManager.StakeInfo\",\"name\":\"senderInfo\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"stake\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"unstakeDelaySec\",\"type\":\"uint256\"}],\"internalType\":\"struct IStakeManager.StakeInfo\",\"name\":\"factoryInfo\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"stake\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"unstakeDelaySec\",\"type\":\"uint256\"}],\"internalType\":\"struct IStakeManager.StakeInfo\",\"name\":\"paymasterInfo\",\"type\":\"tuple\"}],\"name\":\"ValidationResult\",\"type\":\"error\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"preOpGas\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"prefund\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sigFailed\",\"type\":\"bool\"},{\"internalType\":\"uint48\",\"name\":\"validAfter\",\"type\":\"uint48\"},{\"internalType\":\"uint48\",\"name\":\"validUntil\",\"type\":\"uint48\"},{\"internalType\":\"bytes\",\"name\":\"paymasterContext\",\"type\":\"bytes\"}],\"internalType\":\"struct IEntryPoint.ReturnInfo\",\"name\":\"returnInfo\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"stake\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"unstakeDelaySec\",\"type\":\"uint256\"}],\"internalType\":\"struct IStakeManager.StakeInfo\",\"name\":\"senderInfo\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"stake\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"unstakeDelaySec\",\"type\":\"uint256\"}],\"internalType\":\"struct IStakeManager.StakeInfo\",\"name\":\"factoryInfo\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"stake\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"unstakeDelaySec\",\"type\":\"uint256\"}],\"internalType\":\"struct IStakeManager.StakeInfo\",\"name\":\"paymasterInfo\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"aggregator\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"stake\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"unstakeDelaySec\",\"type\":\"uint256\"}],\"internalType\":\"struct IStakeManager.StakeInfo\",\"name\":\"stakeInfo\",\"type\":\"tuple\"}],\"internalType\":\"struct IEntryPoint.AggregatorStakeInfo\",\"name\":\"aggregatorInfo\",\"type\":\"tuple\"}],\"name\":\"ValidationResultWithAggregation\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"userOpHash\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"factory\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"paymaster\",\"type\":\"address\"}],\"name\":\"AccountDeployed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[],\"name\":\"BeforeExecution\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"totalDeposit\",\"type\":\"uint256\"}],\"name\":\"Deposited\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"aggregator\",\"type\":\"address\"}],\"name\":\"SignatureAggregatorChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"totalStaked\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"unstakeDelaySec\",\"type\":\"uint256\"}],\"name\":\"StakeLocked\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"withdrawTime\",\"type\":\"uint256\"}],\"name\":\"StakeUnlocked\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"withdrawAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"StakeWithdrawn\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"userOpHash\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"paymaster\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"success\",\"type\":\"bool\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"actualGasCost\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"actualGasUsed\",\"type\":\"uint256\"}],\"name\":\"UserOperationEvent\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"userOpHash\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"revertReason\",\"type\":\"bytes\"}],\"name\":\"UserOperationRevertReason\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"withdrawAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"Withdrawn\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"SIG_VALIDATION_FAILED\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"initCode\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"paymasterAndData\",\"type\":\"bytes\"}],\"name\":\"_validateSenderAndPaymaster\",\"outputs\":[],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"unstakeDelaySec\",\"type\":\"uint32\"}],\"name\":\"addStake\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"balanceOf\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"depositTo\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"deposits\",\"outputs\":[{\"internalType\":\"uint112\",\"name\":\"deposit\",\"type\":\"uint112\"},{\"internalType\":\"bool\",\"name\":\"staked\",\"type\":\"bool\"},{\"internalType\":\"uint112\",\"name\":\"stake\",\"type\":\"uint112\"},{\"internalType\":\"uint32\",\"name\":\"unstakeDelaySec\",\"type\":\"uint32\"},{\"internalType\":\"uint48\",\"name\":\"withdrawTime\",\"type\":\"uint48\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"getDepositInfo\",\"outputs\":[{\"components\":[{\"internalType\":\"uint112\",\"name\":\"deposit\",\"type\":\"uint112\"},{\"internalType\":\"bool\",\"name\":\"staked\",\"type\":\"bool\"},{\"internalType\":\"uint112\",\"name\":\"stake\",\"type\":\"uint112\"},{\"internalType\":\"uint32\",\"name\":\"unstakeDelaySec\",\"type\":\"uint32\"},{\"internalType\":\"uint48\",\"name\":\"withdrawTime\",\"type\":\"uint48\"}],\"internalType\":\"struct IStakeManager.DepositInfo\",\"name\":\"info\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"uint192\",\"name\":\"key\",\"type\":\"uint192\"}],\"name\":\"getNonce\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"initCode\",\"type\":\"bytes\"}],\"name\":\"getSenderAddress\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"initCode\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"callData\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"callGasLimit\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"verificationGasLimit\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"preVerificationGas\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxFeePerGas\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxPriorityFeePerGas\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"paymasterAndData\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"signature\",\"type\":\"bytes\"}],\"internalType\":\"struct UserOperation\",\"name\":\"userOp\",\"type\":\"tuple\"}],\"name\":\"getUserOpHash\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"initCode\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"callData\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"callGasLimit\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"verificationGasLimit\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"preVerificationGas\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxFeePerGas\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxPriorityFeePerGas\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"paymasterAndData\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"signature\",\"type\":\"bytes\"}],\"internalType\":\"struct UserOperation[]\",\"name\":\"userOps\",\"type\":\"tuple[]\"},{\"internalType\":\"contract IAggregator\",\"name\":\"aggregator\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"signature\",\"type\":\"bytes\"}],\"internalType\":\"struct IEntryPoint.UserOpsPerAggregator[]\",\"name\":\"opsPerAggregator\",\"type\":\"tuple[]\"},{\"internalType\":\"address payable\",\"name\":\"beneficiary\",\"type\":\"address\"}],\"name\":\"handleAggregatedOps\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"initCode\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"callData\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"callGasLimit\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"verificationGasLimit\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"preVerificationGas\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxFeePerGas\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxPriorityFeePerGas\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"paymasterAndData\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"signature\",\"type\":\"bytes\"}],\"internalType\":\"struct UserOperation[]\",\"name\":\"ops\",\"type\":\"tuple[]\"},{\"internalType\":\"address payable\",\"name\":\"beneficiary\",\"type\":\"address\"}],\"name\":\"handleOps\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint192\",\"name\":\"key\",\"type\":\"uint192\"}],\"name\":\"incrementNonce\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"callData\",\"type\":\"bytes\"},{\"components\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"callGasLimit\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"verificationGasLimit\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"preVerificationGas\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"paymaster\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"maxFeePerGas\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxPriorityFeePerGas\",\"type\":\"uint256\"}],\"internalType\":\"struct EntryPoint.MemoryUserOp\",\"name\":\"mUserOp\",\"type\":\"tuple\"},{\"internalType\":\"bytes32\",\"name\":\"userOpHash\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"prefund\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"contextOffset\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"preOpGas\",\"type\":\"uint256\"}],\"internalType\":\"struct EntryPoint.UserOpInfo\",\"name\":\"opInfo\",\"type\":\"tuple\"},{\"internalType\":\"bytes\",\"name\":\"context\",\"type\":\"bytes\"}],\"name\":\"innerHandleOp\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"actualGasCost\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint192\",\"name\":\"\",\"type\":\"uint192\"}],\"name\":\"nonceSequenceNumber\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"initCode\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"callData\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"callGasLimit\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"verificationGasLimit\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"preVerificationGas\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxFeePerGas\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxPriorityFeePerGas\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"paymasterAndData\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"signature\",\"type\":\"bytes\"}],\"internalType\":\"struct UserOperation\",\"name\":\"op\",\"type\":\"tuple\"},{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"targetCallData\",\"type\":\"bytes\"}],\"name\":\"simulateHandleOp\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"initCode\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"callData\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"callGasLimit\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"verificationGasLimit\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"preVerificationGas\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxFeePerGas\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxPriorityFeePerGas\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"paymasterAndData\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"signature\",\"type\":\"bytes\"}],\"internalType\":\"struct UserOperation\",\"name\":\"userOp\",\"type\":\"tuple\"}],\"name\":\"simulateValidation\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"unlockStake\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address payable\",\"name\":\"withdrawAddress\",\"type\":\"address\"}],\"name\":\"withdrawStake\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address payable\",\"name\":\"withdrawAddress\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"withdrawAmount\",\"type\":\"uint256\"}],\"name\":\"withdrawTo\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}]" - ); - factoryContract = await ThirdwebContract.Create( - personalWallet.Client, - factoryAddress, - chainId, - "[{\"type\": \"constructor\",\"name\": \"\",\"inputs\": [{\"type\": \"address\",\"name\": \"_defaultAdmin\",\"internalType\": \"address\"},{\"type\": \"address\",\"name\": \"_entrypoint\",\"internalType\": \"contract IEntryPoint\"},{\"type\": \"tuple[]\",\"name\": \"_defaultExtensions\",\"components\": [{\"type\": \"tuple\",\"name\": \"metadata\",\"components\": [{\"internalType\": \"string\",\"name\": \"name\",\"type\": \"string\"},{\"internalType\": \"string\",\"name\": \"metadataURI\",\"type\": \"string\"},{\"internalType\": \"address\",\"name\": \"implementation\",\"type\": \"address\"}],\"internalType\": \"struct IExtension.ExtensionMetadata\"},{\"type\": \"tuple[]\",\"name\": \"functions\",\"components\": [{\"internalType\": \"bytes4\",\"name\": \"functionSelector\",\"type\": \"bytes4\"},{\"internalType\": \"string\",\"name\": \"functionSignature\",\"type\": \"string\"}],\"internalType\": \"struct IExtension.ExtensionFunction[]\"}],\"internalType\": \"struct IExtension.Extension[]\"}],\"outputs\": [],\"stateMutability\": \"nonpayable\"},{\"type\": \"error\",\"name\": \"InvalidCodeAtRange\",\"inputs\": [{\"type\": \"uint256\",\"name\": \"_size\",\"internalType\": \"uint256\"},{\"type\": \"uint256\",\"name\": \"_start\",\"internalType\": \"uint256\"},{\"type\": \"uint256\",\"name\": \"_end\",\"internalType\": \"uint256\"}],\"outputs\": []},{\"type\": \"error\",\"name\": \"WriteError\",\"inputs\": [],\"outputs\": []},{\"type\": \"event\",\"name\": \"AccountCreated\",\"inputs\": [{\"type\": \"address\",\"name\": \"account\",\"indexed\": true,\"internalType\": \"address\"},{\"type\": \"address\",\"name\": \"accountAdmin\",\"indexed\": true,\"internalType\": \"address\"}],\"outputs\": [],\"anonymous\": false},{\"type\": \"event\",\"name\": \"ContractURIUpdated\",\"inputs\": [{\"type\": \"string\",\"name\": \"prevURI\",\"indexed\": false,\"internalType\": \"string\"},{\"type\": \"string\",\"name\": \"newURI\",\"indexed\": false,\"internalType\": \"string\"}],\"outputs\": [],\"anonymous\": false},{\"type\": \"event\",\"name\": \"ExtensionAdded\",\"inputs\": [{\"type\": \"string\",\"name\": \"name\",\"indexed\": true,\"internalType\": \"string\"},{\"type\": \"address\",\"name\": \"implementation\",\"indexed\": true,\"internalType\": \"address\"},{\"type\": \"tuple\",\"name\": \"extension\",\"components\": [{\"type\": \"tuple\",\"name\": \"metadata\",\"components\": [{\"internalType\": \"string\",\"name\": \"name\",\"type\": \"string\"},{\"internalType\": \"string\",\"name\": \"metadataURI\",\"type\": \"string\"},{\"internalType\": \"address\",\"name\": \"implementation\",\"type\": \"address\"}],\"internalType\": \"struct IExtension.ExtensionMetadata\"},{\"type\": \"tuple[]\",\"name\": \"functions\",\"components\": [{\"internalType\": \"bytes4\",\"name\": \"functionSelector\",\"type\": \"bytes4\"},{\"internalType\": \"string\",\"name\": \"functionSignature\",\"type\": \"string\"}],\"internalType\": \"struct IExtension.ExtensionFunction[]\"}],\"indexed\": false,\"internalType\": \"struct IExtension.Extension\"}],\"outputs\": [],\"anonymous\": false},{\"type\": \"event\",\"name\": \"ExtensionRemoved\",\"inputs\": [{\"type\": \"string\",\"name\": \"name\",\"indexed\": true,\"internalType\": \"string\"},{\"type\": \"tuple\",\"name\": \"extension\",\"components\": [{\"type\": \"tuple\",\"name\": \"metadata\",\"components\": [{\"internalType\": \"string\",\"name\": \"name\",\"type\": \"string\"},{\"internalType\": \"string\",\"name\": \"metadataURI\",\"type\": \"string\"},{\"internalType\": \"address\",\"name\": \"implementation\",\"type\": \"address\"}],\"internalType\": \"struct IExtension.ExtensionMetadata\"},{\"type\": \"tuple[]\",\"name\": \"functions\",\"components\": [{\"internalType\": \"bytes4\",\"name\": \"functionSelector\",\"type\": \"bytes4\"},{\"internalType\": \"string\",\"name\": \"functionSignature\",\"type\": \"string\"}],\"internalType\": \"struct IExtension.ExtensionFunction[]\"}],\"indexed\": false,\"internalType\": \"struct IExtension.Extension\"}],\"outputs\": [],\"anonymous\": false},{\"type\": \"event\",\"name\": \"ExtensionReplaced\",\"inputs\": [{\"type\": \"string\",\"name\": \"name\",\"indexed\": true,\"internalType\": \"string\"},{\"type\": \"address\",\"name\": \"implementation\",\"indexed\": true,\"internalType\": \"address\"},{\"type\": \"tuple\",\"name\": \"extension\",\"components\": [{\"type\": \"tuple\",\"name\": \"metadata\",\"components\": [{\"internalType\": \"string\",\"name\": \"name\",\"type\": \"string\"},{\"internalType\": \"string\",\"name\": \"metadataURI\",\"type\": \"string\"},{\"internalType\": \"address\",\"name\": \"implementation\",\"type\": \"address\"}],\"internalType\": \"struct IExtension.ExtensionMetadata\"},{\"type\": \"tuple[]\",\"name\": \"functions\",\"components\": [{\"internalType\": \"bytes4\",\"name\": \"functionSelector\",\"type\": \"bytes4\"},{\"internalType\": \"string\",\"name\": \"functionSignature\",\"type\": \"string\"}],\"internalType\": \"struct IExtension.ExtensionFunction[]\"}],\"indexed\": false,\"internalType\": \"struct IExtension.Extension\"}],\"outputs\": [],\"anonymous\": false},{\"type\": \"event\",\"name\": \"FunctionDisabled\",\"inputs\": [{\"type\": \"string\",\"name\": \"name\",\"indexed\": true,\"internalType\": \"string\"},{\"type\": \"bytes4\",\"name\": \"functionSelector\",\"indexed\": true,\"internalType\": \"bytes4\"},{\"type\": \"tuple\",\"name\": \"extMetadata\",\"components\": [{\"type\": \"string\",\"name\": \"name\",\"internalType\": \"string\"},{\"type\": \"string\",\"name\": \"metadataURI\",\"internalType\": \"string\"},{\"type\": \"address\",\"name\": \"implementation\",\"internalType\": \"address\"}],\"indexed\": false,\"internalType\": \"struct IExtension.ExtensionMetadata\"}],\"outputs\": [],\"anonymous\": false},{\"type\": \"event\",\"name\": \"FunctionEnabled\",\"inputs\": [{\"type\": \"string\",\"name\": \"name\",\"indexed\": true,\"internalType\": \"string\"},{\"type\": \"bytes4\",\"name\": \"functionSelector\",\"indexed\": true,\"internalType\": \"bytes4\"},{\"type\": \"tuple\",\"name\": \"extFunction\",\"components\": [{\"type\": \"bytes4\",\"name\": \"functionSelector\",\"internalType\": \"bytes4\"},{\"type\": \"string\",\"name\": \"functionSignature\",\"internalType\": \"string\"}],\"indexed\": false,\"internalType\": \"struct IExtension.ExtensionFunction\"},{\"type\": \"tuple\",\"name\": \"extMetadata\",\"components\": [{\"type\": \"string\",\"name\": \"name\",\"internalType\": \"string\"},{\"type\": \"string\",\"name\": \"metadataURI\",\"internalType\": \"string\"},{\"type\": \"address\",\"name\": \"implementation\",\"internalType\": \"address\"}],\"indexed\": false,\"internalType\": \"struct IExtension.ExtensionMetadata\"}],\"outputs\": [],\"anonymous\": false},{\"type\": \"event\",\"name\": \"RoleAdminChanged\",\"inputs\": [{\"type\": \"bytes32\",\"name\": \"role\",\"indexed\": true,\"internalType\": \"bytes32\"},{\"type\": \"bytes32\",\"name\": \"previousAdminRole\",\"indexed\": true,\"internalType\": \"bytes32\"},{\"type\": \"bytes32\",\"name\": \"newAdminRole\",\"indexed\": true,\"internalType\": \"bytes32\"}],\"outputs\": [],\"anonymous\": false},{\"type\": \"event\",\"name\": \"RoleGranted\",\"inputs\": [{\"type\": \"bytes32\",\"name\": \"role\",\"indexed\": true,\"internalType\": \"bytes32\"},{\"type\": \"address\",\"name\": \"account\",\"indexed\": true,\"internalType\": \"address\"},{\"type\": \"address\",\"name\": \"sender\",\"indexed\": true,\"internalType\": \"address\"}],\"outputs\": [],\"anonymous\": false},{\"type\": \"event\",\"name\": \"RoleRevoked\",\"inputs\": [{\"type\": \"bytes32\",\"name\": \"role\",\"indexed\": true,\"internalType\": \"bytes32\"},{\"type\": \"address\",\"name\": \"account\",\"indexed\": true,\"internalType\": \"address\"},{\"type\": \"address\",\"name\": \"sender\",\"indexed\": true,\"internalType\": \"address\"}],\"outputs\": [],\"anonymous\": false},{\"type\": \"event\",\"name\": \"SignerAdded\",\"inputs\": [{\"type\": \"address\",\"name\": \"account\",\"indexed\": true,\"internalType\": \"address\"},{\"type\": \"address\",\"name\": \"signer\",\"indexed\": true,\"internalType\": \"address\"}],\"outputs\": [],\"anonymous\": false},{\"type\": \"event\",\"name\": \"SignerRemoved\",\"inputs\": [{\"type\": \"address\",\"name\": \"account\",\"indexed\": true,\"internalType\": \"address\"},{\"type\": \"address\",\"name\": \"signer\",\"indexed\": true,\"internalType\": \"address\"}],\"outputs\": [],\"anonymous\": false},{\"type\": \"fallback\",\"name\": \"\",\"inputs\": [],\"outputs\": [],\"stateMutability\": \"payable\"},{\"type\": \"function\",\"name\": \"DEFAULT_ADMIN_ROLE\",\"inputs\": [],\"outputs\": [{\"type\": \"bytes32\",\"name\": \"\",\"internalType\": \"bytes32\"}],\"stateMutability\": \"view\"},{\"type\": \"function\",\"name\": \"_disableFunctionInExtension\",\"inputs\": [{\"type\": \"string\",\"name\": \"_extensionName\",\"internalType\": \"string\"},{\"type\": \"bytes4\",\"name\": \"_functionSelector\",\"internalType\": \"bytes4\"}],\"outputs\": [],\"stateMutability\": \"nonpayable\"},{\"type\": \"function\",\"name\": \"accountImplementation\",\"inputs\": [],\"outputs\": [{\"type\": \"address\",\"name\": \"\",\"internalType\": \"address\"}],\"stateMutability\": \"view\"},{\"type\": \"function\",\"name\": \"addExtension\",\"inputs\": [{\"type\": \"tuple\",\"name\": \"_extension\",\"components\": [{\"type\": \"tuple\",\"name\": \"metadata\",\"components\": [{\"internalType\": \"string\",\"name\": \"name\",\"type\": \"string\"},{\"internalType\": \"string\",\"name\": \"metadataURI\",\"type\": \"string\"},{\"internalType\": \"address\",\"name\": \"implementation\",\"type\": \"address\"}],\"internalType\": \"struct IExtension.ExtensionMetadata\"},{\"type\": \"tuple[]\",\"name\": \"functions\",\"components\": [{\"internalType\": \"bytes4\",\"name\": \"functionSelector\",\"type\": \"bytes4\"},{\"internalType\": \"string\",\"name\": \"functionSignature\",\"type\": \"string\"}],\"internalType\": \"struct IExtension.ExtensionFunction[]\"}],\"internalType\": \"struct IExtension.Extension\"}],\"outputs\": [],\"stateMutability\": \"nonpayable\"},{\"type\": \"function\",\"name\": \"contractURI\",\"inputs\": [],\"outputs\": [{\"type\": \"string\",\"name\": \"\",\"internalType\": \"string\"}],\"stateMutability\": \"view\"},{\"type\": \"function\",\"name\": \"createAccount\",\"inputs\": [{\"type\": \"address\",\"name\": \"_admin\",\"internalType\": \"address\"},{\"type\": \"bytes\",\"name\": \"_data\",\"internalType\": \"bytes\"}],\"outputs\": [{\"type\": \"address\",\"name\": \"\",\"internalType\": \"address\"}],\"stateMutability\": \"nonpayable\"},{\"type\": \"function\",\"name\": \"defaultExtensions\",\"inputs\": [],\"outputs\": [{\"type\": \"address\",\"name\": \"\",\"internalType\": \"address\"}],\"stateMutability\": \"view\"},{\"type\": \"function\",\"name\": \"disableFunctionInExtension\",\"inputs\": [{\"type\": \"string\",\"name\": \"_extensionName\",\"internalType\": \"string\"},{\"type\": \"bytes4\",\"name\": \"_functionSelector\",\"internalType\": \"bytes4\"}],\"outputs\": [],\"stateMutability\": \"nonpayable\"},{\"type\": \"function\",\"name\": \"enableFunctionInExtension\",\"inputs\": [{\"type\": \"string\",\"name\": \"_extensionName\",\"internalType\": \"string\"},{\"type\": \"tuple\",\"name\": \"_function\",\"components\": [{\"type\": \"bytes4\",\"name\": \"functionSelector\",\"internalType\": \"bytes4\"},{\"type\": \"string\",\"name\": \"functionSignature\",\"internalType\": \"string\"}],\"internalType\": \"struct IExtension.ExtensionFunction\"}],\"outputs\": [],\"stateMutability\": \"nonpayable\"},{\"type\": \"function\",\"name\": \"entrypoint\",\"inputs\": [],\"outputs\": [{\"type\": \"address\",\"name\": \"\",\"internalType\": \"address\"}],\"stateMutability\": \"view\"},{\"type\": \"function\",\"name\": \"getAccounts\",\"inputs\": [{\"type\": \"uint256\",\"name\": \"_start\",\"internalType\": \"uint256\"},{\"type\": \"uint256\",\"name\": \"_end\",\"internalType\": \"uint256\"}],\"outputs\": [{\"type\": \"address[]\",\"name\": \"accounts\",\"internalType\": \"address[]\"}],\"stateMutability\": \"view\"},{\"type\": \"function\",\"name\": \"getAccountsOfSigner\",\"inputs\": [{\"type\": \"address\",\"name\": \"signer\",\"internalType\": \"address\"}],\"outputs\": [{\"type\": \"address[]\",\"name\": \"accounts\",\"internalType\": \"address[]\"}],\"stateMutability\": \"view\"},{\"type\": \"function\",\"name\": \"getAddress\",\"inputs\": [{\"type\": \"address\",\"name\": \"_adminSigner\",\"internalType\": \"address\"},{\"type\": \"bytes\",\"name\": \"_data\",\"internalType\": \"bytes\"}],\"outputs\": [{\"type\": \"address\",\"name\": \"\",\"internalType\": \"address\"}],\"stateMutability\": \"view\"},{\"type\": \"function\",\"name\": \"getAllAccounts\",\"inputs\": [],\"outputs\": [{\"type\": \"address[]\",\"name\": \"\",\"internalType\": \"address[]\"}],\"stateMutability\": \"view\"},{\"type\": \"function\",\"name\": \"getAllExtensions\",\"inputs\": [],\"outputs\": [{\"type\": \"tuple[]\",\"name\": \"allExtensions\",\"components\": [{\"type\": \"tuple\",\"name\": \"metadata\",\"components\": [{\"internalType\": \"string\",\"name\": \"name\",\"type\": \"string\"},{\"internalType\": \"string\",\"name\": \"metadataURI\",\"type\": \"string\"},{\"internalType\": \"address\",\"name\": \"implementation\",\"type\": \"address\"}],\"internalType\": \"struct IExtension.ExtensionMetadata\"},{\"type\": \"tuple[]\",\"name\": \"functions\",\"components\": [{\"internalType\": \"bytes4\",\"name\": \"functionSelector\",\"type\": \"bytes4\"},{\"internalType\": \"string\",\"name\": \"functionSignature\",\"type\": \"string\"}],\"internalType\": \"struct IExtension.ExtensionFunction[]\"}],\"internalType\": \"struct IExtension.Extension[]\"}],\"stateMutability\": \"view\"},{\"type\": \"function\",\"name\": \"getExtension\",\"inputs\": [{\"type\": \"string\",\"name\": \"extensionName\",\"internalType\": \"string\"}],\"outputs\": [{\"type\": \"tuple\",\"name\": \"\",\"components\": [{\"type\": \"tuple\",\"name\": \"metadata\",\"components\": [{\"internalType\": \"string\",\"name\": \"name\",\"type\": \"string\"},{\"internalType\": \"string\",\"name\": \"metadataURI\",\"type\": \"string\"},{\"internalType\": \"address\",\"name\": \"implementation\",\"type\": \"address\"}],\"internalType\": \"struct IExtension.ExtensionMetadata\"},{\"type\": \"tuple[]\",\"name\": \"functions\",\"components\": [{\"internalType\": \"bytes4\",\"name\": \"functionSelector\",\"type\": \"bytes4\"},{\"internalType\": \"string\",\"name\": \"functionSignature\",\"type\": \"string\"}],\"internalType\": \"struct IExtension.ExtensionFunction[]\"}],\"internalType\": \"struct IExtension.Extension\"}],\"stateMutability\": \"view\"},{\"type\": \"function\",\"name\": \"getImplementationForFunction\",\"inputs\": [{\"type\": \"bytes4\",\"name\": \"_functionSelector\",\"internalType\": \"bytes4\"}],\"outputs\": [{\"type\": \"address\",\"name\": \"\",\"internalType\": \"address\"}],\"stateMutability\": \"view\"},{\"type\": \"function\",\"name\": \"getMetadataForFunction\",\"inputs\": [{\"type\": \"bytes4\",\"name\": \"functionSelector\",\"internalType\": \"bytes4\"}],\"outputs\": [{\"type\": \"tuple\",\"name\": \"\",\"components\": [{\"type\": \"string\",\"name\": \"name\",\"internalType\": \"string\"},{\"type\": \"string\",\"name\": \"metadataURI\",\"internalType\": \"string\"},{\"type\": \"address\",\"name\": \"implementation\",\"internalType\": \"address\"}],\"internalType\": \"struct IExtension.ExtensionMetadata\"}],\"stateMutability\": \"view\"},{\"type\": \"function\",\"name\": \"getRoleAdmin\",\"inputs\": [{\"type\": \"bytes32\",\"name\": \"role\",\"internalType\": \"bytes32\"}],\"outputs\": [{\"type\": \"bytes32\",\"name\": \"\",\"internalType\": \"bytes32\"}],\"stateMutability\": \"view\"},{\"type\": \"function\",\"name\": \"getRoleMember\",\"inputs\": [{\"type\": \"bytes32\",\"name\": \"role\",\"internalType\": \"bytes32\"},{\"type\": \"uint256\",\"name\": \"index\",\"internalType\": \"uint256\"}],\"outputs\": [{\"type\": \"address\",\"name\": \"member\",\"internalType\": \"address\"}],\"stateMutability\": \"view\"},{\"type\": \"function\",\"name\": \"getRoleMemberCount\",\"inputs\": [{\"type\": \"bytes32\",\"name\": \"role\",\"internalType\": \"bytes32\"}],\"outputs\": [{\"type\": \"uint256\",\"name\": \"count\",\"internalType\": \"uint256\"}],\"stateMutability\": \"view\"},{\"type\": \"function\",\"name\": \"grantRole\",\"inputs\": [{\"type\": \"bytes32\",\"name\": \"role\",\"internalType\": \"bytes32\"},{\"type\": \"address\",\"name\": \"account\",\"internalType\": \"address\"}],\"outputs\": [],\"stateMutability\": \"nonpayable\"},{\"type\": \"function\",\"name\": \"hasRole\",\"inputs\": [{\"type\": \"bytes32\",\"name\": \"role\",\"internalType\": \"bytes32\"},{\"type\": \"address\",\"name\": \"account\",\"internalType\": \"address\"}],\"outputs\": [{\"type\": \"bool\",\"name\": \"\",\"internalType\": \"bool\"}],\"stateMutability\": \"view\"},{\"type\": \"function\",\"name\": \"hasRoleWithSwitch\",\"inputs\": [{\"type\": \"bytes32\",\"name\": \"role\",\"internalType\": \"bytes32\"},{\"type\": \"address\",\"name\": \"account\",\"internalType\": \"address\"}],\"outputs\": [{\"type\": \"bool\",\"name\": \"\",\"internalType\": \"bool\"}],\"stateMutability\": \"view\"},{\"type\": \"function\",\"name\": \"isRegistered\",\"inputs\": [{\"type\": \"address\",\"name\": \"_account\",\"internalType\": \"address\"}],\"outputs\": [{\"type\": \"bool\",\"name\": \"\",\"internalType\": \"bool\"}],\"stateMutability\": \"view\"},{\"type\": \"function\",\"name\": \"multicall\",\"inputs\": [{\"type\": \"bytes[]\",\"name\": \"data\",\"internalType\": \"bytes[]\"}],\"outputs\": [{\"type\": \"bytes[]\",\"name\": \"results\",\"internalType\": \"bytes[]\"}],\"stateMutability\": \"nonpayable\"},{\"type\": \"function\",\"name\": \"onRegister\",\"inputs\": [{\"type\": \"bytes32\",\"name\": \"_salt\",\"internalType\": \"bytes32\"}],\"outputs\": [],\"stateMutability\": \"nonpayable\"},{\"type\": \"function\",\"name\": \"onSignerAdded\",\"inputs\": [{\"type\": \"address\",\"name\": \"_signer\",\"internalType\": \"address\"},{\"type\": \"bytes32\",\"name\": \"_salt\",\"internalType\": \"bytes32\"}],\"outputs\": [],\"stateMutability\": \"nonpayable\"},{\"type\": \"function\",\"name\": \"onSignerRemoved\",\"inputs\": [{\"type\": \"address\",\"name\": \"_signer\",\"internalType\": \"address\"},{\"type\": \"bytes32\",\"name\": \"_salt\",\"internalType\": \"bytes32\"}],\"outputs\": [],\"stateMutability\": \"nonpayable\"},{\"type\": \"function\",\"name\": \"removeExtension\",\"inputs\": [{\"type\": \"string\",\"name\": \"_extensionName\",\"internalType\": \"string\"}],\"outputs\": [],\"stateMutability\": \"nonpayable\"},{\"type\": \"function\",\"name\": \"renounceRole\",\"inputs\": [{\"type\": \"bytes32\",\"name\": \"role\",\"internalType\": \"bytes32\"},{\"type\": \"address\",\"name\": \"account\",\"internalType\": \"address\"}],\"outputs\": [],\"stateMutability\": \"nonpayable\"},{\"type\": \"function\",\"name\": \"replaceExtension\",\"inputs\": [{\"type\": \"tuple\",\"name\": \"_extension\",\"components\": [{\"type\": \"tuple\",\"name\": \"metadata\",\"components\": [{\"internalType\": \"string\",\"name\": \"name\",\"type\": \"string\"},{\"internalType\": \"string\",\"name\": \"metadataURI\",\"type\": \"string\"},{\"internalType\": \"address\",\"name\": \"implementation\",\"type\": \"address\"}],\"internalType\": \"struct IExtension.ExtensionMetadata\"},{\"type\": \"tuple[]\",\"name\": \"functions\",\"components\": [{\"internalType\": \"bytes4\",\"name\": \"functionSelector\",\"type\": \"bytes4\"},{\"internalType\": \"string\",\"name\": \"functionSignature\",\"type\": \"string\"}],\"internalType\": \"struct IExtension.ExtensionFunction[]\"}],\"internalType\": \"struct IExtension.Extension\"}],\"outputs\": [],\"stateMutability\": \"nonpayable\"},{\"type\": \"function\",\"name\": \"revokeRole\",\"inputs\": [{\"type\": \"bytes32\",\"name\": \"role\",\"internalType\": \"bytes32\"},{\"type\": \"address\",\"name\": \"account\",\"internalType\": \"address\"}],\"outputs\": [],\"stateMutability\": \"nonpayable\"},{\"type\": \"function\",\"name\": \"setContractURI\",\"inputs\": [{\"type\": \"string\",\"name\": \"_uri\",\"internalType\": \"string\"}],\"outputs\": [],\"stateMutability\": \"nonpayable\"},{\"type\": \"function\",\"name\": \"totalAccounts\",\"inputs\": [],\"outputs\": [{\"type\": \"uint256\",\"name\": \"\",\"internalType\": \"uint256\"}],\"stateMutability\": \"view\"}]" - ); - var accountAddress = accountAddressOverride ?? await ThirdwebContract.Read(factoryContract, "getAddress", await personalWallet.GetAddress(), new byte[0]); - accountContract = await ThirdwebContract.Create( - personalWallet.Client, - accountAddress, - chainId, - "[{type: \"constructor\",inputs: [{name: \"_entrypoint\",type: \"address\",internalType: \"contract IEntryPoint\",},{ name: \"_factory\", type: \"address\", internalType: \"address\" },],stateMutability: \"nonpayable\",},{ type: \"receive\", stateMutability: \"payable\" },{type: \"function\",name: \"addDeposit\",inputs: [],outputs: [],stateMutability: \"payable\",},{type: \"function\",name: \"contractURI\",inputs: [],outputs: [{ name: \"\", type: \"string\", internalType: \"string\" }],stateMutability: \"view\",},{type: \"function\",name: \"entryPoint\",inputs: [],outputs: [{ name: \"\", type: \"address\", internalType: \"contract IEntryPoint\" },],stateMutability: \"view\",},{type: \"function\",name: \"execute\",inputs: [{ name: \"_target\", type: \"address\", internalType: \"address\" },{ name: \"_value\", type: \"uint256\", internalType: \"uint256\" },{ name: \"_calldata\", type: \"bytes\", internalType: \"bytes\" },],outputs: [],stateMutability: \"nonpayable\",},{type: \"function\",name: \"executeBatch\",inputs: [{ name: \"_target\", type: \"address[]\", internalType: \"address[]\" },{ name: \"_value\", type: \"uint256[]\", internalType: \"uint256[]\" },{ name: \"_calldata\", type: \"bytes[]\", internalType: \"bytes[]\" },],outputs: [],stateMutability: \"nonpayable\",},{type: \"function\",name: \"factory\",inputs: [],outputs: [{ name: \"\", type: \"address\", internalType: \"address\" }],stateMutability: \"view\",},{type: \"function\",name: \"getAllActiveSigners\",inputs: [],outputs: [{name: \"signers\",type: \"tuple[]\",internalType: \"struct IAccountPermissions.SignerPermissions[]\",components: [{ name: \"signer\", type: \"address\", internalType: \"address\" },{name: \"approvedTargets\",type: \"address[]\",internalType: \"address[]\",},{name: \"nativeTokenLimitPerTransaction\",type: \"uint256\",internalType: \"uint256\",},{ name: \"startTimestamp\", type: \"uint128\", internalType: \"uint128\" },{ name: \"endTimestamp\", type: \"uint128\", internalType: \"uint128\" },],},],stateMutability: \"view\",},{type: \"function\",name: \"getAllAdmins\",inputs: [],outputs: [{ name: \"\", type: \"address[]\", internalType: \"address[]\" }],stateMutability: \"view\",},{type: \"function\",name: \"getAllSigners\",inputs: [],outputs: [{name: \"signers\",type: \"tuple[]\",internalType: \"struct IAccountPermissions.SignerPermissions[]\",components: [{ name: \"signer\", type: \"address\", internalType: \"address\" },{name: \"approvedTargets\",type: \"address[]\",internalType: \"address[]\",},{name: \"nativeTokenLimitPerTransaction\",type: \"uint256\",internalType: \"uint256\",},{ name: \"startTimestamp\", type: \"uint128\", internalType: \"uint128\" },{ name: \"endTimestamp\", type: \"uint128\", internalType: \"uint128\" },],},],stateMutability: \"view\",},{type: \"function\",name: \"getMessageHash\",inputs: [{ name: \"_hash\", type: \"bytes32\", internalType: \"bytes32\" }],outputs: [{ name: \"\", type: \"bytes32\", internalType: \"bytes32\" }],stateMutability: \"view\",},{type: \"function\",name: \"getNonce\",inputs: [],outputs: [{ name: \"\", type: \"uint256\", internalType: \"uint256\" }],stateMutability: \"view\",},{type: \"function\",name: \"getPermissionsForSigner\",inputs: [{ name: \"signer\", type: \"address\", internalType: \"address\" }],outputs: [{name: \"\",type: \"tuple\",internalType: \"struct IAccountPermissions.SignerPermissions\",components: [{ name: \"signer\", type: \"address\", internalType: \"address\" },{name: \"approvedTargets\",type: \"address[]\",internalType: \"address[]\",},{name: \"nativeTokenLimitPerTransaction\",type: \"uint256\",internalType: \"uint256\",},{ name: \"startTimestamp\", type: \"uint128\", internalType: \"uint128\" },{ name: \"endTimestamp\", type: \"uint128\", internalType: \"uint128\" },],},],stateMutability: \"view\",},{type: \"function\",name: \"initialize\",inputs: [{ name: \"_defaultAdmin\", type: \"address\", internalType: \"address\" },{ name: \"_data\", type: \"bytes\", internalType: \"bytes\" },],outputs: [],stateMutability: \"nonpayable\",},{type: \"function\",name: \"isActiveSigner\",inputs: [{ name: \"signer\", type: \"address\", internalType: \"address\" }],outputs: [{ name: \"\", type: \"bool\", internalType: \"bool\" }],stateMutability: \"view\",},{type: \"function\",name: \"isAdmin\",inputs: [{ name: \"_account\", type: \"address\", internalType: \"address\" }],outputs: [{ name: \"\", type: \"bool\", internalType: \"bool\" }],stateMutability: \"view\",},{type: \"function\",name: \"isValidSignature\",inputs: [{ name: \"_hash\", type: \"bytes32\", internalType: \"bytes32\" },{ name: \"_signature\", type: \"bytes\", internalType: \"bytes\" },],outputs: [{ name: \"magicValue\", type: \"bytes4\", internalType: \"bytes4\" }],stateMutability: \"view\",},{type: \"function\",name: \"isValidSigner\",inputs: [{ name: \"_signer\", type: \"address\", internalType: \"address\" },{name: \"_userOp\",type: \"tuple\",internalType: \"struct UserOperation\",components: [{ name: \"sender\", type: \"address\", internalType: \"address\" },{ name: \"nonce\", type: \"uint256\", internalType: \"uint256\" },{ name: \"initCode\", type: \"bytes\", internalType: \"bytes\" },{ name: \"callData\", type: \"bytes\", internalType: \"bytes\" },{ name: \"callGasLimit\", type: \"uint256\", internalType: \"uint256\" },{name: \"verificationGasLimit\",type: \"uint256\",internalType: \"uint256\",},{name: \"preVerificationGas\",type: \"uint256\",internalType: \"uint256\",},{ name: \"maxFeePerGas\", type: \"uint256\", internalType: \"uint256\" },{name: \"maxPriorityFeePerGas\",type: \"uint256\",internalType: \"uint256\",},{ name: \"paymasterAndData\", type: \"bytes\", internalType: \"bytes\" },{ name: \"signature\", type: \"bytes\", internalType: \"bytes\" },],},],outputs: [{ name: \"\", type: \"bool\", internalType: \"bool\" }],stateMutability: \"view\",},{type: \"function\",name: \"multicall\",inputs: [{ name: \"data\", type: \"bytes[]\", internalType: \"bytes[]\" }],outputs: [{ name: \"results\", type: \"bytes[]\", internalType: \"bytes[]\" }],stateMutability: \"nonpayable\",},{type: \"function\",name: \"onERC1155BatchReceived\",inputs: [{ name: \"\", type: \"address\", internalType: \"address\" },{ name: \"\", type: \"address\", internalType: \"address\" },{ name: \"\", type: \"uint256[]\", internalType: \"uint256[]\" },{ name: \"\", type: \"uint256[]\", internalType: \"uint256[]\" },{ name: \"\", type: \"bytes\", internalType: \"bytes\" },],outputs: [{ name: \"\", type: \"bytes4\", internalType: \"bytes4\" }],stateMutability: \"nonpayable\",},{type: \"function\",name: \"onERC1155Received\",inputs: [{ name: \"\", type: \"address\", internalType: \"address\" },{ name: \"\", type: \"address\", internalType: \"address\" },{ name: \"\", type: \"uint256\", internalType: \"uint256\" },{ name: \"\", type: \"uint256\", internalType: \"uint256\" },{ name: \"\", type: \"bytes\", internalType: \"bytes\" },],outputs: [{ name: \"\", type: \"bytes4\", internalType: \"bytes4\" }],stateMutability: \"nonpayable\",},{type: \"function\",name: \"onERC721Received\",inputs: [{ name: \"\", type: \"address\", internalType: \"address\" },{ name: \"\", type: \"address\", internalType: \"address\" },{ name: \"\", type: \"uint256\", internalType: \"uint256\" },{ name: \"\", type: \"bytes\", internalType: \"bytes\" },],outputs: [{ name: \"\", type: \"bytes4\", internalType: \"bytes4\" }],stateMutability: \"nonpayable\",},{type: \"function\",name: \"setContractURI\",inputs: [{ name: \"_uri\", type: \"string\", internalType: \"string\" }],outputs: [],stateMutability: \"nonpayable\",},{type: \"function\",name: \"setEntrypointOverride\",inputs: [{name: \"_entrypointOverride\",type: \"address\",internalType: \"contract IEntryPoint\",},],outputs: [],stateMutability: \"nonpayable\",},{type: \"function\",name: \"setPermissionsForSigner\",inputs: [{name: \"_req\",type: \"tuple\",internalType: \"struct IAccountPermissions.SignerPermissionRequest\",components: [{ name: \"signer\", type: \"address\", internalType: \"address\" },{ name: \"isAdmin\", type: \"uint8\", internalType: \"uint8\" },{name: \"approvedTargets\",type: \"address[]\",internalType: \"address[]\",},{name: \"nativeTokenLimitPerTransaction\",type: \"uint256\",internalType: \"uint256\",},{name: \"permissionStartTimestamp\",type: \"uint128\",internalType: \"uint128\",},{name: \"permissionEndTimestamp\",type: \"uint128\",internalType: \"uint128\",},{name: \"reqValidityStartTimestamp\",type: \"uint128\",internalType: \"uint128\",},{name: \"reqValidityEndTimestamp\",type: \"uint128\",internalType: \"uint128\",},{ name: \"uid\", type: \"bytes32\", internalType: \"bytes32\" },],},{ name: \"_signature\", type: \"bytes\", internalType: \"bytes\" },],outputs: [],stateMutability: \"nonpayable\",},{type: \"function\",name: \"supportsInterface\",inputs: [{ name: \"interfaceId\", type: \"bytes4\", internalType: \"bytes4\" }],outputs: [{ name: \"\", type: \"bool\", internalType: \"bool\" }],stateMutability: \"view\",},{type: \"function\",name: \"validateUserOp\",inputs: [{name: \"userOp\",type: \"tuple\",internalType: \"struct UserOperation\",components: [{ name: \"sender\", type: \"address\", internalType: \"address\" },{ name: \"nonce\", type: \"uint256\", internalType: \"uint256\" },{ name: \"initCode\", type: \"bytes\", internalType: \"bytes\" },{ name: \"callData\", type: \"bytes\", internalType: \"bytes\" },{ name: \"callGasLimit\", type: \"uint256\", internalType: \"uint256\" },{name: \"verificationGasLimit\",type: \"uint256\",internalType: \"uint256\",},{name: \"preVerificationGas\",type: \"uint256\",internalType: \"uint256\",},{ name: \"maxFeePerGas\", type: \"uint256\", internalType: \"uint256\" },{name: \"maxPriorityFeePerGas\",type: \"uint256\",internalType: \"uint256\",},{ name: \"paymasterAndData\", type: \"bytes\", internalType: \"bytes\" },{ name: \"signature\", type: \"bytes\", internalType: \"bytes\" },],},{ name: \"userOpHash\", type: \"bytes32\", internalType: \"bytes32\" },{ name: \"missingAccountFunds\", type: \"uint256\", internalType: \"uint256\" },],outputs: [{ name: \"validationData\", type: \"uint256\", internalType: \"uint256\" },],stateMutability: \"nonpayable\",},{type: \"function\",name: \"verifySignerPermissionRequest\",inputs: [{name: \"req\",type: \"tuple\",internalType: \"struct IAccountPermissions.SignerPermissionRequest\",components: [{ name: \"signer\", type: \"address\", internalType: \"address\" },{ name: \"isAdmin\", type: \"uint8\", internalType: \"uint8\" },{name: \"approvedTargets\",type: \"address[]\",internalType: \"address[]\",},{name: \"nativeTokenLimitPerTransaction\",type: \"uint256\",internalType: \"uint256\",},{name: \"permissionStartTimestamp\",type: \"uint128\",internalType: \"uint128\",},{name: \"permissionEndTimestamp\",type: \"uint128\",internalType: \"uint128\",},{name: \"reqValidityStartTimestamp\",type: \"uint128\",internalType: \"uint128\",},{name: \"reqValidityEndTimestamp\",type: \"uint128\",internalType: \"uint128\",},{ name: \"uid\", type: \"bytes32\", internalType: \"bytes32\" },],},{ name: \"signature\", type: \"bytes\", internalType: \"bytes\" },],outputs: [{ name: \"success\", type: \"bool\", internalType: \"bool\" },{ name: \"signer\", type: \"address\", internalType: \"address\" },],stateMutability: \"view\",},{type: \"function\",name: \"withdrawDepositTo\",inputs: [{name: \"withdrawAddress\",type: \"address\",internalType: \"address payable\",},{ name: \"amount\", type: \"uint256\", internalType: \"uint256\" },],outputs: [],stateMutability: \"nonpayable\",},{type: \"event\",name: \"AdminUpdated\",inputs: [{name: \"signer\",type: \"address\",indexed: true,internalType: \"address\",},{ name: \"isAdmin\", type: \"bool\", indexed: false, internalType: \"bool\" },],anonymous: false,},{type: \"event\",name: \"ContractURIUpdated\",inputs: [{name: \"prevURI\",type: \"string\",indexed: false,internalType: \"string\",},{name: \"newURI\",type: \"string\",indexed: false,internalType: \"string\",},],anonymous: false,},{type: \"event\",name: \"Initialized\",inputs: [{ name: \"version\", type: \"uint8\", indexed: false, internalType: \"uint8\" },],anonymous: false,},{type: \"event\",name: \"SignerPermissionsUpdated\",inputs: [{name: \"authorizingSigner\",type: \"address\",indexed: true,internalType: \"address\",},{name: \"targetSigner\",type: \"address\",indexed: true,internalType: \"address\",},{name: \"permissions\",type: \"tuple\",indexed: false,internalType: \"struct IAccountPermissions.SignerPermissionRequest\",components: [{ name: \"signer\", type: \"address\", internalType: \"address\" },{ name: \"isAdmin\", type: \"uint8\", internalType: \"uint8\" },{name: \"approvedTargets\",type: \"address[]\",internalType: \"address[]\",},{name: \"nativeTokenLimitPerTransaction\",type: \"uint256\",internalType: \"uint256\",},{name: \"permissionStartTimestamp\",type: \"uint128\",internalType: \"uint128\",},{name: \"permissionEndTimestamp\",type: \"uint128\",internalType: \"uint128\",},{name: \"reqValidityStartTimestamp\",type: \"uint128\",internalType: \"uint128\",},{name: \"reqValidityEndTimestamp\",type: \"uint128\",internalType: \"uint128\",},{ name: \"uid\", type: \"bytes32\", internalType: \"bytes32\" },],},],anonymous: false,},]" - ); - } + public string WalletId => "smart"; - return new SmartWallet(personalWallet, gasless, chainId, bundlerUrl, paymasterUrl, entryPointContract, factoryContract, accountContract); - } + public bool IsDeploying { get; private set; } - public async Task IsDeployed() - { - if (Utils.IsZkSync(_chainId)) - { - return true; - } + public BigInteger ActiveChainId { get; private set; } - var code = await ThirdwebRPC.GetRpcInstance(Client, _chainId).SendRequestAsync("eth_getCode", _accountContract.Address, "latest"); - return code != "0x"; - } + private readonly IThirdwebWallet _personalAccount; + private ThirdwebContract _factoryContract; + private ThirdwebContract _accountContract; + private ThirdwebContract _entryPointContract; + private string _bundlerUrl; + private string _paymasterUrl; + private bool _isApproving; + private bool _isApproved; + + private readonly string _erc20PaymasterAddress; + private readonly string _erc20PaymasterToken; + private readonly BigInteger _erc20PaymasterStorageSlot; + private readonly bool _gasless; - public async Task SendTransaction(ThirdwebTransactionInput transactionInput) + private struct TokenPaymasterConfig + { + public BigInteger ChainId; + public string PaymasterAddress; + public string TokenAddress; + public BigInteger BalanceStorageSlot; + } + + private static readonly Dictionary _tokenPaymasterConfig = new() + { { - if (transactionInput == null) + TokenPaymaster.NONE, + new TokenPaymasterConfig() { - throw new InvalidOperationException("SmartAccount.SendTransaction: Transaction input is required."); + ChainId = 0, + PaymasterAddress = null, + TokenAddress = null, + BalanceStorageSlot = 0, } - - if (Utils.IsZkSync(_chainId)) + }, + { + TokenPaymaster.BASE_USDC, + new TokenPaymasterConfig() { - var transaction = await ThirdwebTransaction.Create(_personalAccount, transactionInput, _chainId); - - if (transactionInput.Nonce == null) - { - _ = transaction.SetNonce(await ThirdwebTransaction.GetNonce(transaction)); - } - if (transactionInput.Gas == null) - { - _ = transaction.SetGasLimit(await ThirdwebTransaction.EstimateGasLimit(transaction)); - } - if (transactionInput.MaxFeePerGas == null) - { - (var maxFee, _) = await ThirdwebTransaction.EstimateGasFees(transaction); - _ = transaction.SetMaxFeePerGas(maxFee); - } - - if (_gasless) - { - (var paymaster, var paymasterInput) = await ZkPaymasterData(transactionInput); - transaction = transaction.SetZkSyncOptions(new ZkSyncOptions(paymaster: paymaster, paymasterInput: paymasterInput)); - var zkTx = await ThirdwebTransaction.ConvertToZkSyncTransaction(transaction); - var zkTxSigned = await EIP712.GenerateSignature_ZkSyncTransaction("zkSync", "2", transaction.Input.ChainId.Value, zkTx, this); - // Match bundler ZkTransactionInput type without recreating - var hash = await ZkBroadcastTransaction( - new - { - nonce = zkTx.Nonce.ToString(), - from = zkTx.From, - to = zkTx.To, - gas = zkTx.GasLimit.ToString(), - gasPrice = string.Empty, - value = zkTx.Value.ToString(), - data = Utils.BytesToHex(zkTx.Data), - maxFeePerGas = zkTx.MaxFeePerGas.ToString(), - maxPriorityFeePerGas = zkTx.MaxPriorityFeePerGas.ToString(), - chainId = _chainId.ToString(), - signedTransaction = zkTxSigned, - paymaster = paymaster - } - ); - return hash; - } - else - { - return await ThirdwebTransaction.Send(transaction); - } + ChainId = 8453, + PaymasterAddress = "0x2222f2738BE6bB7aA0Bfe4AEeAf2908172CF5539", + TokenAddress = "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913", + BalanceStorageSlot = 9, } - else + }, + { + TokenPaymaster.CELO_CUSD, + new TokenPaymasterConfig() { - var signedOp = await SignUserOp(transactionInput); - return await SendUserOp(signedOp); + ChainId = 42220, + PaymasterAddress = "0x3feA3c5744D715ff46e91C4e5C9a94426DfF2aF9", + TokenAddress = "0x765DE816845861e75A25fCA122bb6898B8B1282a", + BalanceStorageSlot = 9, } - } - - private async Task GetInitCode() + }, { - if (_isDeploying || await IsDeployed()) + TokenPaymaster.LISK_LSK, + new TokenPaymasterConfig() { - return new byte[0]; + ChainId = 1135, + PaymasterAddress = "0x9eb8cf7fBa5ed9EeDCC97a0d52254cc0e9B1AC25", + TokenAddress = "0xac485391EB2d7D88253a7F1eF18C37f4242D1A24", + BalanceStorageSlot = 9, } + }, + }; + + private bool UseERC20Paymaster => !string.IsNullOrEmpty(this._erc20PaymasterAddress) && !string.IsNullOrEmpty(this._erc20PaymasterToken); + + protected SmartWallet( + IThirdwebWallet personalAccount, + bool gasless, + BigInteger chainId, + string bundlerUrl, + string paymasterUrl, + ThirdwebContract entryPointContract, + ThirdwebContract factoryContract, + ThirdwebContract accountContract, + string erc20PaymasterAddress, + string erc20PaymasterToken, + BigInteger erc20PaymasterStorageSlot + ) + { + this.Client = personalAccount.Client; + + this._personalAccount = personalAccount; + this._gasless = gasless; + this.ActiveChainId = chainId; + this._bundlerUrl = bundlerUrl; + this._paymasterUrl = paymasterUrl; + this._entryPointContract = entryPointContract; + this._factoryContract = factoryContract; + this._accountContract = accountContract; + this._erc20PaymasterAddress = erc20PaymasterAddress; + this._erc20PaymasterToken = erc20PaymasterToken; + this._erc20PaymasterStorageSlot = erc20PaymasterStorageSlot; + } - var data = new Contract(null, _factoryContract.Abi, _factoryContract.Address).GetFunction("createAccount").GetData(await _personalAccount.GetAddress(), new byte[0]); - data = Utils.HexConcat(_factoryContract.Address, data); - return data.HexToByteArray(); + #region Creation + + /// + /// Creates a new instance of . + /// + /// The smart wallet's signer to use. + /// The chain ID. + /// Whether to sponsor gas for transactions. + /// Override the default factory address. + /// Override the canonical account address that would be found deterministically based on the signer. + /// Override the default entry point address. We provide Constants for different versions. + /// Override the default thirdweb bundler URL. + /// Override the default thirdweb paymaster URL. + /// Use an ERC20 paymaster and sponsor gas with ERC20s. If set, factoryAddress and accountAddressOverride are ignored. + /// A new instance of . + /// Thrown if the personal account is not connected. + public static async Task Create( + IThirdwebWallet personalWallet, + BigInteger chainId, + bool? gasless = null, + string factoryAddress = null, + string accountAddressOverride = null, + string entryPoint = null, + string bundlerUrl = null, + string paymasterUrl = null, + TokenPaymaster tokenPaymaster = TokenPaymaster.NONE + ) + { + if (!await personalWallet.IsConnected().ConfigureAwait(false)) + { + throw new InvalidOperationException("SmartAccount.Connect: Personal account must be connected."); } - private async Task SignUserOp(ThirdwebTransactionInput transactionInput, int? requestId = null, bool simulation = false) + if (personalWallet is EcosystemWallet ecoWallet) { - requestId ??= 1; - - // Wait until deployed to avoid double initCode - if (!simulation) + try { - while (_isDeploying) + var ecoDetails = await ecoWallet.GetEcosystemDetails(); + if (ecoDetails.SmartAccountOptions.HasValue) { - await Task.Delay(1000); // Wait for the deployment to finish + gasless ??= ecoDetails.SmartAccountOptions?.SponsorGas; + factoryAddress ??= string.IsNullOrEmpty(ecoDetails.SmartAccountOptions?.AccountFactoryAddress) ? null : ecoDetails.SmartAccountOptions?.AccountFactoryAddress; } } - - var initCode = await GetInitCode(); - if (!simulation) + catch { - _isDeploying = initCode.Length > 0; + // no-op } + } - // Create the user operation and its safe (hexified) version - - var executeFn = new ExecuteFunction - { - Target = transactionInput.To, - Value = transactionInput.Value.Value, - Calldata = transactionInput.Data.HexToByteArray(), - FromAddress = await GetAddress(), - }; - var executeInput = executeFn.CreateTransactionInput(await GetAddress()); + entryPoint ??= tokenPaymaster == TokenPaymaster.NONE ? Constants.ENTRYPOINT_ADDRESS_V06 : Constants.ENTRYPOINT_ADDRESS_V07; - var fees = await BundlerClient.ThirdwebGetUserOperationGasPrice(Client, _bundlerUrl, requestId); - var maxFee = new HexBigInteger(fees.maxFeePerGas).Value; - var maxPriorityFee = new HexBigInteger(fees.maxPriorityFeePerGas).Value; + var entryPointVersion = Utils.GetEntryPointVersion(entryPoint); - var partialUserOp = new UserOperation() - { - Sender = _accountContract.Address, - Nonce = await GetNonce(), - InitCode = initCode, - CallData = executeInput.Data.HexToByteArray(), - CallGasLimit = 0, - VerificationGasLimit = 0, - PreVerificationGas = 0, - MaxFeePerGas = maxFee, - MaxPriorityFeePerGas = maxPriorityFee, - PaymasterAndData = new byte[] { }, - Signature = Constants.DUMMY_SIG.HexToByteArray(), - }; + gasless ??= true; + bundlerUrl ??= $"https://{chainId}.bundler.thirdweb.com/v2"; + paymasterUrl ??= $"https://{chainId}.bundler.thirdweb.com/v2"; + factoryAddress ??= entryPointVersion == 6 ? Constants.DEFAULT_FACTORY_ADDRESS_V06 : Constants.DEFAULT_FACTORY_ADDRESS_V07; - // Update paymaster data if any + var entryPointAbi = entryPointVersion == 6 ? Constants.ENTRYPOINT_V06_ABI : Constants.ENTRYPOINT_V07_ABI; + var factoryAbi = entryPointVersion == 6 ? Constants.FACTORY_V06_ABI : Constants.FACTORY_V07_ABI; + var entryPointContract = await ThirdwebContract.Create(personalWallet.Client, entryPoint, chainId, entryPointAbi).ConfigureAwait(false); + var factoryContract = await ThirdwebContract.Create(personalWallet.Client, factoryAddress, chainId, factoryAbi).ConfigureAwait(false); - partialUserOp.PaymasterAndData = await GetPaymasterAndData(requestId, EncodeUserOperation(partialUserOp)); + ThirdwebContract accountContract = null; + if (!await Utils.IsZkSync(personalWallet.Client, chainId).ConfigureAwait(false)) + { + var accountAbi = entryPointVersion == 6 ? Constants.ACCOUNT_V06_ABI : Constants.ACCOUNT_V07_ABI; + var personalAddress = await personalWallet.GetAddress().ConfigureAwait(false); + var accountAddress = accountAddressOverride ?? await ThirdwebContract.Read(factoryContract, "getAddress", personalAddress, Array.Empty()).ConfigureAwait(false); - // Estimate gas + accountContract = await ThirdwebContract.Create(personalWallet.Client, accountAddress, chainId, accountAbi).ConfigureAwait(false); + } - var gasEstimates = await BundlerClient.EthEstimateUserOperationGas(Client, _bundlerUrl, requestId, EncodeUserOperation(partialUserOp), _entryPointContract.Address); - partialUserOp.CallGasLimit = 50000 + new HexBigInteger(gasEstimates.CallGasLimit).Value; - partialUserOp.VerificationGasLimit = new HexBigInteger(gasEstimates.VerificationGas).Value; - partialUserOp.PreVerificationGas = new HexBigInteger(gasEstimates.PreVerificationGas).Value; + var erc20PmInfo = _tokenPaymasterConfig[tokenPaymaster]; - // Update paymaster data if any + if (tokenPaymaster != TokenPaymaster.NONE) + { + if (entryPointVersion != 7) + { + throw new InvalidOperationException("Token paymasters are only supported in entry point version 7."); + } + if (erc20PmInfo.ChainId != chainId) + { + throw new InvalidOperationException("Token paymaster chain ID does not match the smart account chain ID."); + } + } - partialUserOp.PaymasterAndData = await GetPaymasterAndData(requestId, EncodeUserOperation(partialUserOp)); + var smartWallet = new SmartWallet( + personalWallet, + gasless.Value, + chainId, + bundlerUrl, + paymasterUrl, + entryPointContract, + factoryContract, + accountContract, + erc20PmInfo.PaymasterAddress, + erc20PmInfo.TokenAddress, + erc20PmInfo.BalanceStorageSlot + ); + Utils.TrackConnection(smartWallet); + return smartWallet; + } - // Hash, sign and encode the user operation + #endregion - partialUserOp.Signature = await HashAndSignUserOp(partialUserOp, _entryPointContract); + #region Wallet Specific - return partialUserOp; - } + /// + /// Returns the signer that was used to connect to this SmartWallet. + /// + /// The signer. + public Task GetPersonalWallet() + { + return Task.FromResult(this._personalAccount); + } - private async Task SendUserOp(UserOperation userOperation, int? requestId = null) + /// + /// Checks if the smart account is deployed on the current chain. A smart account is typically deployed when a personal message is signed or a transaction is sent. + /// + /// True if deployed, otherwise false. + public async Task IsDeployed() + { + if (await Utils.IsZkSync(this.Client, this.ActiveChainId).ConfigureAwait(false)) { - requestId ??= 1; - - // Send the user operation + return true; + } - var userOpHash = await BundlerClient.EthSendUserOperation(Client, _bundlerUrl, requestId, EncodeUserOperation(userOperation), _entryPointContract.Address); + var code = await ThirdwebRPC.GetRpcInstance(this.Client, this.ActiveChainId).SendRequestAsync("eth_getCode", this._accountContract.Address, "latest").ConfigureAwait(false); + return code != "0x"; + } - // Wait for the transaction to be mined + /// + /// Forces the smart account to deploy on the current chain. This is typically not necessary as the account will deploy automatically when needed. + /// + public async Task ForceDeploy() + { + if (await Utils.IsZkSync(this.Client, this.ActiveChainId).ConfigureAwait(false)) + { + return; + } - string txHash = null; - while (txHash == null) - { - var userOpReceipt = await BundlerClient.EthGetUserOperationReceipt(Client, _bundlerUrl, requestId, userOpHash); - txHash = userOpReceipt?.receipt?.TransactionHash; - await Task.Delay(1000); - } - _isDeploying = false; - return txHash; + if (await this.IsDeployed().ConfigureAwait(false)) + { + return; } - private async Task GetNonce() + if (this.IsDeploying) { - var randomBytes = new byte[24]; - RandomNumberGenerator.Fill(randomBytes); - BigInteger randomInt192 = new(randomBytes); - randomInt192 = BigInteger.Abs(randomInt192) % (BigInteger.One << 192); - return await ThirdwebContract.Read(_entryPointContract, "getNonce", await GetAddress(), randomInt192); + throw new InvalidOperationException("SmartAccount.ForceDeploy: Account is already deploying."); } - private async Task<(string, string)> ZkPaymasterData(ThirdwebTransactionInput transactionInput) + var input = new ThirdwebTransactionInput(chainId: this.ActiveChainId, data: "0x", to: this._accountContract.Address, value: 0); + var txHash = await this.SendTransaction(input).ConfigureAwait(false); + _ = await ThirdwebTransaction.WaitForTransactionReceipt(this.Client, this.ActiveChainId, txHash).ConfigureAwait(false); + } + + /// + /// Verifies if a signature is valid for a message using EIP-1271 or ERC-6492. + /// + /// The message to verify. + /// The signature to verify. + /// True if the signature is valid, otherwise false. + public async Task IsValidSignature(string message, string signature) + { + var isCounterFactual = signature.EndsWith(Constants.ERC_6492_MAGIC_VALUE[2..]); + + // ERC-6492 + if (isCounterFactual) { - if (_gasless) + var erc6492Sig = new ABIEncode().DecodeEncodedComplexType(signature.HexToBytes().Take(signature.Length - 32).ToArray()); + var multicall3 = await ThirdwebContract.Create(this.Client, Constants.MULTICALL3_ADDRESS, this.ActiveChainId).ConfigureAwait(false); + List result; + try { - var result = await BundlerClient.ZkPaymasterData(Client, _paymasterUrl, 1, transactionInput); - return (result.paymaster, result.paymasterInput); + result = await multicall3 + .Read>( + method: "aggregate3", + parameters: new object[] + { + new List + { + new() + { + Target = erc6492Sig.Create2Factory, + AllowFailure = true, + CallData = erc6492Sig.FactoryCalldata, + }, + new() + { + Target = this._accountContract.Address, + AllowFailure = true, + CallData = this._accountContract.CreateCallData("isValidSignature", message.HashPrefixedMessage().HexToBytes(), erc6492Sig.SigToValidate).HexToBytes(), + }, + }, + } + ) + .ConfigureAwait(false); + + var success = result[1].Success; + var returnData = result[1].ReturnData.BytesToHex(); + if (!success) + { + var revertMsg = new Nethereum.ABI.FunctionEncoding.FunctionCallDecoder().DecodeFunctionErrorMessage(returnData); + throw new Exception($"SmartAccount.IsValidSignature: Call to account contract failed: {revertMsg}"); + } + else + { + return returnData == Constants.EIP_1271_MAGIC_VALUE; + } } - else + catch { - return (null, null); + return false; } } - - private async Task ZkBroadcastTransaction(object transactionInput) - { - var result = await BundlerClient.ZkBroadcastTransaction(Client, _bundlerUrl, 1, transactionInput); - return result.transactionHash; - } - - private async Task GetPaymasterAndData(object requestId, UserOperationHexified userOp) + // EIP-1271 + else { - if (_gasless) + try { - var paymasterAndData = await BundlerClient.PMSponsorUserOperation(Client, _paymasterUrl, requestId, userOp, _entryPointContract.Address); - return paymasterAndData.paymasterAndData.HexToByteArray(); + var magicValue = await ThirdwebContract + .Read(this._accountContract, "isValidSignature", Encoding.UTF8.GetBytes(message).HashPrefixedMessage(), signature.HexToBytes()) + .ConfigureAwait(false); + return magicValue.BytesToHex() == new byte[] { 0x16, 0x26, 0xba, 0x7e }.BytesToHex(); } - else + catch { - return new byte[] { }; + return false; } } + } - private async Task HashAndSignUserOp(UserOperation userOp, ThirdwebContract entryPointContract) + /// + /// Gets all admins for the smart account. + /// + /// A list of admin addresses. + public async Task> GetAllAdmins() + { + if (await Utils.IsZkSync(this.Client, this.ActiveChainId).ConfigureAwait(false)) { - var userOpHash = await ThirdwebContract.Read(entryPointContract, "getUserOpHash", userOp); - var sig = await _personalAccount.PersonalSign(userOpHash); - return sig.HexToByteArray(); + throw new InvalidOperationException("Account Permissions are not supported in ZkSync"); } - private UserOperationHexified EncodeUserOperation(UserOperation userOperation) + var result = await ThirdwebContract.Read>(this._accountContract, "getAllAdmins").ConfigureAwait(false); + return result ?? new List(); + } + + /// + /// Gets all active signers for the smart account. + /// + /// A list of . + public async Task> GetAllActiveSigners() + { + if (await Utils.IsZkSync(this.Client, this.ActiveChainId).ConfigureAwait(false)) { - return new UserOperationHexified() - { - sender = userOperation.Sender, - nonce = userOperation.Nonce.ToHexBigInteger().HexValue, - initCode = userOperation.InitCode.ToHex(true), - callData = userOperation.CallData.ToHex(true), - callGasLimit = userOperation.CallGasLimit.ToHexBigInteger().HexValue, - verificationGasLimit = userOperation.VerificationGasLimit.ToHexBigInteger().HexValue, - preVerificationGas = userOperation.PreVerificationGas.ToHexBigInteger().HexValue, - maxFeePerGas = userOperation.MaxFeePerGas.ToHexBigInteger().HexValue, - maxPriorityFeePerGas = userOperation.MaxPriorityFeePerGas.ToHexBigInteger().HexValue, - paymasterAndData = userOperation.PaymasterAndData.ToHex(true), - signature = userOperation.Signature.ToHex(true) - }; + throw new InvalidOperationException("Account Permissions are not supported in ZkSync"); } - public async Task ForceDeploy() + var result = await ThirdwebContract.Read>(this._accountContract, "getAllActiveSigners").ConfigureAwait(false); + return result ?? new List(); + } + + /// + /// Creates a new session key for a signer to use with the smart account. + /// + /// The address of the signer to create a session key for. + /// The list of approved targets for the signer. Use a list of a single Constants.ADDRESS_ZERO to enable all contracts. + /// The maximum amount of native tokens the signer can send in a single transaction. + /// The timestamp when the permission starts. Can be set to zero. + /// The timestamp when the permission ends. Make use of our Utils to get UNIX timestamps. + /// The timestamp when the request validity starts. Can be set to zero. + /// The timestamp when the request validity ends. Make use of our Utils to get UNIX timestamps. + public async Task CreateSessionKey( + string signerAddress, + List approvedTargets = null, + string nativeTokenLimitPerTransactionInWei = null, + string permissionStartTimestamp = null, + string permissionEndTimestamp = null, + string reqValidityStartTimestamp = null, + string reqValidityEndTimestamp = null + ) + { + if (await Utils.IsZkSync(this.Client, this.ActiveChainId).ConfigureAwait(false)) { - if (Utils.IsZkSync(_chainId)) - { - return; - } + throw new InvalidOperationException("Account Permissions are not supported in ZkSync"); + } - if (await IsDeployed()) - { - return; - } + var request = new SignerPermissionRequest() + { + Signer = signerAddress, + IsAdmin = 0, + ApprovedTargets = approvedTargets ?? new List { Constants.ADDRESS_ZERO }, + NativeTokenLimitPerTransaction = BigInteger.Parse(nativeTokenLimitPerTransactionInWei ?? "0"), + PermissionStartTimestamp = BigInteger.Parse(permissionStartTimestamp ?? "0"), + PermissionEndTimestamp = BigInteger.Parse(permissionEndTimestamp ?? Utils.GetUnixTimeStampIn10Years().ToString()), + ReqValidityStartTimestamp = BigInteger.Parse(reqValidityStartTimestamp ?? "0"), + ReqValidityEndTimestamp = BigInteger.Parse(reqValidityEndTimestamp ?? Utils.GetUnixTimeStampIn10Years().ToString()), + Uid = Guid.NewGuid().ToByteArray(), + }; + + var signature = await EIP712 + .GenerateSignature_SmartAccount("Account", "1", this.ActiveChainId, await this.GetAddress().ConfigureAwait(false), request, this._personalAccount) + .ConfigureAwait(false); + var data = this._accountContract.CreateCallData("setPermissionsForSigner", request, signature.HexToBytes()); + var txInput = new ThirdwebTransactionInput(chainId: this.ActiveChainId, to: this._accountContract.Address, value: 0, data: data); + var txHash = await this.SendTransaction(txInput).ConfigureAwait(false); + return await ThirdwebTransaction.WaitForTransactionReceipt(this.Client, this.ActiveChainId, txHash).ConfigureAwait(false); + } - if (_isDeploying) - { - throw new InvalidOperationException("SmartAccount.ForceDeploy: Account is already deploying."); - } + /// + /// Revokes a session key from a signer. + /// + /// The address of the signer to revoke. + /// The transaction receipt. + public async Task RevokeSessionKey(string signerAddress) + { + return await Utils.IsZkSync(this.Client, this.ActiveChainId).ConfigureAwait(false) + ? throw new InvalidOperationException("Account Permissions are not supported in ZkSync") + : await this.CreateSessionKey(signerAddress, new List(), "0", "0", "0", "0", Utils.GetUnixTimeStampIn10Years().ToString()).ConfigureAwait(false); + } - var input = new ThirdwebTransactionInput() - { - Data = "0x", - To = _accountContract.Address, - Value = new HexBigInteger(0) - }; - var txHash = await SendTransaction(input); - _ = await ThirdwebTransaction.WaitForTransactionReceipt(Client, _chainId, txHash); + /// + /// Adds a new admin to the smart account. + /// + /// The address of the admin to add. + /// The transaction receipt. + public async Task AddAdmin(string admin) + { + if (await Utils.IsZkSync(this.Client, this.ActiveChainId).ConfigureAwait(false)) + { + throw new InvalidOperationException("Account Permissions are not supported in ZkSync"); } - public Task GetPersonalAccount() + var request = new SignerPermissionRequest() { - return Task.FromResult(_personalAccount); - } + Signer = admin, + IsAdmin = 1, + ApprovedTargets = new List(), + NativeTokenLimitPerTransaction = 0, + PermissionStartTimestamp = Utils.GetUnixTimeStampNow() - 3600, + PermissionEndTimestamp = Utils.GetUnixTimeStampIn10Years(), + ReqValidityStartTimestamp = Utils.GetUnixTimeStampNow() - 3600, + ReqValidityEndTimestamp = Utils.GetUnixTimeStampIn10Years(), + Uid = Guid.NewGuid().ToByteArray(), + }; + + var signature = await EIP712.GenerateSignature_SmartAccount("Account", "1", this.ActiveChainId, await this.GetAddress(), request, this._personalAccount).ConfigureAwait(false); + var data = this._accountContract.CreateCallData("setPermissionsForSigner", request, signature.HexToBytes()); + var txInput = new ThirdwebTransactionInput(chainId: this.ActiveChainId, to: this._accountContract.Address, value: 0, data: data); + var txHash = await this.SendTransaction(txInput).ConfigureAwait(false); + return await ThirdwebTransaction.WaitForTransactionReceipt(this.Client, this.ActiveChainId, txHash).ConfigureAwait(false); + } - public async Task GetAddress() + /// + /// Removes an existing admin from the smart account. + /// + /// The address of the admin to remove. + /// The transaction receipt. + public async Task RemoveAdmin(string admin) + { + if (await Utils.IsZkSync(this.Client, this.ActiveChainId).ConfigureAwait(false)) { - return Utils.IsZkSync(_chainId) ? await _personalAccount.GetAddress() : _accountContract.Address.ToChecksumAddress(); + throw new InvalidOperationException("Account Permissions are not supported in ZkSync"); } - public Task EthSign(byte[] rawMessage) + var request = new SignerPermissionRequest() { - return _personalAccount.EthSign(rawMessage); - } + Signer = admin, + IsAdmin = 2, + ApprovedTargets = new List(), + NativeTokenLimitPerTransaction = 0, + PermissionStartTimestamp = Utils.GetUnixTimeStampNow() - 3600, + PermissionEndTimestamp = Utils.GetUnixTimeStampIn10Years(), + ReqValidityStartTimestamp = Utils.GetUnixTimeStampNow() - 3600, + ReqValidityEndTimestamp = Utils.GetUnixTimeStampIn10Years(), + Uid = Guid.NewGuid().ToByteArray(), + }; + + var signature = await EIP712 + .GenerateSignature_SmartAccount("Account", "1", this.ActiveChainId, await this.GetAddress().ConfigureAwait(false), request, this._personalAccount) + .ConfigureAwait(false); + var data = this._accountContract.CreateCallData("setPermissionsForSigner", request, signature.HexToBytes()); + var txInput = new ThirdwebTransactionInput(chainId: this.ActiveChainId, to: this._accountContract.Address, value: 0, data: data); + var txHash = await this.SendTransaction(txInput).ConfigureAwait(false); + return await ThirdwebTransaction.WaitForTransactionReceipt(this.Client, this.ActiveChainId, txHash).ConfigureAwait(false); + } + + /// + /// Estimates the gas cost for a user operation. More accurate than ThirdwebTransaction estimation, but slower. + /// + /// The transaction to estimate. + /// The estimated gas cost. + public async Task EstimateUserOperationGas(ThirdwebTransactionInput transaction) + { + await this.SwitchNetwork(transaction.ChainId.Value).ConfigureAwait(false); - public Task EthSign(string message) + if (await Utils.IsZkSync(this.Client, this.ActiveChainId).ConfigureAwait(false)) { - return _personalAccount.EthSign(message); + throw new Exception("User Operations are not supported in ZkSync"); } - public Task PersonalSign(byte[] rawMessage) + var signedOp = await this.SignUserOp(transaction, null, simulation: true).ConfigureAwait(false); + if (signedOp is UserOperationV6) + { + var castSignedOp = signedOp as UserOperationV6; + var cost = castSignedOp.CallGasLimit + castSignedOp.VerificationGasLimit + castSignedOp.PreVerificationGas; + return cost; + } + else if (signedOp is UserOperationV7) + { + var castSignedOp = signedOp as UserOperationV7; + var cost = + castSignedOp.CallGasLimit + castSignedOp.VerificationGasLimit + castSignedOp.PreVerificationGas + castSignedOp.PaymasterVerificationGasLimit + castSignedOp.PaymasterPostOpGasLimit; + return cost; + } + else { - return _personalAccount.PersonalSign(rawMessage); + throw new Exception("Invalid signed operation type"); } + } - public async Task PersonalSign(string message) + private async Task<(byte[] initCode, string factory, string factoryData)> GetInitCode() + { + if (await this.IsDeployed().ConfigureAwait(false)) { - if (Utils.IsZkSync(_chainId)) - { - return await _personalAccount.PersonalSign(message); - } + return (Array.Empty(), null, null); + } - if (!await IsDeployed()) - { - await ForceDeploy(); - } - if (await IsDeployed()) + var personalAccountAddress = await this._personalAccount.GetAddress().ConfigureAwait(false); + var data = this._factoryContract.CreateCallData("createAccount", personalAccountAddress, Array.Empty()); + return (Utils.HexConcat(this._factoryContract.Address, data).HexToBytes(), this._factoryContract.Address, data); + } + + private async Task SignUserOp(ThirdwebTransactionInput transactionInput, int? requestId = null, bool simulation = false) + { + requestId ??= 1; + + (var initCode, var factory, var factoryData) = await this.GetInitCode().ConfigureAwait(false); + + // Approve tokens if ERC20Paymaster + if (this.UseERC20Paymaster && !this._isApproving && !this._isApproved && !simulation) + { + try { - var originalMsgHash = System.Text.Encoding.UTF8.GetBytes(message).HashPrefixedMessage(); - bool factorySupports712; - try - { - _ = await ThirdwebContract.Read(_accountContract, "getMessageHash", originalMsgHash); - factorySupports712 = true; - } - catch + this._isApproving = true; + var tokenContract = await ThirdwebContract.Create(this.Client, this._erc20PaymasterToken, this.ActiveChainId).ConfigureAwait(false); + var approvedAmount = await tokenContract.ERC20_Allowance(this._accountContract.Address, this._erc20PaymasterAddress).ConfigureAwait(false); + if (approvedAmount == 0) { - factorySupports712 = false; + _ = await tokenContract.ERC20_Approve(this, this._erc20PaymasterAddress, BigInteger.Pow(2, 96) - 1).ConfigureAwait(false); } - - var sig = factorySupports712 - ? await EIP712.GenerateSignature_SmartAccount_AccountMessage("Account", "1", _chainId, await GetAddress(), originalMsgHash, _personalAccount) - : await _personalAccount.PersonalSign(originalMsgHash); - - var isValid = await IsValidSignature(message, sig); - return isValid ? sig : throw new Exception("Invalid signature."); + this._isApproved = true; + await ThirdwebTask.Delay(1000).ConfigureAwait(false); + (initCode, factory, factoryData) = await this.GetInitCode().ConfigureAwait(false); } - else + catch (Exception e) + { + this._isApproved = false; + throw new Exception($"Approving tokens for ERC20Paymaster spending failed: {e.Message}"); + } + finally { - throw new Exception("Smart account could not be deployed, unable to sign message."); + this._isApproving = false; } } - public async Task IsValidSignature(string message, string signature) + // Wait until deployed to avoid double initCode + if (!simulation) { - try + if (this.IsDeploying) { - var magicValue = await ThirdwebContract.Read(_accountContract, "isValidSignature", message.HashPrefixedMessage().HexToByteArray(), signature.HexToByteArray()); - return magicValue.ToHex(true) == new byte[] { 0x16, 0x26, 0xba, 0x7e }.ToHex(true); + initCode = Array.Empty(); + factory = null; + factoryData = null; } - catch + + while (this.IsDeploying) { - return false; + await ThirdwebTask.Delay(100).ConfigureAwait(false); } + + this.IsDeploying = initCode.Length > 0; } - public async Task CreateSessionKey( - string signerAddress, - List approvedTargets, - string nativeTokenLimitPerTransactionInWei, - string permissionStartTimestamp, - string permissionEndTimestamp, - string reqValidityStartTimestamp, - string reqValidityEndTimestamp - ) + // Create the user operation and its safe (hexified) version + + var fees = await ThirdwebBundler.ThirdwebGetUserOperationGasPrice(this.Client, this._bundlerUrl, requestId).ConfigureAwait(false); + var maxFee = fees.MaxFeePerGas.HexToNumber(); + var maxPriorityFee = fees.MaxPriorityFeePerGas.HexToNumber(); + + var entryPointVersion = Utils.GetEntryPointVersion(this._entryPointContract.Address); + +#pragma warning disable IDE0078 // Use pattern matching + // function execute(address _target, uint256 _value, bytes calldata _calldata) + var executeInput = this._accountContract.CreateCallData( + "execute", + transactionInput.To, + transactionInput.ChainId.Value == 295 || transactionInput.ChainId.Value == 296 ? transactionInput.Value.Value / BigInteger.Pow(10, 10) : transactionInput.Value.Value, + transactionInput.Data.HexToBytes() + ); +#pragma warning restore IDE0078 // Use pattern matching + + if (entryPointVersion == 6) { - if (Utils.IsZkSync(_chainId)) + var partialUserOp = new UserOperationV6() + { + Sender = this._accountContract.Address, + Nonce = await this.GetNonce().ConfigureAwait(false), + InitCode = initCode, + CallData = executeInput.HexToBytes(), + CallGasLimit = transactionInput.Gas == null ? 0 : 21000 + transactionInput.Gas.Value, + VerificationGasLimit = 0, + PreVerificationGas = 0, + MaxFeePerGas = maxFee, + MaxPriorityFeePerGas = maxPriorityFee, + PaymasterAndData = Array.Empty(), + Signature = Constants.DUMMY_SIG.HexToBytes(), + }; + + // Update paymaster data and gas + + var pmSponsorResult = await this.GetPaymasterAndData(requestId, EncodeUserOperation(partialUserOp), simulation).ConfigureAwait(false); + partialUserOp.PaymasterAndData = pmSponsorResult.PaymasterAndData.HexToBytes(); + + if (pmSponsorResult.VerificationGasLimit == null || pmSponsorResult.PreVerificationGas == null) + { + var gasEstimates = await ThirdwebBundler.EthEstimateUserOperationGas(this.Client, this._bundlerUrl, requestId, EncodeUserOperation(partialUserOp), this._entryPointContract.Address); + partialUserOp.CallGasLimit = gasEstimates.CallGasLimit.HexToNumber(); + partialUserOp.VerificationGasLimit = gasEstimates.VerificationGasLimit.HexToNumber(); + partialUserOp.PreVerificationGas = gasEstimates.PreVerificationGas.HexToNumber(); + } + else { - throw new InvalidOperationException("Account Permissions are not supported in ZkSync"); + partialUserOp.CallGasLimit = pmSponsorResult.CallGasLimit.HexToNumber(); + partialUserOp.VerificationGasLimit = pmSponsorResult.VerificationGasLimit.HexToNumber(); + partialUserOp.PreVerificationGas = pmSponsorResult.PreVerificationGas.HexToNumber(); } - var request = new SignerPermissionRequest() + // Hash, sign and encode the user operation + + if (!simulation) { - Signer = signerAddress, - IsAdmin = 0, - ApprovedTargets = approvedTargets, - NativeTokenLimitPerTransaction = BigInteger.Parse(nativeTokenLimitPerTransactionInWei), - PermissionStartTimestamp = BigInteger.Parse(permissionStartTimestamp), - PermissionEndTimestamp = BigInteger.Parse(permissionEndTimestamp), - ReqValidityStartTimestamp = BigInteger.Parse(reqValidityStartTimestamp), - ReqValidityEndTimestamp = BigInteger.Parse(reqValidityEndTimestamp), - Uid = Guid.NewGuid().ToByteArray() - }; + partialUserOp.Signature = await this.HashAndSignUserOp(partialUserOp, this._entryPointContract).ConfigureAwait(false); + } - var signature = await EIP712.GenerateSignature_SmartAccount("Account", "1", _chainId, await GetAddress(), request, _personalAccount); - var data = new Contract(null, _accountContract.Abi, _accountContract.Address).GetFunction("setPermissionsForSigner").GetData(request, signature.HexToByteArray()); - var txInput = new ThirdwebTransactionInput() + return partialUserOp; + } + else + { + var partialUserOp = new UserOperationV7() { - From = await GetAddress(), - To = _accountContract.Address, - Value = new HexBigInteger(0), - Data = data + Sender = this._accountContract.Address, + Nonce = await this.GetNonce().ConfigureAwait(false), + Factory = factory, + FactoryData = factoryData.HexToBytes(), + CallData = executeInput.HexToBytes(), + CallGasLimit = 0, + VerificationGasLimit = 0, + PreVerificationGas = 0, + MaxFeePerGas = maxFee, + MaxPriorityFeePerGas = maxPriorityFee, + Paymaster = null, + PaymasterVerificationGasLimit = 0, + PaymasterPostOpGasLimit = 0, + PaymasterData = Array.Empty(), + Signature = Constants.DUMMY_SIG.HexToBytes(), }; - var txHash = await SendTransaction(txInput); - return await ThirdwebTransaction.WaitForTransactionReceipt(Client, _chainId, txHash); - } - public async Task AddAdmin(string admin) - { - if (Utils.IsZkSync(_chainId)) + // Update Paymaster Data / Estimate gas + + var pmSponsorResult = await this.GetPaymasterAndData(requestId, EncodeUserOperation(partialUserOp), simulation).ConfigureAwait(false); + partialUserOp.Paymaster = pmSponsorResult.Paymaster; + partialUserOp.PaymasterData = pmSponsorResult.PaymasterData?.HexToBytes() ?? Array.Empty(); + + Dictionary stateDict = null; + + if (this.UseERC20Paymaster && !this._isApproving) { - throw new InvalidOperationException("Account Permissions are not supported in ZkSync"); + var abiEncoder = new ABIEncode(); + var slotBytes = abiEncoder.GetABIEncoded(new ABIValue("address", this._accountContract.Address), new ABIValue("uint256", this._erc20PaymasterStorageSlot)); + var desiredBalance = BigInteger.Pow(2, 96) - 1; + var storageDict = new Dictionary { { new Sha3Keccack().CalculateHash(slotBytes).BytesToHex(), desiredBalance.NumberToHex().HexToBytes32().BytesToHex() } }; + stateDict = new Dictionary { { this._erc20PaymasterToken, new { stateDiff = storageDict } } }; } - - var request = new SignerPermissionRequest() + else { - Signer = admin, - IsAdmin = 1, - ApprovedTargets = new List(), - NativeTokenLimitPerTransaction = 0, - PermissionStartTimestamp = Utils.GetUnixTimeStampNow() - 3600, - PermissionEndTimestamp = Utils.GetUnixTimeStampIn10Years(), - ReqValidityStartTimestamp = Utils.GetUnixTimeStampNow() - 3600, - ReqValidityEndTimestamp = Utils.GetUnixTimeStampIn10Years(), - Uid = Guid.NewGuid().ToByteArray() - }; + partialUserOp.PreVerificationGas = (pmSponsorResult.PreVerificationGas ?? "0x0").HexToNumber(); + partialUserOp.VerificationGasLimit = (pmSponsorResult.VerificationGasLimit ?? "0x0").HexToNumber(); + partialUserOp.CallGasLimit = (pmSponsorResult.CallGasLimit ?? "0x0").HexToNumber(); + partialUserOp.PaymasterVerificationGasLimit = (pmSponsorResult.PaymasterVerificationGasLimit ?? "0x0").HexToNumber(); + partialUserOp.PaymasterPostOpGasLimit = (pmSponsorResult.PaymasterPostOpGasLimit ?? "0x0").HexToNumber(); + } - var signature = await EIP712.GenerateSignature_SmartAccount("Account", "1", _chainId, await GetAddress(), request, _personalAccount); - var data = new Contract(null, _accountContract.Abi, _accountContract.Address).GetFunction("setPermissionsForSigner").GetData(request, signature.HexToByteArray()); - var txInput = new ThirdwebTransactionInput() + if (partialUserOp.PreVerificationGas == 0 || partialUserOp.VerificationGasLimit == 0) { - From = await GetAddress(), - To = _accountContract.Address, - Value = new HexBigInteger(0), - Data = data - }; - var txHash = await SendTransaction(txInput); - return await ThirdwebTransaction.WaitForTransactionReceipt(Client, _chainId, txHash); + var gasEstimates = await ThirdwebBundler + .EthEstimateUserOperationGas(this.Client, this._bundlerUrl, requestId, EncodeUserOperation(partialUserOp), this._entryPointContract.Address, stateDict) + .ConfigureAwait(false); + partialUserOp.CallGasLimit = gasEstimates.CallGasLimit.HexToNumber(); + partialUserOp.VerificationGasLimit = gasEstimates.VerificationGasLimit.HexToNumber(); + partialUserOp.PreVerificationGas = gasEstimates.PreVerificationGas.HexToNumber(); + partialUserOp.PaymasterVerificationGasLimit = gasEstimates.PaymasterVerificationGasLimit.HexToNumber(); + partialUserOp.PaymasterPostOpGasLimit = this.UseERC20Paymaster && !this._isApproving ? 500_000 : gasEstimates.PaymasterPostOpGasLimit.HexToNumber(); + } + + // Hash, sign and encode the user operation + + partialUserOp.Signature = await this.HashAndSignUserOp(partialUserOp, this._entryPointContract).ConfigureAwait(false); + + return partialUserOp; + } + } + + private async Task SendUserOp(object userOperation, int? requestId = null) + { + requestId ??= 1; + + // Encode op + + object encodedOp; + if (userOperation is UserOperationV6) + { + encodedOp = EncodeUserOperation(userOperation as UserOperationV6); } + else + { + encodedOp = userOperation is UserOperationV7 ? (object)EncodeUserOperation(userOperation as UserOperationV7) : throw new Exception("Invalid signed operation type"); + } + + // Send the user operation - public async Task RemoveAdmin(string admin) + var userOpHash = await ThirdwebBundler.EthSendUserOperation(this.Client, this._bundlerUrl, requestId, encodedOp, this._entryPointContract.Address).ConfigureAwait(false); + + // Wait for the transaction to be mined + + string txHash = null; + using var ct = new CancellationTokenSource(this.Client.FetchTimeoutOptions.GetTimeout(TimeoutType.Other)); + try { - if (Utils.IsZkSync(_chainId)) + while (txHash == null) { - throw new InvalidOperationException("Account Permissions are not supported in ZkSync"); + ct.Token.ThrowIfCancellationRequested(); + + var userOpReceipt = await ThirdwebBundler.EthGetUserOperationReceipt(this.Client, this._bundlerUrl, requestId, userOpHash).ConfigureAwait(false); + + txHash = userOpReceipt?.Receipt?.TransactionHash; + await ThirdwebTask.Delay(100, ct.Token).ConfigureAwait(false); } + } + catch (OperationCanceledException) + { + throw new Exception($"User operation timed out with user op hash: {userOpHash}"); + } + + this.IsDeploying = false; + return txHash; + } + + private async Task GetNonce() + { + var randomBytes = new byte[24]; + RandomNumberGenerator.Fill(randomBytes); + BigInteger randomInt192 = new(randomBytes); + randomInt192 = BigInteger.Abs(randomInt192) % (BigInteger.One << 192); + return await ThirdwebContract.Read(this._entryPointContract, "getNonce", await this.GetAddress().ConfigureAwait(false), randomInt192).ConfigureAwait(false); + } + + private async Task<(string, string)> ZkPaymasterData(ThirdwebTransactionInput transactionInput) + { + if (this._gasless) + { + var result = await ThirdwebBundler.ZkPaymasterData(this.Client, this._paymasterUrl, 1, transactionInput).ConfigureAwait(false); + return (result.Paymaster, result.PaymasterInput); + } + else + { + return (null, null); + } + } + + private async Task ZkBroadcastTransaction(object transactionInput) + { + var result = await ThirdwebBundler.ZkBroadcastTransaction(this.Client, this._bundlerUrl, 1, transactionInput).ConfigureAwait(false); + return result.TransactionHash; + } - var request = new SignerPermissionRequest() + private async Task GetPaymasterAndData(object requestId, object userOp, bool simulation) + { + if (this.UseERC20Paymaster && !this._isApproving && !simulation) + { + return new PMSponsorOperationResponse() { - Signer = admin, - IsAdmin = 2, - ApprovedTargets = new List(), - NativeTokenLimitPerTransaction = 0, - PermissionStartTimestamp = Utils.GetUnixTimeStampNow() - 3600, - PermissionEndTimestamp = Utils.GetUnixTimeStampIn10Years(), - ReqValidityStartTimestamp = Utils.GetUnixTimeStampNow() - 3600, - ReqValidityEndTimestamp = Utils.GetUnixTimeStampIn10Years(), - Uid = Guid.NewGuid().ToByteArray() + PaymasterAndData = Utils.HexConcat(this._erc20PaymasterAddress, this._erc20PaymasterToken), + Paymaster = this._erc20PaymasterAddress, + PaymasterData = "0x", }; + } + else + { + return this._gasless + ? await ThirdwebBundler.PMSponsorUserOperation(this.Client, this._paymasterUrl, requestId, userOp, this._entryPointContract.Address).ConfigureAwait(false) + : new PMSponsorOperationResponse(); + } + } + + private async Task HashAndSignUserOp(UserOperationV6 userOp, ThirdwebContract entryPointContract) + { + var userOpHash = await ThirdwebContract.Read(entryPointContract, "getUserOpHash", userOp); + var sig = + this._personalAccount.AccountType == ThirdwebAccountType.ExternalAccount + ? await this._personalAccount.PersonalSign(userOpHash.BytesToHex()).ConfigureAwait(false) + : await this._personalAccount.PersonalSign(userOpHash).ConfigureAwait(false); + return sig.HexToBytes(); + } - var signature = await EIP712.GenerateSignature_SmartAccount("Account", "1", _chainId, await GetAddress(), request, _personalAccount); - var data = new Contract(null, _accountContract.Abi, _accountContract.Address).GetFunction("setPermissionsForSigner").GetData(request, signature.HexToByteArray()); - var txInput = new ThirdwebTransactionInput() + private async Task HashAndSignUserOp(UserOperationV7 userOp, ThirdwebContract entryPointContract) + { + var factoryBytes = userOp.Factory.HexToBytes(); + var factoryDataBytes = userOp.FactoryData; + var initCodeBuffer = new byte[factoryBytes.Length + factoryDataBytes.Length]; + Buffer.BlockCopy(factoryBytes, 0, initCodeBuffer, 0, factoryBytes.Length); + Buffer.BlockCopy(factoryDataBytes, 0, initCodeBuffer, factoryBytes.Length, factoryDataBytes.Length); + + var verificationGasLimitBytes = userOp.VerificationGasLimit.NumberToHex().HexToBytes().PadBytes(16); + var callGasLimitBytes = userOp.CallGasLimit.NumberToHex().HexToBytes().PadBytes(16); + var accountGasLimitsBuffer = new byte[32]; + Buffer.BlockCopy(verificationGasLimitBytes, 0, accountGasLimitsBuffer, 0, 16); + Buffer.BlockCopy(callGasLimitBytes, 0, accountGasLimitsBuffer, 16, 16); + + var maxPriorityFeePerGasBytes = userOp.MaxPriorityFeePerGas.NumberToHex().HexToBytes().PadBytes(16); + var maxFeePerGasBytes = userOp.MaxFeePerGas.NumberToHex().HexToBytes().PadBytes(16); + var gasFeesBuffer = new byte[32]; + Buffer.BlockCopy(maxPriorityFeePerGasBytes, 0, gasFeesBuffer, 0, 16); + Buffer.BlockCopy(maxFeePerGasBytes, 0, gasFeesBuffer, 16, 16); + + PackedUserOperation packedOp; + if (userOp.Paymaster is null or Constants.ADDRESS_ZERO or "0x") + { + packedOp = new PackedUserOperation() { - From = await GetAddress(), - To = _accountContract.Address, - Value = new HexBigInteger(0), - Data = data + Sender = userOp.Sender, + Nonce = userOp.Nonce, + InitCode = initCodeBuffer, + CallData = userOp.CallData, + AccountGasLimits = accountGasLimitsBuffer, + PreVerificationGas = userOp.PreVerificationGas, + GasFees = gasFeesBuffer, + PaymasterAndData = Array.Empty(), + Signature = userOp.Signature, }; - var txHash = await SendTransaction(txInput); - return await ThirdwebTransaction.WaitForTransactionReceipt(Client, _chainId, txHash); } - - public Task SignTypedDataV4(string json) + else { - return _personalAccount.SignTypedDataV4(json); + var paymasterBytes = userOp.Paymaster.HexToBytes(); + var paymasterVerificationGasLimitBytes = userOp.PaymasterVerificationGasLimit.NumberToHex().HexToBytes().PadBytes(16); + var paymasterPostOpGasLimitBytes = userOp.PaymasterPostOpGasLimit.NumberToHex().HexToBytes().PadBytes(16); + var paymasterDataBytes = userOp.PaymasterData; + var paymasterAndDataBuffer = new byte[20 + 16 + 16 + paymasterDataBytes.Length]; + Buffer.BlockCopy(paymasterBytes, 0, paymasterAndDataBuffer, 0, 20); + Buffer.BlockCopy(paymasterVerificationGasLimitBytes, 0, paymasterAndDataBuffer, 20, 16); + Buffer.BlockCopy(paymasterPostOpGasLimitBytes, 0, paymasterAndDataBuffer, 20 + 16, 16); + Buffer.BlockCopy(paymasterDataBytes, 0, paymasterAndDataBuffer, 20 + 16 + 16, paymasterDataBytes.Length); + + packedOp = new PackedUserOperation() + { + Sender = userOp.Sender, + Nonce = userOp.Nonce, + InitCode = initCodeBuffer, + CallData = userOp.CallData, + AccountGasLimits = accountGasLimitsBuffer, + PreVerificationGas = userOp.PreVerificationGas, + GasFees = gasFeesBuffer, + PaymasterAndData = paymasterAndDataBuffer, + Signature = userOp.Signature, + }; } - public Task SignTypedDataV4(T data, TypedData typedData) - where TDomain : IDomain + var userOpHash = await ThirdwebContract.Read(entryPointContract, "getUserOpHash", packedOp).ConfigureAwait(false); + + var sig = + this._personalAccount.AccountType == ThirdwebAccountType.ExternalAccount + ? await this._personalAccount.PersonalSign(userOpHash.BytesToHex()).ConfigureAwait(false) + : await this._personalAccount.PersonalSign(userOpHash).ConfigureAwait(false); + + return sig.HexToBytes(); + } + + private static UserOperationHexifiedV6 EncodeUserOperation(UserOperationV6 userOperation) + { + return new UserOperationHexifiedV6() + { + Sender = userOperation.Sender, + Nonce = userOperation.Nonce.NumberToHex(), + InitCode = userOperation.InitCode.BytesToHex(), + CallData = userOperation.CallData.BytesToHex(), + CallGasLimit = userOperation.CallGasLimit.NumberToHex(), + VerificationGasLimit = userOperation.VerificationGasLimit.NumberToHex(), + PreVerificationGas = userOperation.PreVerificationGas.NumberToHex(), + MaxFeePerGas = userOperation.MaxFeePerGas.NumberToHex(), + MaxPriorityFeePerGas = userOperation.MaxPriorityFeePerGas.NumberToHex(), + PaymasterAndData = userOperation.PaymasterAndData.BytesToHex(), + Signature = userOperation.Signature.BytesToHex(), + }; + } + + private static UserOperationHexifiedV7 EncodeUserOperation(UserOperationV7 userOperation) + { + return new UserOperationHexifiedV7() + { + Sender = userOperation.Sender, + Nonce = Utils.HexConcat(Constants.ADDRESS_ZERO, userOperation.Nonce.NumberToHex()), + Factory = userOperation.Factory, + FactoryData = userOperation.FactoryData.BytesToHex(), + CallData = userOperation.CallData.BytesToHex(), + CallGasLimit = userOperation.CallGasLimit.NumberToHex(), + VerificationGasLimit = userOperation.VerificationGasLimit.NumberToHex(), + PreVerificationGas = userOperation.PreVerificationGas.NumberToHex(), + MaxFeePerGas = userOperation.MaxFeePerGas.NumberToHex(), + MaxPriorityFeePerGas = userOperation.MaxPriorityFeePerGas.NumberToHex(), + Paymaster = userOperation.Paymaster, + PaymasterVerificationGasLimit = userOperation.PaymasterVerificationGasLimit.NumberToHex(), + PaymasterPostOpGasLimit = userOperation.PaymasterPostOpGasLimit.NumberToHex(), + PaymasterData = userOperation.PaymasterData.BytesToHex(), + Signature = userOperation.Signature.BytesToHex(), + }; + } + + #endregion + + #region IThirdwebWallet + + public async Task SendTransaction(ThirdwebTransactionInput transactionInput) + { + if (transactionInput == null) { - return _personalAccount.SignTypedDataV4(data, typedData); + throw new InvalidOperationException("SmartAccount.SendTransaction: Transaction input is required."); } - public async Task EstimateUserOperationGas(ThirdwebTransactionInput transaction, BigInteger chainId) + await this.SwitchNetwork(transactionInput.ChainId.Value).ConfigureAwait(false); + + var transaction = await ThirdwebTransaction + .Create(await Utils.IsZkSync(this.Client, this.ActiveChainId).ConfigureAwait(false) ? this._personalAccount : this, transactionInput) + .ConfigureAwait(false); + transaction = await ThirdwebTransaction.Prepare(transaction).ConfigureAwait(false); + transactionInput = transaction.Input; + + if (await Utils.IsZkSync(this.Client, this.ActiveChainId).ConfigureAwait(false)) { - if (Utils.IsZkSync(_chainId)) + if (this._gasless) { - throw new Exception("User Operations are not supported in ZkSync"); + (var paymaster, var paymasterInput) = await this.ZkPaymasterData(transactionInput).ConfigureAwait(false); + transaction = transaction.SetZkSyncOptions(new ZkSyncOptions(paymaster: paymaster, paymasterInput: paymasterInput)); + var zkTx = await ThirdwebTransaction.ConvertToZkSyncTransaction(transaction).ConfigureAwait(false); + var zkTxSigned = await EIP712.GenerateSignature_ZkSyncTransaction("zkSync", "2", transaction.Input.ChainId.Value, zkTx, this).ConfigureAwait(false); + // Match bundler ZkTransactionInput type without recreating + var hash = await this.ZkBroadcastTransaction( + new + { + nonce = zkTx.Nonce.ToString(), + from = zkTx.From, + to = zkTx.To, + gas = zkTx.GasLimit.ToString(), + gasPrice = string.Empty, + value = zkTx.Value.ToString(), + data = Utils.BytesToHex(zkTx.Data), + maxFeePerGas = zkTx.MaxFeePerGas.ToString(), + maxPriorityFeePerGas = zkTx.MaxPriorityFeePerGas.ToString(), + chainId = this.ActiveChainId.ToString(), + signedTransaction = zkTxSigned, + paymaster, + } + ) + .ConfigureAwait(false); + return hash; + } + else + { + return await ThirdwebTransaction.Send(transaction).ConfigureAwait(false); } + } + else + { + var signedOp = await this.SignUserOp(transactionInput).ConfigureAwait(false); + return await this.SendUserOp(signedOp).ConfigureAwait(false); + } + } - var signedOp = await SignUserOp(transaction, null, simulation: true); - var cost = signedOp.CallGasLimit + signedOp.VerificationGasLimit + signedOp.PreVerificationGas; - return cost; + public async Task ExecuteTransaction(ThirdwebTransactionInput transactionInput) + { + var txHash = await this.SendTransaction(transactionInput).ConfigureAwait(false); + return await ThirdwebTransaction.WaitForTransactionReceipt(this.Client, this.ActiveChainId, txHash).ConfigureAwait(false); + } + + public async Task GetAddress() + { + return await Utils.IsZkSync(this.Client, this.ActiveChainId).ConfigureAwait(false) + ? await this._personalAccount.GetAddress().ConfigureAwait(false) + : this._accountContract.Address.ToChecksumAddress(); + } + + public Task PersonalSign(byte[] rawMessage) + { + throw new NotImplementedException(); + } + + /// + /// Signs a message with the personal account. The message will be verified using EIPs 1271 and 6492 if applicable. + /// + /// The message to sign. + /// The signature. + public async Task PersonalSign(string message) + { + if (await Utils.IsZkSync(this.Client, this.ActiveChainId).ConfigureAwait(false)) + { + return await this._personalAccount.PersonalSign(message).ConfigureAwait(false); } - public async Task SignTransaction(ThirdwebTransactionInput transaction) + var originalMsgHash = Encoding.UTF8.GetBytes(message).HashPrefixedMessage(); + + var sig = await EIP712 + .GenerateSignature_SmartAccount_AccountMessage("Account", "1", this.ActiveChainId, await this.GetAddress().ConfigureAwait(false), originalMsgHash, this._personalAccount) + .ConfigureAwait(false); + + if (!await this.IsDeployed().ConfigureAwait(false)) { - if (Utils.IsZkSync(_chainId)) - { - throw new Exception("Offline Signing is not supported in ZkSync"); - } + (_, var factory, var factoryData) = await this.GetInitCode(); + sig = Utils.SerializeErc6492Signature(address: factory, data: factoryData.HexToBytes(), signature: sig.HexToBytes()); + } + + var isValid = await this.IsValidSignature(message, sig); + return isValid ? sig : throw new Exception("Invalid signature."); + } + + public Task SignTypedDataV4(string json) + { + // TODO: Implement wrapped version + return this._personalAccount.SignTypedDataV4(json); + } + + public Task SignTypedDataV4(T data, TypedData typedData) + where TDomain : IDomain + { + // TODO: Implement wrapped version + return this._personalAccount.SignTypedDataV4(data, typedData); + } - return JsonConvert.SerializeObject(EncodeUserOperation(await SignUserOp(transaction))); + public async Task SignTransaction(ThirdwebTransactionInput transaction) + { + await this.SwitchNetwork(transaction.ChainId.Value).ConfigureAwait(false); + + if (await Utils.IsZkSync(this.Client, this.ActiveChainId).ConfigureAwait(false)) + { + throw new Exception("Offline Signing is not supported in ZkSync"); + } + + var signedOp = await this.SignUserOp(transaction).ConfigureAwait(false); + if (signedOp is UserOperationV6) + { + var encodedOp = EncodeUserOperation(signedOp as UserOperationV6); + return JsonConvert.SerializeObject(encodedOp); + } + else if (signedOp is UserOperationV7) + { + var encodedOp = EncodeUserOperation(signedOp as UserOperationV7); + return JsonConvert.SerializeObject(encodedOp); + } + else + { + throw new Exception("Invalid signed operation type"); + } + } + + public async Task IsConnected() + { + return await Utils.IsZkSync(this.Client, this.ActiveChainId).ConfigureAwait(false) ? await this._personalAccount.IsConnected().ConfigureAwait(false) : this._accountContract != null; + } + + public Task Disconnect() + { + this._accountContract = null; + return Task.CompletedTask; + } + + public async Task> UnlinkAccount(LinkedAccount accountToUnlink) + { + var personalWallet = await this.GetPersonalWallet().ConfigureAwait(false); + if (personalWallet is not InAppWallet and not EcosystemWallet) + { + throw new Exception("SmartWallet.UnlinkAccount is only supported if the signer is an InAppWallet or EcosystemWallet"); } + return await personalWallet.UnlinkAccount(accountToUnlink).ConfigureAwait(false); + } - public async Task IsConnected() + public async Task> LinkAccount( + IThirdwebWallet walletToLink, + string otp = null, + bool? isMobile = null, + Action browserOpenAction = null, + string mobileRedirectScheme = "thirdweb://", + IThirdwebBrowser browser = null, + BigInteger? chainId = null, + string jwt = null, + string payload = null, + string defaultSessionIdOverride = null + ) + { + var personalWallet = await this.GetPersonalWallet().ConfigureAwait(false); + if (personalWallet is not InAppWallet and not EcosystemWallet) + { + throw new Exception("SmartWallet.LinkAccount is only supported if the signer is an InAppWallet or EcosystemWallet"); + } + else if (walletToLink is not InAppWallet and not EcosystemWallet) { - return Utils.IsZkSync(_chainId) ? await _personalAccount.IsConnected() : _accountContract != null; + throw new Exception("SmartWallet.LinkAccount is only supported if the wallet to link is an InAppWallet or EcosystemWallet"); } + else if (personalWallet is InAppWallet && walletToLink is not InAppWallet) + { + throw new Exception("SmartWallet.LinkAccount with an InAppWallet signer is only supported if the wallet to link is also an InAppWallet"); + } + else if (personalWallet is EcosystemWallet && walletToLink is not EcosystemWallet) + { + throw new Exception("SmartWallet.LinkAccount with an EcosystemWallet signer is only supported if the wallet to link is also an EcosystemWallet"); + } + else + { + return await personalWallet + .LinkAccount(walletToLink, otp, isMobile, browserOpenAction, mobileRedirectScheme, browser, chainId, jwt, payload, defaultSessionIdOverride) + .ConfigureAwait(false); + } + } - public Task Disconnect() + public async Task> GetLinkedAccounts() + { + var personalWallet = await this.GetPersonalWallet().ConfigureAwait(false); + if (personalWallet is not InAppWallet and not EcosystemWallet) + { + throw new Exception("SmartWallet.LinkAccount is only supported if the signer is an InAppWallet or EcosystemWallet"); + } + else { - _accountContract = null; - return Task.CompletedTask; + return await personalWallet.GetLinkedAccounts().ConfigureAwait(false); } + } + + public Task SignAuthorization(BigInteger chainId, string contractAddress, bool willSelfExecute) + { + return this._personalAccount.SignAuthorization(chainId, contractAddress, willSelfExecute); + } - public async Task Authenticate( - string domain, - BigInteger chainId, - string authPayloadPath = "/auth/payload", - string authLoginPath = "/auth/login", - IThirdwebHttpClient httpClientOverride = null - ) + public async Task SwitchNetwork(BigInteger chainId) + { + if (this.ActiveChainId == chainId) { - var payloadURL = domain + authPayloadPath; - var loginURL = domain + authLoginPath; + return; + } - var payloadBodyRaw = new { address = await GetAddress(), chainId = chainId.ToString() }; - var payloadBody = JsonConvert.SerializeObject(payloadBodyRaw); + if (this.UseERC20Paymaster) + { + throw new InvalidOperationException("You cannot switch networks when using an ERC20 paymaster yet."); + } - var httpClient = httpClientOverride ?? Client.HttpClient; + this._bundlerUrl = this._bundlerUrl.Contains(".thirdweb.com") ? $"https://{chainId}.bundler.thirdweb.com/v2" : this._bundlerUrl; + this._paymasterUrl = this._paymasterUrl.Contains(".thirdweb.com") ? $"https://{chainId}.bundler.thirdweb.com/v2" : this._paymasterUrl; - var payloadContent = new StringContent(payloadBody, Encoding.UTF8, "application/json"); - var payloadResponse = await httpClient.PostAsync(payloadURL, payloadContent); - _ = payloadResponse.EnsureSuccessStatusCode(); - var payloadString = await payloadResponse.Content.ReadAsStringAsync(); + if (!await Utils.IsZkSync(this.Client, chainId).ConfigureAwait(false)) + { + this._entryPointContract = await ThirdwebContract.Create(this.Client, this._entryPointContract.Address, chainId, this._entryPointContract.Abi).ConfigureAwait(false); + this._factoryContract = await ThirdwebContract.Create(this.Client, this._factoryContract.Address, chainId, this._factoryContract.Abi).ConfigureAwait(false); - var loginBodyRaw = JsonConvert.DeserializeObject(payloadString); - var payloadToSign = Utils.GenerateSIWE(loginBodyRaw.payload); + var personalAddress = await this._personalAccount.GetAddress().ConfigureAwait(false); + var accountAddress = await ThirdwebContract.Read(this._factoryContract, "getAddress", personalAddress, Array.Empty()).ConfigureAwait(false); + this._accountContract = await ThirdwebContract.Create(this._personalAccount.Client, accountAddress, chainId, Constants.ACCOUNT_V06_ABI).ConfigureAwait(false); + } - loginBodyRaw.signature = await PersonalSign(payloadToSign); - var loginBody = JsonConvert.SerializeObject(new { payload = loginBodyRaw }); + this.ActiveChainId = chainId; - var loginContent = new StringContent(loginBody, Encoding.UTF8, "application/json"); - var loginResponse = await httpClient.PostAsync(loginURL, loginContent); - _ = loginResponse.EnsureSuccessStatusCode(); - var responseString = await loginResponse.Content.ReadAsStringAsync(); - return responseString; + try + { + await this._personalAccount.SwitchNetwork(chainId).ConfigureAwait(false); + } + catch + { + // Wallet likely still viable in Account Abstraction context } } + + #endregion } diff --git a/Thirdweb/Thirdweb.Wallets/SmartWallet/Thirdweb.AccountAbstraction/AATypes.cs b/Thirdweb/Thirdweb.Wallets/SmartWallet/Thirdweb.AccountAbstraction/AATypes.cs deleted file mode 100644 index 0b46d9ac..00000000 --- a/Thirdweb/Thirdweb.Wallets/SmartWallet/Thirdweb.AccountAbstraction/AATypes.cs +++ /dev/null @@ -1,231 +0,0 @@ -using System.Numerics; -using Nethereum.ABI.FunctionEncoding.Attributes; -using Nethereum.Contracts; - -namespace Thirdweb.AccountAbstraction -{ - public class UserOperation - { - [Parameter("address", "sender", 1)] - public virtual string Sender { get; set; } - - [Parameter("uint256", "nonce", 2)] - public virtual BigInteger Nonce { get; set; } - - [Parameter("bytes", "initCode", 3)] - public virtual byte[] InitCode { get; set; } - - [Parameter("bytes", "callData", 4)] - public virtual byte[] CallData { get; set; } - - [Parameter("uint256", "callGasLimit", 5)] - public virtual BigInteger CallGasLimit { get; set; } - - [Parameter("uint256", "verificationGasLimit", 6)] - public virtual BigInteger VerificationGasLimit { get; set; } - - [Parameter("uint256", "preVerificationGas", 7)] - public virtual BigInteger PreVerificationGas { get; set; } - - [Parameter("uint256", "maxFeePerGas", 8)] - public virtual BigInteger MaxFeePerGas { get; set; } - - [Parameter("uint256", "maxPriorityFeePerGas", 9)] - public virtual BigInteger MaxPriorityFeePerGas { get; set; } - - [Parameter("bytes", "paymasterAndData", 10)] - public virtual byte[] PaymasterAndData { get; set; } - - [Parameter("bytes", "signature", 11)] - public virtual byte[] Signature { get; set; } - } - - public class UserOperationHexified - { - public string sender { get; set; } - public string nonce { get; set; } - public string initCode { get; set; } - public string callData { get; set; } - public string callGasLimit { get; set; } - public string verificationGasLimit { get; set; } - public string preVerificationGas { get; set; } - public string maxFeePerGas { get; set; } - public string maxPriorityFeePerGas { get; set; } - public string paymasterAndData { get; set; } - public string signature { get; set; } - } - - [Function("execute")] - public class ExecuteFunction : FunctionMessage - { - [Parameter("address", "_target", 1)] - public virtual string Target { get; set; } - - [Parameter("uint256", "_value", 2)] - public virtual BigInteger Value { get; set; } - - [Parameter("bytes", "_calldata", 3)] - public virtual byte[] Calldata { get; set; } - } - - public class EthEstimateUserOperationGasResponse - { - public string PreVerificationGas { get; set; } - public string VerificationGas { get; set; } - public string CallGasLimit { get; set; } - } - - public class EthGetUserOperationReceiptResponse - { - public ThirdwebTransactionReceipt receipt { get; set; } - } - - public class EntryPointWrapper - { - public string entryPoint { get; set; } - } - - public class PMSponsorOperationResponse - { - public string paymasterAndData { get; set; } - } - - public class ThirdwebGetUserOperationGasPriceResponse - { - public string maxFeePerGas { get; set; } - public string maxPriorityFeePerGas { get; set; } - } - - [Event("UserOperationEvent")] - public class UserOperationEventEventDTO : IEventDTO - { - [Parameter("bytes32", "userOpHash", 1, true)] - public virtual byte[] UserOpHash { get; set; } - - [Parameter("address", "sender", 2, true)] - public virtual string Sender { get; set; } - - [Parameter("address", "paymaster", 3, true)] - public virtual string Paymaster { get; set; } - - [Parameter("uint256", "nonce", 4, false)] - public virtual BigInteger Nonce { get; set; } - - [Parameter("bool", "success", 5, false)] - public virtual bool Success { get; set; } - - [Parameter("uint256", "actualGasCost", 6, false)] - public virtual BigInteger ActualGasCost { get; set; } - - [Parameter("uint256", "actualGasUsed", 7, false)] - public virtual BigInteger ActualGasUsed { get; set; } - } - - [Event("UserOperationRevertReason")] - public class UserOperationRevertReasonEventDTO : IEventDTO - { - [Parameter("bytes32", "userOpHash", 1, true)] - public virtual byte[] UserOpHash { get; set; } - - [Parameter("address", "sender", 2, true)] - public virtual string Sender { get; set; } - - [Parameter("uint256", "nonce", 3, false)] - public virtual BigInteger Nonce { get; set; } - - [Parameter("bytes", "revertReason", 4, false)] - public virtual byte[] RevertReason { get; set; } - } - - [Struct("SignerPermissionRequest")] - public class SignerPermissionRequest - { - [Parameter("address", "signer", 1)] - public virtual string Signer { get; set; } - - [Parameter("uint8", "isAdmin", 2)] - public virtual byte IsAdmin { get; set; } - - [Parameter("address[]", "approvedTargets", 3)] - public virtual List ApprovedTargets { get; set; } - - [Parameter("uint256", "nativeTokenLimitPerTransaction", 4)] - public virtual BigInteger NativeTokenLimitPerTransaction { get; set; } - - [Parameter("uint128", "permissionStartTimestamp", 5)] - public virtual BigInteger PermissionStartTimestamp { get; set; } - - [Parameter("uint128", "permissionEndTimestamp", 6)] - public virtual BigInteger PermissionEndTimestamp { get; set; } - - [Parameter("uint128", "reqValidityStartTimestamp", 7)] - public virtual BigInteger ReqValidityStartTimestamp { get; set; } - - [Parameter("uint128", "reqValidityEndTimestamp", 8)] - public virtual BigInteger ReqValidityEndTimestamp { get; set; } - - [Parameter("bytes32", "uid", 9)] - public virtual byte[] Uid { get; set; } - } - - [Struct("AccountMessage")] - public class AccountMessage - { - [Parameter("bytes", "message", 1)] - public virtual byte[] Message { get; set; } - } - - [Struct("Transaction")] - public class ZkSyncAATransaction - { - [Parameter("uint256", "txType", 1)] - public virtual BigInteger TxType { get; set; } - - [Parameter("uint256", "from", 2)] - public virtual BigInteger From { get; set; } - - [Parameter("uint256", "to", 3)] - public virtual BigInteger To { get; set; } - - [Parameter("uint256", "gasLimit", 4)] - public virtual BigInteger GasLimit { get; set; } - - [Parameter("uint256", "gasPerPubdataByteLimit", 5)] - public virtual BigInteger GasPerPubdataByteLimit { get; set; } - - [Parameter("uint256", "maxFeePerGas", 6)] - public virtual BigInteger MaxFeePerGas { get; set; } - - [Parameter("uint256", "maxPriorityFeePerGas", 7)] - public virtual BigInteger MaxPriorityFeePerGas { get; set; } - - [Parameter("uint256", "paymaster", 8)] - public virtual BigInteger Paymaster { get; set; } - - [Parameter("uint256", "nonce", 9)] - public virtual BigInteger Nonce { get; set; } - - [Parameter("uint256", "value", 10)] - public virtual BigInteger Value { get; set; } - - [Parameter("bytes", "data", 11)] - public virtual byte[] Data { get; set; } - - [Parameter("bytes32[]", "factoryDeps", 12)] - public virtual List FactoryDeps { get; set; } - - [Parameter("bytes", "paymasterInput", 13)] - public virtual byte[] PaymasterInput { get; set; } - } - - public class ZkPaymasterDataResponse - { - public string paymaster { get; set; } - public string paymasterInput { get; set; } - } - - public class ZkBroadcastTransactionResponse - { - public string transactionHash { get; set; } - } -} diff --git a/Thirdweb/Thirdweb.Wallets/SmartWallet/Thirdweb.AccountAbstraction/BundlerClient.cs b/Thirdweb/Thirdweb.Wallets/SmartWallet/Thirdweb.AccountAbstraction/BundlerClient.cs deleted file mode 100644 index 5c307be9..00000000 --- a/Thirdweb/Thirdweb.Wallets/SmartWallet/Thirdweb.AccountAbstraction/BundlerClient.cs +++ /dev/null @@ -1,107 +0,0 @@ -using Nethereum.JsonRpc.Client.RpcMessages; -using Newtonsoft.Json; - -namespace Thirdweb.AccountAbstraction -{ - public static class BundlerClient - { - // Bundler requests - - public static async Task EthGetUserOperationReceipt(ThirdwebClient client, string bundlerUrl, object requestId, string userOpHash) - { - var response = await BundlerRequest(client, bundlerUrl, requestId, "eth_getUserOperationReceipt", userOpHash); - return JsonConvert.DeserializeObject(response.Result.ToString()); - } - - public static async Task EthSendUserOperation(ThirdwebClient client, string bundlerUrl, object requestId, UserOperationHexified userOp, string entryPoint) - { - var response = await BundlerRequest(client, bundlerUrl, requestId, "eth_sendUserOperation", userOp, entryPoint); - return response.Result.ToString(); - } - - public static async Task EthEstimateUserOperationGas( - ThirdwebClient client, - string bundlerUrl, - object requestId, - UserOperationHexified userOp, - string entryPoint - ) - { - var response = await BundlerRequest(client, bundlerUrl, requestId, "eth_estimateUserOperationGas", userOp, entryPoint); - return JsonConvert.DeserializeObject(response.Result.ToString()); - } - - public static async Task ThirdwebGetUserOperationGasPrice(ThirdwebClient client, string bundlerUrl, object requestId) - { - var response = await BundlerRequest(client, bundlerUrl, requestId, "thirdweb_getUserOperationGasPrice"); - return JsonConvert.DeserializeObject(response.Result.ToString()); - } - - // Paymaster requests - - public static async Task PMSponsorUserOperation(ThirdwebClient client, string paymasterUrl, object requestId, UserOperationHexified userOp, string entryPoint) - { - var response = await BundlerRequest(client, paymasterUrl, requestId, "pm_sponsorUserOperation", userOp, new EntryPointWrapper() { entryPoint = entryPoint }); - try - { - return JsonConvert.DeserializeObject(response.Result.ToString()); - } - catch - { - return new PMSponsorOperationResponse() { paymasterAndData = response.Result.ToString() }; - } - } - - public static async Task ZkPaymasterData(ThirdwebClient client, string paymasterUrl, object requestId, ThirdwebTransactionInput txInput) - { - var response = await BundlerRequest(client, paymasterUrl, requestId, "zk_paymasterData", txInput); - try - { - return JsonConvert.DeserializeObject(response.Result.ToString()); - } - catch - { - return new ZkPaymasterDataResponse() { paymaster = null, paymasterInput = null }; - } - } - - public static async Task ZkBroadcastTransaction(ThirdwebClient client, string paymasterUrl, object requestId, object txInput) - { - var response = await BundlerRequest(client, paymasterUrl, requestId, "zk_broadcastTransaction", txInput); - return JsonConvert.DeserializeObject(response.Result.ToString()); - } - - // Request - - private static async Task BundlerRequest(ThirdwebClient client, string url, object requestId, string method, params object[] args) - { - var cts = new CancellationTokenSource(client.FetchTimeoutOptions.GetTimeout(TimeoutType.Other)); - - var httpClient = client.HttpClient; - var requestMessage = new RpcRequestMessage(requestId, method, args); - var requestMessageJson = JsonConvert.SerializeObject(requestMessage); - - var httpContent = new StringContent(requestMessageJson, System.Text.Encoding.UTF8, "application/json"); - - ThirdwebHttpResponseMessage httpResponse; - try - { - httpResponse = await httpClient.PostAsync(url, httpContent, cts.Token); - } - catch (TaskCanceledException) - { - throw new TimeoutException("The request timed out."); - } - - if (!httpResponse.IsSuccessStatusCode) - { - throw new Exception($"Bundler Request Failed. Error: {httpResponse.StatusCode} - {await httpResponse.Content.ReadAsStringAsync()}"); - } - - var httpResponseJson = await httpResponse.Content.ReadAsStringAsync(); - - var response = JsonConvert.DeserializeObject(httpResponseJson); - return response.Error != null ? throw new Exception($"Bundler Request Failed. Error: {response.Error.Code} - {response.Error.Message} - {response.Error.Data}") : response; - } - } -} diff --git a/Thirdweb/Thirdweb.Wallets/SmartWallet/Thirdweb.AccountAbstraction/ThirdwebBundler.Types.cs b/Thirdweb/Thirdweb.Wallets/SmartWallet/Thirdweb.AccountAbstraction/ThirdwebBundler.Types.cs new file mode 100644 index 00000000..8db23e3a --- /dev/null +++ b/Thirdweb/Thirdweb.Wallets/SmartWallet/Thirdweb.AccountAbstraction/ThirdwebBundler.Types.cs @@ -0,0 +1,678 @@ +using System.Numerics; +using Nethereum.ABI.FunctionEncoding.Attributes; +using Newtonsoft.Json; + +namespace Thirdweb.AccountAbstraction; + +public class UserOperationV6 +{ + [Parameter("address", "sender", 1)] + public virtual string Sender { get; set; } + + [Parameter("uint256", "nonce", 2)] + public virtual BigInteger Nonce { get; set; } + + [Parameter("bytes", "initCode", 3)] + public virtual byte[] InitCode { get; set; } + + [Parameter("bytes", "callData", 4)] + public virtual byte[] CallData { get; set; } + + [Parameter("uint256", "callGasLimit", 5)] + public virtual BigInteger CallGasLimit { get; set; } + + [Parameter("uint256", "verificationGasLimit", 6)] + public virtual BigInteger VerificationGasLimit { get; set; } + + [Parameter("uint256", "preVerificationGas", 7)] + public virtual BigInteger PreVerificationGas { get; set; } + + [Parameter("uint256", "maxFeePerGas", 8)] + public virtual BigInteger MaxFeePerGas { get; set; } + + [Parameter("uint256", "maxPriorityFeePerGas", 9)] + public virtual BigInteger MaxPriorityFeePerGas { get; set; } + + [Parameter("bytes", "paymasterAndData", 10)] + public virtual byte[] PaymasterAndData { get; set; } + + [Parameter("bytes", "signature", 11)] + public virtual byte[] Signature { get; set; } +} + +public class UserOperationV7 +{ + [Parameter("address", "sender", 1)] + public virtual string Sender { get; set; } + + [Parameter("uint256", "nonce", 2)] + public virtual BigInteger Nonce { get; set; } + + [Parameter("address", "factory", 3)] + public virtual string Factory { get; set; } + + [Parameter("bytes", "factoryData", 4)] + public virtual byte[] FactoryData { get; set; } + + [Parameter("bytes", "callData", 5)] + public virtual byte[] CallData { get; set; } + + [Parameter("uint256", "callGasLimit", 6)] + public virtual BigInteger CallGasLimit { get; set; } + + [Parameter("uint256", "verificationGasLimit", 7)] + public virtual BigInteger VerificationGasLimit { get; set; } + + [Parameter("uint256", "preVerificationGas", 8)] + public virtual BigInteger PreVerificationGas { get; set; } + + [Parameter("uint256", "maxFeePerGas", 9)] + public virtual BigInteger MaxFeePerGas { get; set; } + + [Parameter("uint256", "maxPriorityFeePerGas", 10)] + public virtual BigInteger MaxPriorityFeePerGas { get; set; } + + [Parameter("address", "paymaster", 11)] + public virtual string Paymaster { get; set; } + + [Parameter("uint256", "paymasterVerificationGasLimit", 12)] + public virtual BigInteger PaymasterVerificationGasLimit { get; set; } + + [Parameter("uint256", "paymasterPostOpGasLimit", 13)] + public virtual BigInteger PaymasterPostOpGasLimit { get; set; } + + [Parameter("bytes", "paymasterData", 14)] + public virtual byte[] PaymasterData { get; set; } + + [Parameter("bytes", "signature", 15)] + public virtual byte[] Signature { get; set; } +} + +public class PackedUserOperation +{ + [Parameter("address", "sender", 1)] + public virtual string Sender { get; set; } + + [Parameter("uint256", "nonce", 2)] + public virtual BigInteger Nonce { get; set; } + + [Parameter("bytes", "initCode", 3)] + public virtual byte[] InitCode { get; set; } + + [Parameter("bytes", "callData", 4)] + public virtual byte[] CallData { get; set; } + + [Parameter("bytes32", "accountGasLimits", 5)] + public virtual byte[] AccountGasLimits { get; set; } + + [Parameter("uint256", "preVerificationGas", 6)] + public virtual BigInteger PreVerificationGas { get; set; } + + [Parameter("bytes32", "gasFees", 7)] + public virtual byte[] GasFees { get; set; } + + [Parameter("bytes", "paymasterAndData", 8)] + public virtual byte[] PaymasterAndData { get; set; } + + [Parameter("bytes", "signature", 9)] + public virtual byte[] Signature { get; set; } +} + +public class UserOperationHexifiedV6 +{ + [JsonProperty("sender")] + public string Sender { get; set; } + + [JsonProperty("nonce")] + public string Nonce { get; set; } + + [JsonProperty("initCode")] + public string InitCode { get; set; } + + [JsonProperty("callData")] + public string CallData { get; set; } + + [JsonProperty("callGasLimit")] + public string CallGasLimit { get; set; } + + [JsonProperty("verificationGasLimit")] + public string VerificationGasLimit { get; set; } + + [JsonProperty("preVerificationGas")] + public string PreVerificationGas { get; set; } + + [JsonProperty("maxFeePerGas")] + public string MaxFeePerGas { get; set; } + + [JsonProperty("maxPriorityFeePerGas")] + public string MaxPriorityFeePerGas { get; set; } + + [JsonProperty("paymasterAndData")] + public string PaymasterAndData { get; set; } + + [JsonProperty("signature")] + public string Signature { get; set; } +} + +public class UserOperationHexifiedV7 +{ + [JsonProperty("sender")] + public string Sender { get; set; } + + [JsonProperty("nonce")] + public string Nonce { get; set; } + + [JsonProperty("factory")] + public string Factory { get; set; } + + [JsonProperty("factoryData")] + public string FactoryData { get; set; } + + [JsonProperty("callData")] + public string CallData { get; set; } + + [JsonProperty("callGasLimit")] + public string CallGasLimit { get; set; } + + [JsonProperty("verificationGasLimit")] + public string VerificationGasLimit { get; set; } + + [JsonProperty("preVerificationGas")] + public string PreVerificationGas { get; set; } + + [JsonProperty("maxFeePerGas")] + public string MaxFeePerGas { get; set; } + + [JsonProperty("maxPriorityFeePerGas")] + public string MaxPriorityFeePerGas { get; set; } + + [JsonProperty("paymaster")] + public string Paymaster { get; set; } + + [JsonProperty("paymasterVerificationGasLimit")] + public string PaymasterVerificationGasLimit { get; set; } + + [JsonProperty("paymasterPostOpGasLimit")] + public string PaymasterPostOpGasLimit { get; set; } + + [JsonProperty("paymasterData")] + public string PaymasterData { get; set; } + + [JsonProperty("signature")] + public string Signature { get; set; } +} + +public class EthEstimateUserOperationGasResponse +{ + [JsonProperty("preVerificationGas")] + public string PreVerificationGas { get; set; } + + [JsonProperty("verificationGasLimit")] + public string VerificationGasLimit { get; set; } + + [JsonProperty("callGasLimit")] + public string CallGasLimit { get; set; } + + [JsonProperty("paymasterVerificationGasLimit")] + public string PaymasterVerificationGasLimit { get; set; } + + [JsonProperty("paymasterPostOpGasLimit")] + public string PaymasterPostOpGasLimit { get; set; } +} + +public class EthGetUserOperationReceiptResponse +{ + [JsonProperty("receipt")] + public ThirdwebTransactionReceipt Receipt { get; set; } +} + +public class TwGetDelegationContractResponse +{ + [JsonProperty("delegationContract")] + public string DelegationContract { get; set; } +} + +public class TwExecuteResponse +{ + [JsonProperty("queueId")] + public string QueueId { get; set; } +} + +public class TwGetTransactionHashResponse +{ + [JsonProperty("transactionHash")] + public string TransactionHash { get; set; } +} + +public class EntryPointWrapper +{ + [JsonProperty("entryPoint")] + public string EntryPoint { get; set; } +} + +public class PMSponsorOperationResponse +{ + [JsonProperty("paymasterAndData")] + public string PaymasterAndData { get; set; } + + [JsonProperty("paymaster")] + public string Paymaster { get; set; } + + [JsonProperty("paymasterData")] + public string PaymasterData { get; set; } + + [JsonProperty("preVerificationGas")] + public string PreVerificationGas { get; set; } + + [JsonProperty("verificationGasLimit")] + public string VerificationGasLimit { get; set; } + + [JsonProperty("callGasLimit")] + public string CallGasLimit { get; set; } + + [JsonProperty("paymasterVerificationGasLimit")] + public string PaymasterVerificationGasLimit { get; set; } + + [JsonProperty("paymasterPostOpGasLimit")] + public string PaymasterPostOpGasLimit { get; set; } +} + +public class ThirdwebGetUserOperationGasPriceResponse +{ + [JsonProperty("maxFeePerGas")] + public string MaxFeePerGas { get; set; } + + [JsonProperty("maxPriorityFeePerGas")] + public string MaxPriorityFeePerGas { get; set; } +} + +[Event("UserOperationEvent")] +public class UserOperationEventEventDTO : IEventDTO +{ + [Parameter("bytes32", "userOpHash", 1, true)] + public virtual byte[] UserOpHash { get; set; } + + [Parameter("address", "sender", 2, true)] + public virtual string Sender { get; set; } + + [Parameter("address", "paymaster", 3, true)] + public virtual string Paymaster { get; set; } + + [Parameter("uint256", "nonce", 4, false)] + public virtual BigInteger Nonce { get; set; } + + [Parameter("bool", "success", 5, false)] + public virtual bool Success { get; set; } + + [Parameter("uint256", "actualGasCost", 6, false)] + public virtual BigInteger ActualGasCost { get; set; } + + [Parameter("uint256", "actualGasUsed", 7, false)] + public virtual BigInteger ActualGasUsed { get; set; } +} + +[Event("UserOperationRevertReason")] +public class UserOperationRevertReasonEventDTO : IEventDTO +{ + [Parameter("bytes32", "userOpHash", 1, true)] + public virtual byte[] UserOpHash { get; set; } + + [Parameter("address", "sender", 2, true)] + public virtual string Sender { get; set; } + + [Parameter("uint256", "nonce", 3, false)] + public virtual BigInteger Nonce { get; set; } + + [Parameter("bytes", "revertReason", 4, false)] + public virtual byte[] RevertReason { get; set; } +} + +[Event("PostOpRevertReason")] +public class PostOpRevertReasonEventDTO : IEventDTO +{ + [Parameter("bytes32", "userOpHash", 1, true)] + public virtual byte[] UserOpHash { get; set; } + + [Parameter("address", "sender", 2, true)] + public virtual string Sender { get; set; } + + [Parameter("uint256", "nonce", 3, false)] + public virtual BigInteger Nonce { get; set; } + + [Parameter("bytes", "revertReason", 4, false)] + public virtual byte[] RevertReason { get; set; } +} + +[Struct("SignerPermissionRequest")] +public class SignerPermissionRequest +{ + [Parameter("address", "signer", 1)] + public virtual string Signer { get; set; } + + [Parameter("uint8", "isAdmin", 2)] + public virtual byte IsAdmin { get; set; } + + [Parameter("address[]", "approvedTargets", 3)] + public virtual List ApprovedTargets { get; set; } + + [Parameter("uint256", "nativeTokenLimitPerTransaction", 4)] + public virtual BigInteger NativeTokenLimitPerTransaction { get; set; } + + [Parameter("uint128", "permissionStartTimestamp", 5)] + public virtual BigInteger PermissionStartTimestamp { get; set; } + + [Parameter("uint128", "permissionEndTimestamp", 6)] + public virtual BigInteger PermissionEndTimestamp { get; set; } + + [Parameter("uint128", "reqValidityStartTimestamp", 7)] + public virtual BigInteger ReqValidityStartTimestamp { get; set; } + + [Parameter("uint128", "reqValidityEndTimestamp", 8)] + public virtual BigInteger ReqValidityEndTimestamp { get; set; } + + [Parameter("bytes32", "uid", 9)] + public virtual byte[] Uid { get; set; } +} + +[Struct("AccountMessage")] +public class AccountMessage +{ + [Parameter("bytes", "message", 1)] + public virtual byte[] Message { get; set; } +} + +[Struct("Transaction")] +public class ZkSyncAATransaction +{ + [Parameter("uint256", "txType", 1)] + public virtual BigInteger TxType { get; set; } + + [Parameter("uint256", "from", 2)] + public virtual BigInteger From { get; set; } + + [Parameter("uint256", "to", 3)] + public virtual BigInteger To { get; set; } + + [Parameter("uint256", "gasLimit", 4)] + public virtual BigInteger GasLimit { get; set; } + + [Parameter("uint256", "gasPerPubdataByteLimit", 5)] + public virtual BigInteger GasPerPubdataByteLimit { get; set; } + + [Parameter("uint256", "maxFeePerGas", 6)] + public virtual BigInteger MaxFeePerGas { get; set; } + + [Parameter("uint256", "maxPriorityFeePerGas", 7)] + public virtual BigInteger MaxPriorityFeePerGas { get; set; } + + [Parameter("uint256", "paymaster", 8)] + public virtual BigInteger Paymaster { get; set; } + + [Parameter("uint256", "nonce", 9)] + public virtual BigInteger Nonce { get; set; } + + [Parameter("uint256", "value", 10)] + public virtual BigInteger Value { get; set; } + + [Parameter("bytes", "data", 11)] + public virtual byte[] Data { get; set; } + + [Parameter("bytes32[]", "factoryDeps", 12)] + public virtual List FactoryDeps { get; set; } + + [Parameter("bytes", "paymasterInput", 13)] + public virtual byte[] PaymasterInput { get; set; } +} + +public class ZkPaymasterDataResponse +{ + [JsonProperty("paymaster")] + public string Paymaster { get; set; } + + [JsonProperty("paymasterInput")] + public string PaymasterInput { get; set; } +} + +public class ZkBroadcastTransactionResponse +{ + [JsonProperty("transactionHash")] + public string TransactionHash { get; set; } +} + +public class SignerPermissions +{ + [Parameter("address", "signer", 1)] + public virtual string Signer { get; set; } + + [Parameter("address[]", "approvedTargets", 2)] + public virtual List ApprovedTargets { get; set; } + + [Parameter("uint256", "nativeTokenLimitPerTransaction", 3)] + public virtual BigInteger NativeTokenLimitPerTransaction { get; set; } + + [Parameter("uint128", "startTimestamp", 4)] + public virtual BigInteger StartTimestamp { get; set; } + + [Parameter("uint128", "endTimestamp", 5)] + public virtual BigInteger EndTimestamp { get; set; } +} + +public class Multicall3_Call3 +{ + [Parameter("address", "target", 1)] + public virtual string Target { get; set; } + + [Parameter("bool", "allowFailure", 2)] + public virtual bool AllowFailure { get; set; } + + [Parameter("bytes", "callData", 3)] + public virtual byte[] CallData { get; set; } +} + +public class Multicall3_Result +{ + [Parameter("bool", "success", 1)] + public virtual bool Success { get; set; } + + [Parameter("bytes", "returnData", 2)] + public virtual byte[] ReturnData { get; set; } +} + +public class Erc6492Signature +{ + [Parameter("address", "create2Factory", 1)] + public string Create2Factory { get; set; } + + [Parameter("bytes", "factoryCalldata", 2)] + public byte[] FactoryCalldata { get; set; } + + [Parameter("bytes", "callData", 3)] + public byte[] SigToValidate { get; set; } +} + +#region 7702 + +[Struct("SessionSpec")] +public class SessionSpec +{ + [Parameter("address", "signer", 1)] + [JsonProperty("signer")] + public virtual string Signer { get; set; } + + [Parameter("bool", "isWildcard", 2)] + [JsonProperty("isWildcard")] + public virtual bool IsWildcard { get; set; } + + [Parameter("uint256", "expiresAt", 3)] + [JsonProperty("expiresAt")] + public virtual BigInteger ExpiresAt { get; set; } + + [Parameter("tuple[]", "callPolicies", 4, structTypeName: "CallSpec[]")] + [JsonProperty("callPolicies")] + public virtual List CallPolicies { get; set; } + + [Parameter("tuple[]", "transferPolicies", 5, structTypeName: "TransferSpec[]")] + [JsonProperty("transferPolicies")] + public virtual List TransferPolicies { get; set; } + + [Parameter("bytes32", "uid", 6)] + [JsonProperty("uid")] + public virtual byte[] Uid { get; set; } +} + +[Struct("CallSpec")] +public class CallSpec +{ + [Parameter("address", "target", 1)] + [JsonProperty("target")] + public virtual string Target { get; set; } + + [Parameter("bytes4", "selector", 2)] + [JsonProperty("selector")] + public virtual byte[] Selector { get; set; } + + [Parameter("uint256", "maxValuePerUse", 3)] + [JsonProperty("maxValuePerUse")] + public virtual BigInteger MaxValuePerUse { get; set; } + + [Parameter("tuple", "valueLimit", 4, structTypeName: "UsageLimit")] + [JsonProperty("valueLimit")] + public virtual UsageLimit ValueLimit { get; set; } + + [Parameter("tuple[]", "constraints", 5, structTypeName: "Constraint[]")] + [JsonProperty("constraints")] + public virtual List Constraints { get; set; } +} + +[Struct("TransferSpec")] +public class TransferSpec +{ + [Parameter("address", "target", 1)] + [JsonProperty("target")] + public virtual string Target { get; set; } + + [Parameter("uint256", "maxValuePerUse", 2)] + [JsonProperty("maxValuePerUse")] + public virtual BigInteger MaxValuePerUse { get; set; } + + [Parameter("tuple", "valueLimit", 3, structTypeName: "UsageLimit")] + [JsonProperty("valueLimit")] + public virtual UsageLimit ValueLimit { get; set; } +} + +[Struct("UsageLimit")] +public class UsageLimit +{ + [Parameter("uint8", "limitType", 1)] + [JsonProperty("limitType")] + public virtual byte LimitType { get; set; } + + [Parameter("uint256", "limit", 2)] + [JsonProperty("limit")] + public virtual BigInteger Limit { get; set; } + + [Parameter("uint256", "period", 3)] + [JsonProperty("period")] + public virtual BigInteger Period { get; set; } +} + +[Struct("Constraint")] +public class Constraint +{ + [Parameter("uint8", "condition", 1)] + [JsonProperty("condition")] + public virtual byte Condition { get; set; } + + [Parameter("uint64", "index", 2)] + [JsonProperty("index")] + public virtual ulong Index { get; set; } + + [Parameter("bytes32", "refValue", 3)] + [JsonProperty("refValue")] + public virtual byte[] RefValue { get; set; } + + [Parameter("tuple", "limit", 4, structTypeName: "UsageLimit")] + [JsonProperty("limit")] + public virtual UsageLimit Limit { get; set; } +} + +[Struct("Call")] +public class Call +{ + [Parameter("address", "target", 1)] + [JsonProperty("target")] + public virtual string Target { get; set; } + + [Parameter("uint256", "value", 2)] + [JsonProperty("value")] + public virtual BigInteger Value { get; set; } + + [Parameter("bytes", "data", 3)] + [JsonProperty("data")] + public virtual byte[] Data { get; set; } + + public object EncodeForHttp() + { + return new + { + target = this.Target, + value = this.Value, + data = this.Data != null ? this.Data.BytesToHex() : "0x", + }; + } +} + +[Struct("WrappedCalls")] +public class WrappedCalls +{ + [Parameter("tuple[]", "calls", 1, structTypeName: "Call[]")] + [JsonProperty("calls")] + public virtual List Calls { get; set; } + + [Parameter("bytes32", "uid", 2)] + [JsonProperty("uid")] + public virtual byte[] Uid { get; set; } + + public object EncodeForHttp() + { + return new { calls = this.Calls != null ? this.Calls.Select(c => c.EncodeForHttp()).ToList() : new List(), uid = this.Uid.BytesToHex() }; + } +} + +[Struct("LimitState")] +public class LimitState +{ + [Parameter("uint256", "remaining", 1)] + [JsonProperty("remaining")] + public virtual BigInteger Remaining { get; set; } + + [Parameter("address", "target", 2)] + [JsonProperty("target")] + public virtual string Target { get; set; } + + [Parameter("bytes4", "selector", 3)] + [JsonProperty("selector")] + public virtual byte[] Selector { get; set; } + + [Parameter("uint256", "index", 4)] + [JsonProperty("index")] + public virtual BigInteger Index { get; set; } +} + +[Struct("SessionState")] +public class SessionState +{ + [Parameter("tuple[]", "transferValue", 1, structTypeName: "LimitState[]")] + [JsonProperty("transferValue")] + public virtual List TransferValue { get; set; } + + [Parameter("tuple[]", "callValue", 2, structTypeName: "LimitState[]")] + [JsonProperty("callValue")] + public virtual List CallValue { get; set; } + + [Parameter("tuple[]", "callParams", 3, structTypeName: "LimitState[]")] + [JsonProperty("callParams")] + public virtual List CallParams { get; set; } +} + +#endregion diff --git a/Thirdweb/Thirdweb.Wallets/SmartWallet/Thirdweb.AccountAbstraction/ThirdwebBundler.cs b/Thirdweb/Thirdweb.Wallets/SmartWallet/Thirdweb.AccountAbstraction/ThirdwebBundler.cs new file mode 100644 index 00000000..e718bb1b --- /dev/null +++ b/Thirdweb/Thirdweb.Wallets/SmartWallet/Thirdweb.AccountAbstraction/ThirdwebBundler.cs @@ -0,0 +1,146 @@ +using Newtonsoft.Json; + +namespace Thirdweb.AccountAbstraction; + +public static class ThirdwebBundler +{ + // EIP 7702 requests + public static async Task TwGetDelegationContract(ThirdwebClient client, string url, int requestId) + { + var response = await BundlerRequest(client, url, requestId, "tw_getDelegationContract").ConfigureAwait(false); + return JsonConvert.DeserializeObject(response.Result.ToString()); + } + + public static async Task TwExecute( + ThirdwebClient client, + string url, + object requestId, + string eoaAddress, + WrappedCalls wrappedCalls, + string signature, + EIP7702Authorization? authorization + ) + { + var response = await BundlerRequest( + client, + url, + requestId, + "tw_execute", + eoaAddress, + wrappedCalls.EncodeForHttp(), + signature, + authorization == null + ? null + : new + { + chainId = authorization?.ChainId.HexToNumber(), + address = authorization?.Address, + nonce = authorization?.Nonce.HexToNumber().ToString(), + yParity = authorization?.YParity.HexToNumber(), + r = authorization?.R.HexToNumber().ToString(), + s = authorization?.S.HexToNumber().ToString(), + } + ) + .ConfigureAwait(false); + return JsonConvert.DeserializeObject(response.Result.ToString()); + } + + public static async Task TwGetTransactionHash(ThirdwebClient client, string url, int requestId, string queueId) + { + var response = await BundlerRequest(client, url, requestId, "tw_getTransactionHash", queueId).ConfigureAwait(false); + return JsonConvert.DeserializeObject(response.Result.ToString()); + } + + // Bundler requests + + public static async Task EthGetUserOperationReceipt(ThirdwebClient client, string bundlerUrl, object requestId, string userOpHash) + { + var response = await BundlerRequest(client, bundlerUrl, requestId, "eth_getUserOperationReceipt", userOpHash).ConfigureAwait(false); + return JsonConvert.DeserializeObject(response.Result.ToString()); + } + + public static async Task EthSendUserOperation(ThirdwebClient client, string bundlerUrl, object requestId, object userOp, string entryPoint) + { + var response = await BundlerRequest(client, bundlerUrl, requestId, "eth_sendUserOperation", userOp, entryPoint).ConfigureAwait(false); + return response.Result.ToString(); + } + + public static async Task EthEstimateUserOperationGas( + ThirdwebClient client, + string bundlerUrl, + object requestId, + object userOp, + string entryPoint, + object stateOverrides = null + ) + { + var response = await BundlerRequest(client, bundlerUrl, requestId, "eth_estimateUserOperationGas", userOp, entryPoint, stateOverrides).ConfigureAwait(false); + return JsonConvert.DeserializeObject(response.Result.ToString()); + } + + public static async Task ThirdwebGetUserOperationGasPrice(ThirdwebClient client, string bundlerUrl, object requestId) + { + var response = await BundlerRequest(client, bundlerUrl, requestId, "thirdweb_getUserOperationGasPrice").ConfigureAwait(false); + return JsonConvert.DeserializeObject(response.Result.ToString()); + } + + // Paymaster requests + + public static async Task PMSponsorUserOperation(ThirdwebClient client, string paymasterUrl, object requestId, object userOp, string entryPoint) + { + var response = await BundlerRequest(client, paymasterUrl, requestId, "pm_sponsorUserOperation", userOp, entryPoint).ConfigureAwait(false); + return JsonConvert.DeserializeObject(response.Result.ToString()); + } + + public static async Task ZkPaymasterData(ThirdwebClient client, string paymasterUrl, object requestId, ThirdwebTransactionInput txInput) + { + var response = await BundlerRequest(client, paymasterUrl, requestId, "zk_paymasterData", txInput).ConfigureAwait(false); + try + { + return JsonConvert.DeserializeObject(response.Result.ToString()); + } + catch + { + return new ZkPaymasterDataResponse() { Paymaster = null, PaymasterInput = null }; + } + } + + public static async Task ZkBroadcastTransaction(ThirdwebClient client, string paymasterUrl, object requestId, object txInput) + { + var response = await BundlerRequest(client, paymasterUrl, requestId, "zk_broadcastTransaction", txInput).ConfigureAwait(false); + return JsonConvert.DeserializeObject(response.Result.ToString()); + } + + // Request + + private static async Task BundlerRequest(ThirdwebClient client, string url, object requestId, string method, params object[] args) + { + var cts = new CancellationTokenSource(client.FetchTimeoutOptions.GetTimeout(TimeoutType.Other)); + + var httpClient = client.HttpClient; + var requestMessage = new RpcRequestMessage(requestId, method, args = args.Where(a => a != null).ToArray()); + var requestMessageJson = JsonConvert.SerializeObject(requestMessage); + + var httpContent = new StringContent(requestMessageJson, System.Text.Encoding.UTF8, "application/json"); + + ThirdwebHttpResponseMessage httpResponse; + try + { + httpResponse = await httpClient.PostAsync(url, httpContent, cts.Token).ConfigureAwait(false); + } + catch (TaskCanceledException) + { + throw new TimeoutException("The request timed out."); + } + + if (!httpResponse.IsSuccessStatusCode) + { + throw new Exception($"Bundler Request Failed. Error: {httpResponse.StatusCode} - {await httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false)}"); + } + + var httpResponseJson = await httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + + var response = JsonConvert.DeserializeObject(httpResponseJson); + return response.Error != null ? throw new Exception($"Bundler Request Failed. Error: {response.Error.Code} - {response.Error.Message} - {response.Error.Data}") : response; + } +} diff --git a/Thirdweb/Thirdweb.csproj b/Thirdweb/Thirdweb.csproj index ef663915..b451d611 100644 --- a/Thirdweb/Thirdweb.csproj +++ b/Thirdweb/Thirdweb.csproj @@ -1,10 +1,12 @@ - - $(DefaultTargetFrameworks) - $(DefaultVersion) - $(DefaultVersion) - $(DefaultVersion) + netstandard2.1;net6.0;net7.0;net8.0 + 3.1.1 + 3.1.1 + 3.1.1 + latest + true + enable Thirdweb Thirdweb 0xfirekeeper @@ -12,33 +14,27 @@ Copyright (c) thirdweb 2024 https://thirdweb.com/ icon.png - https://github.com/thirdweb-dev/thirdweb-dotnet + https://github.com/thirdweb-dev/dotnet git thirdweb wallet contracts client web3 ethereum blockchain game unity godot true Apache-2.0 - README.md true $(NoWarn);1591 - - - - - - - - - + + + + + + - - - \ No newline at end of file + diff --git a/codecov.yml b/codecov.yml index bd2adf1b..9bd94214 100644 --- a/codecov.yml +++ b/codecov.yml @@ -1,3 +1,3 @@ ignore: - "Thirdweb/Thirdweb.Wallets/InAppWallet" - - "Thirdweb/Thirdweb.Pay" \ No newline at end of file + - "Thirdweb/Thirdweb.Api" \ No newline at end of file diff --git a/global.json b/global.json index 05727086..45334b83 100644 --- a/global.json +++ b/global.json @@ -1,7 +1,7 @@ { "sdk": { - "version": "7.0.402", - "rollForward": "latestMajor", + "version": "8.0.401", + "rollForward": "latestPatch", "allowPrerelease": false } } diff --git a/llms.txt b/llms.txt new file mode 100644 index 00000000..0e84d963 --- /dev/null +++ b/llms.txt @@ -0,0 +1,17965 @@ +THIRDWEB .NET SDK - API DOCUMENTATION +===================================== + +Assembly: Thirdweb + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.InitiateAuthenticationAsync(Thirdweb.Api.Body) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - param1 (Thirdweb.Api.Body) + +SUMMARY: +Initiate Auth + +REMARKS: +Start any authentication flow in one unified endpoint. This endpoint supports all authentication methods including SMS, email, OAuth, passkey, and SIWE (Sign-In with Ethereum). +**Supported Methods:** +- **SMS** - Send verification code to phone number +- **Email** - Send verification code to email address +- **Passkey** - Generate WebAuthn challenge for biometric authentication +- **SIWE** - Generate Sign-In with Ethereum payload +**Flow:** +1. Choose your authentication method +2. Provide method-specific parameters +3. Receive challenge data to complete authentication +4. Use the /complete endpoint to finish the process +**OAuth:** +The OAuth method uses a dedicated `/auth/social` endpoint instead of this one: +`GET /auth/social?provider=google&redirectUrl=...` +**Custom (JWT, auth-payload) and Guest:** +For custom authentication (JWT, auth-payload) and for guest authentication, you can skip this step and use the `/auth/complete` endpoint directly. +**Authentication:** Requires `x-client-id` header for frontend usage or `x-secret-key` for backend usage. + +RETURNS: +Authentication initiated successfully. Use the returned challenge data to complete authentication. + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.InitiateAuthenticationAsync(Thirdweb.Api.Body,System.Threading.CancellationToken) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - cancellationToken (Thirdweb.Api.Body) + A cancellation token that can be used by other objects or threads to receive notice of cancellation. + - param2 (System.Threading.CancellationToken) + +SUMMARY: +Initiate Auth + +REMARKS: +Start any authentication flow in one unified endpoint. This endpoint supports all authentication methods including SMS, email, OAuth, passkey, and SIWE (Sign-In with Ethereum). +**Supported Methods:** +- **SMS** - Send verification code to phone number +- **Email** - Send verification code to email address +- **Passkey** - Generate WebAuthn challenge for biometric authentication +- **SIWE** - Generate Sign-In with Ethereum payload +**Flow:** +1. Choose your authentication method +2. Provide method-specific parameters +3. Receive challenge data to complete authentication +4. Use the /complete endpoint to finish the process +**OAuth:** +The OAuth method uses a dedicated `/auth/social` endpoint instead of this one: +`GET /auth/social?provider=google&redirectUrl=...` +**Custom (JWT, auth-payload) and Guest:** +For custom authentication (JWT, auth-payload) and for guest authentication, you can skip this step and use the `/auth/complete` endpoint directly. +**Authentication:** Requires `x-client-id` header for frontend usage or `x-secret-key` for backend usage. + +RETURNS: +Authentication initiated successfully. Use the returned challenge data to complete authentication. + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.CompleteAuthenticationAsync(Thirdweb.Api.Body2) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - param1 (Thirdweb.Api.Body2) + +SUMMARY: +Complete Auth + +REMARKS: +Complete the authentication flow and receive your wallet credentials. After initiating authentication, use this endpoint to submit the required verification data. +**Completion Methods:** +- **SMS/Email** - Submit the verification code you received +- **Passkey** - Provide the WebAuthn signature response +- **SIWE** - Submit your signed Ethereum message +- **Guest** - Create an ephemeral guest wallet +- **Custom (JWT, auth-payload)** - Send your JWT token or custom payload +**Response:** +- `isNewUser` - Whether this is a new wallet creation +- `token` - JWT token for authenticated API requests +- `type` - The authentication method used +- `userId` - Unique identifier for the authenticated user +- `walletAddress` - Your new or existing wallet address +**Next step - Verify your token:** +```javascript +// Verify the token and get complete wallet details (server-side) +fetch('/v1/wallets/me', { +headers: { +'Authorization': 'Bearer ' + token, +'x-secret-key': 'your-secret-key' +} +}) +.then(response => response.json()) +.then(data => { +console.log('Wallet verified:', data.result.address); +console.log('Auth profiles:', data.result.profiles); +}); +``` +**Authentication:** Requires `x-client-id` header for frontend usage or `x-secret-key` for backend usage. + +RETURNS: +Authentication completed successfully. You now have wallet access. + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.CompleteAuthenticationAsync(Thirdweb.Api.Body2,System.Threading.CancellationToken) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - cancellationToken (Thirdweb.Api.Body2) + A cancellation token that can be used by other objects or threads to receive notice of cancellation. + - param2 (System.Threading.CancellationToken) + +SUMMARY: +Complete Auth + +REMARKS: +Complete the authentication flow and receive your wallet credentials. After initiating authentication, use this endpoint to submit the required verification data. +**Completion Methods:** +- **SMS/Email** - Submit the verification code you received +- **Passkey** - Provide the WebAuthn signature response +- **SIWE** - Submit your signed Ethereum message +- **Guest** - Create an ephemeral guest wallet +- **Custom (JWT, auth-payload)** - Send your JWT token or custom payload +**Response:** +- `isNewUser` - Whether this is a new wallet creation +- `token` - JWT token for authenticated API requests +- `type` - The authentication method used +- `userId` - Unique identifier for the authenticated user +- `walletAddress` - Your new or existing wallet address +**Next step - Verify your token:** +```javascript +// Verify the token and get complete wallet details (server-side) +fetch('/v1/wallets/me', { +headers: { +'Authorization': 'Bearer ' + token, +'x-secret-key': 'your-secret-key' +} +}) +.then(response => response.json()) +.then(data => { +console.log('Wallet verified:', data.result.address); +console.log('Auth profiles:', data.result.profiles); +}); +``` +**Authentication:** Requires `x-client-id` header for frontend usage or `x-secret-key` for backend usage. + +RETURNS: +Authentication completed successfully. You now have wallet access. + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.LinkAuthenticationAsync(Thirdweb.Api.Body3) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - param1 (Thirdweb.Api.Body3) + +SUMMARY: +Link Auth + +REMARKS: +Link an additional authentication method or external wallet to the currently authenticated user. Provide the authentication token from another completed login (for example, a SIWE wallet or OAuth account) and this endpoint will associate it with the user's existing wallet. +**Usage:** +1. Complete an authentication flow using `/auth/complete` to obtain the new authentication token +2. Call this endpoint with the token you want to link +3. Receive the full list of linked authentication profiles for the wallet +**Authentication:** Requires both client authentication (`x-client-id` or `x-secret-key`) and a wallet access token via `Authorization: Bearer `. + +RETURNS: +Authentication method linked successfully. The response contains the updated list of linked authentication profiles. + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.LinkAuthenticationAsync(Thirdweb.Api.Body3,System.Threading.CancellationToken) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - cancellationToken (Thirdweb.Api.Body3) + A cancellation token that can be used by other objects or threads to receive notice of cancellation. + - param2 (System.Threading.CancellationToken) + +SUMMARY: +Link Auth + +REMARKS: +Link an additional authentication method or external wallet to the currently authenticated user. Provide the authentication token from another completed login (for example, a SIWE wallet or OAuth account) and this endpoint will associate it with the user's existing wallet. +**Usage:** +1. Complete an authentication flow using `/auth/complete` to obtain the new authentication token +2. Call this endpoint with the token you want to link +3. Receive the full list of linked authentication profiles for the wallet +**Authentication:** Requires both client authentication (`x-client-id` or `x-secret-key`) and a wallet access token via `Authorization: Bearer `. + +RETURNS: +Authentication method linked successfully. The response contains the updated list of linked authentication profiles. + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.UnlinkAuthenticationAsync(Thirdweb.Api.Body4) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - param1 (Thirdweb.Api.Body4) + +SUMMARY: +Unlink Auth + +REMARKS: +Disconnect an authentication method or external wallet from the currently authenticated user. Provide the identifiers for the provider you want to remove (for example, an email address or wallet address) and this endpoint will detach it from the user's account. +**Usage:** +1. Choose the provider type you want to disconnect (email, phone, siwe, oauth, etc.) +2. Supply the provider-specific identifiers in the request body +3. Receive the updated list of linked authentication profiles +**Authentication:** Requires both client authentication (`x-client-id` or `x-secret-key`) and a wallet access token via `Authorization: Bearer `. + +RETURNS: +Authentication method unlinked successfully. The response contains the updated list of linked authentication profiles. + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.UnlinkAuthenticationAsync(Thirdweb.Api.Body4,System.Threading.CancellationToken) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - cancellationToken (Thirdweb.Api.Body4) + A cancellation token that can be used by other objects or threads to receive notice of cancellation. + - param2 (System.Threading.CancellationToken) + +SUMMARY: +Unlink Auth + +REMARKS: +Disconnect an authentication method or external wallet from the currently authenticated user. Provide the identifiers for the provider you want to remove (for example, an email address or wallet address) and this endpoint will detach it from the user's account. +**Usage:** +1. Choose the provider type you want to disconnect (email, phone, siwe, oauth, etc.) +2. Supply the provider-specific identifiers in the request body +3. Receive the updated list of linked authentication profiles +**Authentication:** Requires both client authentication (`x-client-id` or `x-secret-key`) and a wallet access token via `Authorization: Bearer `. + +RETURNS: +Authentication method unlinked successfully. The response contains the updated list of linked authentication profiles. + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.SocialAuthenticationAsync(Thirdweb.Api.Provider,System.Uri,System.String) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - provider (Thirdweb.Api.Provider) + The OAuth provider to use + - redirectUrl (System.Uri) + URL to redirect the user to after OAuth completion + - clientId (string) + Client ID (alternative to x-client-id header for standard OAuth flows) + +SUMMARY: +Social Auth + +REMARKS: +Complete OAuth authentication with social providers in a single step. Unlike other auth methods that require separate initiate/complete calls, OAuth is handled entirely through redirects. +**OAuth Flow (Self-Contained):** +1. Redirect your user to this endpoint with provider and redirectUrl +2. User completes OAuth flow with the provider +3. User is redirected back to your redirectUrl with wallet credentials +**Why OAuth is different:** OAuth providers handle the challenge/response flow externally, so no separate `/complete` step is needed. +**Example:** +Redirect user to: `GET /v1/auth/social?provider=google&redirectUrl=https://myapp.com/auth/callback` +**Callback Handling:** +After OAuth completion, user arrives at your redirectUrl with an `authResult` query parameter: +``` +https://myapp.com/auth/callback?authResult=%7B%22storedToken%22%3A%7B%22authDetails%22%3A%7B...%7D%2C%22cookieString%22%3A%22eyJ...%22%7D%7D +``` +**Extract JWT token in your callback:** +```javascript +// Parse the authResult from URL +const urlParams = new URLSearchParams(window.location.search); +const authResultString = urlParams.get('authResult'); +const authResult = JSON.parse(authResultString!); +// Extract the JWT token +const token = authResult.storedToken.cookieString; +``` +**Verify and use the JWT token:** +```javascript +// Use the JWT token for authenticated requests +fetch('/v1/wallets/me', { +headers: { +'Authorization': 'Bearer ' + token, +'x-secret-key': 'your-secret-key' +} +}) +.then(response => response.json()) +.then(data => { +console.log('Wallet verified:', data.result.address); +console.log('Auth profiles:', data.result.profiles); +}); +``` +**Authentication Options:** +Choose one of two ways to provide your client credentials: +**Option 1: Query Parameter (Recommended for OAuth flows)** +``` +GET /v1/auth/social?provider=google&redirectUrl=https://myapp.com/callback&clientId=your_client_id +``` +**Option 2: Header (Alternative)** +``` +GET /v1/auth/social?provider=google&redirectUrl=https://myapp.com/callback +Headers: x-client-id: your_client_id +``` + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.SocialAuthenticationAsync(Thirdweb.Api.Provider,System.Uri,System.String,System.Threading.CancellationToken) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - cancellationToken (Thirdweb.Api.Provider) + A cancellation token that can be used by other objects or threads to receive notice of cancellation. + - provider (System.Uri) + The OAuth provider to use + - redirectUrl (string) + URL to redirect the user to after OAuth completion + - clientId (System.Threading.CancellationToken) + Client ID (alternative to x-client-id header for standard OAuth flows) + +SUMMARY: +Social Auth + +REMARKS: +Complete OAuth authentication with social providers in a single step. Unlike other auth methods that require separate initiate/complete calls, OAuth is handled entirely through redirects. +**OAuth Flow (Self-Contained):** +1. Redirect your user to this endpoint with provider and redirectUrl +2. User completes OAuth flow with the provider +3. User is redirected back to your redirectUrl with wallet credentials +**Why OAuth is different:** OAuth providers handle the challenge/response flow externally, so no separate `/complete` step is needed. +**Example:** +Redirect user to: `GET /v1/auth/social?provider=google&redirectUrl=https://myapp.com/auth/callback` +**Callback Handling:** +After OAuth completion, user arrives at your redirectUrl with an `authResult` query parameter: +``` +https://myapp.com/auth/callback?authResult=%7B%22storedToken%22%3A%7B%22authDetails%22%3A%7B...%7D%2C%22cookieString%22%3A%22eyJ...%22%7D%7D +``` +**Extract JWT token in your callback:** +```javascript +// Parse the authResult from URL +const urlParams = new URLSearchParams(window.location.search); +const authResultString = urlParams.get('authResult'); +const authResult = JSON.parse(authResultString!); +// Extract the JWT token +const token = authResult.storedToken.cookieString; +``` +**Verify and use the JWT token:** +```javascript +// Use the JWT token for authenticated requests +fetch('/v1/wallets/me', { +headers: { +'Authorization': 'Bearer ' + token, +'x-secret-key': 'your-secret-key' +} +}) +.then(response => response.json()) +.then(data => { +console.log('Wallet verified:', data.result.address); +console.log('Auth profiles:', data.result.profiles); +}); +``` +**Authentication Options:** +Choose one of two ways to provide your client credentials: +**Option 1: Query Parameter (Recommended for OAuth flows)** +``` +GET /v1/auth/social?provider=google&redirectUrl=https://myapp.com/callback&clientId=your_client_id +``` +**Option 2: Header (Alternative)** +``` +GET /v1/auth/social?provider=google&redirectUrl=https://myapp.com/callback +Headers: x-client-id: your_client_id +``` + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.GetMyWalletAsync +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +SUMMARY: +Get My Wallet + +REMARKS: +Retrieve the authenticated user's wallet information including wallet addresses and linked authentication wallets. This endpoint provides comprehensive user data for the currently authenticated session. +**Returns:** +- userId - Unique identifier for this wallet in thirdweb auth +- Primary wallet address +- Smart wallet address (if available) +- Wallet creation timestamp +- Public key in hexadecimal format (if available) +- All linked authentication profiles (email, phone, OAuth providers) +**Authentication:** Requires `Authorization: Bearer ` header with a valid user authentication token. + +RETURNS: +Wallet retrieved successfully. Returns comprehensive user information including wallet addresses, public key, and linked wallets. + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.GetMyWalletAsync(System.Threading.CancellationToken) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - cancellationToken (System.Threading.CancellationToken) + A cancellation token that can be used by other objects or threads to receive notice of cancellation. + +SUMMARY: +Get My Wallet + +REMARKS: +Retrieve the authenticated user's wallet information including wallet addresses and linked authentication wallets. This endpoint provides comprehensive user data for the currently authenticated session. +**Returns:** +- userId - Unique identifier for this wallet in thirdweb auth +- Primary wallet address +- Smart wallet address (if available) +- Wallet creation timestamp +- Public key in hexadecimal format (if available) +- All linked authentication profiles (email, phone, OAuth providers) +**Authentication:** Requires `Authorization: Bearer ` header with a valid user authentication token. + +RETURNS: +Wallet retrieved successfully. Returns comprehensive user information including wallet addresses, public key, and linked wallets. + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.ListUserWalletsAsync(System.Nullable{System.Double},System.Nullable{System.Double},System.String,System.String,System.String,System.String,System.String,System.String) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - userId (Nullable) + Filter results by the unique user identifier returned by auth flows. + - param2 (Nullable) + - param3 (string) + - param4 (string) + - param5 (string) + - param6 (string) + - param7 (string) + - param8 (string) + +SUMMARY: +List User Wallets + +REMARKS: +Get all user wallet details with filtering and pagination for your project. +**Authentication**: This endpoint requires backend authentication using the `x-secret-key` header. The secret key should never be exposed publicly. + +RETURNS: +Returns a list of user wallet addresses, smart wallet addresses, and auth details. + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.ListUserWalletsAsync(System.Nullable{System.Double},System.Nullable{System.Double},System.String,System.String,System.String,System.String,System.String,System.String,System.Threading.CancellationToken) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - cancellationToken (Nullable) + A cancellation token that can be used by other objects or threads to receive notice of cancellation. + - userId (Nullable) + Filter results by the unique user identifier returned by auth flows. + - param3 (string) + - param4 (string) + - param5 (string) + - param6 (string) + - param7 (string) + - param8 (string) + - param9 (System.Threading.CancellationToken) + +SUMMARY: +List User Wallets + +REMARKS: +Get all user wallet details with filtering and pagination for your project. +**Authentication**: This endpoint requires backend authentication using the `x-secret-key` header. The secret key should never be exposed publicly. + +RETURNS: +Returns a list of user wallet addresses, smart wallet addresses, and auth details. + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.CreateUserWalletAsync(Thirdweb.Api.Body5) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - param1 (Thirdweb.Api.Body5) + +SUMMARY: +Create User Wallet + +REMARKS: +Create a user wallet with a wallet based on their authentication strategy. This endpoint creates a wallet in advance that can be claimed later when the user authenticates. +**Authentication**: This endpoint requires backend authentication using the `x-secret-key` header. The secret key should never be exposed publicly. + +RETURNS: +Successfully created a user wallet with wallet. + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.CreateUserWalletAsync(Thirdweb.Api.Body5,System.Threading.CancellationToken) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - cancellationToken (Thirdweb.Api.Body5) + A cancellation token that can be used by other objects or threads to receive notice of cancellation. + - param2 (System.Threading.CancellationToken) + +SUMMARY: +Create User Wallet + +REMARKS: +Create a user wallet with a wallet based on their authentication strategy. This endpoint creates a wallet in advance that can be claimed later when the user authenticates. +**Authentication**: This endpoint requires backend authentication using the `x-secret-key` header. The secret key should never be exposed publicly. + +RETURNS: +Successfully created a user wallet with wallet. + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.ListServerWalletsAsync(System.Nullable{System.Double},System.Nullable{System.Double}) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - param1 (Nullable) + - param2 (Nullable) + +SUMMARY: +List Server Wallets + +REMARKS: +Get all server wallet details with pagination for your project. +**Authentication**: This endpoint requires backend authentication using the `x-secret-key` header. The secret key should never be exposed publicly. + +RETURNS: +Returns a list of server wallet addresses, smart wallet addresses, and auth details. + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.ListServerWalletsAsync(System.Nullable{System.Double},System.Nullable{System.Double},System.Threading.CancellationToken) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - cancellationToken (Nullable) + A cancellation token that can be used by other objects or threads to receive notice of cancellation. + - param2 (Nullable) + - param3 (System.Threading.CancellationToken) + +SUMMARY: +List Server Wallets + +REMARKS: +Get all server wallet details with pagination for your project. +**Authentication**: This endpoint requires backend authentication using the `x-secret-key` header. The secret key should never be exposed publicly. + +RETURNS: +Returns a list of server wallet addresses, smart wallet addresses, and auth details. + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.CreateServerWalletAsync(Thirdweb.Api.Body6) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - param1 (Thirdweb.Api.Body6) + +SUMMARY: +Create Server Wallet + +REMARKS: +Creates a server wallet from a unique identifier. If the wallet already exists, it will return the existing wallet. +**Authentication**: This endpoint requires backend authentication using the `x-secret-key` header. The secret key should never be exposed publicly. + +RETURNS: +Server wallet created or connected successfully. Returns wallet addresses for subsequent operations. + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.CreateServerWalletAsync(Thirdweb.Api.Body6,System.Threading.CancellationToken) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - cancellationToken (Thirdweb.Api.Body6) + A cancellation token that can be used by other objects or threads to receive notice of cancellation. + - param2 (System.Threading.CancellationToken) + +SUMMARY: +Create Server Wallet + +REMARKS: +Creates a server wallet from a unique identifier. If the wallet already exists, it will return the existing wallet. +**Authentication**: This endpoint requires backend authentication using the `x-secret-key` header. The secret key should never be exposed publicly. + +RETURNS: +Server wallet created or connected successfully. Returns wallet addresses for subsequent operations. + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.GetWalletBalanceAsync(System.String,System.Collections.Generic.IEnumerable{System.Int32},System.String) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - address (string) + A valid Ethereum address (0x-prefixed hex string) or ENS name (e.g., vitalik.eth). + - chainId (System.Collections.Generic.IEnumerable) + Chain ID(s) to request balance data for. You can specify multiple chain IDs by repeating the parameter, up to a maximum of 50. Example: ?chainId=1&chainId=137 + - tokenAddress (string) + The token contract address. Omit for native token (ETH, MATIC, etc.). + +SUMMARY: +Get Balance + +REMARKS: +Get native or ERC20 token balance for a wallet address. Can retrieve live balances for any ERC20 token on a signle chain, or native token balances across multiple chains. +**Authentication**: Pass `x-client-id` header for frontend usage from allowlisted origins or `x-secret-key` for backend usage. + +RETURNS: +Wallet native balances retrieved successfully. Returns detailed native token balance information for each chain including token metadata and formatted values. + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.GetWalletBalanceAsync(System.String,System.Collections.Generic.IEnumerable{System.Int32},System.String,System.Threading.CancellationToken) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - cancellationToken (string) + A cancellation token that can be used by other objects or threads to receive notice of cancellation. + - address (System.Collections.Generic.IEnumerable) + A valid Ethereum address (0x-prefixed hex string) or ENS name (e.g., vitalik.eth). + - chainId (string) + Chain ID(s) to request balance data for. You can specify multiple chain IDs by repeating the parameter, up to a maximum of 50. Example: ?chainId=1&chainId=137 + - tokenAddress (System.Threading.CancellationToken) + The token contract address. Omit for native token (ETH, MATIC, etc.). + +SUMMARY: +Get Balance + +REMARKS: +Get native or ERC20 token balance for a wallet address. Can retrieve live balances for any ERC20 token on a signle chain, or native token balances across multiple chains. +**Authentication**: Pass `x-client-id` header for frontend usage from allowlisted origins or `x-secret-key` for backend usage. + +RETURNS: +Wallet native balances retrieved successfully. Returns detailed native token balance information for each chain including token metadata and formatted values. + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.GetWalletTransactionsAsync(System.String,System.Collections.Generic.IEnumerable{System.Int32},System.Nullable{System.Int32},System.Nullable{System.Int32},System.Nullable{System.Int32},System.Nullable{System.Int32},System.String,System.String,System.Nullable{System.Double},System.Nullable{System.Double},System.Nullable{Thirdweb.Api.SortOrder}) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - address (string) + A valid Ethereum address (0x-prefixed hex string) or ENS name (e.g., vitalik.eth). + - chainId (System.Collections.Generic.IEnumerable) + Chain ID(s) to request transaction data for. You can specify multiple chain IDs by repeating the parameter, up to a maximum of 50. Example: ?chainId=1&chainId=137 + - filterBlockTimestampGte (Nullable) + Filter by block timestamp (Unix timestamp) greater than or equal to this value + - filterBlockTimestampLte (Nullable) + Filter by block timestamp (Unix timestamp) less than or equal to this value + - filterBlockNumberGte (Nullable) + Filter by block number greater than or equal to this value + - filterBlockNumberLte (Nullable) + Filter by block number less than or equal to this value + - filterValueGt (string) + Filter by transaction value (in wei) greater than this value + - filterFunctionSelector (string) + Filter by function selector (4-byte method ID), e.g., '0xa9059cbb' for ERC-20 transfer + - page (Nullable) + Current page number + - limit (Nullable) + Number of items per page + - sortOrder (Nullable) + Sort order: 'asc' for ascending, 'desc' for descending + +SUMMARY: +Get Transactions + +REMARKS: +Retrieves transactions for a specific wallet address across one or more blockchain networks. This endpoint provides comprehensive transaction data including both incoming and outgoing transactions, with block information, gas details, transaction status, and function calls. Results can be filtered, paginated, and sorted to meet specific requirements. +**Authentication**: Pass `x-client-id` header for frontend usage from allowlisted origins or `x-secret-key` for backend usage. + +RETURNS: +Wallet transactions retrieved successfully. Returns transaction data with metadata including pagination information and chain details. Includes decoded function calls when ABI is available. + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.GetWalletTransactionsAsync(System.String,System.Collections.Generic.IEnumerable{System.Int32},System.Nullable{System.Int32},System.Nullable{System.Int32},System.Nullable{System.Int32},System.Nullable{System.Int32},System.String,System.String,System.Nullable{System.Double},System.Nullable{System.Double},System.Nullable{Thirdweb.Api.SortOrder},System.Threading.CancellationToken) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - cancellationToken (string) + A cancellation token that can be used by other objects or threads to receive notice of cancellation. + - address (System.Collections.Generic.IEnumerable) + A valid Ethereum address (0x-prefixed hex string) or ENS name (e.g., vitalik.eth). + - chainId (Nullable) + Chain ID(s) to request transaction data for. You can specify multiple chain IDs by repeating the parameter, up to a maximum of 50. Example: ?chainId=1&chainId=137 + - filterBlockTimestampGte (Nullable) + Filter by block timestamp (Unix timestamp) greater than or equal to this value + - filterBlockTimestampLte (Nullable) + Filter by block timestamp (Unix timestamp) less than or equal to this value + - filterBlockNumberGte (Nullable) + Filter by block number greater than or equal to this value + - filterBlockNumberLte (string) + Filter by block number less than or equal to this value + - filterValueGt (string) + Filter by transaction value (in wei) greater than this value + - filterFunctionSelector (Nullable) + Filter by function selector (4-byte method ID), e.g., '0xa9059cbb' for ERC-20 transfer + - page (Nullable) + Current page number + - limit (Nullable) + Number of items per page + - sortOrder (System.Threading.CancellationToken) + Sort order: 'asc' for ascending, 'desc' for descending + +SUMMARY: +Get Transactions + +REMARKS: +Retrieves transactions for a specific wallet address across one or more blockchain networks. This endpoint provides comprehensive transaction data including both incoming and outgoing transactions, with block information, gas details, transaction status, and function calls. Results can be filtered, paginated, and sorted to meet specific requirements. +**Authentication**: Pass `x-client-id` header for frontend usage from allowlisted origins or `x-secret-key` for backend usage. + +RETURNS: +Wallet transactions retrieved successfully. Returns transaction data with metadata including pagination information and chain details. Includes decoded function calls when ABI is available. + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.GetWalletTokensAsync(System.String,System.Collections.Generic.IEnumerable{System.Int32},System.Collections.Generic.IEnumerable{System.String},System.Nullable{System.Int32},System.Nullable{System.Int32},System.Nullable{Thirdweb.Api.Metadata},System.Nullable{Thirdweb.Api.ResolveMetadataLinks},System.Nullable{Thirdweb.Api.IncludeSpam},System.Nullable{Thirdweb.Api.IncludeNative},System.Nullable{Thirdweb.Api.SortBy},System.Nullable{Thirdweb.Api.SortOrder2},System.Nullable{Thirdweb.Api.IncludeWithoutPrice}) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - address (string) + A valid Ethereum address (0x-prefixed hex string) or ENS name (e.g., vitalik.eth). + - chainId (System.Collections.Generic.IEnumerable) + Chain ID(s) to request token data for. You can specify multiple chain IDs by repeating the parameter, up to a maximum of 50. Example: ?chainId=1&chainId=137 + - tokenAddresses (System.Collections.Generic.IEnumerable) + Token addresses to filter by. If provided, only tokens with these addresses will be returned. + - limit (Nullable) + The number of tokens to return per chain (default: 20, max: 500). + - page (Nullable) + The page number for pagination (default: 1, max: 20). + - metadata (Nullable) + Whether to include token metadata (default: true). + - resolveMetadataLinks (Nullable) + Whether to resolve metadata links to fetch additional token information (default: true). + - includeSpam (Nullable) + Whether to include tokens marked as spam (default: false). + - includeNative (Nullable) + Whether to include native tokens (e.g., ETH, MATIC) in the results (default: true). + - sortBy (Nullable) + Field to sort tokens by: 'balance' for token balance, 'token_address' for token address, 'token_price' for token price, 'usd_value' for USD value (default: usd_value). + - sortOrder (Nullable) + Sort order: 'asc' for ascending, 'desc' for descending (default: desc). + - includeWithoutPrice (Nullable) + Whether to include tokens without price data (default: true). + +SUMMARY: +Get Tokens + +REMARKS: +Retrieves token balances for a specific wallet address across one or more blockchain networks. This endpoint provides comprehensive token data including ERC-20 tokens with their balances, metadata, and price information. Results can be filtered by chain, sorted by balance or USD value, and customized to include/exclude spam tokens, native tokens, and tokens without price data. Supports pagination and metadata resolution options. +**Authentication**: Pass `x-client-id` header for frontend usage from allowlisted origins or `x-secret-key` for backend usage. + +RETURNS: +Wallet tokens retrieved successfully. Returns token data with metadata including pagination information and chain details. Includes token balances, metadata, and price information when available. Results are sorted by the specified criteria (default: USD value descending) and filtered according to the provided parameters. + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.GetWalletTokensAsync(System.String,System.Collections.Generic.IEnumerable{System.Int32},System.Collections.Generic.IEnumerable{System.String},System.Nullable{System.Int32},System.Nullable{System.Int32},System.Nullable{Thirdweb.Api.Metadata},System.Nullable{Thirdweb.Api.ResolveMetadataLinks},System.Nullable{Thirdweb.Api.IncludeSpam},System.Nullable{Thirdweb.Api.IncludeNative},System.Nullable{Thirdweb.Api.SortBy},System.Nullable{Thirdweb.Api.SortOrder2},System.Nullable{Thirdweb.Api.IncludeWithoutPrice},System.Threading.CancellationToken) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - cancellationToken (string) + A cancellation token that can be used by other objects or threads to receive notice of cancellation. + - address (System.Collections.Generic.IEnumerable) + A valid Ethereum address (0x-prefixed hex string) or ENS name (e.g., vitalik.eth). + - chainId (System.Collections.Generic.IEnumerable) + Chain ID(s) to request token data for. You can specify multiple chain IDs by repeating the parameter, up to a maximum of 50. Example: ?chainId=1&chainId=137 + - tokenAddresses (Nullable) + Token addresses to filter by. If provided, only tokens with these addresses will be returned. + - limit (Nullable) + The number of tokens to return per chain (default: 20, max: 500). + - page (Nullable) + The page number for pagination (default: 1, max: 20). + - metadata (Nullable) + Whether to include token metadata (default: true). + - resolveMetadataLinks (Nullable) + Whether to resolve metadata links to fetch additional token information (default: true). + - includeSpam (Nullable) + Whether to include tokens marked as spam (default: false). + - includeNative (Nullable) + Whether to include native tokens (e.g., ETH, MATIC) in the results (default: true). + - sortBy (Nullable) + Field to sort tokens by: 'balance' for token balance, 'token_address' for token address, 'token_price' for token price, 'usd_value' for USD value (default: usd_value). + - sortOrder (Nullable) + Sort order: 'asc' for ascending, 'desc' for descending (default: desc). + - includeWithoutPrice (System.Threading.CancellationToken) + Whether to include tokens without price data (default: true). + +SUMMARY: +Get Tokens + +REMARKS: +Retrieves token balances for a specific wallet address across one or more blockchain networks. This endpoint provides comprehensive token data including ERC-20 tokens with their balances, metadata, and price information. Results can be filtered by chain, sorted by balance or USD value, and customized to include/exclude spam tokens, native tokens, and tokens without price data. Supports pagination and metadata resolution options. +**Authentication**: Pass `x-client-id` header for frontend usage from allowlisted origins or `x-secret-key` for backend usage. + +RETURNS: +Wallet tokens retrieved successfully. Returns token data with metadata including pagination information and chain details. Includes token balances, metadata, and price information when available. Results are sorted by the specified criteria (default: USD value descending) and filtered according to the provided parameters. + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.GetWalletNFTsAsync(System.String,System.Collections.Generic.IEnumerable{System.Int32},System.Collections.Generic.IEnumerable{System.String},System.Nullable{System.Int32},System.Nullable{System.Int32}) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - address (string) + A valid Ethereum address (0x-prefixed hex string) or ENS name (e.g., vitalik.eth). + - chainId (System.Collections.Generic.IEnumerable) + Chain ID(s) to request NFT data for. You can specify multiple chain IDs by repeating the parameter, up to a maximum of 50. Example: ?chainId=1&chainId=137 + - contractAddresses (System.Collections.Generic.IEnumerable) + NFT contract addresses to filter by. If provided, only NFTs with these addresses will be returned. + - limit (Nullable) + The number of NFTs to return per chain (default: 20, max: 500). + - page (Nullable) + The page number for pagination (default: 1, max: 20). + +SUMMARY: +Get NFTs + +REMARKS: +Retrieves NFTs for a specific wallet address across one or more blockchain networks. This endpoint provides comprehensive NFT data including metadata, attributes, and collection information. Results can be filtered by chain and paginated to meet specific requirements. +**Authentication**: Pass `x-client-id` header for frontend usage from allowlisted origins or `x-secret-key` for backend usage. + +RETURNS: +Wallet NFTs retrieved successfully. Returns NFT data with metadata including pagination information and chain details. Includes NFT metadata, attributes, and collection information when available. + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.GetWalletNFTsAsync(System.String,System.Collections.Generic.IEnumerable{System.Int32},System.Collections.Generic.IEnumerable{System.String},System.Nullable{System.Int32},System.Nullable{System.Int32},System.Threading.CancellationToken) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - cancellationToken (string) + A cancellation token that can be used by other objects or threads to receive notice of cancellation. + - address (System.Collections.Generic.IEnumerable) + A valid Ethereum address (0x-prefixed hex string) or ENS name (e.g., vitalik.eth). + - chainId (System.Collections.Generic.IEnumerable) + Chain ID(s) to request NFT data for. You can specify multiple chain IDs by repeating the parameter, up to a maximum of 50. Example: ?chainId=1&chainId=137 + - contractAddresses (Nullable) + NFT contract addresses to filter by. If provided, only NFTs with these addresses will be returned. + - limit (Nullable) + The number of NFTs to return per chain (default: 20, max: 500). + - page (System.Threading.CancellationToken) + The page number for pagination (default: 1, max: 20). + +SUMMARY: +Get NFTs + +REMARKS: +Retrieves NFTs for a specific wallet address across one or more blockchain networks. This endpoint provides comprehensive NFT data including metadata, attributes, and collection information. Results can be filtered by chain and paginated to meet specific requirements. +**Authentication**: Pass `x-client-id` header for frontend usage from allowlisted origins or `x-secret-key` for backend usage. + +RETURNS: +Wallet NFTs retrieved successfully. Returns NFT data with metadata including pagination information and chain details. Includes NFT metadata, attributes, and collection information when available. + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.SignMessageAsync(Thirdweb.Api.Body7) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - param1 (Thirdweb.Api.Body7) + +SUMMARY: +Sign Message + +REMARKS: +Signs an arbitrary message using the specified wallet. This endpoint supports both text and hexadecimal message formats. The signing is performed using thirdweb Engine with smart wallet support for gasless transactions. +**Authentication**: This endpoint requires project authentication and wallet authentication. For backend usage, use `x-secret-key` header. For frontend usage, use `x-client-id` + `Authorization: Bearer ` headers. + +RETURNS: +Message signed successfully. Returns the cryptographic signature that can be used for verification. + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.SignMessageAsync(Thirdweb.Api.Body7,System.Threading.CancellationToken) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - cancellationToken (Thirdweb.Api.Body7) + A cancellation token that can be used by other objects or threads to receive notice of cancellation. + - param2 (System.Threading.CancellationToken) + +SUMMARY: +Sign Message + +REMARKS: +Signs an arbitrary message using the specified wallet. This endpoint supports both text and hexadecimal message formats. The signing is performed using thirdweb Engine with smart wallet support for gasless transactions. +**Authentication**: This endpoint requires project authentication and wallet authentication. For backend usage, use `x-secret-key` header. For frontend usage, use `x-client-id` + `Authorization: Bearer ` headers. + +RETURNS: +Message signed successfully. Returns the cryptographic signature that can be used for verification. + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.SignTypedDataAsync(Thirdweb.Api.Body8) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - param1 (Thirdweb.Api.Body8) + +SUMMARY: +Sign Typed Data + +REMARKS: +Signs structured data according to the EIP-712 standard using the specified wallet. This is commonly used for secure message signing in DeFi protocols, NFT marketplaces, and other dApps that require structured data verification. The typed data includes domain separation and type definitions for enhanced security. +**Authentication**: This endpoint requires project authentication and wallet authentication. For backend usage, use `x-secret-key` header. For frontend usage, use `x-client-id` + `Authorization: Bearer ` headers. + +RETURNS: +Typed data signed successfully. Returns the EIP-712 compliant signature that can be used for on-chain verification. + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.SignTypedDataAsync(Thirdweb.Api.Body8,System.Threading.CancellationToken) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - cancellationToken (Thirdweb.Api.Body8) + A cancellation token that can be used by other objects or threads to receive notice of cancellation. + - param2 (System.Threading.CancellationToken) + +SUMMARY: +Sign Typed Data + +REMARKS: +Signs structured data according to the EIP-712 standard using the specified wallet. This is commonly used for secure message signing in DeFi protocols, NFT marketplaces, and other dApps that require structured data verification. The typed data includes domain separation and type definitions for enhanced security. +**Authentication**: This endpoint requires project authentication and wallet authentication. For backend usage, use `x-secret-key` header. For frontend usage, use `x-client-id` + `Authorization: Bearer ` headers. + +RETURNS: +Typed data signed successfully. Returns the EIP-712 compliant signature that can be used for on-chain verification. + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.SendTokensAsync(Thirdweb.Api.Body9) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - param1 (Thirdweb.Api.Body9) + +SUMMARY: +Send Tokens + +REMARKS: +Send tokens to multiple recipients in a single transaction batch. Supports native tokens (ETH, MATIC, etc.), ERC20 tokens, ERC721 NFTs, and ERC1155 tokens. The token type is automatically determined based on the provided parameters and ERC165 interface detection: +- **Native Token**: No `tokenAddress` provided +- **ERC20**: `tokenAddress` provided, no `tokenId` +- **ERC721/ERC1155**: `tokenAddress` and `tokenId` provided. Auto detects contract type: +- ERC721: quantity must be '1' +- ERC1155: any quantity allowed (including '1') +**Authentication**: This endpoint requires project authentication and wallet authentication. For backend usage, use `x-secret-key` header. For frontend usage, use `x-client-id` + `Authorization: Bearer ` headers. + +RETURNS: +Tokens sent successfully. Returns transaction IDs for tracking and monitoring. + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.SendTokensAsync(Thirdweb.Api.Body9,System.Threading.CancellationToken) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - cancellationToken (Thirdweb.Api.Body9) + A cancellation token that can be used by other objects or threads to receive notice of cancellation. + - param2 (System.Threading.CancellationToken) + +SUMMARY: +Send Tokens + +REMARKS: +Send tokens to multiple recipients in a single transaction batch. Supports native tokens (ETH, MATIC, etc.), ERC20 tokens, ERC721 NFTs, and ERC1155 tokens. The token type is automatically determined based on the provided parameters and ERC165 interface detection: +- **Native Token**: No `tokenAddress` provided +- **ERC20**: `tokenAddress` provided, no `tokenId` +- **ERC721/ERC1155**: `tokenAddress` and `tokenId` provided. Auto detects contract type: +- ERC721: quantity must be '1' +- ERC1155: any quantity allowed (including '1') +**Authentication**: This endpoint requires project authentication and wallet authentication. For backend usage, use `x-secret-key` header. For frontend usage, use `x-client-id` + `Authorization: Bearer ` headers. + +RETURNS: +Tokens sent successfully. Returns transaction IDs for tracking and monitoring. + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.ListContractsAsync(System.Nullable{System.Int32},System.Nullable{System.Int32}) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - limit (Nullable) + The number of contracts to return (default: 20, max: 100). + - page (Nullable) + The page number for pagination (default: 1). + +SUMMARY: +List Contracts + +REMARKS: +Retrieves a list of all smart contracts imported by the authenticated client on the thirdweb dashboard. This endpoint provides access to contracts that have been added to your dashboard for management and interaction. Results include contract metadata, deployment information, and import timestamps. +**Authentication**: This endpoint requires backend authentication using the `x-secret-key` header. The secret key should never be exposed publicly. +**Note**: For detailed contract metadata including compilation information, ABI, and source code, use the dedicated metadata endpoint: `GET /v1/contracts/{chainId}/{address}/metadata`. + +RETURNS: +Successfully retrieved list of contracts + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.ListContractsAsync(System.Nullable{System.Int32},System.Nullable{System.Int32},System.Threading.CancellationToken) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - cancellationToken (Nullable) + A cancellation token that can be used by other objects or threads to receive notice of cancellation. + - limit (Nullable) + The number of contracts to return (default: 20, max: 100). + - page (System.Threading.CancellationToken) + The page number for pagination (default: 1). + +SUMMARY: +List Contracts + +REMARKS: +Retrieves a list of all smart contracts imported by the authenticated client on the thirdweb dashboard. This endpoint provides access to contracts that have been added to your dashboard for management and interaction. Results include contract metadata, deployment information, and import timestamps. +**Authentication**: This endpoint requires backend authentication using the `x-secret-key` header. The secret key should never be exposed publicly. +**Note**: For detailed contract metadata including compilation information, ABI, and source code, use the dedicated metadata endpoint: `GET /v1/contracts/{chainId}/{address}/metadata`. + +RETURNS: +Successfully retrieved list of contracts + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.DeployContractAsync(Thirdweb.Api.Body10) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - param1 (Thirdweb.Api.Body10) + +SUMMARY: +Deploy Contract + +REMARKS: +Deploy a new smart contract to a blockchain network using raw bytecode. This endpoint allows you to deploy contracts by providing the contract bytecode, ABI, constructor parameters, and optional salt for deterministic deployment. +**Authentication**: This endpoint requires backend authentication using the `x-secret-key` header. The secret key should never be exposed publicly. + +RETURNS: +Contract deployed successfully + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.DeployContractAsync(Thirdweb.Api.Body10,System.Threading.CancellationToken) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - cancellationToken (Thirdweb.Api.Body10) + A cancellation token that can be used by other objects or threads to receive notice of cancellation. + - param2 (System.Threading.CancellationToken) + +SUMMARY: +Deploy Contract + +REMARKS: +Deploy a new smart contract to a blockchain network using raw bytecode. This endpoint allows you to deploy contracts by providing the contract bytecode, ABI, constructor parameters, and optional salt for deterministic deployment. +**Authentication**: This endpoint requires backend authentication using the `x-secret-key` header. The secret key should never be exposed publicly. + +RETURNS: +Contract deployed successfully + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.ReadContractAsync(Thirdweb.Api.Body11) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - param1 (Thirdweb.Api.Body11) + +SUMMARY: +Read Contract + +REMARKS: +Executes multiple read-only contract method calls in a single batch request. This endpoint allows efficient batch reading from multiple contracts on the same chain, significantly reducing the number of HTTP requests needed. Each call specifies the contract address, method signature, and optional parameters. Results are returned in the same order as the input calls, with individual success/failure status for each operation. +**Authentication**: Pass `x-client-id` header for frontend usage from allowlisted origins or `x-secret-key` for backend usage. + +RETURNS: +Contract read operations completed successfully. Returns an array of results corresponding to each input call, including both successful and failed operations. + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.ReadContractAsync(Thirdweb.Api.Body11,System.Threading.CancellationToken) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - cancellationToken (Thirdweb.Api.Body11) + A cancellation token that can be used by other objects or threads to receive notice of cancellation. + - param2 (System.Threading.CancellationToken) + +SUMMARY: +Read Contract + +REMARKS: +Executes multiple read-only contract method calls in a single batch request. This endpoint allows efficient batch reading from multiple contracts on the same chain, significantly reducing the number of HTTP requests needed. Each call specifies the contract address, method signature, and optional parameters. Results are returned in the same order as the input calls, with individual success/failure status for each operation. +**Authentication**: Pass `x-client-id` header for frontend usage from allowlisted origins or `x-secret-key` for backend usage. + +RETURNS: +Contract read operations completed successfully. Returns an array of results corresponding to each input call, including both successful and failed operations. + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.WriteContractAsync(Thirdweb.Api.Body12) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - param1 (Thirdweb.Api.Body12) + +SUMMARY: +Write Contract + +REMARKS: +Executes write operations (transactions) on smart contracts. This is a convenience endpoint that simplifies contract interaction by accepting method signatures and parameters directly, without requiring manual transaction encoding. All calls are executed against the same contract address and chain, making it ideal for batch operations. +**Authentication**: This endpoint requires project authentication and wallet authentication. For backend usage, use `x-secret-key` header. For frontend usage, use `x-client-id` + `Authorization: Bearer ` headers. + +RETURNS: +Contract write operations submitted successfully. Returns transaction IDs for tracking and monitoring. + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.WriteContractAsync(Thirdweb.Api.Body12,System.Threading.CancellationToken) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - cancellationToken (Thirdweb.Api.Body12) + A cancellation token that can be used by other objects or threads to receive notice of cancellation. + - param2 (System.Threading.CancellationToken) + +SUMMARY: +Write Contract + +REMARKS: +Executes write operations (transactions) on smart contracts. This is a convenience endpoint that simplifies contract interaction by accepting method signatures and parameters directly, without requiring manual transaction encoding. All calls are executed against the same contract address and chain, making it ideal for batch operations. +**Authentication**: This endpoint requires project authentication and wallet authentication. For backend usage, use `x-secret-key` header. For frontend usage, use `x-client-id` + `Authorization: Bearer ` headers. + +RETURNS: +Contract write operations submitted successfully. Returns transaction IDs for tracking and monitoring. + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.GetContractTransactionsAsync(System.Int32,System.String,System.String,System.String,System.Nullable{System.Int32},System.Nullable{System.Int32},System.Nullable{System.Int32},System.Nullable{System.Int32},System.String,System.String,System.Nullable{System.Double},System.Nullable{System.Double},System.Nullable{Thirdweb.Api.SortOrder3}) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - chainId (int) + The blockchain network identifier where the contract is deployed. + - address (string) + The smart contract address or ENS name. + - filterFromAddress (string) + Filter by transaction sender address + - filterToAddress (string) + Filter by transaction recipient address + - filterBlockTimestampGte (Nullable) + Filter by block timestamp (Unix timestamp) greater than or equal to this value + - filterBlockTimestampLte (Nullable) + Filter by block timestamp (Unix timestamp) less than or equal to this value + - filterBlockNumberGte (Nullable) + Filter by block number greater than or equal to this value + - filterBlockNumberLte (Nullable) + Filter by block number less than or equal to this value + - filterValueGt (string) + Filter by transaction value (in wei) greater than this value + - filterFunctionSelector (string) + Filter by function selector (4-byte method ID), e.g., '0xa9059cbb' for ERC-20 transfer + - page (Nullable) + Current page number + - limit (Nullable) + Number of items per page + - sortOrder (Nullable) + Sort order: 'asc' for ascending, 'desc' for descending + +SUMMARY: +Get Transactions + +REMARKS: +Retrieves transactions for a specific smart contract address on a specific blockchain network. This endpoint provides comprehensive transaction data including block information, gas details, transaction status, and function calls. Results can be filtered, paginated, and sorted to meet specific requirements. +**Authentication**: Pass `x-client-id` header for frontend usage from allowlisted origins or `x-secret-key` for backend usage. + +RETURNS: +Contract transactions retrieved successfully. Returns transaction data with metadata including pagination information. Includes decoded function calls when ABI is available. + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.GetContractTransactionsAsync(System.Int32,System.String,System.String,System.String,System.Nullable{System.Int32},System.Nullable{System.Int32},System.Nullable{System.Int32},System.Nullable{System.Int32},System.String,System.String,System.Nullable{System.Double},System.Nullable{System.Double},System.Nullable{Thirdweb.Api.SortOrder3},System.Threading.CancellationToken) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - cancellationToken (int) + A cancellation token that can be used by other objects or threads to receive notice of cancellation. + - chainId (string) + The blockchain network identifier where the contract is deployed. + - address (string) + The smart contract address or ENS name. + - filterFromAddress (string) + Filter by transaction sender address + - filterToAddress (Nullable) + Filter by transaction recipient address + - filterBlockTimestampGte (Nullable) + Filter by block timestamp (Unix timestamp) greater than or equal to this value + - filterBlockTimestampLte (Nullable) + Filter by block timestamp (Unix timestamp) less than or equal to this value + - filterBlockNumberGte (Nullable) + Filter by block number greater than or equal to this value + - filterBlockNumberLte (string) + Filter by block number less than or equal to this value + - filterValueGt (string) + Filter by transaction value (in wei) greater than this value + - filterFunctionSelector (Nullable) + Filter by function selector (4-byte method ID), e.g., '0xa9059cbb' for ERC-20 transfer + - page (Nullable) + Current page number + - limit (Nullable) + Number of items per page + - sortOrder (System.Threading.CancellationToken) + Sort order: 'asc' for ascending, 'desc' for descending + +SUMMARY: +Get Transactions + +REMARKS: +Retrieves transactions for a specific smart contract address on a specific blockchain network. This endpoint provides comprehensive transaction data including block information, gas details, transaction status, and function calls. Results can be filtered, paginated, and sorted to meet specific requirements. +**Authentication**: Pass `x-client-id` header for frontend usage from allowlisted origins or `x-secret-key` for backend usage. + +RETURNS: +Contract transactions retrieved successfully. Returns transaction data with metadata including pagination information. Includes decoded function calls when ABI is available. + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.GetContractEventsAsync(System.Int32,System.String,System.String,System.String,System.String,System.String,System.String,System.Nullable{System.Int32},System.Nullable{System.Int32},System.Nullable{System.Int32},System.Nullable{System.Int32},System.Nullable{System.Double},System.Nullable{System.Double},System.Nullable{Thirdweb.Api.SortOrder4}) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - chainId (int) + The blockchain network identifier where the contract is deployed. + - address (string) + The smart contract address or ENS name. + - signature (string) + Filter by event signature hash, e.g., '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef' for Transfer event + - filterTopic0 (string) + Filter by event topic 0 (event signature hash) + - filterTopic1 (string) + Filter by event topic 1 + - filterTopic2 (string) + Filter by event topic 2 + - filterTopic3 (string) + Filter by event topic 3 + - filterBlockTimestampGte (Nullable) + Filter by block timestamp (Unix timestamp) greater than or equal to this value + - filterBlockTimestampLte (Nullable) + Filter by block timestamp (Unix timestamp) less than or equal to this value + - filterBlockNumberGte (Nullable) + Filter by block number greater than or equal to this value + - filterBlockNumberLte (Nullable) + Filter by block number less than or equal to this value + - page (Nullable) + Current page number + - limit (Nullable) + Number of items per page + - sortOrder (Nullable) + Sort order: 'asc' for ascending, 'desc' for descending + +SUMMARY: +Get Events + +REMARKS: +Retrieves events emitted by a specific smart contract address on a specific blockchain network. This endpoint provides comprehensive event data including block information, transaction details, event topics, and optional ABI decoding. Results can be filtered, paginated, and sorted to meet specific requirements. +**Authentication**: Pass `x-client-id` header for frontend usage from allowlisted origins or `x-secret-key` for backend usage. + +RETURNS: +Contract events retrieved successfully. Returns event data with metadata including pagination information. Includes decoded event parameters when ABI is available. + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.GetContractEventsAsync(System.Int32,System.String,System.String,System.String,System.String,System.String,System.String,System.Nullable{System.Int32},System.Nullable{System.Int32},System.Nullable{System.Int32},System.Nullable{System.Int32},System.Nullable{System.Double},System.Nullable{System.Double},System.Nullable{Thirdweb.Api.SortOrder4},System.Threading.CancellationToken) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - cancellationToken (int) + A cancellation token that can be used by other objects or threads to receive notice of cancellation. + - chainId (string) + The blockchain network identifier where the contract is deployed. + - address (string) + The smart contract address or ENS name. + - signature (string) + Filter by event signature hash, e.g., '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef' for Transfer event + - filterTopic0 (string) + Filter by event topic 0 (event signature hash) + - filterTopic1 (string) + Filter by event topic 1 + - filterTopic2 (string) + Filter by event topic 2 + - filterTopic3 (Nullable) + Filter by event topic 3 + - filterBlockTimestampGte (Nullable) + Filter by block timestamp (Unix timestamp) greater than or equal to this value + - filterBlockTimestampLte (Nullable) + Filter by block timestamp (Unix timestamp) less than or equal to this value + - filterBlockNumberGte (Nullable) + Filter by block number greater than or equal to this value + - filterBlockNumberLte (Nullable) + Filter by block number less than or equal to this value + - page (Nullable) + Current page number + - limit (Nullable) + Number of items per page + - sortOrder (System.Threading.CancellationToken) + Sort order: 'asc' for ascending, 'desc' for descending + +SUMMARY: +Get Events + +REMARKS: +Retrieves events emitted by a specific smart contract address on a specific blockchain network. This endpoint provides comprehensive event data including block information, transaction details, event topics, and optional ABI decoding. Results can be filtered, paginated, and sorted to meet specific requirements. +**Authentication**: Pass `x-client-id` header for frontend usage from allowlisted origins or `x-secret-key` for backend usage. + +RETURNS: +Contract events retrieved successfully. Returns event data with metadata including pagination information. Includes decoded event parameters when ABI is available. + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.GetContractMetadataAsync(System.Int32,System.String) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - chainId (int) + The blockchain network identifier where the contract is deployed. + - address (string) + The smart contract address or ENS name. + +SUMMARY: +Get Metadata + +REMARKS: +Retrieves detailed metadata for a specific smart contract from the thirdweb contract metadata service. This includes compilation information, ABI, documentation, and other contract-related metadata. Note: Source code is excluded from the response to keep it lightweight and suitable for programmatic access. +**Authentication**: This endpoint requires backend authentication using the `x-secret-key` header. The secret key should never be exposed publicly. +**Metadata Source**: The metadata is fetched from the thirdweb contract metadata service and includes detailed Solidity compilation information, contract ABI, and developer documentation. + +RETURNS: +Successfully retrieved contract metadata + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.GetContractMetadataAsync(System.Int32,System.String,System.Threading.CancellationToken) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - cancellationToken (int) + A cancellation token that can be used by other objects or threads to receive notice of cancellation. + - chainId (string) + The blockchain network identifier where the contract is deployed. + - address (System.Threading.CancellationToken) + The smart contract address or ENS name. + +SUMMARY: +Get Metadata + +REMARKS: +Retrieves detailed metadata for a specific smart contract from the thirdweb contract metadata service. This includes compilation information, ABI, documentation, and other contract-related metadata. Note: Source code is excluded from the response to keep it lightweight and suitable for programmatic access. +**Authentication**: This endpoint requires backend authentication using the `x-secret-key` header. The secret key should never be exposed publicly. +**Metadata Source**: The metadata is fetched from the thirdweb contract metadata service and includes detailed Solidity compilation information, contract ABI, and developer documentation. + +RETURNS: +Successfully retrieved contract metadata + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.GetContractSignaturesAsync(System.Int32,System.String) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - chainId (int) + The blockchain network identifier where the contract is deployed. + - address (string) + The smart contract address or ENS name. + +SUMMARY: +Get Signatures + +REMARKS: +Retrieves human-readable ABI signatures for a specific smart contract. This endpoint fetches the contract metadata from the thirdweb service, extracts the ABI, and converts it into an array of human-readable function and event signatures that can be used directly with contract interaction methods. +**Authentication**: This endpoint requires backend authentication using the `x-secret-key` header. The secret key should never be exposed publicly. +**Usage**: The returned signatures can be used directly in contract read/write operations or event filtering. Each signature follows the standard Solidity format and includes function parameters, return types, state mutability, and event indexing information. + +RETURNS: +Successfully retrieved contract signatures + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.GetContractSignaturesAsync(System.Int32,System.String,System.Threading.CancellationToken) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - cancellationToken (int) + A cancellation token that can be used by other objects or threads to receive notice of cancellation. + - chainId (string) + The blockchain network identifier where the contract is deployed. + - address (System.Threading.CancellationToken) + The smart contract address or ENS name. + +SUMMARY: +Get Signatures + +REMARKS: +Retrieves human-readable ABI signatures for a specific smart contract. This endpoint fetches the contract metadata from the thirdweb service, extracts the ABI, and converts it into an array of human-readable function and event signatures that can be used directly with contract interaction methods. +**Authentication**: This endpoint requires backend authentication using the `x-secret-key` header. The secret key should never be exposed publicly. +**Usage**: The returned signatures can be used directly in contract read/write operations or event filtering. Each signature follows the standard Solidity format and includes function parameters, return types, state mutability, and event indexing information. + +RETURNS: +Successfully retrieved contract signatures + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.GetTransactionByIdAsync(System.String) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - transactionId (string) + Unique identifier of the transaction to retrieve. + +SUMMARY: +Get Transaction + +REMARKS: +Retrieves detailed information about a specific transaction using its unique identifier. Returns comprehensive transaction data including execution status, blockchain details, and any associated metadata. +**Authentication**: Pass `x-client-id` header for frontend usage from allowlisted origins or `x-secret-key` for backend usage. + +RETURNS: +Transaction details retrieved successfully. Returns comprehensive transaction information including status, blockchain details, and execution metadata. + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.GetTransactionByIdAsync(System.String,System.Threading.CancellationToken) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - cancellationToken (string) + A cancellation token that can be used by other objects or threads to receive notice of cancellation. + - transactionId (System.Threading.CancellationToken) + Unique identifier of the transaction to retrieve. + +SUMMARY: +Get Transaction + +REMARKS: +Retrieves detailed information about a specific transaction using its unique identifier. Returns comprehensive transaction data including execution status, blockchain details, and any associated metadata. +**Authentication**: Pass `x-client-id` header for frontend usage from allowlisted origins or `x-secret-key` for backend usage. + +RETURNS: +Transaction details retrieved successfully. Returns comprehensive transaction information including status, blockchain details, and execution metadata. + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.ListTransactionsAsync(System.String,System.Nullable{System.Int32},System.Nullable{System.Int32}) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - from (string) + Filter transactions by sender wallet address or ENS name. + - limit (Nullable) + Number of transactions to return per page (1-100). + - page (Nullable) + Page number for pagination, starting from 1. + +SUMMARY: +List Transactions + +REMARKS: +Retrieves a paginated list of transactions associated with the authenticated client. Results are sorted by creation date in descending order (most recent first). Supports filtering by wallet address and pagination controls. +**Authentication**: Pass `x-client-id` header for frontend usage from allowlisted origins or `x-secret-key` for backend usage. + +RETURNS: +Transactions retrieved successfully. Returns a paginated list of transactions with metadata including creation and confirmation timestamps. + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.ListTransactionsAsync(System.String,System.Nullable{System.Int32},System.Nullable{System.Int32},System.Threading.CancellationToken) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - cancellationToken (string) + A cancellation token that can be used by other objects or threads to receive notice of cancellation. + - from (Nullable) + Filter transactions by sender wallet address or ENS name. + - limit (Nullable) + Number of transactions to return per page (1-100). + - page (System.Threading.CancellationToken) + Page number for pagination, starting from 1. + +SUMMARY: +List Transactions + +REMARKS: +Retrieves a paginated list of transactions associated with the authenticated client. Results are sorted by creation date in descending order (most recent first). Supports filtering by wallet address and pagination controls. +**Authentication**: Pass `x-client-id` header for frontend usage from allowlisted origins or `x-secret-key` for backend usage. + +RETURNS: +Transactions retrieved successfully. Returns a paginated list of transactions with metadata including creation and confirmation timestamps. + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.SendTransactionsAsync(Thirdweb.Api.Body13) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - param1 (Thirdweb.Api.Body13) + +SUMMARY: +Send Transactions + +REMARKS: +Submits pre-encoded blockchain transactions with custom data payloads. This endpoint is for low-level transaction submission where you have already encoded the transaction data. For smart contract method calls, use /v1/contracts/write. For native token transfers, use /v1/wallets/send. +**Authentication**: This endpoint requires project authentication and wallet authentication. For backend usage, use `x-secret-key` header. For frontend usage, use `x-client-id` + `Authorization: Bearer ` headers. + +RETURNS: +Encoded transactions submitted successfully. Returns the transaction IDs for tracking and monitoring. + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.SendTransactionsAsync(Thirdweb.Api.Body13,System.Threading.CancellationToken) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - cancellationToken (Thirdweb.Api.Body13) + A cancellation token that can be used by other objects or threads to receive notice of cancellation. + - param2 (System.Threading.CancellationToken) + +SUMMARY: +Send Transactions + +REMARKS: +Submits pre-encoded blockchain transactions with custom data payloads. This endpoint is for low-level transaction submission where you have already encoded the transaction data. For smart contract method calls, use /v1/contracts/write. For native token transfers, use /v1/wallets/send. +**Authentication**: This endpoint requires project authentication and wallet authentication. For backend usage, use `x-secret-key` header. For frontend usage, use `x-client-id` + `Authorization: Bearer ` headers. + +RETURNS: +Encoded transactions submitted successfully. Returns the transaction IDs for tracking and monitoring. + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.CreatePaymentAsync(Thirdweb.Api.Body14) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - param1 (Thirdweb.Api.Body14) + +SUMMARY: +Create Payment + +REMARKS: +Create a payment to be executed. Users can complete the payment via hosted UI (link is returned), a transaction execution referencing the product ID, or embedded widgets with the product ID. +**Authentication**: This endpoint requires project authentication. + +RETURNS: +Payment created successfully. Returns the ID and link to complete the payment. + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.CreatePaymentAsync(Thirdweb.Api.Body14,System.Threading.CancellationToken) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - cancellationToken (Thirdweb.Api.Body14) + A cancellation token that can be used by other objects or threads to receive notice of cancellation. + - param2 (System.Threading.CancellationToken) + +SUMMARY: +Create Payment + +REMARKS: +Create a payment to be executed. Users can complete the payment via hosted UI (link is returned), a transaction execution referencing the product ID, or embedded widgets with the product ID. +**Authentication**: This endpoint requires project authentication. + +RETURNS: +Payment created successfully. Returns the ID and link to complete the payment. + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.PaymentsPurchaseAsync(System.String,Thirdweb.Api.Body15) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - param1 (string) + - param2 (Thirdweb.Api.Body15) + +SUMMARY: +Complete Payment + +REMARKS: +Completes a payment using its default token and amount. If the user does not have sufficient funds in the product's default payment token a 402 status will be returned containing a link and raw quote for purchase fulfillment. +**Authentication**: This endpoint requires project authentication. + +RETURNS: +Product purchased successfully. Returns the transaction used for the purchase. + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.PaymentsPurchaseAsync(System.String,Thirdweb.Api.Body15,System.Threading.CancellationToken) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - cancellationToken (string) + A cancellation token that can be used by other objects or threads to receive notice of cancellation. + - param2 (Thirdweb.Api.Body15) + - param3 (System.Threading.CancellationToken) + +SUMMARY: +Complete Payment + +REMARKS: +Completes a payment using its default token and amount. If the user does not have sufficient funds in the product's default payment token a 402 status will be returned containing a link and raw quote for purchase fulfillment. +**Authentication**: This endpoint requires project authentication. + +RETURNS: +Product purchased successfully. Returns the transaction used for the purchase. + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.GetPaymentHistoryAsync(System.String) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - param1 (string) + +SUMMARY: +Get Payment History + +REMARKS: +Get payment history for a specific payment link + +RETURNS: +Payment history retrieved successfully + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.GetPaymentHistoryAsync(System.String,System.Threading.CancellationToken) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - cancellationToken (string) + A cancellation token that can be used by other objects or threads to receive notice of cancellation. + - param2 (System.Threading.CancellationToken) + +SUMMARY: +Get Payment History + +REMARKS: +Get payment history for a specific payment link + +RETURNS: +Payment history retrieved successfully + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.VerifyX402PaymentAsync(Thirdweb.Api.Body16) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - param1 (Thirdweb.Api.Body16) + +SUMMARY: +x402 - Verify payment + +REMARKS: +Verify an x402 payment payload against the provided payment requirements. Compatible with any standard x402 middleware. + +RETURNS: +Verification successful + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.VerifyX402PaymentAsync(Thirdweb.Api.Body16,System.Threading.CancellationToken) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - cancellationToken (Thirdweb.Api.Body16) + A cancellation token that can be used by other objects or threads to receive notice of cancellation. + - param2 (System.Threading.CancellationToken) + +SUMMARY: +x402 - Verify payment + +REMARKS: +Verify an x402 payment payload against the provided payment requirements. Compatible with any standard x402 middleware. + +RETURNS: +Verification successful + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.SettleX402PaymentAsync(Thirdweb.Api.Body17) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - param1 (Thirdweb.Api.Body17) + +SUMMARY: +x402 - Settle payment + +REMARKS: +Settle an x402 payment. Compatible with any standard x402 middleware. + +RETURNS: +Settlement successful + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.SettleX402PaymentAsync(Thirdweb.Api.Body17,System.Threading.CancellationToken) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - cancellationToken (Thirdweb.Api.Body17) + A cancellation token that can be used by other objects or threads to receive notice of cancellation. + - param2 (System.Threading.CancellationToken) + +SUMMARY: +x402 - Settle payment + +REMARKS: +Settle an x402 payment. Compatible with any standard x402 middleware. + +RETURNS: +Settlement successful + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.SupportedX402PaymentsAsync(System.String,Thirdweb.Api.ChainId) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - tokenAddress (string) + A valid Ethereum address (0x-prefixed hex string) or ENS name (e.g., vitalik.eth). + - chainId (Thirdweb.Api.ChainId) + Chain ID in CAIP-2 format (e.g., 'eip155:1' for Ethereum, 'solana:mainnet' for Solana). Also accepts legacy numeric IDs for EVM chains. + +SUMMARY: +x402 - Supported payment methods + +REMARKS: +List supported x402 payment methods, optionally filtered by token address and chainId. Compatible with any standard x402 middleware. + +RETURNS: +Supported payment kinds + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.SupportedX402PaymentsAsync(System.String,Thirdweb.Api.ChainId,System.Threading.CancellationToken) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - cancellationToken (string) + A cancellation token that can be used by other objects or threads to receive notice of cancellation. + - tokenAddress (Thirdweb.Api.ChainId) + A valid Ethereum address (0x-prefixed hex string) or ENS name (e.g., vitalik.eth). + - chainId (System.Threading.CancellationToken) + Chain ID in CAIP-2 format (e.g., 'eip155:1' for Ethereum, 'solana:mainnet' for Solana). Also accepts legacy numeric IDs for EVM chains. + +SUMMARY: +x402 - Supported payment methods + +REMARKS: +List supported x402 payment methods, optionally filtered by token address and chainId. Compatible with any standard x402 middleware. + +RETURNS: +Supported payment kinds + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.FetchWithPaymentAsync(System.String,System.Uri,Thirdweb.Api.Method,System.String,System.String,Thirdweb.Api.ChainId2,System.Object) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - from (string) + A valid blockchain address. Accepts Ethereum (0x...) and Solana (base58) addresses, as well as ENS names for Ethereum. + - asset (System.Uri) + A valid blockchain address. Accepts Ethereum (0x...) and Solana (base58) addresses, as well as ENS names for Ethereum. + - chainId (Thirdweb.Api.Method) + Chain ID to use for the payment. Supports CAIP-2 strings (e.g., 'eip155:1', 'solana:mainnet') or legacy numeric EVM IDs. + - param4 (string) + - param5 (string) + - param6 (Thirdweb.Api.ChainId2) + - param7 (object) + +SUMMARY: +x402 - Fetch with payment + +REMARKS: +Fetch any given url. If the url returns HTTP 402 payment required, this endpoint handles payment with the authenticated wallet. +Optionally pass a 'from' query parameter with the authenticated wallet address (server or user wallet) to complete the payment. +If no 'from' parameter is passed, the default project wallet address will be used. +- Works with any x402 compatible endpoint. +- Automatically selects a compatible payment method. +- Signs the appropriate payment payload. +- Sends the payment to the url. +- Returns the final result from the url called. +Request body and headers are always passed through to the url called. +**Authentication**: This endpoint requires wallet authentication for the payment. For frontend usage, include `x-client-id` and `Authorization: Bearer ` headers. For backend usage, include `x-secret-key` header. + +RETURNS: +Returns the final result from the API call + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.FetchWithPaymentAsync(System.String,System.Uri,Thirdweb.Api.Method,System.String,System.String,Thirdweb.Api.ChainId2,System.Object,System.Threading.CancellationToken) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - cancellationToken (string) + A cancellation token that can be used by other objects or threads to receive notice of cancellation. + - from (System.Uri) + A valid blockchain address. Accepts Ethereum (0x...) and Solana (base58) addresses, as well as ENS names for Ethereum. + - asset (Thirdweb.Api.Method) + A valid blockchain address. Accepts Ethereum (0x...) and Solana (base58) addresses, as well as ENS names for Ethereum. + - chainId (string) + Chain ID to use for the payment. Supports CAIP-2 strings (e.g., 'eip155:1', 'solana:mainnet') or legacy numeric EVM IDs. + - param5 (string) + - param6 (Thirdweb.Api.ChainId2) + - param7 (object) + - param8 (System.Threading.CancellationToken) + +SUMMARY: +x402 - Fetch with payment + +REMARKS: +Fetch any given url. If the url returns HTTP 402 payment required, this endpoint handles payment with the authenticated wallet. +Optionally pass a 'from' query parameter with the authenticated wallet address (server or user wallet) to complete the payment. +If no 'from' parameter is passed, the default project wallet address will be used. +- Works with any x402 compatible endpoint. +- Automatically selects a compatible payment method. +- Signs the appropriate payment payload. +- Sends the payment to the url. +- Returns the final result from the url called. +Request body and headers are always passed through to the url called. +**Authentication**: This endpoint requires wallet authentication for the payment. For frontend usage, include `x-client-id` and `Authorization: Bearer ` headers. For backend usage, include `x-secret-key` header. + +RETURNS: +Returns the final result from the API call + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.ListPayableServicesAsync(System.Nullable{System.Double},System.Nullable{System.Double},System.String,System.Nullable{Thirdweb.Api.SortBy2},System.Nullable{Thirdweb.Api.SortOrder5}) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - param1 (Nullable) + - param2 (Nullable) + - param3 (string) + - param4 (Nullable) + - param5 (Nullable) + +SUMMARY: +x402 - Discover resources + +REMARKS: +Discover payable x402 compatible services and HTTP endpoints that can be paid for using the fetchWithPayment tool. Use this tool to browse services, APIs and endpoints to find what you need for your tasks. Each item has a resource url that you can call with the fetchWithPayment tool.Price is in the base units of the asset. For example, if the price is 1000000 and the asset is USDC (which is the default and has 6 decimals), the price is 1 USDC.Examples: if network is eip155:8453, asset is 0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913, max amount required is 10000, resource is https://api.example.com/paid-api, then you should interpret that as "the api.example.com/paid-api service costs 0.01 USDC per call". + +RETURNS: +List of discovered x402 resources + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.ListPayableServicesAsync(System.Nullable{System.Double},System.Nullable{System.Double},System.String,System.Nullable{Thirdweb.Api.SortBy2},System.Nullable{Thirdweb.Api.SortOrder5},System.Threading.CancellationToken) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - cancellationToken (Nullable) + A cancellation token that can be used by other objects or threads to receive notice of cancellation. + - param2 (Nullable) + - param3 (string) + - param4 (Nullable) + - param5 (Nullable) + - param6 (System.Threading.CancellationToken) + +SUMMARY: +x402 - Discover resources + +REMARKS: +Discover payable x402 compatible services and HTTP endpoints that can be paid for using the fetchWithPayment tool. Use this tool to browse services, APIs and endpoints to find what you need for your tasks. Each item has a resource url that you can call with the fetchWithPayment tool.Price is in the base units of the asset. For example, if the price is 1000000 and the asset is USDC (which is the default and has 6 decimals), the price is 1 USDC.Examples: if network is eip155:8453, asset is 0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913, max amount required is 10000, resource is https://api.example.com/paid-api, then you should interpret that as "the api.example.com/paid-api service costs 0.01 USDC per call". + +RETURNS: +List of discovered x402 resources + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.GetX402AcceptsAsync(Thirdweb.Api.Body18) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - param1 (Thirdweb.Api.Body18) + +SUMMARY: +x402 - Get payment accepts + +REMARKS: +Transform payment configuration into x402 payment requirements. This endpoint converts high-level payment parameters (like USD amounts or ERC20 token specifications) into the standardized x402 payment requirements format used by x402-compatible middleware. + +RETURNS: +Returns x402 payment requirements + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.GetX402AcceptsAsync(Thirdweb.Api.Body18,System.Threading.CancellationToken) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - cancellationToken (Thirdweb.Api.Body18) + A cancellation token that can be used by other objects or threads to receive notice of cancellation. + - param2 (System.Threading.CancellationToken) + +SUMMARY: +x402 - Get payment accepts + +REMARKS: +Transform payment configuration into x402 payment requirements. This endpoint converts high-level payment parameters (like USD amounts or ERC20 token specifications) into the standardized x402 payment requirements format used by x402-compatible middleware. + +RETURNS: +Returns x402 payment requirements + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.CreateTokenAsync(Thirdweb.Api.Body19) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - param1 (Thirdweb.Api.Body19) + +SUMMARY: +Create Token + +REMARKS: +Create a new ERC20 token with the provided metadata and starting price. The token is immediately available for purchase using thirdweb Payments. +**Authentication**: This endpoint requires project authentication and wallet authentication. For backend usage, use `x-secret-key` header. For frontend usage, use `x-client-id` + `Authorization: Bearer ` headers. + +RETURNS: +The token is being deployed. Returns the predicted token address. + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.CreateTokenAsync(Thirdweb.Api.Body19,System.Threading.CancellationToken) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - cancellationToken (Thirdweb.Api.Body19) + A cancellation token that can be used by other objects or threads to receive notice of cancellation. + - param2 (System.Threading.CancellationToken) + +SUMMARY: +Create Token + +REMARKS: +Create a new ERC20 token with the provided metadata and starting price. The token is immediately available for purchase using thirdweb Payments. +**Authentication**: This endpoint requires project authentication and wallet authentication. For backend usage, use `x-secret-key` header. For frontend usage, use `x-client-id` + `Authorization: Bearer ` headers. + +RETURNS: +The token is being deployed. Returns the predicted token address. + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.ListTokensAsync(System.Nullable{System.Int32},System.Nullable{System.Int32},System.Nullable{System.Int32},System.String,System.String,System.String) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - limit (Nullable) + Number of tokens to return per page (1-100). + - page (Nullable) + Page number for pagination, starting from 1. + - chainId (Nullable) + Limit tokens to a specific chain. + - tokenAddress (string) + Get a specific token by contract address + - symbol (string) + Limit tokens to a specific symbol. + - name (string) + Limit tokens to a specific name. + +SUMMARY: +List Tokens + +REMARKS: +Lists or search existing tokens based on the provided filters. Supports querying by chain ID, token address, symbol, and/or name. +**Authentication**: Pass `x-client-id` header for frontend usage from allowlisted origins or `x-secret-key` for backend usage. + +RETURNS: +Tokens returned successfully. + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.ListTokensAsync(System.Nullable{System.Int32},System.Nullable{System.Int32},System.Nullable{System.Int32},System.String,System.String,System.String,System.Threading.CancellationToken) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - cancellationToken (Nullable) + A cancellation token that can be used by other objects or threads to receive notice of cancellation. + - limit (Nullable) + Number of tokens to return per page (1-100). + - page (Nullable) + Page number for pagination, starting from 1. + - chainId (string) + Limit tokens to a specific chain. + - tokenAddress (string) + Get a specific token by contract address + - symbol (string) + Limit tokens to a specific symbol. + - name (System.Threading.CancellationToken) + Limit tokens to a specific name. + +SUMMARY: +List Tokens + +REMARKS: +Lists or search existing tokens based on the provided filters. Supports querying by chain ID, token address, symbol, and/or name. +**Authentication**: Pass `x-client-id` header for frontend usage from allowlisted origins or `x-secret-key` for backend usage. + +RETURNS: +Tokens returned successfully. + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.GetTokenOwnersAsync(System.Int32,System.String,System.String,System.Nullable{System.Int32},System.Nullable{System.Int32}) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - chainId (int) + The blockchain network identifier. Common values include: 1 (Ethereum), 8453 (Base), 137 (Polygon), 56 (BSC), 43114 (Avalanche), 42161 (Arbitrum), 10 (Optimism). + - address (string) + A valid Ethereum address (0x-prefixed hex string) or ENS name (e.g., vitalik.eth). + - tokenId (string) + Optional token ID for NFT owners. If provided, returns owners of the specific NFT token. + - limit (Nullable) + Number of owners to return per page (1-100). + - page (Nullable) + Page number for pagination, starting from 1. + +SUMMARY: +Get Owners + +REMARKS: +Retrieves a paginated list of owners for a given token contract on a specific chain. Supports ERC-20 tokens, ERC-721 NFTs, and ERC-1155 tokens: +- **ERC-20**: No `tokenId` provided - returns token holders with balances +- **NFT Collection**: No `tokenId` provided - returns all owners of any token in the collection +- **Specific NFT**: `tokenId` provided - returns owner(s) of that specific token ID +The token standard is automatically detected using ERC165 interface detection when needed. +**Authentication**: Pass `x-client-id` header for frontend usage from allowlisted origins or `x-secret-key` for backend usage. + +RETURNS: +Token owners retrieved successfully. Returns owners with pagination information. For ERC-20 tokens, `amount` represents token balance. For NFTs, `amount` represents quantity owned (usually '1' for ERC-721, can be >1 for ERC-1155). + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.GetTokenOwnersAsync(System.Int32,System.String,System.String,System.Nullable{System.Int32},System.Nullable{System.Int32},System.Threading.CancellationToken) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - cancellationToken (int) + A cancellation token that can be used by other objects or threads to receive notice of cancellation. + - chainId (string) + The blockchain network identifier. Common values include: 1 (Ethereum), 8453 (Base), 137 (Polygon), 56 (BSC), 43114 (Avalanche), 42161 (Arbitrum), 10 (Optimism). + - address (string) + A valid Ethereum address (0x-prefixed hex string) or ENS name (e.g., vitalik.eth). + - tokenId (Nullable) + Optional token ID for NFT owners. If provided, returns owners of the specific NFT token. + - limit (Nullable) + Number of owners to return per page (1-100). + - page (System.Threading.CancellationToken) + Page number for pagination, starting from 1. + +SUMMARY: +Get Owners + +REMARKS: +Retrieves a paginated list of owners for a given token contract on a specific chain. Supports ERC-20 tokens, ERC-721 NFTs, and ERC-1155 tokens: +- **ERC-20**: No `tokenId` provided - returns token holders with balances +- **NFT Collection**: No `tokenId` provided - returns all owners of any token in the collection +- **Specific NFT**: `tokenId` provided - returns owner(s) of that specific token ID +The token standard is automatically detected using ERC165 interface detection when needed. +**Authentication**: Pass `x-client-id` header for frontend usage from allowlisted origins or `x-secret-key` for backend usage. + +RETURNS: +Token owners retrieved successfully. Returns owners with pagination information. For ERC-20 tokens, `amount` represents token balance. For NFTs, `amount` represents quantity owned (usually '1' for ERC-721, can be >1 for ERC-1155). + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.GetBridgeChainsAsync +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +SUMMARY: +List Supported Chains + +REMARKS: +List all blockchain networks available for cross-chain bridging. Each chain includes metadata and native currency details. +**Authentication**: Pass `x-client-id` header for frontend usage from allowlisted origins or `x-secret-key` for backend usage. + +RETURNS: +Successfully retrieved supported bridge chains. + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.GetBridgeChainsAsync(System.Threading.CancellationToken) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - cancellationToken (System.Threading.CancellationToken) + A cancellation token that can be used by other objects or threads to receive notice of cancellation. + +SUMMARY: +List Supported Chains + +REMARKS: +List all blockchain networks available for cross-chain bridging. Each chain includes metadata and native currency details. +**Authentication**: Pass `x-client-id` header for frontend usage from allowlisted origins or `x-secret-key` for backend usage. + +RETURNS: +Successfully retrieved supported bridge chains. + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.GetBridgeSupportedRoutesAsync(System.Nullable{System.Int32},System.Nullable{System.Int32},System.Nullable{System.Int32},System.Nullable{System.Int32},System.String,System.String,System.Nullable{System.Int32}) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - limit (Nullable) + Maximum number of routes to return (1-100). + - page (Nullable) + Page number for pagination, starting at 1. + - originChainId (Nullable) + Filter routes by the origin chain ID. + - destinationChainId (Nullable) + Filter routes by the destination chain ID. + - originTokenAddress (string) + Filter routes by origin token address. + - destinationTokenAddress (string) + Filter routes by destination token address. + - maxSteps (Nullable) + Maximum number of bridge steps allowed in the route. + +SUMMARY: +List Supported Routes + +REMARKS: +List supported bridge routes with simple pagination and optional chain or token filters. +**Authentication**: Pass `x-client-id` header for frontend usage from allowlisted origins or `x-secret-key` for backend usage. + +RETURNS: +Successfully retrieved supported bridge routes. + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.GetBridgeSupportedRoutesAsync(System.Nullable{System.Int32},System.Nullable{System.Int32},System.Nullable{System.Int32},System.Nullable{System.Int32},System.String,System.String,System.Nullable{System.Int32},System.Threading.CancellationToken) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - cancellationToken (Nullable) + A cancellation token that can be used by other objects or threads to receive notice of cancellation. + - limit (Nullable) + Maximum number of routes to return (1-100). + - page (Nullable) + Page number for pagination, starting at 1. + - originChainId (Nullable) + Filter routes by the origin chain ID. + - destinationChainId (string) + Filter routes by the destination chain ID. + - originTokenAddress (string) + Filter routes by origin token address. + - destinationTokenAddress (Nullable) + Filter routes by destination token address. + - maxSteps (System.Threading.CancellationToken) + Maximum number of bridge steps allowed in the route. + +SUMMARY: +List Supported Routes + +REMARKS: +List supported bridge routes with simple pagination and optional chain or token filters. +**Authentication**: Pass `x-client-id` header for frontend usage from allowlisted origins or `x-secret-key` for backend usage. + +RETURNS: +Successfully retrieved supported bridge routes. + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.ConvertFiatToCryptoAsync(Thirdweb.Api.From,System.String,System.Int32,System.String) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - from (Thirdweb.Api.From) + The fiat currency symbol + - fromAmount (string) + The amount of fiat currency to convert + - chainId (int) + The blockchain network identifier + - to (string) + The token address on the specified chain to convert to + +SUMMARY: +Convert Fiat to Crypto + +REMARKS: +Convert fiat currency amount to cryptocurrency token amount. Supports multiple fiat currencies based on available price data for the specific token. Returns the equivalent amount of crypto tokens for the specified fiat amount based on current market prices. If price data is not available for the requested currency, the API will return a 404 error. +**Native Tokens**: To get the price of native tokens (like ETH on Ethereum), use the address `0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE`. For example, to get the price of ETH on Ethereum Mainnet (chainId: 1), pass `to=0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE`. +**Authentication**: Pass `x-client-id` header for frontend usage from allowlisted origins or `x-secret-key` for backend usage. + +RETURNS: +Conversion completed successfully. Returns the amount of crypto tokens equivalent to the specified fiat amount. + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.ConvertFiatToCryptoAsync(Thirdweb.Api.From,System.String,System.Int32,System.String,System.Threading.CancellationToken) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - cancellationToken (Thirdweb.Api.From) + A cancellation token that can be used by other objects or threads to receive notice of cancellation. + - from (string) + The fiat currency symbol + - fromAmount (int) + The amount of fiat currency to convert + - chainId (string) + The blockchain network identifier + - to (System.Threading.CancellationToken) + The token address on the specified chain to convert to + +SUMMARY: +Convert Fiat to Crypto + +REMARKS: +Convert fiat currency amount to cryptocurrency token amount. Supports multiple fiat currencies based on available price data for the specific token. Returns the equivalent amount of crypto tokens for the specified fiat amount based on current market prices. If price data is not available for the requested currency, the API will return a 404 error. +**Native Tokens**: To get the price of native tokens (like ETH on Ethereum), use the address `0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE`. For example, to get the price of ETH on Ethereum Mainnet (chainId: 1), pass `to=0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE`. +**Authentication**: Pass `x-client-id` header for frontend usage from allowlisted origins or `x-secret-key` for backend usage. + +RETURNS: +Conversion completed successfully. Returns the amount of crypto tokens equivalent to the specified fiat amount. + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.BridgeSwapAsync(Thirdweb.Api.Body20) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - param1 (Thirdweb.Api.Body20) + +SUMMARY: +Swap or Bridge Tokens + +REMARKS: +Swap one token for another using the optimal route available. You can specify a tokenIn amount (if exact='input') or tokenOut amount (if exact='output'), but not both. The corresponding output or input amount will be returned as the quote. +**Authentication**: This endpoint requires project authentication and wallet authentication. For backend usage, use `x-secret-key` header. For frontend usage, use `x-client-id` + `Authorization: Bearer ` headers. + +RETURNS: +Swap completed successfully. Returns the transaction used for the swap. + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.BridgeSwapAsync(Thirdweb.Api.Body20,System.Threading.CancellationToken) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - cancellationToken (Thirdweb.Api.Body20) + A cancellation token that can be used by other objects or threads to receive notice of cancellation. + - param2 (System.Threading.CancellationToken) + +SUMMARY: +Swap or Bridge Tokens + +REMARKS: +Swap one token for another using the optimal route available. You can specify a tokenIn amount (if exact='input') or tokenOut amount (if exact='output'), but not both. The corresponding output or input amount will be returned as the quote. +**Authentication**: This endpoint requires project authentication and wallet authentication. For backend usage, use `x-secret-key` header. For frontend usage, use `x-client-id` + `Authorization: Bearer ` headers. + +RETURNS: +Swap completed successfully. Returns the transaction used for the swap. + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.ListSolanaWalletsAsync(System.Nullable{System.Int32},System.Nullable{System.Int32}) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - page (Nullable) + Page number for paginated results. Starts at 1. + - limit (Nullable) + Maximum number of wallets to return per page. + +SUMMARY: +List Solana Wallets + +REMARKS: +List all Solana wallets created for your project. Supports pagination with page and limit parameters. +**Authentication**: This endpoint requires backend authentication using the x-secret-key header. The secret key should never be exposed publicly. + +RETURNS: +Successfully retrieved Solana wallets with pagination metadata. + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.ListSolanaWalletsAsync(System.Nullable{System.Int32},System.Nullable{System.Int32},System.Threading.CancellationToken) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - cancellationToken (Nullable) + A cancellation token that can be used by other objects or threads to receive notice of cancellation. + - page (Nullable) + Page number for paginated results. Starts at 1. + - limit (System.Threading.CancellationToken) + Maximum number of wallets to return per page. + +SUMMARY: +List Solana Wallets + +REMARKS: +List all Solana wallets created for your project. Supports pagination with page and limit parameters. +**Authentication**: This endpoint requires backend authentication using the x-secret-key header. The secret key should never be exposed publicly. + +RETURNS: +Successfully retrieved Solana wallets with pagination metadata. + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.CreateSolanaWalletAsync(Thirdweb.Api.Body21) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - param1 (Thirdweb.Api.Body21) + +SUMMARY: +Create Solana Wallet + +REMARKS: +Create a new Solana wallet or return the existing wallet for a given label. Labels must be unique within your project. +**Authentication**: This endpoint requires backend authentication using the x-secret-key header. The secret key should never be exposed publicly. + +RETURNS: +Solana wallet retrieved for the provided label. + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.CreateSolanaWalletAsync(Thirdweb.Api.Body21,System.Threading.CancellationToken) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - cancellationToken (Thirdweb.Api.Body21) + A cancellation token that can be used by other objects or threads to receive notice of cancellation. + - param2 (System.Threading.CancellationToken) + +SUMMARY: +Create Solana Wallet + +REMARKS: +Create a new Solana wallet or return the existing wallet for a given label. Labels must be unique within your project. +**Authentication**: This endpoint requires backend authentication using the x-secret-key header. The secret key should never be exposed publicly. + +RETURNS: +Solana wallet retrieved for the provided label. + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.GetSolanaWalletBalanceAsync(System.String,System.String,System.String) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - address (string) + Public key of the Solana wallet. + - chainId (string) + Solana network to query. Choose either solana:mainnet or solana:devnet. + - tokenAddress (string) + SPL token mint address. Omit to retrieve native SOL balance. + +SUMMARY: +Get Solana Wallet Balance + +REMARKS: +Get the SOL or SPL token balance for a Solana wallet on a specific Solana network. +**Authentication**: Pass `x-client-id` for frontend usage from allowlisted origins or `x-secret-key` for backend usage. + +RETURNS: +Wallet balance retrieved successfully for the requested Solana network. + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.GetSolanaWalletBalanceAsync(System.String,System.String,System.String,System.Threading.CancellationToken) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - cancellationToken (string) + A cancellation token that can be used by other objects or threads to receive notice of cancellation. + - address (string) + Public key of the Solana wallet. + - chainId (string) + Solana network to query. Choose either solana:mainnet or solana:devnet. + - tokenAddress (System.Threading.CancellationToken) + SPL token mint address. Omit to retrieve native SOL balance. + +SUMMARY: +Get Solana Wallet Balance + +REMARKS: +Get the SOL or SPL token balance for a Solana wallet on a specific Solana network. +**Authentication**: Pass `x-client-id` for frontend usage from allowlisted origins or `x-secret-key` for backend usage. + +RETURNS: +Wallet balance retrieved successfully for the requested Solana network. + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.SignSolanaMessageAsync(Thirdweb.Api.Body22) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - param1 (Thirdweb.Api.Body22) + +SUMMARY: +Sign Solana Message + +REMARKS: +Sign an arbitrary message with a Solana wallet. Supports both text and hexadecimal message formats with automatic format detection. +**Authentication**: This endpoint requires backend authentication using the x-secret-key header. The secret key should never be exposed publicly. + +RETURNS: +Message signed successfully. Returns the base58 signature. + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.SignSolanaMessageAsync(Thirdweb.Api.Body22,System.Threading.CancellationToken) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - cancellationToken (Thirdweb.Api.Body22) + A cancellation token that can be used by other objects or threads to receive notice of cancellation. + - param2 (System.Threading.CancellationToken) + +SUMMARY: +Sign Solana Message + +REMARKS: +Sign an arbitrary message with a Solana wallet. Supports both text and hexadecimal message formats with automatic format detection. +**Authentication**: This endpoint requires backend authentication using the x-secret-key header. The secret key should never be exposed publicly. + +RETURNS: +Message signed successfully. Returns the base58 signature. + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.SignSolanaTransactionAsync(Thirdweb.Api.Body23) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - param1 (Thirdweb.Api.Body23) + +SUMMARY: +Sign Solana Transaction + +REMARKS: +Sign a Solana transaction using a server wallet without broadcasting it. Provide either a serialized transaction or the instructions to assemble one, along with execution options. +**Authentication**: This endpoint requires backend authentication using the x-secret-key header. Optionally, include x-vault-access-token if your wallet is managed via Vault. + +RETURNS: +Transaction signed successfully. Returns the signature and the fully signed transaction payload. + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.SignSolanaTransactionAsync(Thirdweb.Api.Body23,System.Threading.CancellationToken) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - cancellationToken (Thirdweb.Api.Body23) + A cancellation token that can be used by other objects or threads to receive notice of cancellation. + - param2 (System.Threading.CancellationToken) + +SUMMARY: +Sign Solana Transaction + +REMARKS: +Sign a Solana transaction using a server wallet without broadcasting it. Provide either a serialized transaction or the instructions to assemble one, along with execution options. +**Authentication**: This endpoint requires backend authentication using the x-secret-key header. Optionally, include x-vault-access-token if your wallet is managed via Vault. + +RETURNS: +Transaction signed successfully. Returns the signature and the fully signed transaction payload. + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.BroadcastSolanaTransactionAsync(Thirdweb.Api.Body24) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - param1 (Thirdweb.Api.Body24) + +SUMMARY: +Broadcast Signed Solana Transaction + +REMARKS: +Broadcast a signed Solana transaction to the network and wait for confirmation. This endpoint accepts a base64 encoded signed transaction (such as the output from /v1/solana/sign-transaction), submits it to the Solana blockchain, and polls until the transaction is confirmed (up to 30 seconds). +The endpoint waits for the transaction to reach 'confirmed' or 'finalized' status before returning. If the transaction fails on-chain, detailed error information is returned including instruction index, error type, and the transaction signature for debugging. +**Authentication**: This endpoint requires backend authentication using the x-secret-key header. + +RETURNS: +Transaction broadcast and confirmed successfully. Returns the transaction signature (equivalent to EVM transaction hash). + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.BroadcastSolanaTransactionAsync(Thirdweb.Api.Body24,System.Threading.CancellationToken) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - cancellationToken (Thirdweb.Api.Body24) + A cancellation token that can be used by other objects or threads to receive notice of cancellation. + - param2 (System.Threading.CancellationToken) + +SUMMARY: +Broadcast Signed Solana Transaction + +REMARKS: +Broadcast a signed Solana transaction to the network and wait for confirmation. This endpoint accepts a base64 encoded signed transaction (such as the output from /v1/solana/sign-transaction), submits it to the Solana blockchain, and polls until the transaction is confirmed (up to 30 seconds). +The endpoint waits for the transaction to reach 'confirmed' or 'finalized' status before returning. If the transaction fails on-chain, detailed error information is returned including instruction index, error type, and the transaction signature for debugging. +**Authentication**: This endpoint requires backend authentication using the x-secret-key header. + +RETURNS: +Transaction broadcast and confirmed successfully. Returns the transaction signature (equivalent to EVM transaction hash). + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.SendSolanaTokensAsync(Thirdweb.Api.Body25) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - param1 (Thirdweb.Api.Body25) + +SUMMARY: +Send Solana Tokens + +REMARKS: +Transfer native SOL or SPL tokens on Solana. Automatically handles token account creation for SPL tokens if needed. +**Authentication**: This endpoint requires backend authentication using the x-secret-key header. The secret key should never be exposed publicly. + +RETURNS: +Transfer queued successfully. Returns the transaction identifier for status polling. + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.SendSolanaTokensAsync(Thirdweb.Api.Body25,System.Threading.CancellationToken) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - cancellationToken (Thirdweb.Api.Body25) + A cancellation token that can be used by other objects or threads to receive notice of cancellation. + - param2 (System.Threading.CancellationToken) + +SUMMARY: +Send Solana Tokens + +REMARKS: +Transfer native SOL or SPL tokens on Solana. Automatically handles token account creation for SPL tokens if needed. +**Authentication**: This endpoint requires backend authentication using the x-secret-key header. The secret key should never be exposed publicly. + +RETURNS: +Transfer queued successfully. Returns the transaction identifier for status polling. + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.SendSolanaTransactionAsync(Thirdweb.Api.Body26) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - param1 (Thirdweb.Api.Body26) + +SUMMARY: +Send Solana Transaction + +REMARKS: +Submit a Solana transaction composed of one or more instructions. Transactions are queued and processed asynchronously. +**Authentication**: This endpoint requires backend authentication using the x-secret-key header. The secret key should never be exposed publicly. + +RETURNS: +Transaction queued successfully. Returns the transaction identifier for status polling. + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.SendSolanaTransactionAsync(Thirdweb.Api.Body26,System.Threading.CancellationToken) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - cancellationToken (Thirdweb.Api.Body26) + A cancellation token that can be used by other objects or threads to receive notice of cancellation. + - param2 (System.Threading.CancellationToken) + +SUMMARY: +Send Solana Transaction + +REMARKS: +Submit a Solana transaction composed of one or more instructions. Transactions are queued and processed asynchronously. +**Authentication**: This endpoint requires backend authentication using the x-secret-key header. The secret key should never be exposed publicly. + +RETURNS: +Transaction queued successfully. Returns the transaction identifier for status polling. + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.GetSwapQuoteAsync(System.String,System.String,System.String,System.String,System.String) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - address (string) + Solana wallet address that will execute the swap. + - tokenIn (string) + Input token mint address (the token being sold). + - tokenOut (string) + Output token mint address (the token being purchased). + - amount (string) + Amount of input token to swap, expressed in the smallest unit (e.g., lamports for SOL). + - param5 (string) + +SUMMARY: +Get Solana Swap Quote + +REMARKS: +Get a quote for swapping tokens on Solana. This endpoint returns the expected output amount and swap details without executing the transaction. +**Important**: Swaps are only available on Solana mainnet. +**Authentication**: This endpoint requires backend authentication using the x-secret-key header. + +RETURNS: +Quote fetched successfully. Returns expected output amount and swap details. + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.GetSwapQuoteAsync(System.String,System.String,System.String,System.String,System.String,System.Threading.CancellationToken) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - cancellationToken (string) + A cancellation token that can be used by other objects or threads to receive notice of cancellation. + - address (string) + Solana wallet address that will execute the swap. + - tokenIn (string) + Input token mint address (the token being sold). + - tokenOut (string) + Output token mint address (the token being purchased). + - amount (string) + Amount of input token to swap, expressed in the smallest unit (e.g., lamports for SOL). + - param6 (System.Threading.CancellationToken) + +SUMMARY: +Get Solana Swap Quote + +REMARKS: +Get a quote for swapping tokens on Solana. This endpoint returns the expected output amount and swap details without executing the transaction. +**Important**: Swaps are only available on Solana mainnet. +**Authentication**: This endpoint requires backend authentication using the x-secret-key header. + +RETURNS: +Quote fetched successfully. Returns expected output amount and swap details. + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.SwapSolanaTokensAsync(Thirdweb.Api.Body27) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - param1 (Thirdweb.Api.Body27) + +SUMMARY: +Swap Solana Tokens + +REMARKS: +Execute a token swap on Solana. This endpoint handles the full swap flow: fetching the optimal swap route, signing the transaction with your server wallet, executing the swap, and polling until confirmation. +The swap uses aggregated liquidity across Solana DEXs to provide optimal routing. The endpoint waits for the transaction to reach 'confirmed' or 'finalized' status before returning (up to 30 seconds). +**Important**: Swaps are only available on Solana mainnet. +**Authentication**: This endpoint requires backend authentication using the x-secret-key header. + +RETURNS: +Swap executed and confirmed successfully. Returns the transaction signature and swap details including input/output amounts. + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.SwapSolanaTokensAsync(Thirdweb.Api.Body27,System.Threading.CancellationToken) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - cancellationToken (Thirdweb.Api.Body27) + A cancellation token that can be used by other objects or threads to receive notice of cancellation. + - param2 (System.Threading.CancellationToken) + +SUMMARY: +Swap Solana Tokens + +REMARKS: +Execute a token swap on Solana. This endpoint handles the full swap flow: fetching the optimal swap route, signing the transaction with your server wallet, executing the swap, and polling until confirmation. +The swap uses aggregated liquidity across Solana DEXs to provide optimal routing. The endpoint waits for the transaction to reach 'confirmed' or 'finalized' status before returning (up to 30 seconds). +**Important**: Swaps are only available on Solana mainnet. +**Authentication**: This endpoint requires backend authentication using the x-secret-key header. + +RETURNS: +Swap executed and confirmed successfully. Returns the transaction signature and swap details including input/output amounts. + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.GetSolanaTransactionAsync(System.String) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - transactionId (string) + Identifier returned when the transaction was queued. + +SUMMARY: +Get Solana Transaction + +REMARKS: +Retrieve the status and details of a queued Solana transaction using the identifier returned when the transaction was submitted. +**Authentication**: This endpoint requires backend authentication using the x-secret-key header. The secret key should never be exposed publicly. + +RETURNS: +Transaction status retrieved successfully. + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.GetSolanaTransactionAsync(System.String,System.Threading.CancellationToken) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - cancellationToken (string) + A cancellation token that can be used by other objects or threads to receive notice of cancellation. + - transactionId (System.Threading.CancellationToken) + Identifier returned when the transaction was queued. + +SUMMARY: +Get Solana Transaction + +REMARKS: +Retrieve the status and details of a queued Solana transaction using the identifier returned when the transaction was submitted. +**Authentication**: This endpoint requires backend authentication using the x-secret-key header. The secret key should never be exposed publicly. + +RETURNS: +Transaction status retrieved successfully. + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.ChatAsync(Thirdweb.Api.Body28) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - param1 (Thirdweb.Api.Body28) + +SUMMARY: +Chat + +REMARKS: +Thirdweb AI chat completion API (BETA). +Send natural language queries to interact with any EVM chain, read data, prepare transactions, swap tokens, deploy contracts, payments and more. +Compatible with standard OpenAI API chat completion format, can be used raw or with any popular AI library. +**Authentication**: Pass `x-client-id` header for frontend usage from allowlisted origins or `x-secret-key` for backend usage. + +RETURNS: +AI assistant response or SSE stream when stream=true + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.ChatAsync(Thirdweb.Api.Body28,System.Threading.CancellationToken) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - cancellationToken (Thirdweb.Api.Body28) + A cancellation token that can be used by other objects or threads to receive notice of cancellation. + - param2 (System.Threading.CancellationToken) + +SUMMARY: +Chat + +REMARKS: +Thirdweb AI chat completion API (BETA). +Send natural language queries to interact with any EVM chain, read data, prepare transactions, swap tokens, deploy contracts, payments and more. +Compatible with standard OpenAI API chat completion format, can be used raw or with any popular AI library. +**Authentication**: Pass `x-client-id` header for frontend usage from allowlisted origins or `x-secret-key` for backend usage. + +RETURNS: +AI assistant response or SSE stream when stream=true + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body.Method +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Authentication method: SMS + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body.Phone +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Phone number in E.164 format (e.g., +1234567890) + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body2.Method +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Authentication method: SMS + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body2.Phone +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Phone number that received the code + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body2.Code +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Verification code received via SMS + +-------------------------------------------------------------------------------- +T:Thirdweb.Api.Body3 +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Request body for linking an additional authentication method or external wallet to the currently authenticated user. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body3.AccountAuthTokenToConnect +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Authentication token for the account that should be linked to the currently authenticated wallet. + +-------------------------------------------------------------------------------- +T:Thirdweb.Api.Body4 +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Request body for unlinking an authentication provider or wallet from the currently authenticated user. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body4.Type +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Authentication provider type to disconnect + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body4.Details +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Identifiers for the provider profile that should be disconnected + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body4.AllowAccountDeletion +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +If true, allows the account to be deleted when unlinking removes the last authentication method. Defaults to false when omitted. + +-------------------------------------------------------------------------------- +T:Thirdweb.Api.Provider +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +The OAuth provider to use + +-------------------------------------------------------------------------------- +T:Thirdweb.Api.Body5 +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Request body for pre-generating a wallet + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body5.WalletAddress +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +A valid Ethereum address (0x-prefixed hex string) or ENS name (e.g., vitalik.eth). + +-------------------------------------------------------------------------------- +T:Thirdweb.Api.Body6 +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Request body for creating a wallet + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body6.Identifier +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Unique identifier for wallet creation or retrieval. Can be user ID, email, or any unique string. The same identifier will always return the same wallet. + +-------------------------------------------------------------------------------- +T:Thirdweb.Api.SortOrder +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Sort order: 'asc' for ascending, 'desc' for descending + +-------------------------------------------------------------------------------- +T:Thirdweb.Api.Metadata +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Whether to include token metadata (default: true). + +-------------------------------------------------------------------------------- +T:Thirdweb.Api.ResolveMetadataLinks +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Whether to resolve metadata links to fetch additional token information (default: true). + +-------------------------------------------------------------------------------- +T:Thirdweb.Api.IncludeSpam +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Whether to include tokens marked as spam (default: false). + +-------------------------------------------------------------------------------- +T:Thirdweb.Api.IncludeNative +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Whether to include native tokens (e.g., ETH, MATIC) in the results (default: true). + +-------------------------------------------------------------------------------- +T:Thirdweb.Api.SortBy +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Field to sort tokens by: 'balance' for token balance, 'token_address' for token address, 'token_price' for token price, 'usd_value' for USD value (default: usd_value). + +-------------------------------------------------------------------------------- +T:Thirdweb.Api.SortOrder2 +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Sort order: 'asc' for ascending, 'desc' for descending (default: desc). + +-------------------------------------------------------------------------------- +T:Thirdweb.Api.IncludeWithoutPrice +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Whether to include tokens without price data (default: true). + +-------------------------------------------------------------------------------- +T:Thirdweb.Api.Body7 +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Request body for signing a message + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body7.From +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The wallet address or ENS name that will sign the message. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body7.ChainId +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The blockchain network identifier where the signing will occur. Common values include: 1 (Ethereum), 137 (Polygon), 56 (BSC). + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body7.Message +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The message to be signed. Can be plain text or hexadecimal format (starting with 0x). The format is automatically detected. + +-------------------------------------------------------------------------------- +T:Thirdweb.Api.Body8 +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Request body for signing typed data + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body8.From +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The wallet address or ENS name that will sign the typed data. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body8.ChainId +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The blockchain network identifier for EIP-712 domain separation. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body8.Domain +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +EIP-712 domain separator containing contract and chain information for signature verification. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body8.Message +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The structured data to be signed, matching the defined types schema. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body8.PrimaryType +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The primary type name from the types object that defines the main structure being signed. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body8.Types +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Type definitions for the structured data, following EIP-712 specifications. + +-------------------------------------------------------------------------------- +T:Thirdweb.Api.Body9 +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Request body for sending tokens to multiple recipients. Supports native tokens, ERC20, ERC721, and ERC1155 transfers based on the provided parameters. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body9.From +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The wallet address or ENS name that will send the tokens. If omitted, the project wallet will be used if available. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body9.ChainId +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The blockchain network identifier where the transfer will be executed. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body9.Recipients +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Array of recipients and quantities. Maximum 100 recipients per request. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body9.TokenAddress +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The token contract address. Omit for native token (ETH, MATIC, etc.) transfers. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body9.TokenId +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The token ID for NFT transfers (ERC721/ERC1155). Required for NFT transfers. + +-------------------------------------------------------------------------------- +T:Thirdweb.Api.Body10 +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Contract deployment specification for raw bytecode deployment. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body10.ChainId +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The blockchain network identifier. Common values include: 1 (Ethereum), 8453 (Base), 137 (Polygon), 56 (BSC), 43114 (Avalanche), 42161 (Arbitrum), 10 (Optimism). + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body10.From +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The wallet address or ENS name that will deploy the contract. If omitted, the project wallet will be used if available. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body10.Bytecode +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The contract bytecode as a hex string. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body10.Abi +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The contract ABI array. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body10.ConstructorParams +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Object containing constructor parameters for the contract deployment (e.g., { param1: 'value1', param2: 123 }). + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body10.Salt +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Optional salt value for deterministic contract deployment. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body11.Calls +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Array of contract method calls to execute. Each call specifies a contract address, method signature, and optional parameters. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body11.ChainId +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The blockchain network identifier. Common values include: 1 (Ethereum), 8453 (Base), 137 (Polygon), 56 (BSC), 43114 (Avalanche), 42161 (Arbitrum), 10 (Optimism). + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body12.Calls +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Array of contract method calls to execute. Each call specifies a contract address, method signature, and optional parameters. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body12.ChainId +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The blockchain network identifier. Common values include: 1 (Ethereum), 8453 (Base), 137 (Polygon), 56 (BSC), 43114 (Avalanche), 42161 (Arbitrum), 10 (Optimism). + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body12.From +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The wallet address or ENS name that will send the transaction. If omitted, the project wallet will be used if available. + +-------------------------------------------------------------------------------- +T:Thirdweb.Api.SortOrder3 +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Sort order: 'asc' for ascending, 'desc' for descending + +-------------------------------------------------------------------------------- +T:Thirdweb.Api.SortOrder4 +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Sort order: 'asc' for ascending, 'desc' for descending + +-------------------------------------------------------------------------------- +T:Thirdweb.Api.Body13 +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Request object containing an array of encoded blockchain transactions to execute. All transactions must use the same from address and chainId. For contract calls, use /v1/contracts/write. For native token transfers, use /v1/wallets/send. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body13.ChainId +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The blockchain network identifier where all transactions will be executed. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body13.From +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The wallet address or ENS name that will send the transaction. If omitted, the project wallet will be used if available. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body13.Transactions +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Array of encoded blockchain transactions to execute. All transactions will use the same from address and chainId. + +-------------------------------------------------------------------------------- +T:Thirdweb.Api.Body14 +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Request to create a product to be purchased. Users can purchase the product via hosted UI (link is returned), a transaction execution referencing the product ID, or embedded widgets with the product ID. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body14.Name +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The name of the product + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body14.Description +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The description of the product + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body14.ImageUrl +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The URL of the product image + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body14.Token +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The token to purchase + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body14.Recipient +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The wallet address or ENS name that will receive the payment for the product + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body14.PurchaseData +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +App specific purchase data for this payment + +-------------------------------------------------------------------------------- +T:Thirdweb.Api.Body15 +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Request to purchase a product. The system will automatically use your wallet balance to purchase the specified product. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body15.From +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The wallet address or ENS name that will purchase the product. If omitted, the project wallet will be used if available. + +-------------------------------------------------------------------------------- +T:Thirdweb.Api.Body16 +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Request body for x402 facilitator 'verify' + +-------------------------------------------------------------------------------- +T:Thirdweb.Api.Body17 +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Request body for x402 facilitator 'settle' + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body17.PaymentPayload +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Exact x402 payment payload to settle + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body17.WaitUntil +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The event to wait for to determina a transaction confirmation. 'simulated' will only simulate the transaction (fastest), 'submitted' will wait till the transaction is submitted, and 'confirmed' will wait for the transaction to be fully confirmed on chain (slowest). Defaults to 'confirmed'. + +-------------------------------------------------------------------------------- +T:Thirdweb.Api.ChainId +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Chain ID in CAIP-2 format (e.g., 'eip155:1' for Ethereum, 'solana:mainnet' for Solana). Also accepts legacy numeric IDs for EVM chains. + +-------------------------------------------------------------------------------- +T:Thirdweb.Api.Method +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +The method to use, defaults to GET + +-------------------------------------------------------------------------------- +T:Thirdweb.Api.ChainId2 +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Chain ID to use for the payment. Supports CAIP-2 strings (e.g., 'eip155:1', 'solana:mainnet') or legacy numeric EVM IDs. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body18.ResourceUrl +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The URL of the resource being protected by the payment + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body18.Method +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The HTTP method used to access the resource + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body18.Network +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The blockchain network where the payment should be processed + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body18.Price +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The price for accessing the resource - either a USD amount (e.g., '$0.10') or a specific token amount + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body18.RouteConfig +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Optional configuration for the payment middleware route + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body18.ServerWalletAddress +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Your server wallet address, defaults to the project server wallet address + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body18.RecipientAddress +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Optional recipient address to receive the payment if different from your facilitator server wallet address + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body18.ExtraMetadata +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Optional extra data to be passed to in the payment requirements. + +-------------------------------------------------------------------------------- +T:Thirdweb.Api.Body19 +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Request schema for creating a new ERC20 token + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body19.ChainId +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The blockchain network identifier. Common values include: 1 (Ethereum), 8453 (Base), 137 (Polygon), 56 (BSC), 43114 (Avalanche), 42161 (Arbitrum), 10 (Optimism). + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body19.Name +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Token name + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body19.Symbol +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Token symbol + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body19.Description +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Token description + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body19.ImageUrl +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Token image URL + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body19.From +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Wallet address or ENS that will deploy the token. If omitted, the project wallet will be used if available. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body19.Owner +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The token owner address, if different from `from`. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body19.Salt +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +A salt to deterministically generate the token address. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body19.MaxSupply +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The maximum token supply. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body19.Sale +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Setup this token for a sale. + +-------------------------------------------------------------------------------- +T:Thirdweb.Api.From +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +The fiat currency symbol + +-------------------------------------------------------------------------------- +T:Thirdweb.Api.Body20 +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Request to swap tokens using the optimal route available. You can specify a tokenIn amount (if exact='input') or tokenOut amount (if exact='output'), but not both. The corresponding output or input amount will be returned as the quote. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body20.Exact +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Whether to swap the exact input or output amount + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body20.From +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The wallet address or ENS name that will execute the swap. If omitted, the project wallet will be used if available. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body20.SlippageToleranceBps +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The slippage tolerance in basis points. Will be automatically calculated by default. + +-------------------------------------------------------------------------------- +T:Thirdweb.Api.Body21 +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Request payload for creating or fetching a Solana wallet by label. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body21.Label +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Unique label to identify the wallet. Used for retrieval and management. + +-------------------------------------------------------------------------------- +T:Thirdweb.Api.Body22 +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Request payload for signing an arbitrary Solana message. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body22.From +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The Solana wallet address used for signing. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body22.Message +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Message to sign. Can be plain text or hexadecimal format (starting with 0x). The format is automatically detected. + +-------------------------------------------------------------------------------- +T:Thirdweb.Api.Body23 +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Request payload for signing a Solana transaction. Provide a serialized transaction or a set of instructions to be assembled server-side. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body23.From +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The Solana wallet address that will sign the transaction. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body23.ChainId +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Solana network the transaction targets. Use solana:mainnet or solana:devnet. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body23.Transaction +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Base64 encoded Solana transaction to sign. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body23.Instructions +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Instructions that will be assembled into a transaction before signing. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body23.PriorityFee +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Priority fee configuration applied via the compute budget program. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body23.ComputeUnitLimit +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Override the compute unit limit for the transaction via the compute budget program. + +-------------------------------------------------------------------------------- +T:Thirdweb.Api.Body24 +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Request payload for broadcasting a signed Solana transaction. Use the signedTransaction output from /v1/solana/sign-transaction. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body24.ChainId +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Solana network the signed transaction targets. Use solana:mainnet or solana:devnet. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body24.SignedTransaction +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Base64 encoded signed transaction to broadcast to the Solana network. + +-------------------------------------------------------------------------------- +T:Thirdweb.Api.Body25 +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Request payload for transferring SOL or SPL tokens on Solana. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body25.From +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Solana wallet address that will sign and submit the transfer. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body25.To +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Destination Solana address. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body25.Amount +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Amount to transfer expressed in base units (lamports for SOL or token decimals). + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body25.ChainId +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Solana network identifier in CAIP-2 format. Use "solana:mainnet" or "solana:devnet" for convenience, or full CAIP-2 format. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body25.TokenAddress +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Optional SPL token mint address. When omitted a native SOL transfer is performed. + +-------------------------------------------------------------------------------- +T:Thirdweb.Api.Body26 +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Submit a Solana transaction made up of one or more instructions. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body26.From +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Solana wallet address that will sign and submit the transaction. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body26.ChainId +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Solana network identifier in CAIP-2 format. Use "solana:mainnet" or "solana:devnet" for convenience, or full CAIP-2 format. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body26.Instructions +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Set of instructions executed sequentially in a single transaction. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body26.PriorityFee +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Priority fee configuration applied via the compute budget program. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body26.ComputeUnitLimit +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Override the compute unit limit via the compute budget program. + +-------------------------------------------------------------------------------- +T:Thirdweb.Api.Body27 +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Request payload for executing a token swap on Solana. The endpoint handles swap routing, transaction signing, execution, and confirmation polling. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body27.Address +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Solana wallet address that will execute the swap. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body27.TokenIn +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Input token mint address (the token being sold). + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body27.TokenOut +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Output token mint address (the token being purchased). + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body27.Amount +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Amount of input token to swap, expressed in the smallest unit (e.g., lamports for SOL). + +-------------------------------------------------------------------------------- +T:Thirdweb.Api.Body28 +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Chat request + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body28.Messages +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Natural language query for the AI assistant + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body28.Context +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Context for the AI assistant + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body28.Stream +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Enable server streaming of the AI response + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Response.Method +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Authentication method: SMS + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Response.Success +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Whether the SMS code was sent successfully + +-------------------------------------------------------------------------------- +T:Thirdweb.Api.Response2 +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Successful authentication response. Returns wallet address plus authentication tokens. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Response2.IsNewUser +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Whether this is a newly created user/wallet + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Response2.Token +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +JWT authentication token for API access + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Response2.Type +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Type of authentication completed + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Response2.UserId +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Unique identifier for the authenticated user + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Response2.WalletAddress +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The wallet address + +-------------------------------------------------------------------------------- +T:Thirdweb.Api.Response3 +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Response returned after successfully linking an additional authentication provider. The response includes all linked profiles for the user. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Response3.LinkedAccounts +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Updated list of authentication profiles linked to the wallet after the new account has been connected. + +-------------------------------------------------------------------------------- +T:Thirdweb.Api.Response4 +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Response returned after successfully linking an additional authentication provider. The response includes all linked profiles for the user. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Response4.LinkedAccounts +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Updated list of authentication profiles linked to the wallet after the new account has been connected. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Response19.Result +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Array of results corresponding to each contract read call. Results are returned in the same order as the input calls. + +-------------------------------------------------------------------------------- +T:Thirdweb.Api.Response21 +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Payment required response when user has insufficient funds. Contains a quote for completing the purchase. + +-------------------------------------------------------------------------------- +T:Thirdweb.Api.Response24 +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Contract metadata from the thirdweb contract metadata service. + +-------------------------------------------------------------------------------- +T:Thirdweb.Api.Response25 +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Contract ABI signatures in human-readable format. These signatures can be used directly with contract interaction methods. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Response25.Result +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Array of human-readable ABI signatures including functions and events. Each signature is formatted as a string that can be used directly in contract read/write operations or event filtering. + +-------------------------------------------------------------------------------- +T:Thirdweb.Api.Response29 +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Payment required response when user has insufficient funds. Contains a quote for completing the purchase. + +-------------------------------------------------------------------------------- +T:Thirdweb.Api.Response30 +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Successful payment creation response containing the payment ID and link to purchase the product + +-------------------------------------------------------------------------------- +T:Thirdweb.Api.Response32 +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Payment required response when user has insufficient funds. Contains a quote for completing the purchase. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Response33.Data +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +List of payments for the client + +-------------------------------------------------------------------------------- +T:Thirdweb.Api.Response36 +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Response returned by x402 facilitator 'verify' + +-------------------------------------------------------------------------------- +T:Thirdweb.Api.Response37 +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Response returned by x402 facilitator 'settle' + +-------------------------------------------------------------------------------- +T:Thirdweb.Api.Response38 +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Supported payment kinds for this facilitator + +-------------------------------------------------------------------------------- +T:Thirdweb.Api.Response39 +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Payment required response when user has insufficient funds. Contains a quote for completing the purchase. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Response43.TransactionId +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The in-progress deployment transaction ID. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Response43.Address +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The address the token was deployed at + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Response46.Result +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Blockchain networks that support cross-chain bridging + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Response48.Result +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The conversion result - amount of crypto tokens for the fiat amount + +-------------------------------------------------------------------------------- +T:Thirdweb.Api.Response49 +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Successful token swap response containing executed transaction ID + +-------------------------------------------------------------------------------- +T:Thirdweb.Api.Response50 +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Payment required response when user has insufficient funds. Contains a quote for completing the purchase. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Response52.Result +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Details for a Solana wallet in your project. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Response53.Result +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Details for a Solana wallet in your project. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Response54.Result +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Balance data for the requested Solana network. + +-------------------------------------------------------------------------------- +T:Thirdweb.Api.Response62 +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Response containing the swap quote details. + +-------------------------------------------------------------------------------- +T:Thirdweb.Api.Response63 +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Response containing the confirmed swap transaction signature and swap details. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Response64.Result +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Transaction metadata and status information. + +-------------------------------------------------------------------------------- +T:Thirdweb.Api.Response65 +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Chat response + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Response65.Message +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The AI assistant's response + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Details.WalletAddress +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +A valid Ethereum address (0x-prefixed hex string) or ENS name (e.g., vitalik.eth). + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Domain.ChainId +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Chain ID as string for domain separation + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Domain.Name +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The domain name (e.g., token name) + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Domain.Salt +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Optional salt for additional entropy + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Domain.VerifyingContract +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The contract address that will verify this signature + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Domain.Version +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Domain version for signature compatibility + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Anonymous.Name +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The field name + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Anonymous.Type +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The Solidity type (e.g., 'address', 'uint256') + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Recipients.Address +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The recipient wallet address or ENS name + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Recipients.Quantity +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The amount to send. For native tokens and ERC20: amount in wei/smallest unit. For ERC721: should be '1'. For ERC1155: the number of tokens to transfer. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Calls.ContractAddress +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The smart contract address or ENS name. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Calls.Method +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The contract function signature to call (e.g., 'function approve(address spender, uint256 amount)' or `function balanceOf(address)`). Must start with 'function' followed by the function name and parameters as defined in the contract ABI. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Calls.Params +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Array of parameters to pass to the contract method, in the correct order and format. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Calls.Value +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Amount of native token to send with the transaction in wei. Required for payable methods. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.calls.ContractAddress +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The smart contract address or ENS name. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.calls.Method +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The contract function signature to call (e.g., 'function approve(address spender, uint256 amount)' or `function balanceOf(address)`). Must start with 'function' followed by the function name and parameters as defined in the contract ABI. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.calls.Params +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Array of parameters to pass to the contract method, in the correct order and format. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.calls.Value +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Amount of native token to send with the transaction in wei. Required for payable methods. + +-------------------------------------------------------------------------------- +T:Thirdweb.Api.Transactions +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +A blockchain transaction with pre-encoded data payload. For contract calls, use /v1/contracts/write. For native token transfers, use /v1/wallets/send. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Transactions.Data +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Transaction data in hexadecimal format for contract interactions or custom payloads. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Transactions.To +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The target address or ENS name for the transaction. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Transactions.Value +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Amount of native token to send in wei (smallest unit). Use '0' or omit for non-value transactions. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Token.Address +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The token address to purchase (use 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE for native token) + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Token.ChainId +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The blockchain network where the token is located + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Token.Amount +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The amount of the token to purchase in wei. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.PaymentPayload.Network +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +CAIP-2 blockchain identifier (e.g., 'eip155:1' for Ethereum, 'solana:4sGjMW1sUnHzSxGspuhpqLDx6wiyjNtZ' for Solana mainnet). Also accepts numeric EVM chain IDs (e.g., 1, 137) or aliases ('solana:mainnet', 'solana:devnet') for backward compatibility. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.PaymentRequirements.Network +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +CAIP-2 blockchain identifier (e.g., 'eip155:1' for Ethereum, 'solana:4sGjMW1sUnHzSxGspuhpqLDx6wiyjNtZ' for Solana mainnet). Also accepts numeric EVM chain IDs (e.g., 1, 137) or aliases ('solana:mainnet', 'solana:devnet') for backward compatibility. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.PaymentRequirements2.Network +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +CAIP-2 blockchain identifier (e.g., 'eip155:1' for Ethereum, 'solana:4sGjMW1sUnHzSxGspuhpqLDx6wiyjNtZ' for Solana mainnet). Also accepts numeric EVM chain IDs (e.g., 1, 137) or aliases ('solana:mainnet', 'solana:devnet') for backward compatibility. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Sale.StartingPrice +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The initial token price in wei. This price is in the currency specified by `currency` (or the native token if not specified). + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Sale.Amount +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The number of tokens to allocate to the sale. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Sale.DeveloperFeeBps +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The bps fee on the token pool. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Sale.DeveloperFeeRecipient +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The address to send the developer fee to. Defaults to the token owner. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Sale.Currency +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The currency to price this token sale in. Defaults to the native token. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.TokenIn.Address +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The input token address to swap (use 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE for native token) + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.TokenIn.ChainId +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The blockchain network where the token is located + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.TokenIn.Amount +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The amount of the input token to swap in wei. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.TokenIn.MaxAmount +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The maximum amount of the input token to swap in wei. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.TokenOut.Address +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The output token address to swap (use 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE for native token) + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.TokenOut.ChainId +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The blockchain network where the token is located + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.TokenOut.Amount +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The amount of the output token to receive in wei. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.TokenOut.MinAmount +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The minimum amount of the output token to receive in wei. + +-------------------------------------------------------------------------------- +T:Thirdweb.Api.Instructions +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Single Solana instruction that will be included in a transaction. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Instructions.ProgramId +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Program address to invoke for this instruction. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Instructions.Accounts +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Ordered list of accounts consumed by the instruction. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Instructions.Data +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Instruction data encoded using the provided encoding. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Instructions.Encoding +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Encoding used for the instruction data payload. + +-------------------------------------------------------------------------------- +T:Thirdweb.Api.instructions +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Single Solana instruction that will be included in a transaction. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.instructions.ProgramId +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Program address to invoke for this instruction. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.instructions.Accounts +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Ordered list of accounts consumed by the instruction. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.instructions.Data +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Instruction data encoded using the provided encoding. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.instructions.Encoding +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Encoding used for the instruction data payload. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Context.From +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Optional wallet address that will execute transactions + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Context.Chain_ids +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Optional chain IDs for context + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Context.Session_id +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Optional session ID for conversation continuity. If not provided, a new session will be created + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Context.Auto_execute_transactions +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Whether to automatically execute transactions. If not provided, the default is false + +-------------------------------------------------------------------------------- +T:Thirdweb.Api.LinkedAccounts +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Authentication provider details with type-based discrimination + +-------------------------------------------------------------------------------- +T:Thirdweb.Api.linkedAccounts +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Authentication provider details with type-based discrimination + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result.UserId +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Unique identifier for the user wallet within the thirdweb auth system. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result.Address +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The EOA (Externally Owned Wallet) address of the wallet. This is the traditional wallet address. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result.CreatedAt +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The date and time the wallet was created + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result.Profiles +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The profiles linked to the wallet, can be email, phone, google etc, or backend for developer created wallets + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result.SmartWalletAddress +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The smart wallet address with EIP-4337 support. This address enables gasless transactions and advanced wallet features. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result.PublicKey +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The wallet's public key in hexadecimal format. Useful for peer-to-peer encryption and cryptographic operations. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result2.Pagination +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Pagination information + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result2.Wallets +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Array of user wallets + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result3.UserId +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Unique identifier for the user wallet within the thirdweb auth system. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result3.Address +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The EOA (Externally Owned Wallet) address of the wallet. This is the traditional wallet address. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result3.CreatedAt +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The date and time the wallet was created + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result3.Profiles +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The profiles linked to the wallet, can be email, phone, google etc, or backend for developer created wallets + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result3.SmartWalletAddress +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The smart wallet address with EIP-4337 support. This address enables gasless transactions and advanced wallet features. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result3.PublicKey +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The wallet's public key in hexadecimal format. Useful for peer-to-peer encryption and cryptographic operations. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result4.Pagination +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Pagination information + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result4.Wallets +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Array of server wallets + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result5.UserId +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Unique identifier for the user wallet within the thirdweb auth system. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result5.Address +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The EOA (Externally Owned Wallet) address of the wallet. This is the traditional wallet address. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result5.CreatedAt +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The date and time the wallet was created + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result5.Profiles +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The profiles linked to the wallet, can be email, phone, google etc, or backend for developer created wallets + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result5.SmartWalletAddress +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The smart wallet address with EIP-4337 support. This address enables gasless transactions and advanced wallet features. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result5.PublicKey +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The wallet's public key in hexadecimal format. Useful for peer-to-peer encryption and cryptographic operations. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.result.ChainId +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The blockchain network ID + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.result.Decimals +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Number of decimal places for the token + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.result.DisplayValue +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Human-readable balance formatted with appropriate decimal places + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.result.Name +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The token name (e.g., 'Ether', 'USD Coin') + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.result.Symbol +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The token symbol (e.g., 'ETH', 'USDC') + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.result.TokenAddress +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The token contract address. Returns zero address (0x0...0) for native tokens. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.result.Value +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Raw balance value as string in smallest unit (wei for ETH, etc.) + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result6.Transactions +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Array of wallet transactions. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result7.Tokens +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Array of wallet tokens. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result8.Nfts +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Array of wallet NFTs. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result9.Signature +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The cryptographic signature in hexadecimal format. This can be used for verification and authentication purposes. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result10.Signature +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The cryptographic signature in hexadecimal format. This can be used for verification and authentication purposes. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result11.TransactionIds +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Array of transaction IDs for the submitted transfers. One ID per recipient. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result12.Contracts +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Array of contracts imported by the client. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result13.Address +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The deployed contract address. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result13.ChainId +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The chain ID where the contract was deployed. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result13.TransactionId +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The unique identifier for the transaction that deployed the contract. Will not be returned if the contract was already deployed at the predicted address. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result14.Data +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The result of the contract read operation. The type and format depend on the method's return value as defined in the contract ABI. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result14.Error +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Error message if the contract read operation failed. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result14.Success +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Indicates whether the contract read operation was successful. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result15.TransactionIds +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Array of unique identifiers for the submitted transactions. Use these to track transaction status. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result16.Message +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Message to display to the user + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result16.Link +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Link to purchase the product + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result16.Id +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Payment ID + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result16.Quote +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Bridge quote for completing the payment + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result17.Data +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Array of contract transactions. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result18.Events +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Array of contract events. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result19.Compiler +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Compiler information including version. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result19.Language +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Programming language of the contract (e.g., 'Solidity'). + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result19.Output +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Compilation output including ABI and documentation. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result19.Settings +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Compilation settings including optimization and target configuration. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result19.Version +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Metadata format version. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result20.BatchIndex +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Index within transaction batch + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result20.CancelledAt +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +ISO timestamp when transaction was cancelled, if applicable + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result20.ChainId +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Blockchain network identifier as string + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result20.ClientId +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Client identifier that initiated the transaction + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result20.ConfirmedAt +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +ISO timestamp when transaction was confirmed on-chain + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result20.ConfirmedAtBlockNumber +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Block number where transaction was confirmed + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result20.CreatedAt +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +ISO timestamp when transaction was created + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result20.EnrichedData +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Additional metadata and enriched transaction information + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result20.ErrorMessage +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Error message if transaction failed + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result20.ExecutionParams +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Parameters used for transaction execution + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result20.ExecutionResult +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Result data from transaction execution + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result20.From +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Sender wallet address + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result20.Id +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Unique transaction identifier + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result20.TransactionHash +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +On-chain transaction hash once confirmed + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result20.TransactionParams +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Original transaction parameters and data + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result20.Status +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Transaction status + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result22.TransactionIds +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Array of unique identifiers for the submitted transactions. Use these to track transaction status. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result23.Message +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Message to display to the user + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result23.Link +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Link to purchase the product + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result23.Id +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Payment ID + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result23.Quote +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Bridge quote for completing the payment + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result24.Id +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The payment ID + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result24.Link +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The link to purchase the product + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result25.TransactionId +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Transaction ID that was executed for your product purchase + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result26.Message +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Message to display to the user + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result26.Link +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Link to purchase the product + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result26.Id +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Payment ID + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result26.Quote +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Bridge quote for completing the payment + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Data.Sender +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +A valid Ethereum address (0x-prefixed hex string) or ENS name (e.g., vitalik.eth). + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Data.Receiver +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +A valid Ethereum address (0x-prefixed hex string) or ENS name (e.g., vitalik.eth). + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Data.DeveloperFeeRecipient +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +A valid Ethereum address (0x-prefixed hex string) or ENS name (e.g., vitalik.eth). + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Meta.TotalCount +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Total number of payments + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Kinds.Network +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +CAIP-2 blockchain identifier (e.g., 'eip155:1' for Ethereum, 'solana:4sGjMW1sUnHzSxGspuhpqLDx6wiyjNtZ' for Solana mainnet). Also accepts numeric EVM chain IDs (e.g., 1, 137) or aliases ('solana:mainnet', 'solana:devnet') for backward compatibility. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result27.Message +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Message to display to the user + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result27.Link +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Link to purchase the product + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result27.Id +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Payment ID + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result27.Quote +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Bridge quote for completing the payment + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Accepts.Network +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +CAIP-2 blockchain identifier (e.g., 'eip155:1' for Ethereum, 'solana:4sGjMW1sUnHzSxGspuhpqLDx6wiyjNtZ' for Solana mainnet). Also accepts numeric EVM chain IDs (e.g., 1, 137) or aliases ('solana:mainnet', 'solana:devnet') for backward compatibility. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.accepts.Network +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +CAIP-2 blockchain identifier (e.g., 'eip155:1' for Ethereum, 'solana:4sGjMW1sUnHzSxGspuhpqLDx6wiyjNtZ' for Solana mainnet). Also accepts numeric EVM chain IDs (e.g., 1, 137) or aliases ('solana:mainnet', 'solana:devnet') for backward compatibility. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Pagination2.HasMore +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Whether there are more items available + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Pagination2.Limit +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Number of items per page + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Pagination2.Page +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Current page number + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Pagination2.TotalCount +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Total number of items available + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Tokens.ChainId +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The blockchain network identifier. Common values include: 1 (Ethereum), 8453 (Base), 137 (Polygon), 56 (BSC), 43114 (Avalanche), 42161 (Arbitrum), 10 (Optimism). + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Tokens.Address +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +A valid Ethereum address (0x-prefixed hex string) or ENS name (e.g., vitalik.eth). + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Tokens.Prices +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Token price in different FIAT currencies. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result28.Owners +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Array of token owners with amounts. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result29.ChainId +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The chain ID of the chain + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result29.Name +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The name of the chain + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result29.Icon +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The URL of the chain's icon + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result29.NativeCurrency +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Information about the native currency of the chain + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result30.Routes +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Supported bridge routes that match the provided filters. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result30.Pagination +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Pagination details for the returned routes. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result31.TransactionId +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Payment transaction ID that was executed + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result32.Message +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Message to display to the user + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result32.Link +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Link to purchase the product + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result32.Id +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Payment ID + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result32.Quote +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Bridge quote for completing the payment + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result33.Wallets +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Array of Solana wallets created for your project. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result33.Pagination +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Pagination details for the wallet list. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result34.Address +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Base58 encoded Solana address. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result34.Label +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Optional label associated with the wallet. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result34.CreatedAt +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +ISO 8601 timestamp indicating when the wallet was created. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result34.UpdatedAt +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +ISO 8601 timestamp indicating when the wallet was last updated. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result35.Address +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Base58 encoded Solana address. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result35.Label +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Optional label associated with the wallet. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result35.CreatedAt +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +ISO 8601 timestamp indicating when the wallet was created. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result35.UpdatedAt +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +ISO 8601 timestamp indicating when the wallet was last updated. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result36.ChainId +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Requested Solana network. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result36.Decimals +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Number of decimals used by the token. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result36.DisplayValue +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Human-readable balance formatted using token decimals. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result36.Value +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Raw balance value expressed in base units (lamports). + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result37.Signature +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Base58 encoded signature returned from the signer. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result38.Signature +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Base58 encoded signature for the provided transaction. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result38.SignedTransaction +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Base64 encoded signed transaction that can be broadcast to the Solana network. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result39.Signature +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Transaction signature returned by the Solana network. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result40.TransactionId +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Idempotency key assigned to the queued transaction. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result41.TransactionId +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Idempotency key assigned to the queued transaction. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result42.TransactionId +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Idempotency key assigned to the queued transaction. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result43.TransactionId +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Idempotency key assigned to the queued transaction. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result44.InputMint +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Input token mint address. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result44.OutputMint +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Output token mint address. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result44.InputAmount +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Amount of input token to swap. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result44.OutputAmount +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Expected amount of output token to receive. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result44.InputUsdValue +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +USD value of the input amount. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result44.OutputUsdValue +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +USD value of the output amount. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result44.SlippageBps +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Slippage tolerance in basis points (1 bps = 0.01%). + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result44.RequestId +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Quote request ID for executing the swap. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result45.Signature +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Transaction signature for the confirmed swap on the Solana network. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result45.InputMint +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Input token mint address. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result45.OutputMint +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Output token mint address. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result45.InputAmount +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Amount of input token swapped. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result45.OutputAmount +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Amount of output token received. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result45.InputUsdValue +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +USD value of the input amount. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result45.OutputUsdValue +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +USD value of the output amount. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result45.RequestId +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Request ID for this swap. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result46.Id +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Unique identifier for the transaction. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result46.ChainId +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Solana network identifier in CAIP-2 format. Use "solana:mainnet" or "solana:devnet" for convenience, or full CAIP-2 format. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result46.From +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Signer address used on submission. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result46.Signature +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Signature recorded on-chain once available. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result46.Status +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Current status of the transaction in the processing pipeline. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result46.ConfirmedAt +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Timestamp when the transaction reached the reported status. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result46.ConfirmedAtSlot +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Slot where the transaction was confirmed, if available. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result46.BlockTime +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Unix timestamp of the processed block. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result46.CreatedAt +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +ISO 8601 timestamp when the transaction was queued. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result46.ErrorMessage +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Error message if the transaction failed. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result46.ExecutionParams +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Resolved execution parameters used for the transaction. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result46.ExecutionResult +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Raw execution result payload, if present. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result46.TransactionParams +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Original instruction payload submitted. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result46.ClientId +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Project client identifier. + +-------------------------------------------------------------------------------- +T:Thirdweb.Api.Actions +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Sign a transaction + +-------------------------------------------------------------------------------- +T:Thirdweb.Api.Accounts +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Account metadata required for executing an instruction. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Accounts.Address +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Public key for the account. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Accounts.IsSigner +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Whether this account must sign the transaction. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Accounts.IsWritable +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Whether this account can be modified by the instruction. + +-------------------------------------------------------------------------------- +T:Thirdweb.Api.accounts +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Account metadata required for executing an instruction. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.accounts.Address +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Public key for the account. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.accounts.IsSigner +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Whether this account must sign the transaction. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.accounts.IsWritable +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Whether this account can be modified by the instruction. + +-------------------------------------------------------------------------------- +T:Thirdweb.Api.Profiles +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Authentication provider details with type-based discrimination + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Pagination3.HasMore +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Whether there are more items available + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Pagination3.Limit +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Number of items per page + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Pagination3.Page +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Current page number + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Pagination3.TotalCount +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Total number of items available + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Wallets.UserId +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Unique identifier for the user wallet within the thirdweb auth system. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Wallets.Address +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The EOA (Externally Owned Wallet) address of the wallet. This is the traditional wallet address. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Wallets.CreatedAt +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The date and time the wallet was created + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Wallets.Profiles +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The profiles linked to the wallet, can be email, phone, google etc, or backend for developer created wallets + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Wallets.SmartWalletAddress +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The smart wallet address with EIP-4337 support. This address enables gasless transactions and advanced wallet features. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Wallets.PublicKey +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The wallet's public key in hexadecimal format. Useful for peer-to-peer encryption and cryptographic operations. + +-------------------------------------------------------------------------------- +T:Thirdweb.Api.profiles +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Authentication provider details with type-based discrimination + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Pagination4.HasMore +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Whether there are more items available + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Pagination4.Limit +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Number of items per page + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Pagination4.Page +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Current page number + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Pagination4.TotalCount +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Total number of items available + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.wallets.UserId +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Unique identifier for the user wallet within the thirdweb auth system. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.wallets.Address +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The EOA (Externally Owned Wallet) address of the wallet. This is the traditional wallet address. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.wallets.CreatedAt +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The date and time the wallet was created + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.wallets.Profiles +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The profiles linked to the wallet, can be email, phone, google etc, or backend for developer created wallets + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.wallets.SmartWalletAddress +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The smart wallet address with EIP-4337 support. This address enables gasless transactions and advanced wallet features. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.wallets.PublicKey +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The wallet's public key in hexadecimal format. Useful for peer-to-peer encryption and cryptographic operations. + +-------------------------------------------------------------------------------- +T:Thirdweb.Api.Profiles2 +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Authentication provider details with type-based discrimination + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Pagination5.HasMore +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Whether there are more items available + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Pagination5.Limit +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Number of items per page + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Pagination5.Page +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Current page number + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Pagination5.TotalCount +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Total number of items available + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.transactions.BlockHash +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The hash of the block containing this transaction. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.transactions.BlockNumber +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The block number containing this transaction. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.transactions.BlockTimestamp +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The timestamp of the block (Unix timestamp). + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.transactions.ChainId +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The chain ID where the transaction occurred. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.transactions.ContractAddress +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Contract address created if this was a contract creation transaction. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.transactions.CumulativeGasUsed +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Total gas used by all transactions in this block up to and including this one. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.transactions.Data +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The transaction input data. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.transactions.Decoded +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Decoded transaction data (included when ABI is available). + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.transactions.EffectiveGasPrice +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The effective gas price paid (in wei as string). + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.transactions.FromAddress +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The address that initiated the transaction. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.transactions.FunctionSelector +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The function selector (first 4 bytes of the transaction data). + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.transactions.Gas +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The gas limit for the transaction. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.transactions.GasPrice +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The gas price used for the transaction (in wei as string). + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.transactions.GasUsed +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The amount of gas used by the transaction. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.transactions.Hash +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The transaction hash. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.transactions.MaxFeePerGas +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Maximum fee per gas (EIP-1559). + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.transactions.MaxPriorityFeePerGas +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Maximum priority fee per gas (EIP-1559). + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.transactions.Nonce +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The transaction nonce. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.transactions.Status +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The transaction status (1 for success, 0 for failure). + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.transactions.ToAddress +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The address that received the transaction. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.transactions.TransactionIndex +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The index of the transaction within the block. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.transactions.TransactionType +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The transaction type (0=legacy, 1=EIP-2930, 2=EIP-1559). + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.transactions.Value +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The value transferred in the transaction (in wei as string). + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Pagination6.HasMore +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Whether there are more items available + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Pagination6.Limit +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Number of items per page + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Pagination6.Page +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Current page number + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Pagination6.TotalCount +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Total number of items available + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.tokens.Balance +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The token balance as a string + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.tokens.Chain_id +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The chain ID of the token + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.tokens.Decimals +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The number of decimal places + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.tokens.Name +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The token name + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.tokens.Icon_uri +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The token icon URI + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.tokens.Prices +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Price data + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.tokens.Price_data +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Price data for the token + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.tokens.Symbol +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The token symbol + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.tokens.Token_address +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The contract address of the token + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Nfts.Animation_url +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The animation URL of the NFT + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Nfts.Attributes +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The attributes/traits of the NFT + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Nfts.Chain_id +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The chain ID of the NFT + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Nfts.Collection +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Collection information + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Nfts.Description +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The description of the NFT + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Nfts.External_url +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The external URL of the NFT + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Nfts.Image_url +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The image URL of the NFT + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Nfts.Metadata +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Additional metadata for the NFT + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Nfts.Name +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The name of the NFT + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Nfts.Token_address +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The contract address of the NFT collection + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Nfts.Token_id +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The token ID of the NFT + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Pagination7.HasMore +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Whether there are more items available + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Pagination7.Limit +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Number of items per page + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Pagination7.Page +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Current page number + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Pagination7.TotalCount +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Total number of items available + +-------------------------------------------------------------------------------- +T:Thirdweb.Api.Contracts +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Contract details enriched with additional project information from the API server. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Contracts.Address +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The contract address. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Contracts.ChainId +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The chain ID where the contract is deployed. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Contracts.DeployedAt +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The date when the contract was deployed. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Contracts.Id +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The contract ID. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Contracts.ImportedAt +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The date when the contract was imported to the dashboard. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Contracts.Name +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The contract name, if available. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Contracts.Symbol +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The contract symbol, if available. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Contracts.Type +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The contract type (e.g., ERC20, ERC721, etc.). + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Pagination8.HasMore +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Whether there are more items available + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Pagination8.Limit +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Number of items per page + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Pagination8.Page +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Current page number + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Pagination8.TotalCount +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Total number of items available + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Quote.BlockNumber +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Block number when quote was generated + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Quote.DestinationAmount +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Destination amount in wei + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Quote.EstimatedExecutionTimeMs +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Estimated execution time in milliseconds + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Quote.Intent +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Quote intent details + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Quote.OriginAmount +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Origin amount in wei + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Quote.Steps +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Array of steps to complete the bridge operation + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Quote.Timestamp +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Quote timestamp + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.data.BlockHash +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The hash of the block containing this transaction. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.data.BlockNumber +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The block number containing this transaction. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.data.BlockTimestamp +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The timestamp of the block (Unix timestamp). + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.data.ChainId +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The chain ID where the transaction occurred. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.data.ContractAddress +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Contract address created if this was a contract creation transaction. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.data.CumulativeGasUsed +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Total gas used by all transactions in this block up to and including this one. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.data.Data +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The transaction input data. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.data.Decoded +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Decoded transaction data (included when ABI is available). + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.data.EffectiveGasPrice +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The effective gas price paid (in wei as string). + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.data.FromAddress +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The address that initiated the transaction. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.data.FunctionSelector +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The function selector (first 4 bytes of the transaction data). + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.data.Gas +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The gas limit for the transaction. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.data.GasPrice +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The gas price used for the transaction (in wei as string). + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.data.GasUsed +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The amount of gas used by the transaction. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.data.Hash +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The transaction hash. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.data.MaxFeePerGas +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Maximum fee per gas (EIP-1559). + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.data.MaxPriorityFeePerGas +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Maximum priority fee per gas (EIP-1559). + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.data.Nonce +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The transaction nonce. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.data.Status +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The transaction status (1 for success, 0 for failure). + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.data.ToAddress +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The address that received the transaction. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.data.TransactionIndex +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The index of the transaction within the block. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.data.TransactionType +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The transaction type (0=legacy, 1=EIP-2930, 2=EIP-1559). + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.data.Value +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The value transferred in the transaction (in wei as string). + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Pagination9.HasMore +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Whether there are more items available + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Pagination9.Limit +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Number of items per page + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Pagination9.Page +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Current page number + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Pagination9.TotalCount +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Total number of items available + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Events.Address +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The contract address that emitted the event. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Events.BlockHash +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The hash of the block containing this event. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Events.BlockNumber +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The block number where the event was emitted. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Events.BlockTimestamp +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The timestamp of the block (Unix timestamp). + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Events.ChainId +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The chain ID where the event occurred. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Events.Data +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The non-indexed event data as a hex string. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Events.Decoded +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Decoded event data (included when ABI is available). + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Events.LogIndex +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The index of the log within the transaction. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Events.Topics +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Array of indexed event topics (including event signature). + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Events.TransactionHash +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The hash of the transaction containing this event. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Events.TransactionIndex +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The index of the transaction within the block. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Pagination10.HasMore +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Whether there are more items available + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Pagination10.Limit +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Number of items per page + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Pagination10.Page +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Current page number + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Pagination10.TotalCount +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Total number of items available + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Compiler.Version +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Solidity compiler version used to compile the contract. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Output.Abi +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Contract ABI (Application Binary Interface) as an array of function/event/error definitions. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Output.Devdoc +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Developer documentation extracted from contract comments. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Output.Userdoc +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +User documentation extracted from contract comments. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Settings.CompilationTarget +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Compilation target mapping source file names to contract names. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Settings.EvmVersion +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +EVM version target for compilation. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Settings.Libraries +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Library addresses for linking. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Settings.Metadata +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Metadata settings for compilation. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Settings.Optimizer +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Optimizer settings used during compilation. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Settings.Remappings +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Import remappings used during compilation. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Pagination11.HasMore +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Whether there are more items available + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Pagination11.Limit +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Number of items per page + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Pagination11.Page +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Current page number + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Pagination11.TotalCount +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Total number of items available + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Transactions2.BatchIndex +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Index within transaction batch + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Transactions2.CancelledAt +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +ISO timestamp when transaction was cancelled, if applicable + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Transactions2.ChainId +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Blockchain network identifier as string + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Transactions2.ClientId +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Client identifier that initiated the transaction + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Transactions2.ConfirmedAt +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +ISO timestamp when transaction was confirmed on-chain + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Transactions2.ConfirmedAtBlockNumber +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Block number where transaction was confirmed + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Transactions2.CreatedAt +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +ISO timestamp when transaction was created + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Transactions2.EnrichedData +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Additional metadata and enriched transaction information + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Transactions2.ErrorMessage +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Error message if transaction failed + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Transactions2.ExecutionParams +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Parameters used for transaction execution + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Transactions2.ExecutionResult +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Result data from transaction execution + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Transactions2.From +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Sender wallet address + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Transactions2.Id +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Unique transaction identifier + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Transactions2.TransactionHash +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +On-chain transaction hash once confirmed + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Transactions2.TransactionParams +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Original transaction parameters and data + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Transactions2.Status +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Transaction status + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Quote2.BlockNumber +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Block number when quote was generated + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Quote2.DestinationAmount +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Destination amount in wei + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Quote2.EstimatedExecutionTimeMs +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Estimated execution time in milliseconds + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Quote2.Intent +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Quote intent details + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Quote2.OriginAmount +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Origin amount in wei + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Quote2.Steps +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Array of steps to complete the bridge operation + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Quote2.Timestamp +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Quote timestamp + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Quote3.BlockNumber +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Block number when quote was generated + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Quote3.DestinationAmount +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Destination amount in wei + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Quote3.EstimatedExecutionTimeMs +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Estimated execution time in milliseconds + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Quote3.Intent +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Quote intent details + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Quote3.OriginAmount +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Origin amount in wei + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Quote3.Steps +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Array of steps to complete the bridge operation + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Quote3.Timestamp +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Quote timestamp + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.OriginToken.Address +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +A valid Ethereum address (0x-prefixed hex string) or ENS name (e.g., vitalik.eth). + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.DestinationToken.Address +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +A valid Ethereum address (0x-prefixed hex string) or ENS name (e.g., vitalik.eth). + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Quote4.BlockNumber +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Block number when quote was generated + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Quote4.DestinationAmount +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Destination amount in wei + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Quote4.EstimatedExecutionTimeMs +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Estimated execution time in milliseconds + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Quote4.Intent +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Quote intent details + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Quote4.OriginAmount +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Origin amount in wei + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Quote4.Steps +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Array of steps to complete the bridge operation + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Quote4.Timestamp +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Quote timestamp + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Accepts2.Network +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +CAIP-2 blockchain identifier (e.g., 'eip155:1' for Ethereum, 'solana:4sGjMW1sUnHzSxGspuhpqLDx6wiyjNtZ' for Solana mainnet). Also accepts numeric EVM chain IDs (e.g., 1, 137) or aliases ('solana:mainnet', 'solana:devnet') for backward compatibility. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Owners.Address +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Owner wallet address + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Owners.Amount +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Token amount owned as a string + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Owners.TokenId +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Token ID for NFTs + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Pagination12.HasMore +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Whether there are more items available + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Pagination12.Limit +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Number of items per page + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Pagination12.Page +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Current page number + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Pagination12.TotalCount +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Total number of items available + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.NativeCurrency.Name +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The name of the native currency + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.NativeCurrency.Symbol +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The symbol of the native currency + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.NativeCurrency.Decimals +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The number of decimals used by the native currency + +-------------------------------------------------------------------------------- +T:Thirdweb.Api.Routes +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Represents a supported bridge route between an origin and destination token. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Pagination13.HasMore +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Whether there are more items available + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Pagination13.Limit +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Number of items per page + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Pagination13.Page +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Current page number + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Pagination13.TotalCount +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Total number of items available + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Quote5.BlockNumber +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Block number when quote was generated + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Quote5.DestinationAmount +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Destination amount in wei + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Quote5.EstimatedExecutionTimeMs +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Estimated execution time in milliseconds + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Quote5.Intent +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Quote intent details + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Quote5.OriginAmount +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Origin amount in wei + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Quote5.Steps +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Array of steps to complete the bridge operation + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Quote5.Timestamp +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Quote timestamp + +-------------------------------------------------------------------------------- +T:Thirdweb.Api.Wallets2 +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Details for a Solana wallet in your project. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Wallets2.Address +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Base58 encoded Solana address. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Wallets2.Label +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Optional label associated with the wallet. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Wallets2.CreatedAt +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +ISO 8601 timestamp indicating when the wallet was created. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Wallets2.UpdatedAt +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +ISO 8601 timestamp indicating when the wallet was last updated. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Pagination14.TotalCount +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Total number of wallets available. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Pagination14.Page +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Current page number. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Pagination14.Limit +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Number of wallets returned per page. + +-------------------------------------------------------------------------------- +T:Thirdweb.Api.Profiles3 +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Authentication provider details with type-based discrimination + +-------------------------------------------------------------------------------- +T:Thirdweb.Api.Profiles4 +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Authentication provider details with type-based discrimination + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Decoded.Inputs +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Object containing decoded function parameters. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Decoded.Name +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The function name. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Decoded.Signature +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The function signature. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Price_data.Circulating_supply +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The circulating supply of the token + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Price_data.Market_cap_usd +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The market cap of the token in USD + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Price_data.Percent_change_24h +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The percentage change of the token in the last 24 hours + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Price_data.Price_timestamp +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The timestamp of the latest price update + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Price_data.Price_usd +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The price of the token in USD + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Price_data.Total_supply +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The total supply of the token + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Price_data.Usd_value +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The value of the token balance in USD + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Price_data.Volume_24h_usd +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The volume of the token in USD + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Attributes.Display_type +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The display type + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Attributes.Trait_type +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The trait type + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Attributes.Value +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The trait value + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Collection.Description +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The collection description + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Collection.External_url +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The collection external URL + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Collection.Image +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The collection image URL + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Collection.Name +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The collection name + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Intent.Amount +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The amount in wei + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Intent.DestinationChainId +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Destination chain ID + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Intent.DestinationTokenAddress +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Destination token address + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Intent.OriginChainId +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Origin chain ID + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Intent.OriginTokenAddress +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Origin token address + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Intent.Receiver +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Receiver address + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Intent.Sender +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Sender address + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Steps.OriginToken +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Origin token information + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Steps.DestinationToken +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Destination token information + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Steps.Transactions +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Array of transactions for this step + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Steps.OriginAmount +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Origin amount in wei + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Steps.DestinationAmount +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Destination amount in wei + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Steps.EstimatedExecutionTimeMs +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Estimated execution time in milliseconds + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Decoded2.Inputs +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Object containing decoded function parameters. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Decoded2.Name +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The function name. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Decoded2.Signature +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The function signature. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Decoded3.Name +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The event name. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Decoded3.Params +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Object containing decoded parameters. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Decoded3.Signature +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The event signature. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Metadata2.BytecodeHash +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Hash method used for bytecode metadata. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Optimizer.Enabled +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Whether optimizer is enabled. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Optimizer.Runs +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Number of optimizer runs. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Intent2.Amount +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The amount in wei + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Intent2.DestinationChainId +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Destination chain ID + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Intent2.DestinationTokenAddress +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Destination token address + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Intent2.OriginChainId +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Origin chain ID + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Intent2.OriginTokenAddress +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Origin token address + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Intent2.Receiver +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Receiver address + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Intent2.Sender +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Sender address + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.steps.OriginToken +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Origin token information + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.steps.DestinationToken +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Destination token information + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.steps.Transactions +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Array of transactions for this step + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.steps.OriginAmount +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Origin amount in wei + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.steps.DestinationAmount +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Destination amount in wei + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.steps.EstimatedExecutionTimeMs +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Estimated execution time in milliseconds + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Intent3.Amount +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The amount in wei + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Intent3.DestinationChainId +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Destination chain ID + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Intent3.DestinationTokenAddress +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Destination token address + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Intent3.OriginChainId +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Origin chain ID + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Intent3.OriginTokenAddress +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Origin token address + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Intent3.Receiver +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Receiver address + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Intent3.Sender +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Sender address + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Steps2.OriginToken +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Origin token information + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Steps2.DestinationToken +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Destination token information + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Steps2.Transactions +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Array of transactions for this step + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Steps2.OriginAmount +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Origin amount in wei + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Steps2.DestinationAmount +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Destination amount in wei + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Steps2.EstimatedExecutionTimeMs +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Estimated execution time in milliseconds + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.DefaultAsset.Address +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +A valid Ethereum address (0x-prefixed hex string) or ENS name (e.g., vitalik.eth). + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.SupportedAssets.Address +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +A valid Ethereum address (0x-prefixed hex string) or ENS name (e.g., vitalik.eth). + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Intent4.Amount +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The amount in wei + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Intent4.DestinationChainId +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Destination chain ID + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Intent4.DestinationTokenAddress +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Destination token address + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Intent4.OriginChainId +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Origin chain ID + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Intent4.OriginTokenAddress +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Origin token address + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Intent4.Receiver +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Receiver address + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Intent4.Sender +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Sender address + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Steps3.OriginToken +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Origin token information + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Steps3.DestinationToken +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Destination token information + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Steps3.Transactions +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Array of transactions for this step + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Steps3.OriginAmount +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Origin amount in wei + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Steps3.DestinationAmount +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Destination amount in wei + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Steps3.EstimatedExecutionTimeMs +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Estimated execution time in milliseconds + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.OriginToken2.ChainId +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Chain identifier for the token + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.OriginToken2.Address +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Token contract address + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.OriginToken2.Symbol +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Token symbol + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.OriginToken2.Name +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Token name + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.OriginToken2.Decimals +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Number of decimals the token uses + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.OriginToken2.IconUri +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Optional icon URL for the token + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.OriginToken2.MarketCapUsd +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +24h market capitalization in USD when available + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.OriginToken2.Volume24hUsd +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +24h trading volume in USD when available + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.OriginToken2.Prices +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Token price quotes keyed by fiat currency code + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.DestinationToken2.ChainId +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Chain identifier for the token + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.DestinationToken2.Address +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Token contract address + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.DestinationToken2.Symbol +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Token symbol + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.DestinationToken2.Name +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Token name + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.DestinationToken2.Decimals +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Number of decimals the token uses + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.DestinationToken2.IconUri +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Optional icon URL for the token + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.DestinationToken2.MarketCapUsd +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +24h market capitalization in USD when available + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.DestinationToken2.Volume24hUsd +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +24h trading volume in USD when available + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.DestinationToken2.Prices +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Token price quotes keyed by fiat currency code + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Intent5.Amount +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The amount in wei + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Intent5.DestinationChainId +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Destination chain ID + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Intent5.DestinationTokenAddress +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Destination token address + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Intent5.OriginChainId +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Origin chain ID + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Intent5.OriginTokenAddress +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Origin token address + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Intent5.Receiver +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Receiver address + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Intent5.Sender +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Sender address + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Steps4.OriginToken +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Origin token information + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Steps4.DestinationToken +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Destination token information + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Steps4.Transactions +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Array of transactions for this step + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Steps4.OriginAmount +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Origin amount in wei + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Steps4.DestinationAmount +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Destination amount in wei + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Steps4.EstimatedExecutionTimeMs +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Estimated execution time in milliseconds + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.OriginToken3.ChainId +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The blockchain network identifier. Common values include: 1 (Ethereum), 8453 (Base), 137 (Polygon), 56 (BSC), 43114 (Avalanche), 42161 (Arbitrum), 10 (Optimism). + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.OriginToken3.Address +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +A valid Ethereum address (0x-prefixed hex string) or ENS name (e.g., vitalik.eth). + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.OriginToken3.Prices +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Token price in different FIAT currencies. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.DestinationToken3.ChainId +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The blockchain network identifier. Common values include: 1 (Ethereum), 8453 (Base), 137 (Polygon), 56 (BSC), 43114 (Avalanche), 42161 (Arbitrum), 10 (Optimism). + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.DestinationToken3.Address +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +A valid Ethereum address (0x-prefixed hex string) or ENS name (e.g., vitalik.eth). + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.DestinationToken3.Prices +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Token price in different FIAT currencies. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Transactions4.ChainId +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Blockchain network identifier + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Transactions4.To +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Transaction recipient address + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Transactions4.Data +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Transaction data payload + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Transactions4.Action +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Type of action this transaction performs + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Transactions4.From +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Transaction sender address + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Transactions4.Spender +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Spender address for approval transactions + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Transactions4.Value +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Transaction value in wei + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.OriginToken4.ChainId +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The blockchain network identifier. Common values include: 1 (Ethereum), 8453 (Base), 137 (Polygon), 56 (BSC), 43114 (Avalanche), 42161 (Arbitrum), 10 (Optimism). + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.OriginToken4.Address +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +A valid Ethereum address (0x-prefixed hex string) or ENS name (e.g., vitalik.eth). + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.OriginToken4.Prices +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Token price in different FIAT currencies. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.DestinationToken4.ChainId +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The blockchain network identifier. Common values include: 1 (Ethereum), 8453 (Base), 137 (Polygon), 56 (BSC), 43114 (Avalanche), 42161 (Arbitrum), 10 (Optimism). + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.DestinationToken4.Address +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +A valid Ethereum address (0x-prefixed hex string) or ENS name (e.g., vitalik.eth). + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.DestinationToken4.Prices +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Token price in different FIAT currencies. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Transactions5.ChainId +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Blockchain network identifier + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Transactions5.To +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Transaction recipient address + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Transactions5.Data +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Transaction data payload + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Transactions5.Action +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Type of action this transaction performs + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Transactions5.From +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Transaction sender address + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Transactions5.Spender +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Spender address for approval transactions + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Transactions5.Value +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Transaction value in wei + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.OriginToken5.ChainId +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The blockchain network identifier. Common values include: 1 (Ethereum), 8453 (Base), 137 (Polygon), 56 (BSC), 43114 (Avalanche), 42161 (Arbitrum), 10 (Optimism). + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.OriginToken5.Address +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +A valid Ethereum address (0x-prefixed hex string) or ENS name (e.g., vitalik.eth). + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.OriginToken5.Prices +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Token price in different FIAT currencies. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.DestinationToken5.ChainId +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The blockchain network identifier. Common values include: 1 (Ethereum), 8453 (Base), 137 (Polygon), 56 (BSC), 43114 (Avalanche), 42161 (Arbitrum), 10 (Optimism). + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.DestinationToken5.Address +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +A valid Ethereum address (0x-prefixed hex string) or ENS name (e.g., vitalik.eth). + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.DestinationToken5.Prices +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Token price in different FIAT currencies. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Transactions6.ChainId +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Blockchain network identifier + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Transactions6.To +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Transaction recipient address + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Transactions6.Data +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Transaction data payload + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Transactions6.Action +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Type of action this transaction performs + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Transactions6.From +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Transaction sender address + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Transactions6.Spender +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Spender address for approval transactions + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Transactions6.Value +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Transaction value in wei + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.OriginToken6.ChainId +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The blockchain network identifier. Common values include: 1 (Ethereum), 8453 (Base), 137 (Polygon), 56 (BSC), 43114 (Avalanche), 42161 (Arbitrum), 10 (Optimism). + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.OriginToken6.Address +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +A valid Ethereum address (0x-prefixed hex string) or ENS name (e.g., vitalik.eth). + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.OriginToken6.Prices +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Token price in different FIAT currencies. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.DestinationToken6.ChainId +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The blockchain network identifier. Common values include: 1 (Ethereum), 8453 (Base), 137 (Polygon), 56 (BSC), 43114 (Avalanche), 42161 (Arbitrum), 10 (Optimism). + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.DestinationToken6.Address +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +A valid Ethereum address (0x-prefixed hex string) or ENS name (e.g., vitalik.eth). + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.DestinationToken6.Prices +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Token price in different FIAT currencies. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Transactions7.ChainId +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Blockchain network identifier + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Transactions7.To +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Transaction recipient address + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Transactions7.Data +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Transaction data payload + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Transactions7.Action +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Type of action this transaction performs + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Transactions7.From +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Transaction sender address + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Transactions7.Spender +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Spender address for approval transactions + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Transactions7.Value +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Transaction value in wei + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.OriginToken7.ChainId +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The blockchain network identifier. Common values include: 1 (Ethereum), 8453 (Base), 137 (Polygon), 56 (BSC), 43114 (Avalanche), 42161 (Arbitrum), 10 (Optimism). + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.OriginToken7.Address +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +A valid Ethereum address (0x-prefixed hex string) or ENS name (e.g., vitalik.eth). + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.OriginToken7.Prices +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Token price in different FIAT currencies. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.DestinationToken7.ChainId +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The blockchain network identifier. Common values include: 1 (Ethereum), 8453 (Base), 137 (Polygon), 56 (BSC), 43114 (Avalanche), 42161 (Arbitrum), 10 (Optimism). + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.DestinationToken7.Address +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +A valid Ethereum address (0x-prefixed hex string) or ENS name (e.g., vitalik.eth). + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.DestinationToken7.Prices +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Token price in different FIAT currencies. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Transactions8.ChainId +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Blockchain network identifier + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Transactions8.To +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Transaction recipient address + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Transactions8.Data +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Transaction data payload + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Transactions8.Action +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Type of action this transaction performs + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Transactions8.From +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Transaction sender address + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Transactions8.Spender +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Spender address for approval transactions + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Transactions8.Value +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Transaction value in wei + +-------------------------------------------------------------------------------- +T:Thirdweb.Api.ThirdwebHttpClientWrapper +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Wrapper class that adapts IThirdwebHttpClient to work with System.Net.Http.HttpClient expectations + +-------------------------------------------------------------------------------- +T:Thirdweb.ThirdwebClient +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Represents a client for interacting with the Thirdweb API. + +-------------------------------------------------------------------------------- +P:Thirdweb.ThirdwebClient.HttpClient +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets the HTTP client used by the Thirdweb client. + +-------------------------------------------------------------------------------- +P:Thirdweb.ThirdwebClient.ClientId +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets the client ID. + +-------------------------------------------------------------------------------- +P:Thirdweb.ThirdwebClient.Api +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Low-level interaction with https://api.thirdweb.com +Used in some places to enhance the core SDK functionality, or even extend it + +-------------------------------------------------------------------------------- +M:Thirdweb.ThirdwebClient.Create(System.String,System.String,System.String,Thirdweb.TimeoutOptions,Thirdweb.IThirdwebHttpClient,System.String,System.String,System.String,System.String,System.Collections.Generic.Dictionary{System.Numerics.BigInteger,System.String}) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - clientId (string) + The client ID (optional). + - secretKey (string) + The secret key (optional). + - bundleId (string) + The bundle ID (optional). + - fetchTimeoutOptions (Thirdweb.TimeoutOptions) + The fetch timeout options (optional). + - httpClient (Thirdweb.IThirdwebHttpClient) + The HTTP client (optional). + - sdkName (string) + The SDK name (optional). + - sdkOs (string) + The SDK OS (optional). + - sdkPlatform (string) + The SDK platform (optional). + - sdkVersion (string) + The SDK version (optional). + - rpcOverrides (Dictionary) + The timeout for storage operations (optional). + - rpc (Nullable) + The timeout for RPC operations (optional). + - other (Nullable) + The timeout for other operations (optional). + +SUMMARY: +Represents the timeout options for different types of operations. + +REMARKS: +Initializes a new instance of the class. + +-------------------------------------------------------------------------------- +M:Thirdweb.TimeoutOptions.GetTimeout(Thirdweb.TimeoutType,System.Int32) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - type (Thirdweb.TimeoutType) + The type of operation. + - fallback (int) + The fallback timeout value if none is specified (default is ). + +SUMMARY: +Gets the timeout value for the specified operation type. + +RETURNS: +The timeout value for the specified operation type. + +-------------------------------------------------------------------------------- +T:Thirdweb.TimeoutType +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Specifies the type of timeout for various operations. + +-------------------------------------------------------------------------------- +F:Thirdweb.TimeoutType.Storage +-------------------------------------------------------------------------------- + +KIND: Field + +SUMMARY: +Timeout for storage operations. + +-------------------------------------------------------------------------------- +F:Thirdweb.TimeoutType.Rpc +-------------------------------------------------------------------------------- + +KIND: Field + +SUMMARY: +Timeout for RPC operations. + +-------------------------------------------------------------------------------- +F:Thirdweb.TimeoutType.Other +-------------------------------------------------------------------------------- + +KIND: Field + +SUMMARY: +Timeout for other types of operations. + +-------------------------------------------------------------------------------- +T:Thirdweb.ThirdwebContract +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Represents a Thirdweb contract. + +-------------------------------------------------------------------------------- +M:Thirdweb.ThirdwebContract.Deploy(Thirdweb.ThirdwebClient,System.Numerics.BigInteger,System.String,System.String,System.String,System.Collections.Generic.Dictionary{System.String,System.Object},System.String,System.Threading.CancellationToken) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - client (Thirdweb.ThirdwebClient) + The Thirdweb client. + - chainId (System.Numerics.BigInteger) + The chain ID. + - serverWalletAddress (string) + The server wallet address. + - bytecode (string) + The bytecode of the contract. + - abi (string) + The ABI of the contract. + - constructorParams (Dictionary) + Optional metadata override for the token. + +SUMMARY: +Generate a mint signature for ERC721 tokens. + +RETURNS: +A task representing the asynchronous operation, with a tuple containing the mint request and the generated signature. + +EXCEPTION (T:System.ArgumentNullException): +Thrown when the contract, wallet, or mint request is null. + +-------------------------------------------------------------------------------- +M:Thirdweb.ThirdwebExtensions.TokenERC721_VerifyMintSignature(Thirdweb.ThirdwebContract,Thirdweb.TokenERC721_MintRequest,System.String) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - contract (Thirdweb.ThirdwebContract) + The contract to interact with. + - mintRequest (Thirdweb.TokenERC721_MintRequest) + The mint request containing the minting details. + - signature (string) + The signature to verify. + +SUMMARY: +Verify a mint signature for ERC721 tokens. + +RETURNS: +A task representing the asynchronous operation, with a VerifyResult result containing the verification details. + +EXCEPTION (T:System.ArgumentNullException): +Thrown when the contract or mint request is null. + +EXCEPTION (T:System.ArgumentException): +Thrown when the signature is null or empty. + +-------------------------------------------------------------------------------- +M:Thirdweb.ThirdwebExtensions.TokenERC1155_Burn(Thirdweb.ThirdwebContract,Thirdweb.IThirdwebWallet,System.String,System.Numerics.BigInteger,System.Numerics.BigInteger) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - contract (Thirdweb.ThirdwebContract) + The contract to interact with. + - wallet (Thirdweb.IThirdwebWallet) + The wallet to use for the transaction. + - account (string) + The address of the account to burn the tokens from. + - tokenId (System.Numerics.BigInteger) + The ID of the token to burn. + - amount (System.Numerics.BigInteger) + The amount of tokens to burn. + +SUMMARY: +Burn a specific quantity of ERC1155 tokens for a specific account with a given token ID and amount to burn. + +RETURNS: +A task representing the asynchronous operation, with a ThirdwebTransactionReceipt result. + +EXCEPTION (T:System.ArgumentNullException): +Thrown when the contract, wallet, or account is null. + +EXCEPTION (T:System.ArgumentException): +Thrown when the account is null or empty. + +EXCEPTION (T:System.ArgumentOutOfRangeException): +Thrown when the token ID is less than 0 or the amount is less than or equal to 0. + +-------------------------------------------------------------------------------- +M:Thirdweb.ThirdwebExtensions.TokenERC1155_BurnBatch(Thirdweb.ThirdwebContract,Thirdweb.IThirdwebWallet,System.String,System.Numerics.BigInteger[],System.Numerics.BigInteger[]) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - contract (Thirdweb.ThirdwebContract) + The contract to interact with. + - wallet (Thirdweb.IThirdwebWallet) + The wallet to use for the transaction. + - account (string) + The address of the account to burn the tokens from. + - tokenIds (System.Numerics.BigInteger[]) + The IDs of the tokens to burn. + - amounts (System.Numerics.BigInteger[]) + The amounts of tokens to burn. + +SUMMARY: +Burn a specific quantity of ERC1155 tokens for a specific account with given token IDs and amounts to burn. + +RETURNS: +A task representing the asynchronous operation, with a ThirdwebTransactionReceipt result. + +EXCEPTION (T:System.ArgumentNullException): +Thrown when the contract, wallet, or account is null. + +EXCEPTION (T:System.ArgumentException): +Thrown when the account is null or empty, or the token IDs or amounts are null or empty, or the token IDs and amounts have different lengths. + +EXCEPTION (T:System.ArgumentOutOfRangeException): +Thrown when the token IDs or amounts have a length less than or equal to 0. + +EXCEPTION (T:System.ArgumentException): +Thrown when the token IDs and amounts have different lengths. + +-------------------------------------------------------------------------------- +M:Thirdweb.ThirdwebExtensions.TokenERC1155_MintTo(Thirdweb.ThirdwebContract,Thirdweb.IThirdwebWallet,System.String,System.Numerics.BigInteger,System.Numerics.BigInteger,System.String) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - contract (Thirdweb.ThirdwebContract) + The contract to interact with. + - wallet (Thirdweb.IThirdwebWallet) + The wallet to use for the transaction. + - receiverAddress (string) + The address of the receiver. + - tokenId (System.Numerics.BigInteger) + The ID of the token. + - quantity (System.Numerics.BigInteger) + The quantity of tokens to mint. + - uri (string) + The URI of the token metadata. + +SUMMARY: +Mint a specific quantity of ERC1155 tokens to a receiver address with a given URI. + +RETURNS: +A task representing the asynchronous operation, with a ThirdwebTransactionReceipt result. + +EXCEPTION (T:System.ArgumentNullException): +Thrown when the contract, wallet, or URI is null. + +EXCEPTION (T:System.ArgumentException): +Thrown when the receiver address is null or empty. + +EXCEPTION (T:System.ArgumentOutOfRangeException): +Thrown when the token ID is less than 0 or the quantity is less than or equal to 0. + +-------------------------------------------------------------------------------- +M:Thirdweb.ThirdwebExtensions.TokenERC1155_MintTo(Thirdweb.ThirdwebContract,Thirdweb.IThirdwebWallet,System.String,System.Numerics.BigInteger,System.Numerics.BigInteger,Thirdweb.NFTMetadata) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - contract (Thirdweb.ThirdwebContract) + The contract to interact with. + - wallet (Thirdweb.IThirdwebWallet) + The wallet to use for the transaction. + - receiverAddress (string) + The address of the receiver. + - tokenId (System.Numerics.BigInteger) + The ID of the token. + - quantity (System.Numerics.BigInteger) + The quantity of tokens to mint. + - metadata (Thirdweb.NFTMetadata) + The metadata of the token. + +SUMMARY: +Mint a specific quantity of ERC1155 tokens to a receiver address with metadata. + +RETURNS: +A task representing the asynchronous operation, with a ThirdwebTransactionReceipt result. + +EXCEPTION (T:System.ArgumentNullException): +Thrown when the contract or wallet is null. + +EXCEPTION (T:System.ArgumentException): +Thrown when the receiver address is null or empty. + +EXCEPTION (T:System.ArgumentOutOfRangeException): +Thrown when the token ID is less than 0 or the quantity is less than or equal to 0. + +-------------------------------------------------------------------------------- +M:Thirdweb.ThirdwebExtensions.TokenERC1155_MintWithSignature(Thirdweb.ThirdwebContract,Thirdweb.IThirdwebWallet,Thirdweb.TokenERC1155_MintRequest,System.String) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - contract (Thirdweb.ThirdwebContract) + The contract to interact with. + - wallet (Thirdweb.IThirdwebWallet) + The wallet to use for the transaction. + - mintRequest (Thirdweb.TokenERC1155_MintRequest) + The mint request containing the minting details. + - signature (string) + The signature to authorize the minting. + +SUMMARY: +Mint ERC1155 tokens with a signature. + +RETURNS: +A task representing the asynchronous operation, with a ThirdwebTransactionReceipt result. + +EXCEPTION (T:System.ArgumentNullException): +Thrown when the contract, wallet, or mint request is null. + +EXCEPTION (T:System.ArgumentException): +Thrown when the signature is null or empty. + +-------------------------------------------------------------------------------- +M:Thirdweb.ThirdwebExtensions.TokenERC1155_GenerateMintSignature(Thirdweb.ThirdwebContract,Thirdweb.IThirdwebWallet,Thirdweb.TokenERC1155_MintRequest,System.Nullable{Thirdweb.NFTMetadata}) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - contract (Thirdweb.ThirdwebContract) + The contract to interact with. + - wallet (Thirdweb.IThirdwebWallet) + The wallet to use for generating the signature. + - mintRequest (Thirdweb.TokenERC1155_MintRequest) + The mint request containing the minting details. + - metadataOverride (Nullable) + Optional metadata override for the token. + +SUMMARY: +Generate a mint signature for ERC1155 tokens. + +RETURNS: +A task representing the asynchronous operation, with a tuple containing the mint request and the generated signature. + +EXCEPTION (T:System.ArgumentNullException): +Thrown when the contract, wallet, or mint request is null. + +EXCEPTION (T:System.ArgumentException): +Thrown when the MintRequest URI or NFTMetadata override is not provided. + +-------------------------------------------------------------------------------- +M:Thirdweb.ThirdwebExtensions.TokenERC1155_VerifyMintSignature(Thirdweb.ThirdwebContract,Thirdweb.TokenERC1155_MintRequest,System.String) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - contract (Thirdweb.ThirdwebContract) + The contract to interact with. + - mintRequest (Thirdweb.TokenERC1155_MintRequest) + The mint request containing the minting details. + - signature (string) + The signature to verify. + +SUMMARY: +Verify a mint signature for ERC1155 tokens. + +RETURNS: +A task representing the asynchronous operation, with a VerifyResult result containing the verification details. + +EXCEPTION (T:System.ArgumentNullException): +Thrown when the contract or mint request is null. + +EXCEPTION (T:System.ArgumentException): +Thrown when the signature is null or empty. + +-------------------------------------------------------------------------------- +T:Thirdweb.VerifyResult +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Represents the result of a verification operation. + +-------------------------------------------------------------------------------- +P:Thirdweb.VerifyResult.IsValid +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets a value indicating whether the verification is valid. + +-------------------------------------------------------------------------------- +P:Thirdweb.VerifyResult.Signer +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the address of the signer. + +-------------------------------------------------------------------------------- +T:Thirdweb.RoyaltyInfoResult +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Represents the royalty information result. + +-------------------------------------------------------------------------------- +P:Thirdweb.RoyaltyInfoResult.Recipient +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the recipient address. + +-------------------------------------------------------------------------------- +P:Thirdweb.RoyaltyInfoResult.Bps +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the basis points (bps) for royalty. + +-------------------------------------------------------------------------------- +T:Thirdweb.ContractMetadata +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Represents the metadata of a contract. + +-------------------------------------------------------------------------------- +P:Thirdweb.ContractMetadata.Name +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the name of the contract. + +-------------------------------------------------------------------------------- +P:Thirdweb.ContractMetadata.Symbol +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the symbol of the contract. + +-------------------------------------------------------------------------------- +P:Thirdweb.ContractMetadata.Description +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the description of the contract. + +-------------------------------------------------------------------------------- +P:Thirdweb.ContractMetadata.Image +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the image URL of the contract. + +-------------------------------------------------------------------------------- +T:Thirdweb.NFTType +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Represents the type of an NFT. + +-------------------------------------------------------------------------------- +T:Thirdweb.NFT +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Represents an NFT with metadata, owner, type, and supply information. + +-------------------------------------------------------------------------------- +P:Thirdweb.NFT.Metadata +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the metadata of the NFT. + +-------------------------------------------------------------------------------- +P:Thirdweb.NFT.Owner +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the owner address of the NFT. This is only applicable for ERC721 tokens. + +-------------------------------------------------------------------------------- +P:Thirdweb.NFT.Type +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the type of the NFT. + +-------------------------------------------------------------------------------- +P:Thirdweb.NFT.Supply +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the supply of the NFT. + +-------------------------------------------------------------------------------- +P:Thirdweb.NFT.QuantityOwned +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the quantity owned by the user. This is only applicable for ERC1155 tokens. + +-------------------------------------------------------------------------------- +T:Thirdweb.NFTMetadata +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Represents the metadata of an NFT. + +-------------------------------------------------------------------------------- +P:Thirdweb.NFTMetadata.Id +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the ID of the NFT. + +-------------------------------------------------------------------------------- +P:Thirdweb.NFTMetadata.Uri +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the URI of the NFT. + +-------------------------------------------------------------------------------- +P:Thirdweb.NFTMetadata.Description +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the description of the NFT. + +-------------------------------------------------------------------------------- +P:Thirdweb.NFTMetadata.Image +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the image URL of the NFT. + +-------------------------------------------------------------------------------- +P:Thirdweb.NFTMetadata.Name +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the name of the NFT. + +-------------------------------------------------------------------------------- +P:Thirdweb.NFTMetadata.VideoUrl +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the video URL of the NFT. + +-------------------------------------------------------------------------------- +P:Thirdweb.NFTMetadata.AnimationUrl +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the animation URL of the NFT. + +-------------------------------------------------------------------------------- +P:Thirdweb.NFTMetadata.ExternalUrl +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the external URL of the NFT. + +-------------------------------------------------------------------------------- +P:Thirdweb.NFTMetadata.BackgroundColor +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the background color of the NFT. + +-------------------------------------------------------------------------------- +P:Thirdweb.NFTMetadata.Attributes +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the attributes of the NFT. + +-------------------------------------------------------------------------------- +P:Thirdweb.NFTMetadata.Properties +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the properties of the NFT. + +-------------------------------------------------------------------------------- +T:Thirdweb.Drop_ClaimCondition +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Represents a claim condition for a drop. + +-------------------------------------------------------------------------------- +P:Thirdweb.Drop_ClaimCondition.StartTimestamp +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the start timestamp of the claim condition. + +-------------------------------------------------------------------------------- +P:Thirdweb.Drop_ClaimCondition.MaxClaimableSupply +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the maximum claimable supply. + +-------------------------------------------------------------------------------- +P:Thirdweb.Drop_ClaimCondition.SupplyClaimed +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the supply claimed so far. + +-------------------------------------------------------------------------------- +P:Thirdweb.Drop_ClaimCondition.QuantityLimitPerWallet +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the quantity limit per wallet. + +-------------------------------------------------------------------------------- +P:Thirdweb.Drop_ClaimCondition.MerkleRoot +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the Merkle root for the claim condition. + +-------------------------------------------------------------------------------- +P:Thirdweb.Drop_ClaimCondition.PricePerToken +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the price per token for the claim condition. + +-------------------------------------------------------------------------------- +P:Thirdweb.Drop_ClaimCondition.Currency +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the currency address for the claim condition. + +-------------------------------------------------------------------------------- +P:Thirdweb.Drop_ClaimCondition.Metadata +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the metadata for the claim condition. + +-------------------------------------------------------------------------------- +T:Thirdweb.TokenERC20_MintRequest +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Represents a mint request for an ERC20 token. + +-------------------------------------------------------------------------------- +P:Thirdweb.TokenERC20_MintRequest.To +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the address to mint the tokens to. + +-------------------------------------------------------------------------------- +P:Thirdweb.TokenERC20_MintRequest.PrimarySaleRecipient +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the primary sale recipient address. + +-------------------------------------------------------------------------------- +P:Thirdweb.TokenERC20_MintRequest.Quantity +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the quantity of tokens to mint. + +-------------------------------------------------------------------------------- +P:Thirdweb.TokenERC20_MintRequest.Price +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the price of the tokens. + +-------------------------------------------------------------------------------- +P:Thirdweb.TokenERC20_MintRequest.Currency +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the currency address. + +-------------------------------------------------------------------------------- +P:Thirdweb.TokenERC20_MintRequest.ValidityStartTimestamp +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the validity start timestamp. + +-------------------------------------------------------------------------------- +P:Thirdweb.TokenERC20_MintRequest.ValidityEndTimestamp +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the validity end timestamp. + +-------------------------------------------------------------------------------- +P:Thirdweb.TokenERC20_MintRequest.Uid +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the unique identifier for the mint request. + +-------------------------------------------------------------------------------- +T:Thirdweb.TokenERC721_MintRequest +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Represents a mint request for an ERC721 token. + +-------------------------------------------------------------------------------- +P:Thirdweb.TokenERC721_MintRequest.To +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the address to mint the token to. + +-------------------------------------------------------------------------------- +P:Thirdweb.TokenERC721_MintRequest.RoyaltyRecipient +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the royalty recipient address. + +-------------------------------------------------------------------------------- +P:Thirdweb.TokenERC721_MintRequest.RoyaltyBps +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the royalty basis points. + +-------------------------------------------------------------------------------- +P:Thirdweb.TokenERC721_MintRequest.PrimarySaleRecipient +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the primary sale recipient address. + +-------------------------------------------------------------------------------- +P:Thirdweb.TokenERC721_MintRequest.Uri +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the URI of the token. + +-------------------------------------------------------------------------------- +P:Thirdweb.TokenERC721_MintRequest.Price +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the price of the token. + +-------------------------------------------------------------------------------- +P:Thirdweb.TokenERC721_MintRequest.Currency +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the currency address. + +-------------------------------------------------------------------------------- +P:Thirdweb.TokenERC721_MintRequest.ValidityStartTimestamp +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the validity start timestamp. + +-------------------------------------------------------------------------------- +P:Thirdweb.TokenERC721_MintRequest.ValidityEndTimestamp +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the validity end timestamp. + +-------------------------------------------------------------------------------- +P:Thirdweb.TokenERC721_MintRequest.Uid +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the unique identifier for the mint request. + +-------------------------------------------------------------------------------- +T:Thirdweb.TokenERC1155_MintRequest +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Represents a mint request for an ERC1155 token. + +-------------------------------------------------------------------------------- +P:Thirdweb.TokenERC1155_MintRequest.To +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the address to mint the token to. + +-------------------------------------------------------------------------------- +P:Thirdweb.TokenERC1155_MintRequest.RoyaltyRecipient +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the royalty recipient address. + +-------------------------------------------------------------------------------- +P:Thirdweb.TokenERC1155_MintRequest.RoyaltyBps +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the royalty basis points. + +-------------------------------------------------------------------------------- +P:Thirdweb.TokenERC1155_MintRequest.PrimarySaleRecipient +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the primary sale recipient address. + +-------------------------------------------------------------------------------- +P:Thirdweb.TokenERC1155_MintRequest.TokenId +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the token ID. + +-------------------------------------------------------------------------------- +P:Thirdweb.TokenERC1155_MintRequest.Uri +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the URI of the token. + +-------------------------------------------------------------------------------- +P:Thirdweb.TokenERC1155_MintRequest.Quantity +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the quantity of tokens to mint. + +-------------------------------------------------------------------------------- +P:Thirdweb.TokenERC1155_MintRequest.PricePerToken +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the price per token. + +-------------------------------------------------------------------------------- +P:Thirdweb.TokenERC1155_MintRequest.Currency +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the currency address. + +-------------------------------------------------------------------------------- +P:Thirdweb.TokenERC1155_MintRequest.ValidityStartTimestamp +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the validity start timestamp. + +-------------------------------------------------------------------------------- +P:Thirdweb.TokenERC1155_MintRequest.ValidityEndTimestamp +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the validity end timestamp. + +-------------------------------------------------------------------------------- +P:Thirdweb.TokenERC1155_MintRequest.Uid +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the unique identifier for the mint request. + +-------------------------------------------------------------------------------- +T:Thirdweb.IThirdwebHttpClient +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Interface for a HTTP client used in the Thirdweb SDK. + +-------------------------------------------------------------------------------- +P:Thirdweb.IThirdwebHttpClient.Headers +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets the headers for the HTTP client. + +-------------------------------------------------------------------------------- +M:Thirdweb.IThirdwebHttpClient.SetHeaders(System.Collections.Generic.Dictionary{System.String,System.String}) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - headers (Dictionary) + The optional request timeout in milliseconds. + +SUMMARY: +Downloads data from the specified URI. + +TYPEPARAM (T): +The type of data to download. + +RETURNS: +The downloaded data. + +EXCEPTION (T:System.ArgumentNullException): +Thrown if the URI is null or empty. + +EXCEPTION (T:System.Exception): +Thrown if the download fails. + +-------------------------------------------------------------------------------- +M:Thirdweb.ThirdwebStorage.UploadRaw(Thirdweb.ThirdwebClient,System.Byte[]) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - client (Thirdweb.ThirdwebClient) + The Thirdweb client. + - rawBytes (byte[]) + The raw byte data to upload. + +SUMMARY: +Uploads raw byte data to Thirdweb storage. + +RETURNS: +The result of the upload. + +EXCEPTION (T:System.ArgumentNullException): +Thrown if the raw byte data is null or empty. + +EXCEPTION (T:System.Exception): +Thrown if the upload fails. + +-------------------------------------------------------------------------------- +M:Thirdweb.ThirdwebStorage.Upload(Thirdweb.ThirdwebClient,System.String) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - client (Thirdweb.ThirdwebClient) + The Thirdweb client. + - path (string) + The path to the file. + +SUMMARY: +Uploads a file to Thirdweb storage from the specified path. + +RETURNS: +The result of the upload. + +EXCEPTION (T:System.ArgumentNullException): +Thrown if the path is null or empty. + +-------------------------------------------------------------------------------- +T:Thirdweb.IPFSUploadResult +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Represents the result of an IPFS upload. + +-------------------------------------------------------------------------------- +P:Thirdweb.IPFSUploadResult.IpfsHash +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the IPFS hash of the uploaded content. + +-------------------------------------------------------------------------------- +P:Thirdweb.IPFSUploadResult.PinSize +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the size of the pinned content. + +-------------------------------------------------------------------------------- +P:Thirdweb.IPFSUploadResult.Timestamp +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the timestamp of the upload. + +-------------------------------------------------------------------------------- +P:Thirdweb.IPFSUploadResult.PreviewUrl +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the preview URL of the uploaded content. + +-------------------------------------------------------------------------------- +T:Thirdweb.TotalCosts +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Represents the total costs in ether and wei. + +-------------------------------------------------------------------------------- +P:Thirdweb.TotalCosts.Ether +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The cost in ether. + +-------------------------------------------------------------------------------- +P:Thirdweb.TotalCosts.Wei +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The cost in wei. + +-------------------------------------------------------------------------------- +T:Thirdweb.ThirdwebTransaction +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Represents a Thirdweb transaction. + +-------------------------------------------------------------------------------- +M:Thirdweb.ThirdwebTransaction.Create(Thirdweb.IThirdwebWallet,Thirdweb.ThirdwebTransactionInput) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - wallet (Thirdweb.IThirdwebWallet) + The wallet to use for the transaction. + - txInput (Thirdweb.ThirdwebTransactionInput) + The transaction input. + +SUMMARY: +Creates a new Thirdweb transaction. + +RETURNS: +A new Thirdweb transaction. + +-------------------------------------------------------------------------------- +M:Thirdweb.ThirdwebTransaction.ToString +-------------------------------------------------------------------------------- + +KIND: Method + +SUMMARY: +Converts the transaction input to a JSON string. + +RETURNS: +A JSON string representation of the transaction input. + +-------------------------------------------------------------------------------- +M:Thirdweb.ThirdwebTransaction.SetTo(System.String) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - to (string) + The recipient address. + +SUMMARY: +Sets the recipient address of the transaction. + +RETURNS: +The updated transaction. + +-------------------------------------------------------------------------------- +M:Thirdweb.ThirdwebTransaction.SetData(System.String) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - data (string) + The data. + +SUMMARY: +Sets the data for the transaction. + +RETURNS: +The updated transaction. + +-------------------------------------------------------------------------------- +M:Thirdweb.ThirdwebTransaction.SetValue(System.Numerics.BigInteger) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - weiValue (System.Numerics.BigInteger) + The value in wei. + +SUMMARY: +Sets the value to be transferred in the transaction. + +RETURNS: +The updated transaction. + +-------------------------------------------------------------------------------- +M:Thirdweb.ThirdwebTransaction.SetGasLimit(System.Numerics.BigInteger) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - gas (System.Numerics.BigInteger) + The gas limit. + +SUMMARY: +Sets the gas limit for the transaction. + +RETURNS: +The updated transaction. + +-------------------------------------------------------------------------------- +M:Thirdweb.ThirdwebTransaction.SetGasPrice(System.Numerics.BigInteger) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - gasPrice (System.Numerics.BigInteger) + The gas price. + +SUMMARY: +Sets the gas price for the transaction. + +RETURNS: +The updated transaction. + +-------------------------------------------------------------------------------- +M:Thirdweb.ThirdwebTransaction.SetNonce(System.Numerics.BigInteger) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - nonce (System.Numerics.BigInteger) + The nonce. + +SUMMARY: +Sets the nonce for the transaction. + +RETURNS: +The updated transaction. + +-------------------------------------------------------------------------------- +M:Thirdweb.ThirdwebTransaction.SetMaxFeePerGas(System.Numerics.BigInteger) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - maxFeePerGas (System.Numerics.BigInteger) + The maximum fee per gas. + +SUMMARY: +Sets the maximum fee per gas for the transaction. + +RETURNS: +The updated transaction. + +-------------------------------------------------------------------------------- +M:Thirdweb.ThirdwebTransaction.SetMaxPriorityFeePerGas(System.Numerics.BigInteger) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - maxPriorityFeePerGas (System.Numerics.BigInteger) + The maximum priority fee per gas. + +SUMMARY: +Sets the maximum priority fee per gas for the transaction. + +RETURNS: +The updated transaction. + +-------------------------------------------------------------------------------- +M:Thirdweb.ThirdwebTransaction.SetChainId(System.Numerics.BigInteger) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - chainId (System.Numerics.BigInteger) + The chain ID. + +SUMMARY: +Sets the chain ID for the transaction. + +RETURNS: +The updated transaction. + +-------------------------------------------------------------------------------- +M:Thirdweb.ThirdwebTransaction.SetZkSyncOptions(Thirdweb.ZkSyncOptions) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - zkSyncOptions (Thirdweb.ZkSyncOptions) + The zkSync options. + +SUMMARY: +Sets the zkSync options for the transaction. + +RETURNS: +The updated transaction. + +-------------------------------------------------------------------------------- +M:Thirdweb.ThirdwebTransaction.EstimateGasCosts(Thirdweb.ThirdwebTransaction) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - transaction (Thirdweb.ThirdwebTransaction) + The transaction. + +SUMMARY: +Estimates the gas costs for the transaction. + +RETURNS: +The estimated gas costs. + +-------------------------------------------------------------------------------- +M:Thirdweb.ThirdwebTransaction.EstimateTotalCosts(Thirdweb.ThirdwebTransaction) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - transaction (Thirdweb.ThirdwebTransaction) + The transaction. + +SUMMARY: +Estimates the total costs for the transaction. + +RETURNS: +The estimated total costs. + +-------------------------------------------------------------------------------- +M:Thirdweb.ThirdwebTransaction.EstimateGasPrice(Thirdweb.ThirdwebTransaction,System.Boolean) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - transaction (Thirdweb.ThirdwebTransaction) + The transaction. + - withBump (bool) + Whether to include a bump in the gas price. + +SUMMARY: +Estimates the gas price for the transaction. + +RETURNS: +The estimated gas price. + +-------------------------------------------------------------------------------- +M:Thirdweb.ThirdwebTransaction.EstimateGasFees(Thirdweb.ThirdwebTransaction,System.Boolean) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - transaction (Thirdweb.ThirdwebTransaction) + The transaction. + - withBump (bool) + Whether to include a bump in the gas fees. + +SUMMARY: +Estimates the gas fees for the transaction. + +RETURNS: +The estimated maximum fee per gas and maximum priority fee per gas. + +-------------------------------------------------------------------------------- +M:Thirdweb.ThirdwebTransaction.Simulate(Thirdweb.ThirdwebTransaction) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - transaction (Thirdweb.ThirdwebTransaction) + The transaction. + +SUMMARY: +Simulates the transaction. + +RETURNS: +The result of the simulation. + +-------------------------------------------------------------------------------- +M:Thirdweb.ThirdwebTransaction.EstimateGasLimit(Thirdweb.ThirdwebTransaction) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - transaction (Thirdweb.ThirdwebTransaction) + The transaction. + +SUMMARY: +Estimates the gas limit for the transaction. + +RETURNS: +The estimated gas limit. + +-------------------------------------------------------------------------------- +M:Thirdweb.ThirdwebTransaction.GetNonce(Thirdweb.ThirdwebTransaction) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - transaction (Thirdweb.ThirdwebTransaction) + The transaction. + +SUMMARY: +Gets the nonce for the transaction. + +RETURNS: +The nonce. + +-------------------------------------------------------------------------------- +M:Thirdweb.ThirdwebTransaction.Sign(Thirdweb.ThirdwebTransaction) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - transaction (Thirdweb.ThirdwebTransaction) + The transaction. + +SUMMARY: +Signs the transaction. + +RETURNS: +The signed transaction. + +-------------------------------------------------------------------------------- +M:Thirdweb.ThirdwebTransaction.Prepare(Thirdweb.ThirdwebTransaction) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - transaction (Thirdweb.ThirdwebTransaction) + The transaction. + +SUMMARY: +Populates the transaction and prepares it for sending. + +RETURNS: +The populated transaction. + +-------------------------------------------------------------------------------- +M:Thirdweb.ThirdwebTransaction.Send(Thirdweb.ThirdwebTransaction) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - transaction (Thirdweb.ThirdwebTransaction) + The transaction. + +SUMMARY: +Sends the transaction. + +RETURNS: +The transaction hash. + +-------------------------------------------------------------------------------- +M:Thirdweb.ThirdwebTransaction.SendAndWaitForTransactionReceipt(Thirdweb.ThirdwebTransaction) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - transaction (Thirdweb.ThirdwebTransaction) + The transaction. + +SUMMARY: +Sends the transaction and waits for the transaction receipt. + +RETURNS: +The transaction receipt. + +-------------------------------------------------------------------------------- +M:Thirdweb.ThirdwebTransaction.WaitForTransactionReceipt(Thirdweb.ThirdwebClient,System.Numerics.BigInteger,System.String,System.Threading.CancellationToken) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - client (Thirdweb.ThirdwebClient) + The Thirdweb client. + - chainId (System.Numerics.BigInteger) + The chain ID. + - txHash (string) + The transaction hash. + - cancellationToken (System.Threading.CancellationToken) + The cancellation token. + +SUMMARY: +Waits for the transaction receipt. + +RETURNS: +The transaction receipt. + +-------------------------------------------------------------------------------- +M:Thirdweb.ThirdwebTransaction.WaitForTransactionHash(Thirdweb.ThirdwebClient,System.String,System.Threading.CancellationToken) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - client (Thirdweb.ThirdwebClient) + The Thirdweb client. + - txId (string) + The thirdweb transaction id. + - cancellationToken (System.Threading.CancellationToken) + The cancellation token. + +SUMMARY: +Waits for the transaction hash given a thirdweb transaction id. Use WaitForTransactionReceipt if you have a transaction hash. + +RETURNS: +The transaction hash. + +-------------------------------------------------------------------------------- +M:Thirdweb.ThirdwebTransaction.ConvertToZkSyncTransaction(Thirdweb.ThirdwebTransaction) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - transaction (Thirdweb.ThirdwebTransaction) + The transaction. + +SUMMARY: +Converts the transaction to a zkSync transaction. + +RETURNS: +The zkSync transaction. + +-------------------------------------------------------------------------------- +T:Thirdweb.ThirdwebTransactionInput +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Represents the input parameters for a Thirdweb transaction. + +-------------------------------------------------------------------------------- +P:Thirdweb.ThirdwebTransactionInput.Nonce +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the nonce of the transaction. + +-------------------------------------------------------------------------------- +P:Thirdweb.ThirdwebTransactionInput.From +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the sender address of the transaction. + +-------------------------------------------------------------------------------- +P:Thirdweb.ThirdwebTransactionInput.To +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the recipient address of the transaction. + +-------------------------------------------------------------------------------- +P:Thirdweb.ThirdwebTransactionInput.Gas +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the gas limit for the transaction. + +-------------------------------------------------------------------------------- +P:Thirdweb.ThirdwebTransactionInput.GasPrice +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the gas price for the transaction. + +-------------------------------------------------------------------------------- +P:Thirdweb.ThirdwebTransactionInput.Value +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the value to be transferred in the transaction. + +-------------------------------------------------------------------------------- +P:Thirdweb.ThirdwebTransactionInput.Data +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the data to be sent with the transaction. + +-------------------------------------------------------------------------------- +P:Thirdweb.ThirdwebTransactionInput.MaxFeePerGas +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the maximum fee per gas for the transaction. + +-------------------------------------------------------------------------------- +P:Thirdweb.ThirdwebTransactionInput.MaxPriorityFeePerGas +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the maximum priority fee per gas for the transaction. + +-------------------------------------------------------------------------------- +P:Thirdweb.ThirdwebTransactionInput.ChainId +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the chain ID for the transaction. + +-------------------------------------------------------------------------------- +P:Thirdweb.ThirdwebTransactionInput.ZkSync +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the zkSync options for the transaction. + +-------------------------------------------------------------------------------- +T:Thirdweb.ZkSyncOptions +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Represents the zkSync options for a transaction. + +-------------------------------------------------------------------------------- +P:Thirdweb.ZkSyncOptions.GasPerPubdataByteLimit +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the gas limit per pubdata byte. + +-------------------------------------------------------------------------------- +P:Thirdweb.ZkSyncOptions.FactoryDeps +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the factory dependencies. + +-------------------------------------------------------------------------------- +P:Thirdweb.ZkSyncOptions.Paymaster +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the paymaster. + +-------------------------------------------------------------------------------- +P:Thirdweb.ZkSyncOptions.PaymasterInput +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the paymaster input data. + +-------------------------------------------------------------------------------- +M:Thirdweb.ZkSyncOptions.#ctor(System.String,System.String,System.Nullable{System.Numerics.BigInteger},System.Collections.Generic.List{System.Byte[]}) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - paymaster (string) + The paymaster. + - paymasterInput (string) + The paymaster input data. + - gasPerPubdataByteLimit (Nullable) + The gas limit per pubdata byte. + - factoryDeps (List) + The factory dependencies. + +SUMMARY: +Initializes a new instance of the struct. + +-------------------------------------------------------------------------------- +T:Thirdweb.ThirdwebTransactionReceipt +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Represents the receipt of a transaction. + +-------------------------------------------------------------------------------- +P:Thirdweb.ThirdwebTransactionReceipt.TransactionHash +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the transaction hash. + +-------------------------------------------------------------------------------- +P:Thirdweb.ThirdwebTransactionReceipt.TransactionIndex +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the transaction index within the block. + +-------------------------------------------------------------------------------- +P:Thirdweb.ThirdwebTransactionReceipt.BlockHash +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the hash of the block containing the transaction. + +-------------------------------------------------------------------------------- +P:Thirdweb.ThirdwebTransactionReceipt.BlockNumber +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the number of the block containing the transaction. + +-------------------------------------------------------------------------------- +P:Thirdweb.ThirdwebTransactionReceipt.From +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the address of the sender. + +-------------------------------------------------------------------------------- +P:Thirdweb.ThirdwebTransactionReceipt.To +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the address of the recipient. + +-------------------------------------------------------------------------------- +P:Thirdweb.ThirdwebTransactionReceipt.CumulativeGasUsed +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the cumulative gas used by the transaction. + +-------------------------------------------------------------------------------- +P:Thirdweb.ThirdwebTransactionReceipt.GasUsed +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the gas used by the transaction. + +-------------------------------------------------------------------------------- +P:Thirdweb.ThirdwebTransactionReceipt.EffectiveGasPrice +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the effective gas price for the transaction. + +-------------------------------------------------------------------------------- +P:Thirdweb.ThirdwebTransactionReceipt.ContractAddress +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the contract address created by the transaction, if applicable. + +-------------------------------------------------------------------------------- +P:Thirdweb.ThirdwebTransactionReceipt.Status +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the status of the transaction. + +-------------------------------------------------------------------------------- +P:Thirdweb.ThirdwebTransactionReceipt.Logs +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the logs generated by the transaction. + +-------------------------------------------------------------------------------- +P:Thirdweb.ThirdwebTransactionReceipt.Type +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the transaction type. + +-------------------------------------------------------------------------------- +P:Thirdweb.ThirdwebTransactionReceipt.LogsBloom +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the logs bloom filter. + +-------------------------------------------------------------------------------- +P:Thirdweb.ThirdwebTransactionReceipt.Root +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the root of the transaction. + +-------------------------------------------------------------------------------- +T:Thirdweb.EIP712 +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Provides methods for generating and signing EIP712 compliant messages and transactions. + +-------------------------------------------------------------------------------- +M:Thirdweb.EIP712.GenerateSignature_SmartAccount_7702_WrappedCalls(System.String,System.String,System.Numerics.BigInteger,System.String,Thirdweb.AccountAbstraction.WrappedCalls,Thirdweb.IThirdwebWallet) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - domainName (string) + The domain name. + - version (string) + The version. + - chainId (System.Numerics.BigInteger) + The chain ID. + - verifyingContract (string) + The verifying contract. + - wrappedCalls (Thirdweb.AccountAbstraction.WrappedCalls) + The wrapped calls request. + - signer (Thirdweb.IThirdwebWallet) + The wallet signer. + +SUMMARY: +Generates a signature for a 7702 smart account wrapped calls request. + +-------------------------------------------------------------------------------- +M:Thirdweb.EIP712.GenerateSignature_SmartAccount_7702(System.String,System.String,System.Numerics.BigInteger,System.String,Thirdweb.AccountAbstraction.SessionSpec,Thirdweb.IThirdwebWallet) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - domainName (string) + The domain name. + - version (string) + The version. + - chainId (System.Numerics.BigInteger) + The chain ID. + - verifyingContract (string) + The verifying contract. + - sessionKeyParams (Thirdweb.AccountAbstraction.SessionSpec) + The session key request. + - signer (Thirdweb.IThirdwebWallet) + The wallet signer. + +SUMMARY: +Generates a signature for a 7702 smart account session key. + +RETURNS: +The generated signature. + +-------------------------------------------------------------------------------- +M:Thirdweb.EIP712.GenerateSignature_SmartAccount(System.String,System.String,System.Numerics.BigInteger,System.String,Thirdweb.AccountAbstraction.SignerPermissionRequest,Thirdweb.IThirdwebWallet) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - domainName (string) + The domain name. + - version (string) + The version. + - chainId (System.Numerics.BigInteger) + The chain ID. + - verifyingContract (string) + The verifying contract. + - signerPermissionRequest (Thirdweb.AccountAbstraction.SignerPermissionRequest) + The signer permission request. + - signer (Thirdweb.IThirdwebWallet) + The wallet signer. + +SUMMARY: +Generates a signature for a smart account permission request. + +RETURNS: +The generated signature. + +-------------------------------------------------------------------------------- +M:Thirdweb.EIP712.GenerateSignature_SmartAccount_AccountMessage(System.String,System.String,System.Numerics.BigInteger,System.String,System.Byte[],Thirdweb.IThirdwebWallet) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - domainName (string) + The domain name. + - version (string) + The version. + - chainId (System.Numerics.BigInteger) + The chain ID. + - verifyingContract (string) + The verifying contract. + - message (byte[]) + The message to sign. + - signer (Thirdweb.IThirdwebWallet) + The wallet signer. + +SUMMARY: +Generates a signature for a smart account message. + +RETURNS: +The generated signature. + +-------------------------------------------------------------------------------- +M:Thirdweb.EIP712.GenerateSignature_ZkSyncTransaction(System.String,System.String,System.Numerics.BigInteger,Thirdweb.AccountAbstraction.ZkSyncAATransaction,Thirdweb.IThirdwebWallet) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - domainName (string) + The domain name. + - version (string) + The version. + - chainId (System.Numerics.BigInteger) + The chain ID. + - transaction (Thirdweb.AccountAbstraction.ZkSyncAATransaction) + The zkSync transaction. + - signer (Thirdweb.IThirdwebWallet) + The wallet signer. + +SUMMARY: +Generates a signature for a zkSync transaction. + +RETURNS: +The generated signature. + +-------------------------------------------------------------------------------- +M:Thirdweb.EIP712.GenerateSignature_TokenERC20(System.String,System.String,System.Numerics.BigInteger,System.String,Thirdweb.TokenERC20_MintRequest,Thirdweb.IThirdwebWallet) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - domainName (string) + The domain name. + - version (string) + The version. + - chainId (System.Numerics.BigInteger) + The chain ID. + - verifyingContract (string) + The verifying contract. + - mintRequest (Thirdweb.TokenERC20_MintRequest) + The mint request. + - signer (Thirdweb.IThirdwebWallet) + The wallet signer. + +SUMMARY: +Generates a signature for an ERC20 token mint request. + +RETURNS: +The generated signature. + +-------------------------------------------------------------------------------- +M:Thirdweb.EIP712.GenerateSignature_TokenERC721(System.String,System.String,System.Numerics.BigInteger,System.String,Thirdweb.TokenERC721_MintRequest,Thirdweb.IThirdwebWallet) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - domainName (string) + The domain name. + - version (string) + The version. + - chainId (System.Numerics.BigInteger) + The chain ID. + - verifyingContract (string) + The verifying contract. + - mintRequest (Thirdweb.TokenERC721_MintRequest) + The mint request. + - signer (Thirdweb.IThirdwebWallet) + The wallet signer. + +SUMMARY: +Generates a signature for an ERC721 token mint request. + +RETURNS: +The generated signature. + +-------------------------------------------------------------------------------- +M:Thirdweb.EIP712.GenerateSignature_TokenERC1155(System.String,System.String,System.Numerics.BigInteger,System.String,Thirdweb.TokenERC1155_MintRequest,Thirdweb.IThirdwebWallet) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - domainName (string) + The domain name. + - version (string) + The version. + - chainId (System.Numerics.BigInteger) + The chain ID. + - verifyingContract (string) + The verifying contract. + - mintRequest (Thirdweb.TokenERC1155_MintRequest) + The mint request. + - signer (Thirdweb.IThirdwebWallet) + The wallet signer. + +SUMMARY: +Generates a signature for an ERC1155 token mint request. + +RETURNS: +The generated signature. + +-------------------------------------------------------------------------------- +M:Thirdweb.EIP712.GetTypedDefinition_SmartAccount_7702_WrappedCalls(System.String,System.String,System.Numerics.BigInteger,System.String) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - domainName (string) + The domain name. + - version (string) + The version. + - chainId (System.Numerics.BigInteger) + The chain ID. + - verifyingContract (string) + The verifying contract. + +SUMMARY: +Gets the typed data definition for a 7702 smart account wrapped calls request. + +RETURNS: +The typed data definition. + +-------------------------------------------------------------------------------- +M:Thirdweb.EIP712.GetTypedDefinition_SmartAccount_7702(System.String,System.String,System.Numerics.BigInteger,System.String) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - domainName (string) + The domain name. + - version (string) + The version. + - chainId (System.Numerics.BigInteger) + The chain ID. + - verifyingContract (string) + The verifying contract. + +SUMMARY: +Gets the typed data definition for a 7702 smart account session key. + +RETURNS: +The typed data definition. + +-------------------------------------------------------------------------------- +M:Thirdweb.EIP712.GetTypedDefinition_SmartAccount(System.String,System.String,System.Numerics.BigInteger,System.String) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - domainName (string) + The domain name. + - version (string) + The version. + - chainId (System.Numerics.BigInteger) + The chain ID. + - verifyingContract (string) + The verifying contract. + +SUMMARY: +Gets the typed data definition for a smart account permission request. + +RETURNS: +The typed data definition. + +-------------------------------------------------------------------------------- +M:Thirdweb.EIP712.GetTypedDefinition_SmartAccount_AccountMessage(System.String,System.String,System.Numerics.BigInteger,System.String) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - domainName (string) + The domain name. + - version (string) + The version. + - chainId (System.Numerics.BigInteger) + The chain ID. + - verifyingContract (string) + The verifying contract. + +SUMMARY: +Gets the typed data definition for a smart account message. + +RETURNS: +The typed data definition. + +-------------------------------------------------------------------------------- +M:Thirdweb.EIP712.GetTypedDefinition_ZkSyncTransaction(System.String,System.String,System.Numerics.BigInteger) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - domainName (string) + The domain name. + - version (string) + The version. + - chainId (System.Numerics.BigInteger) + The chain ID. + +SUMMARY: +Gets the typed data definition for a zkSync transaction. + +RETURNS: +The typed data definition. + +-------------------------------------------------------------------------------- +M:Thirdweb.EIP712.GetTypedDefinition_TokenERC20(System.String,System.String,System.Numerics.BigInteger,System.String) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - domainName (string) + The domain name. + - version (string) + The version. + - chainId (System.Numerics.BigInteger) + The chain ID. + - verifyingContract (string) + The verifying contract. + +SUMMARY: +Gets the typed data definition for a TokenERC20 mint request. + +RETURNS: +The typed data definition. + +-------------------------------------------------------------------------------- +M:Thirdweb.EIP712.GetTypedDefinition_TokenERC721(System.String,System.String,System.Numerics.BigInteger,System.String) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - domainName (string) + The domain name. + - version (string) + The version. + - chainId (System.Numerics.BigInteger) + The chain ID. + - verifyingContract (string) + The verifying contract. + +SUMMARY: +Gets the typed data definition for a TokenERC721 mint request. + +RETURNS: +The typed data definition. + +-------------------------------------------------------------------------------- +M:Thirdweb.EIP712.GetTypedDefinition_TokenERC1155(System.String,System.String,System.Numerics.BigInteger,System.String) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - domainName (string) + The domain name. + - version (string) + The version. + - chainId (System.Numerics.BigInteger) + The chain ID. + - verifyingContract (string) + The verifying contract. + +SUMMARY: +Gets the typed data definition for a TokenERC1155 mint request. + +RETURNS: +The typed data definition. + +-------------------------------------------------------------------------------- +M:Thirdweb.EIP712.SerializeEip712(Thirdweb.AccountAbstraction.ZkSyncAATransaction,Nethereum.Signer.EthECDSASignature,System.Numerics.BigInteger) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - transaction (Thirdweb.AccountAbstraction.ZkSyncAATransaction) + The transaction. + - signature (Nethereum.Signer.EthECDSASignature) + The ECDSA signature. + - chainId (System.Numerics.BigInteger) + The chain ID. + +SUMMARY: +Serializes an EIP712 zkSync transaction. + +RETURNS: +The serialized transaction. + +-------------------------------------------------------------------------------- +F:Thirdweb.RLP.SIZE_THRESHOLD +-------------------------------------------------------------------------------- + +KIND: Field + +SUMMARY: +Reason for threshold according to Vitalik Buterin: +- 56 bytes maximizes the benefit of both options +- if we went with 60 then we would have only had 4 slots for long strings +so RLP would not have been able to store objects above 4gb +- if we went with 48 then RLP would be fine for 2^128 space, but that's way too much +- so 56 and 2^64 space seems like the right place to put the cutoff +- also, that's where Bitcoin's varint does the cutof + +-------------------------------------------------------------------------------- +F:Thirdweb.RLP.OFFSET_SHORT_ITEM +-------------------------------------------------------------------------------- + +KIND: Field + +SUMMARY: +[0x80] +If a string is 0-55 bytes long, the RLP encoding consists of a single +byte with value 0x80 plus the length of the string followed by the +string. The range of the first byte is thus [0x80, 0xb7]. + +-------------------------------------------------------------------------------- +F:Thirdweb.RLP.OFFSET_LONG_ITEM +-------------------------------------------------------------------------------- + +KIND: Field + +SUMMARY: +[0xb7] +If a string is more than 55 bytes long, the RLP encoding consists of a +single byte with value 0xb7 plus the length of the length of the string +in binary form, followed by the length of the string, followed by the +string. For example, a length-1024 string would be encoded as +\xb9\x04\x00 followed by the string. The range of the first byte is thus +[0xb8, 0xbf]. + +-------------------------------------------------------------------------------- +F:Thirdweb.RLP.OFFSET_SHORT_LIST +-------------------------------------------------------------------------------- + +KIND: Field + +SUMMARY: +[0xc0] +If the total payload of a list (i.e. the combined length of all its +items) is 0-55 bytes long, the RLP encoding consists of a single byte +with value 0xc0 plus the length of the list followed by the concatenation +of the RLP encodings of the items. The range of the first byte is thus +[0xc0, 0xf7]. + +-------------------------------------------------------------------------------- +F:Thirdweb.RLP.OFFSET_LONG_LIST +-------------------------------------------------------------------------------- + +KIND: Field + +SUMMARY: +[0xf7] +If the total payload of a list is more than 55 bytes long, the RLP +encoding consists of a single byte with value 0xf7 plus the length of the +length of the list in binary form, followed by the length of the list, +followed by the concatenation of the RLP encodings of the items. The +range of the first byte is thus [0xf8, 0xff]. + +-------------------------------------------------------------------------------- +M:Thirdweb.ThirdwebTask.Delay(System.Int32,System.Threading.CancellationToken) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - millisecondsDelay (int) + The number of milliseconds to delay. + - cancellationToken (System.Threading.CancellationToken) + A cancellation token to cancel the delay. + +SUMMARY: +Simulates a delay without using Task.Delay or System.Threading.Timer, specifically designed to avoid clashing with WebGL threading. + +RETURNS: +A task that completes after the specified delay. + +-------------------------------------------------------------------------------- +M:Thirdweb.ThirdwebTask.MinimalDelay(System.Int32) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - milliseconds (int) + The number of milliseconds to delay. + +SUMMARY: +Provides a minimal delay using a manual loop with short sleeps to reduce CPU usage. + +-------------------------------------------------------------------------------- +T:Thirdweb.Utils +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Provides utility methods for various operations. + +-------------------------------------------------------------------------------- +M:Thirdweb.Utils.ComputeClientIdFromSecretKey(System.String) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - secretKey (string) + The secret key. + +SUMMARY: +Computes the client ID from the given secret key. + +RETURNS: +The computed client ID. + +-------------------------------------------------------------------------------- +M:Thirdweb.Utils.HexConcat(System.String[]) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - hexStrings (string[]) + The hex strings to concatenate. + +SUMMARY: +Concatenates the given hex strings. + +RETURNS: +The concatenated hex string. + +-------------------------------------------------------------------------------- +M:Thirdweb.Utils.HashPrefixedMessage(System.Byte[]) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - messageBytes (byte[]) + The message bytes to hash. + +SUMMARY: +Hashes the given message bytes with a prefixed message. + +RETURNS: +The hashed message bytes. + +-------------------------------------------------------------------------------- +M:Thirdweb.Utils.HashPrefixedMessage(System.String) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - message (string) + The message to hash. + +SUMMARY: +Hashes the given message with a prefixed message. + +RETURNS: +The hashed message. + +-------------------------------------------------------------------------------- +M:Thirdweb.Utils.HashMessage(System.Byte[]) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - messageBytes (byte[]) + The message bytes to hash. + +SUMMARY: +Hashes the given message bytes. + +RETURNS: +The hashed message bytes. + +-------------------------------------------------------------------------------- +M:Thirdweb.Utils.HashMessage(System.String) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - message (string) + The message to hash. + +SUMMARY: +Hashes the given message. + +RETURNS: +The hashed message. + +-------------------------------------------------------------------------------- +M:Thirdweb.Utils.BytesToHex(System.Byte[],System.Boolean) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - bytes (byte[]) + The bytes to convert. + - addPrefix (bool) + Whether to add the "0x" prefix. + +SUMMARY: +Converts the given bytes to a hex string. + +RETURNS: +The hex string. + +-------------------------------------------------------------------------------- +M:Thirdweb.Utils.HexToBytes(System.String) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - hex (string) + The hex string to convert. + +SUMMARY: +Converts the given hex string to bytes. + +RETURNS: +The bytes. + +-------------------------------------------------------------------------------- +M:Thirdweb.Utils.HexToBigInt(System.String) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - hex (string) + The hex string to convert. + +SUMMARY: +Converts the given hex string to a big integer. + +RETURNS: +The big integer. + +-------------------------------------------------------------------------------- +M:Thirdweb.Utils.HexToNumber(System.String) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - hex (string) + The hex string to convert. + +SUMMARY: +Converts the given hex string to a big integer. + +RETURNS: +The big integer. + +-------------------------------------------------------------------------------- +M:Thirdweb.Utils.NumberToHex(System.Numerics.BigInteger) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - param1 (System.Numerics.BigInteger) + +SUMMARY: +Converts the given big integer to a hex string. + +-------------------------------------------------------------------------------- +M:Thirdweb.Utils.NumberToHex(System.Int32) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - param1 (int) + +SUMMARY: +Converts the given integer to a hex string. + +-------------------------------------------------------------------------------- +M:Thirdweb.Utils.NumberToHex(System.Int64) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - param1 (long) + +SUMMARY: +Converts the given long to a hex string. + +-------------------------------------------------------------------------------- +M:Thirdweb.Utils.StringToHex(System.String) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - str (string) + The string to convert. + +SUMMARY: +Converts the given string to a hex string. + +RETURNS: +The hex string. + +-------------------------------------------------------------------------------- +M:Thirdweb.Utils.HexToString(System.String) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - hex (string) + The hex string to convert. + +SUMMARY: +Converts the given hex string to a regular string. + +RETURNS: +The regular string. + +-------------------------------------------------------------------------------- +M:Thirdweb.Utils.GetUnixTimeStampNow +-------------------------------------------------------------------------------- + +KIND: Method + +SUMMARY: +Gets the current Unix timestamp. + +RETURNS: +The current Unix timestamp. + +-------------------------------------------------------------------------------- +M:Thirdweb.Utils.GetUnixTimeStampIn10Years +-------------------------------------------------------------------------------- + +KIND: Method + +SUMMARY: +Gets the Unix timestamp for 10 years from now. + +RETURNS: +The Unix timestamp for 10 years from now. + +-------------------------------------------------------------------------------- +M:Thirdweb.Utils.ReplaceIPFS(System.String,System.String) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - uri (string) + The URI to replace. + - gateway (string) + The gateway to use. + +SUMMARY: +Replaces the IPFS URI with a specified gateway. + +RETURNS: +The replaced URI. + +-------------------------------------------------------------------------------- +M:Thirdweb.Utils.ToWei(System.String) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - eth (string) + The ether value to convert. + +SUMMARY: +Converts the given ether value to wei. + +RETURNS: +The wei value. + +-------------------------------------------------------------------------------- +M:Thirdweb.Utils.ToEth(System.String,System.Int32,System.Boolean) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - wei (string) + The wei value to convert. + - decimalsToDisplay (int) + The number of decimals to display. + - addCommas (bool) + Whether to add commas to the output. + +SUMMARY: +Converts the given wei value to ether. + +RETURNS: +The ether value. + +-------------------------------------------------------------------------------- +M:Thirdweb.Utils.FormatERC20(System.String,System.Int32,System.Int32,System.Boolean) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - wei (string) + The wei value to format. + - decimalsToDisplay (int) + The number of decimals to display. + - decimals (int) + The number of decimals of the token. + - addCommas (bool) + Whether to add commas to the output. + +SUMMARY: +Formats the given ERC20 token value. + +RETURNS: +The formatted token value. + +-------------------------------------------------------------------------------- +M:Thirdweb.Utils.GenerateSIWE(Thirdweb.LoginPayloadData) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - loginPayloadData (Thirdweb.LoginPayloadData) + The login payload data. + +SUMMARY: +Generates a Sign-In With Ethereum (SIWE) message. + +RETURNS: +The generated SIWE message. + +-------------------------------------------------------------------------------- +M:Thirdweb.Utils.IsZkSync(Thirdweb.ThirdwebClient,System.Numerics.BigInteger) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - client (Thirdweb.ThirdwebClient) + The Thirdweb client. + - chainId (System.Numerics.BigInteger) + The chain ID. + +SUMMARY: +Checks if the chain ID corresponds to zkSync. + +RETURNS: +True if it is a zkSync chain ID, otherwise false. + +-------------------------------------------------------------------------------- +M:Thirdweb.Utils.ToChecksumAddress(System.String) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - address (string) + The Ethereum address. + +SUMMARY: +Converts an Ethereum address to its checksum format. + +RETURNS: +The checksummed Ethereum address. + +-------------------------------------------------------------------------------- +M:Thirdweb.Utils.AdjustDecimals(System.Numerics.BigInteger,System.Int32,System.Int32) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - value (System.Numerics.BigInteger) + The value. + - fromDecimals (int) + The original number of decimals. + - toDecimals (int) + The target number of decimals. + +SUMMARY: +Adjusts the value's decimals. + +RETURNS: +The value adjusted to the new decimals. + +-------------------------------------------------------------------------------- +M:Thirdweb.Utils.GetSocialProfiles(Thirdweb.ThirdwebClient,System.String) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - client (Thirdweb.ThirdwebClient) + The Thirdweb client. + - addressOrEns (string) + The wallet address or ENS. + +SUMMARY: +Gets the social profiles for the given address or ENS. + +RETURNS: +A object containing the social profiles. + +EXCEPTION (T:System.ArgumentNullException): +Thrown when the address or ENS is null or empty. + +EXCEPTION (T:System.ArgumentException): +Thrown when the address or ENS is invalid. + +EXCEPTION (T:System.Exception): +Thrown when the social profiles could not be fetched. + +-------------------------------------------------------------------------------- +M:Thirdweb.Utils.PreprocessTypedDataJson(System.String) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - json (string) + The typed data JSON. + +SUMMARY: +Preprocesses the typed data JSON to stringify large numbers. + +RETURNS: +The preprocessed typed data JSON. + +-------------------------------------------------------------------------------- +M:Thirdweb.Utils.SerializeErc6492Signature(System.String,System.Byte[],System.Byte[]) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - address (string) + The ERC-4337 Account Factory address + - data (byte[]) + Account deployment calldata (if not deployed) for counterfactual verification + - signature (byte[]) + The original signature + +SUMMARY: +Serializes a signature for use with ERC-6492. The signature must be generated by a signer for an ERC-4337 Account Factory account with counterfactual deployment addresses. + +RETURNS: +The serialized signature hex string. + +-------------------------------------------------------------------------------- +M:Thirdweb.Utils.TrimZeroes(System.Byte[]) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - param1 (byte[]) + +SUMMARY: +Removes leading zeroes from the given byte array. + +-------------------------------------------------------------------------------- +M:Thirdweb.Utils.WaitForTransactionReceipt(Thirdweb.ThirdwebClient,System.Numerics.BigInteger,System.String,System.Threading.CancellationToken) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - client (Thirdweb.ThirdwebClient) + The Thirdweb client. + - chainId (System.Numerics.BigInteger) + The chain ID. + - txHash (string) + The transaction hash. + - cancellationToken (System.Threading.CancellationToken) + The cancellation token. + +SUMMARY: +Waits for the transaction receipt. + +RETURNS: +The transaction receipt. + +-------------------------------------------------------------------------------- +T:Thirdweb.SocialProfiles +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +SocialProfiles object that contains all the different types of social profiles and their respective metadata. + +-------------------------------------------------------------------------------- +T:Thirdweb.EcosystemWallet +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Enclave based secure cross ecosystem wallet. + +-------------------------------------------------------------------------------- +M:Thirdweb.EcosystemWallet.Create(Thirdweb.ThirdwebClient,System.String,System.String,System.String,System.String,Thirdweb.AuthProvider,System.String,Thirdweb.IThirdwebWallet,System.String,System.String,Thirdweb.ExecutionMode) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - ecosystemId (Thirdweb.ThirdwebClient) + Your ecosystem ID (see thirdweb dashboard e.g. ecosystem.the-bonfire). + - ecosystemPartnerId (string) + Your ecosystem partner ID (required if you are integrating someone else's ecosystem). + - client (string) + The Thirdweb client instance. + - email (string) + The email address for Email OTP authentication. + - phoneNumber (string) + The phone number for Phone OTP authentication. + - authProvider (Thirdweb.AuthProvider) + The authentication provider to use. + - storageDirectoryPath (string) + The path to the storage directory. + - siweSigner (Thirdweb.IThirdwebWallet) + The SIWE signer wallet for SIWE authentication. + - walletSecret (string) + The wallet secret for Backend authentication. + - twAuthTokenOverride (string) + The auth token to use for the session. This will automatically connect using a raw thirdweb auth token. + - executionMode (Thirdweb.ExecutionMode) + The execution mode for the wallet. EOA represents traditional direct calls, EIP7702 represents upgraded account self sponsored calls, and EIP7702Sponsored represents upgraded account calls with managed/sponsored execution. + +SUMMARY: +Creates a new instance of the class. + +RETURNS: +A task that represents the asynchronous operation. The task result contains the created in-app wallet. + +EXCEPTION (T:System.ArgumentException): +Thrown when required parameters are not provided. + +-------------------------------------------------------------------------------- +M:Thirdweb.EcosystemWallet.GetUserDetails +-------------------------------------------------------------------------------- + +KIND: Method + +SUMMARY: +Gets the user details from the enclave wallet. For auth provider specific details use GetUserAuthDetails. + +RETURNS: +A task that represents the asynchronous operation. The task result contains the user details. + +-------------------------------------------------------------------------------- +M:Thirdweb.EcosystemWallet.GetUserAuthDetails +-------------------------------------------------------------------------------- + +KIND: Method + +SUMMARY: +Gets the user auth details from the corresponding auth provider. For linked account details use GetUserDetails or GetLinkedAccounts. + +RETURNS: +The user auth details as a JObject + +-------------------------------------------------------------------------------- +M:Thirdweb.EcosystemWallet.GetEcosystemDetails +-------------------------------------------------------------------------------- + +KIND: Method + +SUMMARY: +Returns Ecosystem metadata (set in thirdweb Dashboard) + +RETURNS: +Instance of containing metadata + +EXCEPTION (T:System.InvalidOperationException): +Thrown when called on an InAppWallet + +-------------------------------------------------------------------------------- +M:Thirdweb.EcosystemWallet.GenerateExternalLoginLink(System.String) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - redirectUrl (string) + The URL of your thirdweb-powered website. + +SUMMARY: +Returns a link that can be used to transfer the .NET wallet session to a thirdweb powered React website for seamless integration. + +RETURNS: +The URL to redirect the user to. + +EXCEPTION (T:System.InvalidOperationException): +Thrown when no connected session is found + +-------------------------------------------------------------------------------- +M:Thirdweb.EcosystemWallet.CreateSessionKey(System.Numerics.BigInteger,System.String,System.Int64,System.Boolean,System.Collections.Generic.List{Thirdweb.AccountAbstraction.CallSpec},System.Collections.Generic.List{Thirdweb.AccountAbstraction.TransferSpec},System.Byte[]) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - chainId (System.Numerics.BigInteger) + The chain ID for the session key. + - signerAddress (string) + The address of the signer for the session key. + - durationInSeconds (long) + Duration in seconds for which the session key will be valid. + - grantFullPermissions (bool) + Whether to grant full permissions to the session key. If false, only the specified call and transfer policies will be applied. + - callPolicies (List) + List of call policies to apply to the session key. If null, no call policies will be applied. + - transferPolicies (List) + List of transfer policies to apply to the session key. If null, no transfer policies will be applied. + - uid (byte[]) + A unique identifier for the session key. If null, a new GUID will be generated. + +SUMMARY: +Creates a session key for the user wallet. This is only supported for EIP7702 and EIP7702Sponsored execution modes. + +RETURNS: +A task that represents the asynchronous operation. The task result contains the transaction receipt for the session key creation. + +EXCEPTION (T:System.InvalidOperationException): +Thrown when the execution mode is not EIP7702 or EIP7702Sponsored. + +EXCEPTION (T:System.ArgumentException): +Thrown when the signer address is null or empty, or when the duration is less than or equal to zero. + +-------------------------------------------------------------------------------- +M:Thirdweb.EcosystemWallet.SignerHasFullPermissions(System.Numerics.BigInteger,System.String) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - chainId (System.Numerics.BigInteger) + The chain ID of the EIP7702 account. + - signerAddress (string) + The address of the signer to check permissions for. + +SUMMARY: +Checks if the signer has full permissions on the EIP7702 account. + +RETURNS: +A task that represents the asynchronous operation. The task result contains a boolean indicating whether the signer has full permissions. + +EXCEPTION (T:System.InvalidOperationException): +Thrown when the execution mode is not EIP7702 or EIP7702Sponsored. + +EXCEPTION (T:System.ArgumentException): +Thrown when the signer address is null or empty. + +-------------------------------------------------------------------------------- +M:Thirdweb.EcosystemWallet.GetCallPoliciesForSigner(System.Numerics.BigInteger,System.String) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - chainId (System.Numerics.BigInteger) + The chain ID of the EIP7702 account. + - signerAddress (string) + The address of the signer to get call policies for. + +SUMMARY: +Gets the call policies for a specific signer on the EIP7702 account. + +RETURNS: +A task that represents the asynchronous operation. The task result contains a list of call policies for the signer. + +EXCEPTION (T:System.InvalidOperationException): +Thrown when the execution mode is not EIP7702 or EIP7702Sponsored. + +EXCEPTION (T:System.ArgumentException): +Thrown when the signer address is null or empty. + +-------------------------------------------------------------------------------- +M:Thirdweb.EcosystemWallet.GetTransferPoliciesForSigner(System.Numerics.BigInteger,System.String) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - chainId (System.Numerics.BigInteger) + The chain ID of the EIP7702 account. + - signerAddress (string) + The address of the signer to get transfer policies for. + +SUMMARY: +Gets the transfer policies for a specific signer on the EIP7702 account. + +RETURNS: +A task that represents the asynchronous operation. The task result contains a list of transfer policies for the signer. + +EXCEPTION (T:System.InvalidOperationException): +Thrown when the execution mode is not EIP7702 or EIP7702Sponsored. + +EXCEPTION (T:System.ArgumentException): +Thrown when the signer address is null or empty. + +-------------------------------------------------------------------------------- +M:Thirdweb.EcosystemWallet.GetSessionExpirationForSigner(System.Numerics.BigInteger,System.String) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - chainId (System.Numerics.BigInteger) + The chain ID of the EIP7702 account. + - signerAddress (string) + The address of the signer to get session expiration for. + +SUMMARY: +Gets the session expiration timestamp for a specific signer on the EIP7702 account. + +RETURNS: +A task that represents the asynchronous operation. The task result contains the session expiration timestamp. + +EXCEPTION (T:System.InvalidOperationException): +Thrown when the execution mode is not EIP7702 or EIP7702Sponsored. + +EXCEPTION (T:System.ArgumentException): +Thrown when the signer address is null or empty. + +-------------------------------------------------------------------------------- +M:Thirdweb.EcosystemWallet.GetSessionStateForSigner(System.Numerics.BigInteger,System.String) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - chainId (System.Numerics.BigInteger) + The chain ID of the EIP7702 account. + - signerAddress (string) + The address of the signer to get session state for. + +SUMMARY: +Gets the complete session state for a specific signer on the EIP7702 account, including remaining limits and usage information. + +RETURNS: +A task that represents the asynchronous operation. The task result contains the session state with transfer value limits, call value limits, and call parameter limits. + +EXCEPTION (T:System.InvalidOperationException): +Thrown when the execution mode is not EIP7702 or EIP7702Sponsored. + +EXCEPTION (T:System.ArgumentException): +Thrown when the signer address is null or empty. + +-------------------------------------------------------------------------------- +T:Thirdweb.EcosystemWallet.UserStatusResponse +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +User linked account details. + +-------------------------------------------------------------------------------- +P:Thirdweb.EcosystemWallet.UserStatusResponse.LinkedAccounts +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The user's linked accounts. + +-------------------------------------------------------------------------------- +P:Thirdweb.EcosystemWallet.UserStatusResponse.Wallets +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The user's wallets, generally only one wallet is returned. + +-------------------------------------------------------------------------------- +T:Thirdweb.EcosystemWallet.ShardedOrEnclaveWallet +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Represents a user's embedded wallet. + +-------------------------------------------------------------------------------- +P:Thirdweb.EcosystemWallet.ShardedOrEnclaveWallet.Address +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The public address of the wallet. + +-------------------------------------------------------------------------------- +P:Thirdweb.EcosystemWallet.ShardedOrEnclaveWallet.CreatedAt +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The wallet's creation date. + +-------------------------------------------------------------------------------- +T:Thirdweb.InAppWallet +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Represents an in-app wallet that supports email, phone, social, SIWE and custom authentication. + +-------------------------------------------------------------------------------- +M:Thirdweb.InAppWallet.Create(Thirdweb.ThirdwebClient,System.String,System.String,Thirdweb.AuthProvider,System.String,Thirdweb.IThirdwebWallet,System.String,System.String,Thirdweb.ExecutionMode) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - client (Thirdweb.ThirdwebClient) + The Thirdweb client instance. + - email (string) + The email address for Email OTP authentication. + - phoneNumber (string) + The phone number for Phone OTP authentication. + - authProvider (Thirdweb.AuthProvider) + The authentication provider to use. + - storageDirectoryPath (string) + The path to the storage directory. + - siweSigner (Thirdweb.IThirdwebWallet) + The SIWE signer wallet for SIWE authentication. + - walletSecret (string) + The wallet secret for backend authentication. + - twAuthTokenOverride (string) + The auth token to use for the session. This will automatically connect using a raw thirdweb auth token. + - executionMode (Thirdweb.ExecutionMode) + The execution mode for the wallet. EOA represents traditional direct calls, EIP7702 represents upgraded account self sponsored calls, and EIP7702Sponsored represents upgraded account calls with managed/sponsored execution. + +SUMMARY: +Creates a new instance of the class. + +RETURNS: +A task that represents the asynchronous operation. The task result contains the created in-app wallet. + +EXCEPTION (T:System.ArgumentException): +Thrown when required parameters are not provided. + +-------------------------------------------------------------------------------- +T:Thirdweb.AuthProvider +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Specifies the authentication providers available for the in-app wallet. + +-------------------------------------------------------------------------------- +T:Thirdweb.LinkedAccount +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Represents a linked account. + +-------------------------------------------------------------------------------- +P:Thirdweb.LinkedAccount.Type +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The auth provider method used to create or link this account. + +-------------------------------------------------------------------------------- +P:Thirdweb.LinkedAccount.Details +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Additional details about the linked account. + +-------------------------------------------------------------------------------- +T:Thirdweb.LinkedAccount.LinkedAccountDetails +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +The email, address, phone and id related to the linked account, where applicable. + +-------------------------------------------------------------------------------- +T:Thirdweb.InAppWalletBrowser +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Represents an in-app browser for handling wallet login. + +-------------------------------------------------------------------------------- +M:Thirdweb.InAppWalletBrowser.Login(Thirdweb.ThirdwebClient,System.String,System.String,System.Action{System.String},System.Threading.CancellationToken) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - client (Thirdweb.ThirdwebClient) + The Thirdweb client instance. + - loginUrl (string) + The URL to initiate the login process. + - redirectUrl (string) + The URL to redirect to after login. + - browserOpenAction (System.Action) + An action to open the browser with the login URL. + - cancellationToken (System.Threading.CancellationToken) + Optional cancellation token to cancel the operation. + +SUMMARY: +Initiates a login process using the in-app browser. + +RETURNS: +A task representing the asynchronous operation. The task result contains the login result. + +-------------------------------------------------------------------------------- +M:Thirdweb.InAppWalletBrowser.StopHttpListener +-------------------------------------------------------------------------------- + +KIND: Method + +SUMMARY: +Stops the HTTP listener. + +-------------------------------------------------------------------------------- +M:Thirdweb.InAppWalletBrowser.IncomingHttpRequest(System.IAsyncResult) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - result (System.IAsyncResult) + The result of the asynchronous operation. + +SUMMARY: +Handles incoming HTTP requests. + +-------------------------------------------------------------------------------- +M:Thirdweb.InAppWalletBrowser.AddForwardSlashIfNecessary(System.String) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - url (string) + The URL to check. + +SUMMARY: +Adds a forward slash to the URL if necessary. + +RETURNS: +The URL with a forward slash added if necessary. + +-------------------------------------------------------------------------------- +T:Thirdweb.IThirdwebBrowser +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Defines an interface for handling browser-based login for Thirdweb. + +-------------------------------------------------------------------------------- +M:Thirdweb.IThirdwebBrowser.Login(Thirdweb.ThirdwebClient,System.String,System.String,System.Action{System.String},System.Threading.CancellationToken) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - client (Thirdweb.ThirdwebClient) + The Thirdweb client instance. + - loginUrl (string) + The URL to initiate the login process. + - redirectUrl (string) + The URL to redirect to after login. + - browserOpenAction (System.Action) + An action to open the browser with the login URL. + - cancellationToken (System.Threading.CancellationToken) + Optional cancellation token to cancel the operation. + +SUMMARY: +Initiates a login process using the browser. + +RETURNS: +A task representing the asynchronous operation. The task result contains the login result. + +-------------------------------------------------------------------------------- +T:Thirdweb.BrowserStatus +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Enumerates the possible statuses of a browser operation. + +-------------------------------------------------------------------------------- +F:Thirdweb.BrowserStatus.Success +-------------------------------------------------------------------------------- + +KIND: Field + +SUMMARY: +The operation was successful. + +-------------------------------------------------------------------------------- +F:Thirdweb.BrowserStatus.UserCanceled +-------------------------------------------------------------------------------- + +KIND: Field + +SUMMARY: +The user canceled the operation. + +-------------------------------------------------------------------------------- +F:Thirdweb.BrowserStatus.Timeout +-------------------------------------------------------------------------------- + +KIND: Field + +SUMMARY: +The operation timed out. + +-------------------------------------------------------------------------------- +F:Thirdweb.BrowserStatus.UnknownError +-------------------------------------------------------------------------------- + +KIND: Field + +SUMMARY: +An unknown error occurred during the operation. + +-------------------------------------------------------------------------------- +T:Thirdweb.BrowserResult +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Represents the result of a browser-based login operation. + +-------------------------------------------------------------------------------- +P:Thirdweb.BrowserResult.Status +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets the status of the browser operation. + +-------------------------------------------------------------------------------- +P:Thirdweb.BrowserResult.CallbackUrl +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets the callback URL returned from the browser operation. + +-------------------------------------------------------------------------------- +P:Thirdweb.BrowserResult.Error +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets the error message, if any, from the browser operation. + +-------------------------------------------------------------------------------- +M:Thirdweb.BrowserResult.#ctor(Thirdweb.BrowserStatus,System.String) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - status (Thirdweb.BrowserStatus) + The status of the browser operation. + - callbackUrl (string) + The callback URL returned from the browser operation. + +SUMMARY: +Initializes a new instance of the class with the specified status and callback URL. + +-------------------------------------------------------------------------------- +M:Thirdweb.BrowserResult.#ctor(Thirdweb.BrowserStatus,System.String,System.String) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - status (Thirdweb.BrowserStatus) + The status of the browser operation. + - callbackUrl (string) + The callback URL returned from the browser operation. + - error (string) + The error message from the browser operation. + +SUMMARY: +Initializes a new instance of the class with the specified status, callback URL, and error message. + +-------------------------------------------------------------------------------- +T:Thirdweb.IThirdwebWallet +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Interface for a Thirdweb wallet. + +-------------------------------------------------------------------------------- +P:Thirdweb.IThirdwebWallet.Client +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets the Thirdweb client associated with the wallet. + +-------------------------------------------------------------------------------- +P:Thirdweb.IThirdwebWallet.AccountType +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets the account type of the wallet. + +-------------------------------------------------------------------------------- +P:Thirdweb.IThirdwebWallet.WalletId +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +String identifier for the wallet to be used in analytics. + +-------------------------------------------------------------------------------- +M:Thirdweb.IThirdwebWallet.GetAddress +-------------------------------------------------------------------------------- + +KIND: Method + +SUMMARY: +Gets the address of the wallet. + +RETURNS: +The wallet address. + +-------------------------------------------------------------------------------- +M:Thirdweb.IThirdwebWallet.PersonalSign(System.Byte[]) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - rawMessage (byte[]) + The raw message to sign. + +SUMMARY: +Signs a raw message using personal signing. + +RETURNS: +The signed message. + +-------------------------------------------------------------------------------- +M:Thirdweb.IThirdwebWallet.PersonalSign(System.String) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - message (string) + The message to sign. + +SUMMARY: +Signs a message using personal signing. + +RETURNS: +The signed message. + +-------------------------------------------------------------------------------- +M:Thirdweb.IThirdwebWallet.SignTypedDataV4(System.String) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - json (string) + The JSON representation of the typed data. + +SUMMARY: +Signs typed data (version 4). + +RETURNS: +The signed data. + +-------------------------------------------------------------------------------- +M:Thirdweb.IThirdwebWallet.SignTypedDataV4``2(``0,Nethereum.ABI.EIP712.TypedData{``1}) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - data (``0) + The data to sign. + - typedData (Nethereum.ABI.EIP712.TypedData<``1>) + The typed data. + +SUMMARY: +Signs typed data (version 4). + +TYPEPARAM (T): +The type of the data. + +TYPEPARAM (TDomain): +The type of the domain. + +RETURNS: +The signed data. + +-------------------------------------------------------------------------------- +M:Thirdweb.IThirdwebWallet.IsConnected +-------------------------------------------------------------------------------- + +KIND: Method + +SUMMARY: +Checks if the wallet is connected. + +RETURNS: +True if connected, otherwise false. + +-------------------------------------------------------------------------------- +M:Thirdweb.IThirdwebWallet.SignTransaction(Thirdweb.ThirdwebTransactionInput) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - transaction (Thirdweb.ThirdwebTransactionInput) + The transaction to sign. + +SUMMARY: +Signs a transaction. + +RETURNS: +The signed transaction. + +-------------------------------------------------------------------------------- +M:Thirdweb.IThirdwebWallet.SendTransaction(Thirdweb.ThirdwebTransactionInput) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - transaction (Thirdweb.ThirdwebTransactionInput) + The transaction to send. + +SUMMARY: +Sends a transaction. + +RETURNS: +The transaction hash. + +-------------------------------------------------------------------------------- +M:Thirdweb.IThirdwebWallet.ExecuteTransaction(Thirdweb.ThirdwebTransactionInput) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - transaction (Thirdweb.ThirdwebTransactionInput) + The transaction to execute. + +SUMMARY: +Sends a transaction and waits for its receipt. + +RETURNS: +The transaction receipt. + +-------------------------------------------------------------------------------- +M:Thirdweb.IThirdwebWallet.Disconnect +-------------------------------------------------------------------------------- + +KIND: Method + +SUMMARY: +Disconnects the wallet (if using InAppWallet, clears session) + +-------------------------------------------------------------------------------- +M:Thirdweb.IThirdwebWallet.LinkAccount(Thirdweb.IThirdwebWallet,System.String,System.Nullable{System.Boolean},System.Action{System.String},System.String,Thirdweb.IThirdwebBrowser,System.Nullable{System.Numerics.BigInteger},System.String,System.String,System.String) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - walletToLink (Thirdweb.IThirdwebWallet) + The wallet to link. + - otp (string) + The OTP code if the wallet to link is an email or phone wallet. + - isMobile (Nullable) + Set to true if linking OAuth on mobile. + - browserOpenAction (System.Action) + The action to open the browser if linking OAuth. + - mobileRedirectScheme (string) + The redirect scheme if linking OAuth on mobile. + - browser (Thirdweb.IThirdwebBrowser) + The browser to use if linking OAuth. + - chainId (Nullable) + The chain ID if linking an external wallet (SIWE). + - jwt (string) + The JWT token if linking custom JWT auth. + - payload (string) + The login payload if linking custom AuthEndpoint auth. + - defaultSessionIdOverride (string) + The default session ID override if linking Guest auth. + +SUMMARY: +Links a new account (auth method) to the current wallet. The current wallet must be connected and the wallet being linked must not be fully connected ie created. + +RETURNS: +A list of objects. + +-------------------------------------------------------------------------------- +M:Thirdweb.IThirdwebWallet.UnlinkAccount(Thirdweb.LinkedAccount) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - accountToUnlink (Thirdweb.LinkedAccount) + The linked account to unlink. Same type returned by . + +SUMMARY: +Unlinks an account (auth method) from the current wallet. + +-------------------------------------------------------------------------------- +M:Thirdweb.IThirdwebWallet.GetLinkedAccounts +-------------------------------------------------------------------------------- + +KIND: Method + +SUMMARY: +Returns a list of linked accounts to the current wallet. + +RETURNS: +A list of objects. + +-------------------------------------------------------------------------------- +M:Thirdweb.IThirdwebWallet.SignAuthorization(System.Numerics.BigInteger,System.String,System.Boolean) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - chainId (System.Numerics.BigInteger) + The chain ID of the contract. + - contractAddress (string) + The address of the contract. + - willSelfExecute (bool) + Set to true if the wallet will also be the executor of the transaction, otherwise false. + +SUMMARY: +Signs an EIP-7702 authorization to invoke contract functions to an externally owned account. + +RETURNS: +The signed authorization as an that can be used with . + +-------------------------------------------------------------------------------- +M:Thirdweb.IThirdwebWallet.SwitchNetwork(System.Numerics.BigInteger) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - chainId (System.Numerics.BigInteger) + The chain ID to switch to. + +SUMMARY: +Attempts to set the active network to the specified chain ID. + +-------------------------------------------------------------------------------- +T:Thirdweb.ThirdwebAccountType +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Enum for the types of Thirdweb accounts. + +-------------------------------------------------------------------------------- +T:Thirdweb.LoginPayload +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Represents a login payload. + +-------------------------------------------------------------------------------- +T:Thirdweb.LoginPayloadData +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Represents login payload data. + +-------------------------------------------------------------------------------- +P:Thirdweb.LoginPayloadData.Domain +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the domain of the login payload. + +-------------------------------------------------------------------------------- +P:Thirdweb.LoginPayloadData.Address +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the address of the login payload. + +-------------------------------------------------------------------------------- +P:Thirdweb.LoginPayloadData.Statement +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the statement of the login payload. + +-------------------------------------------------------------------------------- +P:Thirdweb.LoginPayloadData.Uri +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the URI of the login payload. + +-------------------------------------------------------------------------------- +P:Thirdweb.LoginPayloadData.Version +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the version of the login payload. + +-------------------------------------------------------------------------------- +P:Thirdweb.LoginPayloadData.ChainId +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the chain ID of the login payload. + +-------------------------------------------------------------------------------- +P:Thirdweb.LoginPayloadData.Nonce +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the nonce of the login payload. + +-------------------------------------------------------------------------------- +P:Thirdweb.LoginPayloadData.IssuedAt +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the issued at timestamp of the login payload. + +-------------------------------------------------------------------------------- +P:Thirdweb.LoginPayloadData.ExpirationTime +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the expiration time of the login payload. + +-------------------------------------------------------------------------------- +P:Thirdweb.LoginPayloadData.InvalidBefore +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the invalid before timestamp of the login payload. + +-------------------------------------------------------------------------------- +P:Thirdweb.LoginPayloadData.Resources +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the resources of the login payload. + +-------------------------------------------------------------------------------- +M:Thirdweb.LoginPayloadData.#ctor +-------------------------------------------------------------------------------- + +KIND: Method + +SUMMARY: +Initializes a new instance of the class. + +-------------------------------------------------------------------------------- +T:Thirdweb.ServerWallet +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Interact with vault-secured server wallets created from the Thirdweb project dashboard's Transactions tab. + +-------------------------------------------------------------------------------- +M:Thirdweb.ServerWallet.Create(Thirdweb.ThirdwebClient,System.String,Thirdweb.ExecutionOptions,System.String) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - client (Thirdweb.ThirdwebClient) + The Thirdweb client. + - label (string) + The label of your created server wallet. + - executionOptions (Thirdweb.ExecutionOptions) + The execution options for the server wallet, defaults to auto if not passed. + - vaultAccessToken (string) + The vault access token for the server wallet if self-managed. + +SUMMARY: +Creates an instance of the ServerWallet. + +RETURNS: +A new instance of the ServerWallet. + +EXCEPTION (T:System.ArgumentNullException): +Thrown when client or label is null or empty. + +EXCEPTION (T:System.InvalidOperationException): +Thrown when no server wallets are found or the specified label does not match any existing server wallet. + +-------------------------------------------------------------------------------- +T:Thirdweb.ExecutionOptions +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Base class for execution options + +-------------------------------------------------------------------------------- +T:Thirdweb.AutoExecutionOptions +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Auto determine execution options + +-------------------------------------------------------------------------------- +T:Thirdweb.EIP7702ExecutionOptions +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Externally Owned Account (EOA) execution options + +-------------------------------------------------------------------------------- +T:Thirdweb.EOAExecutionOptions +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Externally Owned Account (EOA) execution options + +-------------------------------------------------------------------------------- +T:Thirdweb.ERC4337ExecutionOptions +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +ERC-4337 execution options + +-------------------------------------------------------------------------------- +T:Thirdweb.QueuedTransactionResponse +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Response wrapper for queued transactions + +-------------------------------------------------------------------------------- +T:Thirdweb.QueuedTransactionResult +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Result containing the transactions array + +-------------------------------------------------------------------------------- +T:Thirdweb.QueuedTransaction +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Queued transaction response + +-------------------------------------------------------------------------------- +T:Thirdweb.InnerTransaction +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Inner transaction data + +-------------------------------------------------------------------------------- +M:Thirdweb.SmartWallet.Create(Thirdweb.IThirdwebWallet,System.Numerics.BigInteger,System.Nullable{System.Boolean},System.String,System.String,System.String,System.String,System.String,Thirdweb.TokenPaymaster) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - personalWallet (Thirdweb.IThirdwebWallet) + The smart wallet's signer to use. + - chainId (System.Numerics.BigInteger) + The chain ID. + - gasless (Nullable) + Whether to sponsor gas for transactions. + - factoryAddress (string) + Override the default factory address. + - accountAddressOverride (string) + Override the canonical account address that would be found deterministically based on the signer. + - entryPoint (string) + Override the default entry point address. We provide Constants for different versions. + - bundlerUrl (string) + Override the default thirdweb bundler URL. + - paymasterUrl (string) + Override the default thirdweb paymaster URL. + - tokenPaymaster (Thirdweb.TokenPaymaster) + Use an ERC20 paymaster and sponsor gas with ERC20s. If set, factoryAddress and accountAddressOverride are ignored. + +SUMMARY: +Creates a new instance of . + +RETURNS: +A new instance of . + +EXCEPTION (T:System.InvalidOperationException): +Thrown if the personal account is not connected. + +-------------------------------------------------------------------------------- +M:Thirdweb.SmartWallet.GetPersonalWallet +-------------------------------------------------------------------------------- + +KIND: Method + +SUMMARY: +Returns the signer that was used to connect to this SmartWallet. + +RETURNS: +The signer. + +-------------------------------------------------------------------------------- +M:Thirdweb.SmartWallet.IsDeployed +-------------------------------------------------------------------------------- + +KIND: Method + +SUMMARY: +Checks if the smart account is deployed on the current chain. A smart account is typically deployed when a personal message is signed or a transaction is sent. + +RETURNS: +True if deployed, otherwise false. + +-------------------------------------------------------------------------------- +M:Thirdweb.SmartWallet.ForceDeploy +-------------------------------------------------------------------------------- + +KIND: Method + +SUMMARY: +Forces the smart account to deploy on the current chain. This is typically not necessary as the account will deploy automatically when needed. + +-------------------------------------------------------------------------------- +M:Thirdweb.SmartWallet.IsValidSignature(System.String,System.String) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - message (string) + The message to verify. + - signature (string) + The signature to verify. + +SUMMARY: +Verifies if a signature is valid for a message using EIP-1271 or ERC-6492. + +RETURNS: +True if the signature is valid, otherwise false. + +-------------------------------------------------------------------------------- +M:Thirdweb.SmartWallet.GetAllAdmins +-------------------------------------------------------------------------------- + +KIND: Method + +SUMMARY: +Gets all admins for the smart account. + +RETURNS: +A list of admin addresses. + +-------------------------------------------------------------------------------- +M:Thirdweb.SmartWallet.GetAllActiveSigners +-------------------------------------------------------------------------------- + +KIND: Method + +SUMMARY: +Gets all active signers for the smart account. + +RETURNS: +A list of . + +-------------------------------------------------------------------------------- +M:Thirdweb.SmartWallet.CreateSessionKey(System.String,System.Collections.Generic.List{System.String},System.String,System.String,System.String,System.String,System.String) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - signerAddress (string) + The address of the signer to create a session key for. + - approvedTargets (List) + The list of approved targets for the signer. Use a list of a single Constants.ADDRESS_ZERO to enable all contracts. + - nativeTokenLimitPerTransactionInWei (string) + The maximum amount of native tokens the signer can send in a single transaction. + - permissionStartTimestamp (string) + The timestamp when the permission starts. Can be set to zero. + - permissionEndTimestamp (string) + The timestamp when the permission ends. Make use of our Utils to get UNIX timestamps. + - reqValidityStartTimestamp (string) + The timestamp when the request validity starts. Can be set to zero. + - reqValidityEndTimestamp (string) + The timestamp when the request validity ends. Make use of our Utils to get UNIX timestamps. + +SUMMARY: +Creates a new session key for a signer to use with the smart account. + +-------------------------------------------------------------------------------- +M:Thirdweb.SmartWallet.RevokeSessionKey(System.String) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - signerAddress (string) + The address of the signer to revoke. + +SUMMARY: +Revokes a session key from a signer. + +RETURNS: +The transaction receipt. + +-------------------------------------------------------------------------------- +M:Thirdweb.SmartWallet.AddAdmin(System.String) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - admin (string) + The address of the admin to add. + +SUMMARY: +Adds a new admin to the smart account. + +RETURNS: +The transaction receipt. + +-------------------------------------------------------------------------------- +M:Thirdweb.SmartWallet.RemoveAdmin(System.String) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - admin (string) + The address of the admin to remove. + +SUMMARY: +Removes an existing admin from the smart account. + +RETURNS: +The transaction receipt. + +-------------------------------------------------------------------------------- +M:Thirdweb.SmartWallet.EstimateUserOperationGas(Thirdweb.ThirdwebTransactionInput) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - transaction (Thirdweb.ThirdwebTransactionInput) + The transaction to estimate. + +SUMMARY: +Estimates the gas cost for a user operation. More accurate than ThirdwebTransaction estimation, but slower. + +RETURNS: +The estimated gas cost. + +-------------------------------------------------------------------------------- +M:Thirdweb.SmartWallet.PersonalSign(System.String) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - message (string) + The message to sign. + +SUMMARY: +Signs a message with the personal account. The message will be verified using EIPs 1271 and 6492 if applicable. + +RETURNS: +The signature. + diff --git a/thirdweb.sln b/thirdweb.sln index ae00ee2e..9f425dc9 100644 --- a/thirdweb.sln +++ b/thirdweb.sln @@ -8,6 +8,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Thirdweb.Console", "Thirdwe EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Thirdweb.Tests", "Thirdweb.Tests\Thirdweb.Tests.csproj", "{7CEBE316-4F2E-433B-8B1D-CBE8F8EE328F}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Thirdweb.Generator", "Thirdweb.Generator\Thirdweb.Generator.csproj", "{FC27BC73-7F36-4658-9CBD-940957EE6795}" +EndProject Global GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -33,7 +35,6 @@ Global {98BA8071-A8BF-44A5-9DDC-7BBDE4E732E8}.Release|x64.Build.0 = Release|Any CPU {98BA8071-A8BF-44A5-9DDC-7BBDE4E732E8}.Release|x86.ActiveCfg = Release|Any CPU {98BA8071-A8BF-44A5-9DDC-7BBDE4E732E8}.Release|x86.Build.0 = Release|Any CPU - {D78B4271-7DE9-4C54-BB97-31FBBD25A093}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {D78B4271-7DE9-4C54-BB97-31FBBD25A093}.Debug|Any CPU.Build.0 = Debug|Any CPU {D78B4271-7DE9-4C54-BB97-31FBBD25A093}.Debug|x64.ActiveCfg = Debug|Any CPU @@ -46,7 +47,6 @@ Global {D78B4271-7DE9-4C54-BB97-31FBBD25A093}.Release|x64.Build.0 = Release|Any CPU {D78B4271-7DE9-4C54-BB97-31FBBD25A093}.Release|x86.ActiveCfg = Release|Any CPU {D78B4271-7DE9-4C54-BB97-31FBBD25A093}.Release|x86.Build.0 = Release|Any CPU - {7CEBE316-4F2E-433B-8B1D-CBE8F8EE328F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {7CEBE316-4F2E-433B-8B1D-CBE8F8EE328F}.Debug|Any CPU.Build.0 = Debug|Any CPU {7CEBE316-4F2E-433B-8B1D-CBE8F8EE328F}.Debug|x64.ActiveCfg = Debug|Any CPU @@ -59,5 +59,17 @@ Global {7CEBE316-4F2E-433B-8B1D-CBE8F8EE328F}.Release|x64.Build.0 = Release|Any CPU {7CEBE316-4F2E-433B-8B1D-CBE8F8EE328F}.Release|x86.ActiveCfg = Release|Any CPU {7CEBE316-4F2E-433B-8B1D-CBE8F8EE328F}.Release|x86.Build.0 = Release|Any CPU + {FC27BC73-7F36-4658-9CBD-940957EE6795}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {FC27BC73-7F36-4658-9CBD-940957EE6795}.Debug|Any CPU.Build.0 = Debug|Any CPU + {FC27BC73-7F36-4658-9CBD-940957EE6795}.Debug|x64.ActiveCfg = Debug|Any CPU + {FC27BC73-7F36-4658-9CBD-940957EE6795}.Debug|x64.Build.0 = Debug|Any CPU + {FC27BC73-7F36-4658-9CBD-940957EE6795}.Debug|x86.ActiveCfg = Debug|Any CPU + {FC27BC73-7F36-4658-9CBD-940957EE6795}.Debug|x86.Build.0 = Debug|Any CPU + {FC27BC73-7F36-4658-9CBD-940957EE6795}.Release|Any CPU.ActiveCfg = Release|Any CPU + {FC27BC73-7F36-4658-9CBD-940957EE6795}.Release|Any CPU.Build.0 = Release|Any CPU + {FC27BC73-7F36-4658-9CBD-940957EE6795}.Release|x64.ActiveCfg = Release|Any CPU + {FC27BC73-7F36-4658-9CBD-940957EE6795}.Release|x64.Build.0 = Release|Any CPU + {FC27BC73-7F36-4658-9CBD-940957EE6795}.Release|x86.ActiveCfg = Release|Any CPU + {FC27BC73-7F36-4658-9CBD-940957EE6795}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection EndGlobal