diff --git a/.github/workflows/run-regtest-tests.yml b/.github/workflows/run-regtest-tests.yml new file mode 100644 index 0000000..b51dc23 --- /dev/null +++ b/.github/workflows/run-regtest-tests.yml @@ -0,0 +1,74 @@ +name: run-regtest-tests + +on: + workflow_dispatch: + inputs: + core_commit: + description: 'regtest-env config `STACKS_BLOCKCHAIN_COMMIT` (defaults to `develop`)' + required: false + default: 'develop' + type: string + regtest_env_commit: + description: 'regtest-env commit (defaults to `feat/signer`)' + required: false + default: 'feat/signer' + type: string + pull_request: + +concurrency: + group: '${{ github.workflow }} @ ${{ github.event.pull_request.head.label || github.head_ref || github.ref }} + ${{ github.event.inputs.core_commit }} + ${{ github.event.inputs.regtest_env_commit }}' + cancel-in-progress: true + +jobs: + run: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: 20 + cache: 'npm' + - uses: docker/setup-buildx-action@v3 + - uses: actions/cache@v3 + with: + path: /tmp/.buildx-cache + key: ${{ runner.os }}-buildx-${{ github.sha }} + restore-keys: | + ${{ runner.os }}-buildx- + - name: Create buildx builder + run: docker buildx create --use + + - name: Install dependencies + run: npm ci + + - name: Cache regtest-env + uses: actions/cache@v3 + id: cache-regtest-env + with: + path: /tmp/regtest-env + key: ${{ runner.os }}-regtest-env + + - name: Clone or update regtest-env + run: | + if [ ! -d "/tmp/regtest-env" ]; then + git clone https://github.com/hirosystems/stacks-regtest-env.git /tmp/regtest-env + fi + cd /tmp/regtest-env + git fetch origin + git checkout ${{ github.event.inputs.regtest_env_commit || 'feat/signer' }} + git pull origin ${{ github.event.inputs.regtest_env_commit || 'feat/signer' }} + + - name: Prepare regtest-env + run: | + cd /tmp/regtest-env + sed -i 's/\(&STACKS_BLOCKCHAIN_COMMIT \).*/\1${{ github.event.inputs.core_commit || 'develop' }}/' docker-compose.yml + sed -i 's/\(&MINE_INTERVAL_EPOCH25 \).*/\12s/' docker-compose.yml + sed -i 's/\(&MINE_INTERVAL_EPOCH3 \).*/\17s/' docker-compose.yml + sed -i 's/\(&&NAKAMOTO_BLOCK_INTERVAL \).*/\13s/' docker-compose.yml + docker compose build + + - name: Run regtest tests + run: npx jest --runInBand --testNamePattern='stack-stx (in reward-phase)' + env: + NETWORK_UP_CMD: cd /tmp/regtest-env && docker compose down --volumes --remove-orphans --timeout=1 --rmi=all && docker compose up --build -d + NETWORK_DOWN_CMD: cd /tmp/regtest-env && docker compose down --volumes --remove-orphans --timeout=1 diff --git a/.gitignore b/.gitignore index 4d9dfb1..14ee6d7 100644 --- a/.gitignore +++ b/.gitignore @@ -43,3 +43,7 @@ dist/**/* yarn.lock .vercel .git-info + + +# clarinet +.cache diff --git a/Clarinet.toml b/Clarinet.toml new file mode 100644 index 0000000..70a630e --- /dev/null +++ b/Clarinet.toml @@ -0,0 +1,21 @@ +[project] +name = "devnet" +description = "" +authors = [] +telemetry = false +cache_dir = "./.cache" + +# [contracts.counter] +# path = "contracts/counter.clar" + +[repl.analysis] +passes = ["check_checker"] +check_checker = { trusted_sender = false, trusted_caller = false, callee_filter = false } + +# Check-checker settings: +# trusted_sender: if true, inputs are trusted after tx_sender has been checked. +# trusted_caller: if true, inputs are trusted after contract-caller has been checked. +# callee_filter: if true, untrusted data may be passed into a private function without a +# warning, if it gets checked inside. This check will also propagate up to the +# caller. +# More informations: https://www.hiro.so/blog/new-safety-checks-in-clarinet diff --git a/deployments/default.devnet-plan.yaml b/deployments/default.devnet-plan.yaml new file mode 100644 index 0000000..abfa45a --- /dev/null +++ b/deployments/default.devnet-plan.yaml @@ -0,0 +1,8 @@ +--- +id: 0 +name: Devnet deployment +network: devnet +stacks-node: "http://localhost:20443" +bitcoin-node: "http://devnet:devnet@localhost:18443" +plan: + batches: [] diff --git a/jest.config.js b/jest.config.js index 3b4f00f..a307952 100644 --- a/jest.config.js +++ b/jest.config.js @@ -4,198 +4,190 @@ */ module.exports = { - // All imported modules in your tests should be mocked automatically - // automock: false, - - // Stop running tests after `n` failures - // bail: 0, - - // The directory where Jest should store its cached dependency information - // cacheDirectory: "/private/var/folders/v3/swygw5ld38x59y9wtc2qv3fc0000gn/T/jest_dx", - - // Automatically clear mock calls, instances, contexts and results before every test - // clearMocks: false, - - // Indicates whether the coverage information should be collected while executing the test - // collectCoverage: false, - - // An array of glob patterns indicating a set of files for which coverage information should be collected - collectCoverageFrom: [ - "src/**/*.ts", - "migrations/*.ts", - ], - - // The directory where Jest should output its coverage files - // coverageDirectory: undefined, - - // An array of regexp pattern strings used to skip coverage collection - coveragePathIgnorePatterns: [ - "/node_modules/", - "/src/@types/" - ], - - // Indicates which provider should be used to instrument code for coverage - coverageProvider: "v8", - - // A list of reporter names that Jest uses when writing coverage reports - // coverageReporters: [ - // "json", - // "text", - // "lcov", - // "clover" - // ], - - // An object that configures minimum threshold enforcement for coverage results - // coverageThreshold: undefined, - - // A path to a custom dependency extractor - // dependencyExtractor: undefined, - - // Make calling deprecated APIs throw helpful error messages - // errorOnDeprecated: false, - - // The default configuration for fake timers - // fakeTimers: { - // "enableGlobally": false - // }, - - // Force coverage collection from ignored files using an array of glob patterns - // forceCoverageMatch: [], - - // A path to a module which exports an async function that is triggered once before all test suites - // globalSetup: './tests/setup.ts', - - // A path to a module which exports an async function that is triggered once after all test suites - // globalTeardown: undefined, - - // A set of global variables that need to be available in all test environments - // globals: {}, - - // The maximum amount of workers used to run your tests. Can be specified as % or a number. E.g. maxWorkers: 10% will use 10% of your CPU amount + 1 as the maximum worker number. maxWorkers: 2 will use a maximum of 2 workers. - // maxWorkers: "50%", - - // An array of directory names to be searched recursively up from the requiring module's location - // moduleDirectories: [ - // "node_modules" - // ], - - // An array of file extensions your modules use - // moduleFileExtensions: [ - // "js", - // "mjs", - // "cjs", - // "jsx", - // "ts", - // "tsx", - // "json", - // "node" - // ], - - // A map from regular expressions to module names or to arrays of module names that allow to stub out resources with a single module - // moduleNameMapper: {}, - - // An array of regexp pattern strings, matched against all module paths before considered 'visible' to the module loader - // modulePathIgnorePatterns: [], - - // Activates notifications for test results - // notify: false, - - // An enum that specifies notification mode. Requires { notify: true } - // notifyMode: "failure-change", - - // A preset that is used as a base for Jest's configuration - preset: 'ts-jest', - - // Run tests from one or more projects - // projects: undefined, - - // Use this configuration option to add custom reporters to Jest - // reporters: undefined, - - // Automatically reset mock state before every test - // resetMocks: false, - - // Reset the module registry before running each individual test - // resetModules: false, - - // A path to a custom resolver - // resolver: undefined, - - // Automatically restore mock state and implementation before every test - // restoreMocks: false, - - // The root directory that Jest should scan for tests and modules within - rootDir: '', - - // A list of paths to directories that Jest should use to search for files in - // roots: [ - // "" - // ], - - // Allows you to use a custom runner instead of Jest's default test runner - // runner: "jest-runner", - - // The paths to modules that run some code to configure or set up the testing environment before each test - // setupFiles: [], - - // A list of paths to modules that run some code to configure or set up the testing framework before each test - // setupFilesAfterEnv: [], - - // The number of seconds after which a test is considered as slow and reported as such in the results. - // slowTestThreshold: 5, - - // A list of paths to snapshot serializer modules Jest should use for snapshot testing - // snapshotSerializers: [], - - // The test environment that will be used for testing - // testEnvironment: "jest-environment-node", - - // Options that will be passed to the testEnvironment - // testEnvironmentOptions: {}, - - // Adds a location field to test results - // testLocationInResults: false, - - // The glob patterns Jest uses to detect test files - // testMatch: [ - // "**/__tests__/**/*.[jt]s?(x)", - // "**/?(*.)+(spec|test).[tj]s?(x)" - // ], - - // An array of regexp pattern strings that are matched against all test paths, matched tests are skipped - testPathIgnorePatterns: [ - "/node_modules/", - "/client/", - "/dist/" - ], - - // The regexp pattern or array of patterns that Jest uses to detect test files - // testRegex: [], - - // This option allows the use of a custom results processor - // testResultsProcessor: undefined, - - // This option allows use of a custom test runner - // testRunner: "jest-circus/runner", - - // A map from regular expressions to paths to transformers - transform: {}, - - // An array of regexp pattern strings that are matched against all source file paths, matched files will skip transformation - // transformIgnorePatterns: [ - // "/node_modules/", - // "\\.pnp\\.[^\\/]+$" - // ], - - // An array of regexp pattern strings that are matched against all modules before the module loader will automatically return a mock for them - // unmockedModulePathPatterns: undefined, - - // Indicates whether each individual test should be reported during the run - // verbose: undefined, - - // An array of regexp patterns that are matched against all source file paths before re-running tests in watch mode - // watchPathIgnorePatterns: [], - - // Whether to use watchman for file crawling - // watchman: true, - }; \ No newline at end of file + testTimeout: 1_000_000_000, + + // All imported modules in your tests should be mocked automatically + // automock: false, + + // Stop running tests after `n` failures + // bail: 0, + + // The directory where Jest should store its cached dependency information + // cacheDirectory: "/private/var/folders/v3/swygw5ld38x59y9wtc2qv3fc0000gn/T/jest_dx", + + // Automatically clear mock calls, instances, contexts and results before every test + // clearMocks: false, + + // Indicates whether the coverage information should be collected while executing the test + // collectCoverage: false, + + // An array of glob patterns indicating a set of files for which coverage information should be collected + collectCoverageFrom: ['src/**/*.ts', 'migrations/*.ts'], + + // The directory where Jest should output its coverage files + // coverageDirectory: undefined, + + // An array of regexp pattern strings used to skip coverage collection + coveragePathIgnorePatterns: ['/node_modules/', '/src/@types/'], + + // Indicates which provider should be used to instrument code for coverage + coverageProvider: 'v8', + + // A list of reporter names that Jest uses when writing coverage reports + // coverageReporters: [ + // "json", + // "text", + // "lcov", + // "clover" + // ], + + // An object that configures minimum threshold enforcement for coverage results + // coverageThreshold: undefined, + + // A path to a custom dependency extractor + // dependencyExtractor: undefined, + + // Make calling deprecated APIs throw helpful error messages + // errorOnDeprecated: false, + + // The default configuration for fake timers + // fakeTimers: { + // "enableGlobally": false + // }, + + // Force coverage collection from ignored files using an array of glob patterns + // forceCoverageMatch: [], + + // A path to a module which exports an async function that is triggered once before all test suites + // globalSetup: './tests/setup.ts', + + // A path to a module which exports an async function that is triggered once after all test suites + // globalTeardown: undefined, + + // A set of global variables that need to be available in all test environments + // globals: {}, + + // The maximum amount of workers used to run your tests. Can be specified as % or a number. E.g. maxWorkers: 10% will use 10% of your CPU amount + 1 as the maximum worker number. maxWorkers: 2 will use a maximum of 2 workers. + // maxWorkers: "50%", + + // An array of directory names to be searched recursively up from the requiring module's location + // moduleDirectories: [ + // "node_modules" + // ], + + // An array of file extensions your modules use + // moduleFileExtensions: [ + // "js", + // "mjs", + // "cjs", + // "jsx", + // "ts", + // "tsx", + // "json", + // "node" + // ], + + // A map from regular expressions to module names or to arrays of module names that allow to stub out resources with a single module + // moduleNameMapper: {}, + + // An array of regexp pattern strings, matched against all module paths before considered 'visible' to the module loader + // modulePathIgnorePatterns: [], + + // Activates notifications for test results + // notify: false, + + // An enum that specifies notification mode. Requires { notify: true } + // notifyMode: "failure-change", + + // A preset that is used as a base for Jest's configuration + preset: 'ts-jest', + + // Run tests from one or more projects + // projects: undefined, + + // Use this configuration option to add custom reporters to Jest + // reporters: undefined, + + // Automatically reset mock state before every test + // resetMocks: false, + + // Reset the module registry before running each individual test + // resetModules: false, + + // A path to a custom resolver + // resolver: undefined, + + // Automatically restore mock state and implementation before every test + // restoreMocks: false, + + // The root directory that Jest should scan for tests and modules within + rootDir: '', + + // A list of paths to directories that Jest should use to search for files in + // roots: [ + // "" + // ], + + // Allows you to use a custom runner instead of Jest's default test runner + // runner: "jest-runner", + + // The paths to modules that run some code to configure or set up the testing environment before each test + // setupFiles: [], + + // A list of paths to modules that run some code to configure or set up the testing framework before each test + // setupFilesAfterEnv: [], + + // The number of seconds after which a test is considered as slow and reported as such in the results. + // slowTestThreshold: 5, + + // A list of paths to snapshot serializer modules Jest should use for snapshot testing + // snapshotSerializers: [], + + // The test environment that will be used for testing + // testEnvironment: "jest-environment-node", + + // Options that will be passed to the testEnvironment + // testEnvironmentOptions: {}, + + // Adds a location field to test results + // testLocationInResults: false, + + // The glob patterns Jest uses to detect test files + // testMatch: [ + // "**/__tests__/**/*.[jt]s?(x)", + // "**/?(*.)+(spec|test).[tj]s?(x)" + // ], + + // An array of regexp pattern strings that are matched against all test paths, matched tests are skipped + testPathIgnorePatterns: ['/node_modules/', '/client/', '/dist/'], + + // The regexp pattern or array of patterns that Jest uses to detect test files + // testRegex: [], + + // This option allows the use of a custom results processor + // testResultsProcessor: undefined, + + // This option allows use of a custom test runner + // testRunner: "jest-circus/runner", + + // A map from regular expressions to paths to transformers + transform: {}, + + // An array of regexp pattern strings that are matched against all source file paths, matched files will skip transformation + // transformIgnorePatterns: [ + // "/node_modules/", + // "\\.pnp\\.[^\\/]+$" + // ], + + // An array of regexp pattern strings that are matched against all modules before the module loader will automatically return a mock for them + // unmockedModulePathPatterns: undefined, + + // Indicates whether each individual test should be reported during the run + // verbose: undefined, + + // An array of regexp patterns that are matched against all source file paths before re-running tests in watch mode + // watchPathIgnorePatterns: [], + + // Whether to use watchman for file crawling + // watchman: true, +}; diff --git a/package-lock.json b/package-lock.json index 5ef6cd2..0fe04eb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,13 +1,13 @@ { - "name": "stacks-blackbox-tests", - "version": "1.0.0", + "name": "stacks-functional-tests", + "version": "0.1.0", "lockfileVersion": 3, "requires": true, "packages": { "": { - "name": "stacks-blackbox-tests", - "version": "1.0.0", - "license": "ISC", + "name": "stacks-functional-tests", + "version": "0.1.0", + "license": "Apache-2.0", "dependencies": { "@hirosystems/api-toolkit": "^1.3.3", "@scure/btc-signer": "^1.2.1", @@ -17,7 +17,7 @@ "@stacks/network": "^6.13.0", "@stacks/stacking": "^6.13.0", "@stacks/transactions": "^6.13.0", - "@stacks/wallet-sdk": "^6.13.0", + "@stacks/wallet-sdk": "^6.16.1", "@types/node": "^20.11.5", "env-schema": "^5.2.1" }, @@ -2484,14 +2484,15 @@ "integrity": "sha512-+9jVqKhRSpsc591z5vX+X5Yyw+he/HCB4iQ/RYxw35CEPaY1gnsNE43nf9n9AaYjAQrTiI/mOwKUKdUs9vf7Xg==" }, "node_modules/@stacks/auth": { - "version": "6.13.0", - "resolved": "https://registry.npmjs.org/@stacks/auth/-/auth-6.13.0.tgz", - "integrity": "sha512-3a6FwP5yNngQfalu78MltQzCROL4l+MNngnCxFKo52EJfIdJp8TWKuwkzHN/jLzrvdUoq1lQjKlxoINCiUP03g==", - "dependencies": { - "@stacks/common": "^6.13.0", - "@stacks/encryption": "^6.13.0", - "@stacks/network": "^6.13.0", - "@stacks/profile": "^6.13.0", + "version": "6.16.1", + "resolved": "https://registry.npmjs.org/@stacks/auth/-/auth-6.16.1.tgz", + "integrity": "sha512-6Co7VZTlfvWVKEYXh+x2TD1e+3XmCPumJut1jRgW6pYPGruZ4Dz/R4xfkf9qX3MEJabLe4AfasSfoqftg0twTg==", + "license": "MIT", + "dependencies": { + "@stacks/common": "^6.16.0", + "@stacks/encryption": "^6.16.1", + "@stacks/network": "^6.16.0", + "@stacks/profile": "^6.16.1", "cross-fetch": "^3.1.5", "jsontokens": "^4.0.1" } @@ -2511,9 +2512,10 @@ } }, "node_modules/@stacks/common": { - "version": "6.13.0", - "resolved": "https://registry.npmjs.org/@stacks/common/-/common-6.13.0.tgz", - "integrity": "sha512-wwzyihjaSdmL6NxKvDeayy3dqM0L0Q2sawmdNtzJDi0FnXuJGm5PeapJj7bEfcI9XwI7Bw5jZoC6mCn9nc5YIw==", + "version": "6.16.0", + "resolved": "https://registry.npmjs.org/@stacks/common/-/common-6.16.0.tgz", + "integrity": "sha512-PnzvhrdGRMVZvxTulitlYafSK4l02gPCBBoI9QEoTqgSnv62oaOXhYAUUkTMFKxdHW1seVEwZsrahuXiZPIAwg==", + "license": "MIT", "dependencies": { "@types/bn.js": "^5.1.0", "@types/node": "^18.0.4" @@ -2528,14 +2530,15 @@ } }, "node_modules/@stacks/encryption": { - "version": "6.13.0", - "resolved": "https://registry.npmjs.org/@stacks/encryption/-/encryption-6.13.0.tgz", - "integrity": "sha512-CsacBxY1XBVXBuJ5erJPjB5FmQ8KGJ/ft02/pIM6WrJ31ZcBdkn2BPV1AsPSD5qsIkiMdHAe14WKIwm8M2SWtQ==", + "version": "6.16.1", + "resolved": "https://registry.npmjs.org/@stacks/encryption/-/encryption-6.16.1.tgz", + "integrity": "sha512-DtVNNW/iipyxxRDz73S9DbLfRmBMqQCCog89F1Q1i6JUnl2kBB1PR9SPQfYv9zcAJ37oHoNB4i4b2tJWYr01vg==", + "license": "MIT", "dependencies": { "@noble/hashes": "1.1.5", "@noble/secp256k1": "1.7.1", "@scure/bip39": "1.1.0", - "@stacks/common": "^6.13.0", + "@stacks/common": "^6.16.0", "@types/node": "^18.0.4", "base64-js": "^1.5.1", "bs58": "^5.0.0", @@ -2586,11 +2589,12 @@ } }, "node_modules/@stacks/network": { - "version": "6.13.0", - "resolved": "https://registry.npmjs.org/@stacks/network/-/network-6.13.0.tgz", - "integrity": "sha512-Ss/Da4BNyPBBj1OieM981fJ7SkevKqLPkzoI1+Yo7cYR2df+0FipIN++Z4RfpJpc8ne60vgcx7nJZXQsiGhKBQ==", + "version": "6.16.0", + "resolved": "https://registry.npmjs.org/@stacks/network/-/network-6.16.0.tgz", + "integrity": "sha512-uqz9Nb6uf+SeyCKENJN+idt51HAfEeggQKrOMfGjpAeFgZV2CR66soB/ci9+OVQR/SURvasncAz2ScI1blfS8A==", + "license": "MIT", "dependencies": { - "@stacks/common": "^6.13.0", + "@stacks/common": "^6.16.0", "cross-fetch": "^3.1.5" } }, @@ -2616,13 +2620,14 @@ } }, "node_modules/@stacks/profile": { - "version": "6.13.0", - "resolved": "https://registry.npmjs.org/@stacks/profile/-/profile-6.13.0.tgz", - "integrity": "sha512-IIOPtP+bHu53j426UTFn+JFgv9G3JyybtJ6TDcc4zxoMvs8sLKEVTyjZNFrP38DjkoAGo1qWNWqoJhURfL55Uw==", - "dependencies": { - "@stacks/common": "^6.13.0", - "@stacks/network": "^6.13.0", - "@stacks/transactions": "^6.13.0", + "version": "6.16.1", + "resolved": "https://registry.npmjs.org/@stacks/profile/-/profile-6.16.1.tgz", + "integrity": "sha512-FJcwKN6oVDfmwymivkZfm1PcO7gv5fcWN4HI+jtYdMftrl6yxAB4/XD63FSvshIeLPzBJjnCmaZSnPAV2mtdeA==", + "license": "MIT", + "dependencies": { + "@stacks/common": "^6.16.0", + "@stacks/network": "^6.16.0", + "@stacks/transactions": "^6.16.1", "jsontokens": "^4.0.1", "schema-inspector": "^2.0.2", "zone-file": "^2.0.0-beta.3" @@ -2676,27 +2681,29 @@ "integrity": "sha512-wcDSdgIZx/ttQfUTPtGJOIyEkTOjmCsC79TaIyxTIiihSgrGppqTuzkwHD/DyuQkcJtUZvDTxMsAXkBKShE1kw==" }, "node_modules/@stacks/storage": { - "version": "6.13.0", - "resolved": "https://registry.npmjs.org/@stacks/storage/-/storage-6.13.0.tgz", - "integrity": "sha512-BDgGBysgoo756SUGQ7vTtJKPBhZLBbl9UrO7YoAoVO8vfB569X7PiQbUxwE8R7iLutnlBgP+mnpGDhV9UQo1vA==", - "dependencies": { - "@stacks/auth": "^6.13.0", - "@stacks/common": "^6.13.0", - "@stacks/encryption": "^6.13.0", - "@stacks/network": "^6.13.0", + "version": "6.16.1", + "resolved": "https://registry.npmjs.org/@stacks/storage/-/storage-6.16.1.tgz", + "integrity": "sha512-bElxB03dg3XGTX8r/J8Os2tIsodcTglg7zeq6RU4FVUU7tUA+Agpmn9FKl8MmnsWfO4ls5UgeujyBaxUJ//yAw==", + "license": "MIT", + "dependencies": { + "@stacks/auth": "^6.16.1", + "@stacks/common": "^6.16.0", + "@stacks/encryption": "^6.16.1", + "@stacks/network": "^6.16.0", "base64-js": "^1.5.1", "jsontokens": "^4.0.1" } }, "node_modules/@stacks/transactions": { - "version": "6.13.0", - "resolved": "https://registry.npmjs.org/@stacks/transactions/-/transactions-6.13.0.tgz", - "integrity": "sha512-xrx09qsXL/tWCkvAArzsFQqtZKDXyedjdVB9uX8xw+cQCi3xZ7r5MHMKzvEsTgJz3EO+MkQBXcvI1uzfuoqhcA==", + "version": "6.16.1", + "resolved": "https://registry.npmjs.org/@stacks/transactions/-/transactions-6.16.1.tgz", + "integrity": "sha512-yCtUM+8IN0QJbnnlFhY1wBW7Q30Cxje3Zmy8DgqdBoM/EPPWadez/8wNWFANVAMyUZeQ9V/FY+8MAw4E+pCReA==", + "license": "MIT", "dependencies": { "@noble/hashes": "1.1.5", "@noble/secp256k1": "1.7.1", - "@stacks/common": "^6.13.0", - "@stacks/network": "^6.13.0", + "@stacks/common": "^6.16.0", + "@stacks/network": "^6.16.0", "c32check": "^2.0.0", "lodash.clonedeep": "^4.5.0" } @@ -2713,19 +2720,20 @@ ] }, "node_modules/@stacks/wallet-sdk": { - "version": "6.13.0", - "resolved": "https://registry.npmjs.org/@stacks/wallet-sdk/-/wallet-sdk-6.13.0.tgz", - "integrity": "sha512-2+jJ3SWrhPVLc4mokFekwqPLU8tP6ffDC379A4I2xrKWwPk3zjx3/SlqtUnf8CJkwgmsBozRS6SBqd7obIvQAg==", + "version": "6.16.1", + "resolved": "https://registry.npmjs.org/@stacks/wallet-sdk/-/wallet-sdk-6.16.1.tgz", + "integrity": "sha512-QYm/BfRpHZfD5FjvaOJp0hy8yeqde6qrEmSrcIl06IC2SNr4R5NOy0xK/RPUgJFB1/Gd16HbqS9EdyV3o6ybwg==", + "license": "MIT", "dependencies": { "@scure/bip32": "1.1.3", "@scure/bip39": "1.1.0", - "@stacks/auth": "^6.13.0", - "@stacks/common": "^6.13.0", - "@stacks/encryption": "^6.13.0", - "@stacks/network": "^6.13.0", - "@stacks/profile": "^6.13.0", - "@stacks/storage": "^6.13.0", - "@stacks/transactions": "^6.13.0", + "@stacks/auth": "^6.16.1", + "@stacks/common": "^6.16.0", + "@stacks/encryption": "^6.16.1", + "@stacks/network": "^6.16.0", + "@stacks/profile": "^6.16.1", + "@stacks/storage": "^6.16.1", + "@stacks/transactions": "^6.16.1", "buffer": "^6.0.3", "c32check": "^2.0.0", "jsontokens": "^4.0.1", @@ -3525,6 +3533,7 @@ "version": "2.6.4", "resolved": "https://registry.npmjs.org/async/-/async-2.6.4.tgz", "integrity": "sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==", + "license": "MIT", "dependencies": { "lodash": "^4.17.14" } @@ -8510,6 +8519,7 @@ "version": "4.0.1", "resolved": "https://registry.npmjs.org/jsontokens/-/jsontokens-4.0.1.tgz", "integrity": "sha512-+MO415LEN6M+3FGsRz4wU20g7N2JA+2j9d9+pGaNJHviG4L8N0qzavGyENw6fJqsq9CcrHOIL6iWX5yeTZ86+Q==", + "license": "MIT", "dependencies": { "@noble/hashes": "^1.1.2", "@noble/secp256k1": "^1.6.3", @@ -10303,6 +10313,7 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/schema-inspector/-/schema-inspector-2.1.0.tgz", "integrity": "sha512-3bmQVhbA01/EW8cZin4vIpqlpNU2SIy4BhKCfCgogJ3T/L76dLx3QAE+++4o+dNT33sa+SN9vOJL7iHiHFjiNg==", + "license": "MIT", "dependencies": { "async": "~2.6.3" } @@ -11612,6 +11623,7 @@ "version": "2.0.0-beta.3", "resolved": "https://registry.npmjs.org/zone-file/-/zone-file-2.0.0-beta.3.tgz", "integrity": "sha512-6tE3PSRcpN5lbTTLlkLez40WkNPc9vw/u1J2j6DBiy0jcVX48nCkWrx2EC+bWHqC2SLp069Xw4AdnYn/qp/W5g==", + "license": "ISC", "engines": { "node": ">=10" } diff --git a/package.json b/package.json index f565d08..49e118f 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,8 @@ "description": "", "main": "index.js", "scripts": { - "test": "jest --runInBand" + "test": "jest --runInBand", + "test:regtest": "jest --runInBand --testNamePattern='regtest'" }, "author": "", "license": "Apache-2.0", @@ -38,7 +39,7 @@ "@stacks/network": "^6.13.0", "@stacks/stacking": "^6.13.0", "@stacks/transactions": "^6.13.0", - "@stacks/wallet-sdk": "^6.13.0", + "@stacks/wallet-sdk": "^6.16.1", "@types/node": "^20.11.5", "env-schema": "^5.2.1" } diff --git a/settings/Devnet.toml b/settings/Devnet.toml new file mode 100644 index 0000000..52a118c --- /dev/null +++ b/settings/Devnet.toml @@ -0,0 +1,154 @@ +[network] +name = "devnet" +deployment_fee_rate = 10 + +[accounts.deployer] +mnemonic = "twice kind fence tip hidden tilt action fragile skin nothing glory cousin green tomorrow spring wrist shed math olympic multiply hip blue scout claw" +balance = 100_000_000_000_000 +# secret_key: 753b7cc01a1a2e86221266a154af739463fce51219d97e4f856cd7200c3bd2a601 +# stx_address: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM +# btc_address: mqVnk6NPRdhntvfm4hh9vvjiRkFDUuSYsH + +[accounts.wallet_1] +mnemonic = "sell invite acquire kitten bamboo drastic jelly vivid peace spawn twice guilt pave pen trash pretty park cube fragile unaware remain midnight betray rebuild" +balance = 100_000_000_000_000 +# secret_key: 7287ba251d44a4d3fd9276c88ce34c5c52a038955511cccaf77e61068649c17801 +# stx_address: ST1SJ3DTE5DN7X54YDH5D64R3BCB6A2AG2ZQ8YPD5 +# btc_address: mr1iPkD9N3RJZZxXRk7xF9d36gffa6exNC + +[accounts.wallet_2] +mnemonic = "hold excess usual excess ring elephant install account glad dry fragile donkey gaze humble truck breeze nation gasp vacuum limb head keep delay hospital" +balance = 100_000_000_000_000 +# secret_key: 530d9f61984c888536871c6573073bdfc0058896dc1adfe9a6a10dfacadc209101 +# stx_address: ST2CY5V39NHDPWSXMW9QDT3HC3GD6Q6XX4CFRK9AG +# btc_address: muYdXKmX9bByAueDe6KFfHd5Ff1gdN9ErG + +[accounts.wallet_3] +mnemonic = "cycle puppy glare enroll cost improve round trend wrist mushroom scorpion tower claim oppose clever elephant dinosaur eight problem before frozen dune wagon high" +balance = 100_000_000_000_000 +# secret_key: d655b2523bcd65e34889725c73064feb17ceb796831c0e111ba1a552b0f31b3901 +# stx_address: ST2JHG361ZXG51QTKY2NQCVBPPRRE2KZB1HR05NNC +# btc_address: mvZtbibDAAA3WLpY7zXXFqRa3T4XSknBX7 + +[accounts.wallet_4] +mnemonic = "board list obtain sugar hour worth raven scout denial thunder horse logic fury scorpion fold genuine phrase wealth news aim below celery when cabin" +balance = 100_000_000_000_000 +# secret_key: f9d7206a47f14d2870c163ebab4bf3e70d18f5d14ce1031f3902fbbc894fe4c701 +# stx_address: ST2NEB84ASENDXKYGJPQW86YXQCEFEX2ZQPG87ND +# btc_address: mg1C76bNTutiCDV3t9nWhZs3Dc8LzUufj8 + +[accounts.wallet_5] +mnemonic = "hurry aunt blame peanut heavy update captain human rice crime juice adult scale device promote vast project quiz unit note reform update climb purchase" +balance = 100_000_000_000_000 +# secret_key: 3eccc5dac8056590432db6a35d52b9896876a3d5cbdea53b72400bc9c2099fe801 +# stx_address: ST2REHHS5J3CERCRBEPMGH7921Q6PYKAADT7JP2VB +# btc_address: mweN5WVqadScHdA81aATSdcVr4B6dNokqx + +[accounts.wallet_6] +mnemonic = "area desk dutch sign gold cricket dawn toward giggle vibrant indoor bench warfare wagon number tiny universe sand talk dilemma pottery bone trap buddy" +balance = 100_000_000_000_000 +# secret_key: 7036b29cb5e235e5fd9b09ae3e8eec4404e44906814d5d01cbca968a60ed4bfb01 +# stx_address: ST3AM1A56AK2C1XAFJ4115ZSV26EB49BVQ10MGCS0 +# btc_address: mzxXgV6e4BZSsz8zVHm3TmqbECt7mbuErt + +[accounts.wallet_7] +mnemonic = "prevent gallery kind limb income control noise together echo rival record wedding sense uncover school version force bleak nuclear include danger skirt enact arrow" +balance = 100_000_000_000_000 +# secret_key: b463f0df6c05d2f156393eee73f8016c5372caa0e9e29a901bb7171d90dc4f1401 +# stx_address: ST3PF13W7Z0RRM42A8VZRVFQ75SV1K26RXEP8YGKJ +# btc_address: n37mwmru2oaVosgfuvzBwgV2ysCQRrLko7 + +[accounts.wallet_8] +mnemonic = "female adjust gallery certain visit token during great side clown fitness like hurt clip knife warm bench start reunion globe detail dream depend fortune" +balance = 100_000_000_000_000 +# secret_key: 6a1a754ba863d7bab14adbbc3f8ebb090af9e871ace621d3e5ab634e1422885e01 +# stx_address: ST3NBRSFKX28FQ2ZJ1MAKX58HKHSDGNV5N7R21XCP +# btc_address: n2v875jbJ4RjBnTjgbfikDfnwsDV5iUByw + +[accounts.faucet] +mnemonic = "shadow private easily thought say logic fault paddle word top book during ignore notable orange flight clock image wealth health outside kitten belt reform" +balance = 100_000_000_000_000 +# secret_key: de433bdfa14ec43aa1098d5be594c8ffb20a31485ff9de2923b2689471c401b801 +# stx_address: STNHKEPYEPJ8ET55ZZ0M5A34J0R3N5FM2CMMMAZ6 +# btc_address: mjSrB3wS4xab3kYqFktwBzfTdPg367ZJ2d + +[devnet] +disable_stacks_explorer = false +disable_stacks_api = false + +bitcoin_controller_block_time = 1000 + +# disable_subnet_api = false +# disable_bitcoin_explorer = true +# working_dir = "tmp/devnet" +# stacks_node_events_observers = ["host.docker.internal:8002"] +# miner_mnemonic = "fragile loan twenty basic net assault jazz absorb diet talk art shock innocent float punch travel gadget embrace caught blossom hockey surround initial reduce" +# miner_derivation_path = "m/44'/5757'/0'/0/0" +# faucet_mnemonic = "shadow private easily thought say logic fault paddle word top book during ignore notable orange flight clock image wealth health outside kitten belt reform" +# faucet_derivation_path = "m/44'/5757'/0'/0/0" +# orchestrator_port = 20445 +# bitcoin_node_p2p_port = 18444 +# bitcoin_node_rpc_port = 18443 +# bitcoin_node_username = "devnet" +# bitcoin_node_password = "devnet" +# bitcoin_controller_block_time = 30_000 +# stacks_node_rpc_port = 20443 +# stacks_node_p2p_port = 20444 +# stacks_api_port = 3999 +# stacks_api_events_port = 3700 +# bitcoin_explorer_port = 8001 +# stacks_explorer_port = 8000 +# postgres_port = 5432 +# postgres_username = "postgres" +# postgres_password = "postgres" +# postgres_database = "postgres" +# bitcoin_node_image_url = "quay.io/hirosystems/bitcoind:26.0" +# stacks_node_image_url = "quay.io/hirosystems/stacks-node:devnet-2.5" +# stacks_signer_image_url = "quay.io/hirosystems/stacks-signer:devnet-2.5" +# stacks_api_image_url = "hirosystems/stacks-blockchain-api:master" +# stacks_explorer_image_url = "hirosystems/explorer:latest" +# bitcoin_explorer_image_url = "quay.io/hirosystems/bitcoin-explorer:devnet" +# postgres_image_url = "postgres:alpine" +# enable_subnet_node = true +# subnet_node_image_url = "hirosystems/stacks-subnets:0.8.1" +# subnet_leader_mnemonic = "twice kind fence tip hidden tilt action fragile skin nothing glory cousin green tomorrow spring wrist shed math olympic multiply hip blue scout claw" +# subnet_leader_derivation_path = "m/44'/5757'/0'/0/0" +# subnet_contract_id = "ST173JK7NZBA4BS05ZRATQH1K89YJMTGEH1Z5J52E.subnet-v3-0-1" +# subnet_node_rpc_port = 30443 +# subnet_node_p2p_port = 30444 +# subnet_events_ingestion_port = 30445 +# subnet_node_events_observers = ["host.docker.internal:8002"] +# subnet_api_image_url = "hirosystems/stacks-blockchain-api:master" +# subnet_api_postgres_database = "subnet_api" + +# For testing in epoch 2.1 / using Clarity2 +# epoch_2_0 = 100 +# epoch_2_05 = 100 +# epoch_2_1 = 101 +# epoch_2_2 = 102 +# epoch_2_3 = 103 +# epoch_2_4 = 104 +# epoch_2_5 = 108 + + +# Send some stacking orders +[[devnet.pox_stacking_orders]] +start_at_cycle = 1 +duration = 12 +wallet = "wallet_1" +slots = 2 +btc_address = "mr1iPkD9N3RJZZxXRk7xF9d36gffa6exNC" + +[[devnet.pox_stacking_orders]] +start_at_cycle = 1 +duration = 12 +wallet = "wallet_2" +slots = 1 +btc_address = "muYdXKmX9bByAueDe6KFfHd5Ff1gdN9ErG" + +[[devnet.pox_stacking_orders]] +start_at_cycle = 1 +duration = 12 +wallet = "wallet_3" +slots = 1 +btc_address = "mvZtbibDAAA3WLpY7zXXFqRa3T4XSknBX7" diff --git a/src/env.ts b/src/env.ts index 13c6530..deca89d 100644 --- a/src/env.ts +++ b/src/env.ts @@ -2,58 +2,56 @@ import { Static, Type } from '@sinclair/typebox'; import envSchema from 'env-schema'; const schema = Type.Object({ - STACKS_CHAIN: Type.Enum({ mainnet: 'mainnet', testnet: 'testnet' }), - /** STX address of the issuer of all transactions we will be testing */ - SENDER_STX_ADDRESS: Type.String(), - /** `SENDER_STX_ADDRESS`'s hex private key */ - SENDER_KEY: Type.String(), - /** STX address of the receiver of any sent tokens */ - RECEIVER_STX_ADDRESS: Type.String(), + STACKS_CHAIN: Type.Enum({ mainnet: 'mainnet', testnet: 'testnet' }, { default: 'testnet' }), - /** Stacks Blockchain API host */ - STACKS_API: Type.String(), + /** Stacks API host */ + STACKS_API: Type.String({ default: 'http://localhost:3999' }), /** Stacks node host */ - STACKS_NODE: Type.String(), + STACKS_NODE: Type.String({ default: 'http://localhost:20443' }), - STACKS_TX_TIMEOUT: Type.Integer({ default: 15_000 }), - - POLL_INTERVAL: Type.Integer({ default: 1000 }), - RETRY_INTERVAL: Type.Integer({ default: 500 }), - - /** List of pre-funded STX addresses on regtest-env */ - REGTEST_KEYS: Type.Array(Type.String(), { + /** List of pre-funded STX accounts on devnet (wallet 4, 5, 6, 1, 2, 3) */ + PRIVATE_KEYS: Type.Array(Type.String(), { default: [ - // taken from regtest-env `stacks-kryton-miner.toml` - 'cb3df38053d132895220b9ce471f6b676db5b9bf0b4adefb55f2118ece2478df01', - '21d43d2ae0da1d9d04cfcaac7d397a33733881081f0b2cd038062cf0ccbb752601', - '5b8303150239eceaba43892af7cdd1fa7fc26eda5182ebaaa568e3341d54a4d001', + // taken from `settings/Devnet.toml` + 'f9d7206a47f14d2870c163ebab4bf3e70d18f5d14ce1031f3902fbbc894fe4c701', + '3eccc5dac8056590432db6a35d52b9896876a3d5cbdea53b72400bc9c2099fe801', + '7036b29cb5e235e5fd9b09ae3e8eec4404e44906814d5d01cbca968a60ed4bfb01', + '7287ba251d44a4d3fd9276c88ce34c5c52a038955511cccaf77e61068649c17801', // signer + '530d9f61984c888536871c6573073bdfc0058896dc1adfe9a6a10dfacadc209101', // signer + 'd655b2523bcd65e34889725c73064feb17ceb796831c0e111ba1a552b0f31b3901', // signer ], }), - /** - * Signer private key for generating signatures. - * On regtest-env, this should be the private key of a participating signer. - */ - SIGNER_KEY: Type.String({ - default: '7036b29cb5e235e5fd9b09ae3e8eec4404e44906814d5d01cbca968a60ed4bfb01', + + /** Wallet seed phrase of pre-funded wallet on devnet (wallet 4) */ + WALLET_SEED: Type.String({ + default: + // taken from `settings/Devnet.toml` + 'board list obtain sugar hour worth raven scout denial thunder horse logic fury scorpion fold genuine phrase wealth news aim below celery when cabin', }), /** * Command to run to start regtest-env. * e.g. this could `cd` into the regtest-env directory and run `docker compose up -d` */ - REGTEST_UP_CMD: Type.String({ default: "echo 'no-op'" }), + NETWORK_UP_CMD: Type.String({ default: "echo 'no-op'" }), /** * Command to run to stop regtest-env. * e.g. this could `cd` into the regtest-env directory and run `docker compose down` */ - REGTEST_DOWN_CMD: Type.String({ default: "echo 'no-op'" }), + NETWORK_DOWN_CMD: Type.String({ default: "echo 'no-op'" }), /** * If true, doesn't wait for unlock and verifying rewards in regtest tests. * Useful for speeding up tests when running many long-running regtest-env tests */ - REGTEST_SKIP_UNLOCK: Type.Boolean({ default: false }), + SKIP_UNLOCK: Type.Boolean({ default: false }), + + POLL_INTERVAL: Type.Integer({ default: 750 }), + RETRY_INTERVAL: Type.Integer({ default: 500 }), + + STACKS_TX_TIMEOUT: Type.Integer({ default: 10_000 }), + BITCOIN_TX_TIMEOUT: Type.Integer({ default: 15_000 }), }); type Env = Static; diff --git a/src/helpers.ts b/src/helpers.ts index 42cff31..6ad24d6 100644 --- a/src/helpers.ts +++ b/src/helpers.ts @@ -19,6 +19,7 @@ import { getAddressFromPrivateKey, getPublicKey, } from '@stacks/transactions'; +import { Wallet, generateNewAccount, generateWallet } from '@stacks/wallet-sdk'; import { ENV } from './env'; import { withRetry, withTimeout } from './utils'; @@ -30,16 +31,6 @@ export function newSocketClient(): StacksApiSocketClient { } export function stacksNetwork(): StacksNetwork { - const url = ENV.STACKS_NODE; - switch (ENV.STACKS_CHAIN) { - case 'mainnet': - return new StacksMainnet({ url }); - case 'testnet': - return new StacksTestnet({ url }); - } -} - -export function stacksNetworkApi(): StacksNetwork { const url = ENV.STACKS_API; switch (ENV.STACKS_CHAIN) { case 'mainnet': @@ -86,16 +77,19 @@ export function isInPreparePhase(blockHeight: number, poxInfo: PoxInfo): boolean // return pos === 0 || pos > poxInfo.reward_cycle_length - poxInfo.prepare_phase_block_length; } -export async function getNextNonce(fromStacksNode: boolean = true): Promise { +export async function getNextNonce( + address: string, + fromStacksNode: boolean = true +): Promise { const config = new Configuration({ basePath: ENV.STACKS_API, }); const api = new AccountsApi(config); if (fromStacksNode) { - const result = await api.getAccountInfo({ principal: ENV.SENDER_STX_ADDRESS }); + const result = await api.getAccountInfo({ principal: address }); return result.nonce; } else { - const result = await api.getAccountNonces({ principal: ENV.SENDER_STX_ADDRESS }); + const result = await api.getAccountNonces({ principal: address }); return result.possible_next_nonce; } } @@ -180,8 +174,19 @@ export async function getPox4Events() { ); } +async function getInfoStatus() { + const config = new Configuration({ + basePath: ENV.STACKS_API, + }); + const api = new InfoApi(config); + return await Promise.race([ + api.getStatus(), + new Promise((_, reject) => setTimeout(() => reject(new Error('Timeout')), ENV.RETRY_INTERVAL)), + ]); +} + export function getAccount(key: string) { - const network = stacksNetworkApi(); + const network = stacksNetwork(); const address = getAddressFromPrivateKey( key, network.isMainnet() ? TransactionVersion.Mainnet : TransactionVersion.Testnet @@ -200,19 +205,19 @@ export function getAccount(key: string) { }; } -async function getInfoStatus() { - const config = new Configuration({ - basePath: ENV.STACKS_API, +export async function getWalletAccounts(seed: string) { + const wallet = await generateWallet({ + secretKey: seed, + password: '', }); - const api = new InfoApi(config); - return await Promise.race([ - api.getStatus(), - new Promise((_, reject) => setTimeout(() => reject(new Error('Timeout')), ENV.RETRY_INTERVAL)), - ]); + const accounts = Array.from({ length: 10 }) + .reduce((acc: Wallet) => generateNewAccount(acc), wallet) + .accounts.map(a => getAccount(a.stxPrivateKey)); + return accounts; } -export async function waitForNode() { - console.log('waiting for node...'); +export async function waitForNetwork() { + console.log('waiting for network...'); await withRetry(1_000, getInfoStatus)(); } @@ -255,13 +260,14 @@ export async function waitForRewardPhase(poxInfo: PoxInfo) { * @param interval - How often to poll the node */ export async function waitForNextNonce( + address: string, currentNonce: number, interval: number = ENV.POLL_INTERVAL ): Promise { let next: number = currentNonce; while (next != currentNonce + 1) { await timeout(interval); - next = await getNextNonce(); + next = await getNextNonce(address); } } @@ -270,11 +276,29 @@ export async function waitForBurnBlockHeight( burnBlockHeight: number, interval: number = ENV.POLL_INTERVAL ): Promise { - let height: number = -1; - while (height < burnBlockHeight) { + await timeout(100); // let the env catch up + + let lastHeight = -1; + let lastHeightTime = Date.now(); + + while (true) { + const currentHeight = await getBurnBlockHeight(); + + if (currentHeight >= burnBlockHeight) break; + + if (currentHeight === lastHeight) { + if (Date.now() - lastHeightTime > ENV.BITCOIN_TX_TIMEOUT) { + throw new Error( + `Burn block height hasn't changed for ${ENV.BITCOIN_TX_TIMEOUT} milliseconds` + ); + } + } else { + lastHeight = currentHeight; + lastHeightTime = Date.now(); + console.log(`waiting for burn block ${burnBlockHeight} (current ${currentHeight})`); + } + await timeout(interval); - height = await getBurnBlockHeight(); - console.log('waiting', height, '<', burnBlockHeight); } } diff --git a/src/tests/regtest-caller.test.ts b/src/tests/regtest-caller.test.ts index 4478528..d1a8a60 100644 --- a/src/tests/regtest-caller.test.ts +++ b/src/tests/regtest-caller.test.ts @@ -8,12 +8,10 @@ import { broadcastAndWaitForTransaction, getAccount, waitForBurnBlockHeight, - waitForNode, + waitForNetwork, waitForTransaction, } from '../helpers'; -import { startRegtestEnv, stopRegtestEnv, withRetry } from '../utils'; - -jest.setTimeout(1_000_000_000); +import { networkEnvUp, networkEnvDown, withRetry } from '../utils'; describe('regtest-env pox-4 caller', () => { const network = new StacksDevnet({ fetchFn: withRetry(3, fetch) }); // this test only works on regtest-env @@ -21,14 +19,14 @@ describe('regtest-env pox-4 caller', () => { let poxInfo: PoxInfo; let client: StackingClient; - const pool = getAccount(ENV.REGTEST_KEYS[0]) as ReturnType & { + const pool = getAccount(ENV.PRIVATE_KEYS[0]) as ReturnType & { wrappedClient: StackingClient; }; beforeEach(async () => { // SETUP - await startRegtestEnv(); - await waitForNode(); + await networkEnvUp(); + await waitForNetwork(); // POX-4 PREP client = new StackingClient('', network); @@ -63,7 +61,7 @@ describe('regtest-env pox-4 caller', () => { }); afterEach(async () => { - await stopRegtestEnv(); + await networkEnvDown(); }); async function deployWrapperContract() { @@ -99,7 +97,7 @@ describe('regtest-env pox-4 caller', () => { // alice tries to use the pool as a caller // the transaction should fail - const alice = getAccount(ENV.REGTEST_KEYS[1]); + const alice = getAccount(ENV.PRIVATE_KEYS[1]); const amount = BigInt(poxInfo.min_amount_ustx) * 2n; @@ -176,7 +174,7 @@ describe('regtest-env pox-4 caller', () => { }); describe('caller', () => { - const alice = getAccount(ENV.REGTEST_KEYS[1]); + const alice = getAccount(ENV.PRIVATE_KEYS[1]); test('Allowed contract cannot remove permission', async () => { // TEST CASE @@ -220,7 +218,7 @@ describe('regtest-env pox-4 caller', () => { // alice tries to disallow pool via a caller (via wrapper contract) // the transaction should fail - const bob = getAccount(ENV.REGTEST_KEYS[2]); + const bob = getAccount(ENV.PRIVATE_KEYS[2]); // TRANSACTION (alice allow-contract-caller) const [contractAddress, contractName] = client.parseContractId(poxInfo.contract_id); @@ -370,7 +368,7 @@ describe('regtest-env pox-4 caller', () => { // alice revoke-delegate-stx (via wrapper contract) // the transaction should fail - const bob = getAccount(ENV.REGTEST_KEYS[2]); + const bob = getAccount(ENV.PRIVATE_KEYS[2]); // TRANSACTION (alice allow-contract-caller) const [contractAddress, contractName] = client.parseContractId(poxInfo.contract_id); diff --git a/src/tests/regtest.test.ts b/src/tests/regtest.test.ts index ec30c3c..86b96c8 100644 --- a/src/tests/regtest.test.ts +++ b/src/tests/regtest.test.ts @@ -23,13 +23,13 @@ import { getRewards, isInPreparePhase, waitForBurnBlockHeight, + waitForNetwork, waitForNextCycle, - waitForNode, waitForPreparePhase, waitForRewardPhase, waitForTransaction, } from '../helpers'; -import { startRegtestEnv, stopRegtestEnv, storeEventsTsv, withRetry } from '../utils'; +import { networkEnvDown, networkEnvUp, withRetry } from '../utils'; jest.setTimeout(1_000_000_000); @@ -38,20 +38,20 @@ describe('regtest-env pox-4', () => { let poxInfo: PoxInfo; beforeEach(async () => { - await startRegtestEnv(); - await waitForNode(); + await networkEnvUp(); + await waitForNetwork(); }); afterEach(async () => { - await stopRegtestEnv(); + await networkEnvDown(); }); test('stack-stx (in reward-phase)', async () => { // TEST CASE // steph is a solo stacker and stacks in a reward-phase // but steph doesn't run a signer, so we need to use a different signer key - const steph = getAccount(ENV.REGTEST_KEYS[0]); - const signer = getAccount(ENV.SIGNER_KEY); + const steph = getAccount(ENV.PRIVATE_KEYS[0]); + const signer = getAccount(ENV.PRIVATE_KEYS[3]); // PREP const client = new StackingClient(steph.address, network); @@ -83,7 +83,7 @@ describe('regtest-env pox-4', () => { maxAmount: amount, authId, }); - const { txid } = await client.stack({ + const res = await client.stack({ amountMicroStx: amount, poxAddress: steph.btcAddress, cycles: lockPeriod, @@ -94,15 +94,13 @@ describe('regtest-env pox-4', () => { authId, privateKey: steph.key, }); - console.log('txid', txid); + console.log('res', res); + console.log('txid', res.txid); - const result = await waitForTransaction(txid); + const result = await waitForTransaction(res.txid); expect(result.tx_result.repr).toContain('(ok'); expect(result.tx_status).toBe('success'); - await timeout(1000); // current-cycle: 5 - await storeEventsTsv('S1'); // snapshot 1 (stacking tx was successful) - // CHECK POX-4 EVENTS const { results } = await getPox4Events(); const datas = results @@ -134,15 +132,13 @@ describe('regtest-env pox-4', () => { await waitForPreparePhase(poxInfo); // height: 116 - await storeEventsTsv('S2'); // snapshot 2 (in prepare phase, pox-anchor block was mined, pox-set has been sent for cycle 6) await waitForNextCycle(poxInfo); poxInfo = await client.getPoxInfo(); // height: 120, current-cycle: 6 - await storeEventsTsv('S3'); // snapshot 3 (steph is stacked in the current cycle) - if (ENV.REGTEST_SKIP_UNLOCK) return; + if (ENV.SKIP_UNLOCK) return; await waitForBurnBlockHeight(info.details.unlock_height + 2); info = await client.getStatus(); expect(info.stacked).toBeFalsy(); @@ -153,7 +149,6 @@ describe('regtest-env pox-4', () => { expect(reward.burn_block_height).toBeGreaterThan(stackHeight); // EXPORT EVENTS - await storeEventsTsv(); }); test('stack-stx (before prepare-phase)', async () => { @@ -161,8 +156,8 @@ describe('regtest-env pox-4', () => { // steph is a solo stacker and stacks on a prepare-phase start (not deep in // the prepare phase) // but steph doesn't run a signer, so we need to use a different signer key - const steph = getAccount(ENV.REGTEST_KEYS[0]); - const signer = getAccount(ENV.SIGNER_KEY); + const steph = getAccount(ENV.PRIVATE_KEYS[0]); + const signer = getAccount(ENV.PRIVATE_KEYS[3]); // PREP const client = new StackingClient(steph.address, network); @@ -246,9 +241,8 @@ describe('regtest-env pox-4', () => { poxInfo = await client.getPoxInfo(); await waitForNextCycle(poxInfo); - await storeEventsTsv('S1'); // snapshot 1 (steph is stacked in the current cycle) - if (ENV.REGTEST_SKIP_UNLOCK) return; + if (ENV.SKIP_UNLOCK) return; await waitForBurnBlockHeight(info.details.unlock_height + 2); info = await client.getStatus(); expect(info.stacked).toBeFalsy(); @@ -259,7 +253,6 @@ describe('regtest-env pox-4', () => { expect(reward.burn_block_height).toBeGreaterThan(stackHeight); // EXPORT EVENTS - await storeEventsTsv(); }); test('stack-stx (in prepare-phase)', async () => { @@ -268,8 +261,8 @@ describe('regtest-env pox-4', () => { // prepare-phase has started, which is considered a neglected prepare-phase // for stacking -- this should result in no rewards being paid out. // but steph doesn't run a signer, so we need to use a different signer key - const steph = getAccount(ENV.REGTEST_KEYS[0]); - const signer = getAccount(ENV.SIGNER_KEY); + const steph = getAccount(ENV.PRIVATE_KEYS[0]); + const signer = getAccount(ENV.PRIVATE_KEYS[3]); // PREP const client = new StackingClient(steph.address, network); @@ -352,9 +345,8 @@ describe('regtest-env pox-4', () => { poxInfo = await client.getPoxInfo(); await waitForNextCycle(poxInfo); - await storeEventsTsv('S1'); // snapshot 1 (steph is stacked, but didn't make it in time for rewards) - if (ENV.REGTEST_SKIP_UNLOCK) return; + if (ENV.SKIP_UNLOCK) return; await waitForBurnBlockHeight(info.details.unlock_height + 2); info = await client.getStatus(); expect(info.stacked).toBeFalsy(); @@ -364,7 +356,6 @@ describe('regtest-env pox-4', () => { expect(rewards.every(r => r.burn_block_height < stackHeight)).toBeTruthy(); // no new rewards // EXPORT EVENTS - await storeEventsTsv(); }); test('stack-stx (reward-phase), stack-extend (reward-phase)', async () => { @@ -372,8 +363,8 @@ describe('regtest-env pox-4', () => { // steph is a solo stacker and stacks in a reward-phase // steph then extends in a reward-phase // but steph doesn't run a signer, so we need to use a different signer key - const steph = getAccount(ENV.REGTEST_KEYS[0]); - const signer = getAccount(ENV.SIGNER_KEY); + const steph = getAccount(ENV.PRIVATE_KEYS[0]); + const signer = getAccount(ENV.PRIVATE_KEYS[3]); // PREP const client = new StackingClient(steph.address, network); @@ -440,7 +431,6 @@ describe('regtest-env pox-4', () => { poxInfo = await client.getPoxInfo(); await waitForNextCycle(poxInfo); - await storeEventsTsv('S1'); // snapshot 1 (steph is stacked in the current cycle) poxInfo = await client.getPoxInfo(); expect(poxInfo.reward_cycle_id).toBe(nextCycle); @@ -501,9 +491,8 @@ describe('regtest-env pox-4', () => { poxInfo = await client.getPoxInfo(); await waitForNextCycle(poxInfo); - await storeEventsTsv('S2'); // snapshot 2 (steph is stacked and extended in the current cycle) - if (ENV.REGTEST_SKIP_UNLOCK) return; + if (ENV.SKIP_UNLOCK) return; await waitForBurnBlockHeight(status.details.unlock_height + 2); // +1 is more correct, but often fails (race-condition?) status = await client.getStatus(); expect(status.stacked).toBeFalsy(); @@ -514,7 +503,6 @@ describe('regtest-env pox-4', () => { expect(rewards.filter(r => r.burn_block_height > extendHeight).length).toBeGreaterThan(0); // EXPORT EVENTS - await storeEventsTsv(); }); test('stack-stx (reward-phase), stack-extend (prepare-phase)', async () => { @@ -522,8 +510,8 @@ describe('regtest-env pox-4', () => { // steph is a solo stacker and stacks in a reward-phase // steph then attempts to extend in a prepare-phase // but steph doesn't run a signer, so we need to use a different signer key - const steph = getAccount(ENV.REGTEST_KEYS[0]); - const signer = getAccount(ENV.SIGNER_KEY); + const steph = getAccount(ENV.PRIVATE_KEYS[0]); + const signer = getAccount(ENV.PRIVATE_KEYS[3]); // PREP const client = new StackingClient(steph.address, network); @@ -590,7 +578,6 @@ describe('regtest-env pox-4', () => { poxInfo = await client.getPoxInfo(); await waitForNextCycle(poxInfo); - await storeEventsTsv('S1'); // snapshot 1 (steph is stacked in the current cycle) poxInfo = await client.getPoxInfo(); await waitForPreparePhase(poxInfo); @@ -655,9 +642,8 @@ describe('regtest-env pox-4', () => { poxInfo = await client.getPoxInfo(); await waitForNextCycle(poxInfo); - await storeEventsTsv('S2'); // snapshot 2 (steph was stacked, but the extend didn't make it in time) - if (ENV.REGTEST_SKIP_UNLOCK) return; + if (ENV.SKIP_UNLOCK) return; await waitForBurnBlockHeight(status.details.unlock_height + 2); // +1 is more correct, but often fails (race-condition?) status = await client.getStatus(); expect(status.stacked).toBeFalsy(); @@ -668,7 +654,6 @@ describe('regtest-env pox-4', () => { expect(rewards.filter(r => r.burn_block_height > extendHeight).length).toBe(0); // extend didn't make it // EXPORT EVENTS - await storeEventsTsv(); }); test('stack-stx (reward-phase), stack-increase (reward-phase)', async () => { @@ -676,8 +661,8 @@ describe('regtest-env pox-4', () => { // steph is a solo stacker and stacks in a reward-phase // steph then increases in a reward-phase // but steph doesn't run a signer, so we need to use a different signer key - const steph = getAccount(ENV.REGTEST_KEYS[0]); - const signer = getAccount(ENV.SIGNER_KEY); + const steph = getAccount(ENV.PRIVATE_KEYS[0]); + const signer = getAccount(ENV.PRIVATE_KEYS[3]); // PREP const client = new StackingClient(steph.address, network); @@ -744,7 +729,6 @@ describe('regtest-env pox-4', () => { poxInfo = await client.getPoxInfo(); await waitForNextCycle(poxInfo); - await storeEventsTsv('S1'); // snapshot 1 (steph is stacked in the current cycle) poxInfo = await client.getPoxInfo(); expect(poxInfo.reward_cycle_id).toBe(nextCycle); @@ -800,9 +784,8 @@ describe('regtest-env pox-4', () => { poxInfo = await client.getPoxInfo(); await waitForNextCycle(poxInfo); - await storeEventsTsv('S2'); // snapshot 2 (steph was stacked and increased for the current cycle) - if (ENV.REGTEST_SKIP_UNLOCK) return; + if (ENV.SKIP_UNLOCK) return; await waitForBurnBlockHeight(status.details.unlock_height + 2); // +1 is more correct, but often fails (race-condition?) status = await client.getStatus(); expect(status.stacked).toBeFalsy(); @@ -813,7 +796,6 @@ describe('regtest-env pox-4', () => { expect(rewards.filter(r => r.burn_block_height > increaseHeight).length).toBeGreaterThan(0); // EXPORT EVENTS - await storeEventsTsv(); }); test('stack-stx (reward-phase), stack-increase (prepare-phase)', async () => { @@ -821,8 +803,8 @@ describe('regtest-env pox-4', () => { // steph is a solo stacker and stacks in a reward-phase // steph then increases in a prepare-phase // but steph doesn't run a signer, so we need to use a different signer key - const steph = getAccount(ENV.REGTEST_KEYS[0]); - const signer = getAccount(ENV.SIGNER_KEY); + const steph = getAccount(ENV.PRIVATE_KEYS[0]); + const signer = getAccount(ENV.PRIVATE_KEYS[3]); // PREP const client = new StackingClient(steph.address, network); @@ -889,7 +871,6 @@ describe('regtest-env pox-4', () => { poxInfo = await client.getPoxInfo(); await waitForNextCycle(poxInfo); - await storeEventsTsv('S1'); // snapshot 1 (steph is stacked in the current cycle) poxInfo = await client.getPoxInfo(); await waitForPreparePhase(poxInfo); @@ -949,9 +930,8 @@ describe('regtest-env pox-4', () => { poxInfo = await client.getPoxInfo(); await waitForNextCycle(poxInfo); - await storeEventsTsv('S2'); // snapshot 2 (steph was stacked, but the increase didn't make it in time) - if (ENV.REGTEST_SKIP_UNLOCK) return; + if (ENV.SKIP_UNLOCK) return; await waitForBurnBlockHeight(status.details.unlock_height + 2); // +1 is more correct, but often fails (race-condition?) status = await client.getStatus(); expect(status.stacked).toBeFalsy(); @@ -964,7 +944,6 @@ describe('regtest-env pox-4', () => { // todo: (functional) some how ensure the slots were not increased on the blockchain side // EXPORT EVENTS - await storeEventsTsv(); }); test('pool: delegate-stack, agg-increase (prepare-phase)', async () => { @@ -974,10 +953,10 @@ describe('regtest-env pox-4', () => { // the pool commits (in the reward-phase) // the pool stacks for bob (in the prepare-phase) // the pool commit-increases (in the prepare-phase) - const alice = getAccount(ENV.REGTEST_KEYS[0]); - const bob = getAccount(ENV.REGTEST_KEYS[1]); - const pool = getAccount(ENV.REGTEST_KEYS[2]); - const signer = getAccount(ENV.SIGNER_KEY); + const alice = getAccount(ENV.PRIVATE_KEYS[0]); + const bob = getAccount(ENV.PRIVATE_KEYS[1]); + const pool = getAccount(ENV.PRIVATE_KEYS[2]); + const signer = getAccount(ENV.PRIVATE_KEYS[3]); // PREP const client = new StackingClient('', network); @@ -1135,7 +1114,6 @@ describe('regtest-env pox-4', () => { expect(rewardSet?.total_ustx).toBe(amount * 2n); // EXPORT EVENTS - await storeEventsTsv(); }); test.skip('pool: agg increase over maxAmount', async () => { @@ -1146,9 +1124,9 @@ describe('regtest-env pox-4', () => { // pool delegate stack increases for alice (the remaining amount) // pool increases commit, but the signature was only for the initial amount - const alice = getAccount(ENV.REGTEST_KEYS[0]); - const pool = getAccount(ENV.REGTEST_KEYS[2]); - const signer = getAccount(ENV.SIGNER_KEY); + const alice = getAccount(ENV.PRIVATE_KEYS[0]); + const pool = getAccount(ENV.PRIVATE_KEYS[1]); + const signer = getAccount(ENV.PRIVATE_KEYS[3]); // PREP const client = new StackingClient('', network); @@ -1260,15 +1238,14 @@ describe('regtest-env pox-4', () => { expect(rewardSet?.total_ustx).toBe(fullAmount); // EXPORT EVENTS - await storeEventsTsv(); }); test('pool: delegate with invalid hashbyte length', async () => { // TEST CASE // alice delegates to a pool with an invalid hashbyte length // the transaction should fail (but won't) - const alice = getAccount(ENV.REGTEST_KEYS[0]); - const pool = getAccount(ENV.REGTEST_KEYS[2]); + const alice = getAccount(ENV.PRIVATE_KEYS[0]); + const pool = getAccount(ENV.PRIVATE_KEYS[2]); // PREP const client = new StackingClient('', network); @@ -1347,8 +1324,8 @@ describe('regtest-env pox-4', () => { // pool delegate stacks for alice (in the reward-phase) for a cycle that is not the next cycle // the transaction should fail - const alice = getAccount(ENV.REGTEST_KEYS[0]); - const pool = getAccount(ENV.REGTEST_KEYS[2]); + const alice = getAccount(ENV.PRIVATE_KEYS[0]); + const pool = getAccount(ENV.PRIVATE_KEYS[2]); // PREP const client = new StackingClient('', network); @@ -1399,8 +1376,8 @@ describe('regtest-env pox-4', () => { // pool delegate stacks for alice (in the reward-phase) // the transaction should fail - const alice = getAccount(ENV.REGTEST_KEYS[0]); - const pool = getAccount(ENV.REGTEST_KEYS[2]); + const alice = getAccount(ENV.PRIVATE_KEYS[0]); + const pool = getAccount(ENV.PRIVATE_KEYS[2]); // PREP const client = new StackingClient('', network); @@ -1460,8 +1437,8 @@ describe('regtest-env pox-4', () => { // pool delegate stacks for alice (in the reward-phase) // the transaction should fail - const alice = getAccount(ENV.REGTEST_KEYS[0]); - const pool = getAccount(ENV.REGTEST_KEYS[2]); + const alice = getAccount(ENV.PRIVATE_KEYS[0]); + const pool = getAccount(ENV.PRIVATE_KEYS[2]); // PREP const client = new StackingClient('', network); @@ -1535,8 +1512,8 @@ describe('regtest-env pox-4', () => { // pool delegate stacks for alice (with a higher amount) // the transaction should fail - const alice = getAccount(ENV.REGTEST_KEYS[0]); - const pool = getAccount(ENV.REGTEST_KEYS[2]); + const alice = getAccount(ENV.PRIVATE_KEYS[0]); + const pool = getAccount(ENV.PRIVATE_KEYS[2]); // PREP const client = new StackingClient('', network); @@ -1585,9 +1562,9 @@ describe('regtest-env pox-4', () => { // pool B tries to delegate-stack-stx for alice // the transaction should fail - const alice = getAccount(ENV.REGTEST_KEYS[0]); - const poolA = getAccount(ENV.REGTEST_KEYS[1]); - const poolB = getAccount(ENV.REGTEST_KEYS[2]); + const alice = getAccount(ENV.PRIVATE_KEYS[0]); + const poolA = getAccount(ENV.PRIVATE_KEYS[1]); + const poolB = getAccount(ENV.PRIVATE_KEYS[2]); // PREP const client = new StackingClient('', network); @@ -1636,8 +1613,8 @@ describe('regtest-env pox-4', () => { // pool delegate stacks for alice (in the reward-phase) for the current cycle // the transaction should fail - const alice = getAccount(ENV.REGTEST_KEYS[0]); - const pool = getAccount(ENV.REGTEST_KEYS[2]); + const alice = getAccount(ENV.PRIVATE_KEYS[0]); + const pool = getAccount(ENV.PRIVATE_KEYS[2]); // PREP const client = new StackingClient('', network); @@ -1686,8 +1663,8 @@ describe('regtest-env pox-4', () => { // pool delegate stacks for alice (in the reward-phase) // the transaction should fail - const alice = getAccount(ENV.REGTEST_KEYS[0]); - const pool = getAccount(ENV.REGTEST_KEYS[2]); + const alice = getAccount(ENV.PRIVATE_KEYS[0]); + const pool = getAccount(ENV.PRIVATE_KEYS[2]); // PREP const client = new StackingClient('', network); @@ -1724,8 +1701,8 @@ describe('regtest-env pox-4', () => { // alice revokes the delegation // alice is still locked - const alice = getAccount(ENV.REGTEST_KEYS[0]); - const pool = getAccount(ENV.REGTEST_KEYS[2]); + const alice = getAccount(ENV.PRIVATE_KEYS[0]); + const pool = getAccount(ENV.PRIVATE_KEYS[2]); // PREP const client = new StackingClient('', network); @@ -1788,9 +1765,9 @@ describe('regtest-env pox-4', () => { // alice can use the signature while only knowing the signer-key, max-amount, auth-id // bob can't use the consumed signature - const alice = getAccount(ENV.REGTEST_KEYS[0]); - const bob = getAccount(ENV.REGTEST_KEYS[1]); - const pool = getAccount(ENV.REGTEST_KEYS[2]); + const alice = getAccount(ENV.PRIVATE_KEYS[0]); + const bob = getAccount(ENV.PRIVATE_KEYS[1]); + const pool = getAccount(ENV.PRIVATE_KEYS[2]); // PREP const client = new StackingClient('', network); @@ -1902,9 +1879,9 @@ describe('regtest-env pox-4', () => { // alice increases stack with signer B // the transaction should fail - const alice = getAccount(ENV.REGTEST_KEYS[0]); - const signerA = getAccount(ENV.REGTEST_KEYS[1]); - const signerB = getAccount(ENV.REGTEST_KEYS[2]); + const alice = getAccount(ENV.PRIVATE_KEYS[0]); + const signerA = getAccount(ENV.PRIVATE_KEYS[3]); + const signerB = getAccount(ENV.PRIVATE_KEYS[4]); // PREP const client = new StackingClient('', network); @@ -1981,9 +1958,9 @@ describe('regtest-env pox-4', () => { // alice extends stack with signer B // the transaction should work, because it's essentially like a new stack (separate from the first) - const alice = getAccount(ENV.REGTEST_KEYS[0]); - const signerA = getAccount(ENV.REGTEST_KEYS[1]); - const signerB = getAccount(ENV.REGTEST_KEYS[2]); + const alice = getAccount(ENV.PRIVATE_KEYS[0]); + const signerA = getAccount(ENV.PRIVATE_KEYS[3]); + const signerB = getAccount(ENV.PRIVATE_KEYS[4]); // PREP const client = new StackingClient('', network); @@ -2060,7 +2037,7 @@ describe('regtest-env pox-4', () => { // call a read-only function with a weird string // the transaction should fail - const alice = getAccount(ENV.REGTEST_KEYS[0]); + const alice = getAccount(ENV.PRIVATE_KEYS[0]); // PREP const client = new StackingClient('', network); @@ -2106,8 +2083,8 @@ describe('regtest-env pox-4', () => { // alice delegates to a pool with an invalid pox-addr-version // the transaction should fail - const alice = getAccount(ENV.REGTEST_KEYS[0]); - const pool = getAccount(ENV.REGTEST_KEYS[2]); + const alice = getAccount(ENV.PRIVATE_KEYS[0]); + const pool = getAccount(ENV.PRIVATE_KEYS[2]); // PREP const client = new StackingClient('', network); @@ -2152,9 +2129,9 @@ describe('regtest-env pox-4', () => { // alice tries to delegate to another pool // the transaction should fail - const alice = getAccount(ENV.REGTEST_KEYS[0]); - const poolA = getAccount(ENV.REGTEST_KEYS[1]); - const poolB = getAccount(ENV.REGTEST_KEYS[2]); + const alice = getAccount(ENV.PRIVATE_KEYS[0]); + const poolA = getAccount(ENV.PRIVATE_KEYS[1]); + const poolB = getAccount(ENV.PRIVATE_KEYS[2]); // PREP const client = new StackingClient('', network); @@ -2197,8 +2174,8 @@ describe('regtest-env pox-4', () => { // alice revokes stx from a pool (without having delegated) // the transaction should fail - const alice = getAccount(ENV.REGTEST_KEYS[0]); - const pool = getAccount(ENV.REGTEST_KEYS[2]); + const alice = getAccount(ENV.PRIVATE_KEYS[0]); + const pool = getAccount(ENV.PRIVATE_KEYS[2]); // PREP const client = new StackingClient('', network); @@ -2226,8 +2203,8 @@ describe('regtest-env pox-4', () => { // pool delegate stacks for alice (in the reward-phase) // alice should be locked - const alice = getAccount(ENV.REGTEST_KEYS[0]); - const pool = getAccount(ENV.REGTEST_KEYS[2]); + const alice = getAccount(ENV.PRIVATE_KEYS[0]); + const pool = getAccount(ENV.PRIVATE_KEYS[2]); // PREP const client = new StackingClient('', network); @@ -2316,8 +2293,8 @@ describe('regtest-env pox-4', () => { // pool delegate tries to delegate-stack for alice // the transaction should fail - const alice = getAccount(ENV.REGTEST_KEYS[0]); - const pool = getAccount(ENV.REGTEST_KEYS[2]); + const alice = getAccount(ENV.PRIVATE_KEYS[0]); + const pool = getAccount(ENV.PRIVATE_KEYS[2]); // PREP const client = new StackingClient('', network); @@ -2376,8 +2353,8 @@ describe('regtest-env pox-4', () => { // pool tries to commit the stack for the current cycle // the transaction should fail - const alice = getAccount(ENV.REGTEST_KEYS[0]); - const pool = getAccount(ENV.REGTEST_KEYS[2]); + const alice = getAccount(ENV.PRIVATE_KEYS[0]); + const pool = getAccount(ENV.PRIVATE_KEYS[2]); // PREP const client = new StackingClient('', network); @@ -2447,9 +2424,9 @@ describe('regtest-env pox-4', () => { // pool B tries to delegate-stack for alice // the transaction should fail - const alice = getAccount(ENV.REGTEST_KEYS[0]); - const poolA = getAccount(ENV.REGTEST_KEYS[1]); - const poolB = getAccount(ENV.REGTEST_KEYS[2]); + const alice = getAccount(ENV.PRIVATE_KEYS[0]); + const poolA = getAccount(ENV.PRIVATE_KEYS[1]); + const poolB = getAccount(ENV.PRIVATE_KEYS[2]); // PREP const client = new StackingClient('', network); @@ -2494,8 +2471,8 @@ describe('regtest-env pox-4', () => { // pool tries to delegate-stack for alice with more STX than what alice has explicitly allowed // the transaction should fail - const alice = getAccount(ENV.REGTEST_KEYS[0]); - const pool = getAccount(ENV.REGTEST_KEYS[2]); + const alice = getAccount(ENV.PRIVATE_KEYS[0]); + const pool = getAccount(ENV.PRIVATE_KEYS[2]); // PREP const client = new StackingClient('', network); @@ -2552,9 +2529,9 @@ describe('regtest-env pox-4', () => { // pool tries to delegate-stack for alice with a different pox-addr // the transaction should fail - const alice = getAccount(ENV.REGTEST_KEYS[0]); - const pool = getAccount(ENV.REGTEST_KEYS[2]); - const random = getAccount(ENV.REGTEST_KEYS[1]); + const alice = getAccount(ENV.PRIVATE_KEYS[0]); + const pool = getAccount(ENV.PRIVATE_KEYS[2]); + const random = getAccount(ENV.PRIVATE_KEYS[1]); // PREP const client = new StackingClient('', network); @@ -2598,8 +2575,8 @@ describe('regtest-env pox-4', () => { // pool tries to delegate-stack for alice // the transaction should fail - const alice = getAccount(ENV.REGTEST_KEYS[0]); - const pool = getAccount(ENV.REGTEST_KEYS[2]); + const alice = getAccount(ENV.PRIVATE_KEYS[0]); + const pool = getAccount(ENV.PRIVATE_KEYS[2]); // PREP const client = new StackingClient('', network); @@ -2646,8 +2623,8 @@ describe('regtest-env pox-4', () => { // pool tries to delegate-stack for alice with more STX than what alice has // the transaction should fail - const alice = getAccount(ENV.REGTEST_KEYS[0]); - const pool = getAccount(ENV.REGTEST_KEYS[2]); + const alice = getAccount(ENV.PRIVATE_KEYS[0]); + const pool = getAccount(ENV.PRIVATE_KEYS[2]); // PREP const client = new StackingClient('', network); @@ -2695,8 +2672,8 @@ describe('regtest-env pox-4', () => { // pool tries to delegate-stack for alice for more than 12 cycles // the transaction should fail - const alice = getAccount(ENV.REGTEST_KEYS[0]); - const pool = getAccount(ENV.REGTEST_KEYS[2]); + const alice = getAccount(ENV.PRIVATE_KEYS[0]); + const pool = getAccount(ENV.PRIVATE_KEYS[2]); // PREP const client = new StackingClient('', network); @@ -2764,8 +2741,8 @@ describe('regtest-env pox-4', () => { // pool tries to delegate-stack for alice with an invalid pox-addr-ver // the transaction should fail - const alice = getAccount(ENV.REGTEST_KEYS[0]); - const pool = getAccount(ENV.REGTEST_KEYS[2]); + const alice = getAccount(ENV.PRIVATE_KEYS[0]); + const pool = getAccount(ENV.PRIVATE_KEYS[2]); // PREP const client = new StackingClient('', network); @@ -2821,8 +2798,8 @@ describe('regtest-env pox-4', () => { // pool tries to delegate-stack for alice // the transaction should fail - const alice = getAccount(ENV.REGTEST_KEYS[0]); - const pool = getAccount(ENV.REGTEST_KEYS[2]); + const alice = getAccount(ENV.PRIVATE_KEYS[0]); + const pool = getAccount(ENV.PRIVATE_KEYS[2]); // PREP const client = new StackingClient('', network); @@ -2875,8 +2852,8 @@ describe('regtest-env pox-4', () => { // pool delegate-stack-extend for alice // lock has been extended - const alice = getAccount(ENV.REGTEST_KEYS[0]); - const pool = getAccount(ENV.REGTEST_KEYS[2]); + const alice = getAccount(ENV.PRIVATE_KEYS[0]); + const pool = getAccount(ENV.PRIVATE_KEYS[2]); // PREP const client = new StackingClient('', network); diff --git a/src/tests/scripts.test.ts b/src/tests/scripts.test.ts index 968e4a9..3d87ba5 100644 --- a/src/tests/scripts.test.ts +++ b/src/tests/scripts.test.ts @@ -4,35 +4,37 @@ import { ENV } from '../env'; import { getAccount, getRewardSlots, getTransactions } from '../helpers'; test('get account status', async () => { - const steph = getAccount(ENV.REGTEST_KEYS[0]); + const steph = getAccount(ENV.PRIVATE_KEYS[0]); const client = new StackingClient(steph.address, new StacksDevnet()); const status = await client.getStatus(); console.log(status); console.log((await client.getPoxInfo()).current_burnchain_block_height); }); -test('get account', () => { - const steph = getAccount(ENV.REGTEST_KEYS[0]); +test('get account', async () => { + const steph = getAccount(ENV.PRIVATE_KEYS[0]); console.log(steph); -}); - -test('get signer', () => { - const signer = getAccount(ENV.SIGNER_KEY); - console.log(signer); + const balances = await steph.client.getAccountExtendedBalances(); + console.log(balances); }); test('get reward slot', async () => { - const steph = getAccount(ENV.REGTEST_KEYS[0]); + const steph = getAccount(ENV.PRIVATE_KEYS[0]); const rewards = await getRewardSlots(steph.btcAddress); console.log(rewards[0]); }); test('get transactions', async () => { - const steph = getAccount(ENV.REGTEST_KEYS[0]); + const steph = getAccount(ENV.PRIVATE_KEYS[0]); const txs = await getTransactions(steph.address); console.log(txs); }); test('get env info', () => { - console.log(typeof ENV.REGTEST_SKIP_UNLOCK); + console.log(typeof ENV.SKIP_UNLOCK); +}); + +test('log all account addresses', () => { + const addresses = ENV.PRIVATE_KEYS.map(key => getAccount(key).address); + console.log(addresses); }); diff --git a/src/tests/transactions.test.ts b/src/tests/transactions.test.ts index c6d76e9..1b4ce4f 100644 --- a/src/tests/transactions.test.ts +++ b/src/tests/transactions.test.ts @@ -1,40 +1,39 @@ import { makeContractDeploy, makeSTXTokenTransfer } from '@stacks/transactions'; +import * as crypto from 'crypto'; +import * as fs from 'fs'; +import * as path from 'path'; import { ENV } from '../env'; import { broadcastAndWaitForTransaction, + getAccount, getNextNonce, stacksNetwork, waitForNextNonce, } from '../helpers'; -import { StacksNetwork } from '@stacks/network'; -import * as fs from 'fs'; -import * as path from 'path'; -import * as crypto from 'crypto'; describe('Stacks transactions', () => { - let network: StacksNetwork; - let nextNonce: number; + const SENDER = getAccount(ENV.PRIVATE_KEYS[0]).key; + const RECEIVER = getAccount(ENV.PRIVATE_KEYS[1]).address; - beforeAll(() => { - network = stacksNetwork(); - }); + const network = stacksNetwork(); + let nextNonce: number; beforeEach(async () => { - nextNonce = await getNextNonce(); + nextNonce = await getNextNonce(SENDER); }); afterEach(async () => { - await waitForNextNonce(nextNonce); + await waitForNextNonce(SENDER, nextNonce); }); test('STX transfer', async () => { const tx = await makeSTXTokenTransfer({ network, nonce: nextNonce, - recipient: ENV.RECEIVER_STX_ADDRESS, + recipient: RECEIVER, amount: 10_000, anchorMode: 'any', - senderKey: ENV.SENDER_KEY, + senderKey: SENDER, }); const result = await broadcastAndWaitForTransaction(tx, network); expect(result.tx_status).toBe('success'); @@ -48,7 +47,7 @@ describe('Stacks transactions', () => { contractName: `counter-${crypto.randomBytes(3).toString('hex')}`, codeBody, anchorMode: 'any', - senderKey: ENV.SENDER_KEY, + senderKey: SENDER, }); const result = await broadcastAndWaitForTransaction(tx, network); expect(result.tx_status).toBe('success'); @@ -65,7 +64,7 @@ describe('Stacks transactions', () => { contractName: `test-ft-${crypto.randomBytes(3).toString('hex')}`, codeBody, anchorMode: 'any', - senderKey: ENV.SENDER_KEY, + senderKey: SENDER, }); const result = await broadcastAndWaitForTransaction(tx, network); expect(result.tx_status).toBe('success'); diff --git a/src/utils.ts b/src/utils.ts index ffc8edb..6209f50 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -43,6 +43,25 @@ export function withTimeout( }; } +export async function networkEnvUp() { + if (!ENV.NETWORK_UP_CMD) return; + + console.log('starting network...'); + const out = await x(ENV.NETWORK_UP_CMD); + // if (out.stderr) throw new Error(out.stderr); + return out.stdout; +} + +export async function networkEnvDown() { + if (!ENV.NETWORK_DOWN_CMD) return; + + console.log('stopping network...'); + const out = await x(ENV.NETWORK_DOWN_CMD); + // if (out.stderr) throw new Error(out.stderr); + return out.stdout; +} + +/** WIP */ export async function storeEventsTsv(suffix: string = '') { let testname = expect.getState().currentTestName ?? ''; testname = testname @@ -68,17 +87,3 @@ export async function storeEventsTsv(suffix: string = '') { if (out.stderr) throw new Error(out.stderr); return out.stdout; } - -export async function startRegtestEnv() { - console.log('starting regtest-env...'); - const out = await x(ENV.REGTEST_UP_CMD); - // if (out.stderr) throw new Error(out.stderr); - return out.stdout; -} - -export async function stopRegtestEnv() { - console.log('stopping regtest-env...'); - const out = await x(ENV.REGTEST_DOWN_CMD); - // if (out.stderr) throw new Error(out.stderr); - return out.stdout; -}