diff --git a/.buildkite/pipeline.yml b/.buildkite/pipeline.yml index 792f06341dd..e8c0d2e3c85 100644 --- a/.buildkite/pipeline.yml +++ b/.buildkite/pipeline.yml @@ -535,8 +535,10 @@ steps: key: windows-testing-bundle depends_on: - trigger-build-windows-artifacts - command: nix build -L -o result/windows-tests .#ci.artifacts.win64.tests - artifact_paths: [ "./result/windows-tests/**" ] + command: | + nix build -L -o result .#ci.artifacts.win64.tests + cp result/cardano-wallet-*-tests-win64.zip ./windows-tests.zip + artifact_paths: [ "./windows-tests.zip"] agents: system: ${linux} @@ -546,11 +548,12 @@ steps: if: build.env("RELEASE_CANDIDATE") == null || build.env("TEST_RC") == "FALSE" steps: - label: Windows Unit Tests - command: | - cd test\e2e - bundle exec rake get_latest_windows_tests[%BUILDKITE_BRANCH%,cardano-wallet-tests-win64,any,latest] - cd cardano-wallet-tests-win64 - .\cardano-wallet-unit-test-unit.exe --color --jobs 1 --skip /Cardano.Wallet.DB.Sqlite/ +RTS -M2G -N2 + commands: + - buildkite-agent artifact download "windows-tests.zip" . + - mkdir -p windows\tests + - tar -xf windows-tests.zip -C windows\tests + - cd windows\tests # tests seem to rely on ..\.. being the repo root + - .\cardano-wallet-unit-test-unit.exe --color --jobs 1 --skip /Cardano.Wallet.DB.Sqlite/ +RTS -M2G -N2 agents: system: ${windows} env: @@ -560,10 +563,10 @@ steps: - label: Windows Text Class Tests command: | - cd test\e2e - bundle exec rake get_latest_windows_tests[%BUILDKITE_BRANCH%,cardano-wallet-tests-win64,any,latest] - cd cardano-wallet-tests-win64 - .\text-class-test-unit.exe --color + buildkite-agent artifact download "windows-tests.zip" . + mkdir windows-tests + tar -xf windows-tests.zip -C windows-tests + .\windows-tests\text-class-test-unit.exe --color agents: system: ${windows} concurrency: 1 @@ -580,7 +583,10 @@ steps: - trigger-windows-e2e-tests commands: - diff -r configs/cardano/preprod lib/integration/configs/cardano/preprod # ensure the configs don't diverge despite being duplicated - - ./scripts/buildkite/main/windows-e2e.bat + - buildkite-agent artifact download "windows-tests.zip" . + - mkdir windows-tests + - tar -xf windows-tests.zip -C windows-tests + - .\windows-tests\cardano-wallet-integration-test-e2e.exe agents: system: ${windows} env: diff --git a/.github/workflows/rubocop.yml b/.github/workflows/rubocop.yml deleted file mode 100644 index 37f46e0b776..00000000000 --- a/.github/workflows/rubocop.yml +++ /dev/null @@ -1,35 +0,0 @@ -name: Rubocop - -on: - push: - branches: [ "master" ] - paths: ['test/e2e/**.rb'] - pull_request: - branches: [ "master" ] - paths: ['test/e2e/**.rb'] - -permissions: - contents: read - -defaults: - run: - working-directory: ./test/e2e - -jobs: - rubocop-linter: - runs-on: ubuntu-latest - - steps: - - name: 📥 Checkout repository - uses: actions/checkout@v3.2.0 - - - name: 💎 Set up Ruby - uses: ruby/setup-ruby@v1 - with: - ruby-version: 3.1.2 - bundler-cache: true - - - name: 👮 Rubocop - run: | - gem install rubocop - rubocop diff --git a/scripts/buildkite/main/windows-e2e.bat b/scripts/buildkite/main/windows-e2e.bat deleted file mode 100755 index 9399fc68a47..00000000000 --- a/scripts/buildkite/main/windows-e2e.bat +++ /dev/null @@ -1,7 +0,0 @@ -set PATH=%PATH%;C:\Users\hal\AppData\Local\Microsoft\WinGet\Links - -cd test\e2e -call bundle install -call bundle exec rake get_latest_windows_tests[%BUILDKITE_BRANCH%,bins,any,latest] -bins\cardano-wallet-integration-test-e2e.exe -exit /b %ERRORLEVEL% diff --git a/test/e2e/.envrc b/test/e2e/.envrc deleted file mode 100644 index fdb3995c2fe..00000000000 --- a/test/e2e/.envrc +++ /dev/null @@ -1,17 +0,0 @@ -if [ -e .envrc-override ]; then - # This env file will trump lorri, if present. - source_env .envrc-override -elif type lorri &>/dev/null; then - eval "$(lorri direnv)" -else - # Fall back to using direnv's builtin nix support - # to prevent bootstrapping problems. - # It's definitely better to use lorri, because direnv won't - # be fast like this. - use flake -fi - -# Source a user-specific config in .envrc-local at the project -# top-level. -# This file can contain your customizations of `env.rb`. -source_env_if_exists ../../.envrc-local diff --git a/test/e2e/.gitattributes b/test/e2e/.gitattributes deleted file mode 100644 index bb362ff9516..00000000000 --- a/test/e2e/.gitattributes +++ /dev/null @@ -1,9 +0,0 @@ -# Pin line endings for genesis files. -# -# Genesis files are -# * human-readable text data -# * but they also have a hash. -# -# `cardano-node` is sensitive to the line endings in the genesis file. -# -/state/configs/*/*.json text eol=lf diff --git a/test/e2e/.gitignore b/test/e2e/.gitignore deleted file mode 100644 index 7286e195758..00000000000 --- a/test/e2e/.gitignore +++ /dev/null @@ -1,26 +0,0 @@ -# data for tests -/bins/ -/state/logs/ -/state/node_db/ -/state/wallet_db/ - -# secrets -/fixtures/fixture_wallets.json - -# local environment variables -/.envrc-local - -# rspec reports and failure tracking -/spec/reports/ -.rspec_status - -# temporary files -/.bundle/ -/tmp/ -/cardano-wallet-*/ -/binaryDist/ -*binary-dist* -*.prv - -# rake -/.rakeTasks/ diff --git a/test/e2e/.rake_tasks~ b/test/e2e/.rake_tasks~ deleted file mode 100644 index f63a6ecdfb9..00000000000 --- a/test/e2e/.rake_tasks~ +++ /dev/null @@ -1,21 +0,0 @@ -clean_bins -clean_logs -clean_node_db -clean_wallet_db -datetime -display_versions -secrets_decode -secrets_encode -fixture_wallets_template -get_docker_logs -get_latest_bins -get_latest_configs -get_latest_node_db -run_on -spec -setup -start_node_and_wallet -stop_node_and_wallet -start_wallet_light -stop_wallet_light -wait_until_node_synced diff --git a/test/e2e/.rspec b/test/e2e/.rspec deleted file mode 100644 index 34c5164d9b5..00000000000 --- a/test/e2e/.rspec +++ /dev/null @@ -1,3 +0,0 @@ ---format documentation ---color ---require spec_helper diff --git a/test/e2e/.rubocop.yml b/test/e2e/.rubocop.yml deleted file mode 100644 index bee05376449..00000000000 --- a/test/e2e/.rubocop.yml +++ /dev/null @@ -1,44 +0,0 @@ -AllCops: - TargetRubyVersion: 3.1 - NewCops: enable - -Metrics/AbcSize: - Enabled: false - -Metrics/ModuleLength: - Enabled: false - -Metrics/BlockLength: - Enabled: false - -Metrics/ClassLength: - Enabled: false - -Layout/LineLength: - Enabled: false - -Layout/TrailingWhitespace: - Enabled: false - -Style/RedundantLineContinuation: - Enabled: false - -Metrics/MethodLength: - Enabled: false - -Metrics/ParameterLists: - Max: 15 - MaxOptionalParameters: 10 - -Naming/VariableNumber: - CheckSymbols: false - -Naming/MethodParameterName: - Enabled: false - -Style/HashSyntax: - EnforcedStyle: no_mixed_keys - EnforcedShorthandSyntax: either - -Style/MixinUsage: - Enabled: false \ No newline at end of file diff --git a/test/e2e/.ruby-version b/test/e2e/.ruby-version deleted file mode 100644 index ef538c28109..00000000000 --- a/test/e2e/.ruby-version +++ /dev/null @@ -1 +0,0 @@ -3.1.2 diff --git a/test/e2e/Gemfile b/test/e2e/Gemfile deleted file mode 100644 index 9e6b7b86c7e..00000000000 --- a/test/e2e/Gemfile +++ /dev/null @@ -1,12 +0,0 @@ -# frozen_string_literal: true - -source 'https://rubygems.org' - -gem 'cardano_wallet', '~> 0.4.2' -# gem 'cardano_wallet', path: "~/wb/cardano_wallet" -gem 'blake2b', '0.10.0' -gem 'buildkit', '1.5' -gem 'cbor', '0.5.9.8' -gem 'mustache', '1.1.1' -gem 'rake', '12.3.3' -gem 'rspec', '3.11.0' diff --git a/test/e2e/Gemfile.lock b/test/e2e/Gemfile.lock deleted file mode 100644 index 18bfb1b8c2b..00000000000 --- a/test/e2e/Gemfile.lock +++ /dev/null @@ -1,58 +0,0 @@ -GEM - remote: https://rubygems.org/ - specs: - addressable (2.8.1) - public_suffix (>= 2.0.2, < 6.0) - bip_mnemonic (0.0.4) - blake2b (0.10.0) - buildkit (1.5.0) - sawyer (>= 0.6) - cardano_wallet (0.4.2) - bip_mnemonic (= 0.0.4) - httparty (~> 0.21.0) - cbor (0.5.9.8) - diff-lcs (1.5.0) - faraday (2.7.1) - faraday-net_http (>= 2.0, < 3.1) - ruby2_keywords (>= 0.0.4) - faraday-net_http (3.0.2) - httparty (0.21.0) - mini_mime (>= 1.0.0) - multi_xml (>= 0.5.2) - mini_mime (1.1.2) - multi_xml (0.6.0) - mustache (1.1.1) - public_suffix (5.0.1) - rake (12.3.3) - rspec (3.11.0) - rspec-core (~> 3.11.0) - rspec-expectations (~> 3.11.0) - rspec-mocks (~> 3.11.0) - rspec-core (3.11.0) - rspec-support (~> 3.11.0) - rspec-expectations (3.11.1) - diff-lcs (>= 1.2.0, < 2.0) - rspec-support (~> 3.11.0) - rspec-mocks (3.11.1) - diff-lcs (>= 1.2.0, < 2.0) - rspec-support (~> 3.11.0) - rspec-support (3.11.1) - ruby2_keywords (0.0.5) - sawyer (0.9.2) - addressable (>= 2.3.5) - faraday (>= 0.17.3, < 3) - -PLATFORMS - ruby - -DEPENDENCIES - blake2b (= 0.10.0) - buildkit (= 1.5) - cardano_wallet (~> 0.4.2) - cbor (= 0.5.9.8) - mustache (= 1.1.1) - rake (= 12.3.3) - rspec (= 3.11.0) - -BUNDLED WITH - 2.4.22 diff --git a/test/e2e/README.md b/test/e2e/README.md deleted file mode 100644 index 8df837cefe2..00000000000 --- a/test/e2e/README.md +++ /dev/null @@ -1,174 +0,0 @@ -# E2E testing - -E2E functional tests of cardano-wallet are running nightly on [cardano preprod testnet](https://book.world.dev.cardano.org/environments.html). Running tests against public testnet allows to exercise cardano-wallet on environment close to production (mainnet) utilizing and integrating maximally all components of the Cardano ecosystem like Stake pools, SMASH, metadata token server etc. - - -## Running tests - -In order to run tests one needs to [have ruby](https://www.ruby-lang.org/en/documentation/installation/) (at least 3.1.2). - -### Configuring test project -1. Get necessary _gems_. -```bash -cd test/e2e -bundle install -``` -2. Decrypt secret files using `$TESTS_E2E_FIXTURES` secret: - - `fixture_wallets.json.gpg` containing mnemonics of testnet fixture wallets - -```bash -export TESTS_E2E_FIXTURES=******* -rake secrets_decode -``` -> :information_source: **_TESTS_E2E_FIXTURES_** secret -Note that this step is also executed on very first test run. -> :information_source: **_TESTS_E2E_FIXTURES_** is also kept in the team's 1Password. - -#### Fixture wallets -The command `rake secrets_decode` can be used to decode the file [fixture_wallets.json.gpg](https://github.com/cardano-foundation/cardano-wallet/blob/master/test/e2e/fixtures/fixture_wallets.json.gpg) into a plain JSON file named `fixture_wallets.json`. This file contains mnemonic sentences of the wallets that are utilized in tests. The test framework will retrieve these wallets from the file. It is important to note that there are separate sets of wallets for different operating systems, namely Linux, MacOS, and Windows. This allows tests to be run in parallel on different operating systems. - -#### Fixture wallets update -If there is a need to update the mnemonics to new ones, it is certainly possible. After making the updates, remember to use the `rake secrets_encode` command to encode the updated plain JSON file into a GPG-encoded file. The updated GPG file then needs to be pushed to the repository so that it can be used by the continuous integration (CI) system. - -> :information_source: There is a utility command `rake fixture_wallets_template` which generates the file `fixture_wallets.json` from scratch with new mnemonic sentences. - -Please note that the wallets used in tests must have ADA and specific assets on their balance. Test ADA can be obtained from the [Faucet](https://docs.cardano.org/cardano-testnet/tools/faucet/). The assets required on the wallet's balance are: - -- SadCoin (with [metadata](https://metadata.world.dev.cardano.org/metadata/ee1ce9d7560f48a4ba3867037dbec2d8fed776d94dd6b00a35309073)) -- HappyCoin (with [metadata](https://metadata.world.dev.cardano.org/metadata/919e8a1922aaa764b1d66407c6f62244e77081215f385b60a62091494861707079436f696e)) - -Both assets have metadata in the [Testnet Metadata Registry](https://github.com/input-output-hk/metadata-registry-testnet), and there are tests in place to ensure that the wallet reads data from there correctly. Both assets can be minted outside of the wallet using tools such as `cardano-cli` or [token-minter](https://github.com/piotr-iohk/token_minter), and then sent to the balances of the fixture wallets. Policy scripts and keys required for minting are availeble in [tests/e2e/fixtuers/wallet_assets](https://github.com/cardano-foundation/cardano-wallet/tree/master/test/e2e/fixtures/wallet_assets). - -#### Further test setup -There may be certain tests that require additional actions to be performed before they can be successfully executed. In such cases, the test will fail and display an appropriate message with instructions. An example of such a test is `AlwaysFails.plutus with collateral return to the wallet`, which requires a specific UTXO to be set up on the testnet where the test will be executed. This setup is a one-time operation and is only necessary when running tests on a new testnet or when the existing testnet has been reset. The scenario is accompanied by detailed comments and step-by-step instructions on how to proceed. If the required actions have not been taken, the test will fail and display the appropriate message. - -### Running all tests -In order to run all `e2e` tests one can simply run single [rake](https://github.com/ruby/rake) task: -```bash -$ rake run_on[preprod] -``` -This master task is performing also all the necessary configuration steps (i.e. getting latest testnet configs and wallet/node binaries from [Cardano Book](https://book.world.dev.cardano.org/environments.html), starting everything up). All steps can also be executed as separate tasks , i.e.: - -```bash -$ rake secrets_decode -$ rake get_latest_bins -$ rake get_latest_configs[preprod] -$ rake start_node_and_wallet[preprod] -$ rake wait_until_node_synced -$ rake spec -$ rake stop_node_and_wallet[preprod] -``` -> :information_source: **_Linux / MacOS_** -cardano-node and cardano-wallet are started as separate [screen](https://www.gnu.org/software/screen/manual/screen.html) sessions. One can attach to the respective session using: ->```bash ->$ screen -r NODE_preprod ->$ screen -r WALLET_preprod ->``` - -> :information_source: **_Windows_** -cardano-node and cardano-wallet are started as separate Windows services using [nssm](https://nssm.cc/) tool. One can examine services using Windows service manager like `services.msc`. - -> :information_source: **_Docker_** -One can also start tests against cardano-wallet docker. There is docker-compose-test.yml provided that includes cardano-node and cardano-wallet. To start it several env variables need to be set to feed docker-compose: ->```bash ->NETWORK=preprod \ ->TESTS_E2E_TOKEN_METADATA=https://metadata.world.dev.cardano.org/ \ ->WALLET=dev-master \ ->NODE=10.1.4 \ ->NODE_CONFIG_PATH=`pwd`/state/configs/$NETWORK \ ->DATA=`pwd`/state/node_db/$NETWORK ->docker-compose -f docker-compose-test.yml up ->``` -> Then running tests against docker is just: ->```bash ->$ rake wait_until_node_synced ->$ rake spec ->``` - -#### Running tests against local wallet -One can also run tests against `cardano-wallet` and `cardano-node` which are specified on machine's `$PATH`: - -```bash -$ TESTS_E2E_BINDIR="" rake run_on[testnet] -``` -Running tests as such skips downloading latest wallet and node binaries. - -### Test artifacts - -By default following locations are used for different artifacts used by the tests: -- `./bins` - location for wallet and node binaries (will be downloaded here from [Buildkite](https://buildkite.com/cardano-foundation/cardano-wallet)) -- `./state` - wallet/node databases, logs and configs - -Locations are relative to `test/e2e` directory. -Default values can be changed by providing environment variables, for instance: - -```bash -TESTS_E2E_STATEDIR=~/state \ -TESTS_E2E_BINDIR=~/bins \ -rake run_on[preprod] -``` -Full list of environment variables is available in `e2e/env.rb`. - -### Running specific tests -There are two types of tests within the suite: - - `e2e` - tests that require node and wallet to be synced with the network (i.e. `rake wait_until_node_synced` step needs to pass before running them) - - `non-e2e` - tests do not require node to be fully synced - -One can run specific tests using by providing `SPEC` or `SPEC_OPTS` arguments to the rake task. For example: - - - run all tests (by default it'll download binaries from Hydra and wait for node to be synced before starting tests) - ```ruby - $ rake run_on[preprod] - ``` - - run only `e2e` tests - ```ruby - $ rake run_on[preprod] SPEC_OPTS="-t e2e" - ``` - - run only `non-e2e` tests on downloaded binaries and don't wait for node to be synced - ```ruby - $ rake run_on[preprod,no-sync] SPEC_OPTS="-t ~e2e" - ``` - - run only tests matching specific string - ```ruby - $ rake run_on[preprod] SPEC_OPTS="-e 'CardanoWallet::Shelley::Wallets'" - ``` - - run only specific test identified by line of test code against node and wallet from the `$PATH` (skips downloading from CI) - ```ruby - $ TESTS_E2E_BINDIR="" rake run_on[preprod] SPEC=spec/shelley_spec.rb:9 - ``` - ->:information_source: Tests can be also executed using `rspec`. - -### Skipping / making test pending - -When test is failing due to a bug it can be marked as `pending`. This mark expects test to fail. When such test actually passes the report will indicate such test as failure indicating that it can be turned on again. - -```ruby -it "Wallet can make multi-address transaction" do - pending "ADP-777 - Failures on multi-address transactions" - ... -end -``` - -Test can be also skipped, so it is not executed at all. - -```ruby -it "Wallet can show utxo distribution" do - skip "This functionality works intermittently - to be investigated" - ... -end -``` - -### Running tests from CI - -There are several steps in the Buildkite pipeline for testing against different platforms (Linux, MacOS, Windows), which can be triggered manually if desired. - -#### Node DB cache - -For speeding up execution in wallet's full mode we use cardano-node DB from cache. Thanks to this we don't have to wait for hours on each execution until cardano-node is synced with the chain. - -## Documentation - -Cardano-wallet-rb repository: https://github.com/piotr-iohk/cardano-wallet-rb. - -Ruby doc: https://piotr-iohk.github.io/cardano-wallet-rb/master/. diff --git a/test/e2e/Rakefile b/test/e2e/Rakefile deleted file mode 100644 index 9cf67096f85..00000000000 --- a/test/e2e/Rakefile +++ /dev/null @@ -1,440 +0,0 @@ -# frozen_string_literal: true - -require 'rspec/core/rake_task' -require 'cardano_wallet' -require_relative 'env' -require_relative 'helpers/utils' -require_relative 'helpers/buildkite' -require 'io/console' - -include Helpers::Utils - -$stdout.sync = true - -STATE = absolute_path ENV.fetch('TESTS_E2E_STATEDIR', nil) -CONFIGS = absolute_path ENV.fetch('CARDANO_NODE_CONFIGS', nil) -LOGS = absolute_path ENV.fetch('TESTS_LOGDIR', nil) -NODE_DB = absolute_path ENV.fetch('TESTS_NODE_DB', nil) -WALLET_DB = absolute_path ENV.fetch('TESTS_WALLET_DB', nil) -NODE_SOCKET_PATH = ENV.fetch('CARDANO_NODE_SOCKET_PATH', nil) - -BINS = absolute_path ENV.fetch('TESTS_E2E_BINDIR', nil) - -FIXTURES_FILE = absolute_path ENV.fetch('TESTS_E2E_FIXTURES_FILE', nil) -FIXTURES_SECRET = ENV.fetch('TESTS_E2E_FIXTURES', nil) - -TOKEN_METADATA = ENV.fetch('TESTS_E2E_TOKEN_METADATA', nil) -WALLET_PORT = ENV.fetch('WALLET_PORT', nil) - -path_separator = win? ? ';' : ':' -ENV['PATH'] = "#{BINS}#{path_separator}#{ENV.fetch('PATH', nil)}" - -RSpec::Core::RakeTask.new(:spec) -task default: :spec - -task :secrets_encode do - desc 'Encode secrets using $TESTS_E2E_FIXTURES phrase' - - log ">> Encoding #{FIXTURES_FILE}..." - log `gpg --pinentry-mode loopback --passphrase=#{FIXTURES_SECRET} --symmetric --output=#{FIXTURES_FILE}.gpg #{FIXTURES_FILE}` -end - -task :secrets_decode do - desc 'Decode secrets using $TESTS_E2E_FIXTURES phrase' - - if File.exist?(FIXTURES_FILE) - log ">> Skipping decoding #{FIXTURES_FILE}.gpg... #{FIXTURES_FILE} already exists!" - else - log ">> Decoding #{FIXTURES_FILE}.gpg..." - log `gpg --pinentry-mode loopback --yes --passphrase=#{FIXTURES_SECRET} --output #{FIXTURES_FILE} --decrypt #{FIXTURES_FILE}.gpg` - end -end - -task :fixture_wallets_template do - log ">> Creating #{FIXTURES_FILE}" - utils = CardanoWallet.new.utils - fixture_wallets = { linux: { - fixture: { shelley: { mnemonics: utils.mnemonic_sentence(24) }, - icarus: { mnemonics: utils.mnemonic_sentence(24) }, - random: { mnemonics: utils.mnemonic_sentence(24) }, - shared: { mnemonics: utils.mnemonic_sentence(24) }, - shared2: { mnemonics: utils.mnemonic_sentence(24) } }, - target: { shelley: { mnemonics: utils.mnemonic_sentence(24) } } - }, - macos: { - fixture: { shelley: { mnemonics: utils.mnemonic_sentence(24) }, - icarus: { mnemonics: utils.mnemonic_sentence(24) }, - random: { mnemonics: utils.mnemonic_sentence(24) }, - shared: { mnemonics: utils.mnemonic_sentence(24) }, - shared2: { mnemonics: utils.mnemonic_sentence(24) } }, - target: { shelley: { mnemonics: utils.mnemonic_sentence(24) } } - }, - windows: { - fixture: { shelley: { mnemonics: utils.mnemonic_sentence(24) }, - icarus: { mnemonics: utils.mnemonic_sentence(24) }, - random: { mnemonics: utils.mnemonic_sentence(24) }, - shared: { mnemonics: utils.mnemonic_sentence(24) }, - shared2: { mnemonics: utils.mnemonic_sentence(24) } }, - target: { shelley: { mnemonics: utils.mnemonic_sentence(24) } } - }, - currency_contract_wallet: { mnemonics: utils.mnemonic_sentence(24) } } - if File.exist?(FIXTURES_FILE) - err = " - File #{FIXTURES_FILE} already exists! - I don't want to overwrite it in case it - contains fixture wallets already... - " - warn err - else - File.write(FIXTURES_FILE, JSON.pretty_generate(fixture_wallets)) - end -end - -task :clean_logs, [:env] do |_task, args| - log '>> Removing logs' - log_dir = File.join(LOGS, args[:env]) - rm_files(log_dir) -end - -task :clean_node_db, [:env] do |_task, args| - log '>> Removing node_db' - rm_files(File.join(NODE_DB, args[:env])) - rm_files(File.join(NODE_DB, "db-#{args[:env]}.tar.gz")) -end - -task :clean_wallet_db, [:env] do |_task, args| - log '>> Removing wallet_db' - rm_files(File.join(WALLET_DB, args[:env])) -end - -task :clean_bins do - log '>> Removing old bins' - rm_files(BINS) -end - -task :wait_until_node_synced do - log '>> Waiting for node to be synced' - - network = CardanoWallet.new.misc.network - # allow 180 mins for connecting to the node in case it needs to replay ledger - timeout = 180 * 60 - current_time = Time.now - timeout_treshold = current_time + timeout - log "Timeout: #{timeout}s" - log "Current time: #{current_time}" - log "Threshold: #{timeout_treshold}" - log 'Waiting for node to start...' - begin - current_time = Time.now - while network.information['sync_progress']['status'] == 'syncing' - log "Syncing node... #{network.information['sync_progress']['progress']['quantity']}%" - - sleep 5 - end - rescue StandardError => e - if current_time <= timeout_treshold - log "Retrying after error #{e}" - sleep 5 - retry - end - raise("[#{Time.now}] Could not connect to wallet within #{timeout} seconds, last error: #{e}") - end - - log '>> Cardano-node and cardano-wallet are synced! <<' -end - -## -# `rake start_node_and_wallet[testnet]' assumes cardano-node and cardano-wallet in $TESTS_E2E_BINDIR -task :start_node_and_wallet, [:env] do |_task, args| - log '>> Setting up cardano-node and cardano-wallet' - - bin_dir = BINS == '' ? BINS : "#{BINS}/" - log ">> Using binaries from '#{bin_dir}'" - config_dir = File.join(CONFIGS, args[:env]) - log ">> Using config directory '#{config_dir}'" - log_dir = File.join(LOGS, args[:env]) - log ">> Using log directory '#{log_dir}'" - wallet_db_dir = File.join(WALLET_DB, args[:env]) - log ">> Using wallet_db directory '#{wallet_db_dir}'" - node_db_dir = File.join(NODE_DB, args[:env]) - log ">> Using node_db directory '#{node_db_dir}'" - cd = Dir.pwd - mk_dir(STATE) - mk_dir(log_dir) - network = args[:env] == 'mainnet' ? '--mainnet' : "--testnet #{config_dir}/byron-genesis.json" - - if win? - # create cardano-node.bat file - node_cmd = "#{bin_dir}cardano-node.exe run --config #{config_dir}/config.json --topology #{config_dir}/topology.json --database-path #{node_db_dir} --socket-path \\\\.\\pipe\\cardano-node-testnet" - log ">> Starting cardano-node with command: #{node_cmd}" - File.write('cardano-node.bat', node_cmd) - - # create cardano-wallet.bat file - wallet_cmd = "#{bin_dir}cardano-wallet.exe serve --port #{WALLET_PORT} --node-socket \\\\.\\pipe\\cardano-node-testnet #{network} --database #{wallet_db_dir} --token-metadata-server #{TOKEN_METADATA}" - File.write('cardano-wallet.bat', wallet_cmd) - - install_node = "nssm install cardano-node #{cd}/cardano-node.bat" - install_wallet = "nssm install cardano-wallet #{cd}/cardano-wallet.bat" - log_stdout_node = "nssm set cardano-node AppStdout #{log_dir}/node.log" - log_stderr_node = "nssm set cardano-node AppStderr #{log_dir}/node.log" - log_stdout_wallet = "nssm set cardano-wallet AppStdout #{log_dir}/wallet.log" - log_stderr_wallet = "nssm set cardano-wallet AppStderr #{log_dir}/wallet.log" - start_node = 'nssm start cardano-node' - start_wallet = 'nssm start cardano-wallet' - - - # echo PATH to help troubleshoot command issues - path = `echo %PATH%` - log ">> path: #{path}" - - cmd install_node - cmd install_wallet - cmd log_stdout_node - cmd log_stderr_node - cmd log_stdout_wallet - cmd log_stderr_wallet - cmd start_node - cmd start_wallet - - else - start_node = <<~CMD - #{bin_dir}cardano-node run \ - --config #{config_dir}/config.json \ - --topology #{config_dir}/topology.json \ - --database-path #{node_db_dir} \ - --socket-path #{NODE_SOCKET_PATH} - CMD - log ">> Starting cardano-node with command: #{start_node}" - # wait a couple of seconds for the node to provide a socket file, at least - sleep 5.0 - - start_wallet = <<~CMD - #{bin_dir}cardano-wallet serve #{network} \ - --port #{WALLET_PORT} \ - --node-socket #{NODE_SOCKET_PATH} \ - --database #{wallet_db_dir} \ - --token-metadata-server #{TOKEN_METADATA} - CMD - log ">> Starting cardano-wallet with command: #{start_wallet}" - cmd <<~CMD - screen -dmS NODE_#{args[:env]} -L \ - -Logfile #{log_dir}/node.log \ - #{start_node} - CMD - cmd <<~CMD - screen -dmS WALLET_#{args[:env]} -L \ - -Logfile #{log_dir}/wallet.log \ - #{start_wallet} - CMD - cmd 'screen -ls', display_result: true - end -end - -task :stop_node_and_wallet, [:env] do |_task, args| - log '>> Stopping cardano-node and cardano-wallet' - - if win? - cmd 'nssm stop cardano-wallet' - cmd 'nssm stop cardano-node' - - cmd 'nssm remove cardano-wallet confirm' - cmd 'nssm remove cardano-node confirm' - else - cmd "screen -S WALLET_#{args[:env]} -X at '0' stuff '^C'" - cmd "screen -XS WALLET_#{args[:env]} quit" - cmd "screen -S NODE_#{args[:env]} -X at '0' stuff '^C'" - cmd "screen -XS NODE_#{args[:env]} quit" - end -end - -task :display_versions, [:bin_dir] do |_task, args| - puts "\n >> cardano-node and cardano-wallet versions:" - bin_dir = args[:bin_dir] || BINS - - if win? - cmd "#{bin_dir}/cardano-wallet.exe version", display_result: true - cmd "#{bin_dir}/cardano-node.exe version", display_result: true - else - cmd "#{bin_dir}/cardano-wallet version", display_result: true - cmd "#{bin_dir}/cardano-node version", display_result: true - end -end - -task :get_latest_windows_tests, [:branch, :destination, :status, :build] do |_task, args| - destination = args[:destination] || 'cardano-wallet-tests-win64' - job_key = 'windows-testing-bundle' - bk = Buildkite.new - status = args[:status] - branch = args[:branch] || 'master' - build = args[:build] || 'latest' - options = status == 'any' ? { branch: branch } : { branch: branch, state: status } - last_build = - build == 'latest' ? bk.last_build_number(options) : build - log "Latest passing buildkite '#{bk.pipeline}' pipeline for branch '#{branch}' is #{last_build}" - jobs = bk.jobs(last_build) - mk_dir(destination) - log "Getting '#{job_key}' artifact 👇" - bk.get_artifacts(last_build, jobs[job_key], destination, 'cardano-wallet-tests-win64.zip', unzip: true) -end - -task :get_bins, [:nb] do |_task, args| - log ">> Getting node and wallet binaries from Buildkite into #{BINS}" - last_build = args[:nb] || 1 - bk = Buildkite.new - log "Latest passing buildkite '#{bk.pipeline}' pipeline build is #{last_build}" - jobs = bk.jobs(last_build) - mk_dir(BINS) - - if linux? - job_key = 'linux-package' - log "Getting '#{job_key}' artifact 👇" - bk.get_artifacts(last_build, jobs[job_key], BINS) - elsif win? - job_key = 'windows-package' - log "Getting '#{job_key}' artifact 👇" - bk.get_artifacts(last_build, jobs[job_key], BINS) - elsif mac? - job_key = 'macos-package' - log "Getting '#{job_key}' artifact 👇" - bk.get_artifacts(last_build, jobs[job_key], BINS) - end -end - -task :get_latest_bins, [:branch, :state] do |_task, args| - log ">> Getting latest node and wallet binaries from Buildkite into #{BINS}" - branch = args[:branch] || 'master' - state = args[:state] || 'any' - filter = state == 'any' ? { branch: branch } : { branch: branch, state: state } - bk = Buildkite.new - last_build = bk.last_build_number(filter) - log "Latest #{filter} buildkite '#{bk.pipeline}' pipeline build is #{last_build}" - jobs = bk.jobs(last_build) - mk_dir(BINS) - - if linux? - job_key = 'linux-package' - log "Getting '#{job_key}' artifact 👇" - bk.get_artifacts(last_build, jobs[job_key], BINS) - elsif win? - job_key = 'windows-package' - log "Getting '#{job_key}' artifact 👇" - bk.get_artifacts(last_build, jobs[job_key], BINS) - elsif mac? - job_key = 'macos-intel-package' - log "Getting '#{job_key}' artifact 👇" - bk.get_artifacts(last_build, jobs[job_key], BINS) - end -end - -task :get_latest_configs, [:env] do |_task, args| - env = args[:env] - out = File.join(CONFIGS, env) - log ">> Getting latest configs in #{out} for '#{env}'" - if File.exist?(out) - # The config directory is probably a /nix/store path - log ">> Using config directory '#{out}'" - else - log ">> Getting latest configs for '#{env}' into #{CONFIGS}" - - base_url = get_latest_configs_base_url(env) - mk_dir(STATE) - mk_dir(CONFIGS) - mk_dir(out) - log ">> Getting latest configs from #{base_url}" - config_file = File.join(out, 'config.json') - wget("#{base_url}config.json", config_file) - wget("#{base_url}byron-genesis.json", "#{out}/byron-genesis.json") - wget("#{base_url}shelley-genesis.json", "#{out}/shelley-genesis.json") - wget("#{base_url}alonzo-genesis.json", "#{out}/alonzo-genesis.json") - wget("#{base_url}conway-genesis.json", "#{out}/conway-genesis.json") - wget("#{base_url}topology.json", "#{out}/topology.json") - log ">> Configs are ready in #{out}" - config_dir = File.join(CONFIGS, args[:env]) - # Temporary/ad-hoc config changes for cardano-node: - config_json = JSON.parse(File.read("#{config_dir}/config.json")) - config_json['EnableP2P'] = false - File.write("#{config_dir}/config.json", JSON.pretty_generate(config_json)) - - topology = %({ - "Producers": [ - { - "addr": "#{ENV.fetch('NETWORK', nil)}-node.world.dev.cardano.org", - "port": 30000, - "valency": 2 - } - ] - }) - File.write("#{config_dir}/topology.json", topology) - log ">> Configs are ready in #{out}" - end -end - -task :get_docker_logs do - log ">> Getting docker logs into #{LOGS}" - - mk_dir(LOGS) - node_logfile = `docker inspect --format='{{.LogPath}}' cardano-node`.gsub("\n", '') - wallet_logfile = `docker inspect --format='{{.LogPath}}' cardano-wallet`.gsub("\n", '') - - cmd "sudo cp #{node_logfile} #{LOGS}/node.log" - cmd "sudo cp #{wallet_logfile} #{LOGS}/wallet.log" - - # Add permissions so logs can be uploaded from workflow - cmd "sudo chmod a+rw #{LOGS}/node.log" - cmd "sudo chmod a+rw #{LOGS}/wallet.log" -end - -## -# Setup utility task getting node and wallet binaries, configs and decoding fixtures -# so it is ready to start -task :setup, [:env, :branch, :skip_bins, :skip_configs] do |_task, args| - log '>> Getting latest binaries and configs and decoding fixtures...' - env = args[:env] - branch = args[:branch] || 'master' - - if args[:skip_bins] - log '>> Skipping getting latest binaries. Will test wallet and node from $PATH.' - else - Rake::Task[:get_latest_bins].invoke(branch) - end - - if args[:skip_configs] - log '>> Skipping getting latest configs.' - else - log '>> Getting latest configs...' - Rake::Task[:get_latest_configs].invoke(env) - end - - Rake::Task[:secrets_decode].invoke -end - -task :run_on, [:env, :sync_strategy, :skip_bins, :skip_configs, :branch] do |_task, args| - log '>> Setting up env and running tests...' - log "TESTS_E2E_STATEDIR=#{STATE}" - env = args[:env] - sync_strategy = args[:sync_strategy] || :sync - branch = args[:branch] || nil - - Rake::Task[:setup].invoke(env, branch, args[:skip_bins], args[:skip_configs]) - Rake::Task[:display_versions].invoke - - Rake::Task[:stop_node_and_wallet].invoke(env) - Rake::Task[:start_node_and_wallet].invoke(env) - - if sync_strategy == 'no-sync' - log '>> Skipping waiting for node to be synced...' - else - Rake::Task[:wait_until_node_synced].invoke - end - - Rake::Task[:spec].invoke - Rake::Task[:stop_node_and_wallet].invoke(env) -end - -## -# print datetime in format that's consistent across different OS -# $ rake datetime -# 20211122-94332 -task :datetime do - puts Time.now.strftime('%Y%m%d-%H%M%S') -end diff --git a/test/e2e/docker-compose-test.yml b/test/e2e/docker-compose-test.yml deleted file mode 100644 index c3474244f96..00000000000 --- a/test/e2e/docker-compose-test.yml +++ /dev/null @@ -1,24 +0,0 @@ -version: "3.5" - -services: - cardano-node: - container_name: cardano-node - image: ghcr.io/intersectmbo/cardano-node:${NODE} - volumes: - - ${DATA}:/data - - ${DATA}:/ipc - - ${NODE_CONFIG_PATH}:/config - command: run --socket-path /ipc/node.socket --config /config/config.json --topology /config/topology.json --database-path /data - restart: on-failure - - cardano-wallet: - container_name: cardano-wallet - image: cardanofoundation/cardano-wallet:${WALLET} - volumes: - - ${WALLET_DATA}:/wallet-db - - ${DATA}:/ipc - - ${NODE_CONFIG_PATH}:/config - ports: - - 8090:8090 - command: serve --testnet /config/byron-genesis.json --node-socket /ipc/node.socket --database /wallet-db --listen-address 0.0.0.0 --token-metadata-server $TESTS_E2E_TOKEN_METADATA - restart: on-failure diff --git a/test/e2e/docker_compose.sh b/test/e2e/docker_compose.sh deleted file mode 100755 index f68714454de..00000000000 --- a/test/e2e/docker_compose.sh +++ /dev/null @@ -1,10 +0,0 @@ -#!/usr/bin/env bash - -NETWORK=preprod \ -TESTS_E2E_TOKEN_METADATA=https://metadata.world.dev.cardano.org/ \ -WALLET=dev-master \ -NODE=10.1.4 \ -NODE_CONFIG_PATH=`pwd`/state/configs/$NETWORK \ -DATA=`pwd`/state/node_db/$NETWORK \ -WALLET_DATA=`pwd`/state/wallet_db/$NETWORK \ -docker-compose -f docker-compose-test.yml $1 diff --git a/test/e2e/env.rb b/test/e2e/env.rb deleted file mode 100644 index 0f2ea6e95c1..00000000000 --- a/test/e2e/env.rb +++ /dev/null @@ -1,34 +0,0 @@ -# frozen_string_literal: true - -## -# secrets 🤫 -# One needs to set these environment variables to run the tests -# on CI they are set in GitHub Secrets -# $ export TESTS_E2E_FIXTURES=... - for decrypting ./fixtures/fixture_wallets.json.gpg -# $ export BUILDKITE_API_TOKEN=... - for downloading artifacts from Buildkite - -# file with mnemonics of fixture wallets -# decoded from ./fixtures/fixture_wallets.json.gpg using $TESTS_E2E_FIXTURES -ENV['TESTS_E2E_FIXTURES_FILE'] ||= './fixtures/fixture_wallets.json' - -## -# Wallet/node databases, logs and configs will be stored here -ENV['TESTS_E2E_STATEDIR'] ||= './state' -ENV['CARDANO_NODE_CONFIGS'] ||= File.join(ENV.fetch('TESTS_E2E_STATEDIR', nil), 'configs') -ENV['TESTS_LOGDIR'] ||= File.join(ENV.fetch('TESTS_E2E_STATEDIR', nil), 'logs') -ENV['TESTS_NODE_DB'] ||= File.join(ENV.fetch('TESTS_E2E_STATEDIR', nil), 'node_db') -ENV['TESTS_WALLET_DB'] ||= File.join(ENV.fetch('TESTS_E2E_STATEDIR', nil), 'wallet_db') - -## -# Wallet/node binaries will be downloaded here from Hydra. -# NOTE: Running `rake run_on[testnet,local]' overrides this and assumes node and wallet on $PATH -ENV['TESTS_E2E_BINDIR'] ||= './bins' - -ENV['TESTS_E2E_TOKEN_METADATA'] ||= 'https://metadata.world.dev.cardano.org' -ENV['TESTS_E2E_SMASH'] ||= 'https://smash.shelley-qa.dev.cardano.org/' -ENV['WALLET_PORT'] ||= '8090' -ENV['NETWORK'] ||= 'preprod' - -## -# Apply workaround for ADP-827 - Deleting wallets sometimes takes >60s in integration tests -ENV['CARDANO_WALLET_TEST_INTEGRATION'] = '1' diff --git a/test/e2e/fixtures/create-wallets.sh b/test/e2e/fixtures/create-wallets.sh deleted file mode 100755 index 44cefbdcb02..00000000000 --- a/test/e2e/fixtures/create-wallets.sh +++ /dev/null @@ -1,142 +0,0 @@ -#!/usr/bin/env bash - -set -euox pipefail - -load_shelley() { - local name=$1 - mnemonics=$(jq -r ".$name" fixture_wallets.json) - - json_data=$( - cat < job_id - def jobs(build_no) - build_details(build_no)[:jobs].to_h { |j| [j[:step_key], j[:id]] } - end - - # get list of artifacts for given job_id - def artifacts(build_no, job_id) - @client.job_artifacts(@org, @pipeline, build_no, job_id) - end - - # get artifact urls for given job_id - def artifact_urls(build_no, job_id) - artifacts(build_no, job_id).map { |a| a[:download_url] } - end - - # artifact url is redirecting to s3 and requires auth, - # so we need to follow it to retrieve the downloadable url - def make_artifact_url_downloadable(url) - r = self.class.get(url, follow_redirects: false, - headers: { 'Authorization' => "Bearer #{@api_token}" }) - r.to_hash['url'] - end - - # we assume that there is only one artifact for given job - def get_artifact_url(build_no, job_id) - make_artifact_url_downloadable(artifact_urls(build_no, job_id).first) - end - - def get_artifacts(build_no, job_id, target_dir, target_file = 'binary-dist', unzip: true) - log "Downloading artifacts for build #{build_no} job #{job_id} to #{target_dir}" - url = get_artifact_url(build_no, job_id) - wget(url, target_file) - unzip_artifact(target_file, target_dir) if unzip - end -end diff --git a/test/e2e/helpers/cardano_addresses.rb b/test/e2e/helpers/cardano_addresses.rb deleted file mode 100644 index ddf45da2de1..00000000000 --- a/test/e2e/helpers/cardano_addresses.rb +++ /dev/null @@ -1,32 +0,0 @@ -# frozen_string_literal: true - -## -# cardano-address cmd helper wrapper -# -class CardanoAddresses - ## - # @param mnemonics - def prv_key_from_recovery_phrase(mnemonics, cmd_params) - cmd(%(echo #{mnemonics.join(' ')}| cardano-address key from-recovery-phrase #{cmd_params})).gsub( - "\n", '' - ) - end - - def key_public(key, with_chain_code: true) - cmd(%(echo #{key}| cardano-address key public #{with_chain_code ? '--with-chain-code' : '--without-chain-code'})).gsub( - "\n", '' - ) - end - - def key_child(key, derivation_path) - cmd(%(echo #{key}| cardano-address key child #{derivation_path})).gsub("\n", '') - end - - def key_walletid(key, templates = '') - cmd(%(echo #{key}| cardano-address key walletid #{templates})).gsub("\n", '') - end - - def script_hash(script) - cmd(%(cardano-address script hash "#{script}")).gsub("\n", '') - end -end diff --git a/test/e2e/helpers/cardano_cli.rb b/test/e2e/helpers/cardano_cli.rb deleted file mode 100644 index 16f5e1bcd94..00000000000 --- a/test/e2e/helpers/cardano_cli.rb +++ /dev/null @@ -1,149 +0,0 @@ -# frozen_string_literal: true - -## -# cardano-cli cmd helper wrapper -# -class CardanoCli - attr_reader :node_state, :socket_path, :protocol_magic - - def initialize(protocol_magic) - @node_state = File.join(absolute_path(ENV.fetch('TESTS_NODE_DB', nil)), CONTEXT.env) - @protocol_magic = protocol_magic - - if win? - @socket_path = '\\\\.\\pipe\\cardano-node-testnet' - else - @socket_path = ENV.fetch('CARDANO_NODE_SOCKET_PATH') - # Add additional permissions to node.socket if we're in e2e docker test suite, - # so cardano-cli can work with cardano-node from the docker container - cmd(%(sudo chmod a+rwx #{@socket_path})) if ENV['E2E_DOCKER_RUN'] == '1' - end - ENV['CARDANO_NODE_SOCKET_PATH'] = @socket_path - end - - def cli(*options) - cmd(%(cardano-cli #{options.join(' ')})) - end - - def build_script_address(script_file_path) - cli('address', 'build', '--payment-script-file', script_file_path, '--testnet-magic', @protocol_magic).strip - end - - def generate_payment_keys - keys = { - payment_vkey: File.join(@node_state, 'payment.vkey'), - payment_skey: File.join(@node_state, 'payment.skey') - } - cli('address', 'key-gen', - '--verification-key-file', keys[:payment_vkey], - '--signing-key-file', keys[:payment_skey]) - keys - end - - def build_payment_address(keys) - cli('address', 'build', - '--payment-verification-key-file', keys[:payment_vkey], - '--testnet-magic', @protocol_magic).strip - end - - ## - # Returns simplified utxo array for an address. - # Parse cardano-cli query utxo output, like: - # TxHash TxIx Amount - # -------------------------------------------------------------------------------------- - # 4f10e314ca4f71031ae2f801638d1671571bc0fa811bd59520b34d3e68ae5344 0 10000000 lovelace + TxOutDatumNone - # f8e12cf50ebf8b0a3d87869f8ca31ed1a95acc77dcc6007997ea97cb9f5a24cd 0 10000000 lovelace + TxOutDatumNone - # - # into: - # @return [Array] - [{utxo: utxoId, ix: index, amt: ada amount}, ...] - def get_utxos(address) - output = cli('query', 'utxo', - '--address', address, - '--testnet-magic', @protocol_magic) - # [utxo1, utxo2, ... utxoN] - # where utxoN = {utxo: utxoId, ix: index, amt: ada amount} - output.partition('-' * 86).last.strip.split("\n").map do |utxo| - utxo_arr = utxo.split - { utxo: utxo_arr[0], ix: utxo_arr[1], amt: utxo_arr[2] } - end - end - - def get_protocol_params_to_file(file = 'pparams.json') - pparams_path = File.join(@node_state, file) - cli('query', 'protocol-parameters', - '--testnet-magic', @protocol_magic, - '--out-file', pparams_path) - pparams_path - end - - def protocol_params - pparams = cli('query', 'protocol-parameters', - '--testnet-magic', @protocol_magic) - JSON.parse(pparams) - end - - ## - # Build (using trasaction build-raw) an invalid transaction that is - # spending from script address and always fails. Using collateral return option. - def tx_build_raw_always_fails(script_file, - script_utxo, - collateral_utxo, - collateral_utxo_amt, - fee, - target_addr, - collateral_ret_addr) - txbody = File.join(@node_state, 'txbody') - cli('conway', 'transaction', 'build-raw', - '--tx-in', script_utxo, - '--tx-out', "#{target_addr}+#{50_000_000 - fee}", - '--tx-in-script-file', script_file, - '--tx-in-datum-value', 1914, - '--tx-in-redeemer-value', 123, - '--tx-in-collateral', collateral_utxo, - '--tx-in-execution-units', '"(10, 10)"', - '--protocol-params-file', get_protocol_params_to_file, - '--fee', fee, - '--tx-out-return-collateral', "#{collateral_ret_addr}+#{collateral_utxo_amt - (fee * 1.5).to_i}", - '--tx-total-collateral', (fee * 1.5).to_i, - '--script-invalid', - '--out-file', txbody) - txbody - end - - def tx_build(*options) - txbody = File.join(@node_state, 'txbody') - cli('conway', 'transaction', 'build', - '--testnet-magic', @protocol_magic, - '--out-file', txbody, - *options) - txbody - end - - def tx_sign(txbody, keys) - txsigned = File.join(@node_state, 'txsigned') - signing_keys = keys.filter { |k, _| k.to_s.end_with?('_skey') }.map { |_, v| "--signing-key-file #{v}" } - cli('conway', 'transaction', 'sign', - '--tx-body-file', txbody, - '--testnet-magic', @protocol_magic, - signing_keys.join(' '), # --signing-key-file key1 --signing-key-file key2 ... - '--out-file', txsigned) - txsigned - end - - # @return [String] - tx id - def tx_submit(txsigned) - # submit - cli('conway', 'transaction', 'submit', - '--tx-file', txsigned, - '--testnet-magic', @protocol_magic) - - # return tx id - cli('conway', 'transaction', 'txid', - '--tx-file', txsigned).strip - end - - def policy_id(script_file) - cli('conway', 'transaction', 'policyid', - '--script-file', script_file).strip - end -end diff --git a/test/e2e/helpers/context.rb b/test/e2e/helpers/context.rb deleted file mode 100644 index 01504cc8fe5..00000000000 --- a/test/e2e/helpers/context.rb +++ /dev/null @@ -1,22 +0,0 @@ -# frozen_string_literal: true - -## -# Class for keeping track of wallet ids. WalletFactory keeps track of the context. -# CONTEXT = Context.new -# WalletFactory.create(:shelley, payload) -# CONTEXT.shelley.each do |wid| -# WalletFactory.delete(:shelley, wid) -# end -class Context - attr_accessor :env, :shelley, :shared, :byron - - def initialize - clear! - end - - def clear! - @shelley = [] - @shared = [] - @byron = [] - end -end diff --git a/test/e2e/helpers/matchers.rb b/test/e2e/helpers/matchers.rb deleted file mode 100644 index 207ea628d89..00000000000 --- a/test/e2e/helpers/matchers.rb +++ /dev/null @@ -1,69 +0,0 @@ -# frozen_string_literal: true - -require 'rspec/expectations' - -RSpec::Matchers.define :be_correct_and_respond do |code| - match do |response| - if code == 204 - response.code == code - else - response.code == code && response.headers >= { 'content-type' => ['application/json;charset=utf-8'] } - end - end - failure_message do |response| - method = response.request.http_method.to_s.split('::').last.upcase - uri = response.request.last_uri - body = response.request.options[:body] - headers = response.request.options[:headers] - - " - The response did not return expected HTTP code or header 'content-type: application/json'! - Expected code = #{code} - Actual code = #{response.code} - - Actual request: - #{method} #{uri} - #{"Body: #{body}" if body} - #{"Headers: #{headers}" if headers} - - Actual response: - #{response} - - Actual response headers: - #{response.headers} - - Time: #{Time.now} - " - end -end - -RSpec::Matchers.define :respond_with do |code| - match do |response| - response.code == code - end - failure_message do |response| - method = response.request.http_method.to_s.split('::').last.upcase - uri = response.request.last_uri - body = response.request.options[:body] - headers = response.request.options[:headers] - - " - The response did not return expected HTTP code! - Expected code = #{code} - Actual code = #{response.code} - - Actual request: - #{method} #{uri} - #{"Body: #{body}" if body} - #{"Headers: #{headers}" if headers} - - Actual response: - #{response} - - Actual response headers: - #{response.headers} - - Time: #{Time.now} - " - end -end diff --git a/test/e2e/helpers/tx_history.rb b/test/e2e/helpers/tx_history.rb deleted file mode 100644 index 34996608265..00000000000 --- a/test/e2e/helpers/tx_history.rb +++ /dev/null @@ -1,129 +0,0 @@ -# frozen_string_literal: true - -# helper methods for inspecting tx history from GET/LIST tx or decoded tx -module TxHistory - def tx_amount(tx, amt) - expect(tx['amount']['quantity'].to_i).to eq amt - end - - def tx_fee(tx, fee) - expect(tx['fee']['quantity'].to_i).to eq fee - end - - def tx_inputs(tx, present: true) - if present - expect(tx['inputs']).not_to eq [] - else - expect(tx['inputs']).to eq [] - end - end - - def tx_outputs(tx, present: true) - if present - expect(tx['outputs']).not_to eq [] - else - expect(tx['outputs']).to eq [] - end - end - - def tx_direction(tx, direction) - expect(tx['direction']).to eq direction - end - - def tx_status(tx, status) - expect(tx['status']).to eq status - end - - def tx_script_validity(tx, validity) - expect(tx['script_validity']).to eq validity - end - - def tx_script_integrity(tx, present: true) - if present - expect(tx['script_integrity']).to start_with 'script_data' - else - expect(tx['script_integrity']).to eq nil - end - end - - def tx_extra_signatures(tx, present: true) - if present - tx['extra_signatures'].each do |e| - expect(e).to start_with 'req_signer_vkh' - end - else - expect(tx['extra_signatures']).to eq [] - end - end - - def tx_collateral(tx, present: true) - if present - expect(tx['collateral']).not_to eq [] - else - expect(tx['collateral']).to eq [] - end - end - - def tx_collateral_outputs(tx, present: true) - if present - expect(tx['collateral_outputs']).not_to eq [] - else - expect(tx['collateral_outputs']).to eq [] - end - end - - def tx_metadata(tx, metadata) - expect(tx['metadata']).to eq metadata - end - - def tx_deposits(tx, deposit_taken: taken_amt, deposit_returned: returned_amt) - expect(tx['deposit_taken']).to eq({ 'quantity' => deposit_taken, 'unit' => 'lovelace' }) - expect(tx['deposit_returned']).to eq({ 'quantity' => deposit_returned, 'unit' => 'lovelace' }) - end - - def tx_withdrawals(tx, present: true) - if present - expect(tx['withdrawals']).not_to eq [] - else - expect(tx['withdrawals']).to eq [] - end - end - - def tx_mint_burn(tx, mint: nil, burn: nil) - expect(tx['mint']['tokens']).to eq mint if mint - expect(tx['burn']['tokens']).to eq burn if burn - end - - def tx_has_mint_or_burn(tx, mint: true, burn: true) - if mint - expect(tx['mint']['tokens']).not_to eq [] - else - expect(tx['mint']['tokens']).to eq [] - end - - if burn - expect(tx['burn']['tokens']).not_to eq [] - else - expect(tx['burn']['tokens']).to eq [] - end - end - - def tx_validity_interval(tx, invalid_before: before, invalid_hereafter: hereafter) - expect(tx['validity_interval']['invalid_before']).to eq({ 'quantity' => invalid_before, 'unit' => 'slot' }) - expect(tx['validity_interval']['invalid_hereafter']).to eq({ 'quantity' => invalid_hereafter, 'unit' => 'slot' }) - end - - def tx_validity_interval_default(tx) - expect(tx['validity_interval']['invalid_before']).to eq({ 'quantity' => 0, 'unit' => 'slot' }) - expect(tx['validity_interval']['invalid_hereafter']['quantity'].positive?).to be true - end - - def tx_certificates(tx, present: true, certificates: nil) - if present - expect(tx['certificates']).not_to eq [] - expect(tx['certificates']).to eq certificates if certificates - else - expect(tx['certificates']).to eq [] - end - end -end diff --git a/test/e2e/helpers/utils.rb b/test/e2e/helpers/utils.rb deleted file mode 100644 index a4a5af97a9e..00000000000 --- a/test/e2e/helpers/utils.rb +++ /dev/null @@ -1,179 +0,0 @@ -# frozen_string_literal: true - -require 'httparty' -require 'fileutils' - -module Helpers - # general utility methods - module Utils - def log(message) - puts "[#{Time.now}] #{message}" - end - - def cmd(cmd, display_result: false) - cmd.gsub(/\s+/, ' ') - res = `#{cmd}` - log cmd if display_result - log res if display_result - res - end - - ## - # Generate Byron address from mnemonic sentence and derivation path - # $ cat mnemonics \ - # | cardano-address key from-recovery-phrase Byron > root.prv - # - # $ cat root.prv \ - # | cardano-address key child 14H/42H | tee addr.prv \ - # | cardano-address key public --with-chain-code \ - # | cardano-address address bootstrap --root $(cat root.prv | cardano-address key public --with-chain-code) \ - # --network-tag testnet 14H/42H - def cardano_address_get_byron_addr(mnemonics, derivation_path) - root = cmd(%(echo #{mnemonics.join(' ')} | cardano-address key from-recovery-phrase Byron | cardano-address key public --with-chain-code)).gsub( - "\n", '' - ) - cmd(%(echo #{mnemonics.join(' ')} \ - | cardano-address key from-recovery-phrase Byron \ - | cardano-address key child #{derivation_path} \ - | cardano-address key public --with-chain-code \ - | cardano-address address bootstrap \ - --root #{root} \ - --network-tag testnet #{derivation_path} - )).gsub("\n", '') - end - - def cardano_address_get_acc_xpub(mnemonics, derivation_path, wallet_type = 'Shared', - chain_code = '--with-chain-code', hex: false) - cmd(%(echo #{mnemonics.join(' ')} \ - | cardano-address key from-recovery-phrase #{wallet_type} \ - | cardano-address key child #{derivation_path} \ - | cardano-address key public #{chain_code} #{' | bech32' if hex})).gsub("\n", '') - end - - def bech32_to_base16(key) - cmd(%(echo #{key} | bech32)).gsub("\n", '') - end - - def hex_to_bytes(str) - str.scan(/../).map { |x| x.hex.chr }.join - end - - def binary_to_hex(binary_as_string) - format('%02x', binary_as_string.to_i(2)) - end - - ## - # encode string asset_name to hex representation - def asset_name(asset_name) - asset_name.unpack1('H*') - end - - def absolute_path(path) - if path.start_with? '.' - File.join(Dir.pwd, path[1..]) - else - path - end - end - - # Get wallet mnemonics/payment template/delegation template from fixures file - # @param kind [Symbol] :fixture or :target (fixture wallet with funds or target wallet) - # @param wallet_type [Symbol] wallet type = :shelley, :shared, :icarus, :random - # @param info_type [Symbol] wallet type = :mnemonics, :payment_template, :delegation_template - def get_fixture_wallet(kind, wallet_type, info_type = :mnemonics) - fixture = ENV.fetch('TESTS_E2E_FIXTURES_FILE', nil) - raise "File #{fixture} does not exist! (Hint: Template fixture file can be created with 'rake fixture_wallets_template'). Make sure to feed it with mnemonics of wallets with funds and assets." unless File.exist? fixture - - wallets = from_json(fixture) - if linux? - wallets[:linux][kind][wallet_type][info_type] - elsif mac? - wallets[:macos][kind][wallet_type][info_type] - elsif win? - wallets[:windows][kind][wallet_type][info_type] - else - raise 'Unsupported platform!' - end - end - - def from_json(file) - JSON.parse(File.read(file), { symbolize_names: true }) - end - - def wget(url, file = nil) - file ||= File.basename(url) - resp = HTTParty.get(url) - File.binwrite(file, resp.body) - log "#{url} -> #{resp.code}" - end - - def unzip_artifact(target_file, target_dir) - log "Unzipping #{target_file} to #{target_dir}" - if win? - cmd "unzip -o #{target_file} -d #{target_dir}" - cmd "del \\f #{target_file}" - else - cmd "tar -xvf #{target_file}" - cmd "cp -r cardano-wallet-*/* #{target_dir}" - cmd "rm -rf cardano-wallet-*/ #{target_file}" - end - end - - def mk_dir(path) - FileUtils.mkdir_p(path) - end - - def rm_files(path) - FileUtils.rm_rf(path, secure: true) - end - - def mv(src, dst) - FileUtils.mv(src, dst, force: true) - end - - def win? - RUBY_PLATFORM =~ /cygwin|mswin|mingw|bccwin|wince|emx/ - end - - def linux? - RUBY_PLATFORM =~ /linux/ - end - - def mac? - RUBY_PLATFORM =~ /darwin/ - end - - ## - # Latest Cardano configs - def get_latest_configs_base_url(env) - envs = %w[preview preprod].freeze - raise "Env '#{env}' is not supported, supported are: #{envs}" unless envs.include? env - - "https://book.world.dev.cardano.org/environments/#{env}/" - end - - ## - # Get protocol magic from byron-genesis.json corresponding to particular env - def get_protocol_magic(env) - config = File.join(absolute_path(ENV.fetch('CARDANO_NODE_CONFIGS', nil)), env) - byron_genesis = JSON.parse(File.read(File.join(config, 'byron-genesis.json'))) - byron_genesis['protocolConsts']['protocolMagic'].to_i - end - - def base64?(value) - value.is_a?(String) && Base64.strict_encode64(Base64.decode64(value)) == value - end - - def base16?(value) - value.is_a?(String) && value.match?(/^[[:xdigit:]]+$/) - end - end -end - -## -# extend String class with hexdump methods -class String - def cbor_to_hex - bytes.map { |x| format('%02x', x) }.join - end -end diff --git a/test/e2e/helpers/wallet_factory.rb b/test/e2e/helpers/wallet_factory.rb deleted file mode 100644 index 065c61942f1..00000000000 --- a/test/e2e/helpers/wallet_factory.rb +++ /dev/null @@ -1,41 +0,0 @@ -# frozen_string_literal: true - -## -# Factory helper for creating and deleting wallets and keeping their ids in shared context. -# Assumes CONTEXT, SHELLEY, SHARED, BYRON to be initialized. -class WalletFactory - def self.create(type, payload) - case type - when :shelley - wallet = SHELLEY.wallets.create(payload) - CONTEXT.shelley << wallet['id'] - wallet - when :shared - wallet = SHARED.wallets.create(payload) - CONTEXT.shared << wallet['id'] - wallet - when :byron - wallet = BYRON.wallets.create(payload) - CONTEXT.byron << wallet['id'] - wallet - else - raise "Unsupported wallet type: #{type}." - end - end - - def self.delete(type, wid) - case type - when :shelley - CONTEXT.shelley.delete(wid) - SHELLEY.wallets.delete(wid) - when :shared - CONTEXT.shared.delete(wid) - SHARED.wallets.delete(wid) - when :byron - CONTEXT.byron.delete(wid) - BYRON.wallets.delete(wid) - else - raise "Unsupported wallet type: #{type}." - end - end -end diff --git a/test/e2e/regenerate-nix.sh b/test/e2e/regenerate-nix.sh deleted file mode 100755 index 264e2809a36..00000000000 --- a/test/e2e/regenerate-nix.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/usr/bin/env bash - -exec nix-shell --run "bundle lock && bundix" diff --git a/test/e2e/run_all_tests.sh b/test/e2e/run_all_tests.sh deleted file mode 100755 index a617e532a90..00000000000 --- a/test/e2e/run_all_tests.sh +++ /dev/null @@ -1,8 +0,0 @@ -#!/usr/bin/env bash - -TESTS_E2E_STATEDIR=./state \ -TESTS_E2E_BINDIR=./bins \ -TESTS_E2E_TOKEN_METADATA=https://metadata.world.dev.cardano.org/ \ -CARDANO_NODE_SOCKET_PATH=./state/node.socket \ -rake stop_node_and_wallet -rake run_on[preprod,sync,skip] diff --git a/test/e2e/spec/byron_spec.rb b/test/e2e/spec/byron_spec.rb deleted file mode 100644 index c8c45572b26..00000000000 --- a/test/e2e/spec/byron_spec.rb +++ /dev/null @@ -1,343 +0,0 @@ -# frozen_string_literal: true - -RSpec.describe CardanoWallet::Byron, :all, :byron do - after(:each) do - teardown - end - - describe CardanoWallet::Byron::Wallets do - it 'I can list byron wallets' do - l = BYRON.wallets.list - expect(l).to be_correct_and_respond 200 - end - - it 'I could get a wallet' do - g = BYRON.wallets.get 'db66f3d0d796c6aa0ad456a36d5a3ee88d62bd5d' - expect(g).to be_correct_and_respond 404 - end - - it 'I could delete a wallet' do - g = BYRON.wallets.delete 'db66f3d0d796c6aa0ad456a36d5a3ee88d62bd5d' - expect(g).to be_correct_and_respond 404 - end - - it 'I can create, get and delete byron icarus wallet from mnemonics' do - payload = { style: 'icarus', - name: 'Wallet from mnemonic_sentence', - passphrase: 'Secure Passphrase', - mnemonic_sentence: CW.utils.mnemonic_sentence(15) } - wallet = WalletFactory.create(:byron, payload) - expect(wallet).to be_correct_and_respond 201 - - wid = wallet['id'] - expect(BYRON.wallets.get(wid)).to be_correct_and_respond 200 - expect(WalletFactory.delete(:byron, wid)).to be_correct_and_respond 204 - end - - it 'I can create, get and delete byron random wallet from mnemonics' do - payload = { style: 'random', - name: 'Wallet from mnemonic_sentence', - passphrase: 'Secure Passphrase', - mnemonic_sentence: CW.utils.mnemonic_sentence(12) } - wallet = WalletFactory.create(:byron, payload) - expect(wallet).to be_correct_and_respond 201 - - wid = wallet['id'] - expect(BYRON.wallets.get(wid)).to be_correct_and_respond 200 - expect(WalletFactory.delete(:byron, wid)).to be_correct_and_respond 204 - end - - describe 'Update wallet' do - matrix = %w[random icarus] - matrix.each do |wallet_style| - it "Can update_metadata of #{wallet_style} wallet" do - w = BYRON.wallets - id = create_byron_wallet(wallet_style) - u = w.update_metadata(id, { name: 'New wallet name' }) - expect(u).to be_correct_and_respond 200 - end - - it "Can update_passphrase of #{wallet_style} wallet" do - w = BYRON.wallets - id = create_byron_wallet(wallet_style) - upd = w.update_passphrase(id, { old_passphrase: 'Secure Passphrase', - new_passphrase: 'Securer Passphrase' }) - expect(upd).to be_correct_and_respond 204 - end - - it "Cannot update_passphrase of #{wallet_style} wallet not knowing old pass" do - w = BYRON.wallets - id = create_byron_wallet(wallet_style) - upd = w.update_passphrase(id, { old_passphrase: 'wrong-passphrase', - new_passphrase: 'Securer Passphrase' }) - expect(upd).to be_correct_and_respond 403 - expect(upd.to_s).to include 'wrong_encryption_passphrase' - end - end - end - - it 'Can see utxo' do - id = create_byron_wallet - utxo = BYRON.wallets.utxo(id) - expect(utxo).to be_correct_and_respond 200 - end - - it 'Can see utxo snapshot' do - id = create_byron_wallet - utxo = BYRON.wallets.utxo_snapshot(id) - expect(utxo).to be_correct_and_respond 200 - end - - describe 'Wallet id' do - matrix = [ - %w[Byron random], - %w[Icarus icarus] - ] - matrix.each do |m| - wallet_type = m[0] - wallet_style = m[1] - it "I can get #{wallet_type} #{wallet_style} walletid using cardano-addresses" do - mnemonics = CW.utils.mnemonic_sentence(24) - wid = create_byron_wallet(wallet_style, 'Wallet - ID', mnemonics) - - # based on root prv key - root_xsk = CA.prv_key_from_recovery_phrase(mnemonics, wallet_type) - ca_wid_root_xsk = CA.key_walletid(root_xsk) - expect(wid).to eq ca_wid_root_xsk - - # based on pub key - pub_key = CA.key_public(root_xsk) - ca_wid_pub_key = CA.key_walletid(pub_key) - expect(wid).to eq ca_wid_pub_key - end - - it "#{wallet_type} walletid is not based on acct key" do - mnemonics = CW.utils.mnemonic_sentence(24) - wid = create_byron_wallet(wallet_style, 'Wallet - ID', mnemonics) - - # based on acct prv key - root_xsk = CA.prv_key_from_recovery_phrase(mnemonics, wallet_type) - acct_key = CA.key_child(root_xsk, '1852H/1815H/0H') - ca_wid_acct_key = CA.key_walletid(acct_key) - - # based on pub key from acct prv key - pub_key = CA.key_public(acct_key) - ca_wid_pub_key = CA.key_walletid(pub_key) - - # wallet id from cardano-wallet is not the same - expect(ca_wid_acct_key).to eq ca_wid_pub_key - expect(wid).not_to eq ca_wid_acct_key - end - end - end - end - - describe CardanoWallet::Byron::Addresses do - it 'Can list addresses - random', :adp_2211 do - id = create_byron_wallet - addresses = BYRON.addresses.list id - expect(addresses).to be_correct_and_respond 200 - expect(addresses.size).to eq 0 - - create_addr = BYRON.addresses.create(id, { passphrase: PASS }) - expect(create_addr).to be_correct_and_respond 201 - - addresses = BYRON.addresses.list id - expect(addresses).to be_correct_and_respond 200 - - expect(addresses.size).to eq 1 - expect(addresses.first['id']).to eq create_addr['id'] - expect(addresses.first['derivation_path'][0]).to eq create_addr['derivation_path'].first - expect(addresses.first['derivation_path'][1]).to eq create_addr['derivation_path'].last - end - - it 'Can list addresses - icarus' do - id = create_byron_wallet 'icarus' - addresses_unused = BYRON.addresses.list id, { state: 'unused' } - expect(addresses_unused).to be_correct_and_respond 200 - - expect(addresses_unused.size).to eq 20 - addresses_unused.each_with_index do |a, i| - expect(a['derivation_path']).to eq ['44H', '1815H', '0H', '0', i.to_s] - end - end - - it 'Can list addresses - ledger' do - id = create_byron_wallet 'ledger' - addresses_unused = BYRON.addresses.list id, { state: 'unused' } - expect(addresses_unused).to be_correct_and_respond 200 - - expect(addresses_unused.size).to eq 20 - addresses_unused.each_with_index do |a, i| - expect(a['derivation_path']).to eq ['44H', '1815H', '0H', '0', i.to_s] - end - end - - it 'Can list addresses - trezor' do - id = create_byron_wallet 'trezor' - addresses_unused = BYRON.addresses.list id, { state: 'unused' } - expect(addresses_unused).to be_correct_and_respond 200 - - expect(addresses_unused.size).to eq 20 - addresses_unused.each_with_index do |a, i| - expect(a['derivation_path']).to eq ['44H', '1815H', '0H', '0', i.to_s] - end - end - - it 'Can create address - random' do - id = create_byron_wallet - addr = BYRON.addresses.create(id, { passphrase: PASS, - address_index: 2_147_483_648 }) - expect(addr).to be_correct_and_respond 201 - expect(addr['derivation_path']).to eq %w[0H 0H] - - addr_r = BYRON.addresses.create(id, { passphrase: PASS }) - expect(addr_r).to be_correct_and_respond 201 - expect(addr_r['derivation_path'][0]).to eq '0H' - expect(addr_r['derivation_path'][1]).to end_with 'H' - end - - it 'I can import address - random' do - mnemonics = CW.utils.mnemonic_sentence(15) - derivation_path = '14H/42H' - id = create_byron_wallet('random', 'Wallet - import', mnemonics) - - addr = cardano_address_get_byron_addr(mnemonics, derivation_path) - - addr_import = BYRON.addresses.import(id, addr) - expect(addr_import).to be_correct_and_respond 204 - - addresses = BYRON.addresses.list id - expect(addresses).to be_correct_and_respond 200 - expect(addresses.size).to eq 1 - expect(addresses.first['derivation_path']).to eq derivation_path.split('/') - end - - it 'I cannot import address - icarus' do - id = create_byron_wallet 'icarus' - addr = BYRON.addresses.list(id)[0]['id'] - addr_import = BYRON.addresses.import(id, addr) - expect(addr_import).to be_correct_and_respond 403 - expect(addr_import.to_s).to include 'invalid_wallet_type' - end - - it 'I cannot import address - ledger' do - id = create_byron_wallet 'ledger' - addr = BYRON.addresses.list(id)[0]['id'] - addr_import = BYRON.addresses.import(id, addr) - expect(addr_import).to be_correct_and_respond 403 - expect(addr_import.to_s).to include 'invalid_wallet_type' - end - - it 'I cannot import address - trezor' do - id = create_byron_wallet 'trezor' - addr = BYRON.addresses.list(id)[0]['id'] - addr_import = BYRON.addresses.import(id, addr) - expect(addr_import).to be_correct_and_respond 403 - expect(addr_import.to_s).to include 'invalid_wallet_type' - end - end - - describe CardanoWallet::Byron::CoinSelections do - it 'I could trigger random coin selection - if had money' do - wid = create_byron_wallet 'icarus' - addresses = BYRON.addresses.list(wid) - addr_amount = [ - { addresses[0]['id'] => MIN_UTXO_VALUE_PURE_ADA }, - { addresses[1]['id'] => MIN_UTXO_VALUE_PURE_ADA } - ] - - rnd = BYRON.coin_selections.random wid, addr_amount - - expect(rnd).to be_correct_and_respond 403 - expect(rnd.to_s).to include 'no_utxos_available' - end - end - - describe CardanoWallet::Byron::Transactions do - # Run for random and icarus - %w[random icarus].each do |style| - it "I could get a tx if I had proper id - #{style}" do - wid = create_byron_wallet style - txs = BYRON.transactions - g = txs.get(wid, TXID) - expect(g).to be_correct_and_respond 404 - expect(g.to_s).to include 'no_such_transaction' - end - - it "Can list transactions - #{style}" do - id = create_byron_wallet style - txs = BYRON.transactions - - expect(txs.list(id)).to be_correct_and_respond 200 - expect(txs.list(id, { max_count: 1 })).to be_correct_and_respond 200 - expect(txs.list(id, - { start: '2012-09-25T10:15:00Z', - end: '2016-11-21T10:15:00Z', - order: 'ascending', - max_count: 10 })) - .to be_correct_and_respond 200 - expect(txs.list(id, { order: 'bad_order' })).to be_correct_and_respond 400 - expect(txs.list(id, { max_count: 'bad_count' })).to be_correct_and_respond 400 - end - - it "I could send tx if I had money - #{style}" do - id = create_byron_wallet style - target_id = create_byron_wallet 'icarus' - target_addr = BYRON.addresses.list(target_id)[0]['id'] - - tx_sent = BYRON.transactions.create(id, PASS, [{ target_addr => 1_000_000 }]) - expect(tx_sent).to be_correct_and_respond 403 - expect(tx_sent.to_s).to include 'no_utxos_available' - end - - it "I could estimate fees if I had money - #{style}" do - id = create_byron_wallet style - target_id = create_byron_wallet 'icarus' - target_addr = BYRON.addresses.list(target_id)[0]['id'] - - fees = BYRON.transactions.payment_fees(id, [{ target_addr => 1_000_000 }]) - expect(fees).to be_correct_and_respond 403 - expect(fees.to_s).to include 'no_utxos_available' - end - - it "I could forget transaction - #{style}" do - id = create_byron_wallet style - txs = BYRON.transactions - res = txs.forget(id, TXID) - expect(res).to be_correct_and_respond 404 - end - end - end - - describe CardanoWallet::Byron::Migrations do - it 'I could create migration plan - icarus' do - id = create_byron_wallet 'icarus' - target_id = create_shelley_wallet - addrs = SHELLEY.addresses.list(target_id).map { |a| a['id'] } - - plan = BYRON.migrations.plan(id, addrs) - expect(plan).to be_correct_and_respond 403 - expect(plan.to_s).to include 'nothing_to_migrate' - end - - it 'I could create migration plan - random' do - id = create_byron_wallet 'random' - target_id = create_shelley_wallet - addrs = SHELLEY.addresses.list(target_id).map { |a| a['id'] } - - plan = BYRON.migrations.plan(id, addrs) - expect(plan).to be_correct_and_respond 403 - expect(plan.to_s).to include 'nothing_to_migrate' - end - - it 'I could migrate all my funds' do - id = create_byron_wallet 'random' - target_wal_id = create_byron_wallet 'icarus' - addresses = BYRON.addresses.list(target_wal_id).map { |a| a['id'] } - migr = BYRON.migrations.migrate(id, PASS, addresses) - expect(migr).to be_correct_and_respond 403 - expect(migr.to_s).to include 'nothing_to_migrate' - end - end -end diff --git a/test/e2e/spec/e2e_shared_spec.rb b/test/e2e/spec/e2e_shared_spec.rb deleted file mode 100644 index f7c7fa8cf2e..00000000000 --- a/test/e2e/spec/e2e_shared_spec.rb +++ /dev/null @@ -1,1549 +0,0 @@ -# frozen_string_literal: true - -RSpec.describe 'Cardano Wallet E2E tests - Shared wallets', :all, :e2e, :shared do - before(:all) do - # shelley wallets - @wid = create_fixture_wallet(:shelley) - @target_id = create_target_wallet(:shelley) - - # shared wallets - @wid_sha = create_fixture_wallet(:shared, :payment_cosigner0_all0, :delegation_cosigner0_all0) - @wid_sha_cos0_all = create_fixture_wallet(:shared, :payment_cosigner0_all, :delegation_cosigner0_all) - @wid_sha_cos1_all = create_fixture_wallet(:shared2, :payment_cosigner1_all, :delegation_cosigner1_all) - @wid_sha_cos0_any = create_fixture_wallet(:shared, :payment_cosigner0_any, :delegation_cosigner0_any) - cos0 = shared_acc_pubkey(@wid_sha_cos0_all) - cos1 = shared_acc_pubkey(@wid_sha_cos1_all) - patch_if_incomplete(@wid_sha_cos0_all, { 'cosigner#1' => cos1 }, { 'cosigner#1' => cos1 }) - patch_if_incomplete(@wid_sha_cos1_all, { 'cosigner#0' => cos0 }, { 'cosigner#0' => cos0 }) - patch_if_incomplete(@wid_sha_cos0_any, { 'cosigner#1' => cos1 }, { 'cosigner#1' => cos1 }) - - @nightly_shared_wallets = [@wid_sha, @wid_sha_cos0_all, @wid_sha_cos1_all, @wid_sha_cos0_any] - @nightly_shelley_wallets = [@wid, @target_id] - wait_for_all_shelley_wallets(@nightly_shelley_wallets) - wait_for_all_shared_wallets(@nightly_shared_wallets) - end - - after(:each) do - teardown - end - - after(:all) do - quit_pool = [{ 'quit' => { 'stake_key_index' => '0H' } }] - tx_constructed = SHARED.transactions.construct(@wid_sha, - nil, # payment - nil, # withdrawal - nil, # metadata - quit_pool, - nil, # mint_burn - nil) # validity_interval - tx_signed = SHARED.transactions.sign(@wid_sha, PASS, tx_constructed['transaction']) - SHARED.transactions.submit(@wid_sha, tx_signed['transaction']) - end - - describe 'E2E Shared' do - describe 'UTxOs' do - it 'Fixture shared wallets have utxos' do - @nightly_shared_wallets.each do |wid| - utxo_stats = SHARED.wallets.utxo(wid) - expect(utxo_stats).to be_correct_and_respond 200 - - utxo_snap = SHARED.wallets.utxo_snapshot(wid) - expect(utxo_snap).to be_correct_and_respond 200 - expect(utxo_snap['entries'].size).to be > 0 - end - end - end - - describe 'E2E Construct -> Sign -> Submit - multi signers' do - it 'Cannot submit if partially signed - one cosigner, all' do - amt = MIN_UTXO_VALUE_PURE_ADA * 2 - src_wid = @wid_sha_cos0_all - target_wid = @target_id - address = SHELLEY.addresses.list(target_wid)[1]['id'] - - tx_constructed = SHARED.transactions.construct(src_wid, payment_payload(amt, address)) - expect(tx_constructed).to be_correct_and_respond 202 - expected_fee = tx_constructed['fee']['quantity'] - - # Can be decoded - tx_decoded = SHARED.transactions.decode(src_wid, tx_constructed['transaction']) - expect(tx_decoded).to be_correct_and_respond 202 - - expect(tx_decoded['id'].size).to be 64 - decoded_fee = tx_decoded['fee']['quantity'] - expect(expected_fee).to eq decoded_fee - - # cosigner0 signs - tx_signed1 = SHARED.transactions.sign(src_wid, PASS, tx_constructed['transaction']) - expect(tx_signed1).to be_correct_and_respond 202 - - # cosigner0 submits - tx_submitted = SHARED.transactions.submit(src_wid, tx_signed1['transaction']) - expect(tx_submitted).to be_correct_and_respond 403 - expect(tx_submitted['code']).to eq 'missing_witnesses_in_transaction' - end - - it 'Cannot submit if tx is foreign - two cosigners, all' do - amt = MIN_UTXO_VALUE_PURE_ADA * 2 - src_wid = @wid_sha_cos0_all - cosigner_wid = @wid_sha_cos1_all - foreign_wid = @wid_sha - target_wid = @target_id - address = SHELLEY.addresses.list(target_wid)[1]['id'] - - tx_constructed = SHARED.transactions.construct(src_wid, payment_payload(amt, address)) - expect(tx_constructed).to be_correct_and_respond 202 - expected_fee = tx_constructed['fee']['quantity'] - - # Can be decoded - tx_decoded = SHARED.transactions.decode(src_wid, tx_constructed['transaction']) - expect(tx_decoded).to be_correct_and_respond 202 - - expect(tx_decoded['id'].size).to be 64 - decoded_fee = tx_decoded['fee']['quantity'] - expect(expected_fee).to eq decoded_fee - - # cosigner0 signs - tx_signed1 = SHARED.transactions.sign(src_wid, PASS, tx_constructed['transaction']) - expect(tx_signed1).to be_correct_and_respond 202 - - # cosigner1 signs - tx_signed = SHARED.transactions.sign(cosigner_wid, PASS, tx_constructed['transaction']) - expect(tx_signed).to be_correct_and_respond 202 - - # foreign submits - tx_submitted = SHARED.transactions.submit(foreign_wid, tx_signed['transaction']) - expect(tx_submitted).to be_correct_and_respond 403 - expect(tx_submitted['code']).to eq 'foreign_transaction' - end - - it 'Single output transaction - two cosigners, all' do - amt = MIN_UTXO_VALUE_PURE_ADA * 2 - src_wid = @wid_sha_cos0_all - cosigner_wid = @wid_sha_cos1_all - target_wid = @target_id - address = SHELLEY.addresses.list(target_wid)[1]['id'] - target_before = get_shelley_balances(target_wid) - src_before = get_shared_balances(src_wid) - - tx_constructed = SHARED.transactions.construct(src_wid, payment_payload(amt, address)) - expect(tx_constructed).to be_correct_and_respond 202 - expected_fee = tx_constructed['fee']['quantity'] - - # Can be decoded - tx_decoded = SHARED.transactions.decode(src_wid, tx_constructed['transaction']) - expect(tx_decoded).to be_correct_and_respond 202 - - expect(tx_decoded['id'].size).to be 64 - decoded_fee = tx_decoded['fee']['quantity'] - expect(expected_fee).to eq decoded_fee - - # cosigner0 signs - tx_signed1 = SHARED.transactions.sign(src_wid, PASS, tx_constructed['transaction']) - expect(tx_signed1).to be_correct_and_respond 202 - - # cosigner1 signs - tx_signed = SHARED.transactions.sign(cosigner_wid, PASS, tx_signed1['transaction']) - expect(tx_signed).to be_correct_and_respond 202 - - # cosigner0 submits - tx_submitted = SHARED.transactions.submit(src_wid, tx_signed['transaction']) - expect(tx_submitted).to be_correct_and_respond 202 - - tx_id = tx_submitted['id'] - wait_for_tx_in_ledger(src_wid, tx_id, SHARED) - verify_tx_status(src_wid, tx_id, 'in_ledger', SHARED) - - target_after = get_shelley_balances(target_wid) - src_after = get_shared_balances(src_wid) - - verify_ada_balance(src_after, src_before, - target_after, target_before, - amt, expected_fee) - # tx history - # on src wallet - tx = SHARED.transactions.get(src_wid, tx_id) - tx_amount(tx, amt + expected_fee) - tx_fee(tx, expected_fee) - tx_inputs(tx, present: true) - tx_outputs(tx, present: true) - tx_direction(tx, 'outgoing') - tx_script_validity(tx, 'valid') - tx_status(tx, 'in_ledger') - tx_collateral(tx, present: false) - tx_collateral_outputs(tx, present: false) - tx_metadata(tx, nil) - tx_deposits(tx, deposit_taken: 0, deposit_returned: 0) - tx_withdrawals(tx, present: false) - tx_mint_burn(tx, mint: [], burn: []) - tx_extra_signatures(tx, present: false) - tx_script_integrity(tx, present: false) - tx_validity_interval_default(tx) - tx_certificates(tx, present: false) - - # on co-signer wid - tx = SHARED.transactions.get(cosigner_wid, tx_id) - tx_amount(tx, amt + expected_fee) - tx_fee(tx, expected_fee) - tx_inputs(tx, present: true) - tx_outputs(tx, present: true) - tx_direction(tx, 'outgoing') - tx_script_validity(tx, 'valid') - tx_status(tx, 'in_ledger') - tx_collateral(tx, present: false) - tx_collateral_outputs(tx, present: false) - tx_metadata(tx, nil) - tx_deposits(tx, deposit_taken: 0, deposit_returned: 0) - tx_withdrawals(tx, present: false) - tx_mint_burn(tx, mint: [], burn: []) - tx_extra_signatures(tx, present: false) - tx_script_integrity(tx, present: false) - tx_validity_interval_default(tx) - tx_certificates(tx, present: false) - - # on target wallet - txt = SHELLEY.transactions.get(target_wid, tx_id) - tx_amount(txt, amt) - tx_fee(tx, expected_fee) - tx_inputs(txt, present: true) - tx_outputs(txt, present: true) - tx_direction(txt, 'incoming') - tx_script_validity(txt, 'valid') - tx_status(txt, 'in_ledger') - tx_collateral(txt, present: false) - tx_collateral_outputs(txt, present: false) - tx_metadata(txt, nil) - # ADP-2298 - Deposit_returned is falsely reported on some incoming transactions (intermittently) - # tx_deposits(txt, deposit_taken: 0, deposit_returned: 0) - tx_withdrawals(txt, present: false) - tx_mint_burn(txt, mint: [], burn: []) - tx_extra_signatures(txt, present: false) - tx_script_integrity(txt, present: false) - tx_validity_interval_default(txt) - tx_certificates(txt, present: false) - end - - it 'Multi output transaction - two cosigners, all' do - amt = MIN_UTXO_VALUE_PURE_ADA - src_wid = @wid_sha_cos0_all - cosigner_wid = @wid_sha_cos1_all - target_wid = @target_id - address = SHELLEY.addresses.list(target_wid)[1]['id'] - target_before = get_shelley_balances(target_wid) - src_before = get_shared_balances(src_wid) - payment = [{ address: address, - amount: { quantity: amt, - unit: 'lovelace' } }, - { address: address, - amount: { quantity: amt, - unit: 'lovelace' } }] - - tx_constructed = SHARED.transactions.construct(src_wid, payment) - expect(tx_constructed).to be_correct_and_respond 202 - expected_fee = tx_constructed['fee']['quantity'] - - # Can be decoded - tx_decoded = SHARED.transactions.decode(src_wid, tx_constructed['transaction']) - expect(tx_decoded).to be_correct_and_respond 202 - - expect(tx_decoded['id'].size).to be 64 - decoded_fee = tx_decoded['fee']['quantity'] - expect(expected_fee).to eq decoded_fee - - # cosigner0 signs - tx_signed1 = SHARED.transactions.sign(src_wid, PASS, tx_constructed['transaction']) - expect(tx_signed1).to be_correct_and_respond 202 - - # cosigner1 signs - tx_signed = SHARED.transactions.sign(cosigner_wid, PASS, tx_signed1['transaction']) - expect(tx_signed).to be_correct_and_respond 202 - - # cosigner1 submits - tx_submitted = SHARED.transactions.submit(cosigner_wid, tx_signed['transaction']) - expect(tx_submitted).to be_correct_and_respond 202 - - tx_id = tx_submitted['id'] - wait_for_tx_in_ledger(src_wid, tx_id, SHARED) - verify_tx_status(cosigner_wid, tx_id, 'in_ledger', SHARED) - - target_after = get_shelley_balances(target_wid) - src_after = get_shared_balances(src_wid) - - verify_ada_balance(src_after, src_before, - target_after, target_before, - amt * 2, expected_fee) - # tx history - # on src wallet - tx = SHARED.transactions.get(src_wid, tx_id) - tx_amount(tx, (amt * 2) + expected_fee) - tx_fee(tx, expected_fee) - tx_inputs(tx, present: true) - tx_outputs(tx, present: true) - tx_direction(tx, 'outgoing') - tx_script_validity(tx, 'valid') - tx_status(tx, 'in_ledger') - tx_collateral(tx, present: false) - tx_collateral_outputs(tx, present: false) - tx_metadata(tx, nil) - tx_deposits(tx, deposit_taken: 0, deposit_returned: 0) - tx_withdrawals(tx, present: false) - tx_mint_burn(tx, mint: [], burn: []) - tx_extra_signatures(tx, present: false) - tx_script_integrity(tx, present: false) - tx_validity_interval_default(tx) - tx_certificates(tx, present: false) - - # on co-signer wid - tx = SHARED.transactions.get(cosigner_wid, tx_id) - tx_amount(tx, (amt * 2) + expected_fee) - tx_fee(tx, expected_fee) - tx_inputs(tx, present: true) - tx_outputs(tx, present: true) - tx_direction(tx, 'outgoing') - tx_script_validity(tx, 'valid') - tx_status(tx, 'in_ledger') - tx_collateral(tx, present: false) - tx_collateral_outputs(tx, present: false) - tx_metadata(tx, nil) - tx_deposits(tx, deposit_taken: 0, deposit_returned: 0) - tx_withdrawals(tx, present: false) - tx_mint_burn(tx, mint: [], burn: []) - tx_extra_signatures(tx, present: false) - tx_script_integrity(tx, present: false) - tx_validity_interval_default(tx) - tx_certificates(tx, present: false) - - # on target wallet - txt = SHELLEY.transactions.get(target_wid, tx_id) - tx_amount(txt, amt * 2) - tx_fee(tx, expected_fee) - tx_inputs(txt, present: true) - tx_outputs(txt, present: true) - tx_direction(txt, 'incoming') - tx_script_validity(txt, 'valid') - tx_status(txt, 'in_ledger') - tx_collateral(txt, present: false) - tx_collateral_outputs(txt, present: false) - tx_metadata(txt, nil) - # ADP-2298 - Deposit_returned is falsely reported on some incoming transactions (intermittently) - # tx_deposits(txt, deposit_taken: 0, deposit_returned: 0) - tx_withdrawals(txt, present: false) - tx_mint_burn(txt, mint: [], burn: []) - tx_extra_signatures(txt, present: false) - tx_script_integrity(txt, present: false) - tx_validity_interval_default(txt) - tx_certificates(txt, present: false) - end - - it 'Multi-assets transaction - two cosigners, all' do - # TODO: [ADP-3419] https://cardanofoundation.atlassian.net/browse/ADP-3419 - skip 'wallet has run out of HappyCoin and SadCoin' - amt = 1 - amt_ada = 1_600_000 - src_wid = @wid_sha_cos0_all - cosigner_wid = @wid_sha_cos1_all - target_wid = @target_id - address = SHELLEY.addresses.list(target_wid)[1]['id'] - target_before = get_shelley_balances(target_wid) - src_before = get_shared_balances(src_wid) - payment = [{ 'address' => address, - 'amount' => { 'quantity' => amt_ada, 'unit' => 'lovelace' }, - 'assets' => [{ 'policy_id' => ASSETS[0]['policy_id'], - 'asset_name' => ASSETS[0]['asset_name'], - 'quantity' => amt }, - { 'policy_id' => ASSETS[1]['policy_id'], - 'asset_name' => ASSETS[1]['asset_name'], - 'quantity' => amt }] }] - - tx_constructed = SHARED.transactions.construct(src_wid, payment) - expect(tx_constructed).to be_correct_and_respond 202 - expected_fee = tx_constructed['fee']['quantity'] - - # Can be decoded - tx_decoded = SHARED.transactions.decode(src_wid, tx_constructed['transaction']) - expect(tx_decoded).to be_correct_and_respond 202 - - expect(tx_decoded['id'].size).to be 64 - decoded_fee = tx_decoded['fee']['quantity'] - expect(expected_fee).to eq decoded_fee - - # cosigner0 signs - tx_signed1 = SHARED.transactions.sign(src_wid, PASS, tx_constructed['transaction']) - expect(tx_signed1).to be_correct_and_respond 202 - - # cosigner1 signs - tx_signed = SHARED.transactions.sign(cosigner_wid, PASS, tx_signed1['transaction']) - expect(tx_signed).to be_correct_and_respond 202 - - # cosigner0 submits - tx_submitted = SHARED.transactions.submit(src_wid, tx_signed['transaction']) - expect(tx_submitted).to be_correct_and_respond 202 - - tx_id = tx_submitted['id'] - wait_for_tx_in_ledger(src_wid, tx_id, SHARED) - - target_after = get_shelley_balances(target_wid) - src_after = get_shared_balances(src_wid) - - verify_ada_balance(src_after, src_before, - target_after, target_before, - amt_ada, expected_fee) - # tx history - # on src wallet - tx = SHARED.transactions.get(src_wid, tx_id) - tx_amount(tx, amt_ada + expected_fee) - tx_fee(tx, expected_fee) - tx_inputs(tx, present: true) - tx_outputs(tx, present: true) - tx_direction(tx, 'outgoing') - tx_script_validity(tx, 'valid') - tx_status(tx, 'in_ledger') - tx_collateral(tx, present: false) - tx_collateral_outputs(tx, present: false) - tx_metadata(tx, nil) - tx_deposits(tx, deposit_taken: 0, deposit_returned: 0) - tx_withdrawals(tx, present: false) - tx_mint_burn(tx, mint: [], burn: []) - tx_extra_signatures(tx, present: false) - tx_script_integrity(tx, present: false) - tx_validity_interval_default(tx) - tx_certificates(tx, present: false) - - # on co-signer wid - tx = SHARED.transactions.get(cosigner_wid, tx_id) - tx_amount(tx, amt_ada + expected_fee) - tx_fee(tx, expected_fee) - tx_inputs(tx, present: true) - tx_outputs(tx, present: true) - tx_direction(tx, 'outgoing') - tx_script_validity(tx, 'valid') - tx_status(tx, 'in_ledger') - tx_collateral(tx, present: false) - tx_collateral_outputs(tx, present: false) - tx_metadata(tx, nil) - tx_deposits(tx, deposit_taken: 0, deposit_returned: 0) - tx_withdrawals(tx, present: false) - tx_mint_burn(tx, mint: [], burn: []) - tx_extra_signatures(tx, present: false) - tx_script_integrity(tx, present: false) - tx_validity_interval_default(tx) - tx_certificates(tx, present: false) - - # on target wallet - txt = SHELLEY.transactions.get(target_wid, tx_id) - tx_amount(txt, amt_ada) - tx_fee(tx, expected_fee) - tx_inputs(txt, present: true) - tx_outputs(txt, present: true) - tx_direction(txt, 'incoming') - tx_script_validity(txt, 'valid') - tx_status(txt, 'in_ledger') - tx_collateral(txt, present: false) - tx_collateral_outputs(txt, present: false) - tx_metadata(txt, nil) - # ADP-2298 - Deposit_returned is falsely reported on some incoming transactions (intermittently) - # tx_deposits(txt, deposit_taken: 0, deposit_returned: 0) - tx_withdrawals(txt, present: false) - tx_mint_burn(txt, mint: [], burn: []) - tx_extra_signatures(txt, present: false) - tx_script_integrity(txt, present: false) - tx_validity_interval_default(txt) - tx_certificates(txt, present: false) - end - - it 'Validity intervals - two cosigners, all' do - amt = MIN_UTXO_VALUE_PURE_ADA - src_wid = @wid_sha_cos0_all - cosigner_wid = @wid_sha_cos1_all - target_wid = @target_id - address = SHELLEY.addresses.list(target_wid)[1]['id'] - target_before = get_shelley_balances(target_wid) - src_before = get_shared_balances(src_wid) - inv_before = 500 - inv_hereafter = 5_000_000_000 - validity_interval = { 'invalid_before' => { 'quantity' => inv_before, 'unit' => 'slot' }, - 'invalid_hereafter' => { 'quantity' => inv_hereafter, 'unit' => 'slot' } } - tx_constructed = SHARED.transactions.construct(cosigner_wid, - payment_payload(amt, address), - nil, # withdrawal - nil, # metadata - nil, # delegations - nil, # mint_burn - validity_interval) - expect(tx_constructed).to be_correct_and_respond 202 - expected_fee = tx_constructed['fee']['quantity'] - - # Can be decoded - tx_decoded = SHARED.transactions.decode(src_wid, tx_constructed['transaction']) - expect(tx_decoded).to be_correct_and_respond 202 - - expect(tx_decoded['id'].size).to be 64 - decoded_fee = tx_decoded['fee']['quantity'] - expect(expected_fee).to eq decoded_fee - - # cosigner0 signs - tx_signed1 = SHARED.transactions.sign(src_wid, PASS, tx_constructed['transaction']) - expect(tx_signed1).to be_correct_and_respond 202 - - # cosigner1 signs - tx_signed = SHARED.transactions.sign(cosigner_wid, PASS, tx_signed1['transaction']) - expect(tx_signed).to be_correct_and_respond 202 - - # cosigner0 submits - tx_submitted = SHARED.transactions.submit(src_wid, tx_signed['transaction']) - expect(tx_submitted).to be_correct_and_respond 202 - - tx_id = tx_submitted['id'] - wait_for_tx_in_ledger(src_wid, tx_id, SHARED) - - target_after = get_shelley_balances(target_wid) - src_after = get_shared_balances(src_wid) - - verify_ada_balance(src_after, src_before, - target_after, target_before, - amt, expected_fee) - # tx history - # on src wallet - tx = SHARED.transactions.get(src_wid, tx_id) - tx_amount(tx, amt + expected_fee) - tx_fee(tx, expected_fee) - tx_inputs(tx, present: true) - tx_outputs(tx, present: true) - tx_direction(tx, 'outgoing') - tx_script_validity(tx, 'valid') - tx_status(tx, 'in_ledger') - tx_collateral(tx, present: false) - tx_collateral_outputs(tx, present: false) - tx_metadata(tx, nil) - tx_deposits(tx, deposit_taken: 0, deposit_returned: 0) - tx_withdrawals(tx, present: false) - tx_mint_burn(tx, mint: [], burn: []) - tx_extra_signatures(tx, present: false) - tx_script_integrity(tx, present: false) - tx_validity_interval(tx, invalid_before: inv_before, invalid_hereafter: inv_hereafter) - tx_certificates(tx, present: false) - - # on co-signer wid - tx = SHARED.transactions.get(cosigner_wid, tx_id) - tx_amount(tx, amt + expected_fee) - tx_fee(tx, expected_fee) - tx_inputs(tx, present: true) - tx_outputs(tx, present: true) - tx_direction(tx, 'outgoing') - tx_script_validity(tx, 'valid') - tx_status(tx, 'in_ledger') - tx_collateral(tx, present: false) - tx_collateral_outputs(tx, present: false) - tx_metadata(tx, nil) - tx_deposits(tx, deposit_taken: 0, deposit_returned: 0) - tx_withdrawals(tx, present: false) - tx_mint_burn(tx, mint: [], burn: []) - tx_extra_signatures(tx, present: false) - tx_script_integrity(tx, present: false) - tx_validity_interval(tx, invalid_before: inv_before, invalid_hereafter: inv_hereafter) - tx_certificates(tx, present: false) - - # on target wallet - txt = SHELLEY.transactions.get(target_wid, tx_id) - tx_amount(txt, amt) - tx_fee(tx, expected_fee) - tx_inputs(txt, present: true) - tx_outputs(txt, present: true) - tx_direction(txt, 'incoming') - tx_script_validity(txt, 'valid') - tx_status(txt, 'in_ledger') - tx_collateral(txt, present: false) - tx_collateral_outputs(txt, present: false) - tx_metadata(txt, nil) - # ADP-2298 - Deposit_returned is falsely reported on some incoming transactions (intermittently) - # tx_deposits(txt, deposit_taken: 0, deposit_returned: 0) - tx_withdrawals(txt, present: false) - tx_mint_burn(txt, mint: [], burn: []) - tx_extra_signatures(txt, present: false) - tx_script_integrity(txt, present: false) - tx_validity_interval(txt, invalid_before: inv_before, invalid_hereafter: inv_hereafter) - tx_certificates(txt, present: false) - end - - it 'Only metadata - two cosigners, all' do - src_wid = @wid_sha_cos0_all - cosigner_wid = @wid_sha_cos1_all - metadata = METADATA - balance = get_shared_balances(src_wid) - - tx_constructed = SHARED.transactions.construct(src_wid, - nil, # payments - nil, # withdrawal - metadata) - expect(tx_constructed).to be_correct_and_respond 202 - expected_fee = tx_constructed['fee']['quantity'] - - # Can be decoded - tx_decoded = SHARED.transactions.decode(src_wid, tx_constructed['transaction']) - expect(tx_decoded).to be_correct_and_respond 202 - - expect(tx_decoded['id'].size).to be 64 - decoded_fee = tx_decoded['fee']['quantity'] - expect(expected_fee).to eq decoded_fee - - # cosigner0 signs - tx_signed1 = SHARED.transactions.sign(src_wid, PASS, tx_constructed['transaction']) - expect(tx_signed1).to be_correct_and_respond 202 - - # cosigner1 signs - tx_signed = SHARED.transactions.sign(cosigner_wid, PASS, tx_signed1['transaction']) - expect(tx_signed).to be_correct_and_respond 202 - - # cosigner0 submits - tx_submitted = SHARED.transactions.submit(src_wid, tx_signed['transaction']) - expect(tx_submitted).to be_correct_and_respond 202 - - tx_id = tx_submitted['id'] - wait_for_tx_in_ledger(src_wid, tx_id, SHARED) - - # examine the tx in history - # on src wallet - tx = SHARED.transactions.get(src_wid, tx_id) - tx_amount(tx, expected_fee) - tx_fee(tx, expected_fee) - tx_inputs(tx, present: true) - tx_outputs(tx, present: true) - tx_direction(tx, 'outgoing') - tx_script_validity(tx, 'valid') - tx_status(tx, 'in_ledger') - tx_collateral(tx, present: false) - tx_collateral_outputs(tx, present: false) - tx_metadata(tx, metadata) - tx_deposits(tx, deposit_taken: 0, deposit_returned: 0) - tx_withdrawals(tx, present: false) - tx_mint_burn(tx, mint: [], burn: []) - tx_extra_signatures(tx, present: false) - tx_script_integrity(tx, present: false) - tx_validity_interval_default(tx) - tx_certificates(tx, present: false) - - # verify balance is as expected - new_balance = get_shared_balances(src_wid) - expect(new_balance['available']).to eq(balance['available'] - expected_fee) - expect(new_balance['total']).to eq(balance['total'] - expected_fee) - end - - it 'Single output transaction - one cosigner, any' do - amt = MIN_UTXO_VALUE_PURE_ADA * 2 - src_wid = @wid_sha_cos0_any - target_wid = @target_id - address = SHELLEY.addresses.list(target_wid)[1]['id'] - target_before = get_shelley_balances(target_wid) - src_before = get_shared_balances(src_wid) - - tx_constructed = SHARED.transactions.construct(src_wid, payment_payload(amt, address)) - expect(tx_constructed).to be_correct_and_respond 202 - expected_fee = tx_constructed['fee']['quantity'] - - # Can be decoded - tx_decoded = SHARED.transactions.decode(src_wid, tx_constructed['transaction']) - expect(tx_decoded).to be_correct_and_respond 202 - - expect(tx_decoded['id'].size).to be 64 - decoded_fee = tx_decoded['fee']['quantity'] - expect(expected_fee).to eq decoded_fee - - # cosigner0 signs - tx_signed = SHARED.transactions.sign(src_wid, PASS, tx_constructed['transaction']) - expect(tx_signed).to be_correct_and_respond 202 - - # cosigner0 submits - tx_submitted = SHARED.transactions.submit(src_wid, tx_signed['transaction']) - expect(tx_submitted).to be_correct_and_respond 202 - - tx_id = tx_submitted['id'] - wait_for_tx_in_ledger(src_wid, tx_id, SHARED) - - target_after = get_shelley_balances(target_wid) - src_after = get_shared_balances(src_wid) - - verify_ada_balance(src_after, src_before, - target_after, target_before, - amt, expected_fee) - # tx history - # on src wallet - tx = SHARED.transactions.get(src_wid, tx_id) - tx_amount(tx, amt + expected_fee) - tx_fee(tx, expected_fee) - tx_inputs(tx, present: true) - tx_outputs(tx, present: true) - tx_direction(tx, 'outgoing') - tx_script_validity(tx, 'valid') - tx_status(tx, 'in_ledger') - tx_collateral(tx, present: false) - tx_collateral_outputs(tx, present: false) - tx_metadata(tx, nil) - tx_deposits(tx, deposit_taken: 0, deposit_returned: 0) - tx_withdrawals(tx, present: false) - tx_mint_burn(tx, mint: [], burn: []) - tx_extra_signatures(tx, present: false) - tx_script_integrity(tx, present: false) - tx_validity_interval_default(tx) - tx_certificates(tx, present: false) - - # on target wallet - txt = SHELLEY.transactions.get(target_wid, tx_id) - tx_amount(txt, amt) - tx_fee(tx, expected_fee) - tx_inputs(txt, present: true) - tx_outputs(txt, present: true) - tx_direction(txt, 'incoming') - tx_script_validity(txt, 'valid') - tx_status(txt, 'in_ledger') - tx_collateral(txt, present: false) - tx_collateral_outputs(txt, present: false) - tx_metadata(txt, nil) - # ADP-2298 - Deposit_returned is falsely reported on some incoming transactions (intermittently) - # tx_deposits(txt, deposit_taken: 0, deposit_returned: 0) - tx_withdrawals(txt, present: false) - tx_mint_burn(txt, mint: [], burn: []) - tx_extra_signatures(txt, present: false) - tx_script_integrity(txt, present: false) - tx_validity_interval_default(txt) - tx_certificates(txt, present: false) - end - end - describe 'E2E Construct -> Sign -> Submit - single signer' do - it 'I can get min_utxo_value when contructing tx' do - amt = 1 - tx_constructed = SHARED.transactions.construct(@wid_sha, payment_payload(amt)) - expect(tx_constructed.code).to eq 403 - expect(tx_constructed['code']).to eq 'utxo_too_small' - required_minimum = tx_constructed['info']['tx_output_lovelace_required_minimum']['quantity'] - - tx_constructed = SHARED.transactions.construct(@wid_sha, payment_payload(required_minimum)) - expect(tx_constructed).to be_correct_and_respond 202 - end - - it 'Single output transaction' do - amt = MIN_UTXO_VALUE_PURE_ADA * 2 - address = SHELLEY.addresses.list(@target_id)[1]['id'] - target_before = get_shelley_balances(@target_id) - src_before = get_shared_balances(@wid_sha) - - tx_constructed = SHARED.transactions.construct(@wid_sha, payment_payload(amt, address)) - expect(tx_constructed).to be_correct_and_respond 202 - expected_fee = tx_constructed['fee']['quantity'] - - # Can be decoded - tx_decoded = SHARED.transactions.decode(@wid_sha, tx_constructed['transaction']) - expect(tx_decoded).to be_correct_and_respond 202 - - expect(tx_decoded['id'].size).to be 64 - decoded_fee = tx_decoded['fee']['quantity'] - expect(expected_fee).to eq decoded_fee - # inputs are ours - expect(tx_decoded['inputs'].to_s).to include 'address' - expect(tx_decoded['inputs'].to_s).to include 'amount' - expect(tx_decoded['outputs']).not_to eq [] - expect(tx_decoded['script_validity']).to eq 'valid' - expect(tx_decoded['validity_interval']['invalid_before']).to eq({ 'quantity' => 0, 'unit' => 'slot' }) - expect(tx_decoded['validity_interval']['invalid_hereafter']['quantity']).to be > 0 - expect(tx_decoded['collateral']).to eq [] - expect(tx_decoded['collateral_outputs']).to eq [] - expect(tx_decoded['metadata']).to eq nil - expect(tx_decoded['deposits_taken']).to eq [] - expect(tx_decoded['deposits_returned']).to eq [] - expect(tx_decoded['withdrawals']).to eq [] - expect(tx_decoded['mint']).to eq({ 'tokens' => [] }) - expect(tx_decoded['burn']).to eq({ 'tokens' => [] }) - expect(tx_decoded['certificates']).to eq [] - - tx_signed = SHARED.transactions.sign(@wid_sha, PASS, tx_constructed['transaction']) - expect(tx_signed).to be_correct_and_respond 202 - - tx_submitted = SHARED.transactions.submit(@wid_sha, tx_signed['transaction']) - expect(tx_submitted).to be_correct_and_respond 202 - - tx_id = tx_submitted['id'] - wait_for_tx_in_ledger(@wid_sha, tx_id, SHARED) - - target_after = get_shelley_balances(@target_id) - src_after = get_shared_balances(@wid_sha) - - verify_ada_balance(src_after, src_before, - target_after, target_before, - amt, expected_fee) - # tx history - # on src wallet - tx = SHARED.transactions.get(@wid_sha, tx_id) - tx_amount(tx, amt + expected_fee) - tx_fee(tx, expected_fee) - tx_inputs(tx, present: true) - tx_outputs(tx, present: true) - tx_direction(tx, 'outgoing') - tx_script_validity(tx, 'valid') - tx_status(tx, 'in_ledger') - tx_collateral(tx, present: false) - tx_collateral_outputs(tx, present: false) - tx_metadata(tx, nil) - tx_deposits(tx, deposit_taken: 0, deposit_returned: 0) - tx_withdrawals(tx, present: false) - tx_mint_burn(tx, mint: [], burn: []) - tx_extra_signatures(tx, present: false) - tx_script_integrity(tx, present: false) - tx_validity_interval_default(tx) - tx_certificates(tx, present: false) - - # on target wallet - txt = SHELLEY.transactions.get(@target_id, tx_id) - tx_amount(txt, amt) - tx_fee(tx, expected_fee) - tx_inputs(txt, present: true) - tx_outputs(txt, present: true) - tx_direction(txt, 'incoming') - tx_script_validity(txt, 'valid') - tx_status(txt, 'in_ledger') - tx_collateral(txt, present: false) - tx_collateral_outputs(txt, present: false) - tx_metadata(txt, nil) - # ADP-2298 - Deposit_returned is falsely reported on some incoming transactions (intermittently) - # tx_deposits(txt, deposit_taken: 0, deposit_returned: 0) - tx_withdrawals(txt, present: false) - tx_mint_burn(txt, mint: [], burn: []) - tx_extra_signatures(txt, present: false) - tx_script_integrity(txt, present: false) - tx_validity_interval_default(txt) - tx_certificates(txt, present: false) - end - - it 'Multi output transaction' do - amt = MIN_UTXO_VALUE_PURE_ADA - address = SHELLEY.addresses.list(@target_id)[1]['id'] - target_before = get_shelley_balances(@target_id) - src_before = get_shared_balances(@wid_sha) - - payment = [{ address: address, - amount: { quantity: amt, - unit: 'lovelace' } }, - { address: address, - amount: { quantity: amt, - unit: 'lovelace' } }] - tx_constructed = SHARED.transactions.construct(@wid_sha, payment) - expect(tx_constructed).to be_correct_and_respond 202 - expected_fee = tx_constructed['fee']['quantity'] - - # Can be decoded - tx_decoded = SHARED.transactions.decode(@wid_sha, tx_constructed['transaction']) - expect(tx_decoded).to be_correct_and_respond 202 - - expect(tx_decoded['id'].size).to be 64 - decoded_fee = tx_decoded['fee']['quantity'] - expect(expected_fee).to eq decoded_fee - # inputs are ours - expect(tx_decoded['inputs'].to_s).to include 'address' - expect(tx_decoded['inputs'].to_s).to include 'amount' - expect(tx_decoded['outputs']).not_to eq [] - expect(tx_decoded['script_validity']).to eq 'valid' - expect(tx_decoded['validity_interval']['invalid_before']).to eq({ 'quantity' => 0, 'unit' => 'slot' }) - expect(tx_decoded['validity_interval']['invalid_hereafter']['quantity']).to be > 0 - expect(tx_decoded['collateral']).to eq [] - expect(tx_decoded['collateral_outputs']).to eq [] - expect(tx_decoded['metadata']).to eq nil - expect(tx_decoded['deposits_taken']).to eq [] - expect(tx_decoded['deposits_returned']).to eq [] - expect(tx_decoded['withdrawals']).to eq [] - expect(tx_decoded['mint']).to eq({ 'tokens' => [] }) - expect(tx_decoded['burn']).to eq({ 'tokens' => [] }) - expect(tx_decoded['certificates']).to eq [] - - tx_signed = SHARED.transactions.sign(@wid_sha, PASS, tx_constructed['transaction']) - expect(tx_signed).to be_correct_and_respond 202 - - tx_submitted = SHARED.transactions.submit(@wid_sha, tx_signed['transaction']) - expect(tx_submitted).to be_correct_and_respond 202 - - tx_id = tx_submitted['id'] - wait_for_tx_in_ledger(@wid_sha, tx_id, SHARED) - - target_after = get_shelley_balances(@target_id) - src_after = get_shared_balances(@wid_sha) - - verify_ada_balance(src_after, src_before, - target_after, target_before, - amt * 2, expected_fee) - # tx history - # on src wallet - tx = SHARED.transactions.get(@wid_sha, tx_id) - tx_amount(tx, (amt * 2) + expected_fee) - tx_fee(tx, expected_fee) - tx_inputs(tx, present: true) - tx_outputs(tx, present: true) - tx_direction(tx, 'outgoing') - tx_script_validity(tx, 'valid') - tx_status(tx, 'in_ledger') - tx_collateral(tx, present: false) - tx_collateral_outputs(tx, present: false) - tx_metadata(tx, nil) - tx_deposits(tx, deposit_taken: 0, deposit_returned: 0) - tx_withdrawals(tx, present: false) - tx_mint_burn(tx, mint: [], burn: []) - tx_extra_signatures(tx, present: false) - tx_script_integrity(tx, present: false) - tx_validity_interval_default(tx) - tx_certificates(tx, present: false) - - # on target wallet - txt = SHELLEY.transactions.get(@target_id, tx_id) - tx_amount(txt, amt * 2) - tx_fee(tx, expected_fee) - tx_inputs(txt, present: true) - tx_outputs(txt, present: true) - tx_direction(txt, 'incoming') - tx_script_validity(txt, 'valid') - tx_status(txt, 'in_ledger') - tx_collateral(txt, present: false) - tx_collateral_outputs(txt, present: false) - tx_metadata(txt, nil) - # ADP-2298 - Deposit_returned is falsely reported on some incoming transactions (intermittently) - # tx_deposits(txt, deposit_taken: 0, deposit_returned: 0) - tx_withdrawals(txt, present: false) - tx_mint_burn(txt, mint: [], burn: []) - tx_extra_signatures(txt, present: false) - tx_script_integrity(txt, present: false) - tx_validity_interval_default(txt) - tx_certificates(txt, present: false) - end - - it 'Multi-assets transaction' do - amt = 1 - amt_ada = MIN_UTXO_VALUE_PURE_ADA * 2 - address = SHELLEY.addresses.list(@target_id)[1]['id'] - target_before = get_shelley_balances(@target_id) - src_before = get_shared_balances(@wid_sha) - - payment = [{ 'address' => address, - 'amount' => { 'quantity' => amt_ada, 'unit' => 'lovelace' }, - 'assets' => [{ 'policy_id' => ASSETS[0]['policy_id'], - 'asset_name' => ASSETS[0]['asset_name'], - 'quantity' => amt }, - { 'policy_id' => ASSETS[1]['policy_id'], - 'asset_name' => ASSETS[1]['asset_name'], - 'quantity' => amt }] }] - tx_constructed = SHARED.transactions.construct(@wid_sha, payment) - expect(tx_constructed).to be_correct_and_respond 202 - expected_fee = tx_constructed['fee']['quantity'] - - # Can be decoded - tx_decoded = SHARED.transactions.decode(@wid_sha, tx_constructed['transaction']) - expect(tx_decoded).to be_correct_and_respond 202 - - expect(tx_decoded['id'].size).to be 64 - decoded_fee = tx_decoded['fee']['quantity'] - expect(expected_fee).to eq decoded_fee - # inputs are ours - expect(tx_decoded['inputs'].to_s).to include 'address' - expect(tx_decoded['inputs'].to_s).to include 'amount' - expect(tx_decoded['outputs']).not_to eq [] - expect(tx_decoded['script_validity']).to eq 'valid' - expect(tx_decoded['validity_interval']['invalid_before']).to eq({ 'quantity' => 0, 'unit' => 'slot' }) - expect(tx_decoded['validity_interval']['invalid_hereafter']['quantity']).to be > 0 - expect(tx_decoded['collateral']).to eq [] - expect(tx_decoded['collateral_outputs']).to eq [] - expect(tx_decoded['metadata']).to eq nil - expect(tx_decoded['deposits_taken']).to eq [] - expect(tx_decoded['deposits_returned']).to eq [] - expect(tx_decoded['withdrawals']).to eq [] - expect(tx_decoded['mint']).to eq({ 'tokens' => [] }) - expect(tx_decoded['burn']).to eq({ 'tokens' => [] }) - expect(tx_decoded['certificates']).to eq [] - - tx_signed = SHARED.transactions.sign(@wid_sha, PASS, tx_constructed['transaction']) - expect(tx_signed).to be_correct_and_respond 202 - - tx_submitted = SHARED.transactions.submit(@wid_sha, tx_signed['transaction']) - expect(tx_submitted).to be_correct_and_respond 202 - - tx_id = tx_submitted['id'] - wait_for_tx_in_ledger(@wid_sha, tx_id, SHARED) - - target_after = get_shelley_balances(@target_id) - src_after = get_shared_balances(@wid_sha) - - verify_ada_balance(src_after, src_before, - target_after, target_before, - amt_ada, expected_fee) - - verify_asset_balance(src_after, src_before, - target_after, target_before, - amt) - # tx history - # on src wallet - tx = SHARED.transactions.get(@wid_sha, tx_id) - tx_amount(tx, amt_ada + expected_fee) - tx_fee(tx, expected_fee) - tx_inputs(tx, present: true) - tx_outputs(tx, present: true) - tx_direction(tx, 'outgoing') - tx_script_validity(tx, 'valid') - tx_status(tx, 'in_ledger') - tx_collateral(tx, present: false) - tx_collateral_outputs(tx, present: false) - tx_metadata(tx, nil) - tx_deposits(tx, deposit_taken: 0, deposit_returned: 0) - tx_withdrawals(tx, present: false) - tx_mint_burn(tx, mint: [], burn: []) - tx_extra_signatures(tx, present: false) - tx_script_integrity(tx, present: false) - tx_validity_interval_default(tx) - tx_certificates(tx, present: false) - - # on target wallet - txt = SHELLEY.transactions.get(@target_id, tx_id) - tx_amount(txt, amt_ada) - tx_fee(tx, expected_fee) - tx_inputs(txt, present: true) - tx_outputs(txt, present: true) - tx_direction(txt, 'incoming') - tx_script_validity(txt, 'valid') - tx_status(txt, 'in_ledger') - tx_collateral(txt, present: false) - tx_collateral_outputs(txt, present: false) - tx_metadata(txt, nil) - # ADP-2298 - Deposit_returned is falsely reported on some incoming transactions (intermittently) - # tx_deposits(txt, deposit_taken: 0, deposit_returned: 0) - tx_withdrawals(txt, present: false) - tx_mint_burn(txt, mint: [], burn: []) - tx_extra_signatures(txt, present: false) - tx_script_integrity(txt, present: false) - tx_validity_interval_default(txt) - tx_certificates(txt, present: false) - end - - it 'Validity intervals' do - amt = MIN_UTXO_VALUE_PURE_ADA - address = SHELLEY.addresses.list(@target_id)[1]['id'] - target_before = get_shelley_balances(@target_id) - src_before = get_shared_balances(@wid_sha) - inv_before = 500 - inv_hereafter = 5_000_000_000 - validity_interval = { 'invalid_before' => { 'quantity' => inv_before, 'unit' => 'slot' }, - 'invalid_hereafter' => { 'quantity' => inv_hereafter, 'unit' => 'slot' } } - tx_constructed = SHARED.transactions.construct(@wid_sha, - payment_payload(amt, address), - nil, # withdrawal - nil, # metadata - nil, # delegations - nil, # mint_burn - validity_interval) - expect(tx_constructed).to be_correct_and_respond 202 - expected_fee = tx_constructed['fee']['quantity'] - - # Can be decoded - tx_decoded = SHARED.transactions.decode(@wid_sha, tx_constructed['transaction']) - expect(tx_decoded).to be_correct_and_respond 202 - - expect(tx_decoded['id'].size).to be 64 - decoded_fee = tx_decoded['fee']['quantity'] - expect(expected_fee).to eq decoded_fee - # inputs are ours - expect(tx_decoded['inputs'].to_s).to include 'address' - expect(tx_decoded['inputs'].to_s).to include 'amount' - expect(tx_decoded['outputs']).not_to eq [] - expect(tx_decoded['script_validity']).to eq 'valid' - expect(tx_decoded['validity_interval']['invalid_before']).to eq validity_interval['invalid_before'] - expect(tx_decoded['validity_interval']['invalid_hereafter']).to eq validity_interval['invalid_hereafter'] - expect(tx_decoded['collateral']).to eq [] - expect(tx_decoded['collateral_outputs']).to eq [] - expect(tx_decoded['metadata']).to eq nil - expect(tx_decoded['deposits_taken']).to eq [] - expect(tx_decoded['deposits_returned']).to eq [] - expect(tx_decoded['withdrawals']).to eq [] - expect(tx_decoded['mint']).to eq({ 'tokens' => [] }) - expect(tx_decoded['burn']).to eq({ 'tokens' => [] }) - expect(tx_decoded['certificates']).to eq [] - - tx_signed = SHARED.transactions.sign(@wid_sha, PASS, tx_constructed['transaction']) - expect(tx_signed).to be_correct_and_respond 202 - - tx_submitted = SHARED.transactions.submit(@wid_sha, tx_signed['transaction']) - expect(tx_submitted).to be_correct_and_respond 202 - - tx_id = tx_submitted['id'] - wait_for_tx_in_ledger(@wid_sha, tx_id, SHARED) - - target_after = get_shelley_balances(@target_id) - src_after = get_shared_balances(@wid_sha) - - verify_ada_balance(src_after, src_before, - target_after, target_before, - amt, expected_fee) - # tx history - # on src wallet - tx = SHARED.transactions.get(@wid_sha, tx_id) - tx_amount(tx, amt + expected_fee) - tx_fee(tx, expected_fee) - tx_inputs(tx, present: true) - tx_outputs(tx, present: true) - tx_direction(tx, 'outgoing') - tx_script_validity(tx, 'valid') - tx_status(tx, 'in_ledger') - tx_collateral(tx, present: false) - tx_collateral_outputs(tx, present: false) - tx_metadata(tx, nil) - tx_deposits(tx, deposit_taken: 0, deposit_returned: 0) - tx_withdrawals(tx, present: false) - tx_mint_burn(tx, mint: [], burn: []) - tx_extra_signatures(tx, present: false) - tx_script_integrity(tx, present: false) - tx_validity_interval(tx, invalid_before: inv_before, invalid_hereafter: inv_hereafter) - tx_certificates(tx, present: false) - - # on target wallet - txt = SHELLEY.transactions.get(@target_id, tx_id) - tx_amount(txt, amt) - tx_fee(tx, expected_fee) - tx_inputs(txt, present: true) - tx_outputs(txt, present: true) - tx_direction(txt, 'incoming') - tx_script_validity(txt, 'valid') - tx_status(txt, 'in_ledger') - tx_collateral(txt, present: false) - tx_collateral_outputs(txt, present: false) - tx_metadata(txt, nil) - # ADP-2298 - Deposit_returned is falsely reported on some incoming transactions (intermittently) - # tx_deposits(txt, deposit_taken: 0, deposit_returned: 0) - tx_withdrawals(txt, present: false) - tx_mint_burn(txt, mint: [], burn: []) - tx_extra_signatures(txt, present: false) - tx_script_integrity(txt, present: false) - tx_validity_interval(txt, invalid_before: inv_before, invalid_hereafter: inv_hereafter) - tx_certificates(txt, present: false) - end - - it 'Only metadata' do - metadata = METADATA - balance = get_shared_balances(@wid_sha) - tx_constructed = SHARED.transactions.construct(@wid_sha, - nil, # payments - nil, # withdrawal - metadata) - expect(tx_constructed).to be_correct_and_respond 202 - expected_fee = tx_constructed['fee']['quantity'] - - # Can be decoded - tx_decoded = SHARED.transactions.decode(@wid_sha, tx_constructed['transaction']) - expect(tx_decoded).to be_correct_and_respond 202 - - expect(tx_decoded['id'].size).to be 64 - decoded_fee = tx_decoded['fee']['quantity'] - expect(expected_fee).to eq decoded_fee - # inputs are ours - expect(tx_decoded['inputs'].to_s).to include 'address' - expect(tx_decoded['inputs'].to_s).to include 'amount' - expect(tx_decoded['outputs']).not_to eq [] - expect(tx_decoded['script_validity']).to eq 'valid' - expect(tx_decoded['validity_interval']['invalid_before']).to eq({ 'quantity' => 0, 'unit' => 'slot' }) - expect(tx_decoded['validity_interval']['invalid_hereafter']['quantity']).to be > 0 - expect(tx_decoded['collateral']).to eq [] - expect(tx_decoded['collateral_outputs']).to eq [] - expect(tx_decoded['metadata']).to eq metadata - expect(tx_decoded['deposits_taken']).to eq [] - expect(tx_decoded['deposits_returned']).to eq [] - expect(tx_decoded['withdrawals']).to eq [] - expect(tx_decoded['mint']).to eq({ 'tokens' => [] }) - expect(tx_decoded['burn']).to eq({ 'tokens' => [] }) - expect(tx_decoded['certificates']).to eq [] - - tx_signed = SHARED.transactions.sign(@wid_sha, PASS, tx_constructed['transaction']) - expect(tx_signed).to be_correct_and_respond 202 - - tx_submitted = SHARED.transactions.submit(@wid_sha, tx_signed['transaction']) - expect(tx_submitted).to be_correct_and_respond 202 - signed_decoded = SHARED.transactions.decode(@wid_sha, tx_signed['transaction']) - expect(signed_decoded['witness_count']['verification_key']).to be >= 1 - expect(expected_fee).to eq signed_decoded['fee']['quantity'] - - tx_id = tx_submitted['id'] - wait_for_tx_in_ledger(@wid_sha, tx_id, SHARED) - - # examine the tx in history - # on src wallet - tx = SHARED.transactions.get(@wid_sha, tx_id) - tx_amount(tx, expected_fee) - tx_fee(tx, expected_fee) - tx_inputs(tx, present: true) - tx_outputs(tx, present: true) - tx_direction(tx, 'outgoing') - tx_script_validity(tx, 'valid') - tx_status(tx, 'in_ledger') - tx_collateral(tx, present: false) - tx_collateral_outputs(tx, present: false) - tx_metadata(tx, metadata) - tx_deposits(tx, deposit_taken: 0, deposit_returned: 0) - tx_withdrawals(tx, present: false) - tx_mint_burn(tx, mint: [], burn: []) - tx_extra_signatures(tx, present: false) - tx_script_integrity(tx, present: false) - tx_validity_interval_default(tx) - tx_certificates(tx, present: false) - - # verify balance is as expected - new_balance = get_shared_balances(@wid_sha) - expect(new_balance['available']).to eq(balance['available'] - expected_fee) - expect(new_balance['total']).to eq(balance['total'] - expected_fee) - end - - it 'Delegation (join and quit)' do - balance = get_shared_balances(@wid_sha) - expected_deposit = CARDANO_CLI.protocol_params['stakeAddressDeposit'] - puts "Expected deposit #{expected_deposit}" - - # Check wallet stake keys before joing stake pool - wallet = SHARED.wallets.get(@wid_sha) - expect(wallet['delegation']['active']['status']).to eq 'not_delegating' - - # Pick up pool id to join - pools = SHELLEY.stake_pools - pool_id = pools.list({ stake: 1000 }).sample['id'] - - # Join pool - delegation = [{ - 'join' => { - 'pool' => pool_id, - 'stake_key_index' => '0H' - } - }] - - tx_constructed = SHARED.transactions.construct(@wid_sha, - nil, # payment - nil, # withdrawal - nil, # metadata - delegation, - nil, # mint_burn - nil) # validity_interval - # Check fee and deposit on joining - tx_decoded = SHARED.transactions.decode(@wid_sha, tx_constructed['transaction']) - expect(tx_decoded).to be_correct_and_respond 202 - - deposit_taken = tx_constructed['coin_selection']['deposits_taken'].first['quantity'] - decoded_deposit_taken = tx_decoded['deposits_taken'].first['quantity'] - expect(deposit_taken).to eq decoded_deposit_taken - expect(deposit_taken).to eq expected_deposit - - expected_fee = tx_constructed['fee']['quantity'] - decoded_fee = tx_decoded['fee']['quantity'] - expect(decoded_fee).to eq expected_fee - # inputs are ours - expect(tx_decoded['inputs'].to_s).to include 'address' - expect(tx_decoded['inputs'].to_s).to include 'amount' - expect(tx_decoded['outputs']).not_to eq [] - expect(tx_decoded['script_validity']).to eq 'valid' - expect(tx_decoded['validity_interval']['invalid_before']).to eq({ 'quantity' => 0, 'unit' => 'slot' }) - expect(tx_decoded['validity_interval']['invalid_hereafter']['quantity']).to be > 0 - expect(tx_decoded['collateral']).to eq [] - expect(tx_decoded['collateral_outputs']).to eq [] - expect(tx_decoded['metadata']).to eq nil - expect(tx_decoded['deposits_returned']).to eq [] - expect(tx_decoded['withdrawals']).to eq [] - expect(tx_decoded['mint']).to eq({ 'tokens' => [] }) - expect(tx_decoded['burn']).to eq({ 'tokens' => [] }) - - # Certificates - expect(tx_decoded['certificates']).to include(have_key('certificate_type')).twice - expect(tx_decoded['certificates']).to include(have_value('register_reward_account')).once - expect(tx_decoded['certificates']).to include(have_value('join_pool')).once - expect(tx_decoded['certificates']).to include(have_key('reward_account_path')).twice - expect(tx_decoded['certificates']).to include(have_value(%w[1854H 1815H 0H 2 0])).twice - expect(tx_decoded['certificates']).to include(have_key('pool')).once - expect(tx_decoded['certificates']).to include(have_value(pool_id)).once - - # Sign - tx_signed = SHARED.transactions.sign(@wid_sha, PASS, tx_constructed['transaction']) - expect(tx_signed).to be_correct_and_respond 202 - - # Submit - tx_submitted = SHARED.transactions.submit(@wid_sha, tx_signed['transaction']) - expect(tx_submitted).to be_correct_and_respond 202 - tx_id = tx_submitted['id'] - wait_for_tx_in_ledger(@wid_sha, tx_id, SHARED) - - # Check fee and balance and deposit after joining - tx = SHARED.transactions.get(@wid_sha, tx_id) - tx_amount(tx, expected_deposit + expected_fee) - tx_fee(tx, expected_fee) - tx_inputs(tx, present: true) - tx_outputs(tx, present: true) - tx_direction(tx, 'outgoing') - tx_script_validity(tx, 'valid') - tx_status(tx, 'in_ledger') - tx_collateral(tx, present: false) - tx_collateral_outputs(tx, present: false) - tx_metadata(tx, nil) - tx_deposits(tx, deposit_taken: deposit_taken, deposit_returned: 0) - tx_withdrawals(tx, present: false) - tx_mint_burn(tx, mint: [], burn: []) - tx_extra_signatures(tx, present: false) - tx_script_integrity(tx, present: false) - tx_validity_interval_default(tx) - tx_certificates(tx, present: true, certificates: tx_decoded['certificates']) - expect(tx['certificates'].to_s).to include 'register_reward_account' - expect(tx['certificates'].to_s).to include 'join_pool' - expect(tx['certificates'].to_s).to include pool_id - - join_balance = get_shared_balances(@wid_sha) - expected_join_balance = balance['total'] - deposit_taken - expected_fee - expect(join_balance['total']).to eq expected_join_balance - - # Quit pool - quit_pool = [{ 'quit' => { 'stake_key_index' => '0H' } }] - tx_constructed = SHARED.transactions.construct(@wid_sha, - nil, # payment - nil, # withdrawal - nil, # metadata - quit_pool, - nil, # mint_burn - nil) # validity_interval - - # Check fee and deposit on quitting - decoded_tx = SHARED.transactions.decode(@wid_sha, tx_constructed['transaction']) - expect(decoded_tx).to be_correct_and_respond 202 - - # Certificates - expect(decoded_tx['certificates']).to include(have_key('certificate_type')).once - expect(decoded_tx['certificates']).to include(have_value('quit_pool')).once - expect(decoded_tx['certificates']).to include(have_key('reward_account_path')).once - expect(decoded_tx['certificates']).to include(have_value(%w[1854H 1815H 0H 2 0])).once - expect(decoded_tx['certificates']).not_to include(have_value('register_reward_account')) - expect(decoded_tx['certificates']).not_to include(have_key('pool')).once - expect(decoded_tx['certificates']).not_to include(have_value(pool_id)).once - - expect(tx_constructed['coin_selection']['deposits_taken']).to eq [] - expect(decoded_tx['deposits_taken']).to eq [] - deposit_returned = tx_constructed['coin_selection']['deposits_returned'].first['quantity'] - decoded_deposit_returned = decoded_tx['deposits_returned'].first['quantity'] - expect(deposit_returned).to eq decoded_deposit_returned - expect(deposit_returned).to eq expected_deposit - - expected_fee = tx_constructed['fee']['quantity'] - decoded_fee = decoded_tx['fee']['quantity'] - expect(expected_fee).to eq decoded_fee - - # Sign - tx_signed = SHARED.transactions.sign(@wid_sha, PASS, tx_constructed['transaction']) - expect(tx_signed).to be_correct_and_respond 202 - - # Submit - tx_submitted = SHARED.transactions.submit(@wid_sha, tx_signed['transaction']) - expect(tx_submitted).to be_correct_and_respond 202 - tx_id = tx_submitted['id'] - wait_for_tx_in_ledger(@wid_sha, tx_id, SHARED) - - # Check fee and balance and deposit after quitting - quit_balance = get_shared_balances(@wid_sha) - tx = SHARED.transactions.get(@wid_sha, tx_id) - expect(tx['amount']['quantity']).to be > 0 - expect(tx['amount']['quantity']).to be < deposit_returned - tx_fee(tx, expected_fee) - tx_inputs(tx, present: true) - tx_outputs(tx, present: true) - tx_direction(tx, 'incoming') - tx_script_validity(tx, 'valid') - tx_status(tx, 'in_ledger') - tx_collateral(tx, present: false) - tx_collateral_outputs(tx, present: false) - tx_metadata(tx, nil) - tx_deposits(tx, deposit_taken: 0, deposit_returned: deposit_returned) - tx_withdrawals(tx, present: false) - tx_mint_burn(tx, mint: [], burn: []) - tx_extra_signatures(tx, present: false) - tx_script_integrity(tx, present: false) - tx_validity_interval_default(tx) - tx_certificates(tx, present: true, certificates: decoded_tx['certificates']) - expect(tx['certificates'].to_s).to include 'quit_pool' - - expected_quit_balance = join_balance['total'] + deposit_returned - expected_fee - expect(quit_balance['total']).to eq expected_quit_balance - end - - describe 'Minting and Burning' do - it 'Can mint and then burn (without submitting)' do - # Minting and Burning not yet implemented, only construct and sign in this tc - # src_before = get_shared_balances(@wid_sha) - policy_script1 = 'cosigner#0' - policy_script2 = { 'all' => ['cosigner#0'] } - policy_script3 = { 'any' => ['cosigner#0'] } - - # Minting: - mint = [mint(asset_name('Token1'), 1000, policy_script1), - mint(asset_name('Token2'), 1000, policy_script2), - mint('', 1000, policy_script3)] - - tx_constructed = SHARED.transactions.construct(@wid_sha, - nil, # payment - nil, # withdrawal - nil, # metadata - nil, # delegation - mint) - expect(tx_constructed).to be_correct_and_respond 202 - - tx_decoded = SHARED.transactions.decode(@wid_sha, tx_constructed['transaction']) - expect(tx_decoded).to be_correct_and_respond 202 - - expected_fee = tx_constructed['fee']['quantity'] - decoded_fee = tx_decoded['fee']['quantity'] - expect(expected_fee).to eq decoded_fee - # inputs are ours - expect(tx_decoded['inputs'].to_s).to include 'address' - expect(tx_decoded['inputs'].to_s).to include 'amount' - expect(tx_decoded['outputs']).not_to eq [] - expect(tx_decoded['script_validity']).to eq 'valid' - expect(tx_decoded['validity_interval']['invalid_before']).to eq({ 'quantity' => 0, 'unit' => 'slot' }) - expect(tx_decoded['validity_interval']['invalid_hereafter']['quantity']).to be > 0 - expect(tx_decoded['collateral']).to eq [] - expect(tx_decoded['collateral_outputs']).to eq [] - expect(tx_decoded['metadata']).to eq nil - expect(tx_decoded['deposits_taken']).to eq [] - expect(tx_decoded['deposits_returned']).to eq [] - expect(tx_decoded['withdrawals']).to eq [] - # TODO: mint / burn currently not decoded - expect(tx_decoded['mint']).to eq({ 'tokens' => [] }) - expect(tx_decoded['burn']).to eq({ 'tokens' => [] }) - expect(tx_decoded['certificates']).to eq [] - - tx_signed = SHARED.transactions.sign(@wid_sha, PASS, tx_constructed['transaction']) - expect(tx_signed).to be_correct_and_respond 202 - end - end - end - - it 'I can receive transaction to shared wallet' do - amt = 1 - amt_ada = 3_000_000 - address = SHARED.addresses.list(@wid_sha)[1]['id'] - target_before = get_shared_balances(@wid_sha) - src_before = get_shelley_balances(@wid) - - payload = [{ 'address' => address, - 'amount' => { 'quantity' => amt_ada, 'unit' => 'lovelace' }, - 'assets' => [{ 'policy_id' => ASSETS[0]['policy_id'], - 'asset_name' => ASSETS[0]['asset_name'], - 'quantity' => amt }, - { 'policy_id' => ASSETS[1]['policy_id'], - 'asset_name' => ASSETS[1]['asset_name'], - 'quantity' => amt }] }] - - tx_sent = SHELLEY.transactions.create(@wid, PASS, payload) - - expect(tx_sent).to be_correct_and_respond 202 - wait_for_tx_in_ledger(@wid, tx_sent['id']) - - target_after = get_shared_balances(@wid_sha) - src_after = get_shelley_balances(@wid) - fee = SHELLEY.transactions.get(@wid, tx_sent['id'])['fee']['quantity'] - - verify_ada_balance(src_after, src_before, - target_after, target_before, - amt_ada, fee) - - verify_asset_balance(src_after, src_before, - target_after, target_before, - amt) - end - - it 'I can list transactions and limit response with query parameters' do - wid = @wid_sha - - # get 3 txs - txs = SHARED.transactions.list(wid, { max_count: 3, order: 'ascending' }) - expect(txs).to be_correct_and_respond 200 - expect(txs.size).to be 3 - - last_tx_time = txs.first['inserted_at']['time'] - first_tx_time = txs.last['inserted_at']['time'] - - # get 2 txs - txs = SHARED.transactions.list(wid, { max_count: 2, order: 'ascending' }) - expect(txs).to be_correct_and_respond 200 - expect(txs.size).to eq 2 - expect(txs.first['inserted_at']['time']).to eq last_tx_time - - # get 2 txs in ascending order - txs = SHARED.transactions.list(wid, { max_count: 2, start: first_tx_time, order: 'ascending' }) - expect(txs).to be_correct_and_respond 200 - expect(txs.size).to eq 2 - expect(txs.first['inserted_at']['time']).to eq first_tx_time - - # get 2 txs in ascending order with start and end time - txs = SHARED.transactions.list(wid, { max_count: 2, start: last_tx_time, end: first_tx_time, order: 'ascending' }) - expect(txs).to be_correct_and_respond 200 - expect(txs.size).to eq 2 - expect(txs.first['inserted_at']['time']).to eq last_tx_time - end - end - - describe 'E2E Migration' do - it 'I can migrate all funds back to fixture shared wallet' do - address = SHARED.addresses.list(@wid_sha)[0]['id'] - src_before = get_shelley_balances(@target_id) - target_before = get_shared_balances(@wid_sha) - - migration = SHELLEY.migrations.migrate(@target_id, PASS, [address]) - tx_ids = migration.map { |m| m['id'] } - fees = migration.map { |m| m['fee']['quantity'] }.sum - amounts = migration.map { |m| m['amount']['quantity'] }.sum - fees - tx_ids.each do |tx_id| - wait_for_tx_in_ledger(@target_id, tx_id) - end - src_after = get_shelley_balances(@target_id) - target_after = get_shared_balances(@wid_sha) - expected_src_balance = { 'total' => 0, - 'available' => 0, - 'rewards' => 0, - 'assets_total' => [], - 'assets_available' => [] } - - expect(src_after).to eq expected_src_balance - - verify_ada_balance(src_after, src_before, - target_after, target_before, - amounts, fees) - - tx_ids.each do |tx_id| - # examine the tx in history - # on src wallet - tx = SHELLEY.transactions.get(@target_id, tx_id) - tx_inputs(tx, present: true) - tx_outputs(tx, present: true) - tx_direction(tx, 'outgoing') - tx_script_validity(tx, 'valid') - tx_status(tx, 'in_ledger') - tx_collateral(tx, present: false) - tx_collateral_outputs(tx, present: false) - tx_metadata(tx, nil) - tx_deposits(tx, deposit_taken: 0, deposit_returned: 0) - tx_withdrawals(tx, present: false) - tx_mint_burn(tx, mint: [], burn: []) - tx_extra_signatures(tx, present: false) - tx_script_integrity(tx, present: false) - tx_validity_interval_default(tx) - tx_certificates(tx, present: false) - - # on target wallet - txt = SHARED.transactions.get(@wid_sha, tx_id) - expect(tx['fee']['quantity'].to_i).to be > 0 - tx_inputs(txt, present: true) - tx_outputs(txt, present: true) - tx_direction(txt, 'incoming') - tx_script_validity(txt, 'valid') - tx_status(txt, 'in_ledger') - tx_collateral(txt, present: false) - tx_collateral_outputs(txt, present: false) - tx_metadata(txt, nil) - # ADP-2298 - Deposit_returned is falsely reported on some incoming transactions (intermittently) - # tx_deposits(txt, deposit_taken: 0, deposit_returned: 0) - tx_withdrawals(txt, present: false) - tx_mint_burn(txt, mint: [], burn: []) - tx_extra_signatures(txt, present: false) - tx_script_integrity(txt, present: false) - tx_validity_interval_default(txt) - tx_certificates(txt, present: false) - end - end - end -end diff --git a/test/e2e/spec/e2e_spec.rb b/test/e2e/spec/e2e_spec.rb deleted file mode 100644 index 83042c49c2e..00000000000 --- a/test/e2e/spec/e2e_spec.rb +++ /dev/null @@ -1,3389 +0,0 @@ -# frozen_string_literal: true - -RSpec.describe 'Cardano Wallet E2E tests', :all, :e2e do - before(:all) do - # shelley wallets - @wid = create_fixture_wallet(:shelley) - @target_id = create_target_wallet(:shelley) - - # byron wallets - @wid_rnd = create_fixture_wallet(:random) - @wid_ic = create_fixture_wallet(:icarus) - - @nightly_byron_wallets = [@wid_rnd, @wid_ic] - @nightly_shelley_wallets = [@wid, @target_id] - wait_for_all_shelley_wallets(@nightly_shelley_wallets) - wait_for_all_byron_wallets(@nightly_byron_wallets) - end - - after(:each) do - teardown - end - - after(:all) do - SHELLEY.stake_pools.quit(@target_id, PASS) - end - - describe 'Regressions' do - it 'ADP-2523 - Make sure there are no null values in the response', :adp_2523 do - pools = SHELLEY.stake_pools - l = pools.list({ stake: 1000 }) - expect(l).to be_correct_and_respond 200 - expect(l.length).to be > 0 - expect(l.to_s).not_to include 'null' - end - end - - describe 'Collateral return', :collateral do - it 'AlwaysFails.plutus with collateral return to the wallet' do - ## - # This test is trying to spend utxo from a script address - # that will always fail. - # Script: https://github.com/IntersectMBO/cardano-node/blob/master/scripts/plutus/scripts/v2/always-fails.plutus - # - # The spending transaction sets: - # - collateral return output to be sent to wallet address - # - aims to spend ADA also to the wallet address - # - # Because the script will fail we expect: - # - collateral return output to be send to the wallet address - # - wallet to show balance correctly - # - wallet to be able to spend this collateral output in the subsequent transaction - # - # We are trying to spend pre-created UTxO from the script address, - # which was created as follows using fixtures/alwaysfails.plutus: - # - # export NETWORK_ID="--testnet-magic 2" - # cardano-cli address build --payment-script-file alwaysfails.plutus $NETWORK_ID > AlwaysFails.addr - # cardano-cli transaction hash-script-data --script-data-value 1914 > datumhash - # cardano-cli transaction build \ - # --babbage-era \ - # $NETWORK_ID \ - # --tx-in "ab08ccdf5c62ad8008d0ac165b68ff714b88de19235a9bd65c731fc264125daf#0" \ - # --tx-out $( collateral_utxo[:utxo], 'index' => collateral_utxo[:ix].to_i }] - collateral_outputs = [{ 'address' => target_address, - 'amount' => { 'quantity' => collateral_ret_amt, 'unit' => 'lovelace' }, - 'assets' => [] }] - expect(tx['collateral']).to eq collateral - expect(tx['collateral_outputs']).to eq collateral_outputs - expect(tx['script_validity']).to eq 'invalid' - - # Make sure balance is correct (+collateral_ret_amt) - target_after = get_shelley_balances(@target_id) - expect(target_after['available']).to eq(target_before['available'] + collateral_ret_amt) - - # Make sure you can spend collateral return output from the wallet - tx = construct_sign_submit(@target_id, payment_payload(6_500_000, payment_address)) - wait_for_tx_in_ledger(@target_id, tx.last['id']) - end - end - - describe 'E2E Balance -> Sign -> Submit' do - def run_script(script, payload) - tx_balanced, tx_signed, tx_submitted = balance_sign_submit(@wid, payload) - tx_id = tx_submitted['id'] - - eventually "#{script} is in ledger" do - tx = SHELLEY.transactions.get(@wid, tx_id) - tx.code == 200 && tx['status'] == 'in_ledger' - end - - { tx_id: tx_id, - tx_unbalanced: SHELLEY.transactions.decode(@wid, payload['transaction']).parsed_response, - tx_balanced: SHELLEY.transactions.decode(@wid, tx_balanced['transaction']).parsed_response, - tx_signed: SHELLEY.transactions.decode(@wid, tx_signed['transaction']).parsed_response } - end - - def run_contract(contract_setup, scripts) - # Contract setup - payload = get_plutus_tx(contract_setup) - r = run_script(contract_setup, payload) - tx_id = r[:tx_id] - - # Run Plutus contract - scripts.each do |s| - payload = get_templated_plutus_tx(s, { transactionId: tx_id }) - r = run_script(s, payload) - tx_id = r[:tx_id] - end - end - - before(:all) do - log 'Making transaction with 10 pure ADA inputs to the wallet to make sure there is collateral' - amt = 10_000_000 - address = SHELLEY.addresses.list(@wid)[0]['id'] - payment = [] - 10.times do - payment << { address: address, amount: { quantity: amt, unit: 'lovelace' } } - end - _, _, tx_submitted = construct_sign_submit(@wid, payment) - tx_id = tx_submitted['id'] - wait_for_tx_in_ledger(@wid, tx_id) - end - - it 'cannot balance on empty wallet' do - wid = create_shelley_wallet - payload = get_plutus_tx 'ping-pong_1.json' - tx_balanced = SHELLEY.transactions.balance(wid, payload) - expect(tx_balanced).to be_correct_and_respond 403 - expect(tx_balanced.to_s).to include 'no_utxos_available' - end - - it 'ping-pong' do - init_src = get_shelley_balances(@wid) - contract_setup = 'ping-pong_1.json' - script = 'ping-pong_2.json' - - # run contract setup - payload = get_plutus_tx(contract_setup) - r = run_script(contract_setup, payload) - # verify that decoded balanced tx is the same as signed tx (modulo witness_count) - r_balanced = r[:tx_balanced].clone - r_signed = r[:tx_signed].clone - r_balanced.delete('witness_count') - r_signed.delete('witness_count') - expect(r_balanced).to eq r_signed - - # verify witness count - expect(r[:tx_balanced]['witness_count']['verification_key']).to eq 0 - expect(r[:tx_signed]['witness_count']['verification_key']).to be >= 1 - - # verify wallet balance decreases as expected after transaction (by fee + amt) - fee = r[:tx_balanced]['fee']['quantity'] - amt = get_sent_amt(r[:tx_balanced]['outputs']) - src_after = get_shelley_balances(@wid) - expect(src_after['total']).to eq(init_src['total'] - fee - amt) - - # examine tx history - tx1 = SHELLEY.transactions.get(@wid, r[:tx_id]) - tx_inputs(tx1, present: true) - tx_outputs(tx1, present: true) - tx_direction(tx1, 'outgoing') - tx_script_validity(tx1, 'valid') - tx_status(tx1, 'in_ledger') - tx_collateral(tx1, present: false) - tx_collateral_outputs(tx1, present: false) - tx_metadata(tx1, nil) - tx_deposits(tx1, deposit_taken: 0, deposit_returned: 0) - tx_withdrawals(tx1, present: false) - tx_mint_burn(tx1, mint: [], burn: []) - tx_extra_signatures(tx1, present: true) - tx_script_integrity(tx1, present: true) - tx_validity_interval_default(tx1) - tx_certificates(tx1, present: false) - - # run ping-pong_2 - src_before2 = get_shelley_balances(@wid) - payload2 = get_templated_plutus_tx(script, { transactionId: r[:tx_id] }) - r2 = run_script(script, payload2) - - # verify that decoded balanced tx is the same as signed tx (modulo witness_count) - r2_balanced = r2[:tx_balanced].clone - r2_signed = r2[:tx_signed].clone - r2_balanced.delete('witness_count') - r2_signed.delete('witness_count') - expect(r2_balanced).to eq r2_signed - - # verify witness count - expect(r2[:tx_balanced]['witness_count']['verification_key']).to eq 0 - expect(r2[:tx_signed]['witness_count']['verification_key']).to be >= 1 - - fee2 = r2[:tx_balanced]['fee']['quantity'] - - # verify balance decreases as expected after transaction - # ping-pong_2 spends from external utxo, so wallet balance decreases only by fee2 - src_after2 = get_shelley_balances(@wid) - expect(src_after2['total']).to eq(src_before2['total'] - fee2) - - # examine tx history - tx2 = SHELLEY.transactions.get(@wid, r2[:tx_id]) - tx_inputs(tx2, present: true) - tx_outputs(tx2, present: true) - tx_direction(tx2, 'outgoing') - tx_script_validity(tx2, 'valid') - tx_status(tx2, 'in_ledger') - tx_collateral(tx2, present: true) - tx_collateral_outputs(tx2, present: false) - tx_metadata(tx2, nil) - tx_deposits(tx2, deposit_taken: 0, deposit_returned: 0) - tx_withdrawals(tx2, present: false) - tx_mint_burn(tx2, mint: [], burn: []) - tx_extra_signatures(tx2, present: true) - tx_script_integrity(tx2, present: true) - tx_validity_interval_default(tx2) - tx_certificates(tx2, present: false) - end - - it 'game' do - contract_setup = 'game_1.json' - scripts = ['game_2.json', 'game_3.json'] - - run_contract(contract_setup, scripts) - end - - it 'mint-burn' do - vk = SHELLEY.keys.get_public_key(@wid, 'utxo_external', 0, { hash: true }).gsub('"', '') - vk_hash = bech32_to_base16(vk) - policy = read_mustached_file('mintBurn_policy', { vkHash: vk_hash }) - policy_id = get_policy_id(policy) - def fingerprint - if linux? - 'asset1q78ea9ds0rc3tfwu2damsjehjup2xuzddtg6xh' - elsif mac? - 'asset1kjxaamf0p2p2z9g3k4xu0ne0g6h5j70st6z4pz' - elsif win? - 'asset1arj5nz8zxjuxvut5wqt5q0xw7905hllugahvu7' - end - end - - def script_hash - if linux? - 'c22560ac64be051102d6d1cfe5b9b82eb6af4f00dd3806e5cd82e837' - elsif mac? - '87c822cd8fb44f2e3bffc3eaf41c63c2301a0ac2325ee3db634bd435' - elsif win? - 'c8a35944deea4a336faaeb88c35fee23ca88316eb698646e58a9298c' - end - end - mint_script = 'mintBurn_1.json' - burn_script = 'mintBurn_2.json' - assets = [{ 'policy_script' => { 'script_info' => { 'language_version' => 'v1', - 'script_hash' => script_hash }, - 'script_type' => 'plutus' }, - 'policy_id' => policy_id, - 'assets' => [{ 'fingerprint' => fingerprint, - 'quantity' => 1, - 'asset_name' => asset_name('mint-burn') }] }] - - payload_mint = get_templated_plutus_tx(mint_script, { vkHash: vk_hash, - policyId: policy_id, - policy: policy }) - - payload_burn = get_templated_plutus_tx(burn_script, { vkHash: vk_hash, - policyId: policy_id, - policy: policy }) - mint = run_script(mint_script, payload_mint) - burn = run_script(burn_script, payload_burn) - - # verify that decoded balanced tx is the same as signed tx (modulo witness_count) - mint_balanced = mint[:tx_balanced].clone - mint_signed = mint[:tx_signed].clone - mint_balanced.delete('witness_count') - mint_signed.delete('witness_count') - expect(mint_balanced).to eq mint_signed - burn_balanced = burn[:tx_balanced].clone - burn_signed = burn[:tx_signed].clone - burn_balanced.delete('witness_count') - burn_signed.delete('witness_count') - expect(burn_balanced).to eq burn_signed - - # verify witness count - expect(mint[:tx_balanced]['witness_count']['verification_key']).to eq 0 - expect(mint[:tx_signed]['witness_count']['verification_key']).to be >= 1 - expect(burn[:tx_balanced]['witness_count']['verification_key']).to eq 0 - expect(burn[:tx_signed]['witness_count']['verification_key']).to be >= 1 - - # verify decoded unbalanced transaction includes assets minted and burned - expect(mint[:tx_unbalanced]['mint']['tokens']).to eq assets - expect(mint[:tx_unbalanced]['burn']['tokens']).to eq [] - expect(burn[:tx_unbalanced]['mint']['tokens']).to eq [] - expect(burn[:tx_unbalanced]['burn']['tokens']).to eq assets - - # verify decoded balanced transaction includes assets minted and burned - expect(mint[:tx_balanced]['mint']['tokens']).to eq assets - expect(mint[:tx_balanced]['burn']['tokens']).to eq [] - expect(burn[:tx_balanced]['mint']['tokens']).to eq [] - expect(burn[:tx_balanced]['burn']['tokens']).to eq assets - - # examine tx history - mint_tx = SHELLEY.transactions.get(@wid, mint[:tx_id]) - burn_tx = SHELLEY.transactions.get(@wid, burn[:tx_id]) - - tx_inputs(mint_tx, present: true) - tx_outputs(mint_tx, present: true) - tx_direction(mint_tx, 'outgoing') - tx_script_validity(mint_tx, 'valid') - tx_status(mint_tx, 'in_ledger') - tx_collateral(mint_tx, present: true) - tx_collateral_outputs(mint_tx, present: false) - tx_metadata(mint_tx, nil) - tx_deposits(mint_tx, deposit_taken: 0, deposit_returned: 0) - tx_withdrawals(mint_tx, present: false) - tx_mint_burn(mint_tx, mint: assets, burn: []) - tx_extra_signatures(mint_tx, present: true) - tx_script_integrity(mint_tx, present: true) - tx_validity_interval_default(mint_tx) - tx_certificates(mint_tx, present: false) - - tx_inputs(burn_tx, present: true) - tx_outputs(burn_tx, present: true) - tx_direction(burn_tx, 'outgoing') - tx_script_validity(burn_tx, 'valid') - tx_status(burn_tx, 'in_ledger') - tx_collateral(burn_tx, present: true) - tx_collateral_outputs(burn_tx, present: false) - tx_metadata(burn_tx, nil) - tx_deposits(burn_tx, deposit_taken: 0, deposit_returned: 0) - tx_withdrawals(burn_tx, present: false) - tx_mint_burn(burn_tx, mint: [], burn: assets) - tx_extra_signatures(burn_tx, present: true) - tx_script_integrity(burn_tx, present: true) - tx_validity_interval_default(burn_tx) - tx_certificates(burn_tx, present: false) - end - - it 'withdrawal' do - ## - # This test is withdrawing 0 rewards from stake account that has... 0 rewards. - # Such tx is silly but allowed by the node. - # Producing rewards on testnet is not practical due to long epoch length, - # however there is full e2e test version of this script redeemding 42 A rewards on local cluster. - # - # NOTE: - # The script cert had to be registered on-chain such that withdrawing is permitted. - # It was done once, manually: - # - # 1. Create cert from Plutus script: - # - # $ cat fixtures/plutus/withdrawal_validator_cardano_cli.script - # {"cborHex":"590853590850[...]cc0080080041","type":"PlutusScriptV1","description":""} - # $ cardano-cli stake-address registration-certificate --stake-script-file fixtures/plutus/withdrawal_validator_cardano_cli.script --out-file stake.cert - # - # 2. Register cert on-chain - # - # $ cardano-cli query utxo --address $(cat payment.addr) --testnet-magic 2 - # $ cardano-cli transaction build \ - # --babbage-era \ - # --testnet-magic 2 \ - # --change-address "addr_test1qrfqc909vvxfq7903kaz09cuh5q2un8zw7j9ys4uh3k7j3qpgncz6fapajjvkyqka2sldfpk250nml40sf67am68wd2shl9fth" \ - # --tx-in "0c07395aed88bdddc6de0518d1462dd0ec7e52e1e3a53599f7cdb24dc80237f8#0" \ - # --certificate-file stake.cert \ - # --protocol-params-file protocol.json \ - # --out-file body.tx - # - # $ cardano-cli transaction sign \ - # --tx-body-file body.tx \ - # --testnet-magic 2 \ - # --signing-key-file payment.skey \ - # --out-file signed.tx - # - # $ cardano-cli transaction submit --tx-file signed.tx --testnet-magic 2 - validator = read_mustached_file('withdrawal_validator') - validator_hash = get_policy_id(validator) - withdrawal_script = 'withdrawal.json' - payload = get_templated_plutus_tx(withdrawal_script, { script: validator, - scriptHash: validator_hash }) - - init_src = get_shelley_balances(@wid) - - r = run_script(withdrawal_script, payload) - - # verify wallet balance decreases as expected by fee - fee = r[:tx_balanced]['fee']['quantity'] - src_after = get_shelley_balances(@wid) - expect(src_after['total']).to eq(init_src['total'] - fee) - - # examine tx history - tx = SHELLEY.transactions.get(@wid, r[:tx_id]) - tx_inputs(tx, present: true) - tx_outputs(tx, present: true) - tx_direction(tx, 'outgoing') - tx_script_validity(tx, 'valid') - tx_status(tx, 'in_ledger') - tx_collateral(tx, present: true) - tx_collateral_outputs(tx, present: false) - tx_metadata(tx, nil) - tx_deposits(tx, deposit_taken: 0, deposit_returned: 0) - tx_withdrawals(tx, present: true) - tx_mint_burn(tx, mint: [], burn: []) - tx_extra_signatures(tx, present: true) - tx_script_integrity(tx, present: true) - tx_validity_interval_default(tx) - tx_certificates(tx, present: false) - end - - it 'currency' do - currency_script = 'currency.json' - currency_policy = 'currency_policy' - - # Perform coin selection to select input to be used in minting contract - address = SHELLEY.addresses.list(@wid)[0]['id'] - payload_cs = [{ address: address, - amount: { quantity: 10_000_000, unit: 'lovelace' } }] - coin_selection = SHELLEY.coin_selections.random(@wid, payload_cs) - print coin_selection if coin_selection['inputs'].nil? - input = coin_selection['inputs'].select { |i| i['assets'] == [] }.first - tx_id = input['id'] - tx_idx = input['index'].to_i - amount = input['amount']['quantity'].to_i - address = input['address'] - - # encode input indexes for contract payload - tx_idx_hex = tx_idx.to_cbor.cbor_to_hex # cbor as hex - encoded_tx_idx = plutus_encode_idx(tx_idx) # special Plutus bit-wise encoding - - # feed payload for contract with data from coin selection - policy = read_mustached_file(currency_policy, { transactionId: tx_id, - encodedTransactionIdx: encoded_tx_idx }) - policy_id = get_policy_id(policy) - payload = get_templated_plutus_tx(currency_script, { policy: policy, - policyId: policy_id, - transactionId: tx_id, - transactionIdx: tx_idx, - transactionIdxHex: tx_idx_hex, - amount: amount, - address: address }) - - # run contract - r = run_script(currency_script, payload) - - # expected minted currency - apfel = { 'policy_id' => policy_id, - 'asset_name' => asset_name('apfel'), - 'quantity' => 1000 } - banana = { 'policy_id' => policy_id, - 'asset_name' => asset_name('banana'), - 'quantity' => 1 } - - # verify decoded transactions show that currency will be minted - expect(r[:tx_unbalanced]['mint']['tokens'].to_s).to include policy_id - expect(r[:tx_unbalanced]['mint']['tokens'].to_s).to include asset_name('apfel') - expect(r[:tx_unbalanced]['mint']['tokens'].to_s).to include asset_name('banana') - expect(r[:tx_balanced]['mint']['tokens'].to_s).to include policy_id - expect(r[:tx_balanced]['mint']['tokens'].to_s).to include asset_name('apfel') - expect(r[:tx_balanced]['mint']['tokens'].to_s).to include asset_name('banana') - - # make sure currency is minted as expected - src_balance = get_shelley_balances(@wid) - expect(src_balance['assets_total']).to include(apfel) - expect(src_balance['assets_total']).to include(banana) - - # examine tx history - tx = SHELLEY.transactions.get(@wid, r[:tx_id]) - tx_inputs(tx, present: true) - tx_outputs(tx, present: true) - tx_direction(tx, 'outgoing') - tx_script_validity(tx, 'valid') - tx_status(tx, 'in_ledger') - tx_collateral(tx, present: true) - tx_collateral_outputs(tx, present: false) - tx_metadata(tx, nil) - tx_deposits(tx, deposit_taken: 0, deposit_returned: 0) - tx_withdrawals(tx, present: false) - mint_tokens = tx['mint']['tokens'].to_s - expect(mint_tokens).to include(asset_name('apfel')) - expect(mint_tokens).to include(asset_name('banana')) - expect(mint_tokens).to include(policy_id) - expect(mint_tokens).to include('plutus') - tx_mint_burn(tx, burn: []) - tx_extra_signatures(tx, present: true) - tx_script_integrity(tx, present: true) - tx_validity_interval_default(tx) - tx_certificates(tx, present: false) - - # send out minted currency to special address not to litter fixture wallet - payment = [{ address: 'addr_test1qqkgrywfhejgd67twkzqmx84rsr3v374pzujd5rlm0e8exnlxjupjgrqwk5dk9tard6zfwwjq4lc89szs2w599js35tqmaykuj', - amount: { quantity: 0, unit: 'lovelace' }, - assets: [apfel, banana] }] - tx_constructed = SHELLEY.transactions.construct(@wid, payment) - tx_signed = SHELLEY.transactions.sign(@wid, PASS, tx_constructed['transaction']) - tx_submitted = SHELLEY.transactions.submit(@wid, tx_signed['transaction']) - tx_id = tx_submitted['id'] - - wait_for_tx_in_ledger(@wid, tx_id) - - src_balance_after = get_shelley_balances(@wid) - expect(src_balance_after['assets_total']).not_to include(apfel) - expect(src_balance_after['assets_total']).not_to include(banana) - end - end - - describe 'E2E Construct -> Sign -> Submit' do - it 'I can get min_utxo_value when contructing tx' do - amt = 1 - tx_constructed = SHELLEY.transactions.construct(@wid, payment_payload(amt)) - expect(tx_constructed.code).to eq 403 - expect(tx_constructed['code']).to eq 'utxo_too_small' - required_minimum = tx_constructed['info']['tx_output_lovelace_required_minimum']['quantity'] - - tx_constructed = SHELLEY.transactions.construct(@wid, payment_payload(required_minimum)) - expect(tx_constructed).to be_correct_and_respond 202 - end - - it 'Single output transaction' do - amt = MIN_UTXO_VALUE_PURE_ADA - address = SHELLEY.addresses.list(@target_id)[0]['id'] - target_before = get_shelley_balances(@target_id) - src_before = get_shelley_balances(@wid) - - tx_constructed = SHELLEY.transactions.construct(@wid, payment_payload(amt, address)) - expect(tx_constructed).to be_correct_and_respond 202 - expected_fee = tx_constructed['fee']['quantity'] - tx_decoded = SHELLEY.transactions.decode(@wid, tx_constructed['transaction']) - expect(tx_decoded).to be_correct_and_respond 202 - # inputs are ours - expect(tx_decoded['inputs'].to_s).to include 'address' - expect(tx_decoded['inputs'].to_s).to include 'amount' - expect(tx_decoded['outputs']).not_to eq [] - expect(tx_decoded['script_validity']).to eq 'valid' - expect(tx_decoded['validity_interval']['invalid_before']).to eq({ 'quantity' => 0, 'unit' => 'slot' }) - expect(tx_decoded['validity_interval']['invalid_hereafter']['quantity']).to be > 0 - expect(tx_decoded['collateral']).to eq [] - expect(tx_decoded['collateral_outputs']).to eq [] - expect(tx_decoded['metadata']).to eq nil - expect(tx_decoded['deposits_taken']).to eq [] - expect(tx_decoded['deposits_returned']).to eq [] - expect(tx_decoded['withdrawals']).to eq [] - expect(tx_decoded['mint']).to eq({ 'tokens' => [] }) - expect(tx_decoded['burn']).to eq({ 'tokens' => [] }) - expect(tx_decoded['certificates']).to eq [] - expect(tx_decoded['witness_count']['verification_key']).to eq 0 - - decoded_fee = tx_decoded['fee']['quantity'] - expect(expected_fee).to eq decoded_fee - - tx_signed = SHELLEY.transactions.sign(@wid, PASS, tx_constructed['transaction']) - expect(tx_signed).to be_correct_and_respond 202 - signed_decoded = SHELLEY.transactions.decode(@wid, tx_signed['transaction']) - expect(signed_decoded['witness_count']['verification_key']).to be >= 1 - expect(expected_fee).to eq signed_decoded['fee']['quantity'] - - tx_submitted = SHELLEY.transactions.submit(@wid, tx_signed['transaction']) - expect(tx_submitted).to be_correct_and_respond 202 - tx_id = tx_submitted['id'] - - wait_for_tx_in_ledger(@wid, tx_id) - - target_after = get_shelley_balances(@target_id) - src_after = get_shelley_balances(@wid) - - # examine the tx in history - # on src wallet - tx = SHELLEY.transactions.get(@wid, tx_id) - tx_amount(tx, amt + expected_fee) - tx_fee(tx, expected_fee) - tx_inputs(tx, present: true) - tx_outputs(tx, present: true) - tx_direction(tx, 'outgoing') - tx_script_validity(tx, 'valid') - tx_status(tx, 'in_ledger') - tx_collateral(tx, present: false) - tx_collateral_outputs(tx, present: false) - tx_metadata(tx, nil) - tx_deposits(tx, deposit_taken: 0, deposit_returned: 0) - tx_withdrawals(tx, present: false) - tx_mint_burn(tx, mint: [], burn: []) - tx_extra_signatures(tx, present: false) - tx_script_integrity(tx, present: false) - tx_validity_interval_default(tx) - tx_certificates(tx, present: false) - - # on target wallet - txt = SHELLEY.transactions.get(@target_id, tx_id) - tx_amount(txt, amt) - tx_fee(tx, expected_fee) - tx_inputs(txt, present: true) - tx_outputs(txt, present: true) - tx_direction(txt, 'incoming') - tx_script_validity(txt, 'valid') - tx_status(txt, 'in_ledger') - tx_collateral(txt, present: false) - tx_collateral_outputs(txt, present: false) - tx_metadata(txt, nil) - # ADP-2298 - Deposit_returned is falsely reported on some incoming transactions (intermittently) - # tx_deposits(txt, deposit_taken: 0, deposit_returned: 0) - tx_withdrawals(txt, present: false) - tx_mint_burn(txt, mint: [], burn: []) - tx_extra_signatures(txt, present: false) - tx_script_integrity(txt, present: false) - tx_validity_interval_default(txt) - tx_certificates(txt, present: false) - - verify_ada_balance(src_after, src_before, - target_after, target_before, - amt, expected_fee) - end - - it 'Multi output transaction' do - amt = MIN_UTXO_VALUE_PURE_ADA - address = SHELLEY.addresses.list(@target_id)[0]['id'] - target_before = get_shelley_balances(@target_id) - src_before = get_shelley_balances(@wid) - - payment = [{ address: address, - amount: { quantity: amt, - unit: 'lovelace' } }, - { address: address, - amount: { quantity: amt, - unit: 'lovelace' } }] - tx_constructed = SHELLEY.transactions.construct(@wid, payment) - expect(tx_constructed).to be_correct_and_respond 202 - expected_fee = tx_constructed['fee']['quantity'] - tx_decoded = SHELLEY.transactions.decode(@wid, tx_constructed['transaction']) - expect(tx_decoded).to be_correct_and_respond 202 - # inputs are ours - expect(tx_decoded['inputs'].to_s).to include 'address' - expect(tx_decoded['inputs'].to_s).to include 'amount' - expect(tx_decoded['outputs']).not_to eq [] - expect(tx_decoded['script_validity']).to eq 'valid' - expect(tx_decoded['validity_interval']['invalid_before']).to eq({ 'quantity' => 0, 'unit' => 'slot' }) - expect(tx_decoded['validity_interval']['invalid_hereafter']['quantity']).to be > 0 - expect(tx_decoded['collateral']).to eq [] - expect(tx_decoded['collateral_outputs']).to eq [] - expect(tx_decoded['metadata']).to eq nil - expect(tx_decoded['deposits_taken']).to eq [] - expect(tx_decoded['deposits_returned']).to eq [] - expect(tx_decoded['withdrawals']).to eq [] - expect(tx_decoded['mint']).to eq({ 'tokens' => [] }) - expect(tx_decoded['burn']).to eq({ 'tokens' => [] }) - expect(tx_decoded['certificates']).to eq [] - expect(tx_decoded['witness_count']['verification_key']).to eq 0 - - decoded_fee = tx_decoded['fee']['quantity'] - expect(expected_fee).to eq decoded_fee - - tx_signed = SHELLEY.transactions.sign(@wid, PASS, tx_constructed['transaction']) - expect(tx_signed).to be_correct_and_respond 202 - signed_decoded = SHELLEY.transactions.decode(@wid, tx_signed['transaction']) - expect(signed_decoded['witness_count']['verification_key']).to be >= 1 - expect(expected_fee).to eq signed_decoded['fee']['quantity'] - - tx_submitted = SHELLEY.transactions.submit(@wid, tx_signed['transaction']) - expect(tx_submitted).to be_correct_and_respond 202 - tx_id = tx_submitted['id'] - - wait_for_tx_in_ledger(@wid, tx_id) - - target_after = get_shelley_balances(@target_id) - src_after = get_shelley_balances(@wid) - - # examine the tx in history - # on src wallet - tx = SHELLEY.transactions.get(@wid, tx_id) - tx_amount(tx, (amt * 2) + expected_fee) - tx_fee(tx, expected_fee) - tx_inputs(tx, present: true) - tx_outputs(tx, present: true) - tx_direction(tx, 'outgoing') - tx_script_validity(tx, 'valid') - tx_status(tx, 'in_ledger') - tx_collateral(tx, present: false) - tx_collateral_outputs(tx, present: false) - tx_metadata(tx, nil) - tx_deposits(tx, deposit_taken: 0, deposit_returned: 0) - tx_withdrawals(tx, present: false) - tx_mint_burn(tx, mint: [], burn: []) - tx_extra_signatures(tx, present: false) - tx_script_integrity(tx, present: false) - tx_validity_interval_default(tx) - tx_certificates(tx, present: false) - - # on target wallet - txt = SHELLEY.transactions.get(@target_id, tx_id) - tx_amount(txt, amt * 2) - tx_fee(tx, expected_fee) - tx_inputs(txt, present: true) - tx_outputs(txt, present: true) - tx_direction(txt, 'incoming') - tx_script_validity(txt, 'valid') - tx_status(txt, 'in_ledger') - tx_collateral(txt, present: false) - tx_collateral_outputs(txt, present: false) - tx_metadata(txt, nil) - # ADP-2298 - Deposit_returned is falsely reported on some incoming transactions (intermittently) - # tx_deposits(txt, deposit_taken: 0, deposit_returned: 0) - tx_withdrawals(txt, present: false) - tx_mint_burn(txt, mint: [], burn: []) - tx_extra_signatures(txt, present: false) - tx_script_integrity(txt, present: false) - tx_validity_interval_default(txt) - tx_certificates(txt, present: false) - - verify_ada_balance(src_after, src_before, - target_after, target_before, - (amt * 2), expected_fee) - end - - it 'Multi-assets transaction' do - amt = 1 - amt_ada = 1_600_000 - address = SHELLEY.addresses.list(@target_id)[1]['id'] - target_before = get_shelley_balances(@target_id) - src_before = get_shelley_balances(@wid) - - payment = [{ 'address' => address, - 'amount' => { 'quantity' => amt_ada, 'unit' => 'lovelace' }, - 'assets' => [{ 'policy_id' => ASSETS[0]['policy_id'], - 'asset_name' => ASSETS[0]['asset_name'], - 'quantity' => amt }, - { 'policy_id' => ASSETS[1]['policy_id'], - 'asset_name' => ASSETS[1]['asset_name'], - 'quantity' => amt }] }] - - tx_constructed = SHELLEY.transactions.construct(@wid, payment) - expect(tx_constructed).to be_correct_and_respond 202 - expected_fee = tx_constructed['fee']['quantity'] - tx_decoded = SHELLEY.transactions.decode(@wid, tx_constructed['transaction']) - expect(tx_decoded).to be_correct_and_respond 202 - # inputs are ours - expect(tx_decoded['inputs'].to_s).to include 'address' - expect(tx_decoded['inputs'].to_s).to include 'amount' - expect(tx_decoded['outputs']).not_to eq [] - expect(tx_decoded['script_validity']).to eq 'valid' - expect(tx_decoded['validity_interval']['invalid_before']).to eq({ 'quantity' => 0, 'unit' => 'slot' }) - expect(tx_decoded['validity_interval']['invalid_hereafter']['quantity']).to be > 0 - expect(tx_decoded['collateral']).to eq [] - expect(tx_decoded['collateral_outputs']).to eq [] - expect(tx_decoded['metadata']).to eq nil - expect(tx_decoded['deposits_taken']).to eq [] - expect(tx_decoded['deposits_returned']).to eq [] - expect(tx_decoded['withdrawals']).to eq [] - expect(tx_decoded['mint']).to eq({ 'tokens' => [] }) - expect(tx_decoded['burn']).to eq({ 'tokens' => [] }) - expect(tx_decoded['certificates']).to eq [] - expect(tx_decoded['witness_count']['verification_key']).to eq 0 - - decoded_fee = tx_decoded['fee']['quantity'] - expect(expected_fee).to eq decoded_fee - - tx_signed = SHELLEY.transactions.sign(@wid, PASS, tx_constructed['transaction']) - expect(tx_signed).to be_correct_and_respond 202 - signed_decoded = SHELLEY.transactions.decode(@wid, tx_signed['transaction']) - expect(signed_decoded['witness_count']['verification_key']).to be >= 1 - expect(expected_fee).to eq signed_decoded['fee']['quantity'] - - tx_submitted = SHELLEY.transactions.submit(@wid, tx_signed['transaction']) - expect(tx_submitted).to be_correct_and_respond 202 - tx_id = tx_submitted['id'] - - wait_for_tx_in_ledger(@wid, tx_id) - - target_after = get_shelley_balances(@target_id) - src_after = get_shelley_balances(@wid) - - # examine the tx in history - # on src wallet - tx = SHELLEY.transactions.get(@wid, tx_id) - tx_amount(tx, amt_ada + expected_fee) - tx_fee(tx, expected_fee) - tx_inputs(tx, present: true) - tx_outputs(tx, present: true) - tx_direction(tx, 'outgoing') - tx_script_validity(tx, 'valid') - tx_status(tx, 'in_ledger') - tx_collateral(tx, present: false) - tx_collateral_outputs(tx, present: false) - tx_metadata(tx, nil) - tx_deposits(tx, deposit_taken: 0, deposit_returned: 0) - tx_withdrawals(tx, present: false) - tx_mint_burn(tx, mint: [], burn: []) - tx_extra_signatures(tx, present: false) - tx_script_integrity(tx, present: false) - tx_validity_interval_default(tx) - tx_certificates(tx, present: false) - - # on target wallet - txt = SHELLEY.transactions.get(@target_id, tx_id) - tx_amount(txt, amt_ada) - tx_fee(tx, expected_fee) - tx_inputs(txt, present: true) - tx_outputs(txt, present: true) - tx_direction(txt, 'incoming') - tx_script_validity(txt, 'valid') - tx_status(txt, 'in_ledger') - tx_collateral(txt, present: false) - tx_collateral_outputs(txt, present: false) - tx_metadata(txt, nil) - # ADP-2298 - Deposit_returned is falsely reported on some incoming transactions (intermittently) - # tx_deposits(txt, deposit_taken: 0, deposit_returned: 0) - tx_withdrawals(txt, present: false) - tx_mint_burn(txt, mint: [], burn: []) - tx_extra_signatures(txt, present: false) - tx_script_integrity(txt, present: false) - tx_validity_interval_default(txt) - tx_certificates(txt, present: false) - - verify_ada_balance(src_after, src_before, - target_after, target_before, - amt_ada, expected_fee) - - verify_asset_balance(src_after, src_before, - target_after, target_before, - amt) - - # Target wallet lists my associated assets - assets = SHELLEY.assets.get(@target_id) - expect(assets).to be_correct_and_respond 200 - expect(assets.to_s).to include ASSETS[0]['policy_id'] - expect(assets.to_s).to include ASSETS[0]['asset_name'] - expect(assets.to_s).to include ASSETS[1]['policy_id'] - expect(assets.to_s).to include ASSETS[1]['asset_name'] - end - - it 'Only withdrawal' do - balance = get_shelley_balances(@wid) - tx_constructed = SHELLEY.transactions.construct(@wid, - nil, # payments - 'self') # withdrawal - expect(tx_constructed).to be_correct_and_respond 202 - # withdrawal = tx_constructed['coin_selection']['withdrawals'].map { |x| x['amount']['quantity'] }.first - # expect(withdrawal).to eq 0 - expected_fee = tx_constructed['fee']['quantity'] - tx_decoded = SHELLEY.transactions.decode(@wid, tx_constructed['transaction']) - expect(tx_decoded).to be_correct_and_respond 202 - # inputs are ours - expect(tx_decoded['inputs'].to_s).to include 'address' - expect(tx_decoded['inputs'].to_s).to include 'amount' - expect(tx_decoded['outputs']).not_to eq [] - expect(tx_decoded['script_validity']).to eq 'valid' - expect(tx_decoded['validity_interval']['invalid_before']).to eq({ 'quantity' => 0, 'unit' => 'slot' }) - expect(tx_decoded['validity_interval']['invalid_hereafter']['quantity']).to be > 0 - expect(tx_decoded['collateral']).to eq [] - expect(tx_decoded['collateral_outputs']).to eq [] - expect(tx_decoded['metadata']).to eq nil - expect(tx_decoded['deposits_taken']).to eq [] - expect(tx_decoded['deposits_returned']).to eq [] - expect(tx_decoded['withdrawals']).to eq [] - expect(tx_decoded['mint']).to eq({ 'tokens' => [] }) - expect(tx_decoded['burn']).to eq({ 'tokens' => [] }) - expect(tx_decoded['certificates']).to eq [] - expect(tx_decoded['witness_count']['verification_key']).to eq 0 - - decoded_fee = tx_decoded['fee']['quantity'] - expect(expected_fee).to eq decoded_fee - - tx_signed = SHELLEY.transactions.sign(@wid, PASS, tx_constructed['transaction']) - expect(tx_signed).to be_correct_and_respond 202 - signed_decoded = SHELLEY.transactions.decode(@wid, tx_signed['transaction']) - expect(signed_decoded['witness_count']['verification_key']).to be >= 1 - expect(expected_fee).to eq signed_decoded['fee']['quantity'] - - tx_submitted = SHELLEY.transactions.submit(@wid, tx_signed['transaction']) - expect(tx_submitted).to be_correct_and_respond 202 - tx_id = tx_submitted['id'] - - wait_for_tx_in_ledger(@wid, tx_id) - - # examine the tx in history - # on src wallet - tx = SHELLEY.transactions.get(@wid, tx_id) - tx_amount(tx, expected_fee) - tx_fee(tx, expected_fee) - tx_inputs(tx, present: true) - tx_outputs(tx, present: true) - tx_direction(tx, 'outgoing') - tx_script_validity(tx, 'valid') - tx_status(tx, 'in_ledger') - tx_collateral(tx, present: false) - tx_collateral_outputs(tx, present: false) - tx_metadata(tx, nil) - tx_deposits(tx, deposit_taken: 0, deposit_returned: 0) - tx_withdrawals(tx, present: false) # tx has no withdrawals - tx_mint_burn(tx, mint: [], burn: []) - tx_extra_signatures(tx, present: false) - tx_script_integrity(tx, present: false) - tx_validity_interval_default(tx) - tx_certificates(tx, present: false) - - # verify balance is as expected - new_balance = get_shelley_balances(@wid) - expect(new_balance['available']).to eq(balance['available'] - expected_fee) - expect(new_balance['total']).to eq(balance['total'] - expected_fee) - end - - it 'Only metadata' do - metadata = METADATA - balance = get_shelley_balances(@wid) - tx_constructed = SHELLEY.transactions.construct(@wid, - nil, # payments - nil, # withdrawal - metadata) - expect(tx_constructed).to be_correct_and_respond 202 - expected_fee = tx_constructed['fee']['quantity'] - tx_decoded = SHELLEY.transactions.decode(@wid, tx_constructed['transaction']) - expect(tx_decoded).to be_correct_and_respond 202 - - decoded_fee = tx_decoded['fee']['quantity'] - expect(expected_fee).to eq decoded_fee - - # inputs are ours - expect(tx_decoded['inputs'].to_s).to include 'address' - expect(tx_decoded['inputs'].to_s).to include 'amount' - expect(tx_decoded['outputs']).not_to eq [] - expect(tx_decoded['script_validity']).to eq 'valid' - expect(tx_decoded['validity_interval']['invalid_before']).to eq({ 'quantity' => 0, 'unit' => 'slot' }) - expect(tx_decoded['validity_interval']['invalid_hereafter']['quantity']).to be > 0 - expect(tx_decoded['collateral']).to eq [] - expect(tx_decoded['collateral_outputs']).to eq [] - expect(tx_decoded['metadata']).to eq metadata - expect(tx_decoded['deposits_taken']).to eq [] - expect(tx_decoded['deposits_returned']).to eq [] - expect(tx_decoded['withdrawals']).to eq [] - expect(tx_decoded['mint']).to eq({ 'tokens' => [] }) - expect(tx_decoded['burn']).to eq({ 'tokens' => [] }) - expect(tx_decoded['certificates']).to eq [] - expect(tx_decoded['witness_count']['verification_key']).to eq 0 - - tx_signed = SHELLEY.transactions.sign(@wid, PASS, tx_constructed['transaction']) - expect(tx_signed).to be_correct_and_respond 202 - signed_decoded = SHELLEY.transactions.decode(@wid, tx_signed['transaction']) - expect(signed_decoded['witness_count']['verification_key']).to be >= 1 - expect(expected_fee).to eq signed_decoded['fee']['quantity'] - - tx_submitted = SHELLEY.transactions.submit(@wid, tx_signed['transaction']) - expect(tx_submitted).to be_correct_and_respond 202 - tx_id = tx_submitted['id'] - - wait_for_tx_in_ledger(@wid, tx_id) - - # examine the tx in history - # on src wallet - tx = SHELLEY.transactions.get(@wid, tx_id) - tx_amount(tx, expected_fee) - tx_fee(tx, expected_fee) - tx_inputs(tx, present: true) - tx_outputs(tx, present: true) - tx_direction(tx, 'outgoing') - tx_script_validity(tx, 'valid') - tx_status(tx, 'in_ledger') - tx_collateral(tx, present: false) - tx_collateral_outputs(tx, present: false) - tx_metadata(tx, metadata) - tx_deposits(tx, deposit_taken: 0, deposit_returned: 0) - tx_withdrawals(tx, present: false) - tx_mint_burn(tx, mint: [], burn: []) - tx_extra_signatures(tx, present: false) - tx_script_integrity(tx, present: false) - tx_validity_interval_default(tx) - tx_certificates(tx, present: false) - - # verify balance is as expected - new_balance = get_shelley_balances(@wid) - expect(new_balance['available']).to eq(balance['available'] - expected_fee) - expect(new_balance['total']).to eq(balance['total'] - expected_fee) - end - - it 'Validity intervals' do - amt = MIN_UTXO_VALUE_PURE_ADA - address = SHELLEY.addresses.list(@target_id)[0]['id'] - target_before = get_shelley_balances(@target_id) - src_before = get_shelley_balances(@wid) - inv_before = 500 - inv_hereafter = 5_000_000_000 - validity_interval = { 'invalid_before' => { 'quantity' => inv_before, 'unit' => 'slot' }, - 'invalid_hereafter' => { 'quantity' => inv_hereafter, 'unit' => 'slot' } } - - tx_constructed = SHELLEY.transactions.construct(@wid, - payment_payload(amt, address), - nil, # withdrawal - nil, # metadata - nil, # delegations - nil, # mint_burn - validity_interval) - expect(tx_constructed).to be_correct_and_respond 202 - expected_fee = tx_constructed['fee']['quantity'] - tx_decoded = SHELLEY.transactions.decode(@wid, tx_constructed['transaction']) - expect(tx_decoded).to be_correct_and_respond 202 - # inputs are ours - expect(tx_decoded['inputs'].to_s).to include 'address' - expect(tx_decoded['inputs'].to_s).to include 'amount' - expect(tx_decoded['outputs']).not_to eq [] - expect(tx_decoded['script_validity']).to eq 'valid' - expect(tx_decoded['validity_interval']['invalid_before']).to eq validity_interval['invalid_before'] - expect(tx_decoded['validity_interval']['invalid_hereafter']).to eq validity_interval['invalid_hereafter'] - expect(tx_decoded['collateral']).to eq [] - expect(tx_decoded['collateral_outputs']).to eq [] - expect(tx_decoded['metadata']).to eq nil - expect(tx_decoded['deposits_taken']).to eq [] - expect(tx_decoded['deposits_returned']).to eq [] - expect(tx_decoded['withdrawals']).to eq [] - expect(tx_decoded['mint']).to eq({ 'tokens' => [] }) - expect(tx_decoded['burn']).to eq({ 'tokens' => [] }) - expect(tx_decoded['certificates']).to eq [] - expect(tx_decoded['witness_count']['verification_key']).to eq 0 - - decoded_fee = tx_decoded['fee']['quantity'] - expect(expected_fee).to eq decoded_fee - - tx_signed = SHELLEY.transactions.sign(@wid, PASS, tx_constructed['transaction']) - expect(tx_signed).to be_correct_and_respond 202 - signed_decoded = SHELLEY.transactions.decode(@wid, tx_signed['transaction']) - expect(signed_decoded['witness_count']['verification_key']).to be >= 1 - expect(expected_fee).to eq signed_decoded['fee']['quantity'] - - tx_submitted = SHELLEY.transactions.submit(@wid, tx_signed['transaction']) - expect(tx_submitted).to be_correct_and_respond 202 - tx_id = tx_submitted['id'] - - wait_for_tx_in_ledger(@wid, tx_id) - - target_after = get_shelley_balances(@target_id) - src_after = get_shelley_balances(@wid) - - # examine the tx in history - # on src wallet - tx = SHELLEY.transactions.get(@wid, tx_id) - tx_amount(tx, amt + expected_fee) - tx_fee(tx, expected_fee) - tx_inputs(tx, present: true) - tx_outputs(tx, present: true) - tx_direction(tx, 'outgoing') - tx_script_validity(tx, 'valid') - tx_status(tx, 'in_ledger') - tx_collateral(tx, present: false) - tx_collateral_outputs(tx, present: false) - tx_metadata(tx, nil) - tx_deposits(tx, deposit_taken: 0, deposit_returned: 0) - tx_withdrawals(tx, present: false) - tx_mint_burn(tx, mint: [], burn: []) - tx_extra_signatures(tx, present: false) - tx_script_integrity(tx, present: false) - tx_validity_interval(tx, invalid_before: inv_before, invalid_hereafter: inv_hereafter) - tx_certificates(tx, present: false) - - # on target wallet - txt = SHELLEY.transactions.get(@target_id, tx_id) - tx_amount(txt, amt) - tx_fee(tx, expected_fee) - tx_inputs(txt, present: true) - tx_outputs(txt, present: true) - tx_direction(txt, 'incoming') - tx_script_validity(txt, 'valid') - tx_status(txt, 'in_ledger') - tx_collateral(txt, present: false) - tx_collateral_outputs(txt, present: false) - tx_metadata(txt, nil) - # ADP-2298 - Deposit_returned is falsely reported on some incoming transactions (intermittently) - # tx_deposits(txt, deposit_taken: 0, deposit_returned: 0) - tx_withdrawals(txt, present: false) - tx_mint_burn(txt, mint: [], burn: []) - tx_extra_signatures(txt, present: false) - tx_script_integrity(txt, present: false) - tx_validity_interval(txt, invalid_before: inv_before, invalid_hereafter: inv_hereafter) - tx_certificates(txt, present: false) - - verify_ada_balance(src_after, src_before, - target_after, target_before, - amt, expected_fee) - end - - it 'Delegation (join and quit)' do - skip 'ADP-3243' - balance = get_shelley_balances(@target_id) - expected_deposit = CARDANO_CLI.protocol_params['stakeAddressDeposit'] - puts "Expected deposit #{expected_deposit}" - # Check wallet stake keys before joing stake pool - stake_keys = SHELLEY.stake_pools.list_stake_keys(@target_id) - expect(stake_keys).to be_correct_and_respond 200 - expect(stake_keys['foreign'].size).to eq 0 - expect(stake_keys['ours'].size).to eq 1 - expect(stake_keys['ours'].first['stake']['quantity']).to eq balance['total'] - expect(stake_keys['none']['stake']['quantity']).to eq 0 - expect(stake_keys['ours'].first['delegation']['active']['status']).to eq 'not_delegating' - - # Pick up pool id to join - pools = SHELLEY.stake_pools - pool_id = pools.list({ stake: 1000 }).sample['id'] - - # Join pool - delegation = [{ - 'join' => { - 'pool' => pool_id, - 'stake_key_index' => '0H' - } - }] - tx_constructed, tx_signed, tx_submitted = construct_sign_submit(@target_id, - nil, # payments - nil, # withdrawal - nil, # metadata - delegation) - # Check fee and deposit on joining - decoded_tx = SHELLEY.transactions.decode(@target_id, tx_constructed['transaction']) - deposit_taken = tx_constructed['coin_selection']['deposits_taken'].first['quantity'] - decoded_deposit_taken = decoded_tx['deposits_taken'].first['quantity'] - expect(deposit_taken).to eq decoded_deposit_taken - expect(deposit_taken).to eq expected_deposit - expect(decoded_tx['deposits_returned']).to eq [] - - expected_fee = tx_constructed['fee']['quantity'] - decoded_fee = decoded_tx['fee']['quantity'] - expect(decoded_fee).to eq expected_fee - - # witness count - expect(decoded_tx['witness_count']['verification_key']).to eq 0 - signed_tx = SHELLEY.transactions.decode(@target_id, tx_signed['transaction']) - expect(signed_tx['witness_count']['verification_key']).to be >= 1 - - # Certificates - expect(decoded_tx['certificates']).to include(have_key('certificate_type')).twice - expect(decoded_tx['certificates']).to include(have_value('register_reward_account')).once - expect(decoded_tx['certificates']).to include(have_value('join_pool')).once - expect(decoded_tx['certificates']).to include(have_key('reward_account_path')).twice - expect(decoded_tx['certificates']).to include(have_value(%w[1852H 1815H 0H 2 0])).twice - expect(decoded_tx['certificates']).to include(have_key('pool')).once - expect(decoded_tx['certificates']).to include(have_value(pool_id)).once - - tx_id = tx_submitted['id'] - wait_for_tx_in_ledger(@target_id, tx_id) - - # Check fee and balance and deposit after joining - tx = SHELLEY.transactions.get(@target_id, tx_id) - tx_amount(tx, expected_deposit + expected_fee) - tx_fee(tx, expected_fee) - tx_inputs(tx, present: true) - tx_outputs(tx, present: true) - tx_direction(tx, 'outgoing') - tx_script_validity(tx, 'valid') - tx_status(tx, 'in_ledger') - tx_collateral(tx, present: false) - tx_collateral_outputs(tx, present: false) - tx_metadata(tx, nil) - tx_deposits(tx, deposit_taken: deposit_taken, deposit_returned: 0) - tx_withdrawals(tx, present: false) - tx_mint_burn(tx, mint: [], burn: []) - tx_extra_signatures(tx, present: false) - tx_script_integrity(tx, present: false) - tx_validity_interval_default(tx) - tx_certificates(tx, present: true, certificates: decoded_tx['certificates']) - expect(tx['certificates'].to_s).to include 'register_reward_account' - expect(tx['certificates'].to_s).to include 'join_pool' - expect(tx['certificates'].to_s).to include pool_id - - join_balance = get_shelley_balances(@target_id) - expected_join_balance = balance['total'] - deposit_taken - expected_fee - expect(join_balance['total']).to eq expected_join_balance - - # Check wallet stake keys after joing stake pool - stake_keys = SHELLEY.stake_pools.list_stake_keys(@target_id) - expect(stake_keys).to be_correct_and_respond 200 - expect(stake_keys['foreign'].size).to eq 0 - expect(stake_keys['ours'].size).to eq 1 - expect(stake_keys['ours'].first['stake']['quantity']).to eq expected_join_balance - expect(stake_keys['none']['stake']['quantity']).to eq 0 - expect(stake_keys['ours'].first['delegation']['active']['status']).to eq 'not_delegating' - expect(stake_keys['ours'].first['delegation']['next'].last['status']).to eq 'delegating' - - # Quit pool - quit_pool = [{ 'quit' => { 'stake_key_index' => '0H' } }] - tx_constructed, tx_signed, tx_submitted = construct_sign_submit(@target_id, - nil, # payments - nil, # withdrawal - nil, # metadata - quit_pool) - - # Check fee and deposit on quitting - decoded_tx = SHELLEY.transactions.decode(@target_id, tx_constructed['transaction']) - expect(decoded_tx).to be_correct_and_respond 202 - - # witness count - expect(decoded_tx['witness_count']['verification_key']).to eq 0 - signed_tx = SHELLEY.transactions.decode(@target_id, tx_signed['transaction']) - expect(signed_tx['witness_count']['verification_key']).to be >= 1 - - # Certificates - expect(decoded_tx['certificates']).to include(have_key('certificate_type')).once - expect(decoded_tx['certificates']).to include(have_value('quit_pool')).once - expect(decoded_tx['certificates']).to include(have_key('reward_account_path')).once - expect(decoded_tx['certificates']).to include(have_value(%w[1852H 1815H 0H 2 0])).once - expect(decoded_tx['certificates']).not_to include(have_value('register_reward_account')) - expect(decoded_tx['certificates']).not_to include(have_key('pool')).once - expect(decoded_tx['certificates']).not_to include(have_value(pool_id)).once - - expect(tx_constructed['coin_selection']['deposits_taken']).to eq [] - expect(decoded_tx['deposits_taken']).to eq [] - deposit_returned = tx_constructed['coin_selection']['deposits_returned'].first['quantity'] - decoded_deposit_returned = decoded_tx['deposits_returned'].first['quantity'] - expect(deposit_returned).to eq decoded_deposit_returned - expect(deposit_returned).to eq expected_deposit - - expected_fee = tx_constructed['fee']['quantity'] - decoded_fee = decoded_tx['fee']['quantity'] - expect(expected_fee).to eq decoded_fee - - tx_id = tx_submitted['id'] - wait_for_tx_in_ledger(@target_id, tx_id) - - # Check fee and balance and deposit after quitting - quit_balance = get_shelley_balances(@target_id) - tx = SHELLEY.transactions.get(@target_id, tx_id) - expect(tx['amount']['quantity']).to be > 0 - expect(tx['amount']['quantity']).to be < deposit_returned - tx_fee(tx, expected_fee) - tx_inputs(tx, present: true) - tx_outputs(tx, present: true) - tx_direction(tx, 'incoming') - tx_script_validity(tx, 'valid') - tx_status(tx, 'in_ledger') - tx_collateral(tx, present: false) - tx_collateral_outputs(tx, present: false) - tx_metadata(tx, nil) - # ADP-2298 - Deposit_returned is falsely reported on some incoming transactions (intermittently) - # tx_deposits(tx, deposit_taken: 0, deposit_returned: deposit_returned) - tx_withdrawals(tx, present: false) - tx_mint_burn(tx, mint: [], burn: []) - tx_extra_signatures(tx, present: false) - tx_script_integrity(tx, present: false) - tx_validity_interval_default(tx) - tx_certificates(tx, present: true, certificates: decoded_tx['certificates']) - expect(tx['certificates'].to_s).to include 'quit_pool' - - expected_quit_balance = join_balance['total'] + deposit_returned - expected_fee - expect(quit_balance['total']).to eq expected_quit_balance - - # Check wallet stake keys after quitting - stake_keys = SHELLEY.stake_pools.list_stake_keys(@target_id) - expect(stake_keys).to be_correct_and_respond 200 - expect(stake_keys['foreign'].size).to eq 0 - expect(stake_keys['ours'].size).to eq 1 - # deposit is back on quitting so stake is higher than before - expect(stake_keys['ours'].first['stake']['quantity']).to eq expected_quit_balance - expect(stake_keys['none']['stake']['quantity']).to eq 0 - expect(stake_keys['ours'].first['delegation']['active']['status']).to eq 'not_delegating' - expect(stake_keys['ours'].first['delegation']['next'].last['status']).to eq 'not_delegating' - end - - describe 'Minting and Burning' do - ## - # Tx1: Mints 3 x 1000 assets, each guarded by different policy script - # Tx2: Burns 3 x 500 of each and verifies 500 of each remain on wallet - # Tx3: Burns remaining 3 x 500 and verifies they're no longer on balance - it 'Can mint and then burn' do - src_before = get_shelley_balances(@wid) - address = SHELLEY.addresses.list(@wid).first['id'] - policy_script1 = 'cosigner#0' - policy_script2 = { 'all' => ['cosigner#0'] } - policy_script3 = { 'any' => ['cosigner#0'] } - # Get policy_ids: - policy_id1 = SHELLEY.keys.create_policy_id(@wid, policy_script1)['policy_id'] - policy_id2 = SHELLEY.keys.create_policy_id(@wid, policy_script2)['policy_id'] - policy_id3 = SHELLEY.keys.create_policy_id(@wid, policy_script3)['policy_id'] - # Get policy key hash - policy_vkh = SHELLEY.keys.get_policy_key(@wid, { hash: true }).gsub('"', '') - - # Minting: - mint = [mint(asset_name('Token1'), 1000, policy_script1, address), - mint(asset_name('Token2'), 1000, policy_script2), - mint('', 1000, policy_script3)] - create_policy_key_if_not_exists(@wid) - tx_constructed, tx_signed, tx_submitted = construct_sign_submit(@wid, - nil, # payments - nil, # withdrawal - nil, # metadata - nil, # delegations - mint) - tx_decoded = SHELLEY.transactions.decode(@wid, tx_constructed['transaction']) - expect(tx_constructed).to be_correct_and_respond 202 - expected_fee = tx_constructed['fee']['quantity'] - decoded_fee = tx_decoded['fee']['quantity'] - expect(expected_fee).to eq decoded_fee - - # witness count - expect(tx_decoded['witness_count']['verification_key']).to eq 0 - signed_tx = SHELLEY.transactions.decode(@wid, tx_signed['transaction']) - expect(signed_tx['witness_count']['verification_key']).to be >= 1 - - # Mint - expect(tx_decoded['mint']['tokens']).to include(have_key('assets')).exactly(3).times - expect(tx_decoded['mint']['tokens'].to_s).to include(policy_vkh).exactly(3).times - expect(tx_decoded['mint']['tokens'].to_s).to include('1000').exactly(3).times - expect(tx_decoded['mint']['tokens'].to_s).to include(policy_id1).once - expect(tx_decoded['mint']['tokens'].to_s).to include(policy_id2).once - expect(tx_decoded['mint']['tokens'].to_s).to include(policy_id3).once - expect(tx_decoded['mint']['tokens'].to_s).to include(asset_name('Token1')).once - expect(tx_decoded['mint']['tokens'].to_s).to include(asset_name('Token2')).once - - tx_id = tx_submitted['id'] - wait_for_tx_in_ledger(@wid, tx_id) - - # examine the tx in history - # on src wallet - tx = SHELLEY.transactions.get(@wid, tx_id) - tx_amount(tx, expected_fee) - tx_fee(tx, expected_fee) - tx_inputs(tx, present: true) - tx_outputs(tx, present: true) - tx_direction(tx, 'outgoing') - tx_script_validity(tx, 'valid') - tx_status(tx, 'in_ledger') - tx_collateral(tx, present: false) - tx_collateral_outputs(tx, present: false) - tx_metadata(tx, nil) - tx_deposits(tx, deposit_taken: 0, deposit_returned: 0) - tx_withdrawals(tx, present: false) - expect(tx['mint']).to eq tx_decoded['mint'] - tx_mint_burn(tx, mint: tx_decoded['mint']['tokens'], burn: []) - tx_extra_signatures(tx, present: false) - tx_script_integrity(tx, present: false) - tx_validity_interval_default(tx) - tx_certificates(tx, present: false) - - # verify ADA balance is correct (fee is deducted) - src_after_minting = get_shelley_balances(@wid) - expect(src_after_minting['available']).to eq(src_before['available'] - expected_fee) - expect(src_after_minting['total']).to eq(src_before['total'] - expected_fee) - - # verify assets have been minted and on wallet's balance - assets_to_check = get_assets_from_decode(tx_decoded['mint']) - assets = assets_balance(src_after_minting['assets_total'], { assets_to_check: assets_to_check }) - expect(assets).to eq(assets_to_check.to_set { |z| { z => 1000 } }) - - # Burn half: - burn = [burn(asset_name('Token1'), 500, policy_script1), - burn(asset_name('Token2'), 500, policy_script2), - burn('', 500, policy_script3)] - tx_constructed, tx_signed, tx_submitted = construct_sign_submit(@wid, - nil, # payments - nil, # withdrawal - nil, # metadata - nil, # delegations - burn) - tx_decoded = SHELLEY.transactions.decode(@wid, tx_constructed['transaction']) - expect(tx_constructed).to be_correct_and_respond 202 - expected_fee = tx_constructed['fee']['quantity'] - decoded_fee = tx_decoded['fee']['quantity'] - expect(expected_fee).to eq decoded_fee - - # witness count - expect(tx_decoded['witness_count']['verification_key']).to eq 0 - signed_tx = SHELLEY.transactions.decode(@target_id, tx_signed['transaction']) - expect(signed_tx['witness_count']['verification_key']).to be >= 1 - - # Burn - expect(tx_decoded['burn']['tokens']).to include(have_key('assets')).exactly(3).times - expect(tx_decoded['burn']['tokens'].to_s).to include(policy_vkh).exactly(3).times - expect(tx_decoded['burn']['tokens'].to_s).to include('500').exactly(3).times - expect(tx_decoded['burn']['tokens'].to_s).to include(policy_id1).once - expect(tx_decoded['burn']['tokens'].to_s).to include(policy_id2).once - expect(tx_decoded['burn']['tokens'].to_s).to include(policy_id3).once - expect(tx_decoded['burn']['tokens'].to_s).to include(asset_name('Token1')).once - expect(tx_decoded['burn']['tokens'].to_s).to include(asset_name('Token2')).once - - tx_id = tx_submitted['id'] - wait_for_tx_in_ledger(@wid, tx_id) - # examine the burn tx in history - # on src wallet - tx = SHELLEY.transactions.get(@wid, tx_id) - tx_amount(tx, expected_fee) - tx_fee(tx, expected_fee) - tx_inputs(tx, present: true) - tx_outputs(tx, present: true) - tx_direction(tx, 'outgoing') - tx_script_validity(tx, 'valid') - tx_status(tx, 'in_ledger') - tx_collateral(tx, present: false) - tx_collateral_outputs(tx, present: false) - tx_metadata(tx, nil) - tx_deposits(tx, deposit_taken: 0, deposit_returned: 0) - tx_withdrawals(tx, present: false) - expect(tx['burn']).to eq tx_decoded['burn'] - tx_mint_burn(tx, mint: [], burn: tx_decoded['burn']['tokens']) - tx_extra_signatures(tx, present: false) - tx_script_integrity(tx, present: false) - tx_validity_interval_default(tx) - tx_certificates(tx, present: false) - - # verify ADA balance is correct (fee is deducted) - src_after_burning = get_shelley_balances(@wid) - expect(src_after_burning['available']).to eq(src_after_minting['available'] - expected_fee) - expect(src_after_burning['total']).to eq(src_after_minting['total'] - expected_fee) - - # verify half of assets have ben burned - assets = assets_balance(src_after_burning['assets_total'], - { assets_to_check: assets_to_check }) - expect(assets).to eq(assets_to_check.to_set { |z| { z => 500 } }) - - # Burn all the rest: - burn = [burn(asset_name('Token1'), 500, policy_script1), - burn(asset_name('Token2'), 500, policy_script2), - burn(nil, 500, policy_script3)] - tx_constructed, _, tx_submitted = construct_sign_submit(@wid, - nil, # payments - nil, # withdrawal - nil, # metadata - nil, # delegations - burn) - tx_decoded = SHELLEY.transactions.decode(@wid, tx_constructed['transaction']) - expect(tx_constructed).to be_correct_and_respond 202 - expected_fee = tx_constructed['fee']['quantity'] - decoded_fee = tx_decoded['fee']['quantity'] - expect(expected_fee).to eq decoded_fee - - # Burn again - expect(tx_decoded['burn']['tokens']).to include(have_key('assets')).exactly(3).times - expect(tx_decoded['burn']['tokens'].to_s).to include(policy_vkh).exactly(3).times - expect(tx_decoded['burn']['tokens'].to_s).to include('500').exactly(3).times - expect(tx_decoded['burn']['tokens'].to_s).to include(policy_id1).once - expect(tx_decoded['burn']['tokens'].to_s).to include(policy_id2).once - expect(tx_decoded['burn']['tokens'].to_s).to include(policy_id3).once - expect(tx_decoded['burn']['tokens'].to_s).to include(asset_name('Token1')).once - expect(tx_decoded['burn']['tokens'].to_s).to include(asset_name('Token2')).once - - tx_id = tx_submitted['id'] - wait_for_tx_in_ledger(@wid, tx_id) - src_after_burning_all = get_shelley_balances(@wid) - # examine the burn again tx in history - # on src wallet - tx = SHELLEY.transactions.get(@wid, tx_id) - tx_amount(tx, expected_fee) - tx_fee(tx, expected_fee) - tx_inputs(tx, present: true) - tx_outputs(tx, present: true) - tx_direction(tx, 'outgoing') - tx_script_validity(tx, 'valid') - tx_status(tx, 'in_ledger') - tx_collateral(tx, present: false) - tx_collateral_outputs(tx, present: false) - tx_metadata(tx, nil) - tx_deposits(tx, deposit_taken: 0, deposit_returned: 0) - tx_withdrawals(tx, present: false) - expect(tx['burn']).to eq tx_decoded['burn'] - tx_mint_burn(tx, mint: [], burn: tx_decoded['burn']['tokens']) - tx_extra_signatures(tx, present: false) - tx_script_integrity(tx, present: false) - tx_validity_interval_default(tx) - tx_certificates(tx, present: false) - - # verify ADA balance is correct (fee is deducted) - expect(src_after_burning_all['available']).to eq(src_after_burning['available'] - expected_fee) - expect(src_after_burning_all['total']).to eq(src_after_burning['total'] - expected_fee) - - # verify all assets have been burned and no longer on wallet's balance - assets = assets_balance(src_after_burning_all['assets_total'], - { assets_to_check: assets_to_check }) - expect(assets).to eq({}.to_set) - end - - ## - # Tx1: Mints 3 x 1 assets with metadata - # Tx2: Burns 3 x 1 assets and also assign metadata to tx - it 'Can mint and burn with metadata' do - src_before = get_shelley_balances(@wid) - address = SHELLEY.addresses.list(@wid).first['id'] - policy_script1 = 'cosigner#0' - policy_script2 = 'cosigner#0' - policy_script3 = { 'any' => ['cosigner#0'] } - metadata = METADATA - assets_quantity = 1 - - # Minting: - mint = [mint(asset_name('TokenMetadata1'), assets_quantity, policy_script1, address), - mint(asset_name('TokenMetadata2'), assets_quantity, policy_script2), - mint(asset_name('TokenMetadata3'), assets_quantity, policy_script3)] - create_policy_key_if_not_exists(@wid) - tx_constructed, _, tx_submitted = construct_sign_submit(@wid, - nil, # payments - nil, # withdrawal - metadata, - nil, # delegations - mint) - tx_decoded = SHELLEY.transactions.decode(@wid, tx_constructed['transaction']) - expect(tx_constructed).to be_correct_and_respond 202 - expected_fee = tx_constructed['fee']['quantity'] - decoded_fee = tx_decoded['fee']['quantity'] - expect(expected_fee).to eq decoded_fee - - tx_id = tx_submitted['id'] - wait_for_tx_in_ledger(@wid, tx_id) - src_after_minting = get_shelley_balances(@wid) - - # verify tx has metadata - tx = SHELLEY.transactions.get(@wid, tx_id) - expect(tx['metadata']).to eq metadata - - # verify ADA balance is correct (fee is deducted) - expect(src_after_minting['available']).to eq(src_before['available'] - expected_fee) - expect(src_after_minting['total']).to eq(src_before['total'] - expected_fee) - - # verify assets have been minted and on wallet's balance - assets_to_check = get_assets_from_decode(tx_decoded['mint']) - assets = assets_balance(src_after_minting['assets_total'], { assets_to_check: assets_to_check }) - expect(assets).to eq(assets_to_check.to_set { |z| { z => assets_quantity } }) - - # Burn all: - burn = [burn(asset_name('TokenMetadata1'), assets_quantity, policy_script1), - burn(asset_name('TokenMetadata2'), assets_quantity, policy_script2), - burn(asset_name('TokenMetadata3'), assets_quantity, policy_script3)] - tx_constructed, _, tx_submitted = construct_sign_submit(@wid, - nil, # payments - nil, # withdrawal - metadata, - nil, # delegations - burn) - tx_decoded = SHELLEY.transactions.decode(@wid, tx_constructed['transaction']) - expect(tx_constructed).to be_correct_and_respond 202 - expected_fee = tx_constructed['fee']['quantity'] - decoded_fee = tx_decoded['fee']['quantity'] - expect(expected_fee).to eq decoded_fee - - tx_id = tx_submitted['id'] - wait_for_tx_in_ledger(@wid, tx_id) - src_after_burning = get_shelley_balances(@wid) - - # verify tx has metadata - tx = SHELLEY.transactions.get(@wid, tx_id) - expect(tx['metadata']).to eq metadata - - # verify ADA balance is correct (fee is deducted) - expect(src_after_burning['available']).to eq(src_after_minting['available'] - expected_fee) - expect(src_after_burning['total']).to eq(src_after_minting['total'] - expected_fee) - - # verify all assets have been burned and no longer on wallet's balance - assets = assets_balance(src_after_burning['assets_total'], - { assets_to_check: assets_to_check }) - expect(assets).to eq({}.to_set) - end - - ## - # Mint NFT with CIP-25 metadata - it 'Can mint NFT attaching CIP-25 metadata' do - src_before = get_shelley_balances(@wid) - address = SHELLEY.addresses.list(@wid).first['id'] - policy_script = 'cosigner#0' - assets_quantity = 1 - nft_name = 'MyAmazingNFT' - nft_name_hex = asset_name(nft_name) - mint = [mint(nft_name_hex, assets_quantity, policy_script, address)] - - create_policy_key_if_not_exists(@wid) - - # Get policy_id: - policy_id = SHELLEY.keys.create_policy_id(@wid, policy_script)['policy_id'] - - # Build CIP-25 metadata - cip25_metadata = { '721' => { - policy_id.to_s => { - nft_name.to_s => { - 'name' => "NFT FTW: #{nft_name}", - 'image' => 'ipfs://XXXXYYYYZZZZ' - } - } - } } - - # Minting: - tx_constructed, _, tx_submitted = construct_sign_submit(@wid, - nil, # payments - nil, # withdrawal - cip25_metadata, - nil, # delegations - mint) - tx_decoded = SHELLEY.transactions.decode(@wid, tx_constructed['transaction']) - expect(tx_constructed).to be_correct_and_respond 202 - expected_fee = tx_constructed['fee']['quantity'] - - tx_id = tx_submitted['id'] - wait_for_tx_in_ledger(@wid, tx_id) - src_after_minting = get_shelley_balances(@wid) - - # verify tx has metadata - tx = SHELLEY.transactions.get(@wid, tx_id, 'simple-metadata' => true) - expect(tx['metadata']).to eq cip25_metadata - - # verify ADA balance is correct (fee is deducted) - expect(src_after_minting['available']).to eq(src_before['available'] - expected_fee) - expect(src_after_minting['total']).to eq(src_before['total'] - expected_fee) - - # verify assets have been minted and on wallet's balance - assets_to_check = get_assets_from_decode(tx_decoded['mint']) - assets = assets_balance(src_after_minting['assets_total'], { assets_to_check: assets_to_check }) - expect(assets).to eq(assets_to_check.to_set { |z| { z => assets_quantity } }) - - # Burn: - burn = [burn(nft_name_hex, assets_quantity, policy_script)] - - tx_constructed, _, tx_submitted = construct_sign_submit(@wid, - nil, # payments - nil, # withdrawal - nil, # metadata - nil, # delegations - burn) - expect(tx_constructed).to be_correct_and_respond 202 - expected_fee = tx_constructed['fee']['quantity'] - - tx_id = tx_submitted['id'] - wait_for_tx_in_ledger(@wid, tx_id) - src_after_burning = get_shelley_balances(@wid) - - # verify ADA balance is correct (fee is deducted) - expect(src_after_burning['available']).to eq(src_after_minting['available'] - expected_fee) - expect(src_after_burning['total']).to eq(src_after_minting['total'] - expected_fee) - - # verify all assets have been burned and no longer on wallet's balance - assets = assets_balance(src_after_burning['assets_total'], - { assets_to_check: assets_to_check }) - expect(assets).to eq({}.to_set) - end - - ## - # Tx1: Mints 2 x 500 assets, each guarded by different policy script => A1 = 500, A2 = 500 - # Tx2: Mints 500 more of A1 and burns 500 of A2 => A1 = 1000, A2 = 0 - # Tx3: Burns remaining 1000 of A1 => A1 = 0, A2 = 0 - it 'Can mint and burn in the same tx' do - src_before = get_shelley_balances(@wid) - address = SHELLEY.addresses.list(@wid).first['id'] - policy_script1 = { 'some' => { 'at_least' => 1, 'from' => ['cosigner#0'] } } - policy_script2 = { 'any' => ['cosigner#0'] } - - # Minting: - mint = [mint(asset_name('Asset1'), 500, policy_script1, address), - mint(asset_name('Asset2'), 500, policy_script2)] - - create_policy_key_if_not_exists(@wid) - tx_constructed, _, tx_submitted = construct_sign_submit(@wid, - nil, # payments - nil, # withdrawal - nil, # metadata - nil, # delegations - mint) - tx_decoded = SHELLEY.transactions.decode(@wid, tx_constructed['transaction']) - expect(tx_constructed).to be_correct_and_respond 202 - expected_fee = tx_constructed['fee']['quantity'] - decoded_fee = tx_decoded['fee']['quantity'] - expect(expected_fee).to eq decoded_fee - - tx_id = tx_submitted['id'] - wait_for_tx_in_ledger(@wid, tx_id) - src_after_minting = get_shelley_balances(@wid) - - # verify ADA balance is correct (fee is deducted) - expect(src_after_minting['available']).to eq(src_before['available'] - expected_fee) - expect(src_after_minting['total']).to eq(src_before['total'] - expected_fee) - - # verify assets have been minted and on wallet's balance - assets_to_check = get_assets_from_decode(tx_decoded['mint']) - assets = assets_balance(src_after_minting['assets_total'], { assets_to_check: assets_to_check }) - expect(assets).to eq(assets_to_check.to_set { |z| { z => 500 } }) - - # Minting and burning: - mint_burn = [mint(asset_name('Asset1'), 500, policy_script1), - burn(asset_name('Asset2'), 500, policy_script2)] - - # p JSON.parse(mint_burn.to_json) - tx_constructed, _, tx_submitted = construct_sign_submit(@wid, - nil, # payments - nil, # withdrawal - nil, # metadata - nil, # delegations - mint_burn) - tx_decoded = SHELLEY.transactions.decode(@wid, tx_constructed['transaction']) - expect(tx_constructed).to be_correct_and_respond 202 - expected_fee = tx_constructed['fee']['quantity'] - decoded_fee = tx_decoded['fee']['quantity'] - expect(expected_fee).to eq decoded_fee - - tx_id = tx_submitted['id'] - wait_for_tx_in_ledger(@wid, tx_id) - src_after_minting_burning = get_shelley_balances(@wid) - - # verify ADA balance is correct (fee is deducted) - expect(src_after_minting_burning['available']).to eq(src_after_minting['available'] - expected_fee) - expect(src_after_minting_burning['total']).to eq(src_after_minting['total'] - expected_fee) - - # verify Asset1 has been minted and Asset2 burned - assets_minted_to_check = get_assets_from_decode(tx_decoded['mint']) - assets_burned_to_check = get_assets_from_decode(tx_decoded['burn']) - assets_minted = assets_balance(src_after_minting_burning['assets_total'], - { assets_to_check: assets_minted_to_check }) - assets_burned = assets_balance(src_after_minting_burning['assets_total'], - { assets_to_check: assets_burned_to_check }) - - expect(assets_minted).to eq(assets_minted_to_check.to_set { |z| { z => 1000 } }) - expect(assets_burned).to eq({}.to_set) - - # Burn all the rest: - burn = [burn(asset_name('Asset1'), 1000, policy_script1)] - tx_constructed, _, tx_submitted = construct_sign_submit(@wid, - nil, # payments - nil, # withdrawal - nil, # metadata - nil, # delegations - burn) - - tx_decoded = SHELLEY.transactions.decode(@wid, tx_constructed['transaction']) - expect(tx_constructed).to be_correct_and_respond 202 - expected_fee = tx_constructed['fee']['quantity'] - decoded_fee = tx_decoded['fee']['quantity'] - expect(expected_fee).to eq decoded_fee - - tx_id = tx_submitted['id'] - wait_for_tx_in_ledger(@wid, tx_id) - src_after_burning = get_shelley_balances(@wid) - - # verify ADA balance is correct (fee is deducted) - expect(src_after_burning['available']).to eq(src_after_minting_burning['available'] - expected_fee) - expect(src_after_burning['total']).to eq(src_after_minting_burning['total'] - expected_fee) - - # verify Asset1 has been burned - assets_burned_to_check = get_assets_from_decode(tx_decoded['burn']) - assets_burned = assets_balance(src_after_burning['assets_total'], - { assets_to_check: assets_burned_to_check }) - expect(assets_burned).to eq({}.to_set) - end - - ## - # Tx1: Mints 10 asset => has 10 - # Tx2: Burns 10 and mints 1 of the same asset => has 1 - # Tx3: Burns 1 remaining assets => has 0 - it 'Can mint and burn the same asset in single tx' do - src_before = get_shelley_balances(@wid) - address = SHELLEY.addresses.list(@wid).first['id'] - policy_script = 'cosigner#0' - assets_name = asset_name('MintBurnX') - - # Minting 10 MintBurn: - mint = [mint(assets_name, 10, policy_script, address)] - - create_policy_key_if_not_exists(@wid) - tx_constructed, _, tx_submitted = construct_sign_submit(@wid, - nil, # payments - nil, # withdrawal - nil, # metadata - nil, # delegations - mint) - tx_decoded = SHELLEY.transactions.decode(@wid, tx_constructed['transaction']) - expect(tx_constructed).to be_correct_and_respond 202 - expected_fee = tx_constructed['fee']['quantity'] - decoded_fee = tx_decoded['fee']['quantity'] - expect(expected_fee).to eq decoded_fee - - tx_id = tx_submitted['id'] - wait_for_tx_in_ledger(@wid, tx_id) - src_after_minting = get_shelley_balances(@wid) - - # verify ADA balance is correct (fee is deducted) - expect(src_after_minting['available']).to eq(src_before['available'] - expected_fee) - expect(src_after_minting['total']).to eq(src_before['total'] - expected_fee) - - # verify assets have been minted and on wallet's balance - assets_to_check = get_assets_from_decode(tx_decoded['mint']) - assets = assets_balance(src_after_minting['assets_total'], { assets_to_check: assets_to_check }) - expect(assets).to eq(assets_to_check.to_set { |z| { z => 10 } }) - - # Burning 10 MintBurn and minting 1 MintBurn: - mint_burn = [burn(assets_name, 10, policy_script), - mint(assets_name, 1, policy_script, address)] - - tx_constructed, _, tx_submitted = construct_sign_submit(@wid, - nil, # payments - nil, # withdrawal - nil, # metadata - nil, # delegations - mint_burn) - tx_decoded = SHELLEY.transactions.decode(@wid, tx_constructed['transaction']) - expect(tx_constructed).to be_correct_and_respond 202 - expected_fee = tx_constructed['fee']['quantity'] - decoded_fee = tx_decoded['fee']['quantity'] - expect(expected_fee).to eq decoded_fee - - tx_id = tx_submitted['id'] - wait_for_tx_in_ledger(@wid, tx_id) - src_after_minting_burning = get_shelley_balances(@wid) - - # verify ADA balance is correct (fee is deducted) - expect(src_after_minting_burning['available']).to eq(src_after_minting['available'] - expected_fee) - expect(src_after_minting_burning['total']).to eq(src_after_minting['total'] - expected_fee) - - # verify MintBurn has 1 (because 10 was burned and 1 additional minted) - assets_minted_to_check = get_assets_from_decode(tx_decoded['mint']) - assets_minted = assets_balance(src_after_minting_burning['assets_total'], - { assets_to_check: assets_minted_to_check }) - - expect(assets_minted).to eq(assets_minted_to_check.to_set { |z| { z => 1 } }) - - # Burn all the rest: - burn = [burn(assets_name, 1, policy_script)] - tx_constructed, _, tx_submitted = construct_sign_submit(@wid, - nil, # payments - nil, # withdrawal - nil, # metadata - nil, # delegations - burn) - - tx_decoded = SHELLEY.transactions.decode(@wid, tx_constructed['transaction']) - expect(tx_constructed).to be_correct_and_respond 202 - expected_fee = tx_constructed['fee']['quantity'] - decoded_fee = tx_decoded['fee']['quantity'] - expect(expected_fee).to eq decoded_fee - - tx_id = tx_submitted['id'] - wait_for_tx_in_ledger(@wid, tx_id) - src_after_burning = get_shelley_balances(@wid) - - # verify ADA balance is correct (fee is deducted) - expect(src_after_burning['available']).to eq(src_after_minting_burning['available'] - expected_fee) - expect(src_after_burning['total']).to eq(src_after_minting_burning['total'] - expected_fee) - - # verify all is burned - assets_burned_to_check = get_assets_from_decode(tx_decoded['burn']) - assets_burned = assets_balance(src_after_burning['assets_total'], - { assets_to_check: assets_burned_to_check }) - expect(assets_burned).to eq({}.to_set) - end - - ## - # Tx1: Fail to burn asset that's not on the wallet - it "Cannot burn if I don't have it" do - policy_script = 'cosigner#0' - burn = [burn(asset_name('AmazingNFTIdontHave'), 1, policy_script)] - create_policy_key_if_not_exists(@wid) - tx_constructed = SHELLEY.transactions.construct(@wid, - nil, # payments - nil, # withdrawal - nil, # metadata - nil, # delegations - burn) - expect(tx_constructed).to be_correct_and_respond 403 - expect(tx_constructed['code'].to_s).to eq 'not_enough_money' - shortfall = tx_constructed['info']['shortfall']['assets'][0] - expect(shortfall['asset_name']).to eq asset_name('AmazingNFTIdontHave') - expect(shortfall['quantity']).to eq 1 - end - - ## - # Tx1: Mints 1000 assets - # Tx2: Fails to burn 1000 assets using different policy_script - # Tx2: Fails to burn 1022 assets using correct policy_script - # Tx3: Burns remaining 1000 assets - it 'Cannot burn with wrong policy_script or more than I have' do - address = SHELLEY.addresses.list(@wid).first['id'] - policy_script = 'cosigner#0' - - # Mint it: - mint = [mint(asset_name('MintIt'), 1000, policy_script, address)] - create_policy_key_if_not_exists(@wid) - _, _, tx_submitted = construct_sign_submit(@wid, - nil, # payments - nil, # withdrawal - nil, # metadata - nil, # delegations - mint) - - tx_id = tx_submitted['id'] - wait_for_tx_in_ledger(@wid, tx_id) - - # Try to burn: - # - with different policy_script - burn1 = [burn(asset_name('MintIt'), 1000, { 'all' => ['cosigner#0'] })] - tx_constructed = SHELLEY.transactions.construct(@wid, - nil, # payments - nil, # withdrawal - nil, # metadata - nil, # delegations - burn1) - - expect(tx_constructed).to be_correct_and_respond 403 - expect(tx_constructed['code'].to_s).to eq 'not_enough_money' - shortfall = tx_constructed['info']['shortfall']['assets'][0] - expect(shortfall['asset_name']).to eq asset_name('MintIt') - expect(shortfall['quantity']).to eq 1000 - - # - correct policy_script but too much - burn2 = [burn(asset_name('MintIt'), 1022, policy_script)] - tx_constructed = SHELLEY.transactions.construct(@wid, - nil, # payments - nil, # withdrawal - nil, # metadata - nil, # delegations - burn2) - - expect(tx_constructed).to be_correct_and_respond 403 - expect(tx_constructed['code'].to_s).to eq 'not_enough_money' - shortfall = tx_constructed['info']['shortfall']['assets'][0] - expect(shortfall['asset_name']).to eq asset_name('MintIt') - expect(shortfall['quantity']).to eq 22 - - # Burn it: - burn3 = [burn(asset_name('MintIt'), 1000, policy_script)] - tx_constructed, _, tx_submitted = construct_sign_submit(@wid, - nil, # payments - nil, # withdrawal - nil, # metadata - nil, # delegations - burn3) - tx_decoded = SHELLEY.transactions.decode(@wid, tx_constructed['transaction']) - - tx_id = tx_submitted['id'] - wait_for_tx_in_ledger(@wid, tx_id) - src_after_burning = get_shelley_balances(@wid) - - # verify MintIt has been burned - assets_burned_to_check = get_assets_from_decode(tx_decoded['burn']) - assets_burned = assets_balance(src_after_burning['assets_total'], - { assets_to_check: assets_burned_to_check }) - expect(assets_burned).to eq({}.to_set) - end - - ## - # Tx1: Mints 1500 assets to different wallet - # Tx2: Fails to burn 1500 assets on different wallet - # Tx3: Sends assets back to src wallet - # Tx4: Burns them - it "Mint to foreign wallet / Cannot burn if I don't have keys" do - address = SHELLEY.addresses.list(@target_id).first['id'] - policy_script = 'cosigner#0' - assets_quantity = 1500 - assets_name = asset_name('ToForeignWallet') - - # Mint it: - mint = [mint(assets_name, assets_quantity, policy_script, address)] - create_policy_key_if_not_exists(@wid) - tx_constructed, _, tx_submitted = construct_sign_submit(@wid, - nil, # payments - nil, # withdrawal - nil, # metadata - nil, # delegations - mint) - - tx_decoded = SHELLEY.transactions.decode(@wid, tx_constructed['transaction']) - expect(tx_constructed).to be_correct_and_respond 202 - expected_fee = tx_constructed['fee']['quantity'] - decoded_fee = tx_decoded['fee']['quantity'] - expect(expected_fee).to eq decoded_fee - - tx_id = tx_submitted['id'] - wait_for_tx_in_ledger(@wid, tx_id) - target_after_minting = get_shelley_balances(@target_id) - - # verify assets have been minted and on target wallet's balance - assets_to_check = get_assets_from_decode(tx_decoded['mint']) - assets = assets_balance(target_after_minting['assets_total'], { assets_to_check: assets_to_check }) - expect(assets).to eq(assets_to_check.to_set { |z| { z => assets_quantity } }) - - # Try to burn on target wallet and fail: - create_policy_key_if_not_exists(@target_id) - burn = [burn(assets_name, assets_quantity, policy_script)] - tx_constructed = SHELLEY.transactions.construct(@target_id, - nil, # payments - nil, # withdrawal - nil, # metadata - nil, # delegations - burn) - expect(tx_constructed).to be_correct_and_respond 403 - expect(tx_constructed['code'].to_s).to eq 'not_enough_money' - shortfall = tx_constructed['info']['shortfall']['assets'][0] - expect(shortfall['asset_name']).to eq assets_name - expect(shortfall['quantity']).to eq assets_quantity - - # Send them back to src wallet: - src_address = SHELLEY.addresses.list(@wid).first['id'] - policy_id = get_policy_id_from_decode(tx_decoded['mint']) - # Make sure decoded policy id correct - expect(policy_id).to eq SHELLEY.keys.create_policy_id(@wid, policy_script)['policy_id'] - payment = [{ 'address' => src_address, - 'amount' => { 'quantity' => 0, 'unit' => 'lovelace' }, - 'assets' => [{ 'policy_id' => policy_id, - 'asset_name' => assets_name, - 'quantity' => assets_quantity }] }] - - _, _, tx_submitted = construct_sign_submit(@target_id, payment) - tx_id = tx_submitted['id'] - wait_for_tx_in_ledger(@target_id, tx_id) - src_after_sending = get_shelley_balances(@wid) - assets = assets_balance(src_after_sending['assets_total'], { assets_to_check: assets_to_check }) - expect(assets).to eq(assets_to_check.to_set { |z| { z => assets_quantity } }) - - # Burn them on src wallet: - burn = [burn(assets_name, assets_quantity, policy_script)] - tx_constructed, _, tx_submitted = construct_sign_submit(@wid, - nil, # payments - nil, # withdrawal - nil, # metadata - nil, # delegations - burn) - - tx_decoded = SHELLEY.transactions.decode(@wid, tx_constructed['transaction']) - expect(tx_constructed).to be_correct_and_respond 202 - expected_fee = tx_constructed['fee']['quantity'] - decoded_fee = tx_decoded['fee']['quantity'] - expect(expected_fee).to eq decoded_fee - - tx_id = tx_submitted['id'] - wait_for_tx_in_ledger(@wid, tx_id) - - # make sure it was burned - src_after_burning = get_shelley_balances(@wid) - assets_to_check = get_assets_from_decode(tx_decoded['burn']) - assets = assets_balance(src_after_burning['assets_total'], { assets_to_check: assets_to_check }) - expect(assets).to eq({}.to_set) - end - - ## - # Make sure minting above boundary quantity values returns proper error - describe 'Mint/Burn quantities' do - matrix = [ - [-9_223_372_036_854_775_808, 400, 'bad_request'], - [-1, 400, 'bad_request'], - [0, 403, 'mint_or_burn_asset_quantity_out_of_bounds'], - [9_223_372_036_854_775_808, 403, 'mint_or_burn_asset_quantity_out_of_bounds'] - ] - matrix.each do |m| - quantity = m[0] - code = m[1] - message = m[2] - it "Cannot mint #{quantity} assets" do - policy_script = 'cosigner#0' - assets_name = asset_name('AmazingNFTIdontHave') - assets_quantity = quantity - address = SHELLEY.addresses.list(@wid).first['id'] - mint = [mint(assets_name, assets_quantity, policy_script, address)] - create_policy_key_if_not_exists(@wid) - tx_constructed = SHELLEY.transactions.construct(@wid, - nil, # payments - nil, # withdrawal - nil, # metadata - nil, # delegations - mint) - expect(tx_constructed).to be_correct_and_respond code - expect(tx_constructed['code'].to_s).to eq message - end - - it "Cannot burn #{quantity} assets" do - policy_script = 'cosigner#0' - assets_name = asset_name('AmazingNFTIdontHave') - assets_quantity = quantity - burn = [burn(assets_name, assets_quantity, policy_script)] - create_policy_key_if_not_exists(@wid) - tx_constructed = SHELLEY.transactions.construct(@wid, - nil, # payments - nil, # withdrawal - nil, # metadata - nil, # delegations - burn) - expect(tx_constructed).to be_correct_and_respond code - expect(tx_constructed['code'].to_s).to eq message - end - end - end - - ## - # Make sure minting above boundary asset_name values returns proper error - describe 'Mint/Burn asset_name' do - matrix = [ - ['too long', '1' * 66, 403, 'asset_name_too_long'], - ['invalid hex', '1', 400, 'bad_request'] - ] - matrix.each do |m| - test = m[0] - assets_name = m[1] - code = m[2] - message = m[3] - it "Cannot mint if my asset name is #{test}" do - address = SHELLEY.addresses.list(@wid).first['id'] - policy_script = 'cosigner#0' - assets_quantity = 1500 - mint = [mint(assets_name, assets_quantity, policy_script, address)] - tx_constructed = SHELLEY.transactions.construct(@wid, - nil, # payments - nil, # withdrawal - nil, # metadata - nil, # delegations - mint) - - expect(tx_constructed).to be_correct_and_respond code - expect(tx_constructed['code']).to eq message - end - end - end - - ## - # Test against some invalid policy script examples - describe 'Mint/Burn invalid policy script' do - matrix = [ - ['cosigner#1', 403, 'created_wrong_policy_script_template'], - [{ 'all' => ['cosigner#0', 'cosigner#1'] }, 403, 'created_wrong_policy_script_template'], - [{ 'any' => ['cosigner#0', 'cosigner#0'] }, 403, 'created_wrong_policy_script_template'], - [{ 'some' => { 'at_least' => 2, 'from' => ['cosigner#0'] } }, 403, 'created_wrong_policy_script_template'], - [{ 'some' => ['cosigner#0'] }, 400, 'bad_request'] - ] - - matrix.each do |m| - policy_script = m[0] - code = m[1] - message = m[2] - it "Cannot mint if my policy script is invalid: #{policy_script}" do - address = SHELLEY.addresses.list(@wid).first['id'] - assets_name = asset_name('WillNotMintIt') - assets_quantity = 1500 - mint = [mint(assets_name, assets_quantity, policy_script, address)] - tx_constructed = SHELLEY.transactions.construct(@wid, - nil, # payments - nil, # withdrawal - nil, # metadata - nil, # delegations - mint) - - expect(tx_constructed).to be_correct_and_respond code - expect(tx_constructed['code']).to eq message - end - end - end - - it 'Cannot mint if I make too big transaction' do - address = SHELLEY.addresses.list(@wid).first['id'] - policy_script = 'cosigner#0' - assets_quantity = 1500 - - mint = [] - 1000.times do |i| - mint << mint(asset_name("TooBIG#{i}"), assets_quantity, policy_script, address) - end - tx_constructed = SHELLEY.transactions.construct(@wid, - nil, # payments - nil, # withdrawal - nil, # metadata - nil, # delegations - mint) - - expect(tx_constructed).to be_correct_and_respond 403 - expect(tx_constructed['code']).to eq 'output_token_bundle_size_exceeds_limit' - end - end - - describe 'Output encoding' do - # Check construct and sign output has desired encoding as per - # encoding parameter - matrix = %w[base16 base64] - matrix.each do |o_enc| - it o_enc do - tx_constructed = SHELLEY.transactions.construct(@wid, - nil, # payments - nil, # withdrawal - METADATA, - nil, # delegations - nil, # mint - nil, # validity_interval - o_enc) # encoding - expect(tx_constructed).to be_correct_and_respond 202 - expect(method("#{o_enc}?").call(tx_constructed['transaction'])).to be true - - tx_signed = SHELLEY.transactions.sign(@wid, PASS, - tx_constructed['transaction'], - o_enc) - expect(tx_signed).to be_correct_and_respond 202 - expect(method("#{o_enc}?").call(tx_signed['transaction'])).to be true - end - end - end - end - - describe 'E2E Shelley' do - describe 'UTxOs' do - it 'Fixture shelley wallet has utxos' do - utxo_stats = SHELLEY.wallets.utxo(@wid) - expect(utxo_stats).to be_correct_and_respond 200 - - utxo_snap = SHELLEY.wallets.utxo_snapshot(@wid) - expect(utxo_snap).to be_correct_and_respond 200 - expect(utxo_snap['entries'].size).to be > 0 - end - end - - describe 'Native Assets' do - it 'I can list native assets' do - assets = SHELLEY.assets.get @wid - expect(assets).to be_correct_and_respond 200 - expect(assets.to_s).to include ASSETS[0]['policy_id'] - expect(assets.to_s).to include ASSETS[0]['asset_name'] - expect(assets.to_s).to include ASSETS[1]['policy_id'] - expect(assets.to_s).to include ASSETS[1]['asset_name'] - - assets = SHELLEY.assets.get(@wid, ASSETS[0]['policy_id']) - expect(assets).to be_correct_and_respond 200 - expect(assets['policy_id']).to eq ASSETS[0]['policy_id'] - expect(assets['asset_name']).to eq ASSETS[0]['asset_name'] - expect(assets['asset_name']).not_to eq ASSETS[1]['asset_name'] - - assets = SHELLEY.assets.get(@wid, ASSETS[1]['policy_id'], - ASSETS[1]['asset_name']) - expect(assets).to be_correct_and_respond 200 - expect(assets['policy_id']).to eq ASSETS[1]['policy_id'] - expect(assets['asset_name']).to eq ASSETS[1]['asset_name'] - expect(assets['asset_name']).not_to eq ASSETS[0]['asset_name'] - end - - it 'I can list native assets and get offchain metadata', :offchain do - assets = SHELLEY.assets.get @wid - expect(assets).to be_correct_and_respond 200 - expect(assets.to_s).to include ASSETS[0]['policy_id'] - expect(assets.to_s).to include ASSETS[0]['asset_name'] - expect(assets.to_s).to include ASSETS[0]['metadata']['name'] - expect(assets.to_s).to include ASSETS[1]['policy_id'] - expect(assets.to_s).to include ASSETS[1]['asset_name'] - expect(assets.to_s).to include ASSETS[1]['metadata']['name'] - - assets = SHELLEY.assets.get(@wid, ASSETS[0]['policy_id']) - expect(assets).to be_correct_and_respond 200 - expect(assets['policy_id']).to eq ASSETS[0]['policy_id'] - expect(assets['asset_name']).to eq ASSETS[0]['asset_name'] - expect(assets['metadata']).to eq ASSETS[0]['metadata'] - expect(assets['asset_name']).not_to eq ASSETS[1]['asset_name'] - expect(assets['metadata']).not_to eq ASSETS[1]['metadata'] - - assets = SHELLEY.assets.get(@wid, ASSETS[1]['policy_id'], - ASSETS[1]['asset_name']) - expect(assets).to be_correct_and_respond 200 - expect(assets['policy_id']).to eq ASSETS[1]['policy_id'] - expect(assets['asset_name']).to eq ASSETS[1]['asset_name'] - expect(assets['metadata']).to eq ASSETS[1]['metadata'] - expect(assets['asset_name']).not_to eq ASSETS[0]['asset_name'] - expect(assets['metadata']).not_to eq ASSETS[0]['metadata']['name'] - end - - it 'I can send native assets tx and they are received' do - amt = 1 - address = SHELLEY.addresses.list(@target_id)[1]['id'] - target_before = get_shelley_balances(@target_id) - - payload = [{ 'address' => address, - 'amount' => { 'quantity' => 0, 'unit' => 'lovelace' }, - 'assets' => [{ 'policy_id' => ASSETS[0]['policy_id'], - 'asset_name' => ASSETS[0]['asset_name'], - 'quantity' => amt }, - { 'policy_id' => ASSETS[1]['policy_id'], - 'asset_name' => ASSETS[1]['asset_name'], - 'quantity' => amt }] }] - - tx_sent = SHELLEY.transactions.create(@wid, PASS, payload) - - expect(tx_sent).to be_correct_and_respond 202 - wait_for_tx_in_ledger(@wid, tx_sent['id']) - verify_tx_status(@wid, tx_sent['id'], 'in_ledger') - - target_after = get_shelley_balances(@target_id) - - # verify balances are correct on target wallet - assets_to_check = ["#{ASSETS[0]['policy_id']}#{ASSETS[0]['asset_name']}", - "#{ASSETS[1]['policy_id']}#{ASSETS[1]['asset_name']}"] - target_total_after = assets_balance(target_after['assets_total'], { assets_to_check: assets_to_check }) - target_avail_after = assets_balance(target_after['assets_available'], { assets_to_check: assets_to_check }) - target_total_expected = assets_balance(target_before['assets_total'], { assets_to_check: assets_to_check, delta: +amt }) - target_avail_expected = assets_balance(target_before['assets_available'], { assets_to_check: assets_to_check, delta: +amt }) - if target_before['assets_total'] == [] - target_balance_expected = assets_to_check.to_set { |a| { a => amt } } - expect(target_total_after).to eq target_balance_expected - expect(target_avail_after).to eq target_balance_expected - else - expect(target_total_after).to eq target_total_expected - expect(target_avail_after).to eq target_avail_expected - end - end - end - - describe 'Shelley Migrations' do - it 'I can create migration plan shelley -> shelley' do - addrs = SHELLEY.addresses.list(@target_id).map { |a| a['id'] } - - plan = SHELLEY.migrations.plan(@wid, addrs) - expect(plan).to be_correct_and_respond 202 - expect(plan['balance_selected']['assets']).not_to be [] - expect(plan['balance_leftover']).to eq({ 'ada' => { 'quantity' => 0, - 'unit' => 'lovelace' }, - 'assets' => [] }) - end - end - - describe 'Shelley Transactions' do - it 'I can send transaction and funds are received (min_utxo_value)' do - address = SHELLEY.addresses.list(@target_id)[0]['id'] - available_before = SHELLEY.wallets.get(@target_id)['balance']['available']['quantity'] - total_before = SHELLEY.wallets.get(@target_id)['balance']['total']['quantity'] - - # get required minimum ada - tx = SHELLEY.transactions.create(@wid, PASS, payment_payload(1, address)) - expect(tx.code).to eq 403 - expect(tx['code']).to eq 'utxo_too_small' - amt = tx['info']['tx_output_lovelace_required_minimum']['quantity'] - - tx_sent = SHELLEY.transactions.create(@wid, PASS, payment_payload(amt, address)) - - expect(tx_sent).to be_correct_and_respond 202 - tx_id = tx_sent['id'] - wait_for_tx_in_ledger(@wid, tx_id) - verify_tx_status(@wid, tx_id, 'in_ledger') - - eventually "Funds are on target wallet: #{@target_id}" do - available = SHELLEY.wallets.get(@target_id)['balance']['available']['quantity'] - total = SHELLEY.wallets.get(@target_id)['balance']['total']['quantity'] - (available == amt + available_before) && (total == amt + total_before) - end - - # examine the tx in history - # on src wallet - tx = SHELLEY.transactions.get(@wid, tx_id) - expect(tx['amount']['quantity']).to be > amt - tx_inputs(tx, present: true) - tx_outputs(tx, present: true) - tx_direction(tx, 'outgoing') - tx_script_validity(tx, 'valid') - tx_status(tx, 'in_ledger') - tx_collateral(tx, present: false) - tx_collateral_outputs(tx, present: false) - tx_metadata(tx, nil) - tx_deposits(tx, deposit_taken: 0, deposit_returned: 0) - tx_withdrawals(tx, present: false) - tx_mint_burn(tx, mint: [], burn: []) - tx_extra_signatures(tx, present: false) - tx_script_integrity(tx, present: false) - tx_validity_interval_default(tx) - tx_certificates(tx, present: false) - - # on target wallet - txt = SHELLEY.transactions.get(@target_id, tx_id) - tx_amount(txt, amt) - # in old tx workflow, only expecting fee to be present because fee calculation is not reliable enough for strong assertions - expect(tx['fee']['quantity'].to_i).to be > 0 - tx_inputs(txt, present: true) - tx_outputs(txt, present: true) - tx_direction(txt, 'incoming') - tx_script_validity(txt, 'valid') - tx_status(txt, 'in_ledger') - tx_collateral(txt, present: false) - tx_collateral_outputs(txt, present: false) - tx_metadata(txt, nil) - # ADP-2298 - Deposit_returned is falsely reported on some incoming transactions (intermittently) - # tx_deposits(txt, deposit_taken: 0, deposit_returned: 0) - tx_withdrawals(txt, present: false) - tx_mint_burn(txt, mint: [], burn: []) - tx_extra_signatures(txt, present: false) - tx_script_integrity(txt, present: false) - tx_validity_interval_default(txt) - tx_certificates(txt, present: false) - end - - it 'I can send transaction with ttl and funds are received' do - amt = MIN_UTXO_VALUE_PURE_ADA - ttl_in_s = 1200 - - address = SHELLEY.addresses.list(@target_id)[0]['id'] - target_before = get_shelley_balances(@target_id) - tx_sent = SHELLEY.transactions.create(@wid, - PASS, - [{ address => amt }], - nil, # withdrawal - nil, # metadata - ttl_in_s) - - expect(tx_sent).to be_correct_and_respond 202 - tx_id = tx_sent['id'] - wait_for_tx_in_ledger(@wid, tx_id) - verify_tx_status(@wid, tx_id, 'in_ledger') - - target_after = get_shelley_balances(@target_id) - - expect(target_after['available']).to eq(amt + target_before['available']) - expect(target_after['total']).to eq(amt + target_before['total']) - expect(target_after['reward']).to eq(target_before['reward']) - - # examine the tx in history - # on src wallet - tx = SHELLEY.transactions.get(@wid, tx_id) - expect(tx['amount']['quantity']).to be > amt - tx_inputs(tx, present: true) - tx_outputs(tx, present: true) - tx_direction(tx, 'outgoing') - tx_script_validity(tx, 'valid') - tx_status(tx, 'in_ledger') - tx_collateral(tx, present: false) - tx_collateral_outputs(tx, present: false) - tx_metadata(tx, nil) - tx_deposits(tx, deposit_taken: 0, deposit_returned: 0) - tx_withdrawals(tx, present: false) - tx_mint_burn(tx, mint: [], burn: []) - tx_extra_signatures(tx, present: false) - tx_script_integrity(tx, present: false) - tx_validity_interval_default(tx) - tx_certificates(tx, present: false) - - # on target wallet - txt = SHELLEY.transactions.get(@target_id, tx_id) - tx_amount(txt, amt) - expect(tx['fee']['quantity'].to_i).to be > 0 - tx_inputs(txt, present: true) - tx_outputs(txt, present: true) - tx_direction(txt, 'incoming') - tx_script_validity(txt, 'valid') - tx_status(txt, 'in_ledger') - tx_collateral(txt, present: false) - tx_collateral_outputs(txt, present: false) - tx_metadata(txt, nil) - # ADP-2298 - Deposit_returned is falsely reported on some incoming transactions (intermittently) - # tx_deposits(txt, deposit_taken: 0, deposit_returned: 0) - tx_withdrawals(txt, present: false) - tx_mint_burn(txt, mint: [], burn: []) - tx_extra_signatures(txt, present: false) - tx_script_integrity(txt, present: false) - tx_validity_interval_default(txt) - tx_certificates(txt, present: false) - end - - it 'Transaction with ttl = 0 would expire and I can forget it' do - skip 'Test is flaky due to ADP-608' - amt = MIN_UTXO_VALUE_PURE_ADA - ttl_in_s = 0 - - address = SHELLEY.addresses.list(@target_id)[0]['id'] - tx_sent = SHELLEY.transactions.create(@wid, - PASS, - [{ address => amt }], - nil, # withdrawal - nil, # metadata - ttl_in_s) - - expect(tx_sent).to be_correct_and_respond 202 - - eventually "TX `#{tx_sent['id']}' expires on `#{@wid}'" do - SHELLEY.transactions.get(@wid, tx_sent['id'])['status'] == 'expired' - end - - res = SHELLEY.transactions.forget(@wid, tx_sent['id']) - expect(res).to be_correct_and_respond 204 - - fres = SHELLEY.transactions.get(@wid, tx_sent['id']) - expect(fres).to be_correct_and_respond 404 - end - - it "I can send transaction using 'withdrawal' flag and funds are received" do - amt = MIN_UTXO_VALUE_PURE_ADA - address = SHELLEY.addresses.list(@target_id)[0]['id'] - target_before = get_shelley_balances(@target_id) - src_before = get_shelley_balances(@wid) - - tx_sent = SHELLEY.transactions.create(@wid, PASS, [{ address => amt }], 'self') - - expect(tx_sent).to be_correct_and_respond 202 - tx_id = tx_sent['id'] - wait_for_tx_in_ledger(@wid, tx_id) - verify_tx_status(@wid, tx_id, 'in_ledger') - - fee = SHELLEY.transactions.get(@wid, tx_id)['fee']['quantity'] - target_after = get_shelley_balances(@target_id) - src_after = get_shelley_balances(@wid) - - verify_ada_balance(src_after, src_before, - target_after, target_before, - amt, fee) - - # examine the tx in history - # on src wallet - tx = SHELLEY.transactions.get(@wid, tx_id) - expect(tx['amount']['quantity']).to be > amt - tx_inputs(tx, present: true) - tx_outputs(tx, present: true) - tx_direction(tx, 'outgoing') - tx_script_validity(tx, 'valid') - tx_status(tx, 'in_ledger') - tx_collateral(tx, present: false) - tx_collateral_outputs(tx, present: false) - tx_metadata(tx, nil) - tx_deposits(tx, deposit_taken: 0, deposit_returned: 0) - tx_withdrawals(tx, present: false) - tx_mint_burn(tx, mint: [], burn: []) - tx_extra_signatures(tx, present: false) - tx_script_integrity(tx, present: false) - tx_validity_interval_default(tx) - tx_certificates(tx, present: false) - - # on target wallet - txt = SHELLEY.transactions.get(@target_id, tx_id) - tx_amount(txt, amt) - expect(tx['fee']['quantity'].to_i).to be > 0 - tx_inputs(txt, present: true) - tx_outputs(txt, present: true) - tx_direction(txt, 'incoming') - tx_script_validity(txt, 'valid') - tx_status(txt, 'in_ledger') - tx_collateral(txt, present: false) - tx_collateral_outputs(txt, present: false) - tx_metadata(txt, nil) - # ADP-2298 - Deposit_returned is falsely reported on some incoming transactions (intermittently) - # tx_deposits(txt, deposit_taken: 0, deposit_returned: 0) - tx_withdrawals(txt, present: false) - tx_mint_burn(txt, mint: [], burn: []) - tx_extra_signatures(txt, present: false) - tx_script_integrity(txt, present: false) - tx_validity_interval_default(txt) - tx_certificates(txt, present: false) - end - - it 'I can send transaction with metadata' do - amt = MIN_UTXO_VALUE_PURE_ADA - metadata = METADATA - - address = SHELLEY.addresses.list(@target_id)[0]['id'] - target_before = get_shelley_balances(@target_id) - - tx_sent = SHELLEY.transactions.create(@wid, - PASS, - [{ address => amt }], - nil, - metadata) - - expect(tx_sent).to be_correct_and_respond 202 - tx_id = tx_sent['id'] - wait_for_tx_in_ledger(@wid, tx_id) - verify_tx_status(@wid, tx_id, 'in_ledger') - - target_after = get_shelley_balances(@target_id) - - expect(target_after['available']).to eq(amt + target_before['available']) - expect(target_after['total']).to eq(amt + target_before['total']) - expect(target_after['reward']).to eq(target_before['reward']) - - # examine the tx in history - # on src wallet - tx = SHELLEY.transactions.get(@wid, tx_id) - expect(tx['amount']['quantity']).to be > amt - tx_inputs(tx, present: true) - tx_outputs(tx, present: true) - tx_direction(tx, 'outgoing') - tx_script_validity(tx, 'valid') - tx_status(tx, 'in_ledger') - tx_collateral(tx, present: false) - tx_collateral_outputs(tx, present: false) - tx_metadata(tx, metadata) - tx_deposits(tx, deposit_taken: 0, deposit_returned: 0) - tx_withdrawals(tx, present: false) - tx_mint_burn(tx, mint: [], burn: []) - tx_extra_signatures(tx, present: false) - tx_script_integrity(tx, present: false) - tx_validity_interval_default(tx) - tx_certificates(tx, present: false) - - # on target wallet - txt = SHELLEY.transactions.get(@target_id, tx_id) - tx_amount(txt, amt) - expect(tx['fee']['quantity'].to_i).to be > 0 - tx_inputs(txt, present: true) - tx_outputs(txt, present: true) - tx_direction(txt, 'incoming') - tx_script_validity(txt, 'valid') - tx_status(txt, 'in_ledger') - tx_collateral(txt, present: false) - tx_collateral_outputs(txt, present: false) - tx_metadata(txt, metadata) - # ADP-2298 - Deposit_returned is falsely reported on some incoming transactions (intermittently) - # tx_deposits(txt, deposit_taken: 0, deposit_returned: 0) - tx_withdrawals(txt, present: false) - tx_mint_burn(txt, mint: [], burn: []) - tx_extra_signatures(txt, present: false) - tx_script_integrity(txt, present: false) - tx_validity_interval_default(txt) - tx_certificates(txt, present: false) - end - - it 'I can estimate fee (min_utxo_value)' do - metadata = METADATA - txs = SHELLEY.transactions - # get required minimum ada - fees = txs.payment_fees(@wid, payment_payload(1)) - expect(fees.code).to eq 403 - expect(fees['code']).to eq 'utxo_too_small' - amt = fees['info']['tx_output_lovelace_required_minimum']['quantity'] - - fees = txs.payment_fees(@wid, payment_payload(amt)) - expect(fees).to be_correct_and_respond 202 - - fees = txs.payment_fees(@wid, payment_payload(amt), 'self') - expect(fees).to be_correct_and_respond 202 - - fees = txs.payment_fees(@wid, payment_payload(amt), 'self', metadata) - expect(fees).to be_correct_and_respond 202 - end - - it 'I can list transactions and limit response with query parameters' do - wid = @wid - - # get 3 txs - txs = SHELLEY.transactions.list(wid, { max_count: 3, order: 'ascending' }) - expect(txs).to be_correct_and_respond 200 - expect(txs.size).to be 3 - - last_tx_time = txs.first['inserted_at']['time'] - first_tx_time = txs.last['inserted_at']['time'] - - # get 2 txs - txs = SHELLEY.transactions.list(wid, { max_count: 2, order: 'ascending' }) - expect(txs).to be_correct_and_respond 200 - expect(txs.size).to eq 2 - expect(txs.first['inserted_at']['time']).to eq last_tx_time - - # get 2 txs in ascending order - txs = SHELLEY.transactions.list(wid, { max_count: 2, start: first_tx_time, order: 'ascending' }) - expect(txs).to be_correct_and_respond 200 - expect(txs.size).to eq 2 - expect(txs.first['inserted_at']['time']).to eq first_tx_time - - # get 2 txs in ascending order with start and end time - txs = SHELLEY.transactions.list(wid, { max_count: 2, start: last_tx_time, end: first_tx_time, order: 'ascending' }) - expect(txs).to be_correct_and_respond 200 - expect(txs.size).to eq 2 - expect(txs.first['inserted_at']['time']).to eq last_tx_time - end - end - - describe 'Stake Pools' do - it "I could join Stake Pool - if I knew it's id" do - pools = SHELLEY.stake_pools - - join = pools.join(SPID, @wid, PASS) - expect(join).to be_correct_and_respond 404 - expect(join.to_s).to include 'no_such_pool' - end - - it 'I could check delegation fees - if I could cover fee' do - id = create_shelley_wallet - - pools = SHELLEY.stake_pools - fees = pools.delegation_fees(id) - expect(fees).to be_correct_and_respond 403 - expect(fees.to_s).to include 'no_utxos_available' - end - - it 'Can list stake pools only when stake is provided' do - pools = SHELLEY.stake_pools - l = pools.list({ stake: 1000 }) - l_bad = pools.list - expect(l).to be_correct_and_respond 200 - - expect(l_bad).to be_correct_and_respond 400 - expect(l_bad.to_s).to include 'query_param_missing' - end - - it 'Can join and quit Stake Pool' do - skip 'ADP-3243' - # Get funds on the wallet - address = SHELLEY.addresses.list(@target_id)[0]['id'] - amt = 10_000_000 - deposit = CARDANO_CLI.protocol_params['stakeAddressDeposit'] - tx_sent = SHELLEY.transactions.create(@wid, - PASS, - [{ address => amt }]) - - expect(tx_sent).to be_correct_and_respond 202 - wait_for_tx_in_ledger(@wid, tx_sent['id']) - verify_tx_status(@wid, tx_sent['id'], 'in_ledger') - - stake = get_shelley_balances(@target_id)['total'] - - # Check wallet stake keys before joing stake pool - stake_keys = SHELLEY.stake_pools.list_stake_keys(@target_id) - expect(stake_keys).to be_correct_and_respond 200 - expect(stake_keys['foreign'].size).to eq 0 - expect(stake_keys['ours'].size).to eq 1 - expect(stake_keys['ours'].first['stake']['quantity']).to eq stake - expect(stake_keys['none']['stake']['quantity']).to eq 0 - expect(stake_keys['ours'].first['delegation']['active']['status']).to eq 'not_delegating' - # expect(stake_keys['ours'].first['delegation']['next']).to eq [] - - # Pick up pool id to join - pools = SHELLEY.stake_pools - pool_id = pools.list({ stake: 1000 }).sample['id'] - - # Join pool - puts "Joining pool: #{pool_id}" - join = pools.join(pool_id, @target_id, PASS) - - expect(join).to be_correct_and_respond 202 - expect(join.to_s).to include 'status' - - join_tx_id = join['id'] - eventually "Checking if join tx id (#{join_tx_id}) is in_ledger" do - tx = SHELLEY.transactions.get(@target_id, join_tx_id) - tx['status'] == 'in_ledger' - end - tx = SHELLEY.transactions.get(@target_id, join_tx_id) - fee = tx['fee']['quantity'] - - stake_after_joining = stake - deposit - fee - - # Check wallet stake keys after joing stake pool - stake_keys = SHELLEY.stake_pools.list_stake_keys(@target_id) - expect(stake_keys).to be_correct_and_respond 200 - expect(stake_keys['foreign'].size).to eq 0 - expect(stake_keys['ours'].size).to eq 1 - expect(stake_keys['ours'].first['stake']['quantity']).to eq stake_after_joining - expect(stake_keys['none']['stake']['quantity']).to eq 0 - expect(stake_keys['ours'].first['delegation']['active']['status']).to eq 'not_delegating' - expect(stake_keys['ours'].first['delegation']['next'].last['status']).to eq 'delegating' - - # examine the tx in history - tx_amount(tx, fee + deposit) - tx_fee(tx, fee) - tx_inputs(tx, present: true) - tx_outputs(tx, present: true) - tx_direction(tx, 'outgoing') - tx_script_validity(tx, 'valid') - tx_status(tx, 'in_ledger') - tx_collateral(tx, present: false) - tx_collateral_outputs(tx, present: false) - tx_metadata(tx, nil) - tx_deposits(tx, deposit_taken: deposit, deposit_returned: 0) - tx_withdrawals(tx, present: false) - tx_mint_burn(tx, mint: [], burn: []) - tx_extra_signatures(tx, present: false) - tx_script_integrity(tx, present: false) - tx_validity_interval_default(tx) - tx_certificates(tx, present: true) - expect(tx['certificates'].to_s).to include 'register_reward_account' - expect(tx['certificates'].to_s).to include 'join_pool' - expect(tx['certificates'].to_s).to include pool_id - - # Quit pool - puts "Quitting pool: #{pool_id}" - quit = pools.quit(@target_id, PASS) - - expect(quit).to be_correct_and_respond 202 - expect(quit.to_s).to include 'status' - - quit_tx_id = quit['id'] - eventually "Checking if quit tx id (#{quit_tx_id}) is in_ledger" do - tx = SHELLEY.transactions.get(@target_id, quit_tx_id) - tx['status'] == 'in_ledger' - end - total_balance_after = get_shelley_balances(@target_id)['total'] - - # Check wallet stake keys after quitting stake pool - stake_keys = SHELLEY.stake_pools.list_stake_keys(@target_id) - expect(stake_keys).to be_correct_and_respond 200 - expect(stake_keys['foreign'].size).to eq 0 - expect(stake_keys['ours'].size).to eq 1 - # deposit is back on quitting so stake is higher than before - expect(stake_keys['ours'].first['stake']['quantity']).to be > stake_after_joining - expect(stake_keys['ours'].first['stake']['quantity']).to eq total_balance_after - expect(stake_keys['none']['stake']['quantity']).to eq 0 - expect(stake_keys['ours'].first['delegation']['active']['status']).to eq 'not_delegating' - expect(stake_keys['ours'].first['delegation']['next'].last['status']).to eq 'not_delegating' - - # examine the tx in history - tx = SHELLEY.transactions.get(@target_id, quit_tx_id) - expect(tx['amount']['quantity']).to be > 0 - expect(tx['amount']['quantity']).to be < deposit - expect(tx['fee']['quantity'].to_i).to be > 0 - tx_inputs(tx, present: true) - tx_outputs(tx, present: true) - tx_direction(tx, 'incoming') - tx_script_validity(tx, 'valid') - tx_status(tx, 'in_ledger') - tx_collateral(tx, present: false) - tx_collateral_outputs(tx, present: false) - tx_metadata(tx, nil) - tx_deposits(tx, deposit_taken: 0, deposit_returned: deposit) - tx_withdrawals(tx, present: true) # automatic withdrawal - tx_mint_burn(tx, mint: [], burn: []) - tx_extra_signatures(tx, present: false) - tx_script_integrity(tx, present: false) - tx_validity_interval_default(tx) - tx_certificates(tx, present: true) - expect(tx['certificates'].to_s).to include 'quit_pool' - end - end - - describe 'Coin Selection' do - it 'I can trigger random coin selection' do - addresses = SHELLEY.addresses.list(@target_id) - payload = [{ 'address' => addresses[0]['id'], - 'amount' => { 'quantity' => 2_000_000, 'unit' => 'lovelace' }, - 'assets' => [{ 'policy_id' => ASSETS[0]['policy_id'], - 'asset_name' => ASSETS[0]['asset_name'], - 'quantity' => 1 }, - { 'policy_id' => ASSETS[1]['policy_id'], - 'asset_name' => ASSETS[1]['asset_name'], - 'quantity' => 1 }] }] - - rnd = SHELLEY.coin_selections.random(@wid, payload, 'self', METADATA) - - expect(rnd).to be_correct_and_respond 200 - expect(rnd.to_s).to include 'outputs' - expect(rnd.to_s).to include 'change' - expect(rnd.to_s).to include 'metadata' - expect(rnd['inputs']).not_to be_empty - expect(rnd['outputs']).not_to be_empty - end - - it 'I can trigger random coin selection delegation action' do - pid = SHELLEY.stake_pools.list({ stake: 10_000_000 }).sample['id'] - action_join = { action: 'join', pool: pid } - - rnd = SHELLEY.coin_selections.random_deleg @wid, action_join - - expect(rnd).to be_correct_and_respond 200 - expect(rnd.to_s).to include 'outputs' - expect(rnd.to_s).to include 'change' - expect(rnd['inputs']).not_to be_empty - expect(rnd['change']).not_to be_empty - expect(rnd['outputs']).to be_empty - expect(rnd['certificates']).not_to be_empty - # expect(rnd['certificates'].to_s).to include "register_reward_account" - expect(rnd['certificates'].to_s).to include 'join_pool' - end - - it 'I could trigger random coin selection delegation action - if I had money' do - wid = create_shelley_wallet - pid = SHELLEY.stake_pools.list({ stake: 10_000_000 }).sample['id'] - action_join = { action: 'join', pool: pid } - - rnd = SHELLEY.coin_selections.random_deleg wid, action_join - expect(rnd).to be_correct_and_respond 403 - expect(rnd.to_s).to include 'no_utxos_available' - end - - it 'I could trigger random coin selection delegation action - if I known pool id' do - action_join = { action: 'join', pool: SPID_BECH32 } - action_quit = { action: 'quit' } - - rnd = SHELLEY.coin_selections.random_deleg @wid, action_join - expect(rnd).to be_correct_and_respond 404 - expect(rnd.to_s).to include 'no_such_pool' - - rnd = SHELLEY.coin_selections.random_deleg @wid, action_quit - expect(rnd).to be_correct_and_respond 403 - expect(rnd.to_s).to include 'not_delegating_to' - end - end - - describe 'Update passphrase' do - it 'I can update passphrase with mnemonic and the wallet does not have to re-sync' do - mnemonics = get_fixture_wallet(:fixture, :shelley, :mnemonics) - upd = SHELLEY.wallets.update_passphrase(@wid, { mnemonic_sentence: mnemonics, - new_passphrase: PASS }) - expect(upd).to be_correct_and_respond 204 - wallet = SHELLEY.wallets.get(@wid) - expect(wallet['state']['status']).to eq 'ready' - end - end - end - - describe 'E2E Byron' do - def test_byron_fees(source_wid) - txs = BYRON.transactions - # get required minimum ada - fees = txs.payment_fees(source_wid, payment_payload(1)) - expect(fees.code).to eq 403 - expect(fees['code']).to eq 'utxo_too_small' - amt = fees['info']['tx_output_lovelace_required_minimum']['quantity'] - - fees = txs.payment_fees(source_wid, payment_payload(amt)) - expect(fees).to be_correct_and_respond 202 - end - - def test_byron_tx(source_wid, target_wid) - address = SHELLEY.addresses.list(target_wid)[0]['id'] - target_before = get_shelley_balances(target_wid) - src_before = get_byron_balances(source_wid) - - # get required minimum ada - tx = BYRON.transactions.create(source_wid, PASS, payment_payload(1, address)) - expect(tx.code).to eq 403 - expect(tx['code']).to eq 'utxo_too_small' - amt = tx['info']['tx_output_lovelace_required_minimum']['quantity'] - - tx_sent = BYRON.transactions.create(source_wid, PASS, payment_payload(amt, address)) - - expect(tx_sent).to be_correct_and_respond 202 - tx_id = tx_sent['id'] - wait_for_tx_in_ledger(target_wid, tx_id) - verify_tx_status(source_wid, tx_id, 'in_ledger', BYRON) - - target_after = get_shelley_balances(target_wid) - src_after = get_byron_balances(source_wid) - fee = BYRON.transactions.get(source_wid, tx_id)['fee']['quantity'] - - verify_ada_balance(src_after, src_before, - target_after, target_before, - amt, fee) - - # examine the tx in history - # on src wallet - tx = BYRON.transactions.get(source_wid, tx_id) - tx_amount(tx, amt + fee) - tx_fee(tx, fee) - tx_inputs(tx, present: true) - tx_outputs(tx, present: true) - tx_direction(tx, 'outgoing') - tx_script_validity(tx, 'valid') - tx_status(tx, 'in_ledger') - tx_collateral(tx, present: false) - tx_collateral_outputs(tx, present: false) - tx_metadata(tx, nil) - tx_deposits(tx, deposit_taken: 0, deposit_returned: 0) - tx_withdrawals(tx, present: false) - tx_mint_burn(tx, mint: [], burn: []) - tx_extra_signatures(tx, present: false) - tx_script_integrity(tx, present: false) - tx_validity_interval_default(tx) - tx_certificates(tx, present: false) - - # on target wallet - txt = SHELLEY.transactions.get(target_wid, tx_id) - tx_amount(txt, amt) - tx_fee(tx, fee) - tx_inputs(txt, present: true) - tx_outputs(txt, present: true) - tx_direction(txt, 'incoming') - tx_script_validity(txt, 'valid') - tx_status(txt, 'in_ledger') - tx_collateral(txt, present: false) - tx_collateral_outputs(txt, present: false) - tx_metadata(txt, nil) - # ADP-2298 - Deposit_returned is falsely reported on some incoming transactions (intermittently) - # tx_deposits(txt, deposit_taken: 0, deposit_returned: 0) - tx_withdrawals(txt, present: false) - tx_mint_burn(txt, mint: [], burn: []) - tx_extra_signatures(txt, present: false) - tx_script_integrity(txt, present: false) - tx_validity_interval_default(txt) - tx_certificates(txt, present: false) - end - - def test_byron_assets_tx(source_id, target_id) - amt = 1 - address = SHELLEY.addresses.list(target_id)[1]['id'] - target_before = get_shelley_balances(target_id) - src_before = get_byron_balances(source_id) - payload = [{ 'address' => address, - 'amount' => { 'quantity' => 0, 'unit' => 'lovelace' }, - 'assets' => [{ 'policy_id' => ASSETS[0]['policy_id'], - 'asset_name' => ASSETS[0]['asset_name'], - 'quantity' => amt }, - { 'policy_id' => ASSETS[1]['policy_id'], - 'asset_name' => ASSETS[1]['asset_name'], - 'quantity' => amt }] }] - - tx_sent = BYRON.transactions.create(source_id, PASS, payload) - - expect(tx_sent).to be_correct_and_respond 202 - tx_id = tx_sent['id'] - wait_for_tx_in_ledger(target_id, tx_id) - verify_tx_status(source_id, tx_id, 'in_ledger', BYRON) - - target_after = get_shelley_balances(target_id) - src_after = get_byron_balances(source_id) - tx = BYRON.transactions.get(source_id, tx_id) - fee = tx['fee']['quantity'] - amt_ada = tx['amount']['quantity'] - fee - - verify_ada_balance(src_after, src_before, - target_after, target_before, - amt_ada, fee) - - verify_asset_balance(src_after, src_before, - target_after, target_before, - amt) - - # Target wallet lists my associated assets - assets = SHELLEY.assets.get(target_id) - expect(assets).to be_correct_and_respond 200 - expect(assets.to_s).to include ASSETS[0]['policy_id'] - expect(assets.to_s).to include ASSETS[0]['asset_name'] - expect(assets.to_s).to include ASSETS[1]['policy_id'] - expect(assets.to_s).to include ASSETS[1]['asset_name'] - - # examine the tx in history - # on src wallet - tx = BYRON.transactions.get(source_id, tx_id) - tx_amount(tx, amt_ada + fee) - tx_fee(tx, fee) - tx_inputs(tx, present: true) - tx_outputs(tx, present: true) - tx_direction(tx, 'outgoing') - tx_script_validity(tx, 'valid') - tx_status(tx, 'in_ledger') - tx_collateral(tx, present: false) - tx_collateral_outputs(tx, present: false) - tx_metadata(tx, nil) - tx_deposits(tx, deposit_taken: 0, deposit_returned: 0) - tx_withdrawals(tx, present: false) - tx_mint_burn(tx, mint: [], burn: []) - tx_extra_signatures(tx, present: false) - tx_script_integrity(tx, present: false) - tx_validity_interval_default(tx) - tx_certificates(tx, present: false) - - # on target wallet - txt = SHELLEY.transactions.get(target_id, tx_id) - tx_amount(txt, amt_ada) - tx_fee(tx, fee) - tx_inputs(txt, present: true) - tx_outputs(txt, present: true) - tx_direction(txt, 'incoming') - tx_script_validity(txt, 'valid') - tx_status(txt, 'in_ledger') - tx_collateral(txt, present: false) - tx_collateral_outputs(txt, present: false) - tx_metadata(txt, nil) - # ADP-2298 - Deposit_returned is falsely reported on some incoming transactions (intermittently) - # tx_deposits(txt, deposit_taken: 0, deposit_returned: 0) - tx_withdrawals(txt, present: false) - tx_mint_burn(txt, mint: [], burn: []) - tx_extra_signatures(txt, present: false) - tx_script_integrity(txt, present: false) - tx_validity_interval_default(txt) - tx_certificates(txt, present: false) - end - - def test_byron_trans_list(wid) - # get 3 txs - txs = BYRON.transactions.list(wid, { max_count: 3, order: 'ascending' }) - expect(txs).to be_correct_and_respond 200 - expect(txs.size).to be 3 - - last_tx_time = txs.first['inserted_at']['time'] - first_tx_time = txs.last['inserted_at']['time'] - - # get 2 txs - txs = BYRON.transactions.list(wid, { max_count: 2, order: 'ascending' }) - expect(txs).to be_correct_and_respond 200 - expect(txs.size).to eq 2 - expect(txs.first['inserted_at']['time']).to eq last_tx_time - - # get 2 txs in ascending order - txs = BYRON.transactions.list(wid, { max_count: 2, start: first_tx_time, order: 'ascending' }) - expect(txs).to be_correct_and_respond 200 - expect(txs.size).to eq 2 - expect(txs.first['inserted_at']['time']).to eq first_tx_time - - # get 2 txs in ascending order with start and end time - txs = BYRON.transactions.list(wid, { max_count: 2, start: last_tx_time, end: first_tx_time, order: 'ascending' }) - expect(txs).to be_correct_and_respond 200 - expect(txs.size).to eq 2 - expect(txs.first['inserted_at']['time']).to eq last_tx_time - end - - describe 'UTxOs' do - it 'Fixture shared wallets have utxos' do - @nightly_byron_wallets.each do |wid| - utxo_stats = BYRON.wallets.utxo(wid) - expect(utxo_stats).to be_correct_and_respond 200 - - utxo_snap = BYRON.wallets.utxo_snapshot(wid) - expect(utxo_snap).to be_correct_and_respond 200 - expect(utxo_snap['entries'].size).to be > 0 - end - end - end - describe 'Byron Transactions' do - it 'I can estimate fees (min_utxo_value), random' do - test_byron_fees(@wid_rnd) - end - - it 'I can estimate fees (min_utxo_value), icarus' do - test_byron_fees(@wid_ic) - end - - it 'I can send transaction and funds are received (min_utxo_value), random -> shelley' do - test_byron_tx(@wid_rnd, @target_id) - end - - it 'I can send transaction and funds are received (min_utxo_value), icarus -> shelley' do - test_byron_tx(@wid_ic, @target_id) - end - - it 'I can send native assets tx and they are received (random -> shelley)' do - test_byron_assets_tx(@wid_rnd, @target_id) - end - - it 'I can send native assets tx and they are received (icarus -> shelley)' do - test_byron_assets_tx(@wid_ic, @target_id) - end - - it 'I can list transactions and limit response with query parameters (byron)' do - test_byron_trans_list(@wid_rnd) - end - - it 'I can list transactions and limit response with query parameters (icarus)' do - test_byron_trans_list(@wid_ic) - end - end - - describe 'Byron Migrations' do - it 'I can create migration plan byron -> shelley' do - addrs = SHELLEY.addresses.list(@target_id).map { |a| a['id'] } - - plan = BYRON.migrations.plan(@wid_rnd, addrs) - expect(plan).to be_correct_and_respond 202 - expect(plan['balance_selected']['assets']).not_to be [] - expect(plan['balance_leftover']).to eq({ 'ada' => { 'quantity' => 0, - 'unit' => 'lovelace' }, - 'assets' => [] }) - end - - it 'I can create migration plan icarus -> shelley' do - addrs = SHELLEY.addresses.list(@target_id).map { |a| a['id'] } - - plan = BYRON.migrations.plan(@wid_ic, addrs) - expect(plan).to be_correct_and_respond 202 - expect(plan['balance_selected']['assets']).not_to be [] - expect(plan['balance_leftover']).to eq({ 'ada' => { 'quantity' => 0, - 'unit' => 'lovelace' }, - 'assets' => [] }) - end - end - - describe 'Native Assets' do - it 'I can list assets -> random' do - assets = BYRON.assets.get @wid_rnd - expect(assets).to be_correct_and_respond 200 - expect(assets.to_s).to include ASSETS[0]['policy_id'] - expect(assets.to_s).to include ASSETS[0]['asset_name'] - expect(assets.to_s).to include ASSETS[1]['policy_id'] - expect(assets.to_s).to include ASSETS[1]['asset_name'] - - assets = BYRON.assets.get(@wid_rnd, ASSETS[0]['policy_id']) - expect(assets).to be_correct_and_respond 200 - expect(assets['policy_id']).to eq ASSETS[0]['policy_id'] - expect(assets['asset_name']).to eq ASSETS[0]['asset_name'] - expect(assets['asset_name']).not_to eq ASSETS[1]['asset_name'] - - assets = BYRON.assets.get(@wid_rnd, ASSETS[1]['policy_id'], ASSETS[1]['asset_name']) - expect(assets).to be_correct_and_respond 200 - expect(assets['policy_id']).to eq ASSETS[1]['policy_id'] - expect(assets['asset_name']).to eq ASSETS[1]['asset_name'] - expect(assets['asset_name']).not_to eq ASSETS[0]['asset_name'] - end - - it 'I can list assets -> icarus' do - assets = BYRON.assets.get @wid_ic - expect(assets).to be_correct_and_respond 200 - expect(assets.to_s).to include ASSETS[0]['policy_id'] - expect(assets.to_s).to include ASSETS[0]['asset_name'] - expect(assets.to_s).to include ASSETS[1]['policy_id'] - expect(assets.to_s).to include ASSETS[1]['asset_name'] - - assets = BYRON.assets.get(@wid_ic, ASSETS[0]['policy_id']) - expect(assets).to be_correct_and_respond 200 - expect(assets['policy_id']).to eq ASSETS[0]['policy_id'] - expect(assets['asset_name']).to eq ASSETS[0]['asset_name'] - expect(assets['asset_name']).not_to eq ASSETS[1]['asset_name'] - - assets = BYRON.assets.get(@wid_ic, ASSETS[1]['policy_id'], ASSETS[1]['asset_name']) - expect(assets).to be_correct_and_respond 200 - expect(assets['policy_id']).to eq ASSETS[1]['policy_id'] - expect(assets['asset_name']).to eq ASSETS[1]['asset_name'] - expect(assets['asset_name']).not_to eq ASSETS[0]['asset_name'] - end - - it 'I can list assets with offchain metadata -> random', :offchain do - assets = BYRON.assets.get(@wid_rnd, ASSETS[0]['policy_id']) - expect(assets).to be_correct_and_respond 200 - expect(assets['policy_id']).to eq ASSETS[0]['policy_id'] - expect(assets['asset_name']).to eq ASSETS[0]['asset_name'] - expect(assets['metadata']).to eq ASSETS[0]['metadata'] - expect(assets['asset_name']).not_to eq ASSETS[1]['asset_name'] - expect(assets['metadata']).not_to eq ASSETS[1]['metadata'] - - assets = BYRON.assets.get(@wid_rnd, ASSETS[1]['policy_id'], ASSETS[1]['asset_name']) - expect(assets).to be_correct_and_respond 200 - expect(assets['policy_id']).to eq ASSETS[1]['policy_id'] - expect(assets['asset_name']).to eq ASSETS[1]['asset_name'] - expect(assets['metadata']).to eq ASSETS[1]['metadata'] - expect(assets['asset_name']).not_to eq ASSETS[0]['asset_name'] - expect(assets['metadata']).not_to eq ASSETS[0]['metadata']['name'] - end - - it 'I can list assets with offchain metadata -> icarus', :offchain do - assets = BYRON.assets.get(@wid_ic, ASSETS[0]['policy_id']) - expect(assets).to be_correct_and_respond 200 - expect(assets['policy_id']).to eq ASSETS[0]['policy_id'] - expect(assets['asset_name']).to eq ASSETS[0]['asset_name'] - expect(assets['metadata']).to eq ASSETS[0]['metadata'] - expect(assets['asset_name']).not_to eq ASSETS[1]['asset_name'] - expect(assets['metadata']).not_to eq ASSETS[1]['metadata'] - - assets = BYRON.assets.get(@wid_ic, ASSETS[1]['policy_id'], ASSETS[1]['asset_name']) - expect(assets).to be_correct_and_respond 200 - expect(assets['policy_id']).to eq ASSETS[1]['policy_id'] - expect(assets['asset_name']).to eq ASSETS[1]['asset_name'] - expect(assets['metadata']).to eq ASSETS[1]['metadata'] - expect(assets['asset_name']).not_to eq ASSETS[0]['asset_name'] - expect(assets['metadata']).not_to eq ASSETS[0]['metadata']['name'] - end - end - end - - describe 'E2E External transaction' do - it 'Submit tx via POST /proxy/transactions' do - amt = MIN_UTXO_VALUE_PURE_ADA - address = SHELLEY.addresses.list(@target_id)[0]['id'] - target_before = get_shelley_balances(@target_id) - src_before = get_shelley_balances(@wid) - - tx_constructed = SHELLEY.transactions.construct(@wid, payment_payload(amt, address)) - expect(tx_constructed).to be_correct_and_respond 202 - expected_fee = tx_constructed['fee']['quantity'] - tx_decoded = SHELLEY.transactions.decode(@wid, tx_constructed['transaction']) - expect(tx_decoded).to be_correct_and_respond 202 - - decoded_fee = tx_decoded['fee']['quantity'] - expect(expected_fee).to eq decoded_fee - - tx_signed = SHELLEY.transactions.sign(@wid, PASS, tx_constructed['transaction']) - expect(tx_signed).to be_correct_and_respond 202 - - # construct tx binary blob - serialized_tx = Base64.decode64(tx_signed['transaction'].strip) - # submitting tx via POST /proxy/transactions - tx_submitted = PROXY.submit_external_transaction(serialized_tx) - expect(tx_submitted).to be_correct_and_respond 202 - - # tx is visible on the src wallet as inputs belong to it - tx_id = tx_submitted['id'] - wait_for_tx_in_ledger(@wid, tx_id) - - target_after = get_shelley_balances(@target_id) - src_after = get_shelley_balances(@wid) - tx = SHELLEY.transactions.get(@wid, tx_id) - # verify actual fee the same as constructed - expect(expected_fee).to eq tx['fee']['quantity'] - - verify_ada_balance(src_after, src_before, - target_after, target_before, - amt, expected_fee) - end - - it 'Cannot submit unsigned tx via POST /proxy/transactions' do - amt = MIN_UTXO_VALUE_PURE_ADA - address = SHELLEY.addresses.list(@target_id)[0]['id'] - - tx_constructed = SHELLEY.transactions.construct(@wid, payment_payload(amt, address)) - expect(tx_constructed).to be_correct_and_respond 202 - - # construct tx binary blob - serialized_tx = Base64.decode64(tx_constructed['transaction'].strip) - # submitting tx via POST /proxy/transactions - tx_submitted = PROXY.submit_external_transaction(serialized_tx) - expect(tx_submitted.parsed_response).to include 'code' => 'created_invalid_transaction' - end - end - - describe 'E2E Migration' do - it 'I can migrate all funds back to fixture wallet' do - address = SHELLEY.addresses.list(@wid)[0]['id'] - src_before = get_shelley_balances(@target_id) - target_before = get_shelley_balances(@wid) - - migration = SHELLEY.migrations.migrate(@target_id, PASS, [address]) - tx_ids = migration.map { |m| m['id'] } - fees = migration.map { |m| m['fee']['quantity'] }.sum - amounts = migration.map { |m| m['amount']['quantity'] }.sum - fees - - tx_ids.each do |tx_id| - wait_for_tx_in_ledger(@target_id, tx_id) - end - src_after = get_shelley_balances(@target_id) - target_after = get_shelley_balances(@wid) - expected_src_balance = { 'total' => 0, - 'available' => 0, - 'rewards' => 0, - 'assets_total' => [], - 'assets_available' => [] } - - expect(src_after).to eq expected_src_balance - - verify_ada_balance(src_after, src_before, - target_after, target_before, - amounts, fees) - - tx_ids.each do |tx_id| - # examine the tx in history - # on src wallet - tx = SHELLEY.transactions.get(@target_id, tx_id) - tx_inputs(tx, present: true) - tx_outputs(tx, present: true) - tx_direction(tx, 'outgoing') - tx_script_validity(tx, 'valid') - tx_status(tx, 'in_ledger') - tx_collateral(tx, present: false) - tx_collateral_outputs(tx, present: false) - tx_metadata(tx, nil) - tx_deposits(tx, deposit_taken: 0, deposit_returned: 0) - tx_withdrawals(tx, present: false) - tx_mint_burn(tx, mint: [], burn: []) - tx_extra_signatures(tx, present: false) - tx_script_integrity(tx, present: false) - tx_validity_interval_default(tx) - tx_certificates(tx, present: false) - - # on target wallet - txt = SHELLEY.transactions.get(@wid, tx_id) - expect(tx['fee']['quantity'].to_i).to be > 0 - tx_inputs(txt, present: true) - tx_outputs(txt, present: true) - tx_direction(txt, 'incoming') - tx_script_validity(txt, 'valid') - tx_status(txt, 'in_ledger') - tx_collateral(txt, present: false) - tx_collateral_outputs(txt, present: false) - tx_metadata(txt, nil) - # ADP-2298 - Deposit_returned is falsely reported on some incoming transactions (intermittently) - # tx_deposits(txt, deposit_taken: 0, deposit_returned: 0) - tx_withdrawals(txt, present: false) - tx_mint_burn(txt, mint: [], burn: []) - tx_extra_signatures(txt, present: false) - tx_script_integrity(txt, present: false) - tx_validity_interval_default(txt) - tx_certificates(txt, present: false) - end - end - end -end diff --git a/test/e2e/spec/misc_spec.rb b/test/e2e/spec/misc_spec.rb deleted file mode 100644 index 9e97fea58d9..00000000000 --- a/test/e2e/spec/misc_spec.rb +++ /dev/null @@ -1,357 +0,0 @@ -# frozen_string_literal: true - -RSpec.describe CardanoWallet::Misc, :all, :misc do - describe CardanoWallet::Misc::Node do - it 'Can get latest block header info' do - res = NODE.block_header - expect(res).to be_correct_and_respond 200 - expect(res.to_s).to include 'block_height' - expect(res.to_s).to include 'header_hash' - expect(res.to_s).to include 'slot_no' - end - end - - describe CardanoWallet::Misc::Network do - it 'Can get network information' do - res = NETWORK.information - expect(res).to be_correct_and_respond 200 - expect(res['network_info']['protocol_magic']).to eq get_protocol_magic(CONTEXT.env) - expect(res['network_info']['network_id']).to eq 'testnet' - expect(res['wallet_mode']).to eq 'node' - end - - it 'Can check network clock offset' do - res = NETWORK.clock - expect(res).to be_correct_and_respond 200 - end - - it 'Can check network parameters' do - network_params = %w[slot_length - decentralization_level - maximum_token_bundle_size - genesis_block_hash - blockchain_start_time - desired_pool_number - execution_unit_prices - eras - minimum_collateral_percentage - active_slot_coefficient - security_parameter - maximum_collateral_input_count] - res = NETWORK.parameters - expect(res).to be_correct_and_respond 200 - network_params.each do |p| - expect(res.to_s).to include p - end - end - end - - describe CardanoWallet::Misc::Utils do - describe 'SMASH health' do - it 'SMASH health - unreachable' do - r = UTILS.smash_health({ url: 'http://onet.pl' }) - expect(r).to be_correct_and_respond 200 - expect(r.to_s).to include 'unreachable' - end - - it 'SMASH health - bad url' do - r = UTILS.smash_health({ url: 'dsds' }) - expect(r).to be_correct_and_respond 400 - expect(r.to_s).to include 'bad_request' - end - end - - it 'Inspect invalid address' do - addr = 'addr' - res = UTILS.addresses addr - expect(res).to be_correct_and_respond 400 - expect(res.to_s).to include 'bad_request' - end - - it 'Inspect Shelley payment address' do - addr = 'addr1qqlgm2dh3vpv07cjfcyuu6vhaqhf8998qcx6s8ucpkly6f8l0dw5r75vk42mv3ykq8vyjeaanvpytg79xqzymqy5acmqej0mk7' - res = UTILS.addresses addr - - expect(res).to be_correct_and_respond 200 - expect(res['address_style']).to eq 'Shelley' - expect(res['stake_reference']).to eq 'by value' - expect(res['stake_key_hash']).to eq 'ff7b5d41fa8cb555b6449601d84967bd9b0245a3c530044d8094ee36' - expect(res['spending_key_hash']).to eq '3e8da9b78b02c7fb124e09ce6997e82e9394a7060da81f980dbe4d24' - expect(res['network_tag']).to eq 0 - end - - it 'Inspect Shelley stake address' do - addr = 'stake_test1uzws33ghf8kugc8ea8p7h8mr7dcsl6ggw7tfy479y9t0d4qp48dkq' - res = UTILS.addresses addr - - expect(res).to be_correct_and_respond 200 - expect(res['address_style']).to eq 'Shelley' - expect(res['stake_reference']).to eq 'by value' - expect(res['stake_key_hash']).to eq '9d08c51749edc460f9e9c3eb9f63f3710fe90877969257c52156f6d4' - expect(res['network_tag']).to eq 0 - end - - it 'Inspect Byron Random address' do - addr = '37btjrVyb4KEzz6YprjHfqz3DS4JvoDpAf3QWLABzQ7uzMEk7g3PD2AwL1SbYWekneuRFkyTipbyKMZyEMed5LroZtQAvA2LqcWmJuwaqt6oJLbssS' - res = UTILS.addresses addr - - expect(res).to be_correct_and_respond 200 - expect(res['address_style']).to eq 'Byron' - expect(res['stake_reference']).to eq 'none' - expect(res['address_root']).to eq 'c23a0f86c7bc977f0dee4721c9850467047a0e6acd928a991b5cbba8' - expect(res['derivation_path']).to eq '581c6a6589ca57730b33d1bb316c13a76d7794a11ba2d077724bdfb51b45' - expect(res['network_tag']).to eq 1_097_911_063 - end - - it 'Inspect Byron Icarus address' do - addr = '2cWKMJemoBajQcoTotf4xYba7fV7Ztx7AvbnzvaQY6PbezPWM6DtJD6Df2bVejBCpykmt' - res = UTILS.addresses addr - - expect(res).to be_correct_and_respond 200 - expect(res['address_style']).to eq 'Icarus' - expect(res['stake_reference']).to eq 'none' - expect(res['address_root']).to eq '88940c753ee50d556ecaefadd0d2fee9fabacf4366a7d4a8cdfa2b64' - expect(res['network_tag']).to eq 1_097_911_063 - end - - describe 'Construct addresses' do - it 'Enterprise script address - signature' do - script = { - payment: 'addr_shared_vkh1zxt0uvrza94h3hv4jpv0ttddgnwkvdgeyq8jf9w30mcs6y8w3nq' - } - res = UTILS.post_address(script) - expect(res).to be_correct_and_respond 202 - expect(res.to_s).to include 'addr_test1wrrqr8fmk4ulc7pgycd96fuqcg40e5ecuway0ypc2tsnteqqu6qs0' - end - - it 'Enterprise script address - any' do - script = { - payment: { - any: %w[ - addr_shared_vkh1zxt0uvrza94h3hv4jpv0ttddgnwkvdgeyq8jf9w30mcs6y8w3nq - addr_shared_vkh1y3zl4nqgm96ankt96dsdhc86vd5geny0wr7hu8cpzdfcqskq2cp - ] - } - } - res = UTILS.post_address(script) - expect(res).to be_correct_and_respond 202 - expect(res.to_s).to include 'addr_test1wrjtlgneqelxxlckcsgrkd7rd6ycrgegu5th24x0f058gmqvc8s20' - end - - it 'Enterprise script address - all' do - addr1 = 'addr_shared_vkh1zxt0uvrza94h3hv4jpv0ttddgnwkvdgeyq8jf9w30mcs6y8w3nq' - addr2 = 'addr_shared_vkh1y3zl4nqgm96ankt96dsdhc86vd5geny0wr7hu8cpzdfcqskq2cp' - script = { - payment: { - all: [ - addr1, - addr2 - ] - } - } - ca_script_hash = CA.script_hash("all [#{addr1}, #{addr2}]") - script_hash = { payment: ca_script_hash } - - script_res = UTILS.post_address(script) - expect(script_res).to be_correct_and_respond 202 - script_hash_res = UTILS.post_address(script_hash) - expect(script_hash_res).to be_correct_and_respond 202 - - expect(script_res['address']).to eq script_hash_res['address'] - - expect(script_res['address']).to eq 'addr_test1wpq0ghwy73wapjcdwqxm6ytwe66j8eccsmn9jptshrjerashp7y82' - end - - it 'Enterprise script address - some' do - addr1 = 'addr_shared_vkh1zxt0uvrza94h3hv4jpv0ttddgnwkvdgeyq8jf9w30mcs6y8w3nq' - addr2 = 'addr_shared_vkh1y3zl4nqgm96ankt96dsdhc86vd5geny0wr7hu8cpzdfcqskq2cp' - addr3 = 'addr_shared_vkh175wsm9ckhm3snwcsn72543yguxeuqm7v9r6kl6gx57h8gdydcd9' - script = { - payment: { - some: { - from: [ - addr1, - addr2, - addr3 - ], - at_least: 2 - } - } - } - ca_script_hash = CA.script_hash("at_least 2 [#{addr1}, #{addr2}, #{addr3}]") - script_hash = { payment: ca_script_hash } - - script_res = UTILS.post_address(script) - expect(script_res).to be_correct_and_respond 202 - script_hash_res = UTILS.post_address(script_hash) - expect(script_hash_res).to be_correct_and_respond 202 - - expect(script_res['address']).to eq script_hash_res['address'] - expect(script_res['address']).to eq 'addr_test1wqqmnmwuh85e0fxaggl6ac2hfeqncg76gsr0ld8qdjd84agpc0nuz' - end - - it 'Reward account script address - any' do - addr1 = 'stake_shared_vkh1nqc00hvlc6cq0sfhretk0rmzw8dywmusp8retuqnnxzajtzhjg5' - addr2 = 'stake_shared_vkh1nac0awgfa4zjsh4elnjmsscz0huhss8q2g0x3n7m539mwaa5m7s' - script = { - stake: { - any: [ - addr1, - addr2 - ] - } - } - - ca_script_hash = CA.script_hash("any [#{addr1}, #{addr2}]") - script_hash = { stake: ca_script_hash } - - script_res = UTILS.post_address(script) - expect(script_res).to be_correct_and_respond 202 - script_hash_res = UTILS.post_address(script_hash) - expect(script_hash_res).to be_correct_and_respond 202 - - expect(script_res['address']).to eq script_hash_res['address'] - expect(script_res['address']).to eq 'stake_test17qshpfjkgh98wumvnn9y3yfhevllp4y04u6y84q3flxcv9s2kvrnx' - end - - it 'Delegating script address - any' do - addr1 = 'addr_shared_vkh1zxt0uvrza94h3hv4jpv0ttddgnwkvdgeyq8jf9w30mcs6y8w3nq' - addr2 = 'addr_shared_vkh1y3zl4nqgm96ankt96dsdhc86vd5geny0wr7hu8cpzdfcqskq2cp' - addr3 = 'addr_shared_vkh175wsm9ckhm3snwcsn72543yguxeuqm7v9r6kl6gx57h8gdydcd9' - addr4 = 'addr_shared_vkh1zxt0uvrza94h3hv4jpv0ttddgnwkvdgeyq8jf9w30mcs6y8w3nq' - addr5 = 'addr_shared_vkh1y3zl4nqgm96ankt96dsdhc86vd5geny0wr7hu8cpzdfcqskq2cp' - script = { - payment: { - some: { - from: [ - addr1, - addr2, - addr3 - ], - at_least: 2 - } - }, - stake: { - any: [ - addr4, - addr5 - ] - } - } - ca_script_hash_payment = CA.script_hash("at_least 2 [#{addr1}, #{addr2}, #{addr3}]") - ca_script_hash_stake = CA.script_hash("any [#{addr4}, #{addr5}]") - script_hash = { payment: ca_script_hash_payment, stake: ca_script_hash_stake } - - script_res = UTILS.post_address(script) - expect(script_res).to be_correct_and_respond 202 - script_hash_res = UTILS.post_address(script_hash) - expect(script_hash_res).to be_correct_and_respond 202 - - expect(script_res['address']).to eq script_hash_res['address'] - expect(script_res['address']).to eq 'addr_test1xqqmnmwuh85e0fxaggl6ac2hfeqncg76gsr0ld8qdjd84a0yh738jpn7vdl3d3qs8vmuxm5fsx3j3eghw42v7jlgw3kqrw53af' - end - - it 'Enterprise pub key address' do - script = { - payment: 'addr_vk1lqglg77z6kajsdz4739q22c0zm0yhuy567z6xk2vc0z5ucjtkwpschzd2j' - } - res = UTILS.post_address(script) - expect(res).to be_correct_and_respond 202 - expect(res.to_s).to include 'addr_test1vpqthemrg5kczwfjjnahwt65elhrl95e9hcgufnajtp6wfgdmxm9u' - end - - it 'Reward account pub key address' do - script = { - stake: 'stake_vk16apaenn9ut6s40lcw3l8v68xawlrlq20z2966uzcx8jmv2q9uy7qau558d' - } - res = UTILS.post_address(script) - expect(res).to be_correct_and_respond 202 - expect(res.to_s).to include 'stake_test1uq6pmlvyl3wn4ca6807e26gy2gek9hqu0gastzh5tk0xx0gdfvj8f' - end - - it 'Delegating address with both pub key credentials' do - script = { - payment: 'addr_vk1lqglg77z6kajsdz4739q22c0zm0yhuy567z6xk2vc0z5ucjtkwpschzd2j', - stake: 'stake_vk16apaenn9ut6s40lcw3l8v68xawlrlq20z2966uzcx8jmv2q9uy7qau558d' - } - res = UTILS.post_address(script) - expect(res).to be_correct_and_respond 202 - expect(res.to_s).to include 'addr_test1qpqthemrg5kczwfjjnahwt65elhrl95e9hcgufnajtp6wff5rh7cflza8t3m5wlaj45sg53nvtwpc73mqk90ghv7vv7ser7yl4' - end - - it 'Delegating address - payment from script, stake from key' do - script = { - payment: { - some: { - from: %w[ - addr_shared_vkh1zxt0uvrza94h3hv4jpv0ttddgnwkvdgeyq8jf9w30mcs6y8w3nq - addr_shared_vkh1y3zl4nqgm96ankt96dsdhc86vd5geny0wr7hu8cpzdfcqskq2cp - addr_shared_vkh175wsm9ckhm3snwcsn72543yguxeuqm7v9r6kl6gx57h8gdydcd9 - ], - at_least: 2 - } - }, - stake: 'stake_vk16apaenn9ut6s40lcw3l8v68xawlrlq20z2966uzcx8jmv2q9uy7qau558d' - } - res = UTILS.post_address(script) - expect(res).to be_correct_and_respond 202 - expect(res.to_s).to include 'addr_test1zqqmnmwuh85e0fxaggl6ac2hfeqncg76gsr0ld8qdjd84af5rh7cflza8t3m5wlaj45sg53nvtwpc73mqk90ghv7vv7sq4jdnx' - end - - it 'Delegating address - payment from key, stake from script' do - script = { - payment: 'addr_vk1lqglg77z6kajsdz4739q22c0zm0yhuy567z6xk2vc0z5ucjtkwpschzd2j', - stake: { - some: { - from: %w[ - addr_shared_vkh1zxt0uvrza94h3hv4jpv0ttddgnwkvdgeyq8jf9w30mcs6y8w3nq - addr_shared_vkh1y3zl4nqgm96ankt96dsdhc86vd5geny0wr7hu8cpzdfcqskq2cp - addr_shared_vkh175wsm9ckhm3snwcsn72543yguxeuqm7v9r6kl6gx57h8gdydcd9 - ], - at_least: 2 - } - } - } - res = UTILS.post_address(script) - expect(res).to be_correct_and_respond 202 - expect(res.to_s).to include 'addr_test1ypqthemrg5kczwfjjnahwt65elhrl95e9hcgufnajtp6wfgph8kaew0fj7jd6s3l4ms4wnjp8s3a53qxl76wqmy60t6snk9ahl' - end - end - end - - describe CardanoWallet::Misc::Proxy do - it 'Malformed payload when tx is not binary' do - pending 'ADP-1145 - DecoderErrorDeserialiseFailure error message from the API /proxy/transactions' - no_binary_blob = 'test' - res = PROXY.submit_external_transaction(no_binary_blob) - expect(res).to be_correct_and_respond 400 - expect(res.to_s).to include 'malformed_tx_payload' - end - end - - describe CardanoWallet::Misc::Settings do - after(:all) do - SETTINGS.update({ pool_metadata_source: 'none' }) - end - - matrix = { 'direct' => 'no_smash_configured', - 'https://smash.pl' => 'unreachable', - 'none' => 'no_smash_configured' } - - matrix.each do |strategy, smash_health_response| - it "I can read and update settings to #{strategy} and verify SMASH health = #{smash_health_response}" do - s = SETTINGS.update({ pool_metadata_source: strategy }) - expect(s).to be_correct_and_respond 204 - - g = SETTINGS.get - expect(g['pool_metadata_source']).to eq strategy - expect(g).to be_correct_and_respond 200 - - # check smash health - r = UTILS.smash_health - expect(r).to be_correct_and_respond 200 - expect(r.to_s).to include smash_health_response - end - end - end -end diff --git a/test/e2e/spec/shared_spec.rb b/test/e2e/spec/shared_spec.rb deleted file mode 100644 index 457487c63d4..00000000000 --- a/test/e2e/spec/shared_spec.rb +++ /dev/null @@ -1,786 +0,0 @@ -# frozen_string_literal: true - -RSpec.describe CardanoWallet::Shared, :all, :shared do - after(:each) do - teardown - end - - describe CardanoWallet::Shared::Wallets do - describe 'Create wallets' do - it 'I can create, get and delete wallet from mnemonics getting acc_xpub from cardano-address' do - m24 = CW.utils.mnemonic_sentence(24) - acc_ix = '0H' - acc_xpub = cardano_address_get_acc_xpub(m24, "1854H/1815H/#{acc_ix}") - script_template = { 'cosigners' => - { 'cosigner#0' => acc_xpub }, - 'template' => - { 'all' => - ['cosigner#0', - { 'active_from' => 120 }] } } - - payload = { mnemonic_sentence: m24, - passphrase: PASS, - name: 'Shared wallet', - account_index: acc_ix, - payment_script_template: script_template, - delegation_script_template: script_template } - - wallet = WalletFactory.create(:shared, payload) - expect(wallet).to be_correct_and_respond 201 - - wid = wallet['id'] - g = SHARED.wallets.get(wid) - expect(g).to be_correct_and_respond 200 - - l = SHARED.wallets.list - expect(l).to be_correct_and_respond 200 - - expect(WalletFactory.delete(:shared, wid)).to be_correct_and_respond 204 - end - - it 'I can create, get and delete wallet from pub key getting acc_xpub from cardano-address' do - m24 = CW.utils.mnemonic_sentence(24) - acc_ix = '0H' - acc_xpub = cardano_address_get_acc_xpub(m24, "1854H/1815H/#{acc_ix}") - - payment_script_template = { 'cosigners' => - { 'cosigner#0' => acc_xpub }, - 'template' => - { 'all' => - ['cosigner#0', - { 'active_from' => 120 }] } } - - delegation_script_template = { 'cosigners' => - { 'cosigner#0' => acc_xpub }, - 'template' => - { 'all' => - ['cosigner#0', - 'cosigner#1'] } } - payload = { account_public_key: acc_xpub, - passphrase: PASS, - name: 'Shared wallet', - account_index: acc_ix, - payment_script_template: payment_script_template, - delegation_script_template: delegation_script_template } - - wallet = WalletFactory.create(:shared, payload) - expect(wallet).to be_correct_and_respond 201 - - wid = wallet['id'] - g = SHARED.wallets.get(wid) - expect(g).to be_correct_and_respond 200 - - l = SHARED.wallets.list - expect(l).to be_correct_and_respond 200 - - expect(WalletFactory.delete(:shared, wid)).to be_correct_and_respond 204 - end - - it 'Cannot create wallet with different acc xpub - derived from different mnemonic sentence' do - m24 = CW.utils.mnemonic_sentence(24) - acc_ix = '0H' - acc_xpub_wrong = cardano_address_get_acc_xpub(CW.utils.mnemonic_sentence(24), - '1854H/1815H/0H') - - payment_script_template = { 'cosigners' => - { 'cosigner#0' => acc_xpub_wrong }, - 'template' => - { 'all' => - ['cosigner#0'] } } - - delegation_script_template = { 'cosigners' => - { 'cosigner#0' => acc_xpub_wrong }, - 'template' => - { 'all' => - ['cosigner#0', - 'cosigner#1'] } } - payload = { mnemonic_sentence: m24, - passphrase: PASS, - name: 'Shared wallet', - account_index: acc_ix, - payment_script_template: payment_script_template, - delegation_script_template: delegation_script_template } - - size = SHARED.wallets.list.size - wallet = SHARED.wallets.create(payload) - expect(wallet).to be_correct_and_respond 403 - - l = SHARED.wallets.list - expect(l).to be_correct_and_respond 200 - expect(l.size).to be size - end - - it 'Cannot create wallet with different acc xpub - derived from different acc ix' do - m24 = CW.utils.mnemonic_sentence(24) - acc_ix = '0H' - acc_xpub_wrong = cardano_address_get_acc_xpub(m24, '1854H/1815H/255H') - - payment_script_template = { 'cosigners' => - { 'cosigner#0' => acc_xpub_wrong }, - 'template' => - { 'all' => - ['cosigner#0'] } } - - delegation_script_template = { 'cosigners' => - { 'cosigner#0' => acc_xpub_wrong }, - 'template' => - { 'all' => - ['cosigner#0', - 'cosigner#1'] } } - payload = { mnemonic_sentence: m24, - passphrase: PASS, - name: 'Shared wallet', - account_index: acc_ix, - payment_script_template: payment_script_template, - delegation_script_template: delegation_script_template } - - size = SHARED.wallets.list.size - wallet = SHARED.wallets.create(payload) - expect(wallet).to be_correct_and_respond 403 - - l = SHARED.wallets.list - expect(l).to be_correct_and_respond 200 - expect(l.size).to be size - end - - it 'I can create incomplete wallet and update cosigners with acc_xpub from cardano-address' do - m24 = CW.utils.mnemonic_sentence(24) - acc_xpub = cardano_address_get_acc_xpub(m24, '1854H/1815H/0H') - incomplete_wid = create_incomplete_shared_wallet(m24, '0H', acc_xpub) - addr = SHARED.addresses.list(incomplete_wid) - expect(addr).to be_correct_and_respond 200 - expect(addr.size).to eq 0 - - acc_xpub_upd = cardano_address_get_acc_xpub(CW.utils.mnemonic_sentence(24), - '1854H/1815H/0H') - - update_payment = SHARED.wallets.update_payment_script(incomplete_wid, - 'cosigner#1', - acc_xpub_upd) - - expect(update_payment).to be_correct_and_respond 200 - expect(SHARED.wallets.get(incomplete_wid)['state']['status']).to eq 'incomplete' - expect(SHARED.wallets.get(incomplete_wid)).to be_correct_and_respond 200 - addr = SHARED.addresses.list(incomplete_wid) - expect(addr).to be_correct_and_respond 200 - expect(addr.size).to eq 0 - - update_delegation = SHARED.wallets.update_delegation_script(incomplete_wid, - 'cosigner#1', - acc_xpub_upd) - - expect(update_delegation).to be_correct_and_respond 200 - eventually "The wallet is no longer 'incomplete'" do - SHARED.wallets.get(incomplete_wid)['state']['status'] != 'incomplete' - end - expect(SHARED.wallets.list).to be_correct_and_respond 200 - addr = SHARED.addresses.list(incomplete_wid) - expect(addr).to be_correct_and_respond 200 - expect(addr.size).to eq 20 - end - - it 'Create / update partially / get / list / delete' do - m24 = CW.utils.mnemonic_sentence(24) - acc_xpub = cardano_address_get_acc_xpub(m24, '1854H/1815H/0H') - incomplete_wid = create_incomplete_shared_wallet(m24, '0H', acc_xpub) - - acc_xpub_upd = cardano_address_get_acc_xpub(CW.utils.mnemonic_sentence(24), - '1854H/1815H/0H') - - update_payment = SHARED.wallets.update_payment_script(incomplete_wid, - 'cosigner#1', - acc_xpub_upd) - - expect(update_payment).to be_correct_and_respond 200 - - expect(SHARED.wallets.get(incomplete_wid)).to be_correct_and_respond 200 - expect(SHARED.wallets.get(incomplete_wid)['state']['status']).to eq 'incomplete' - - expect(SHARED.wallets.list).to be_correct_and_respond 200 - - expect(WalletFactory.delete(:shared, incomplete_wid)).to be_correct_and_respond 204 - end - - it 'Cannot update main cosigner' do - m24 = CW.utils.mnemonic_sentence(24) - acc_xpub = cardano_address_get_acc_xpub(m24, '1854H/1815H/0H') - incomplete_wid = create_incomplete_shared_wallet(m24, '0H', acc_xpub) - acc_xpub_upd = cardano_address_get_acc_xpub(CW.utils.mnemonic_sentence(24), - '1854H/1815H/0H') - - update_payment = SHARED.wallets.update_payment_script(incomplete_wid, - 'cosigner#0', - acc_xpub_upd) - - expect(update_payment).to be_correct_and_respond 403 - - update_delegation = SHARED.wallets.update_delegation_script(incomplete_wid, - 'cosigner#0', - acc_xpub_upd) - - expect(update_delegation).to be_correct_and_respond 403 - end - - it "Cannot update cosigner with main cosigner's xpub" do - m24 = CW.utils.mnemonic_sentence(24) - acc_xpub = cardano_address_get_acc_xpub(m24, '1854H/1815H/0H') - incomplete_wid = create_incomplete_shared_wallet(m24, '0H', acc_xpub) - - update_payment = SHARED.wallets.update_payment_script(incomplete_wid, - 'cosigner#1', - acc_xpub) - - expect(update_payment).to be_correct_and_respond 403 - - update_delegation = SHARED.wallets.update_delegation_script(incomplete_wid, - 'cosigner#1', - acc_xpub) - - expect(update_delegation).to be_correct_and_respond 403 - end - - it "I can create/get/list/delete wallet using cosigner: 'self' - from mnemonics" do - m24 = CW.utils.mnemonic_sentence(24) - acc_ix = '0H' - script_template = { 'cosigners' => - { 'cosigner#0' => 'self' }, - 'template' => - { 'all' => - ['cosigner#0'] } } - - payload = { mnemonic_sentence: m24, - passphrase: PASS, - name: 'Shared wallet', - account_index: acc_ix, - payment_script_template: script_template, - delegation_script_template: script_template } - - wallet = WalletFactory.create(:shared, payload) - expect(wallet).to be_correct_and_respond 201 - expect(wallet['state']['status']).to eq 'syncing' - - wid = wallet['id'] - g = SHARED.wallets.get(wid) - expect(g).to be_correct_and_respond 200 - - l = SHARED.wallets.list - expect(l).to be_correct_and_respond 200 - expect(l.to_s).to include wid - - expect(WalletFactory.delete(:shared, wid)).to be_correct_and_respond 204 - end - - it "I can create/get/list/delete wallet using cosigner: 'self' - from pub key" do - m24 = CW.utils.mnemonic_sentence(24) - acc_ix = '0H' - acc_xpub = cardano_address_get_acc_xpub(m24, "1854H/1815H/#{acc_ix}") - payment_script_template = { 'cosigners' => - { 'cosigner#0' => 'self' }, - 'template' => - { 'all' => - ['cosigner#0', - { 'active_from' => 120 }] } } - - delegation_script_template = { 'cosigners' => - { 'cosigner#0' => 'self' }, - 'template' => - { 'all' => - ['cosigner#0', - 'cosigner#1'] } } - payload = { account_public_key: acc_xpub, - passphrase: PASS, - name: 'Shared wallet', - account_index: acc_ix, - payment_script_template: payment_script_template, - delegation_script_template: delegation_script_template } - - wallet = WalletFactory.create(:shared, payload) - expect(wallet).to be_correct_and_respond 201 - expect(wallet['state']['status']).to eq 'incomplete' - - wid = wallet['id'] - g = SHARED.wallets.get(wid) - expect(g).to be_correct_and_respond 200 - - l = SHARED.wallets.list - expect(l).to be_correct_and_respond 200 - expect(l.to_s).to include wid - - expect(WalletFactory.delete(:shared, wid)).to be_correct_and_respond 204 - end - - describe 'Wallet id' do - it 'Shared walletid with only spending template from cardano-addresses' do - mnemonics = CW.utils.mnemonic_sentence(24) - acc_ix = '0H' - script_template = { 'cosigners' => { 'cosigner#0' => 'self' }, - 'template' => - { 'all' => - ['cosigner#0', - { 'active_from' => 120 }] } } - - payload = { mnemonic_sentence: mnemonics, - passphrase: PASS, - name: 'Shared wallet', - account_index: acc_ix, - payment_script_template: script_template } - - wallet = WalletFactory.create(:shared, payload) - expect(wallet).to be_correct_and_respond 201 - wid = wallet['id'] - - # based on acct prv key - template = '--spending "all [cosigner#0, active_from 120]"' - root_xsk = CA.prv_key_from_recovery_phrase(mnemonics, 'Shared') - acct_key = CA.key_child(root_xsk, "1854H/1815H/#{acc_ix}") - ca_wid_acct_key = CA.key_walletid(acct_key, template) - - # based on pub key from acct prv key - pub_key = CA.key_public(acct_key, with_chain_code: true) - ca_wid_pub_key = CA.key_walletid(pub_key, template) - - # wallet id from cardano-wallet is the same - expect(ca_wid_acct_key).to eq ca_wid_pub_key - expect(wid).to eq ca_wid_acct_key - end - - it 'Shared walletid with spending and delegation template from cardano-addresses' do - mnemonics = CW.utils.mnemonic_sentence(24) - acc_ix = '0H' - script_template = { 'cosigners' => { 'cosigner#0' => 'self' }, - 'template' => - { 'all' => - ['cosigner#0', - { 'active_from' => 120 }] } } - - delegation_template = { 'cosigners' => { 'cosigner#1' => 'self' }, - 'template' => - { 'any' => - ['cosigner#0', - 'cosigner#1'] } } - - payload = { mnemonic_sentence: mnemonics, - passphrase: PASS, - name: 'Shared wallet', - account_index: acc_ix, - payment_script_template: script_template, - delegation_script_template: delegation_template } - - wallet = WalletFactory.create(:shared, payload) - expect(wallet).to be_correct_and_respond 201 - wid = wallet['id'] - - # based on acct prv key - template = '--spending "all [cosigner#0, active_from 120]" --staking "any [cosigner#0, cosigner#1]"' - root_xsk = CA.prv_key_from_recovery_phrase(mnemonics, 'Shared') - acct_key = CA.key_child(root_xsk, "1854H/1815H/#{acc_ix}") - ca_wid_acct_key = CA.key_walletid(acct_key, template) - - # based on pub key from acct prv key - pub_key = CA.key_public(acct_key, with_chain_code: true) - ca_wid_pub_key = CA.key_walletid(pub_key, template) - - # wallet id from cardano-wallet is the same - expect(ca_wid_acct_key).to eq ca_wid_pub_key - expect(wid).to eq ca_wid_acct_key - end - end - end - - describe 'UTxOs' do - it 'Can see utxo' do - id = create_active_shared_wallet(CW.utils.mnemonic_sentence(24), '0H', 'self') - utxo = SHARED.wallets.utxo(id) - expect(utxo).to be_correct_and_respond 200 - end - - it 'Can see utxo snapshot' do - id = create_active_shared_wallet(CW.utils.mnemonic_sentence(24), '0H', 'self') - utxo = SHARED.wallets.utxo_snapshot(id) - expect(utxo).to be_correct_and_respond 200 - end - end - - describe 'Addresses' do - it 'Can list addresses on active shared wallet - from pub key' do - m24 = CW.utils.mnemonic_sentence(24) - acc_ix = '0H' - acc_xpub = cardano_address_get_acc_xpub(m24, "1854H/1815H/#{acc_ix}") - active_wid = create_active_shared_wallet(acc_xpub, acc_ix, 'self') - - a = SHARED.addresses.list(active_wid) - expect(a).to be_correct_and_respond 200 - expect(a.size).to be 20 - - a = SHARED.addresses.list(active_wid, { state: 'used' }) - expect(a).to be_correct_and_respond 200 - expect(a.size).to be 0 - - a = SHARED.addresses.list(active_wid, { state: 'unused' }) - expect(a).to be_correct_and_respond 200 - expect(a.size).to be 20 - end - - it 'Can list addresses on active shared wallet - from mnemonics' do - m24 = CW.utils.mnemonic_sentence(24) - active_wid = create_active_shared_wallet(m24, '0H', 'self') - - a = SHARED.addresses.list(active_wid) - expect(a).to be_correct_and_respond 200 - expect(a.size).to be 20 - - a = SHARED.addresses.list(active_wid, { state: 'used' }) - expect(a).to be_correct_and_respond 200 - expect(a.size).to be 0 - - a = SHARED.addresses.list(active_wid, { state: 'unused' }) - expect(a).to be_correct_and_respond 200 - expect(a.size).to be 20 - end - - it 'Lists empty addresses on incomplete shared wallet - from pub key' do - m24 = CW.utils.mnemonic_sentence(24) - acc_ix = '0H' - acc_xpub = cardano_address_get_acc_xpub(m24, "1854H/1815H/#{acc_ix}") - incomplete_wid = create_incomplete_shared_wallet(acc_xpub, acc_ix, 'self') - - a = SHARED.addresses.list(incomplete_wid) - expect(a).to be_correct_and_respond 200 - expect(a.size).to be 0 - - a = SHARED.addresses.list(incomplete_wid, { state: 'used' }) - expect(a).to be_correct_and_respond 200 - expect(a.size).to be 0 - - a = SHARED.addresses.list(incomplete_wid, { state: 'unused' }) - expect(a).to be_correct_and_respond 200 - expect(a.size).to be 0 - - acc_xpub = cardano_address_get_acc_xpub(CW.utils.mnemonic_sentence(24), '1854H/1815H/0H') - patch_incomplete_shared_wallet(incomplete_wid, - { 'cosigner#1' => acc_xpub }, - { 'cosigner#1' => acc_xpub }) - - a = SHARED.addresses.list(incomplete_wid) - expect(a).to be_correct_and_respond 200 - expect(a.size).to be 20 - - a = SHARED.addresses.list(incomplete_wid, { state: 'used' }) - expect(a).to be_correct_and_respond 200 - expect(a.size).to be 0 - - a = SHARED.addresses.list(incomplete_wid, { state: 'unused' }) - expect(a).to be_correct_and_respond 200 - expect(a.size).to be 20 - end - - it 'Lists empty addresses on incomplete shared wallet - from mnemonics' do - m24 = CW.utils.mnemonic_sentence(24) - incomplete_wid = create_incomplete_shared_wallet(m24, '0H', 'self') - - a = SHARED.addresses.list(incomplete_wid) - expect(a).to be_correct_and_respond 200 - expect(a.size).to be 0 - - a = SHARED.addresses.list(incomplete_wid, { state: 'used' }) - expect(a).to be_correct_and_respond 200 - expect(a.size).to be 0 - - a = SHARED.addresses.list(incomplete_wid, { state: 'unused' }) - expect(a).to be_correct_and_respond 200 - expect(a.size).to be 0 - - acc_xpub = cardano_address_get_acc_xpub(CW.utils.mnemonic_sentence(24), '1854H/1815H/0H') - patch_incomplete_shared_wallet(incomplete_wid, - { 'cosigner#1' => acc_xpub }, - { 'cosigner#1' => acc_xpub }) - - a = SHARED.addresses.list(incomplete_wid) - expect(a).to be_correct_and_respond 200 - expect(a.size).to be 20 - - a = SHARED.addresses.list(incomplete_wid, { state: 'used' }) - expect(a).to be_correct_and_respond 200 - expect(a.size).to be 0 - - a = SHARED.addresses.list(incomplete_wid, { state: 'unused' }) - expect(a).to be_correct_and_respond 200 - expect(a.size).to be 20 - end - end - - describe 'Public Keys' do - matrix = { - 'utxo_internal' => 'addr_shared_vk', - 'utxo_external' => 'addr_shared_vk', - 'mutable_account' => 'stake_shared_vk' - } - matrix_h = { - 'utxo_internal' => 'addr_shared_vkh', - 'utxo_external' => 'addr_shared_vkh', - 'mutable_account' => 'stake_shared_vkh' - } - - it 'Get public key - incomplete wallet from mnemonics' do - m24 = CW.utils.mnemonic_sentence(24) - acc_xpub = cardano_address_get_acc_xpub(m24, '1854H/1815H/0H') - incomplete_wid = create_incomplete_shared_wallet(m24, '0H', acc_xpub) - - matrix.each do |role, addr_prefix| - id = [*0..100_000].sample - res = SHARED.keys.get_public_key(incomplete_wid, role, id) - expect(res).to be_correct_and_respond 200 - expect(res.to_s).to include addr_prefix - end - - matrix_h.each do |role, addr_prefix| - id = [*0..100_000].sample - res = SHARED.keys.get_public_key(incomplete_wid, role, id, { hash: true }) - expect(res).to be_correct_and_respond 200 - expect(res.to_s).to include addr_prefix - end - end - - it 'Get public key - incomplete wallet from acc pub key' do - m24 = CW.utils.mnemonic_sentence(24) - acc_ix = '0H' - acc_xpub = cardano_address_get_acc_xpub(m24, "1854H/1815H/#{acc_ix}") - incomplete_wid = create_incomplete_shared_wallet(acc_xpub, acc_ix, acc_xpub) - - matrix.each do |role, addr_prefix| - id = [*0..100_000].sample - res = SHARED.keys.get_public_key(incomplete_wid, role, id) - expect(res).to be_correct_and_respond 200 - expect(res.to_s).to include addr_prefix - end - - matrix_h.each do |role, addr_prefix| - id = [*0..100_000].sample - res = SHARED.keys.get_public_key(incomplete_wid, role, id, { hash: true }) - expect(res).to be_correct_and_respond 200 - expect(res.to_s).to include addr_prefix - end - end - - it 'Get public key - active wallet from mnemonics' do - m24 = CW.utils.mnemonic_sentence(24) - active_wid = create_incomplete_shared_wallet(m24, '11H', 'self') - - matrix.each do |role, addr_prefix| - id = [*0..100_000].sample - res = SHARED.keys.get_public_key(active_wid, role, id) - expect(res).to be_correct_and_respond 200 - expect(res.to_s).to include addr_prefix - end - - matrix_h.each do |role, addr_prefix| - id = [*0..100_000].sample - res = SHARED.keys.get_public_key(active_wid, role, id, { hash: true }) - expect(res).to be_correct_and_respond 200 - expect(res.to_s).to include addr_prefix - end - end - - it 'Get public key - active wallet from acc pub key' do - m24 = CW.utils.mnemonic_sentence(24) - acc_ix = '0H' - acc_xpub = cardano_address_get_acc_xpub(m24, "1854H/1815H/#{acc_ix}") - active_wid = create_active_shared_wallet(acc_xpub, acc_ix, 'self') - - matrix.each do |role, addr_prefix| - id = [*0..100_000].sample - res = SHARED.keys.get_public_key(active_wid, role, id) - expect(res).to be_correct_and_respond 200 - expect(res.to_s).to include addr_prefix - end - - matrix_h.each do |role, addr_prefix| - id = [*0..100_000].sample - res = SHARED.keys.get_public_key(active_wid, role, id, { hash: true }) - expect(res).to be_correct_and_respond 200 - expect(res.to_s).to include addr_prefix - end - end - end - - describe 'Account Public Keys' do - it 'Create account public key - incomplete wallet from mnemonics' do - m24 = CW.utils.mnemonic_sentence(24) - der_path = '1854H/1815H/0H' - acc_xpub = cardano_address_get_acc_xpub(m24, der_path) - incomplete_wid = create_incomplete_shared_wallet(m24, '0H', acc_xpub) - %w[0H 1H 2147483647H 44H].each do |index| - payload = { passphrase: PASS, format: 'extended' } - res = SHARED.keys.create_acc_public_key(incomplete_wid, index, payload) - expect(res).to be_correct_and_respond 202 - expect(res.to_s).to include cardano_address_get_acc_xpub(m24, - "1854H/1815H/#{index}", - 'Shared', - '--with-chain-code', - hex: false) - - payload = { passphrase: PASS, format: 'non_extended' } - res = SHARED.keys.create_acc_public_key(incomplete_wid, index, payload) - expect(res).to be_correct_and_respond 202 - expect(res.to_s).to include cardano_address_get_acc_xpub(m24, - "1854H/1815H/#{index}", - 'Shared', - '--without-chain-code', - hex: false) - end - end - - it 'Cannot create account public key - incomplete wallet from acc pub key' do - m24 = CW.utils.mnemonic_sentence(24) - acc_ix = '0H' - acc_xpub = cardano_address_get_acc_xpub(m24, "1854H/1815H/#{acc_ix}") - incomplete_wid = create_incomplete_shared_wallet(acc_xpub, acc_ix, 'self') - %w[0H 1H 2147483647H 44H].each do |index| - res = SHARED.keys.create_acc_public_key(incomplete_wid, index, { passphrase: PASS, format: 'extended' }) - expect(res).to be_correct_and_respond 403 - expect(res.to_s).to include 'no_root_key' - - res = SHARED.keys.create_acc_public_key(incomplete_wid, index, { passphrase: PASS, format: 'non_extended' }) - expect(res).to be_correct_and_respond 403 - expect(res.to_s).to include 'no_root_key' - end - end - - it 'Create account public key - active wallet from mnemonics' do - m24 = CW.utils.mnemonic_sentence(24) - acc_xpub = cardano_address_get_acc_xpub(m24, '1854H/1815H/0H') - active_wid = create_active_shared_wallet(m24, '0H', acc_xpub) - %w[0H 1H 2147483647H 44H].each do |index| - res = SHARED.keys.create_acc_public_key(active_wid, index, { passphrase: PASS, format: 'extended' }) - expect(res).to be_correct_and_respond 202 - expect(res.to_s).to include cardano_address_get_acc_xpub(m24, - "1854H/1815H/#{index}", - 'Shared', - '--with-chain-code', - hex: false) - - res = SHARED.keys.create_acc_public_key(active_wid, index, { passphrase: PASS, format: 'non_extended' }) - expect(res).to be_correct_and_respond 202 - expect(res.to_s).to include cardano_address_get_acc_xpub(m24, - "1854H/1815H/#{index}", - 'Shared', - '--without-chain-code', - hex: false) - end - end - - it 'Cannot create account public key - active wallet from acc pub key' do - m24 = CW.utils.mnemonic_sentence(24) - acc_ix = '0H' - acc_xpub = cardano_address_get_acc_xpub(m24, "1854H/1815H/#{acc_ix}") - active_wid = create_active_shared_wallet(acc_xpub, acc_ix, 'self') - %w[0H 1H 2147483647H 44H].each do |index| - res = SHARED.keys.create_acc_public_key(active_wid, index, { passphrase: PASS, format: 'extended' }) - expect(res).to be_correct_and_respond 403 - expect(res.to_s).to include 'no_root_key' - - res = SHARED.keys.create_acc_public_key(active_wid, index, { passphrase: PASS, format: 'non_extended' }) - expect(res).to be_correct_and_respond 403 - expect(res.to_s).to include 'no_root_key' - end - end - - it 'Get account public key - active wallet from mnemonics' do - m24 = CW.utils.mnemonic_sentence(24) - acc_xpub = cardano_address_get_acc_xpub(m24, '1854H/1815H/0H') - active_wid = create_active_shared_wallet(m24, '0H', acc_xpub) - - res = SHARED.keys.get_acc_public_key(active_wid) - expect(res).to be_correct_and_respond 200 - expect(res.to_s).to include 'acct_shared_vk' - - res = SHARED.keys.get_acc_public_key(active_wid, { format: 'extended' }) - expect(res).to be_correct_and_respond 200 - expect(res.to_s).to include 'acct_shared_xvk' - - res = SHARED.keys.get_acc_public_key(active_wid, { format: 'non_extended' }) - expect(res).to be_correct_and_respond 200 - expect(res.to_s).to include 'acct_shared_vk' - end - - it 'Get account public key - active wallet from acc pub key' do - m24 = CW.utils.mnemonic_sentence(24) - acc_ix = '0H' - acc_xpub = cardano_address_get_acc_xpub(m24, "1854H/1815H/#{acc_ix}") - active_wid = create_active_shared_wallet(acc_xpub, acc_ix, 'self') - - res = SHARED.keys.get_acc_public_key(active_wid) - expect(res).to be_correct_and_respond 200 - expect(res.to_s).to include 'acct_shared_vk' - - res = SHARED.keys.get_acc_public_key(active_wid, { format: 'extended' }) - expect(res).to be_correct_and_respond 200 - expect(res.to_s).to include 'acct_shared_xvk' - - res = SHARED.keys.get_acc_public_key(active_wid, { format: 'non_extended' }) - expect(res).to be_correct_and_respond 200 - expect(res.to_s).to include 'acct_shared_vk' - end - - it 'Get account public key - incomplete wallet from mnemonics' do - m24 = CW.utils.mnemonic_sentence(24) - acc_xpub = cardano_address_get_acc_xpub(m24, '1854H/1815H/0H') - incomplete_wid = create_incomplete_shared_wallet(m24, '0H', acc_xpub) - - res = SHARED.keys.get_acc_public_key(incomplete_wid) - expect(res).to be_correct_and_respond 200 - expect(res.to_s).to include 'acct_shared_vk' - - res = SHARED.keys.get_acc_public_key(incomplete_wid, { format: 'extended' }) - expect(res).to be_correct_and_respond 200 - expect(res.to_s).to include 'acct_shared_xvk' - - res = SHARED.keys.get_acc_public_key(incomplete_wid, { format: 'non_extended' }) - expect(res).to be_correct_and_respond 200 - expect(res.to_s).to include 'acct_shared_vk' - end - - it 'Get account public key - incomplete wallet from acc pub key' do - m24 = CW.utils.mnemonic_sentence(24) - acc_ix = '0H' - acc_xpub = cardano_address_get_acc_xpub(m24, "1854H/1815H/#{acc_ix}") - incomplete_wid = create_incomplete_shared_wallet(acc_xpub, acc_ix, 'self') - - res = SHARED.keys.get_acc_public_key(incomplete_wid) - expect(res).to be_correct_and_respond 200 - expect(res.to_s).to include 'acct_shared_vk' - - res = SHARED.keys.get_acc_public_key(incomplete_wid, { format: 'extended' }) - expect(res).to be_correct_and_respond 200 - expect(res.to_s).to include 'acct_shared_xvk' - - res = SHARED.keys.get_acc_public_key(incomplete_wid, { format: 'non_extended' }) - expect(res).to be_correct_and_respond 200 - expect(res.to_s).to include 'acct_shared_vk' - end - end - end - - describe CardanoWallet::Shared::Transactions do - it 'I could get a tx if I had proper id' do - wid = create_active_shared_wallet(CW.utils.mnemonic_sentence(24), '0H', 'self') - txs = SHARED.transactions - g = txs.get(wid, TXID) - expect(g).to be_correct_and_respond 404 - expect(g.to_s).to include 'no_such_transaction' - end - - it 'Can list transactions' do - id = create_active_shared_wallet(CW.utils.mnemonic_sentence(24), '0H', 'self') - txs = SHARED.transactions - expect(txs.list(id)).to be_correct_and_respond 200 - expect(txs.list(id, { max_count: 1 })).to be_correct_and_respond 200 - expect(txs.list(id, { start: '2012-09-25T10:15:00Z', - end: '2016-11-21T10:15:00Z', - order: 'ascending', - max_count: 10 })).to be_correct_and_respond 200 - expect(txs.list(id, { order: 'bad_order' })).to be_correct_and_respond 400 - expect(txs.list(id, { max_count: 'bad_count' })).to be_correct_and_respond 400 - end - end -end diff --git a/test/e2e/spec/shelley_spec.rb b/test/e2e/spec/shelley_spec.rb deleted file mode 100644 index a2466f1e3be..00000000000 --- a/test/e2e/spec/shelley_spec.rb +++ /dev/null @@ -1,699 +0,0 @@ -# frozen_string_literal: true - -RSpec.describe CardanoWallet::Shelley, :all, :shelley do - after(:each) do - teardown - end - - describe CardanoWallet::Shelley::Wallets do - it 'I can list wallets' do - l = SHELLEY.wallets.list - expect(l).to be_correct_and_respond 200 - size = l.size - - create_shelley_wallet - l = SHELLEY.wallets.list - expect(l).to be_correct_and_respond 200 - expect(l.size).to eq(size + 1) - end - - it 'When wallet does not exist it gives 404' do - wid = create_shelley_wallet - WalletFactory.delete :shelley, wid - g = SHELLEY.wallets.get wid - expect(g).to be_correct_and_respond 404 - - d = SHELLEY.wallets.delete wid - expect(d).to be_correct_and_respond 404 - end - - describe 'Create wallets' do - it 'I can create, get and delete wallet from mnemonics' do - payload = { name: 'Wallet from mnemonic_sentence', - passphrase: 'Secure Passphrase', - mnemonic_sentence: CW.utils.mnemonic_sentence(15) } - wallet = WalletFactory.create(:shelley, payload) - expect(wallet).to be_correct_and_respond 201 - - wid = wallet['id'] - g = SHELLEY.wallets.get(wid) - expect(g).to be_correct_and_respond 200 - - expect(WalletFactory.delete(:shelley, wid)).to be_correct_and_respond 204 - end - - it 'I can create, get and delete wallet from mnemonics / second factor' do - payload = { name: 'Wallet from mnemonic_sentence', - passphrase: 'Secure Passphrase', - mnemonic_sentence: CW.utils.mnemonic_sentence(15), - mnemonic_second_factor: CW.utils.mnemonic_sentence(12) } - wallet = WalletFactory.create(:shelley, payload) - expect(wallet).to be_correct_and_respond 201 - - wid = wallet['id'] - g = SHELLEY.wallets.get(wid) - expect(g).to be_correct_and_respond 200 - expect(WalletFactory.delete(:shelley, wid)).to be_correct_and_respond 204 - end - - it 'I can set address pool gap' do - pool_gap = 55 - payload = { name: 'Wallet from mnemonic_sentence', - passphrase: 'Secure Passphrase', - mnemonic_sentence: CW.utils.mnemonic_sentence(15), - address_pool_gap: pool_gap } - wallet = WalletFactory.create(:shelley, payload) - expect(wallet).to be_correct_and_respond 201 - addr = SHELLEY.addresses.list(wallet['id']) - expect(addr).to be_correct_and_respond 200 - expect(addr.size).to eq pool_gap - end - - it 'I can create, get and delete wallet from pub key' do - payload = { name: 'Wallet from pub key', - account_public_key: 'b47546e661b6c1791452d003d375756dde6cac2250093ce4630f16b9b9c0ac87411337bda4d5bc0216462480b809824ffb48f17e08d95ab9f1b91d391e48e66b', - address_pool_gap: 20 } - wallet = WalletFactory.create(:shelley, payload) - expect(wallet).to be_correct_and_respond 201 - - wid = wallet['id'] - g = SHELLEY.wallets.get(wid) - expect(g).to be_correct_and_respond 200 - expect(WalletFactory.delete(:shelley, wid)).to be_correct_and_respond 204 - end - - describe 'Wallet id' do - it 'I can get Shelley walletid using cardano-addresses' do - mnemonics = CW.utils.mnemonic_sentence(24) - wid = create_shelley_wallet('Shelley Wallet', mnemonics) - - # based on root prv key - root_xsk = CA.prv_key_from_recovery_phrase(mnemonics, 'Shelley') - ca_wid_root_xsk = CA.key_walletid(root_xsk) - expect(wid).to eq ca_wid_root_xsk - - # based on pub key - pub_key = CA.key_public(root_xsk) - ca_wid_pub_key = CA.key_walletid(pub_key) - expect(wid).to eq ca_wid_pub_key - end - - it 'Shelley walletid is not based on acct key' do - mnemonics = CW.utils.mnemonic_sentence(24) - wid = create_shelley_wallet('Shelley Wallet', mnemonics) - - # based on acct prv key - root_xsk = CA.prv_key_from_recovery_phrase(mnemonics, 'Shelley') - acct_key = CA.key_child(root_xsk, '1852H/1815H/0H') - ca_wid_acct_key = CA.key_walletid(acct_key) - - # based on pub key from acct prv key - pub_key = CA.key_public(acct_key) - ca_wid_pub_key = CA.key_walletid(pub_key) - - # wallet id from cardano-wallet is not the same - expect(ca_wid_acct_key).to eq ca_wid_pub_key - expect(wid).not_to eq ca_wid_acct_key - end - end - end - - describe 'Update wallet' do - it 'Can update_metadata' do - new_name = 'New wallet name' - w = SHELLEY.wallets - id = create_shelley_wallet - u = w.update_metadata(id, { name: new_name }) - expect(u).to be_correct_and_respond 200 - expect(w.get(id)['name']).to eq new_name - end - - it 'Can update_passphrase' do - w = SHELLEY.wallets - id = create_shelley_wallet - upd = w.update_passphrase(id, { old_passphrase: 'Secure Passphrase', - new_passphrase: 'Securer Passphrase' }) - expect(upd).to be_correct_and_respond 204 - end - - it 'Cannot update_passphrase not knowing old pass' do - w = SHELLEY.wallets - id = create_shelley_wallet - upd = w.update_passphrase(id, { old_passphrase: 'wrong-passphrase', - new_passphrase: 'Securer Passphrase' }) - expect(upd).to be_correct_and_respond 403 - expect(upd.to_s).to include 'wrong_encryption_passphrase' - end - - it 'Can update_passphrase, mnemonics' do - w = SHELLEY.wallets - mnemonics = CW.utils.mnemonic_sentence(24) - id = create_shelley_wallet('Wallet', mnemonics) - upd = w.update_passphrase(id, { mnemonic_sentence: mnemonics, - new_passphrase: 'Securer Passphrase' }) - expect(upd).to be_correct_and_respond 204 - end - - it 'Can update_passphrase, mnemonics, mnemonic_second_factor' do - w = SHELLEY.wallets - mnemonics = CW.utils.mnemonic_sentence(24) - mnemonic_second_factor = CW.utils.mnemonic_sentence(12) - id = create_shelley_wallet('Wallet', mnemonics, mnemonic_second_factor) - upd = w.update_passphrase(id, { mnemonic_sentence: mnemonics, - mnemonic_second_factor: mnemonic_second_factor, - new_passphrase: 'Securer Passphrase' }) - expect(upd).to be_correct_and_respond 204 - end - - it 'Cannot update_passphrase with wrong mnemonics' do - w = SHELLEY.wallets - mnemonics = CW.utils.mnemonic_sentence(24) - wrong_mnemonics = CW.utils.mnemonic_sentence(24) - id = create_shelley_wallet('Wallet', mnemonics) - upd = w.update_passphrase(id, { mnemonic_sentence: wrong_mnemonics, - new_passphrase: 'Securer Passphrase' }) - expect(upd).to be_correct_and_respond 403 - expect(upd.to_s).to include 'wrong_mnemonic' - end - - it 'Cannot update_passphrase with wrong mnemonic_second_factor' do - w = SHELLEY.wallets - mnemonics = CW.utils.mnemonic_sentence(24) - mnemonic_second_factor = CW.utils.mnemonic_sentence(12) - wrong_mnemonic_second_factor = CW.utils.mnemonic_sentence(12) - id = create_shelley_wallet('Wallet', mnemonics, mnemonic_second_factor) - upd = w.update_passphrase(id, { mnemonic_sentence: mnemonics, - mnemonic_second_factor: wrong_mnemonic_second_factor, - new_passphrase: 'Securer Passphrase' }) - expect(upd).to be_correct_and_respond 403 - expect(upd.to_s).to include 'wrong_mnemonic' - end - - it 'Cannot update_passphrase of wallet from pub key' do - payload = { name: 'Wallet from pub key', - account_public_key: 'b47546e661b6c1791452d003d375756dde6cac2250093ce4630f16b9b9c0ac87411337bda4d5bc0216462480b809824ffb48f17e08d95ab9f1b91d391e48e66b', - address_pool_gap: 20 } - wallet = WalletFactory.create(:shelley, payload) - expect(wallet).to be_correct_and_respond 201 - - wid = wallet['id'] - upd = SHELLEY.wallets.update_passphrase(wid, { old_passphrase: 'Secure Passphrase', - new_passphrase: 'Securer Passphrase' }) - expect(upd).to be_correct_and_respond 403 - expect(upd.to_s).to include 'no_root_key' - end - - it 'Can update_passphrase of wallet from pub key using mnemonics from which pub key is derived' do - mnemonics = CW.utils.mnemonic_sentence(24) - root_xsk = CA.prv_key_from_recovery_phrase(mnemonics, 'Shelley') - acct_key = CA.key_child(root_xsk, '1852H/1815H/0H') - pub_key = CA.key_public(acct_key) - acc_pub_key_base16 = bech32_to_base16(pub_key) - - payload = { name: 'Wallet from pub key', - account_public_key: acc_pub_key_base16, - address_pool_gap: 20 } - wallet = WalletFactory.create(:shelley, payload) - expect(wallet).to be_correct_and_respond 201 - - wid = wallet['id'] - - # I can update passphrase using mnemonics - upd = SHELLEY.wallets.update_passphrase(wid, { mnemonic_sentence: mnemonics, - new_passphrase: 'Secure Passphrase' }) - expect(upd).to be_correct_and_respond 204 - - # Once password is set I can perform passphrase-protected operations, - # like update passphrase using old passprase - upd2 = SHELLEY.wallets.update_passphrase(wid, { old_passphrase: 'Secure Passphrase', - new_passphrase: 'Securer Passphrase' }) - expect(upd2).to be_correct_and_respond 204 - end - - it 'Cannot update_passphrase of wallet from pub key using wrong mnemonics' do - mnemonics = CW.utils.mnemonic_sentence(24) - root_xsk = CA.prv_key_from_recovery_phrase(mnemonics, 'Shelley') - acct_key = CA.key_child(root_xsk, '1852H/1815H/0H') - pub_key = CA.key_public(acct_key) - acc_pub_key_base16 = bech32_to_base16(pub_key) - - payload = { name: 'Wallet from pub key', - account_public_key: acc_pub_key_base16, - address_pool_gap: 20 } - wallet = WalletFactory.create(:shelley, payload) - expect(wallet).to be_correct_and_respond 201 - - wid = wallet['id'] - wrong_mnemonics = CW.utils.mnemonic_sentence(24) - upd = SHELLEY.wallets.update_passphrase(wid, { mnemonic_sentence: wrong_mnemonics, - new_passphrase: 'Securer Passphrase' }) - expect(upd).to be_correct_and_respond 403 - expect(upd.to_s).to include 'wrong_mnemonic' - end - end - - it 'Can see utxo' do - id = create_shelley_wallet - utxo = SHELLEY.wallets.utxo(id) - expect(utxo).to be_correct_and_respond 200 - end - - it 'Can see utxo snapshot' do - id = create_shelley_wallet - utxo = SHELLEY.wallets.utxo_snapshot(id) - expect(utxo).to be_correct_and_respond 200 - end - end - - describe CardanoWallet::Shelley::Addresses do - it 'Can list addresses' do - id = create_shelley_wallet - shelley_addr = SHELLEY.addresses - addresses = shelley_addr.list id - expect(addresses).to be_correct_and_respond 200 - expect(addresses.size).to eq 20 - addresses.each_with_index do |a, i| - expect(a['derivation_path']).to eq ['1852H', '1815H', '0H', '0', i.to_s] - end - - addresses_unused = shelley_addr.list id, { state: 'used' } - expect(addresses_unused).to be_correct_and_respond 200 - expect(addresses_unused.size).to eq 0 - - addresses_unused = shelley_addr.list id, { state: 'unused' } - expect(addresses_unused).to be_correct_and_respond 200 - expect(addresses_unused.size).to eq 20 - addresses_unused.each_with_index do |a, i| - expect(a['derivation_path']).to eq ['1852H', '1815H', '0H', '0', i.to_s] - end - end - end - - describe CardanoWallet::Shelley::CoinSelections do - it 'I could trigger random coin selection - if had money' do - wid = create_shelley_wallet - addresses = SHELLEY.addresses.list(wid) - addr_amount = [ - { addresses[0]['id'] => MIN_UTXO_VALUE_PURE_ADA }, - { addresses[1]['id'] => MIN_UTXO_VALUE_PURE_ADA } - ] - - rnd = SHELLEY.coin_selections.random wid, addr_amount - expect(rnd).to be_correct_and_respond 403 - expect(rnd.to_s).to include 'no_utxos_available' - end - end - - describe CardanoWallet::Shelley::Transactions do - it 'I could get a tx if I had proper id' do - wid = create_shelley_wallet - txs = SHELLEY.transactions - g = txs.get(wid, TXID) - expect(g).to be_correct_and_respond 404 - expect(g.to_s).to include 'no_such_transaction' - end - - it 'Can list transactions' do - id = create_shelley_wallet - txs = SHELLEY.transactions - expect(txs.list(id)).to be_correct_and_respond 200 - expect(txs.list(id, { max_count: 1 })).to be_correct_and_respond 200 - expect(txs.list(id, { start: '2012-09-25T10:15:00Z', - end: '2016-11-21T10:15:00Z', - order: 'ascending', - max_count: 10 })).to be_correct_and_respond 200 - expect(txs.list(id, { order: 'bad_order' })).to be_correct_and_respond 400 - expect(txs.list(id, { max_count: 'bad_count' })).to be_correct_and_respond 400 - end - - it 'I could create transaction - if I had money' do - id = create_shelley_wallet - target_id = create_shelley_wallet - address = SHELLEY.addresses.list(target_id)[0]['id'] - txs = SHELLEY.transactions - amt = [{ address => 1_000_000 }] - - tx_sent = txs.create(id, PASS, amt) - expect(tx_sent).to be_correct_and_respond 403 - expect(tx_sent.to_s).to include 'no_utxos_available' - end - - it 'I could create transaction using rewards - if I had money' do - id = create_shelley_wallet - target_id = create_shelley_wallet - address = SHELLEY.addresses.list(target_id)[0]['id'] - txs = SHELLEY.transactions - amt = [{ address => 1_000_000 }] - - tx_sent = txs.create(id, PASS, amt, 'self') - expect(tx_sent).to be_correct_and_respond 403 - expect(tx_sent.to_s).to include 'no_utxos_available' - end - - it 'I could estimate transaction fee - if I had money' do - id = create_shelley_wallet - target_id = create_shelley_wallet - address = SHELLEY.addresses.list(target_id)[0]['id'] - amt = [{ address => 1_000_000 }] - - txs = SHELLEY.transactions - - fees = txs.payment_fees(id, amt) - expect(fees).to be_correct_and_respond 403 - expect(fees.to_s).to include 'no_utxos_available' - - fees = txs.payment_fees(id, amt, 'self') - expect(fees).to be_correct_and_respond 403 - expect(fees.to_s).to include 'no_utxos_available' - - metadata = { '0' => { 'string' => 'cardano' }, - '1' => { 'int' => 14 }, - '2' => { 'bytes' => '2512a00e9653fe49a44a5886202e24d77eeb998f' }, - '3' => { 'list' => [{ 'int' => 14 }, { 'int' => 42 }, { 'string' => '1337' }] }, - '4' => { 'map' => [{ 'k' => { 'string' => 'key' }, 'v' => { 'string' => 'value' } }, - { 'k' => { 'int' => 14 }, 'v' => { 'int' => 42 } }] } } - - fees = txs.payment_fees(id, amt, 'self', metadata) - expect(fees).to be_correct_and_respond 403 - expect(fees.to_s).to include 'no_utxos_available' - end - - it 'I could forget transaction' do - id = create_shelley_wallet - txs = SHELLEY.transactions - res = txs.forget(id, TXID) - expect(res).to be_correct_and_respond 404 - end - end - - describe CardanoWallet::Shelley::StakePools do - after(:each) do - settings = CW.misc.settings - settings.update({ pool_metadata_source: 'none' }) - end - - it 'I can list stake keys' do - id = create_shelley_wallet - stake_keys = SHELLEY.stake_pools.list_stake_keys(id) - expect(stake_keys).to be_correct_and_respond 200 - expect(stake_keys['foreign'].size).to eq 0 - expect(stake_keys['ours'].size).to eq 1 - expect(stake_keys['ours'].first['stake']).to eq({ 'quantity' => 0, 'unit' => 'lovelace' }) - expect(stake_keys['none']['stake']).to eq({ 'quantity' => 0, 'unit' => 'lovelace' }) - expect(stake_keys['ours'].first['delegation']).to eq({ 'next' => [], - 'active' => - { 'status' => 'not_delegating' } }) - end - - describe 'ADP-634 - Pool metadata is updated when settings are updated', :offchain, :smash do - it 'pool_metadata_source = direct <> none' do - settings = CW.misc.settings - pools = SHELLEY.stake_pools - - s = settings.update({ pool_metadata_source: 'direct' }) - expect(s).to be_correct_and_respond 204 - - eventually "Pools have metadata when 'pool_metadata_source' => 'direct'" do - pools.list({ stake: 1000 }).any? { |p| p['metadata'] } - end - - s = settings.update({ pool_metadata_source: 'none' }) - expect(s).to be_correct_and_respond 204 - - eventually "Pools have no metadata when 'pool_metadata_source' => 'none'" do - pools.list({ stake: 1000 }).none? { |p| p['metadata'] } - end - end - - it "pool_metadata_source = #{ENV.fetch('TESTS_E2E_SMASH', nil)} <> none" do - skip 'Smash is not set up yet on preview / preprod' - settings = CW.misc.settings - pools = SHELLEY.stake_pools - s = settings.update({ pool_metadata_source: ENV.fetch('TESTS_E2E_SMASH', nil) }) - expect(s).to be_correct_and_respond 204 - - eventually "Pools have metadata when 'pool_metadata_source' => '#{ENV.fetch('TESTS_E2E_SMASH', nil)}'" do - pools.list({ stake: 1000 }).any? { |p| p['metadata'] } - end - - s = settings.update({ pool_metadata_source: 'none' }) - expect(s).to be_correct_and_respond 204 - - eventually "Pools have no metadata when 'pool_metadata_source' => 'none'" do - pools.list({ stake: 1000 }).none? { |p| p['metadata'] } - end - end - end - - describe 'Stake Pools GC Maintenance' do - matrix = [{ 'direct' => 'not_applicable' }, - { 'none' => 'not_applicable' }] - matrix.each do |tc| - it "GC metadata maintenance action on metadata source #{tc}" do - settings = CW.misc.settings - pools = SHELLEY.stake_pools - - s = settings.update({ pool_metadata_source: tc.keys.first }) - expect(s).to be_correct_and_respond 204 - - t = pools.trigger_maintenance_actions({ maintenance_action: 'gc_stake_pools' }) - expect(t).to be_correct_and_respond 204 - - eventually "Maintenance action has status = #{tc.values.first}" do - r = pools.view_maintenance_actions - (r.code == 200) && (r.to_s.include? tc.values.first) - end - end - end - end - describe 'Stake Pools GC Maintenance' do - matrix = [{ ENV.fetch('TESTS_E2E_SMASH', nil) => 'has_run' }] - matrix.each do |tc| - it "GC metadata maintenance action on metadata source #{tc}" do - pending "GC metadata maintenance action on metadata source #{ENV.fetch('TESTS_E2E_SMASH', nil)}" - settings = CW.misc.settings - pools = SHELLEY.stake_pools - - s = settings.update({ pool_metadata_source: tc.keys.first }) - expect(s).to be_correct_and_respond 204 - - t = pools.trigger_maintenance_actions({ maintenance_action: 'gc_stake_pools' }) - expect(t).to be_correct_and_respond 204 - - eventually "Maintenance action has status = #{tc.values.first}" do - r = pools.view_maintenance_actions - (r.code == 200) && (r.to_s.include? tc.values.first) - end - end - end - end - it 'I could quit stake pool - if I was delegating' do - id = create_shelley_wallet - - pools = SHELLEY.stake_pools - quit = pools.quit(id, PASS) - expect(quit).to be_correct_and_respond 403 - expect(quit.to_s).to include 'not_delegating_to' - end - end - - describe CardanoWallet::Shelley::Migrations do - it 'I could create migration plan' do - id = create_shelley_wallet - target_id = create_shelley_wallet - addrs = SHELLEY.addresses.list(target_id).map { |a| a['id'] } - - plan = SHELLEY.migrations.plan(id, addrs) - expect(plan).to be_correct_and_respond 403 - expect(plan.to_s).to include 'nothing_to_migrate' - end - - it 'I could migrate all my funds' do - id = create_shelley_wallet - target_id = create_shelley_wallet - addrs = SHELLEY.addresses.list(target_id).map { |a| a['id'] } - migr = SHELLEY.migrations.migrate(id, PASS, addrs) - expect(migr).to be_correct_and_respond 403 - expect(migr.to_s).to include 'nothing_to_migrate' - end - end - - describe CardanoWallet::Shelley::Keys do - it 'Get signed metadata' do - wid = create_shelley_wallet - %w[utxo_internal utxo_external mutable_account].each do |role| - id = [*0..100_000].sample - res = SHELLEY.keys.sign_metadata(wid, - role, - id, - 'Secure Passphrase', - { '0' => { 'string' => 'cardano' } }) - puts "#{wid}/#{role}/#{id}" - expect(res).to respond_with 200 - end - end - - it 'Get public key' do - wid = create_shelley_wallet - %w[utxo_internal utxo_external mutable_account].each do |role| - id = [*0..100_000].sample - res = SHELLEY.keys.get_public_key(wid, role, id) - puts "#{wid}/#{role}/#{id}" - expect(res).to be_correct_and_respond 200 - end - end - - it 'Create account public key - extended' do - m24 = CW.utils.mnemonic_sentence(24) - wid = create_shelley_wallet('Wallet', m24) - %w[0H 1H 2147483647H 44H].each do |index| - payload = { passphrase: PASS, format: 'extended' } - res = SHELLEY.keys.create_acc_public_key(wid, index, payload) - expect(res).to be_correct_and_respond 202 - expect(res.parsed_response).to eq cardano_address_get_acc_xpub(m24, - "1852H/1815H/#{index}", - 'Shelley', - '--with-chain-code', - hex: false) - end - end - - it 'Create account public key - non_extended' do - m24 = CW.utils.mnemonic_sentence(24) - wid = create_shelley_wallet('Wallet', m24) - %w[0H 1H 2147483647H 44H].each do |index| - payload = { passphrase: PASS, format: 'non_extended' } - res = SHELLEY.keys.create_acc_public_key(wid, index, payload) - expect(res.parsed_response).to eq cardano_address_get_acc_xpub(m24, - "1852H/1815H/#{index}", - 'Shelley', - '--without-chain-code', - hex: false) - end - end - - it 'Create account public key - extended with purpose' do - m24 = CW.utils.mnemonic_sentence(24) - wid = create_shelley_wallet('Wallet', m24) - %w[0H 1H 2147483647H 1854H].each do |index_purpose| - payload = { passphrase: PASS, format: 'extended', purpose: index_purpose } - res = SHELLEY.keys.create_acc_public_key(wid, index_purpose, payload) - expect(res).to be_correct_and_respond 202 - type_for_cardano_address = index_purpose == '1854H' ? 'Shared' : 'Shelley' - expect(res.parsed_response).to eq cardano_address_get_acc_xpub(m24, - "#{index_purpose}/1815H/#{index_purpose}", - type_for_cardano_address, - '--with-chain-code', - hex: false) - end - end - - it 'Create account public key - non_extended with purpose' do - m24 = CW.utils.mnemonic_sentence(24) - wid = create_shelley_wallet('Wallet', m24) - %w[0H 1H 2147483647H 1854H].each do |index_purpose| - payload = { passphrase: PASS, format: 'non_extended', purpose: index_purpose } - res = SHELLEY.keys.create_acc_public_key(wid, index_purpose, payload) - expect(res).to be_correct_and_respond 202 - type_for_cardano_address = index_purpose == '1854H' ? 'Shared' : 'Shelley' - expect(res.parsed_response).to eq cardano_address_get_acc_xpub(m24, - "#{index_purpose}/1815H/#{index_purpose}", - type_for_cardano_address, - '--without-chain-code', - hex: false) - end - end - - it 'Get account public key - wallet from acc pub key' do - payload = { name: 'Wallet from pub key 2', - account_public_key: 'b47546e661b6c1791452d003d375756dde6cac2250093ce4630f16b9b9c0ac87411337bda4d5bc0216462480b809824ffb48f17e08d95ab9f1b91d391e48e66b', - address_pool_gap: 20 } - wallet = WalletFactory.create(:shelley, payload) - expect(wallet).to be_correct_and_respond 201 - - res = SHELLEY.keys.get_acc_public_key(wallet['id'], { format: 'non_extended' }) - expect(res).to be_correct_and_respond 200 - expect(res.parsed_response).to include 'acct_vk' - end - - it 'Get account public key - wallet from mnemonics' do - m24 = CW.utils.mnemonic_sentence(24) - wid = create_shelley_wallet('Wallet', m24) - - # Get account pub key from the wallet - w_acct_key = SHELLEY.keys.get_acc_public_key(wid, { format: 'extended' }) - expect(w_acct_key).to be_correct_and_respond 200 - - # Get equivalent account pub key using cardano-addresses - root_xsk = CA.prv_key_from_recovery_phrase(m24, 'Shelley') - acct_key = CA.key_child(root_xsk, '1852H/1815H/0H') - pub_key = CA.key_public(acct_key) - - expect(pub_key).to eq w_acct_key.parsed_response - end - - it 'Get account public key (mnemonic_snd_factor)' do - m24 = CW.utils.mnemonic_sentence(24) - m12 = CW.utils.mnemonic_sentence(12) - wid = create_shelley_wallet('Wallet', m24, m12) - - # Get account pub key from the wallet - w_acct_key = SHELLEY.keys.get_acc_public_key(wid, { format: 'extended' }) - expect(w_acct_key).to be_correct_and_respond 200 - - # Get equivalent account pub key using cardano-addresses - pub_key = Dir.mktmpdir do |dir| - sndfactor_file = File.join(dir, 'sndfactor.prv') - File.write(sndfactor_file, m12.join(' ')) - root_xsk = CA.prv_key_from_recovery_phrase(m24, "Shelley --passphrase from-mnemonic --from-file #{sndfactor_file}") - acct_key = CA.key_child(root_xsk, '1852H/1815H/0H') - CA.key_public(acct_key) - end - - expect(pub_key).to eq w_acct_key.parsed_response - end - - it "I can create and get policy key and it's hash" do - wid = create_shelley_wallet - created = SHELLEY.keys.create_policy_key(wid, PASS, { hash: true }) - expect(created).to be_correct_and_respond 202 - expect(created.to_s).to include 'policy_vkh' - - get = SHELLEY.keys.get_policy_key(wid, { hash: true }) - expect(get).to be_correct_and_respond 200 - - expect(get.to_s).to eq created.to_s - - created = SHELLEY.keys.create_policy_key(wid, PASS) - expect(created).to be_correct_and_respond 202 - expect(created.to_s).to include 'policy_vk' - expect(created.to_s).not_to include 'policy_vkh' - - get = SHELLEY.keys.get_policy_key(wid) - expect(get).to be_correct_and_respond 200 - - expect(get.to_s).to eq created.to_s - end - - describe 'Policy Id' do - matrix = [ - ['cosigner#0', 202], - [{ all: ['cosigner#0'] }, 202], - [{ any: ['cosigner#0'] }, 202], - [{ some: { at_least: 1, from: ['cosigner#0'] } }, 202], - [{ all: ['cosigner#0', { active_from: 120 }] }, 202], - ['cosigner#1', 403], - [{ all: ['cosigner#0', 'cosigner#1'] }, 403] - ] - matrix.each do |m| - template = m[0] - code = m[1] - it "Script template = #{template} gives #{code}" do - wid = create_shelley_wallet - created = SHELLEY.keys.create_policy_id(wid, template) - expect(created).to be_correct_and_respond code - end - end - end - end -end diff --git a/test/e2e/spec/spec_helper.rb b/test/e2e/spec/spec_helper.rb deleted file mode 100644 index def8b80e298..00000000000 --- a/test/e2e/spec/spec_helper.rb +++ /dev/null @@ -1,683 +0,0 @@ -# frozen_string_literal: true - -require 'bundler/setup' -require 'cardano_wallet' -require 'base64' -require 'blake2b' -require 'mustache' -require 'cbor' -require 'tmpdir' -require 'set' -require_relative '../env' -require_relative '../helpers/utils' -require_relative '../helpers/tx_history' -require_relative '../helpers/matchers' -require_relative '../helpers/context' -require_relative '../helpers/wallet_factory' -require_relative '../helpers/cardano_addresses' -require_relative '../helpers/cardano_cli' - -include Helpers::Utils -include TxHistory - -RSpec.configure do |config| - # Enable flags like --only-failures and --next-failure - config.example_status_persistence_file_path = '.rspec_status' - - # Disable RSpec exposing methods globally on `Module` and `main` - config.disable_monkey_patching! - - config.expect_with :rspec do |c| - c.syntax = :expect - c.max_formatted_output_length = nil - end -end - -# Helpers - -## -# timeout in seconds for custom verifications -TIMEOUT = 600 -FIXTURES_DIR = 'fixtures' - -## -# Intit cardano-wallet wrapper with timeout for getting the response back -CW = CardanoWallet.new({ timeout: TIMEOUT, port: ENV['WALLET_PORT'].to_i }) -BYRON = CW.byron -SHELLEY = CW.shelley -SHARED = CW.shared -SETTINGS = CW.misc.settings -UTILS = CW.misc.utils -NETWORK = CW.misc.network -PROXY = CW.misc.proxy -NODE = CW.misc.node -CA = CardanoAddresses.new - -CONTEXT = Context.new -CONTEXT.env = ENV.fetch('NETWORK', nil) - -CARDANO_CLI = CardanoCli.new(get_protocol_magic(CONTEXT.env)) - -## -# default passphrase for wallets -PASS = 'Secure Passphrase' - -## -# Artificial, non-existing id's -TXID = '1acf9c0f504746cbd102b49ffaf16dcafd14c0a2f1bbb23af265fbe0a04951cc' -SPID = 'feea59bc6664572e631e9adfee77142cb51264156debf2e52970cc00' -SPID_BECH32 = 'pool1v7g9ays8h668d74xjvln9xuh9adzh6xz0v0hvcd3xukpck5z56d' -DEV_NULL_ADDR = 'addr_test1qp760qtlwv6cyvvkpz3a6s0y72aea4xd4da85rm5qe2u6awgscyn6cz7plwgtanjanvpg9xt4lc3wlrqhcw5cmxk334q0wca8l' - -# exemplary metadata -METADATA = { '0' => { 'string' => 'cardano' }, - '1' => { 'int' => 14 }, - '2' => { 'bytes' => '2512a00e9653fe49a44a5886202e24d77eeb998f' }, - '3' => { 'list' => [{ 'int' => 14 }, { 'int' => 42 }, { 'string' => '1337' }] }, - '4' => { 'map' => [{ 'k' => { 'string' => 'key' }, 'v' => { 'string' => 'value' } }, - { 'k' => { 'int' => 14 }, 'v' => { 'int' => 42 } }] } }.freeze - -# Testnet assets with metadata from mock server https://metadata.world.dev.cardano.org/ -ASSETS = [{ 'policy_id' => 'ee1ce9d7560f48a4ba3867037dbec2d8fed776d94dd6b00a35309073', - 'asset_name' => '', - 'fingerprint' => 'asset1s3yhz885gnyu2wcpz5h275u37hw3axz3c9sfqu', - 'metadata' => { 'name' => 'SadCoin', - 'description' => 'Coin with no asset name', - 'url' => 'https://sad.io', - 'ticker' => 'SAD', - 'logo' => 'iVBORw0KGgoAAAANSUhEUgAAABkAAAAeCAYAAADZ7LXbAAAACXBIWXMAAA7EAAAOxAGVKw4bAAACbUlEQVRIie3Vy0tUURzA8e855965c8lXUhlhEQVBSEmQRAURQbSIEqFl4N6/oHYtAhdtonatK8hVBCERZC+0jbZpIRVkIeagTJrO3Nd5tBhDMHOcGiHCA2dxHvDh9zs/fkc45xwbPORGA5tI/RFdGCL9MgAm/mNEVKuuaHA3OW+RlDb8zjt4O07VjFRPV8NBZC5PGMxj3/YQv7uGs7p+iJ5+ipgfIZr7hnWSXBjgT98iHr6IS+fqg7h0Dl8ZQpmQFKdJSmWkkuSj10TD3WCzv0f89m6S8BjWQehbVDpPWiojsASlEeLxG3WIJFtANneQei3EqpnMeWRxgtMahYGP/dhoqiry2+rKJh9i3l8l2KIRUlVQazDlRXTpOzIr43uQ7LlCvrO/9kjisT7Ehz6CBgtCki4sEC+ALpdQQUC+qQmXC3EO3NQAsHaP/QVx1mBnh5BKYpOYON2L6npJ/sw4svMRacmCc+TyOQwKGX/CRl9rQ4SQyPZeFqM27L7bhCcHUY37AVCtR7EtZ8EZhLN4vkIKhy1N1Ibo4ijq83UavAl04QmIFVekB1aDNQhnQFBZ14KABauRaFThHrrwbPmkPImYeQw6A5OBNRjnIxsPrIl4KzdUcwep9SFL8JVHNnqJeFcvyBCm7hJQBKPBZJWH334eGe5cE1m1hKM3l8nP3kcICVLiEEuXLfycQKpBnnhRtWmuWsLBkZtEucNYa8BkCJMiTFrJ/RLgHJjWc+vqyqsiMthGePo5SWsP2ohKWpamdZBqQbz1AvnjD6oCsI7/RM+8whTHljf8RrzWLlTLoXUB60LqMf6NP34T+T+RH/HOKLJ+ho1iAAAAAElFTkSuQmCC' } }, - { 'policy_id' => '919e8a1922aaa764b1d66407c6f62244e77081215f385b60a6209149', - 'asset_name' => asset_name('HappyCoin'), - 'fingerprint' => 'asset19mwamgpre24at3z34v2e5achszlhhqght9djqp', - 'metadata' => { 'name' => 'HappyCoin', - 'description' => 'Coin with asset name - and everyone is happy!!!', - 'url' => 'https://happy.io', - 'decimals' => 6, - 'ticker' => 'HAPP', - 'logo' => 'iVBORw0KGgoAAAANSUhEUgAAABkAAAAeCAYAAADZ7LXbAAAACXBIWXMAAA7EAAAOxAGVKw4bAAACbUlEQVRIie3Vy0tUURzA8e855965c8lXUhlhEQVBSEmQRAURQbSIEqFl4N6/oHYtAhdtonatK8hVBCERZC+0jbZpIRVkIeagTJrO3Nd5tBhDMHOcGiHCA2dxHvDh9zs/fkc45xwbPORGA5tI/RFdGCL9MgAm/mNEVKuuaHA3OW+RlDb8zjt4O07VjFRPV8NBZC5PGMxj3/YQv7uGs7p+iJ5+ipgfIZr7hnWSXBjgT98iHr6IS+fqg7h0Dl8ZQpmQFKdJSmWkkuSj10TD3WCzv0f89m6S8BjWQehbVDpPWiojsASlEeLxG3WIJFtANneQei3EqpnMeWRxgtMahYGP/dhoqiry2+rKJh9i3l8l2KIRUlVQazDlRXTpOzIr43uQ7LlCvrO/9kjisT7Ehz6CBgtCki4sEC+ALpdQQUC+qQmXC3EO3NQAsHaP/QVx1mBnh5BKYpOYON2L6npJ/sw4svMRacmCc+TyOQwKGX/CRl9rQ4SQyPZeFqM27L7bhCcHUY37AVCtR7EtZ8EZhLN4vkIKhy1N1Ibo4ijq83UavAl04QmIFVekB1aDNQhnQFBZ14KABauRaFThHrrwbPmkPImYeQw6A5OBNRjnIxsPrIl4KzdUcwep9SFL8JVHNnqJeFcvyBCm7hJQBKPBZJWH334eGe5cE1m1hKM3l8nP3kcICVLiEEuXLfycQKpBnnhRtWmuWsLBkZtEucNYa8BkCJMiTFrJ/RLgHJjWc+vqyqsiMthGePo5SWsP2ohKWpamdZBqQbz1AvnjD6oCsI7/RM+8whTHljf8RrzWLlTLoXUB60LqMf6NP34T+T+RH/HOKLJ+ho1iAAAAAElFTkSuQmCC' } }].freeze - -## -# Since alonzo min_utxo_value is calculated based on the particular output size -# 1 ADA, however should be enough for sending pure Ada output to shelley address -# setting it to 2 ADA temporarily because of: -# ADP-2298 - Deposit_returned is falsely reported on some incoming transactions (intermittently) -MIN_UTXO_VALUE_PURE_ADA = 2_000_000 - -def payment_payload(amt, addr = DEV_NULL_ADDR) - [{ :address => addr, - :amount => { :quantity => amt, - :unit => 'lovelace' } }] -end - -def create_incomplete_shared_wallet(m, acc_ix, acc_xpub) - script_template = { 'cosigners' => - { 'cosigner#0' => acc_xpub }, - 'template' => - { 'all' => - ['cosigner#0', - 'cosigner#1'] } } - pscript = script_template - dscript = script_template - payload = if m.is_a? Array - { mnemonic_sentence: m, - passphrase: PASS, - name: 'Shared wallet', - account_index: acc_ix, - payment_script_template: pscript, - delegation_script_template: dscript } - else - { account_public_key: m, - passphrase: PASS, - name: 'Shared wallet', - account_index: acc_ix, - payment_script_template: pscript, - delegation_script_template: dscript } - end - WalletFactory.create(:shared, payload)['id'] -end - -def shared_acc_pubkey(wallet_id) - SHARED.keys.get_acc_public_key(wallet_id, { format: 'extended' }).parsed_response.delete_prefix('"').delete_suffix('"') -end - -def patch_incomplete_shared_wallet(wid, payment_patch, deleg_patch) - if payment_patch - p_upd = SHARED.wallets.update_payment_script(wid, - payment_patch.keys.first, - payment_patch.values.first) - expect(p_upd).to be_correct_and_respond 200 - end - - return unless deleg_patch - - d_upd = SHARED.wallets.update_delegation_script(wid, - deleg_patch.keys.first, - deleg_patch.values.first) - expect(d_upd).to be_correct_and_respond 200 -end - -def patch_if_incomplete(wid, payment_patch, deleg_patch) - if payment_patch - p_upd = SHARED.wallets.update_payment_script(wid, - payment_patch.keys.first, - payment_patch.values.first) - case p_upd.code - when 200 - expect(p_upd).to be_correct_and_respond 200 - when 403 - expect(p_upd).to be_correct_and_respond 403 - expect(p_upd.parsed_response['code']).to eq 'shared_wallet_active' - end - end - - return unless deleg_patch - - d_upd = SHARED.wallets.update_delegation_script(wid, - deleg_patch.keys.first, - deleg_patch.values.first) - case d_upd.code - when 200 - expect(d_upd).to be_correct_and_respond 200 - when 403 - expect(d_upd).to be_correct_and_respond 403 - expect(d_upd.parsed_response['code']).to eq 'shared_wallet_active' - end -end - -def create_active_shared_wallet(m, acc_ix, acc_xpub) - script_template = { 'cosigners' => - { 'cosigner#0' => acc_xpub }, - 'template' => - { 'all' => - ['cosigner#0'] } } - pscript = script_template - dscript = script_template - payload = if m.is_a? Array - { mnemonic_sentence: m, - passphrase: PASS, - name: 'Shared wallet', - account_index: acc_ix, - payment_script_template: pscript, - delegation_script_template: dscript } - else - { account_public_key: m, - passphrase: PASS, - name: 'Shared wallet', - account_index: acc_ix, - payment_script_template: pscript, - delegation_script_template: dscript } - end - - WalletFactory.create(:shared, payload)['id'] -end - -def wait_for_shared_wallet_to_sync(wid) - puts 'Syncing Shared wallet...' - retry_count = 10 - begin - while SHARED.wallets.get(wid)['state']['status'].to_s == 'syncing' - w = SHARED.wallets.get(wid) - puts " Syncing... #{w['state']['progress']['quantity'].to_i}%" if w['state']['progress'] - sleep 5 - end - rescue StandardError - puts "Retry #{retry_count}" - retry_count -= 1 - puts "SHARED.wallets.get(#{wid}) returned:" - puts SHARED.wallets.get(wid) - retry if retry_count > 0 - end -end - -def wait_for_all_shared_wallets(wids) - wids.each do |w| - wait_for_shared_wallet_to_sync(w) - end -end - -def create_shelley_wallet(name = 'Wallet from mnemonic_sentence', - mnemonic_sentence = CW.utils.mnemonic_sentence(24), - mnemonic_second_factor = nil) - payload = { name: name, - passphrase: PASS, - mnemonic_sentence: mnemonic_sentence } - payload[:mnemonic_second_factor] = mnemonic_second_factor if mnemonic_second_factor - WalletFactory.create(:shelley, payload)['id'] -end - -def wait_for_shelley_wallet_to_sync(wid) - puts 'Syncing Shelley wallet...' - retry_count = 10 - begin - while SHELLEY.wallets.get(wid)['state']['status'].to_s == 'syncing' - w = SHELLEY.wallets.get(wid) - puts " Syncing... #{w['state']['progress']['quantity'].to_i}%" if w['state']['progress'] - sleep 5 - end - rescue StandardError - puts "Retry #{retry_count}" - retry_count -= 1 - puts "SHELLEY.wallets.get(#{wid}) returned:" - puts w - retry if retry_count > 0 - end -end - -def wait_for_all_shelley_wallets(wids) - wids.each do |w| - wait_for_shelley_wallet_to_sync(w) - end -end - -def create_byron_wallet(style = 'random', - name = 'Wallet from mnemonic_sentence', - mnemonics = CW.utils.mnemonic_sentence(24)) - payload = { style: style, - name: name, - passphrase: PASS, - mnemonic_sentence: mnemonics } - WalletFactory.create(:byron, payload)['id'] -end - -def wait_for_byron_wallet_to_sync(wid) - puts 'Syncing Byron wallet...' - retry_count = 10 - begin - while BYRON.wallets.get(wid)['state']['status'].to_s == 'syncing' - w = BYRON.wallets.get(wid) - puts " Syncing... #{w['state']['progress']['quantity'].to_i}%" if w['state']['progress'] - sleep 5 - end - rescue StandardError - puts "Retry #{retry_count}" - retry_count -= 1 - puts "BYRON.wallets.get(#{wid}) returned:" - puts BYRON.wallets.get(wid) - retry if retry_count > 0 - end -end - -def wait_for_all_byron_wallets(wids) - wids.each do |w| - wait_for_byron_wallet_to_sync(w) - end -end - -## FIXTURE AND TARGET WALLETS ## - -## -# return wallet id from create wallet response even if it already exists -def return_wallet_id(create_wallet_response) - if create_wallet_response.code == 409 - create_wallet_response['message'].split[10] - else - create_wallet_response['id'] - end -end - -## -# create fixture wallet or return it's id if it exists -# @param type [Symbol] :shelley, :shared, :shared_cosigner_0, :shared_cosigner_1, :random, :icarus -# @param templates [Symbols] ':payment_cosigner{0,1}_{all,any,all0}', :delegation_cosigner{0,1}_{all,any,all0} -# rubocop:disable Metrics/CyclomaticComplexity -def create_fixture_wallet(type, *templates) - payload = { name: "Fixture wallet with funds (#{type}#{" #{templates}" unless templates.empty?}", - passphrase: PASS, - mnemonic_sentence: get_fixture_wallet(:fixture, type.to_sym, :mnemonics) } - case type.to_sym - when :shelley - wallet = SHELLEY.wallets.create(payload) - return_wallet_id(wallet) - when :random, :icarus - payload[:style] = type - wallet = BYRON.wallets.create(payload) - return_wallet_id(wallet) - when :shared, :shared2 - templates.each do |t| - case t - when :payment_cosigner0_all - payload[:payment_script_template] = { 'cosigners' => { 'cosigner#0' => 'self' }, 'template' => { 'all' => ['cosigner#0', 'cosigner#1'] } } - when :delegation_cosigner0_all - payload[:delegation_script_template] = { 'cosigners' => { 'cosigner#0' => 'self' }, 'template' => { 'all' => ['cosigner#0', 'cosigner#1'] } } - when :payment_cosigner1_all - payload[:payment_script_template] = { 'cosigners' => { 'cosigner#1' => 'self' }, 'template' => { 'all' => ['cosigner#0', 'cosigner#1'] } } - when :delegation_cosigner1_all - payload[:delegation_script_template] = { 'cosigners' => { 'cosigner#1' => 'self' }, 'template' => { 'all' => ['cosigner#0', 'cosigner#1'] } } - when :payment_cosigner0_any - payload[:payment_script_template] = { 'cosigners' => { 'cosigner#0' => 'self' }, 'template' => { 'any' => ['cosigner#0', 'cosigner#1'] } } - when :delegation_cosigner0_any - payload[:delegation_script_template] = { 'cosigners' => { 'cosigner#0' => 'self' }, 'template' => { 'any' => ['cosigner#0', 'cosigner#1'] } } - when :payment_cosigner1_any - payload[:payment_script_template] = { 'cosigners' => { 'cosigner#1' => 'self' }, 'template' => { 'any' => ['cosigner#0', 'cosigner#1'] } } - when :delegation_cosigner1_any - payload[:delegation_script_template] = { 'cosigners' => { 'cosigner#1' => 'self' }, 'template' => { 'any' => ['cosigner#0', 'cosigner#1'] } } - when :payment_cosigner0_all0 - payload[:payment_script_template] = { 'cosigners' => { 'cosigner#0' => 'self' }, 'template' => { 'all' => ['cosigner#0'] } } - when :delegation_cosigner0_all0 - payload[:delegation_script_template] = { 'cosigners' => { 'cosigner#0' => 'self' }, 'template' => { 'all' => ['cosigner#0'] } } - end - end - payload[:account_index] = '0H' - wallet = SHARED.wallets.create(payload) - return_wallet_id(wallet) - else - raise "Unsupported wallet type: #{type}" - end -end -# rubocop:enable Metrics/CyclomaticComplexity - -## -# create target wallet or return it's id if it exists -# @param type [Symbol] :shelley, :shared -def create_target_wallet(type) - payload = { name: 'Target wallet for txs', - passphrase: PASS, - mnemonic_sentence: get_fixture_wallet(:target, type.to_sym, :mnemonics) } - case type.to_sym - when :shelley - wallet = SHELLEY.wallets.create(payload) - return_wallet_id(wallet) - else - raise "Unsupported wallet type: #{type}" - end -end - -## -# wait until action passed as &block returns true or TIMEOUT is reached -def eventually(label, &block) - current_time = Time.now - timeout_treshold = current_time + TIMEOUT - while (block.call == false) && (current_time <= timeout_treshold) - sleep 5 - current_time = Time.now - end - raise "Action '#{label}' did not resolve within timeout: #{TIMEOUT}s" if current_time > timeout_treshold -end - -def teardown - CONTEXT.byron.dup.each do |wid| - WalletFactory.delete(:byron, wid) - end - - CONTEXT.shelley.dup.each do |wid| - WalletFactory.delete(:shelley, wid) - end - - CONTEXT.shared.dup.each do |wid| - WalletFactory.delete(:shared, wid) - end -end - -## -# return asset total or available balance for comparison -# @param [Hash] assets - asset balance Hash from the wallet (output of get_wallet_balances['assets_*']) -# @param [Hash] options - -# options[:delta] [Int] - received/sent assets that we are expecting (default: 0) -# options[:assets_to_check] [Array] - limit looking up balance to only assets in the array ["#{policy_id}#{asset_name}",...] (default: nil) -# @return [Set] Set of Hashes {"#{policy_id}#{asset_name}" => balance} -def assets_balance(assets, options = {}) - options[:delta] ||= 0 - assets_to_check = options[:assets_to_check] - - asset_set = assets.to_set { |x| { "#{x['policy_id']}#{x['asset_name']}" => x['quantity'] + options[:delta] } } - if assets_to_check - asset_set.select { |a| assets_to_check.include? a.keys.first }.to_set - else - asset_set - end -end - -## -# return ada and asset accounts balance for wallet -# identified by wallet_api -def get_wallet_balances(wid, wallet_api) - w = wallet_api.wallets.get(wid) - total = w['balance']['total']['quantity'] - available = w['balance']['available']['quantity'] - reward = w['balance']['reward']['quantity'] - assets_total = w['assets']['total'] - assets_available = w['assets']['available'] - { 'total' => total, - 'available' => available, - 'rewards' => reward, - 'assets_available' => assets_available, - 'assets_total' => assets_total } -end - -def get_shelley_balances(wid) - get_wallet_balances(wid, SHELLEY) -end - -def get_shared_balances(wid) - get_wallet_balances(wid, SHARED) -end - -def get_byron_balances(wid) - w = BYRON.wallets.get(wid) - total = w['balance']['total']['quantity'] - available = w['balance']['available']['quantity'] - assets_total = w['assets']['total'] - assets_available = w['assets']['available'] - { 'total' => total, - 'available' => available, - 'assets_available' => assets_available, - 'assets_total' => assets_total } -end - -## -# verify ADA balance on src and target wallets after transaction for amt ADA -# incurring fee ADA -def verify_ada_balance(src_after, src_before, target_after, target_before, amt, fee) - expect(target_after['available']).to eq(amt + target_before['available']) - expect(target_after['total']).to eq(amt + target_before['total']) - - expect(src_after['available']).to eq(src_before['available'] - amt - fee) - expect(src_after['total']).to eq(src_before['total'] - amt - fee) -end - -## -# Verify assets balance on target and src wallets after transaction -# @params src_after, src_before, target_after, target_before - src and target wallet balances before and after tx -# @param [Int] amt - amt of assets sent in tx -# @param [Array] assets_to_check - array of assets sent in the tx in the form of ["#{policy_id}#{asset_name}",...] -def verify_asset_balance(src_after, src_before, target_after, target_before, amt, - assets_to_check = ["#{ASSETS[0]['policy_id']}#{ASSETS[0]['asset_name']}", - "#{ASSETS[1]['policy_id']}#{ASSETS[1]['asset_name']}"]) - - target_total_after = assets_balance(target_after['assets_total'], { assets_to_check: assets_to_check }) - target_avail_after = assets_balance(target_after['assets_available'], { assets_to_check: assets_to_check }) - target_total_expected = assets_balance(target_before['assets_total'], { assets_to_check: assets_to_check, delta: +amt }) - target_avail_expected = assets_balance(target_before['assets_available'], { assets_to_check: assets_to_check, delta: +amt }) - src_total_after = assets_balance(src_after['assets_total'], { assets_to_check: assets_to_check }) - src_avail_after = assets_balance(src_after['assets_available'], { assets_to_check: assets_to_check }) - src_total_expected = assets_balance(src_before['assets_total'], { assets_to_check: assets_to_check, delta: -amt }) - src_avail_expected = assets_balance(src_before['assets_available'], { assets_to_check: assets_to_check, delta: -amt }) - - if target_before['assets_total'] == [] - target_balance_expected = assets_to_check.to_set { |a| { a => amt } } - expect(target_total_after).to eq target_balance_expected - expect(target_avail_after).to eq target_balance_expected - else - expect(target_total_after).to eq target_total_expected - expect(target_avail_after).to eq target_avail_expected - end - - expect(src_total_after).to eq src_total_expected - expect(src_avail_after).to eq src_avail_expected -end - -def wait_for_tx_in_ledger(wid, tx_id, wallet_api = SHELLEY) - eventually "Tx #{tx_id} is in ledger" do - tx = wallet_api.transactions.get(wid, tx_id) - tx.code == 200 && tx['status'] == 'in_ledger' - end -end - -def verify_tx_status(wid, tx_id, status, wallet_api = SHELLEY) - tx = wallet_api.transactions.get(wid, tx_id) - expect(tx.code).to eq(200) - expect(tx['status']).to eq(status) -end - -## Mint/burn helpers - -# Build mint payload for construct tx -def mint(asset_name, quantity, policy_script, address = nil) - mint = { 'operation' => { 'mint' => { 'quantity' => quantity } }, - 'policy_script_template' => policy_script } - mint['operation']['mint']['receiving_address'] = address unless address.nil? - mint['asset_name'] = asset_name unless asset_name.nil? - mint -end - -# Build burn payload for construct tx -def burn(asset_name, quantity, policy_script) - burn = { 'operation' => { 'burn' => { 'quantity' => quantity } }, - 'policy_script_template' => policy_script } - burn['asset_name'] = asset_name unless asset_name.nil? - burn -end - -## -# Gets assets list in the form of 'policy_id + asset_name' array -# @return [Array] - ["#{policy_id}#{asset_name}"...] of all minted/burnt assets -def get_assets_from_decode(tx_decoded_mint_or_burn) - tx_decoded_mint_or_burn['tokens'].map do |x| - assets = x['assets'].map { |z| z['asset_name'] } - assets.map { |a| "#{x['policy_id']}#{a}" } - end.flatten -end - -def get_policy_id_from_decode(tx_decoded_mint_or_burn) - tx_decoded_mint_or_burn['tokens'].first['policy_id'] -end - -## -# Balance -> Sign -> Submit -def balance_sign_submit(wid, payload) - tx_balanced = SHELLEY.transactions.balance(wid, payload) - expect(tx_balanced).to be_correct_and_respond 202 - - tx_signed = SHELLEY.transactions.sign(wid, PASS, tx_balanced['transaction']) - expect(tx_signed).to be_correct_and_respond 202 - - tx_submitted = SHELLEY.transactions.submit(wid, tx_signed['transaction']) - expect(tx_submitted).to be_correct_and_respond 202 - - [tx_balanced, tx_signed, tx_submitted] -end - -## -# Construct -> Sign -> Submit -def construct_sign_submit(wid, - payments = nil, - withdrawal = nil, - metadata = nil, - delegations = nil, - mint = nil, - validity_interval = nil) - - tx_constructed = SHELLEY.transactions.construct(wid, - payments, - withdrawal, - metadata, - delegations, - mint, - validity_interval) - expect(tx_constructed).to be_correct_and_respond 202 - - tx_signed = SHELLEY.transactions.sign(wid, PASS, tx_constructed['transaction']) - expect(tx_signed).to be_correct_and_respond 202 - - tx_submitted = SHELLEY.transactions.submit(wid, tx_signed['transaction']) - expect(tx_submitted).to be_correct_and_respond 202 - - [tx_constructed, tx_signed, tx_submitted] -end - -def create_policy_key_if_not_exists(wid) - gpkey = SHELLEY.keys.get_policy_key(wid) - if gpkey.code == 403 && gpkey['code'] == 'missing_policy_public_key' - pkey = SHELLEY.keys.create_policy_key(wid, PASS) - expect(pkey).to be_correct_and_respond 202 - pkey - else - gpkey - end -end - -## -# Plutus helpers - -## -# Encode input index the way Plutus does in hex-encoded CBOR script -# _probably_ should work fine for 0-127 index range -# @param [Int] input idx -# @return [Hex] hex encoded input idx imitating Plutus bit-wise, non-standard encoding -# -# @example -# > plutus_encode_idx(43) -# => "158c" -# -# @see lib/wallet/extra/Plutus/FlatInteger.hs -# reference Haskell impl of encoding Int into sequence of bits -# @see lib/wallet/src/Test/Integration/Plutus.hs -# the way it's done in the integration tests -# ``` -# idxEncoded = toHex $ BS.pack $ Bits.asBytes -# $ toBits "00" <> Bits.bits (fromIntegral idx :: Integer) <> toBits "001100" -# ``` -def plutus_encode_idx(int) - raise 'Not supported index. (0-127) are supported.' if int > 127 - - # convert int to binary and add trailing bit - b = "#{int.to_s(2)}0" - # add additional leading bits so it is 8-bit long - b = ('0' * (8 - b.length)) + b - # add additional leading and trailing bits - b = "00#{b}001100" - # convert to hex and add leading 0's if needed (so it is 4 digit long) - h = binary_to_hex(b) - ('0' * (4 - h.length)) + h -end - -def get_simple_scripts_file_path(file) - File.join(FIXTURES_DIR, 'simple', file) -end - -def get_plutus_file_path(file) - File.join(FIXTURES_DIR, 'plutus', file) -end - -def get_plutus_tx(file) - JSON.parse(File.read(get_plutus_file_path(file))) -end - -def read_mustached_file(file, ctx = {}) - Mustache.render(File.read(get_plutus_file_path(file)), ctx).strip -end - -def get_templated_plutus_tx(file, ctx = {}) - JSON.parse(read_mustached_file(file, ctx)) -end - -## -# Get policyId of base16-encoded minting policy -# which is Blake2b (28 byte long) hash of (script tag = 0x01 + policy) -def get_policy_id(policy) - key = Blake2b::Key.none - Blake2b.hex(hex_to_bytes("01#{policy}"), key, 28) -end - -## -# Get all sent ADA amounts from the wallet from decoded tx outputs -# We assume multi output transaction -def get_sent_amts(outputs) - outputs.map { |o| o['amount']['quantity'] if o['derivation_path'].nil? } -end - -## -# The same as get_sent_amts, but we assume single output tx -def get_sent_amt(outputs) - get_sent_amts(outputs).first -end diff --git a/test/e2e/state/configs/preprod b/test/e2e/state/configs/preprod deleted file mode 120000 index f88eefd17a6..00000000000 --- a/test/e2e/state/configs/preprod +++ /dev/null @@ -1 +0,0 @@ -../../../../configs/cardano/preprod \ No newline at end of file