diff --git a/.circleci/config.yml b/.circleci/config.yml index c73a2b4b3040..24cd1587c963 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -857,7 +857,8 @@ jobs: command: | TESTFILES=$(circleci tests glob "test/e2e/playwright/swap/**/*.spec.ts") echo "$TESTFILES" - echo "$TESTFILES" | timeout 20m circleci tests run --command="xvfb-run xargs yarn playwright test --project=swap" verbose + echo "$TESTFILES" | timeout 20m circleci tests run --command="xvfb-run xargs yarn playwright test --project=swap" verbose || true + # above line makes it never fail, and these tests are going away soon no_output_timeout: 10m - slack/notify: event: fail diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index fbef53372e33..08ffdd127c9c 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -137,5 +137,5 @@ ui/components/ui/deprecated-networks @MetaMask/metamask-assets ui/components/ui/nft-collection-image @MetaMask/metamask-assets # Extension Platform -yarnrc.yml @MetaMask/extension-platform +.yarnrc.yml @MetaMask/extension-platform test/e2e/mock-e2e-allowlist.js @MetaMask/extension-platform \ No newline at end of file diff --git a/.github/scripts/identify-codeowners.ts b/.github/scripts/identify-codeowners.ts new file mode 100644 index 000000000000..8dbcbe0edaa1 --- /dev/null +++ b/.github/scripts/identify-codeowners.ts @@ -0,0 +1,281 @@ +import * as core from '@actions/core'; +import { context, getOctokit } from '@actions/github'; +import { GitHub } from '@actions/github/lib/utils'; +import { retrievePullRequestFiles } from './shared/pull-request'; +import micromatch from 'micromatch'; + +type TeamFiles = Record; + +type TeamEmojis = { + [team: string]: string; +} + +type CodeOwnerRule = { + pattern: string; + owners: string[]; +} + +// Team emoji mappings +const teamEmojis: TeamEmojis = { + '@MetaMask/extension-devs': '🧩', + '@MetaMask/policy-reviewers': 'šŸ“œ', + '@MetaMask/supply-chain': 'šŸ”—', + '@MetaMask/snaps-devs': '🫰', + '@MetaMask/extension-security-team': 'šŸ”’', + '@MetaMask/extension-privacy-reviewers': 'šŸ•µļø', + '@MetaMask/confirmations': 'āœ…', + '@MetaMask/design-system-engineers': 'šŸŽØ', + '@MetaMask/notifications': 'šŸ””', + '@MetaMask/identity': '🪪', + '@MetaMask/accounts-engineers': 'šŸ”‘', + '@MetaMask/swaps-engineers': 'šŸ”„', + '@MetaMask/ramp': 'šŸ“ˆ', + '@MetaMask/wallet-ux': 'šŸ–„ļø', + '@MetaMask/metamask-assets': 'šŸ’Ž', +}; + +main().catch((error: Error): void => { + console.error(error); + process.exit(1); +}); + +async function main(): Promise { + const PR_COMMENT_TOKEN = process.env.PR_COMMENT_TOKEN; + if (!PR_COMMENT_TOKEN) { + core.setFailed('PR_COMMENT_TOKEN not found'); + process.exit(1); + } + + // Initialise octokit, required to call Github API + const octokit: InstanceType = getOctokit(PR_COMMENT_TOKEN); + + + const owner = context.repo.owner; + const repo = context.repo.repo; + const prNumber = context.payload.pull_request?.number; + if (!prNumber) { + core.setFailed('Pull request number not found'); + process.exit(1); + } + + // Get the changed files in the PR + const changedFiles = await retrievePullRequestFiles(octokit, owner, repo, prNumber); + + // Read and parse the CODEOWNERS file + const codeownersContent = await getCodeownersContent(octokit, owner, repo); + const codeowners = parseCodeowners(codeownersContent); + + // Match files to codeowners + const fileOwners = matchFilesToCodeowners(changedFiles, codeowners); + + // Group files by team + const teamFiles = groupFilesByTeam(fileOwners); + + // If no teams need to review, don't create or update comments + if (Object.keys(teamFiles).length === 0) { + console.log('No files requiring codeowner review, skipping comment'); + + // Check for existing bot comment and delete it if it exists + // (in case previous version of PR had files requiring review) + await deleteExistingComment(octokit, owner, repo, prNumber); + return; + } + + // Create the comment body + const commentBody = createCommentBody(teamFiles, teamEmojis); + + // Check for an existing comment and update or create as needed + await updateOrCreateComment(octokit, owner, repo, prNumber, commentBody); +} + +async function getCodeownersContent( + octokit: InstanceType, + owner: string, + repo: string +): Promise { + try { + const response = await octokit.rest.repos.getContent({ + owner, + repo, + path: '.github/CODEOWNERS', + headers: { + 'accept': 'application/vnd.github.raw', + }, + }); + + if (response) { + return response.data as unknown as string; + } + + throw new Error('Failed to get CODEOWNERS file content'); + } catch (error) { + throw new Error(`Failed to get CODEOWNERS file: ${error instanceof Error ? error.message : String(error)}`); + } +} + +function parseCodeowners(content: string): CodeOwnerRule[] { + return content + .split('\n') + .filter(line => line.trim() && !line.startsWith('#')) + .map(line => { + const [pattern, ...owners] = line.trim().split(/\s+/); + return { pattern, owners }; + }); +} + +function matchFilesToCodeowners(files: string[], codeowners: CodeOwnerRule[]): Map> { + const fileOwners: Map> = new Map(); + + files.forEach(file => { + for (const { pattern, owners } of codeowners) { + if (isFileMatchingPattern(file, pattern)) { + // Not breaking here to allow for multiple patterns to match the same file + // i.e. if a directory is owned by one team, but specific files within that directory + // are also owned by another team, the file will be added to both teams + const ownerSet = fileOwners.get(file); + if (!ownerSet) { + fileOwners.set(file, new Set(owners)); + } else { + owners.forEach((owner) => ownerSet.add(owner)); + } + } + } + }); + + return fileOwners; +} + +function isFileMatchingPattern(file: string, pattern: string): boolean { + // Case 1: Pattern explicitly ends with a slash (e.g., "docs/") + if (pattern.endsWith('/')) { + return micromatch.isMatch(file, `${pattern}**`); + } + + // Case 2: Pattern doesn't end with a file extension - treat as directory + if (!pattern.match(/\.[^/]*$/)) { + // Treat as directory - match this path and everything under it + return micromatch.isMatch(file, `${pattern}/**`); + } + + // Case 3: Pattern with file extension or already has wildcards + return micromatch.isMatch(file, pattern); +} + +function groupFilesByTeam(fileOwners: Map>): TeamFiles { + const teamFiles: TeamFiles = {}; + + fileOwners.forEach((owners, file) => { + owners.forEach(owner => { + if (!teamFiles[owner]) { + teamFiles[owner] = []; + } + teamFiles[owner].push(file); + }); + }); + + // Sort files within each team for consistent ordering + Object.values(teamFiles).forEach(files => files.sort()); + + return teamFiles; +} + +function createCommentBody(teamFiles: TeamFiles, teamEmojis: TeamEmojis): string { + let commentBody = `\n✨ Files requiring CODEOWNER review ✨\n---\n`; + + // Sort teams for consistent ordering + const allOwners = Object.keys(teamFiles); + + const teamOwners = allOwners.filter(owner => owner.startsWith('@MetaMask/')); + const individualOwners = allOwners.filter(owner => !owner.startsWith('@MetaMask/')); + + const sortFn = (a, b) => a.toLowerCase().localeCompare(b.toLowerCase()); + const sortedTeamOwners = teamOwners.sort(sortFn); + const sortedIndividualOwners = individualOwners.sort(sortFn); + + const sortedOwners= [...sortedTeamOwners, ...sortedIndividualOwners]; + + sortedOwners.forEach(team => { + const emoji = teamEmojis[team] || 'šŸ‘Øā€šŸ”§'; + commentBody += `${emoji} ${team}\n`; + teamFiles[team].forEach(file => { + commentBody += `- \`${file}\`\n`; + }); + commentBody += '\n'; + }); + + return commentBody; +} + +async function deleteExistingComment( + octokit: InstanceType, + owner: string, + repo: string, + prNumber: number +): Promise { + // Get existing comments + const { data: comments } = await octokit.rest.issues.listComments({ + owner, + repo, + issue_number: prNumber, + }); + + const botComment = comments.find(comment => + comment.body?.includes('') + ); + + if (botComment) { + // Delete the existing comment + await octokit.rest.issues.deleteComment({ + owner, + repo, + comment_id: botComment.id, + }); + + console.log('Deleted existing codeowners comment'); + } +} + +async function updateOrCreateComment( + octokit: InstanceType, + owner: string, + repo: string, + prNumber: number, + commentBody: string +): Promise { + // Get existing comments + const { data: comments } = await octokit.rest.issues.listComments({ + owner, + repo, + issue_number: prNumber, + }); + + const botComment = comments.find(comment => + comment.body?.includes('') + ); + + if (botComment) { + // Simple text comparison is sufficient since we control both sides + if (botComment.body !== commentBody) { + await octokit.rest.issues.updateComment({ + owner, + repo, + comment_id: botComment.id, + body: commentBody, + }); + + console.log('Updated existing codeowners comment'); + } else { + console.log('No changes to codeowners, skipping comment update'); + } + } else { + // Create new comment + await octokit.rest.issues.createComment({ + owner, + repo, + issue_number: prNumber, + body: commentBody, + }); + + console.log('Created new codeowners comment'); + } +} \ No newline at end of file diff --git a/.github/scripts/shared/pull-request.ts b/.github/scripts/shared/pull-request.ts index 8cf6805f57cf..e8ebdf4e03f4 100644 --- a/.github/scripts/shared/pull-request.ts +++ b/.github/scripts/shared/pull-request.ts @@ -67,3 +67,26 @@ export async function retrievePullRequest( return pullRequest; } + +/** + * Retrieves files changed in a specific pull request + * @param octokit GitHub API client + * @param repoOwner Repository owner (e.g., "MetaMask") + * @param repoName Repository name (e.g., "metamask-extension") + * @param prNumber Pull request number + * @returns Array of filenames that were changed in the PR + */ +export async function retrievePullRequestFiles( + octokit: InstanceType, + repoOwner: string, + repoName: string, + prNumber: number, +): Promise { + const response = await octokit.rest.pulls.listFiles({ + owner: repoOwner, + repo: repoName, + pull_number: prNumber, + }); + + return response.data.map((file) => file.filename); +} \ No newline at end of file diff --git a/.github/workflows/add-release-label.yml b/.github/workflows/add-release-label.yml index cbceba0a2cac..072a1544b1eb 100644 --- a/.github/workflows/add-release-label.yml +++ b/.github/workflows/add-release-label.yml @@ -17,6 +17,7 @@ jobs: with: is-high-risk-environment: false fetch-depth: 0 # This is needed to checkout all branches + skip-allow-scripts: true - name: Get the next semver version id: get-next-semver-version diff --git a/.github/workflows/add-team-label.yml b/.github/workflows/add-team-label.yml index b5d9eaa18603..9bd96ec03a9c 100644 --- a/.github/workflows/add-team-label.yml +++ b/.github/workflows/add-team-label.yml @@ -4,9 +4,12 @@ on: pull_request: types: - opened + - reopened + - synchronize jobs: add-team-label: + if: ${{ !github.event.pull_request.head.repo.fork }} uses: metamask/github-tools/.github/workflows/add-team-label.yml@18af6e4b56a18230d1792480e249ebc50b324927 secrets: TEAM_LABEL_TOKEN: ${{ secrets.TEAM_LABEL_TOKEN }} diff --git a/.github/workflows/build-beta.yml b/.github/workflows/build-beta.yml index 73a8279d3cea..b169dd405463 100644 --- a/.github/workflows/build-beta.yml +++ b/.github/workflows/build-beta.yml @@ -2,11 +2,23 @@ name: Build beta on: workflow_call: + secrets: + INFURA_PROJECT_ID: + required: true + SENTRY_DSN_DEV: + required: false jobs: build-beta: name: Build beta runs-on: ubuntu-latest + env: + # For a `pull_request` event, the branch is `github.head_ref``. + # For a `push` event, the branch is `github.ref_name`. + BRANCH: ${{ github.head_ref || github.ref_name }} + # For a `pull_request` event, the head commit hash is `github.event.pull_request.head.sha`. + # For a `push` event, the head commit hash is `github.sha`. + HEAD_COMMIT_HASH: ${{ github.event.pull_request.head.sha || github.sha }} steps: - name: Checkout repository uses: actions/checkout@v4 @@ -16,55 +28,27 @@ jobs: # However, we need the head commit (the latest commit pushed to the source branch) # because in the workflow, we would like to parse the latest commit message. # Specifying `ref` ensures that the head commit is checked out directly. - # For a `pull_request` event, the head commit hash is `github.event.pull_request.head.sha`. - # For a `push` event, the head commit hash is `github.sha`. - ref: ${{ github.event.pull_request.head.sha || github.sha }} - - - name: Needs beta build - # For a `pull_request` event, the branch is `github.head_ref``. - # For a `push` event, the branch is `github.ref_name`. - if: ${{ (github.head_ref || github.ref_name) != 'master' }} - id: needs-beta-build - env: - BRANCH: ${{ github.head_ref || github.ref_name }} - run: | - version="${BRANCH/Version-v/}" - commit_message=$(git show -s --format=%s HEAD) - beta_version_regex="Version v[0-9]+\.[0-9]+\.[0-9]+-beta\.[0-9]+" - - if [[ "$commit_message" =~ $beta_version_regex ]]; then - printf '%s\n' "Creating a build for $version with $commit_message" - echo "NEEDS_BETA_BUILD=true" >> "$GITHUB_OUTPUT" - else - printf '%s\n' 'Commit message does not match commit message for beta pattern; skipping beta build' - echo "NEEDS_BETA_BUILD=false" >> "$GITHUB_OUTPUT" - fi + ref: ${{ env.HEAD_COMMIT_HASH }} - name: Checkout and setup high risk environment - if: ${{ steps.needs-beta-build.outputs.NEEDS_BETA_BUILD == 'true' }} uses: MetaMask/action-checkout-and-setup@v1 with: is-high-risk-environment: true - ref: ${{ github.event.pull_request.head.sha || github.sha }} + ref: ${{ env.HEAD_COMMIT_HASH }} + skip-allow-scripts: true - name: Run beta build - if: ${{ steps.needs-beta-build.outputs.NEEDS_BETA_BUILD == 'true' }} env: - INFURA_PROJECT_ID: ${{ vars.INFURA_PROJECT_ID }} - INFURA_BETA_PROJECT_ID: ${{ vars.INFURA_BETA_PROJECT_ID }} - SEGMENT_BETA_WRITE_KEY: 00000000000 - SENTRY_DSN: https://fake@sentry.io/0000000 - ENABLE_MV3: true + INFURA_PROJECT_ID: ${{ secrets.INFURA_PROJECT_ID }} + SENTRY_DSN_DEV: ${{ secrets.SENTRY_DSN_DEV }} run: | yarn build --build-type beta --platform='chrome' dist - yarn build --build-type beta --platform='chrome' prod - name: Validate source maps - if: ${{ steps.needs-beta-build.outputs.NEEDS_BETA_BUILD == 'true' }} run: yarn validate-source-maps - name: Upload 'dist-beta' to S3 - if: ${{ steps.needs-beta-build.outputs.NEEDS_BETA_BUILD == 'true' }} + if: ${{ vars.AWS_REGION && vars.AWS_IAM_ROLE && vars.AWS_S3_BUCKET }} uses: metamask/github-tools/.github/actions/upload-s3@1233659b3850eb84824d7375e2e0c58eb237701d with: aws-region: ${{ vars.AWS_REGION }} @@ -73,7 +57,7 @@ jobs: path: dist - name: Upload 'builds-beta' to S3 - if: ${{ steps.needs-beta-build.outputs.NEEDS_BETA_BUILD == 'true' }} + if: ${{ vars.AWS_REGION && vars.AWS_IAM_ROLE && vars.AWS_S3_BUCKET }} uses: metamask/github-tools/.github/actions/upload-s3@1233659b3850eb84824d7375e2e0c58eb237701d with: aws-region: ${{ vars.AWS_REGION }} diff --git a/.github/workflows/build-storybook.yml b/.github/workflows/build-storybook.yml index a5a17c8fe65c..8bd0498dadd9 100644 --- a/.github/workflows/build-storybook.yml +++ b/.github/workflows/build-storybook.yml @@ -10,16 +10,22 @@ jobs: build-storybook: name: Build storybook runs-on: ubuntu-latest + env: + # For a `pull_request` event, the branch is `github.head_ref``. + # For a `push` event, the branch is `github.ref_name`. + BRANCH: ${{ github.head_ref || github.ref_name }} steps: - name: Checkout and setup high risk environment uses: MetaMask/action-checkout-and-setup@v1 with: is-high-risk-environment: true + skip-allow-scripts: true - name: Build storybook run: yarn storybook:build - name: Upload 'storybook-build' to S3 + if: ${{ vars.AWS_REGION && vars.AWS_IAM_ROLE && vars.AWS_S3_BUCKET }} uses: metamask/github-tools/.github/actions/upload-s3@1233659b3850eb84824d7375e2e0c58eb237701d with: aws-region: ${{ vars.AWS_REGION }} @@ -28,9 +34,9 @@ jobs: path: storybook-build - name: Deploy storybook - # For a `pull_request` event, the branch is `github.head_ref``. - # For a `push` event, the branch is `github.ref_name`. - if: ${{ (github.head_ref || github.ref_name) == 'main' }} + if: ${{ env.BRANCH == 'main' && env.STORYBOOK_TOKEN }} + env: + STORYBOOK_TOKEN: ${{ secrets.STORYBOOK_TOKEN }} run: | - git remote add storybook https://${{ secrets.STORYBOOK_TOKEN }}@github.com/MetaMask/metamask-storybook.git + git remote add storybook "https://${STORYBOOK_TOKEN}@github.com/MetaMask/metamask-storybook.git" yarn storybook:deploy diff --git a/.github/workflows/check-attributions.yml b/.github/workflows/check-attributions.yml index 05de6ff6b5eb..793c2f3fb9c4 100644 --- a/.github/workflows/check-attributions.yml +++ b/.github/workflows/check-attributions.yml @@ -12,6 +12,7 @@ jobs: uses: MetaMask/action-checkout-and-setup@v1 with: is-high-risk-environment: false + skip-allow-scripts: true - name: Check attributions changes run: yarn attributions:check diff --git a/.github/workflows/check-pr-labels.yml b/.github/workflows/check-pr-labels.yml index 06a8e3c7870f..6f0bfb4a582c 100644 --- a/.github/workflows/check-pr-labels.yml +++ b/.github/workflows/check-pr-labels.yml @@ -21,6 +21,7 @@ jobs: uses: MetaMask/action-checkout-and-setup@v1 with: is-high-risk-environment: false + skip-allow-scripts: true - name: Check PR has required labels env: diff --git a/.github/workflows/check-template-and-add-labels.yml b/.github/workflows/check-template-and-add-labels.yml index 0317998444d7..4b37d0f96172 100644 --- a/.github/workflows/check-template-and-add-labels.yml +++ b/.github/workflows/check-template-and-add-labels.yml @@ -14,6 +14,7 @@ jobs: uses: MetaMask/action-checkout-and-setup@v1 with: is-high-risk-environment: false + skip-allow-scripts: true - name: Check template and add labels id: check-template-and-add-labels diff --git a/.github/workflows/close-bug-report.yml b/.github/workflows/close-bug-report.yml index 286c1f8ddb14..fc5a019c776d 100644 --- a/.github/workflows/close-bug-report.yml +++ b/.github/workflows/close-bug-report.yml @@ -16,6 +16,7 @@ jobs: uses: MetaMask/action-checkout-and-setup@v1 with: is-high-risk-environment: false + skip-allow-scripts: true - name: Close release bug report issue env: diff --git a/.github/workflows/create-bug-report.yml b/.github/workflows/create-bug-report.yml index 85b1a687a7a3..1a83341da2e8 100644 --- a/.github/workflows/create-bug-report.yml +++ b/.github/workflows/create-bug-report.yml @@ -22,6 +22,7 @@ jobs: uses: MetaMask/action-checkout-and-setup@v1 with: is-high-risk-environment: false + skip-allow-scripts: true - name: Create bug report issue on planning repo if: steps.extract_version.outputs.version diff --git a/.github/workflows/e2e-chrome.yml b/.github/workflows/e2e-chrome.yml index 33b7b0138946..9d663be36b50 100644 --- a/.github/workflows/e2e-chrome.yml +++ b/.github/workflows/e2e-chrome.yml @@ -19,6 +19,21 @@ jobs: matrix-index: ${{ matrix.index }} matrix-total: ${{ strategy.job-total }} + test-e2e-chrome-webpack: + uses: ./.github/workflows/run-e2e.yml + strategy: + fail-fast: false + matrix: + index: + [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19] + with: + test-suite-name: test-e2e-chrome-webpack + build-artifact: prep-build-test-webpack-chrome + build-command: yarn build:test:webpack + test-command: yarn test:e2e:chrome:webpack + matrix-index: ${{ matrix.index }} + matrix-total: ${{ strategy.job-total }} + test-e2e-chrome-multiple-providers: uses: ./.github/workflows/run-e2e.yml with: @@ -40,7 +55,7 @@ jobs: strategy: fail-fast: false matrix: - index: [0, 1, 2, 3, 4, 5, 6, 7] + index: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] with: test-suite-name: test-e2e-chrome-flask build-command: yarn build:test:flask @@ -48,30 +63,9 @@ jobs: matrix-index: ${{ matrix.index }} matrix-total: ${{ strategy.job-total }} - test-e2e-chrome-report: - needs: - - test-e2e-chrome - - test-e2e-chrome-multiple-providers - - test-e2e-chrome-rpc - - test-e2e-chrome-flask - runs-on: ubuntu-latest - if: always() - continue-on-error: true # soft launch - steps: - - uses: actions/checkout@v4 - - - name: Download test results - uses: actions/download-artifact@v4 - with: - path: . - pattern: test-e2e-* - merge-multiple: true - - - name: Test Report - uses: dorny/test-reporter@6e6a65b7a0bd2c9197df7d0ae36ac5cee784230c - with: - name: 'šŸ“ Consolidated E2E Tests Report' - path: './test/test-results/e2e/**/*.xml' - reporter: jest-junit - fail-on-empty: false - fail-on-error: false # soft launch + test-e2e-chrome-vault-decryption: + uses: ./.github/workflows/run-e2e.yml + with: + test-suite-name: test-e2e-chrome-vault-decryption + build-artifact: prep-build-dist-browserify-chrome + test-command: yarn test:e2e:single test/e2e/vault-decryption-chrome.spec.ts --browser chrome diff --git a/.github/workflows/e2e-firefox.yml b/.github/workflows/e2e-firefox.yml index e02247a6a30d..2e2cd044d65e 100644 --- a/.github/workflows/e2e-firefox.yml +++ b/.github/workflows/e2e-firefox.yml @@ -9,8 +9,8 @@ jobs: strategy: fail-fast: false matrix: - # prettier-ignore - index: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23] + index: + [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19] with: test-suite-name: test-e2e-firefox build-command: yarn build:test:mv2 @@ -30,29 +30,3 @@ jobs: test-command: yarn test:e2e:firefox:flask matrix-index: ${{ matrix.index }} matrix-total: ${{ strategy.job-total }} - - test-e2e-firefox-report: - needs: - - test-e2e-firefox - - test-e2e-firefox-flask - runs-on: ubuntu-latest - if: always() - continue-on-error: true # soft launch - steps: - - uses: actions/checkout@v4 - - - name: Download test results - uses: actions/download-artifact@v4 - with: - path: . - pattern: test-e2e-* - merge-multiple: true - - - name: Test Report - uses: dorny/test-reporter@6e6a65b7a0bd2c9197df7d0ae36ac5cee784230c - with: - name: 'šŸ“ Consolidated Firefox E2E Tests Report' - path: './test/test-results/e2e/**/*.xml' - reporter: jest-junit - fail-on-empty: false - fail-on-error: false # soft launch diff --git a/.github/workflows/fitness-functions.yml b/.github/workflows/fitness-functions.yml index 2391b1d269b5..fca59a659a79 100644 --- a/.github/workflows/fitness-functions.yml +++ b/.github/workflows/fitness-functions.yml @@ -16,6 +16,7 @@ jobs: with: is-high-risk-environment: false fetch-depth: 0 # This is needed to checkout all branches + skip-allow-scripts: true - name: Run fitness functions env: diff --git a/.github/workflows/get-release-timelines.yml b/.github/workflows/get-release-timelines.yml index 7507738ec69e..5b6b01a4efd1 100644 --- a/.github/workflows/get-release-timelines.yml +++ b/.github/workflows/get-release-timelines.yml @@ -6,13 +6,13 @@ on: version: required: true type: string - description: 'The version of the release' + description: The version of the release jobs: get-release-timelines: - uses: metamask/github-tools/.github/workflows/get-release-timelines.yml@3e0b0204e41b576263b9060945de3b3b9b8c5448 + uses: metamask/github-tools/.github/workflows/get-release-timelines.yml@13b73c8c7dd15f38bacc1bb95401fe11914c6629 with: - version: ${{ github.event.inputs.version }} + version: ${{ inputs.version }} secrets: - RUNWAY_APP_ID: '' - RUNWAY_API_KEY: '' + RUNWAY_APP_ID: ${{ secrets.RUNWAY_APP_ID }} + RUNWAY_API_KEY: ${{ secrets.RUNWAY_API_KEY }} diff --git a/.github/workflows/identify-codeowners.yml b/.github/workflows/identify-codeowners.yml new file mode 100644 index 000000000000..08879938d6bf --- /dev/null +++ b/.github/workflows/identify-codeowners.yml @@ -0,0 +1,25 @@ +name: Identify Codeowners + +on: + pull_request: + types: + - opened + - reopened + - synchronize + - ready_for_review + +jobs: + identify-codeowners: + runs-on: ubuntu-latest + steps: + - name: Checkout and setup environment + uses: MetaMask/action-checkout-and-setup@v1 + with: + is-high-risk-environment: false + skip-allow-scripts: true + + - name: Identify codeowners + if: ${{ env.PR_COMMENT_TOKEN }} + env: + PR_COMMENT_TOKEN: ${{ secrets.PR_COMMENT_TOKEN }} + run: yarn tsx ./.github/scripts/identify-codeowners.ts diff --git a/.github/workflows/locales-only.yml b/.github/workflows/locales-only.yml index f2af3a5358a8..5114108791e7 100644 --- a/.github/workflows/locales-only.yml +++ b/.github/workflows/locales-only.yml @@ -19,6 +19,7 @@ jobs: uses: MetaMask/action-checkout-and-setup@v1 with: is-high-risk-environment: false + skip-allow-scripts: true - name: Get changed files with git diff run: yarn tsx .github/scripts/git-diff-default-branch.ts diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 692665b49adf..ec2619ef383b 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -17,15 +17,13 @@ on: jobs: prep-deps: runs-on: ubuntu-latest - # For a `pull_request` event, the branch is `github.head_ref``. - # For a `push` event, the branch is `github.ref_name`. - if: ${{ (github.head_ref || github.ref_name) != 'l10n_crowdin_action' }} steps: - name: Checkout and setup environment uses: MetaMask/action-checkout-and-setup@v1 with: is-high-risk-environment: false cache-node-modules: true + skip-allow-scripts: true lint-workflows: name: Lint workflows @@ -46,6 +44,7 @@ jobs: uses: MetaMask/action-checkout-and-setup@v1 with: is-high-risk-environment: false + skip-allow-scripts: true - name: Check circular dependencies run: yarn circular-deps:check @@ -80,6 +79,7 @@ jobs: uses: MetaMask/action-checkout-and-setup@v1 with: is-high-risk-environment: false + skip-allow-scripts: true - run: yarn build:test @@ -104,10 +104,9 @@ jobs: uses: MetaMask/action-checkout-and-setup@v1 with: is-high-risk-environment: false + skip-allow-scripts: true - - run: yarn webpack --test --no-lavamoat --no-cache --browser=chrome --browser=firefox --lockdown --sentry --snow --env production - env: - SEGMENT_PROD_WRITE_KEY: '-' + - run: yarn build:test:webpack - name: Upload artifact prep-build-test-webpack-chrome uses: actions/upload-artifact@v4 @@ -125,15 +124,21 @@ jobs: needs: - prep-deps runs-on: ubuntu-latest + env: + # For a `pull_request` event, the branch is `github.head_ref``. + # For a `push` event, the branch is `github.ref_name`. + BRANCH: ${{ github.head_ref || github.ref_name }} steps: - name: Checkout and setup environment uses: MetaMask/action-checkout-and-setup@v1 with: is-high-risk-environment: false + skip-allow-scripts: true - - run: yarn build dist + # GHA does not allow the : ? ternary operator, you must write && || + - run: ${{ env.BRANCH == 'master' && 'yarn build prod' || 'yarn build dist' }} env: - INFURA_PROJECT_ID: '-' + INFURA_PROJECT_ID: 'FAKE' - name: Upload artifact prep-build-dist-browserify-chrome uses: actions/upload-artifact@v4 @@ -173,6 +178,9 @@ jobs: # For a `pull_request` event, the branch is `github.head_ref``. # For a `push` event, the branch is `github.ref_name`. BRANCH: ${{ github.head_ref || github.ref_name }} + # For a `pull_request` event, the fork is `github.event.pull_request.head.repo.fork`. + # For a `push` event, the fork is `github.event.repository.fork`. + IS_FORK: ${{ github.event.pull_request.head.repo.fork || github.event.repository.fork }} permissions: contents: read # id-token permission is required for uploading to s3 @@ -182,6 +190,7 @@ jobs: uses: MetaMask/action-checkout-and-setup@v1 with: is-high-risk-environment: false + skip-allow-scripts: true - name: Download artifact prep-build-dist-browserify-chrome uses: actions/download-artifact@v4 @@ -194,10 +203,11 @@ jobs: run: yarn tsx test/e2e/mv3-perf-stats/bundle-size.ts --out test-artifacts/chrome - name: Record bundle size at commit - if: ${{ env.BRANCH == 'main' }} + if: ${{ env.BRANCH == 'main' && !env.IS_FORK }} run: ./.github/scripts/bundle-stats-commit.sh - name: Upload 'bundle-size' to S3 + if: ${{ vars.AWS_REGION && vars.AWS_IAM_ROLE && vars.AWS_S3_BUCKET }} uses: metamask/github-tools/.github/actions/upload-s3@1233659b3850eb84824d7375e2e0c58eb237701d with: aws-region: ${{ vars.AWS_REGION }} @@ -214,6 +224,8 @@ jobs: needs: - needs-e2e - prep-build-test-browserify + - prep-build-test-webpack + - prep-build-dist-browserify if: ${{ needs.needs-e2e.outputs.needs-e2e == 'true' }} uses: ./.github/workflows/e2e-chrome.yml @@ -249,6 +261,9 @@ jobs: build-beta: name: Build beta uses: ./.github/workflows/build-beta.yml + secrets: + INFURA_PROJECT_ID: ${{ secrets.INFURA_PROJECT_ID }} + SENTRY_DSN_DEV: ${{ secrets.SENTRY_DSN_DEV }} permissions: contents: read # id-token permission is required for uploading to s3 diff --git a/.github/workflows/needs-e2e.yml b/.github/workflows/needs-e2e.yml index 2d17e8cbac9b..04c7f3b46632 100644 --- a/.github/workflows/needs-e2e.yml +++ b/.github/workflows/needs-e2e.yml @@ -9,23 +9,16 @@ on: jobs: needs-e2e: - name: Needs E2E runs-on: ubuntu-latest outputs: needs-e2e: ${{ steps.needs-e2e.outputs.NEEDS_E2E }} env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - # For a `pull_request` event, the branch is `github.head_ref``. - # For a `push` event, the branch is `github.ref_name`. - BRANCH: ${{ github.head_ref || github.ref_name }} # For a `pull_request` event, the head commit hash is `github.event.pull_request.head.sha`. # For a `push` event, the head commit hash is `github.sha`. HEAD_COMMIT_HASH: ${{ github.event.pull_request.head.sha || github.sha }} steps: - - name: Checkout and setup environment - uses: MetaMask/action-checkout-and-setup@v1 + - uses: actions/checkout@v4 with: - is-high-risk-environment: false # By default, the checkout action checks out the last merge commit for pull requests. # Source: https://docs.github.com/en/actions/writing-workflows/choosing-when-your-workflow-runs/events-that-trigger-workflows#pull_request # However, we need the head commit (the latest commit pushed to the source branch) @@ -37,15 +30,39 @@ jobs: id: needs-e2e run: | if git show --format='%B' --no-patch "${HEAD_COMMIT_HASH}" | grep --fixed-strings --quiet '[skip e2e]'; then - printf '%s\n' "${HEAD_COMMIT_HASH} contains the tag '[skip e2e]' so e2e tests will not run" + printf '%s\n' "Commit message of '${HEAD_COMMIT_HASH}' contains the substring '[skip e2e]' so e2e tests will not run" echo "NEEDS_E2E=false" >> "$GITHUB_OUTPUT" else - printf '%s\n' "${HEAD_COMMIT_HASH} does not contain the tag '[skip e2e]' so e2e tests will run" + printf '%s\n' "Commit message of '${HEAD_COMMIT_HASH}' does not contain the substring '[skip e2e]' so e2e tests will run" echo "NEEDS_E2E=true" >> "$GITHUB_OUTPUT" fi + changed-files: + # For a `pull_request` event, the branch is `github.head_ref``. + # For a `push` event, the branch is `github.ref_name`. + if: ${{ needs.needs-e2e.outputs.needs-e2e == 'true' && (github.head_ref || github.ref_name) != 'master' }} + needs: + - needs-e2e + runs-on: ubuntu-latest + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + # For a `pull_request` event, the head commit hash is `github.event.pull_request.head.sha`. + # For a `push` event, the head commit hash is `github.sha`. + HEAD_COMMIT_HASH: ${{ github.event.pull_request.head.sha || github.sha }} + steps: + - name: Checkout and setup environment + uses: MetaMask/action-checkout-and-setup@v1 + with: + is-high-risk-environment: false + # By default, the checkout action checks out the last merge commit for pull requests. + # Source: https://docs.github.com/en/actions/writing-workflows/choosing-when-your-workflow-runs/events-that-trigger-workflows#pull_request + # However, we need the head commit (the latest commit pushed to the source branch) + # because in the workflow, we would like to parse the latest commit tag. + # Specifying `ref` ensures that the head commit is checked out directly. + ref: ${{ env.HEAD_COMMIT_HASH }} + skip-allow-scripts: true + - name: Get changed files with git diff - if: ${{ steps.needs-e2e.outputs.NEEDS_E2E == 'true' && env.BRANCH != 'master' }} run: yarn tsx .github/scripts/git-diff-default-branch.ts - name: Upload changed files artifact @@ -55,18 +72,21 @@ jobs: path: ./changed-files/ run-e2e-pom-validation: + if: ${{ needs.needs-e2e.outputs.needs-e2e == 'true' && (github.head_ref || github.ref_name) != 'master' }} needs: - needs-e2e + - changed-files runs-on: ubuntu-latest steps: - name: Checkout and setup environment uses: MetaMask/action-checkout-and-setup@v1 with: is-high-risk-environment: false + skip-allow-scripts: true - name: Download changed-files artifact - continue-on-error: true uses: actions/download-artifact@v4 + continue-on-error: true with: name: changed-files path: ./changed-files/ diff --git a/.github/workflows/publish-prerelease.yml b/.github/workflows/publish-prerelease.yml index 7dfee6deb387..909bdf7c785c 100644 --- a/.github/workflows/publish-prerelease.yml +++ b/.github/workflows/publish-prerelease.yml @@ -16,6 +16,7 @@ jobs: with: is-high-risk-environment: true fetch-depth: 0 # This is needed to get merge base to calculate bundle size diff + skip-allow-scripts: true - name: Get merge base commit hash id: get-merge-base @@ -32,25 +33,30 @@ jobs: env: OWNER: ${{ github.repository_owner }} REPOSITORY: ${{ github.event.repository.name }} - # For a `pull_request` event, the branch is `github.head_ref``. - BRANCH: ${{ github.head_ref }} + # For a `pull_request` event, the fork is `github.event.pull_request.head.repo.fork`, and the branch is `github.head_ref`. + BRANCH: ${{ github.event.pull_request.head.repo.fork && format('pull/{0}', github.event.pull_request.number) || github.head_ref }} # For a `pull_request` event, the head commit hash is `github.event.pull_request.head.sha`. HEAD_COMMIT_HASH: ${{ github.event.pull_request.head.sha }} JOB_NAME: job-publish-prerelease run: | - pipeline_id=$(curl --silent "https://circleci.com/api/v2/project/gh/$OWNER/$REPOSITORY/pipeline?branch=$BRANCH" | jq --arg head_commit_hash "${HEAD_COMMIT_HASH}" -r '.items | map(select(.vcs.revision == $head_commit_hash)) | first | .id') - workflow_id=$(curl --silent "https://circleci.com/api/v2/pipeline/$pipeline_id/workflow" | jq -r ".items[0].id") - job_details=$(curl --silent "https://circleci.com/api/v2/workflow/$workflow_id/job" | jq --arg job_name "${JOB_NAME}" -r '.items[] | select(.name == $job_name)') + pipeline=$(curl --silent "https://circleci.com/api/v2/project/gh/${OWNER}/${REPOSITORY}/pipeline?branch=${BRANCH}" | jq --arg head_commit_hash "${HEAD_COMMIT_HASH}" -r '.items | map(select(.vcs.revision == $head_commit_hash)) | first') + pipeline_id=$(echo "${pipeline}" | jq -r '.id') + pipeline_number=$(echo "${pipeline}" | jq -r '.number') - build_num=$(echo "$job_details" | jq -r '.job_number') - echo 'CIRCLE_BUILD_NUM='"$build_num" >> "$GITHUB_OUTPUT" + workflow=$(curl --silent "https://circleci.com/api/v2/pipeline/${pipeline_id}/workflow" | jq -r '.items[0]') + workflow_id=$(echo "${workflow}" | jq -r '.id') - job_id=$(echo "$job_details" | jq -r '.id') - echo 'CIRCLE_WORKFLOW_JOB_ID='"$job_id" >> "$GITHUB_OUTPUT" + job=$(curl --silent "https://circleci.com/api/v2/workflow/${workflow_id}/job" | jq --arg job_name "${JOB_NAME}" -r '.items[] | select(.name == $job_name)') + job_id=$(echo "${job}" | jq -r '.id') + job_number=$(echo "${job}" | jq -r '.job_number') - echo "Getting artifacts from pipeline '${pipeline_id}', workflow '${workflow_id}', build number '${build_num}', job id '${job_id}'" + echo "CIRCLE_WORKFLOW_JOB_ID=${job_id}" >> "$GITHUB_OUTPUT" + echo "CIRCLE_BUILD_NUM=${job_number}" >> "$GITHUB_OUTPUT" + + echo "Getting artifacts from pipeline number '${pipeline_number}', workflow id '${workflow_id}', job number '${job_number}' at https://app.circleci.com/pipelines/github/${OWNER}/${REPOSITORY}/${pipeline_number}/workflows/${workflow_id}/jobs/${job_number}/artifacts" - name: Publish prerelease + if: ${{ env.PR_COMMENT_TOKEN && vars.AWS_CLOUDFRONT_URL }} env: PR_COMMENT_TOKEN: ${{ secrets.PR_COMMENT_TOKEN }} PR_NUMBER: ${{ github.event.pull_request.number }} diff --git a/.github/workflows/repository-health-checks.yml b/.github/workflows/repository-health-checks.yml index 5bf5d07a353a..157aa6cea091 100644 --- a/.github/workflows/repository-health-checks.yml +++ b/.github/workflows/repository-health-checks.yml @@ -15,6 +15,7 @@ jobs: uses: MetaMask/action-checkout-and-setup@v1 with: is-high-risk-environment: false + skip-allow-scripts: true # test-lint-shellcheck - name: ShellCheck Lint diff --git a/.github/workflows/run-benchmarks.yml b/.github/workflows/run-benchmarks.yml index f6a8fd87b153..da1393ddcf99 100644 --- a/.github/workflows/run-benchmarks.yml +++ b/.github/workflows/run-benchmarks.yml @@ -28,6 +28,7 @@ jobs: uses: MetaMask/action-checkout-and-setup@v1 with: is-high-risk-environment: false + skip-allow-scripts: true - name: Download artifact ${{ env.ARTIFACT_NAME }} uses: actions/download-artifact@v4 @@ -42,6 +43,7 @@ jobs: run: ${{ format(fromJson(env.COMMANDS)[matrix.testType], matrix.browser, matrix.buildType) }} - name: Upload '${{ env.OUTPUT_NAME }}' to S3 + if: ${{ vars.AWS_REGION && vars.AWS_IAM_ROLE && vars.AWS_S3_BUCKET }} uses: metamask/github-tools/.github/actions/upload-s3@1233659b3850eb84824d7375e2e0c58eb237701d with: aws-region: ${{ vars.AWS_REGION }} diff --git a/.github/workflows/run-e2e.yml b/.github/workflows/run-e2e.yml index fb9c731a1dec..ff0dbc69d74b 100644 --- a/.github/workflows/run-e2e.yml +++ b/.github/workflows/run-e2e.yml @@ -12,8 +12,8 @@ on: default: '' description: The build artifact to download build-command: - required: true type: string + default: '' description: The build command to run test-command: required: true @@ -21,7 +21,7 @@ on: description: The test command to run test-timeout-minutes: type: number - default: 30 + default: 40 description: The timeout in minutes for the test command matrix-index: type: number @@ -56,6 +56,7 @@ jobs: uses: MetaMask/action-checkout-and-setup@v1 with: is-high-risk-environment: false + skip-allow-scripts: true # not installed by checkout-and-setup when cache is restored - name: Install anvil @@ -70,9 +71,9 @@ jobs: name: ${{ inputs.build-artifact }} path: ./dist/ - # if there is no build artifact, or the specified artifact does not exist, we run the build command + # if there is a build-command and there is no build artifact, or the specified artifact does not exist, we run the build command - run: ${{ inputs.build-command }} - if: ${{ inputs.build-artifact == '' || steps.download-build-artifact.outcome == 'failure' }} + if: ${{ inputs.build-command != '' && (inputs.build-artifact == '' || steps.download-build-artifact.outcome == 'failure') }} - name: Configure Xvfb run: Xvfb -ac :99 -screen 0 1280x1024x16 & @@ -95,7 +96,7 @@ jobs: run: ${{ inputs.test-command }} --retries 1 - name: Upload test results and artifacts - if: always() + if: ${{ !cancelled() }} uses: actions/upload-artifact@v4 with: name: ${{ inputs.test-suite-name }}${{ inputs.matrix-total > 1 && format('-{0}', inputs.matrix-index) || '' }} diff --git a/.github/workflows/run-tests.yml b/.github/workflows/run-tests.yml index 5f92b0365d1e..29587ac2923c 100644 --- a/.github/workflows/run-tests.yml +++ b/.github/workflows/run-tests.yml @@ -22,6 +22,7 @@ jobs: uses: MetaMask/action-checkout-and-setup@v1 with: is-high-risk-environment: false + skip-allow-scripts: true - name: test:unit:coverage run: yarn test:unit:coverage --shard=${{ matrix.shard }}/${{ strategy.job-total }} @@ -42,6 +43,7 @@ jobs: uses: MetaMask/action-checkout-and-setup@v1 with: is-high-risk-environment: false + skip-allow-scripts: true - name: test:unit:webpack:coverage run: yarn test:unit:webpack:coverage @@ -62,6 +64,7 @@ jobs: uses: MetaMask/action-checkout-and-setup@v1 with: is-high-risk-environment: false + skip-allow-scripts: true - name: test:integration:coverage run: yarn test:integration:coverage @@ -89,6 +92,7 @@ jobs: uses: MetaMask/action-checkout-and-setup@v1 with: is-high-risk-environment: false + skip-allow-scripts: true - name: Download artifacts uses: actions/download-artifact@v4 diff --git a/.github/workflows/security-code-scanner.yml b/.github/workflows/security-code-scanner.yml index 2180083150b8..58a377bd305d 100644 --- a/.github/workflows/security-code-scanner.yml +++ b/.github/workflows/security-code-scanner.yml @@ -1,10 +1,13 @@ -name: 'MetaMask Security Code Scanner' +name: MetaMask Security Code Scanner on: push: - branches: ['main'] + branches: + - main pull_request: - branches: ['main'] + branches: + - main + workflow_dispatch: jobs: run-security-scan: diff --git a/.github/workflows/test-lint.yml b/.github/workflows/test-lint.yml index 09e73a2b8235..024a4cfc5b5a 100644 --- a/.github/workflows/test-lint.yml +++ b/.github/workflows/test-lint.yml @@ -12,6 +12,7 @@ jobs: uses: MetaMask/action-checkout-and-setup@v1 with: is-high-risk-environment: false + skip-allow-scripts: true - name: Lint run: yarn lint diff --git a/.github/workflows/test-storybook.yml b/.github/workflows/test-storybook.yml index 63b9c72daa38..da5f3f92ba66 100644 --- a/.github/workflows/test-storybook.yml +++ b/.github/workflows/test-storybook.yml @@ -12,6 +12,7 @@ jobs: uses: MetaMask/action-checkout-and-setup@v1 with: is-high-risk-environment: false + skip-allow-scripts: true - name: Install Playwright browsers run: yarn exec playwright install chromium diff --git a/.github/workflows/update-attributions.yml b/.github/workflows/update-attributions.yml index c5095fb7f0be..51dc9d113fd5 100644 --- a/.github/workflows/update-attributions.yml +++ b/.github/workflows/update-attributions.yml @@ -62,6 +62,7 @@ jobs: uses: MetaMask/action-checkout-and-setup@v1 with: is-high-risk-environment: false + skip-allow-scripts: true - name: Get commit SHA id: commit-sha run: echo "COMMIT_SHA=$(git rev-parse --short HEAD)" >> "$GITHUB_OUTPUT" @@ -86,6 +87,7 @@ jobs: uses: MetaMask/action-checkout-and-setup@v1 with: is-high-risk-environment: false + skip-allow-scripts: true - name: Generate Attributions run: yarn attributions:generate - name: Cache attributions file diff --git a/.github/workflows/update-lavamoat-policies.yml b/.github/workflows/update-lavamoat-policies.yml index 9dd1bdb8339c..6b765673bde1 100644 --- a/.github/workflows/update-lavamoat-policies.yml +++ b/.github/workflows/update-lavamoat-policies.yml @@ -62,6 +62,7 @@ jobs: uses: MetaMask/action-checkout-and-setup@v1 with: is-high-risk-environment: false + skip-allow-scripts: true - name: Get commit SHA id: commit-sha run: echo "COMMIT_SHA=$(git rev-parse --short HEAD)" >> "$GITHUB_OUTPUT" @@ -83,6 +84,7 @@ jobs: uses: MetaMask/action-checkout-and-setup@v1 with: is-high-risk-environment: false + skip-allow-scripts: true - name: Update LavaMoat build policy run: yarn lavamoat:build:auto - name: Cache build policy @@ -114,6 +116,7 @@ jobs: uses: MetaMask/action-checkout-and-setup@v1 with: is-high-risk-environment: false + skip-allow-scripts: true - name: Restore build policy uses: actions/cache/restore@v4 with: diff --git a/.github/workflows/validate-lavamoat-policy-build.yml b/.github/workflows/validate-lavamoat-policy-build.yml index 42c6be31ce39..d0af292b4798 100644 --- a/.github/workflows/validate-lavamoat-policy-build.yml +++ b/.github/workflows/validate-lavamoat-policy-build.yml @@ -12,6 +12,7 @@ jobs: uses: MetaMask/action-checkout-and-setup@v1 with: is-high-risk-environment: false + skip-allow-scripts: true - name: Validate lavamoat build policy run: yarn lavamoat:build:auto diff --git a/.github/workflows/validate-lavamoat-policy-webapp.yml b/.github/workflows/validate-lavamoat-policy-webapp.yml index b2ecc2d9c7f8..447c23a76c64 100644 --- a/.github/workflows/validate-lavamoat-policy-webapp.yml +++ b/.github/workflows/validate-lavamoat-policy-webapp.yml @@ -15,6 +15,7 @@ jobs: uses: MetaMask/action-checkout-and-setup@v1 with: is-high-risk-environment: false + skip-allow-scripts: true - name: Validate lavamoat ${{ matrix.build-type }} policy run: yarn lavamoat:webapp:auto:ci --build-types=${{ matrix.build-type }} diff --git a/.github/workflows/wait-for-circleci-workflow-status.yml b/.github/workflows/wait-for-circleci-workflow-status.yml index 9c3c58f3aabc..3d5bb1e071b5 100644 --- a/.github/workflows/wait-for-circleci-workflow-status.yml +++ b/.github/workflows/wait-for-circleci-workflow-status.yml @@ -12,26 +12,32 @@ jobs: env: OWNER: ${{ github.repository_owner }} REPOSITORY: ${{ github.event.repository.name }} - # For a `pull_request` event, the branch is `github.head_ref``. - # For a `push` event, the branch is `github.ref_name`. - BRANCH: ${{ github.head_ref || github.ref_name }} + # For a `pull_request` event, the fork is `github.event.pull_request.head.repo.fork`, and the branch is `github.head_ref`. + # For a `push` event, the fork is `github.event.repository.fork`, and the branch is `github.ref_name`. + BRANCH: ${{ (github.event.pull_request.head.repo.fork || github.event.repository.fork) && format('pull/{0}', github.event.pull_request.number) || (github.head_ref || github.ref_name) }} # For a `pull_request` event, the head commit hash is `github.event.pull_request.head.sha`. # For a `push` event, the head commit hash is `github.sha`. HEAD_COMMIT_HASH: ${{ github.event.pull_request.head.sha || github.sha }} run: | - pipeline_id=$(curl --silent "https://circleci.com/api/v2/project/gh/$OWNER/$REPOSITORY/pipeline?branch=$BRANCH" | jq --arg head_commit_hash "${HEAD_COMMIT_HASH}" -r '.items | map(select(.vcs.revision == $head_commit_hash)) | first | .id') - echo "Waiting for pipeline '${pipeline_id}', commit hash '${HEAD_COMMIT_HASH}'" - workflow_status=$(curl --silent "https://circleci.com/api/v2/pipeline/$pipeline_id/workflow" | jq -r ".items[0].status") + pipeline=$(curl --silent "https://circleci.com/api/v2/project/gh/${OWNER}/${REPOSITORY}/pipeline?branch=${BRANCH}" | jq --arg head_commit_hash "${HEAD_COMMIT_HASH}" -r '.items | map(select(.vcs.revision == $head_commit_hash)) | first') + pipeline_id=$(echo "${pipeline}" | jq -r '.id') + pipeline_number=$(echo "${pipeline}" | jq -r '.number') - if [ "$workflow_status" == "running" ]; then - while [ "$workflow_status" == "running" ]; do + workflow=$(curl --silent "https://circleci.com/api/v2/pipeline/${pipeline_id}/workflow" | jq -r '.items[0]') + workflow_id=$(echo "${workflow}" | jq -r '.id') + workflow_status=$(echo "${workflow}" | jq -r '.status') + + echo "Waiting for pipeline number '${pipeline_number}', workflow id '${workflow_id}' at https://app.circleci.com/pipelines/github/${OWNER}/${REPOSITORY}/${pipeline_number}/workflows/${workflow_id}" + + if [ "${workflow_status}" == "running" ]; then + while [ "${workflow_status}" == "running" ]; do sleep 30 - workflow_status=$(curl --silent "https://circleci.com/api/v2/pipeline/$pipeline_id/workflow" | jq -r ".items[0].status") + workflow_status=$(curl --silent "https://circleci.com/api/v2/pipeline/${pipeline_id}/workflow" | jq -r ".items[0].status") done fi # The "not_run" only happens when you're developing CI workflows and testing weird cases - if [ "$workflow_status" != "success" ] && [ "$workflow_status" != "not_run" ]; then - echo "::error::Workflow status is '$workflow_status'. Exiting with error." + if [ "${workflow_status}" != "success" ] && [ "${workflow_status}" != "not_run" ]; then + echo "::error::Workflow status is '${workflow_status}'. Exiting with error." exit 1 fi diff --git a/.madgerc b/.madgerc index 775bb386147c..4572e9401249 100644 --- a/.madgerc +++ b/.madgerc @@ -24,7 +24,6 @@ }, "allowedCircularGlob": [ "ui/pages/confirmations/**", - "ui/pages/notifications/**", "ui/ducks/**", "ui/selectors/**", "ui/hooks/**", diff --git a/.storybook/metamask-storybook-theme.js b/.storybook/metamask-storybook-theme.js index 685702767484..afed3241a3c3 100644 --- a/.storybook/metamask-storybook-theme.js +++ b/.storybook/metamask-storybook-theme.js @@ -2,5 +2,5 @@ export const metamaskStorybookTheme = { brandTitle: 'MetaMask Storybook', // Typography - fontBase: 'Euclid Circular B, Helvetica, Arial, sans-serif', + fontBase: 'var(--font-family-default)', // from @metamask/design-tokens stylesheet }; diff --git a/.storybook/test-data.js b/.storybook/test-data.js index 0bb5a82fe7bb..590388d2c692 100644 --- a/.storybook/test-data.js +++ b/.storybook/test-data.js @@ -718,12 +718,6 @@ const state = { }, tokenNetworkFilter: {}, }, - incomingTransactionsPreferences: { - [CHAIN_IDS.MAINNET]: true, - [CHAIN_IDS.GOERLI]: false, - [CHAIN_IDS.OPTIMISM_TESTNET]: false, - [CHAIN_IDS.AVALANCHE_TESTNET]: true, - }, firstTimeFlowType: FirstTimeFlowType.create, completedOnboarding: true, knownMethodData: { diff --git a/.yarn/patches/@keystonehq-metamask-airgapped-keyring-npm-0.14.1-bb25561255.patch b/.yarn/patches/@keystonehq-metamask-airgapped-keyring-npm-0.14.1-bb25561255.patch deleted file mode 100644 index 5a75b494d235..000000000000 --- a/.yarn/patches/@keystonehq-metamask-airgapped-keyring-npm-0.14.1-bb25561255.patch +++ /dev/null @@ -1,60 +0,0 @@ -diff --git a/dist/MetaMaskKeyring.d.ts b/dist/MetaMaskKeyring.d.ts -index 992e911b068dca6331c1a0ccab7b72ccf324aa02..f4274ec3246ea01a33e29db445810cf6b1f902f5 100644 ---- a/dist/MetaMaskKeyring.d.ts -+++ b/dist/MetaMaskKeyring.d.ts -@@ -4,6 +4,7 @@ export declare class MetaMaskKeyring extends BaseKeyring { - static type: string; - static instance: MetaMaskKeyring; - constructor(opts?: StoredKeyring); -+ addAccounts(n?: number): Promise; - getInteraction: () => MetamaskInteractionProvider; - resetStore: () => void; - getMemStore: () => import("./MetaMaskInteractionProvider").IMemState; -diff --git a/dist/metamask-airgapped-keyring.cjs.development.js b/dist/metamask-airgapped-keyring.cjs.development.js -index f2ea37802fea46db869d57240349143f06a2ce40..a3c577accbf283d0e80c370e2f076a15ff12b21c 100644 ---- a/dist/metamask-airgapped-keyring.cjs.development.js -+++ b/dist/metamask-airgapped-keyring.cjs.development.js -@@ -180,6 +180,15 @@ class MetaMaskKeyring extends baseEthKeyring.BaseKeyring { - } - MetaMaskKeyring.instance = this; - } -+ /** -+ * PATCH INFORMATION -+ * The addAccounts method from keyrings is now expected to return only newly created accounts. -+ * This patch overrides the method and its return value to ensure it behaves as intended. -+ */ -+ async addAccounts(n = 1) { -+ const accounts = await super.addAccounts(n); -+ return accounts.slice(-1 * n); -+ } - async signTransaction(address, tx$1) { - const dataType = tx$1.type === 0 ? bcUrRegistryEth.DataType.transaction : bcUrRegistryEth.DataType.typedTransaction; - let messageToSign; -diff --git a/dist/metamask-airgapped-keyring.cjs.production.min.js b/dist/metamask-airgapped-keyring.cjs.production.min.js -index 72a1301360eee7b35956faa9b8b7965a7ae76a75..1cc9549d8b6fc94ea1bdfaf423ced92d130c1037 100644 ---- a/dist/metamask-airgapped-keyring.cjs.production.min.js -+++ b/dist/metamask-airgapped-keyring.cjs.production.min.js -@@ -1,2 +1,2 @@ --"use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e,t=require("@keystonehq/base-eth-keyring"),s=require("events"),n=require("@metamask/obs-store"),i=require("@keystonehq/bc-ur-registry-eth"),r=require("uuid"),c=require("@ethereumjs/tx"),o=(e=require("rlp"))&&"object"==typeof e&&"default"in e?e.default:e;class a extends s.EventEmitter{constructor(){if(super(),this.cleanSyncListeners=()=>{this.removeAllListeners("keystone-sync_success-hdkey"),this.removeAllListeners("keystone-sync_success-account"),this.removeAllListeners("keystone-sync_cancel")},this.cleanSignListeners=e=>{this.removeAllListeners(e+"-signed"),this.removeAllListeners(e+"-canceled")},this.readCryptoHDKeyOrCryptoAccount=()=>new Promise((e,t)=>{this.memStore.updateState({sync:{reading:!0}}),this.on("keystone-sync_success-hdkey",t=>{const s=i.CryptoHDKey.fromCBOR(Buffer.from(t,"hex"));this.resetState(),e(s)}),this.on("keystone-sync_success-account",t=>{const s=i.CryptoAccount.fromCBOR(Buffer.from(t,"hex"));this.resetState(),e(s)}),this.on("keystone-sync_cancel",()=>{this.resetState(),t(new Error("KeystoneError#sync_cancel. Sync process canceled, please retry"))})}),this.submitCryptoHDKey=e=>{this.emit("keystone-sync_success-hdkey",e)},this.submitCryptoAccount=e=>{this.emit("keystone-sync_success-account",e)},this.cancelSync=()=>{this.emit("keystone-sync_cancel")},this.requestSignature=(e,t,s)=>new Promise((n,c)=>{const o=e.toUR(),a=e.getRequestId(),h=r.stringify(a),u={requestId:h,payload:{type:o.type,cbor:o.cbor.toString("hex")},title:t,description:s};this.memStore.updateState({sign:{request:u}}),this.once(h+"-signed",e=>{const t=i.ETHSignature.fromCBOR(Buffer.from(e,"hex"));this.resetState(),n(t)}),this.once(h+"-canceled",()=>{this.resetState(),c(new Error("KeystoneError#Tx_canceled. Signing canceled, please retry"))})}),this.submitSignature=(e,t)=>{this.emit(e+"-signed",t)},this.cancelRequestSignature=()=>{const e=this.memStore.getState().sign.request;if(e){const{requestId:t}=e;this.memStore.updateState({sign:{}}),this.emit(t+"-canceled")}},this.reset=()=>{this.cleanSyncListeners();const e=this.memStore.getState().sign.request;if(e){const{requestId:t}=e;this.cleanSignListeners(t)}this.resetState()},this.resetState=()=>{this.memStore.updateState({sync:{reading:!1},sign:{}})},a.instance)return a.instance;this.memStore=new n.ObservableStore({sync:{reading:!1},sign:{},_version:1}),a.instance=this}}class h extends t.BaseKeyring{constructor(e){if(super(e),this.getInteraction=()=>new a,this.resetStore=()=>{this.getInteraction().reset()},this.getMemStore=()=>this.getInteraction().memStore,this.removeAccount=e=>{if(!this.accounts.map(e=>e.toLowerCase()).includes(e.toLowerCase()))throw new Error(`Address ${e} not found in this keyring`);this.accounts=this.accounts.filter(t=>t.toLowerCase()!==e.toLowerCase())},this.forgetDevice=()=>{this.page=0,this.perPage=5,this.accounts=[],this.currentAccount=0,this.name="QR Hardware",this.initialized=!1,this.xfp="",this.xpub="",this.hdPath="",this.indexes={},this.hdk=void 0,this.paths={}},this.submitCryptoHDKey=this.getInteraction().submitCryptoHDKey,this.submitCryptoAccount=this.getInteraction().submitCryptoAccount,this.submitSignature=this.getInteraction().submitSignature,this.cancelSync=this.getInteraction().cancelSync,this.cancelSignRequest=this.getInteraction().cancelRequestSignature,h.instance)return h.instance.deserialize(e),h.instance;h.instance=this}async signTransaction(e,t){const s=0===t.type?i.DataType.transaction:i.DataType.typedTransaction;let n;n=0===t.type?o.encode(t.getMessageToSign(!1)):t.getMessageToSign(!1);const a=await this._pathFromAddress(e),h=t.common.chainId(),u=r.v4(),y=i.EthSignRequest.constructETHRequest(n,s,a,this.xfp,u,h,e),{r:m,s:g,v:d}=await this.requestSignature(u,y,"Scan with your Keystone",'After your Keystone has signed the transaction, click on "Scan Keystone" to receive the signature'),S=t.toJSON();return S.v=d,S.s=g,S.r=m,S.type=t.type,c.TransactionFactory.fromTxData(S,{common:t.common})}}h.type=t.BaseKeyring.type,exports.MetaMaskKeyring=h; -+"use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e,t=require("@keystonehq/base-eth-keyring"),s=require("events"),n=require("@metamask/obs-store"),i=require("@keystonehq/bc-ur-registry-eth"),r=require("uuid"),c=require("@ethereumjs/tx"),o=(e=require("rlp"))&&"object"==typeof e&&"default"in e?e.default:e;class a extends s.EventEmitter{constructor(){if(super(),this.cleanSyncListeners=()=>{this.removeAllListeners("keystone-sync_success-hdkey"),this.removeAllListeners("keystone-sync_success-account"),this.removeAllListeners("keystone-sync_cancel")},this.cleanSignListeners=e=>{this.removeAllListeners(e+"-signed"),this.removeAllListeners(e+"-canceled")},this.readCryptoHDKeyOrCryptoAccount=()=>new Promise((e,t)=>{this.memStore.updateState({sync:{reading:!0}}),this.on("keystone-sync_success-hdkey",t=>{const s=i.CryptoHDKey.fromCBOR(Buffer.from(t,"hex"));this.resetState(),e(s)}),this.on("keystone-sync_success-account",t=>{const s=i.CryptoAccount.fromCBOR(Buffer.from(t,"hex"));this.resetState(),e(s)}),this.on("keystone-sync_cancel",()=>{this.resetState(),t(new Error("KeystoneError#sync_cancel. Sync process canceled, please retry"))})}),this.submitCryptoHDKey=e=>{this.emit("keystone-sync_success-hdkey",e)},this.submitCryptoAccount=e=>{this.emit("keystone-sync_success-account",e)},this.cancelSync=()=>{this.emit("keystone-sync_cancel")},this.requestSignature=(e,t,s)=>new Promise((n,c)=>{const o=e.toUR(),a=e.getRequestId(),h=r.stringify(a),u={requestId:h,payload:{type:o.type,cbor:o.cbor.toString("hex")},title:t,description:s};this.memStore.updateState({sign:{request:u}}),this.once(h+"-signed",e=>{const t=i.ETHSignature.fromCBOR(Buffer.from(e,"hex"));this.resetState(),n(t)}),this.once(h+"-canceled",()=>{this.resetState(),c(new Error("KeystoneError#Tx_canceled. Signing canceled, please retry"))})}),this.submitSignature=(e,t)=>{this.emit(e+"-signed",t)},this.cancelRequestSignature=()=>{const e=this.memStore.getState().sign.request;if(e){const{requestId:t}=e;this.memStore.updateState({sign:{}}),this.emit(t+"-canceled")}},this.reset=()=>{this.cleanSyncListeners();const e=this.memStore.getState().sign.request;if(e){const{requestId:t}=e;this.cleanSignListeners(t)}this.resetState()},this.resetState=()=>{this.memStore.updateState({sync:{reading:!1},sign:{}})},a.instance)return a.instance;this.memStore=new n.ObservableStore({sync:{reading:!1},sign:{},_version:1}),a.instance=this}}class h extends t.BaseKeyring{constructor(e){if(super(e),this.getInteraction=()=>new a,this.resetStore=()=>{this.getInteraction().reset()},this.getMemStore=()=>this.getInteraction().memStore,this.removeAccount=e=>{if(!this.accounts.map(e=>e.toLowerCase()).includes(e.toLowerCase()))throw new Error(`Address ${e} not found in this keyring`);this.accounts=this.accounts.filter(t=>t.toLowerCase()!==e.toLowerCase())},this.forgetDevice=()=>{this.page=0,this.perPage=5,this.accounts=[],this.currentAccount=0,this.name="QR Hardware",this.initialized=!1,this.xfp="",this.xpub="",this.hdPath="",this.indexes={},this.hdk=void 0,this.paths={}},this.submitCryptoHDKey=this.getInteraction().submitCryptoHDKey,this.submitCryptoAccount=this.getInteraction().submitCryptoAccount,this.submitSignature=this.getInteraction().submitSignature,this.cancelSync=this.getInteraction().cancelSync,this.cancelSignRequest=this.getInteraction().cancelRequestSignature,h.instance)return h.instance.deserialize(e),h.instance;h.instance=this}async addAccounts(e=1){return(await super.addAccounts(e)).slice(-1*e)}async signTransaction(e,t){const s=0===t.type?i.DataType.transaction:i.DataType.typedTransaction;let n;n=0===t.type?o.encode(t.getMessageToSign(!1)):t.getMessageToSign(!1);const a=await this._pathFromAddress(e),h=t.common.chainId(),u=r.v4(),y=i.EthSignRequest.constructETHRequest(n,s,a,this.xfp,u,h,e),{r:m,s:g,v:d}=await this.requestSignature(u,y,"Scan with your Keystone",'After your Keystone has signed the transaction, click on "Scan Keystone" to receive the signature'),S=t.toJSON();return S.v=d,S.s=g,S.r=m,S.type=t.type,c.TransactionFactory.fromTxData(S,{common:t.common})}}h.type=t.BaseKeyring.type,exports.MetaMaskKeyring=h; - //# sourceMappingURL=metamask-airgapped-keyring.cjs.production.min.js.map -diff --git a/dist/metamask-airgapped-keyring.esm.js b/dist/metamask-airgapped-keyring.esm.js -index a59a9a5265fa6a11cbd8215422e4896383900148..3593297b93395cbc7d52e7fedd2bcff787169097 100644 ---- a/dist/metamask-airgapped-keyring.esm.js -+++ b/dist/metamask-airgapped-keyring.esm.js -@@ -174,6 +174,15 @@ class MetaMaskKeyring extends BaseKeyring { - } - MetaMaskKeyring.instance = this; - } -+ /** -+ * PATCH INFORMATION -+ * The addAccounts method from keyrings is now expected to return only newly created accounts. -+ * This patch overrides the method and its return value to ensure it behaves as intended. -+ */ -+ async addAccounts(n = 1) { -+ const accounts = await super.addAccounts(n); -+ return accounts.slice(-1 * n); -+ } - async signTransaction(address, tx) { - const dataType = tx.type === 0 ? DataType.transaction : DataType.typedTransaction; - let messageToSign; diff --git a/.yarn/patches/@metamask-transaction-controller-npm-52.3.0-56fc57fbe6.patch b/.yarn/patches/@metamask-transaction-controller-npm-54.0.0-ccc4668363.patch similarity index 51% rename from .yarn/patches/@metamask-transaction-controller-npm-52.3.0-56fc57fbe6.patch rename to .yarn/patches/@metamask-transaction-controller-npm-54.0.0-ccc4668363.patch index c79085b1b4e8..51b34b5de26a 100644 --- a/.yarn/patches/@metamask-transaction-controller-npm-52.3.0-56fc57fbe6.patch +++ b/.yarn/patches/@metamask-transaction-controller-npm-54.0.0-ccc4668363.patch @@ -1,34 +1,8 @@ diff --git a/dist/TransactionController.cjs b/dist/TransactionController.cjs -index c46bd8463907268ac5e2a762a04615d5c1371c20..817b21293437f055249e76cbb75ff4e348606a8c 100644 +index fef52f6b9c89b7ab4c000123a06a2bc00caa8c14..d0fb5d264305ece036f4393d1a064ee848fd2433 100644 --- a/dist/TransactionController.cjs +++ b/dist/TransactionController.cjs -@@ -334,12 +334,12 @@ class TransactionController extends base_controller_1.BaseController { - /** - * Determine which chains support atomic batch transactions with the given account address. - * -- * @param address - The address of the account to check. -- * @returns The supported chain IDs. -+ * @param request - Request object containing the account address and other parameters. -+ * @returns Result object containing the supported chains and related information. - */ -- async isAtomicBatchSupported(address) { -+ async isAtomicBatchSupported(request) { - return (0, batch_1.isAtomicBatchSupported)({ -- address, -+ ...request, - getEthQuery: (chainId) => __classPrivateFieldGet(this, _TransactionController_instances, "m", _TransactionController_getEthQuery).call(this, { chainId }), - messenger: this.messagingSystem, - publicKeyEIP7702: __classPrivateFieldGet(this, _TransactionController_publicKeyEIP7702, "f"), -@@ -399,7 +399,7 @@ class TransactionController extends base_controller_1.BaseController { - }); - const delegationAddressPromise = (0, eip7702_1.getDelegationAddress)(txParams.from, ethQuery).catch(() => undefined); - const isEIP1559Compatible = await this.getEIP1559Compatibility(networkClientId); -- (0, validation_1.validateTxParams)(txParams, isEIP1559Compatible); -+ (0, validation_1.validateTxParams)(txParams, isEIP1559Compatible, chainId); - if (!txParams.type) { - // Determine transaction type based on transaction parameters and network compatibility - (0, utils_2.setEnvelopeType)(txParams, isEIP1559Compatible); -@@ -407,7 +407,7 @@ class TransactionController extends base_controller_1.BaseController { +@@ -408,7 +408,7 @@ class TransactionController extends base_controller_1.BaseController { const isDuplicateBatchId = batchId?.length && this.state.transactions.some((tx) => tx.batchId?.toLowerCase() === batchId?.toLowerCase()); if (isDuplicateBatchId && origin && origin !== controller_utils_1.ORIGIN_METAMASK) { @@ -37,70 +11,8 @@ index c46bd8463907268ac5e2a762a04615d5c1371c20..817b21293437f055249e76cbb75ff4e3 } const dappSuggestedGasFees = this.generateDappSuggestedGasFees(txParams, origin); const transactionType = type ?? (await (0, transaction_type_1.determineTransactionType)(txParams, ethQuery)).type; -@@ -2182,6 +2182,7 @@ _TransactionController_internalEvents = new WeakMap(), _TransactionController_me - ethQuery, - isCustomNetwork, - isSimulationEnabled: __classPrivateFieldGet(this, _TransactionController_isSimulationEnabled, "f").call(this), -+ messenger: this.messagingSystem, - txMeta: transactionMeta, - }); - }, _TransactionController_deleteTransaction = function _TransactionController_deleteTransaction(transactionId) { -diff --git a/dist/TransactionController.d.cts b/dist/TransactionController.d.cts -index 713414992d9086fd5ac53856a75619c7ea797452..af58af2e81a2aaeb7b19ebea0ed233c23aac63d2 100644 ---- a/dist/TransactionController.d.cts -+++ b/dist/TransactionController.d.cts -@@ -11,7 +11,7 @@ import type { NonceLock, Transaction as NonceTrackerTransaction } from "@metamas - import type { RemoteFeatureFlagControllerGetStateAction } from "@metamask/remote-feature-flag-controller"; - import type { Hex } from "@metamask/utils"; - import type { IncomingTransactionOptions } from "./helpers/IncomingTransactionHelper.cjs"; --import type { SavedGasFees, SecurityProviderRequest, SendFlowHistoryEntry, TransactionParams, TransactionMeta, TransactionReceipt, WalletDevice, SecurityAlertResponse, GasFeeFlowResponse, GasPriceValue, FeeMarketEIP1559Values, SubmitHistoryEntry, TransactionBatchRequest, TransactionBatchResult, BatchTransactionParams, PublishHook, PublishBatchHook } from "./types.cjs"; -+import type { SavedGasFees, SecurityProviderRequest, SendFlowHistoryEntry, TransactionParams, TransactionMeta, TransactionReceipt, WalletDevice, SecurityAlertResponse, GasFeeFlowResponse, GasPriceValue, FeeMarketEIP1559Values, SubmitHistoryEntry, TransactionBatchRequest, TransactionBatchResult, BatchTransactionParams, PublishHook, PublishBatchHook, IsAtomicBatchSupportedResult, IsAtomicBatchSupportedRequest } from "./types.cjs"; - import { TransactionType, TransactionStatus } from "./types.cjs"; - /** - * Object with new transaction's meta and a promise resolving to the -@@ -393,10 +393,10 @@ export declare class TransactionController extends BaseController; -+ isAtomicBatchSupported(request: IsAtomicBatchSupportedRequest): Promise; - /** - * Add a new unapproved transaction to state. Parameters will be validated, a - * unique transaction id will be generated, and gas and gasPrice will be calculated -diff --git a/dist/TransactionController.d.mts b/dist/TransactionController.d.mts -index c0f1dd6c6ba188a86a41a5c9af8de6474ad2c6ee..066a0b2646f523df4259eb1d080faef3fbcc3785 100644 ---- a/dist/TransactionController.d.mts -+++ b/dist/TransactionController.d.mts -@@ -11,7 +11,7 @@ import type { NonceLock, Transaction as NonceTrackerTransaction } from "@metamas - import type { RemoteFeatureFlagControllerGetStateAction } from "@metamask/remote-feature-flag-controller"; - import type { Hex } from "@metamask/utils"; - import type { IncomingTransactionOptions } from "./helpers/IncomingTransactionHelper.mjs"; --import type { SavedGasFees, SecurityProviderRequest, SendFlowHistoryEntry, TransactionParams, TransactionMeta, TransactionReceipt, WalletDevice, SecurityAlertResponse, GasFeeFlowResponse, GasPriceValue, FeeMarketEIP1559Values, SubmitHistoryEntry, TransactionBatchRequest, TransactionBatchResult, BatchTransactionParams, PublishHook, PublishBatchHook } from "./types.mjs"; -+import type { SavedGasFees, SecurityProviderRequest, SendFlowHistoryEntry, TransactionParams, TransactionMeta, TransactionReceipt, WalletDevice, SecurityAlertResponse, GasFeeFlowResponse, GasPriceValue, FeeMarketEIP1559Values, SubmitHistoryEntry, TransactionBatchRequest, TransactionBatchResult, BatchTransactionParams, PublishHook, PublishBatchHook, IsAtomicBatchSupportedResult, IsAtomicBatchSupportedRequest } from "./types.mjs"; - import { TransactionType, TransactionStatus } from "./types.mjs"; - /** - * Object with new transaction's meta and a promise resolving to the -@@ -393,10 +393,10 @@ export declare class TransactionController extends BaseController; -+ isAtomicBatchSupported(request: IsAtomicBatchSupportedRequest): Promise; - /** - * Add a new unapproved transaction to state. Parameters will be validated, a - * unique transaction id will be generated, and gas and gasPrice will be calculated diff --git a/dist/TransactionController.mjs b/dist/TransactionController.mjs -index 866bce89ab3c39ed2dc389b53a4fd220d014d8fb..186864d535d8a5feb98a5c2817896c351b37c7ba 100644 +index d169f516b09cc7e5ba77ad399aebdc6cc603ae80..8cc1708679f0349a28f09193a52a6bf71a2ebe57 100644 --- a/dist/TransactionController.mjs +++ b/dist/TransactionController.mjs @@ -22,7 +22,7 @@ import $EthQuery from "@metamask/eth-query"; @@ -121,33 +33,7 @@ index 866bce89ab3c39ed2dc389b53a4fd220d014d8fb..186864d535d8a5feb98a5c2817896c35 /** * Metadata for the TransactionController state, describing how to "anonymize" * the state and which parts should be persisted. -@@ -336,12 +336,12 @@ export class TransactionController extends BaseController { - /** - * Determine which chains support atomic batch transactions with the given account address. - * -- * @param address - The address of the account to check. -- * @returns The supported chain IDs. -+ * @param request - Request object containing the account address and other parameters. -+ * @returns Result object containing the supported chains and related information. - */ -- async isAtomicBatchSupported(address) { -+ async isAtomicBatchSupported(request) { - return isAtomicBatchSupported({ -- address, -+ ...request, - getEthQuery: (chainId) => __classPrivateFieldGet(this, _TransactionController_instances, "m", _TransactionController_getEthQuery).call(this, { chainId }), - messenger: this.messagingSystem, - publicKeyEIP7702: __classPrivateFieldGet(this, _TransactionController_publicKeyEIP7702, "f"), -@@ -401,7 +401,7 @@ export class TransactionController extends BaseController { - }); - const delegationAddressPromise = getDelegationAddress(txParams.from, ethQuery).catch(() => undefined); - const isEIP1559Compatible = await this.getEIP1559Compatibility(networkClientId); -- validateTxParams(txParams, isEIP1559Compatible); -+ validateTxParams(txParams, isEIP1559Compatible, chainId); - if (!txParams.type) { - // Determine transaction type based on transaction parameters and network compatibility - setEnvelopeType(txParams, isEIP1559Compatible); -@@ -409,7 +409,7 @@ export class TransactionController extends BaseController { +@@ -410,7 +410,7 @@ export class TransactionController extends BaseController { const isDuplicateBatchId = batchId?.length && this.state.transactions.some((tx) => tx.batchId?.toLowerCase() === batchId?.toLowerCase()); if (isDuplicateBatchId && origin && origin !== ORIGIN_METAMASK) { @@ -156,14 +42,6 @@ index 866bce89ab3c39ed2dc389b53a4fd220d014d8fb..186864d535d8a5feb98a5c2817896c35 } const dappSuggestedGasFees = this.generateDappSuggestedGasFees(txParams, origin); const transactionType = type ?? (await determineTransactionType(txParams, ethQuery)).type; -@@ -2183,6 +2183,7 @@ _TransactionController_internalEvents = new WeakMap(), _TransactionController_me - ethQuery, - isCustomNetwork, - isSimulationEnabled: __classPrivateFieldGet(this, _TransactionController_isSimulationEnabled, "f").call(this), -+ messenger: this.messagingSystem, - txMeta: transactionMeta, - }); - }, _TransactionController_deleteTransaction = function _TransactionController_deleteTransaction(transactionId) { diff --git a/dist/constants.cjs b/dist/constants.cjs index f98509f3bdb8243fc649e312d5442d54b28f05a6..7628bb1ee798a3922921b8ef452d4bb5cbd09bd9 100644 --- a/dist/constants.cjs @@ -232,271 +110,103 @@ index 21c0af4e0d88942c47d22b74b5ac07377751bb6a..bfb1144959d3f356eba690384b87cccf /** Extract of the Wrapped ERC-20 ABI required for simulation. */ export const ABI_SIMULATION_ERC20_WRAPPED = [ { -diff --git a/dist/index.d.cts b/dist/index.d.cts -index dd5d172984cffb39bbde3d49aa72a23d85676e2a..577ff30dccd17738f867439bd52f9d2bdfbcd92b 100644 ---- a/dist/index.d.cts -+++ b/dist/index.d.cts -@@ -1,6 +1,6 @@ - export type { MethodData, Result, TransactionControllerActions, TransactionControllerEvents, TransactionControllerGetStateAction, TransactionControllerIncomingTransactionsReceivedEvent, TransactionControllerPostTransactionBalanceUpdatedEvent, TransactionControllerSpeedupTransactionAddedEvent, TransactionControllerState, TransactionControllerStateChangeEvent, TransactionControllerTransactionApprovedEvent, TransactionControllerTransactionConfirmedEvent, TransactionControllerTransactionDroppedEvent, TransactionControllerTransactionFailedEvent, TransactionControllerTransactionFinishedEvent, TransactionControllerTransactionNewSwapApprovalEvent, TransactionControllerTransactionNewSwapEvent, TransactionControllerTransactionPublishingSkipped, TransactionControllerTransactionRejectedEvent, TransactionControllerTransactionStatusUpdatedEvent, TransactionControllerTransactionSubmittedEvent, TransactionControllerUnapprovedTransactionAddedEvent, TransactionControllerMessenger, TransactionControllerOptions, } from "./TransactionController.cjs"; - export { CANCEL_RATE, SPEED_UP_RATE, TransactionController, } from "./TransactionController.cjs"; --export type { Authorization, AuthorizationList, BatchTransactionParams, DappSuggestedGasFees, DefaultGasEstimates, FeeMarketEIP1559Values, FeeMarketGasFeeEstimateForLevel, FeeMarketGasFeeEstimates, GasFeeEstimates, GasFeeToken, GasPriceGasFeeEstimates, GasPriceValue, InferTransactionTypeResult, LegacyGasFeeEstimates, Log, NestedTransactionMetadata, PublishBatchHook, PublishBatchHookRequest, PublishBatchHookResult, PublishBatchHookTransaction, PublishHook, PublishHookResult, SavedGasFees, SecurityAlertResponse, SecurityProviderRequest, SendFlowHistoryEntry, SimulationBalanceChange, SimulationData, SimulationError, SimulationToken, SimulationTokenBalanceChange, TransactionBatchRequest, TransactionBatchResult, TransactionError, TransactionHistory, TransactionHistoryEntry, TransactionMeta, TransactionParams, TransactionReceipt, ValidateSecurityRequest, } from "./types.cjs"; -+export type { Authorization, AuthorizationList, BatchTransactionParams, DappSuggestedGasFees, DefaultGasEstimates, FeeMarketEIP1559Values, FeeMarketGasFeeEstimateForLevel, FeeMarketGasFeeEstimates, GasFeeEstimates, GasFeeToken, GasPriceGasFeeEstimates, GasPriceValue, InferTransactionTypeResult, IsAtomicBatchSupportedRequest, IsAtomicBatchSupportedResult, IsAtomicBatchSupportedResultEntry, LegacyGasFeeEstimates, Log, NestedTransactionMetadata, PublishBatchHook, PublishBatchHookRequest, PublishBatchHookResult, PublishBatchHookTransaction, PublishHook, PublishHookResult, SavedGasFees, SecurityAlertResponse, SecurityProviderRequest, SendFlowHistoryEntry, SimulationBalanceChange, SimulationData, SimulationError, SimulationToken, SimulationTokenBalanceChange, TransactionBatchRequest, TransactionBatchResult, TransactionError, TransactionHistory, TransactionHistoryEntry, TransactionMeta, TransactionParams, TransactionReceipt, ValidateSecurityRequest, } from "./types.cjs"; - export { GasFeeEstimateLevel, GasFeeEstimateType, SimulationErrorCode, SimulationTokenStandard, TransactionEnvelopeType, TransactionStatus, TransactionType, UserFeeLevel, WalletDevice, } from "./types.cjs"; - export { DISPLAYED_TRANSACTION_HISTORY_PATHS, MAX_TRANSACTION_HISTORY_LENGTH, } from "./utils/history.cjs"; - export { determineTransactionType } from "./utils/transaction-type.cjs"; -diff --git a/dist/index.d.mts b/dist/index.d.mts -index 5c295f0f6a0c137befbc86d7fe7e4fff7586b2b7..24ce4cdde5f76029496b5f36bee37f9fc471543d 100644 ---- a/dist/index.d.mts -+++ b/dist/index.d.mts -@@ -1,6 +1,6 @@ - export type { MethodData, Result, TransactionControllerActions, TransactionControllerEvents, TransactionControllerGetStateAction, TransactionControllerIncomingTransactionsReceivedEvent, TransactionControllerPostTransactionBalanceUpdatedEvent, TransactionControllerSpeedupTransactionAddedEvent, TransactionControllerState, TransactionControllerStateChangeEvent, TransactionControllerTransactionApprovedEvent, TransactionControllerTransactionConfirmedEvent, TransactionControllerTransactionDroppedEvent, TransactionControllerTransactionFailedEvent, TransactionControllerTransactionFinishedEvent, TransactionControllerTransactionNewSwapApprovalEvent, TransactionControllerTransactionNewSwapEvent, TransactionControllerTransactionPublishingSkipped, TransactionControllerTransactionRejectedEvent, TransactionControllerTransactionStatusUpdatedEvent, TransactionControllerTransactionSubmittedEvent, TransactionControllerUnapprovedTransactionAddedEvent, TransactionControllerMessenger, TransactionControllerOptions, } from "./TransactionController.mjs"; - export { CANCEL_RATE, SPEED_UP_RATE, TransactionController, } from "./TransactionController.mjs"; --export type { Authorization, AuthorizationList, BatchTransactionParams, DappSuggestedGasFees, DefaultGasEstimates, FeeMarketEIP1559Values, FeeMarketGasFeeEstimateForLevel, FeeMarketGasFeeEstimates, GasFeeEstimates, GasFeeToken, GasPriceGasFeeEstimates, GasPriceValue, InferTransactionTypeResult, LegacyGasFeeEstimates, Log, NestedTransactionMetadata, PublishBatchHook, PublishBatchHookRequest, PublishBatchHookResult, PublishBatchHookTransaction, PublishHook, PublishHookResult, SavedGasFees, SecurityAlertResponse, SecurityProviderRequest, SendFlowHistoryEntry, SimulationBalanceChange, SimulationData, SimulationError, SimulationToken, SimulationTokenBalanceChange, TransactionBatchRequest, TransactionBatchResult, TransactionError, TransactionHistory, TransactionHistoryEntry, TransactionMeta, TransactionParams, TransactionReceipt, ValidateSecurityRequest, } from "./types.mjs"; -+export type { Authorization, AuthorizationList, BatchTransactionParams, DappSuggestedGasFees, DefaultGasEstimates, FeeMarketEIP1559Values, FeeMarketGasFeeEstimateForLevel, FeeMarketGasFeeEstimates, GasFeeEstimates, GasFeeToken, GasPriceGasFeeEstimates, GasPriceValue, InferTransactionTypeResult, IsAtomicBatchSupportedRequest, IsAtomicBatchSupportedResult, IsAtomicBatchSupportedResultEntry, LegacyGasFeeEstimates, Log, NestedTransactionMetadata, PublishBatchHook, PublishBatchHookRequest, PublishBatchHookResult, PublishBatchHookTransaction, PublishHook, PublishHookResult, SavedGasFees, SecurityAlertResponse, SecurityProviderRequest, SendFlowHistoryEntry, SimulationBalanceChange, SimulationData, SimulationError, SimulationToken, SimulationTokenBalanceChange, TransactionBatchRequest, TransactionBatchResult, TransactionError, TransactionHistory, TransactionHistoryEntry, TransactionMeta, TransactionParams, TransactionReceipt, ValidateSecurityRequest, } from "./types.mjs"; - export { GasFeeEstimateLevel, GasFeeEstimateType, SimulationErrorCode, SimulationTokenStandard, TransactionEnvelopeType, TransactionStatus, TransactionType, UserFeeLevel, WalletDevice, } from "./types.mjs"; - export { DISPLAYED_TRANSACTION_HISTORY_PATHS, MAX_TRANSACTION_HISTORY_LENGTH, } from "./utils/history.mjs"; - export { determineTransactionType } from "./utils/transaction-type.mjs"; -diff --git a/dist/types.d.cts b/dist/types.d.cts -index 0b709a5f4e5a941ab770ea2ced7fce96e7d9abd3..94c5504d22bca3131be24fbdb29fab635364da9c 100644 ---- a/dist/types.d.cts -+++ b/dist/types.d.cts -@@ -613,6 +613,9 @@ export type TransactionParams = { - authorizationList?: AuthorizationList; - /** - * Network ID as per EIP-155. -+ * -+ * @deprecated Ignored. -+ * Use `networkClientId` when calling `addTransaction`. - */ - chainId?: Hex; - /** -@@ -1345,5 +1348,28 @@ export type GasFeeToken = { - /** Address of the token contract. */ - tokenAddress: Hex; - }; -+/** Request to check if atomic batch is supported for an account. */ -+export type IsAtomicBatchSupportedRequest = { -+ /** Address of the account to check. */ -+ address: Hex; -+ /** -+ * IDs of specific chains to check. -+ * If not provided, all supported chains will be checked. -+ */ -+ chainIds?: Hex[]; -+}; -+/** Result of checking if atomic batch is supported for an account. */ -+export type IsAtomicBatchSupportedResult = IsAtomicBatchSupportedResultEntry[]; -+/** Info about atomic batch support for a single chain. */ -+export type IsAtomicBatchSupportedResultEntry = { -+ /** ID of the chain. */ -+ chainId: Hex; -+ /** Address of the contract that the account was upgraded to. */ -+ delegationAddress?: Hex; -+ /** Whether the upgraded contract is supported. */ -+ isSupported: boolean; -+ /** Address of the contract that the account would be upgraded to. */ -+ upgradeContractAddress?: Hex; -+}; - export {}; - //# sourceMappingURL=types.d.cts.map -\ No newline at end of file -diff --git a/dist/types.d.mts b/dist/types.d.mts -index 17f5366caba8fa9a388b79ee46d617425a9c2728..e43adcecc7d406e4203ee998163f9c2b31b7e6f8 100644 ---- a/dist/types.d.mts -+++ b/dist/types.d.mts -@@ -613,6 +613,9 @@ export type TransactionParams = { - authorizationList?: AuthorizationList; - /** - * Network ID as per EIP-155. -+ * -+ * @deprecated Ignored. -+ * Use `networkClientId` when calling `addTransaction`. - */ - chainId?: Hex; - /** -@@ -1345,5 +1348,28 @@ export type GasFeeToken = { - /** Address of the token contract. */ - tokenAddress: Hex; - }; -+/** Request to check if atomic batch is supported for an account. */ -+export type IsAtomicBatchSupportedRequest = { -+ /** Address of the account to check. */ -+ address: Hex; -+ /** -+ * IDs of specific chains to check. -+ * If not provided, all supported chains will be checked. -+ */ -+ chainIds?: Hex[]; -+}; -+/** Result of checking if atomic batch is supported for an account. */ -+export type IsAtomicBatchSupportedResult = IsAtomicBatchSupportedResultEntry[]; -+/** Info about atomic batch support for a single chain. */ -+export type IsAtomicBatchSupportedResultEntry = { -+ /** ID of the chain. */ -+ chainId: Hex; -+ /** Address of the contract that the account was upgraded to. */ -+ delegationAddress?: Hex; -+ /** Whether the upgraded contract is supported. */ -+ isSupported: boolean; -+ /** Address of the contract that the account would be upgraded to. */ -+ upgradeContractAddress?: Hex; -+}; - export {}; - //# sourceMappingURL=types.d.mts.map -\ No newline at end of file diff --git a/dist/utils/batch.cjs b/dist/utils/batch.cjs -index ac9ea2743fb008b11821967a93ec62c266294e97..e8a4232f60e47942182a9275f96e92ce286dd245 100644 +index ad23a77dd88efcabc15649fb31982d265ec9a405..e06922cfc070dbbffb0439adb28c0746df9afce2 100644 --- a/dist/utils/batch.cjs +++ b/dist/utils/batch.cjs -@@ -105,21 +105,25 @@ exports.addTransactionBatch = addTransactionBatch; - * @returns The chain IDs that support atomic batch transactions. - */ - async function isAtomicBatchSupported(request) { -- const { address, getEthQuery, messenger, publicKeyEIP7702: publicKey, } = request; -+ const { address, chainIds, getEthQuery, messenger, publicKeyEIP7702: publicKey, } = request; - if (!publicKey) { +@@ -111,21 +111,25 @@ async function isAtomicBatchSupported(request) { throw rpc_errors_1.rpcErrors.internal('EIP-7702 public key not specified'); } const chainIds7702 = (0, feature_flags_1.getEIP7702SupportedChains)(messenger); -- const chainIds = []; +- const results = []; - for (const chainId of chainIds7702) { +- if (chainIds && !chainIds.includes(chainId)) { +- continue; + const filteredChainIds = chainIds7702.filter((chainId) => !chainIds || chainIds.includes(chainId)); -+ const results = await Promise.all(filteredChainIds.map(async (chainId) => { - const ethQuery = getEthQuery(chainId); - const { isSupported, delegationAddress } = await (0, eip7702_1.isAccountUpgradedToEIP7702)(address, chainId, publicKey, messenger, ethQuery); -- if (!delegationAddress || isSupported) { -- chainIds.push(chainId); -- } ++ const resultsRaw = await Promise.all(filteredChainIds.map(async (chainId) => { ++ try { ++ const ethQuery = getEthQuery(chainId); ++ const { isSupported, delegationAddress } = await (0, eip7702_1.isAccountUpgradedToEIP7702)(address, chainId, publicKey, messenger, ethQuery); ++ const upgradeContractAddress = (0, feature_flags_1.getEIP7702UpgradeContractAddress)(chainId, messenger, publicKey); ++ return { ++ chainId, ++ delegationAddress, ++ isSupported, ++ upgradeContractAddress, ++ }; + } +- const ethQuery = getEthQuery(chainId); +- const { isSupported, delegationAddress } = await (0, eip7702_1.isAccountUpgradedToEIP7702)(address, chainId, publicKey, messenger, ethQuery); +- const upgradeContractAddress = (0, feature_flags_1.getEIP7702UpgradeContractAddress)(chainId, messenger, publicKey); +- results.push({ +- chainId, +- delegationAddress, +- isSupported, +- upgradeContractAddress, +- }); - } -- log('Atomic batch supported chains', chainIds); -- return chainIds; -+ const upgradeContractAddress = (0, feature_flags_1.getEIP7702UpgradeContractAddress)(chainId, messenger, publicKey); -+ return { -+ chainId, -+ delegationAddress, -+ isSupported, -+ upgradeContractAddress, -+ }; ++ catch (error) { ++ log('Error checking atomic batch support', chainId, error); ++ return undefined; ++ } + })); -+ log('Atomic batch supported results', results); -+ return results; ++ const results = resultsRaw.filter((result) => Boolean(result)); + log('Atomic batch supported results', results); + return results; } - exports.isAtomicBatchSupported = isAtomicBatchSupported; - /** -diff --git a/dist/utils/batch.d.cts b/dist/utils/batch.d.cts -index f7fcbecc94c9ab99d8ceecf79dae44014830ad0b..211870434058047b2a2a6f5c6718680498a2ec77 100644 ---- a/dist/utils/batch.d.cts -+++ b/dist/utils/batch.d.cts -@@ -1,7 +1,7 @@ - import type EthQuery from "@metamask/eth-query"; - import type { Hex } from "@metamask/utils"; - import { type TransactionController, type TransactionControllerMessenger, type TransactionMeta } from "../index.cjs"; --import type { PublishBatchHook, TransactionBatchRequest } from "../types.cjs"; -+import type { PublishBatchHook, TransactionBatchRequest, IsAtomicBatchSupportedResult } from "../types.cjs"; - import { type TransactionBatchResult } from "../types.cjs"; - type AddTransactionBatchRequest = { - addTransaction: TransactionController['addTransaction']; -@@ -17,8 +17,9 @@ type AddTransactionBatchRequest = { - transactionId: string; - }, callback: (transactionMeta: TransactionMeta) => void) => void; - }; --type IsAtomicBatchSupportedRequest = { -+type IsAtomicBatchSupportedRequestInternal = { - address: Hex; -+ chainIds?: Hex[]; - getEthQuery: (chainId: Hex) => EthQuery; - messenger: TransactionControllerMessenger; - publicKeyEIP7702?: Hex; -@@ -36,6 +37,6 @@ export declare function addTransactionBatch(request: AddTransactionBatchRequest) - * @param request - The request object including the account address and necessary callbacks. - * @returns The chain IDs that support atomic batch transactions. - */ --export declare function isAtomicBatchSupported(request: IsAtomicBatchSupportedRequest): Promise; -+export declare function isAtomicBatchSupported(request: IsAtomicBatchSupportedRequestInternal): Promise; - export {}; - //# sourceMappingURL=batch.d.cts.map -\ No newline at end of file -diff --git a/dist/utils/batch.d.mts b/dist/utils/batch.d.mts -index db1e8ff8b906acfd7eea6d73e66693efeacdc2d1..6829f6b09f9b7629d5203da5662aa7ab4ae3d3fb 100644 ---- a/dist/utils/batch.d.mts -+++ b/dist/utils/batch.d.mts -@@ -1,7 +1,7 @@ - import type EthQuery from "@metamask/eth-query"; - import type { Hex } from "@metamask/utils"; - import { type TransactionController, type TransactionControllerMessenger, type TransactionMeta } from "../index.mjs"; --import type { PublishBatchHook, TransactionBatchRequest } from "../types.mjs"; -+import type { PublishBatchHook, TransactionBatchRequest, IsAtomicBatchSupportedResult } from "../types.mjs"; - import { type TransactionBatchResult } from "../types.mjs"; - type AddTransactionBatchRequest = { - addTransaction: TransactionController['addTransaction']; -@@ -17,8 +17,9 @@ type AddTransactionBatchRequest = { - transactionId: string; - }, callback: (transactionMeta: TransactionMeta) => void) => void; - }; --type IsAtomicBatchSupportedRequest = { -+type IsAtomicBatchSupportedRequestInternal = { - address: Hex; -+ chainIds?: Hex[]; - getEthQuery: (chainId: Hex) => EthQuery; - messenger: TransactionControllerMessenger; - publicKeyEIP7702?: Hex; -@@ -36,6 +37,6 @@ export declare function addTransactionBatch(request: AddTransactionBatchRequest) - * @param request - The request object including the account address and necessary callbacks. - * @returns The chain IDs that support atomic batch transactions. - */ --export declare function isAtomicBatchSupported(request: IsAtomicBatchSupportedRequest): Promise; -+export declare function isAtomicBatchSupported(request: IsAtomicBatchSupportedRequestInternal): Promise; - export {}; - //# sourceMappingURL=batch.d.mts.map -\ No newline at end of file diff --git a/dist/utils/batch.mjs b/dist/utils/batch.mjs -index a98e695fe5671da4deff8d7620462acd73f2a451..03809bc22f70210fac114c0d372a8df850cf1d47 100644 +index 9db6e45c8b31e3e7fb56b36a9b004d0f58045ce1..387e4886a0e938411efd2997caeba92052e866b1 100644 --- a/dist/utils/batch.mjs +++ b/dist/utils/batch.mjs -@@ -101,21 +101,25 @@ export async function addTransactionBatch(request) { - * @returns The chain IDs that support atomic batch transactions. - */ - export async function isAtomicBatchSupported(request) { -- const { address, getEthQuery, messenger, publicKeyEIP7702: publicKey, } = request; -+ const { address, chainIds, getEthQuery, messenger, publicKeyEIP7702: publicKey, } = request; - if (!publicKey) { +@@ -107,21 +107,25 @@ export async function isAtomicBatchSupported(request) { throw rpcErrors.internal('EIP-7702 public key not specified'); } const chainIds7702 = getEIP7702SupportedChains(messenger); -- const chainIds = []; +- const results = []; - for (const chainId of chainIds7702) { +- if (chainIds && !chainIds.includes(chainId)) { +- continue; + const filteredChainIds = chainIds7702.filter((chainId) => !chainIds || chainIds.includes(chainId)); -+ const results = await Promise.all(filteredChainIds.map(async (chainId) => { - const ethQuery = getEthQuery(chainId); - const { isSupported, delegationAddress } = await isAccountUpgradedToEIP7702(address, chainId, publicKey, messenger, ethQuery); -- if (!delegationAddress || isSupported) { -- chainIds.push(chainId); -- } ++ const resultsRaw = await Promise.all(filteredChainIds.map(async (chainId) => { ++ try { ++ const ethQuery = getEthQuery(chainId); ++ const { isSupported, delegationAddress } = await isAccountUpgradedToEIP7702(address, chainId, publicKey, messenger, ethQuery); ++ const upgradeContractAddress = getEIP7702UpgradeContractAddress(chainId, messenger, publicKey); ++ return { ++ chainId, ++ delegationAddress, ++ isSupported, ++ upgradeContractAddress, ++ }; + } +- const ethQuery = getEthQuery(chainId); +- const { isSupported, delegationAddress } = await isAccountUpgradedToEIP7702(address, chainId, publicKey, messenger, ethQuery); +- const upgradeContractAddress = getEIP7702UpgradeContractAddress(chainId, messenger, publicKey); +- results.push({ +- chainId, +- delegationAddress, +- isSupported, +- upgradeContractAddress, +- }); - } -- log('Atomic batch supported chains', chainIds); -- return chainIds; -+ const upgradeContractAddress = getEIP7702UpgradeContractAddress(chainId, messenger, publicKey); -+ return { -+ chainId, -+ delegationAddress, -+ isSupported, -+ upgradeContractAddress, -+ }; ++ catch (error) { ++ log('Error checking atomic batch support', chainId, error); ++ return undefined; ++ } + })); -+ log('Atomic batch supported results', results); -+ return results; ++ const results = resultsRaw.filter((result) => Boolean(result)); + log('Atomic batch supported results', results); + return results; } - /** - * Generate a tranasction batch ID. diff --git a/dist/utils/feature-flags.cjs b/dist/utils/feature-flags.cjs -index 1df8d0899cf69070528ab89756730913e9c4b2bb..248d5dc622fbbe0b23163bc0caa8fdedd7afbca9 100644 +index c8c3910aa788014c00ecbddb5eb17e2eb4c2f914..71eea48106f672bcb950dd25edbbb9d5b71b2e6a 100644 --- a/dist/utils/feature-flags.cjs +++ b/dist/utils/feature-flags.cjs -@@ -1,15 +1,23 @@ +@@ -1,16 +1,24 @@ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); --exports.getGasFeeRandomisation = exports.getAcceleratedPollingParams = exports.getBatchSizeLimit = exports.getEIP7702UpgradeContractAddress = exports.getEIP7702ContractAddresses = exports.getEIP7702SupportedChains = exports.FEATURE_FLAG_EIP_7702 = exports.FEATURE_FLAG_TRANSACTIONS = void 0; -+exports.getGasEstimateBuffer = exports.getGasFeeRandomisation = exports.getAcceleratedPollingParams = exports.getBatchSizeLimit = exports.getEIP7702UpgradeContractAddress = exports.getEIP7702ContractAddresses = exports.getEIP7702SupportedChains = exports.FeatureFlag = void 0; +-exports.getGasEstimateFallback = exports.getGasFeeRandomisation = exports.getAcceleratedPollingParams = exports.getBatchSizeLimit = exports.getEIP7702UpgradeContractAddress = exports.getEIP7702ContractAddresses = exports.getEIP7702SupportedChains = exports.FEATURE_FLAG_EIP_7702 = exports.FEATURE_FLAG_TRANSACTIONS = void 0; ++exports.getGasEstimateBuffer = exports.getGasEstimateFallback = exports.getGasFeeRandomisation = exports.getAcceleratedPollingParams = exports.getBatchSizeLimit = exports.getEIP7702UpgradeContractAddress = exports.getEIP7702ContractAddresses = exports.getEIP7702SupportedChains = exports.FeatureFlag = void 0; const utils_1 = require("@metamask/utils"); const signature_1 = require("./signature.cjs"); const utils_2 = require("./utils.cjs"); @@ -506,6 +216,7 @@ index 1df8d0899cf69070528ab89756730913e9c4b2bb..248d5dc622fbbe0b23163bc0caa8fded const DEFAULT_BATCH_SIZE_LIMIT = 10; const DEFAULT_ACCELERATED_POLLING_COUNT_MAX = 10; const DEFAULT_ACCELERATED_POLLING_INTERVAL_MS = 3 * 1000; + const DEFAULT_GAS_ESTIMATE_FALLBACK_BLOCK_PERCENT = 35; +const DEFAULT_GAS_ESTIMATE_BUFFER = 1; +/** + * Feature flags supporting the transaction controller. @@ -519,7 +230,7 @@ index 1df8d0899cf69070528ab89756730913e9c4b2bb..248d5dc622fbbe0b23163bc0caa8fded const log = (0, utils_1.createModuleLogger)(logger_1.projectLogger, 'feature-flags'); /** * Retrieves the supported EIP-7702 chains. -@@ -19,7 +27,7 @@ const log = (0, utils_1.createModuleLogger)(logger_1.projectLogger, 'feature-fla +@@ -20,7 +28,7 @@ const log = (0, utils_1.createModuleLogger)(logger_1.projectLogger, 'feature-fla */ function getEIP7702SupportedChains(messenger) { const featureFlags = getFeatureFlags(messenger); @@ -528,7 +239,7 @@ index 1df8d0899cf69070528ab89756730913e9c4b2bb..248d5dc622fbbe0b23163bc0caa8fded } exports.getEIP7702SupportedChains = getEIP7702SupportedChains; /** -@@ -32,7 +40,7 @@ exports.getEIP7702SupportedChains = getEIP7702SupportedChains; +@@ -33,7 +41,7 @@ exports.getEIP7702SupportedChains = getEIP7702SupportedChains; */ function getEIP7702ContractAddresses(chainId, messenger, publicKey) { const featureFlags = getFeatureFlags(messenger); @@ -537,7 +248,7 @@ index 1df8d0899cf69070528ab89756730913e9c4b2bb..248d5dc622fbbe0b23163bc0caa8fded return contracts .filter((contract) => (0, signature_1.isValidSignature)([contract.address, (0, utils_2.padHexToEvenLength)(chainId)], contract.signature, publicKey)) .map((contract) => contract.address); -@@ -59,7 +67,7 @@ exports.getEIP7702UpgradeContractAddress = getEIP7702UpgradeContractAddress; +@@ -60,7 +68,7 @@ exports.getEIP7702UpgradeContractAddress = getEIP7702UpgradeContractAddress; */ function getBatchSizeLimit(messenger) { const featureFlags = getFeatureFlags(messenger); @@ -546,7 +257,7 @@ index 1df8d0899cf69070528ab89756730913e9c4b2bb..248d5dc622fbbe0b23163bc0caa8fded DEFAULT_BATCH_SIZE_LIMIT); } exports.getBatchSizeLimit = getBatchSizeLimit; -@@ -72,7 +80,7 @@ exports.getBatchSizeLimit = getBatchSizeLimit; +@@ -73,7 +81,7 @@ exports.getBatchSizeLimit = getBatchSizeLimit; */ function getAcceleratedPollingParams(chainId, messenger) { const featureFlags = getFeatureFlags(messenger); @@ -555,7 +266,7 @@ index 1df8d0899cf69070528ab89756730913e9c4b2bb..248d5dc622fbbe0b23163bc0caa8fded const countMax = acceleratedPollingParams?.perChainConfig?.[chainId]?.countMax || acceleratedPollingParams?.defaultCountMax || DEFAULT_ACCELERATED_POLLING_COUNT_MAX; -@@ -90,13 +98,42 @@ exports.getAcceleratedPollingParams = getAcceleratedPollingParams; +@@ -91,7 +99,7 @@ exports.getAcceleratedPollingParams = getAcceleratedPollingParams; */ function getGasFeeRandomisation(messenger) { const featureFlags = getFeatureFlags(messenger); @@ -564,9 +275,19 @@ index 1df8d0899cf69070528ab89756730913e9c4b2bb..248d5dc622fbbe0b23163bc0caa8fded return { randomisedGasFeeDigits: gasFeeRandomisation.randomisedGasFeeDigits || {}, preservedNumberOfDigits: gasFeeRandomisation.preservedNumberOfDigits, - }; +@@ -108,7 +116,7 @@ exports.getGasFeeRandomisation = getGasFeeRandomisation; + */ + function getGasEstimateFallback(chainId, messenger) { + const featureFlags = getFeatureFlags(messenger); +- const gasEstimateFallbackFlags = featureFlags?.[exports.FEATURE_FLAG_TRANSACTIONS]?.gasEstimateFallback; ++ const gasEstimateFallbackFlags = featureFlags?.[FeatureFlag.Transactions]?.gasEstimateFallback; + const chainFlags = gasEstimateFallbackFlags?.perChainConfig?.[chainId]; + const percentage = chainFlags?.percentage ?? + gasEstimateFallbackFlags?.default?.percentage ?? +@@ -117,6 +125,35 @@ function getGasEstimateFallback(chainId, messenger) { + return { fixed, percentage }; } - exports.getGasFeeRandomisation = getGasFeeRandomisation; + exports.getGasEstimateFallback = getGasEstimateFallback; +/** + * Retrieves the gas buffers for a given chain ID. + * @@ -600,10 +321,10 @@ index 1df8d0899cf69070528ab89756730913e9c4b2bb..248d5dc622fbbe0b23163bc0caa8fded * Retrieves the relevant feature flags from the remote feature flag controller. * diff --git a/dist/utils/feature-flags.d.cts b/dist/utils/feature-flags.d.cts -index 0964f4bacccc02872d5bd942f59e91cf0ffbf709..d99fb63156e793980f484e890510aa47c3030bd8 100644 +index 146e04897b689c83cbb73683d40cb39b98bc0cf6..f6c2749f54693e59e2a16ce3ebd604a46d9207c8 100644 --- a/dist/utils/feature-flags.d.cts +++ b/dist/utils/feature-flags.d.cts -@@ -1,9 +1,16 @@ +@@ -1,7 +1,13 @@ import { type Hex } from "@metamask/utils"; import type { TransactionControllerMessenger } from "../TransactionController.cjs"; -export declare const FEATURE_FLAG_TRANSACTIONS = "confirmations_transactions"; @@ -616,6 +337,12 @@ index 0964f4bacccc02872d5bd942f59e91cf0ffbf709..d99fb63156e793980f484e890510aa47 + GasBuffer = "confirmations_gas_buffer", + Transactions = "confirmations_transactions" +} + type GasEstimateFallback = { + /** + * The fixed gas estimate fallback for a transaction. +@@ -13,7 +19,8 @@ type GasEstimateFallback = { + percentage?: number; + }; export type TransactionControllerFeatureFlags = { - [FEATURE_FLAG_EIP_7702]?: { + /** Feature flags to support EIP-7702 / type-4 transactions. */ @@ -623,7 +350,7 @@ index 0964f4bacccc02872d5bd942f59e91cf0ffbf709..d99fb63156e793980f484e890510aa47 /** * All contracts that support EIP-7702 batch transactions. * Keyed by chain ID. -@@ -18,16 +25,51 @@ export type TransactionControllerFeatureFlags = { +@@ -28,16 +35,51 @@ export type TransactionControllerFeatureFlags = { /** Chains enabled for EIP-7702 batch transactions. */ supportedChains?: Hex[]; }; @@ -681,9 +408,9 @@ index 0964f4bacccc02872d5bd942f59e91cf0ffbf709..d99fb63156e793980f484e890510aa47 [chainId: Hex]: { /** * Maximum number of polling requests that can be made in a row, before -@@ -105,4 +147,20 @@ export declare function getGasFeeRandomisation(messenger: TransactionControllerM - randomisedGasFeeDigits: Record; - preservedNumberOfDigits: number | undefined; +@@ -139,5 +181,21 @@ export declare function getGasEstimateFallback(chainId: Hex, messenger: Transact + fixed?: number; + percentage: number; }; +/** + * Retrieves the gas buffers for a given chain ID. @@ -701,13 +428,14 @@ index 0964f4bacccc02872d5bd942f59e91cf0ffbf709..d99fb63156e793980f484e890510aa47 + isUpgradeWithDataToSelf: boolean; + messenger: TransactionControllerMessenger; +}): number; + export {}; //# sourceMappingURL=feature-flags.d.cts.map \ No newline at end of file diff --git a/dist/utils/feature-flags.d.mts b/dist/utils/feature-flags.d.mts -index 2b197afd66708162e463abb34031061f3bb18f5c..531c758dc6a90627468670b45361d3a85428e822 100644 +index dba130cf82b5451230772641509dff44404769b3..32a6b819e92bf6b69eb492d7facd8fa5f158a495 100644 --- a/dist/utils/feature-flags.d.mts +++ b/dist/utils/feature-flags.d.mts -@@ -1,9 +1,16 @@ +@@ -1,7 +1,13 @@ import { type Hex } from "@metamask/utils"; import type { TransactionControllerMessenger } from "../TransactionController.mjs"; -export declare const FEATURE_FLAG_TRANSACTIONS = "confirmations_transactions"; @@ -720,6 +448,12 @@ index 2b197afd66708162e463abb34031061f3bb18f5c..531c758dc6a90627468670b45361d3a8 + GasBuffer = "confirmations_gas_buffer", + Transactions = "confirmations_transactions" +} + type GasEstimateFallback = { + /** + * The fixed gas estimate fallback for a transaction. +@@ -13,7 +19,8 @@ type GasEstimateFallback = { + percentage?: number; + }; export type TransactionControllerFeatureFlags = { - [FEATURE_FLAG_EIP_7702]?: { + /** Feature flags to support EIP-7702 / type-4 transactions. */ @@ -727,7 +461,7 @@ index 2b197afd66708162e463abb34031061f3bb18f5c..531c758dc6a90627468670b45361d3a8 /** * All contracts that support EIP-7702 batch transactions. * Keyed by chain ID. -@@ -18,16 +25,51 @@ export type TransactionControllerFeatureFlags = { +@@ -28,16 +35,51 @@ export type TransactionControllerFeatureFlags = { /** Chains enabled for EIP-7702 batch transactions. */ supportedChains?: Hex[]; }; @@ -785,9 +519,9 @@ index 2b197afd66708162e463abb34031061f3bb18f5c..531c758dc6a90627468670b45361d3a8 [chainId: Hex]: { /** * Maximum number of polling requests that can be made in a row, before -@@ -105,4 +147,20 @@ export declare function getGasFeeRandomisation(messenger: TransactionControllerM - randomisedGasFeeDigits: Record; - preservedNumberOfDigits: number | undefined; +@@ -139,5 +181,21 @@ export declare function getGasEstimateFallback(chainId: Hex, messenger: Transact + fixed?: number; + percentage: number; }; +/** + * Retrieves the gas buffers for a given chain ID. @@ -805,13 +539,14 @@ index 2b197afd66708162e463abb34031061f3bb18f5c..531c758dc6a90627468670b45361d3a8 + isUpgradeWithDataToSelf: boolean; + messenger: TransactionControllerMessenger; +}): number; + export {}; //# sourceMappingURL=feature-flags.d.mts.map \ No newline at end of file diff --git a/dist/utils/feature-flags.mjs b/dist/utils/feature-flags.mjs -index 2b50654f117bdbe06337036b1f31d1400ca12f62..e1a4ceb62e906632c4de3346cee394b781941fec 100644 +index fa9937f27d488184865b460116cdf7573d199255..50ddae79090932f8381d16fea8c34a69d7f40af8 100644 --- a/dist/utils/feature-flags.mjs +++ b/dist/utils/feature-flags.mjs -@@ -2,11 +2,19 @@ import { createModuleLogger } from "@metamask/utils"; +@@ -2,12 +2,20 @@ import { createModuleLogger } from "@metamask/utils"; import { isValidSignature } from "./signature.mjs"; import { padHexToEvenLength } from "./utils.mjs"; import { projectLogger } from "../logger.mjs"; @@ -820,6 +555,7 @@ index 2b50654f117bdbe06337036b1f31d1400ca12f62..e1a4ceb62e906632c4de3346cee394b7 const DEFAULT_BATCH_SIZE_LIMIT = 10; const DEFAULT_ACCELERATED_POLLING_COUNT_MAX = 10; const DEFAULT_ACCELERATED_POLLING_INTERVAL_MS = 3 * 1000; + const DEFAULT_GAS_ESTIMATE_FALLBACK_BLOCK_PERCENT = 35; +const DEFAULT_GAS_ESTIMATE_BUFFER = 1; +/** + * Feature flags supporting the transaction controller. @@ -833,7 +569,7 @@ index 2b50654f117bdbe06337036b1f31d1400ca12f62..e1a4ceb62e906632c4de3346cee394b7 const log = createModuleLogger(projectLogger, 'feature-flags'); /** * Retrieves the supported EIP-7702 chains. -@@ -16,7 +24,7 @@ const log = createModuleLogger(projectLogger, 'feature-flags'); +@@ -17,7 +25,7 @@ const log = createModuleLogger(projectLogger, 'feature-flags'); */ export function getEIP7702SupportedChains(messenger) { const featureFlags = getFeatureFlags(messenger); @@ -842,7 +578,7 @@ index 2b50654f117bdbe06337036b1f31d1400ca12f62..e1a4ceb62e906632c4de3346cee394b7 } /** * Retrieves the supported EIP-7702 contract addresses for a given chain ID. -@@ -28,7 +36,7 @@ export function getEIP7702SupportedChains(messenger) { +@@ -29,7 +37,7 @@ export function getEIP7702SupportedChains(messenger) { */ export function getEIP7702ContractAddresses(chainId, messenger, publicKey) { const featureFlags = getFeatureFlags(messenger); @@ -851,7 +587,7 @@ index 2b50654f117bdbe06337036b1f31d1400ca12f62..e1a4ceb62e906632c4de3346cee394b7 return contracts .filter((contract) => isValidSignature([contract.address, padHexToEvenLength(chainId)], contract.signature, publicKey)) .map((contract) => contract.address); -@@ -53,7 +61,7 @@ export function getEIP7702UpgradeContractAddress(chainId, messenger, publicKey) +@@ -54,7 +62,7 @@ export function getEIP7702UpgradeContractAddress(chainId, messenger, publicKey) */ export function getBatchSizeLimit(messenger) { const featureFlags = getFeatureFlags(messenger); @@ -860,7 +596,7 @@ index 2b50654f117bdbe06337036b1f31d1400ca12f62..e1a4ceb62e906632c4de3346cee394b7 DEFAULT_BATCH_SIZE_LIMIT); } /** -@@ -65,7 +73,7 @@ export function getBatchSizeLimit(messenger) { +@@ -66,7 +74,7 @@ export function getBatchSizeLimit(messenger) { */ export function getAcceleratedPollingParams(chainId, messenger) { const featureFlags = getFeatureFlags(messenger); @@ -869,7 +605,7 @@ index 2b50654f117bdbe06337036b1f31d1400ca12f62..e1a4ceb62e906632c4de3346cee394b7 const countMax = acceleratedPollingParams?.perChainConfig?.[chainId]?.countMax || acceleratedPollingParams?.defaultCountMax || DEFAULT_ACCELERATED_POLLING_COUNT_MAX; -@@ -82,12 +90,40 @@ export function getAcceleratedPollingParams(chainId, messenger) { +@@ -83,7 +91,7 @@ export function getAcceleratedPollingParams(chainId, messenger) { */ export function getGasFeeRandomisation(messenger) { const featureFlags = getFeatureFlags(messenger); @@ -878,7 +614,18 @@ index 2b50654f117bdbe06337036b1f31d1400ca12f62..e1a4ceb62e906632c4de3346cee394b7 return { randomisedGasFeeDigits: gasFeeRandomisation.randomisedGasFeeDigits || {}, preservedNumberOfDigits: gasFeeRandomisation.preservedNumberOfDigits, - }; +@@ -99,7 +107,7 @@ export function getGasFeeRandomisation(messenger) { + */ + export function getGasEstimateFallback(chainId, messenger) { + const featureFlags = getFeatureFlags(messenger); +- const gasEstimateFallbackFlags = featureFlags?.[FEATURE_FLAG_TRANSACTIONS]?.gasEstimateFallback; ++ const gasEstimateFallbackFlags = featureFlags?.[FeatureFlag.Transactions]?.gasEstimateFallback; + const chainFlags = gasEstimateFallbackFlags?.perChainConfig?.[chainId]; + const percentage = chainFlags?.percentage ?? + gasEstimateFallbackFlags?.default?.percentage ?? +@@ -107,6 +115,34 @@ export function getGasEstimateFallback(chainId, messenger) { + const fixed = chainFlags?.fixed ?? gasEstimateFallbackFlags?.default?.fixed; + return { fixed, percentage }; } +/** + * Retrieves the gas buffers for a given chain ID. @@ -912,20 +659,18 @@ index 2b50654f117bdbe06337036b1f31d1400ca12f62..e1a4ceb62e906632c4de3346cee394b7 * Retrieves the relevant feature flags from the remote feature flag controller. * diff --git a/dist/utils/gas.cjs b/dist/utils/gas.cjs -index 9f9d9999911032d40db5be615cd181c07ecabeab..89fd87e9c36f00428b41daf22cb192c975fe2a7b 100644 +index 7fe7133d22abd32d2f145ff67250c0434d944f27..f69a4968f7f773f1c56aa2c60f68fce57f698441 100644 --- a/dist/utils/gas.cjs +++ b/dist/utils/gas.cjs -@@ -4,8 +4,8 @@ exports.addGasBuffer = exports.estimateGas = exports.updateGas = exports.DUMMY_A - const controller_utils_1 = require("@metamask/controller-utils"); - const utils_1 = require("@metamask/utils"); +@@ -6,7 +6,6 @@ const utils_1 = require("@metamask/utils"); const eip7702_1 = require("./eip7702.cjs"); -+const feature_flags_1 = require("./feature-flags.cjs"); + const feature_flags_1 = require("./feature-flags.cjs"); const simulation_api_1 = require("./simulation-api.cjs"); -const constants_1 = require("../constants.cjs"); const logger_1 = require("../logger.cjs"); const types_1 = require("../types.cjs"); exports.log = (0, utils_1.createModuleLogger)(logger_1.projectLogger, 'gas'); -@@ -62,8 +62,8 @@ async function estimateGas({ chainId, ethQuery, isSimulationEnabled, txParams, } +@@ -67,8 +66,8 @@ async function estimateGas({ chainId, ethQuery, isSimulationEnabled, messenger, let estimatedGas = fallback; let simulationFails; const isUpgradeWithDataToSelf = txParams.type === types_1.TransactionEnvelopeType.setCode && @@ -936,7 +681,7 @@ index 9f9d9999911032d40db5be615cd181c07ecabeab..89fd87e9c36f00428b41daf22cb192c9 data !== '0x' && from?.toLowerCase() === to?.toLowerCase(); try { -@@ -89,6 +89,7 @@ async function estimateGas({ chainId, ethQuery, isSimulationEnabled, txParams, } +@@ -94,6 +93,7 @@ async function estimateGas({ chainId, ethQuery, isSimulationEnabled, messenger, return { blockGasLimit, estimatedGas, @@ -944,7 +689,7 @@ index 9f9d9999911032d40db5be615cd181c07ecabeab..89fd87e9c36f00428b41daf22cb192c9 simulationFails, }; } -@@ -128,7 +129,7 @@ exports.addGasBuffer = addGasBuffer; +@@ -133,7 +133,7 @@ exports.addGasBuffer = addGasBuffer; * @returns The final gas value and the estimate used. */ async function getGas(request) { @@ -953,7 +698,7 @@ index 9f9d9999911032d40db5be615cd181c07ecabeab..89fd87e9c36f00428b41daf22cb192c9 const { disableGasBuffer } = txMeta; if (txMeta.txParams.gas) { (0, exports.log)('Using value from request', txMeta.txParams.gas); -@@ -138,24 +139,32 @@ async function getGas(request) { +@@ -143,25 +143,33 @@ async function getGas(request) { (0, exports.log)('Using fixed value', exports.FIXED_GAS); return [exports.FIXED_GAS, undefined, exports.FIXED_GAS]; } @@ -962,6 +707,8 @@ index 9f9d9999911032d40db5be615cd181c07ecabeab..89fd87e9c36f00428b41daf22cb192c9 chainId: request.chainId, ethQuery: request.ethQuery, isSimulationEnabled, +- messenger: request.messenger, ++ messenger, txParams: txMeta.txParams, }); - if (isCustomNetwork || simulationFails) { @@ -998,25 +745,10 @@ index 9f9d9999911032d40db5be615cd181c07ecabeab..89fd87e9c36f00428b41daf22cb192c9 /** * Determine if the gas for the provided request should be fixed. diff --git a/dist/utils/gas.d.cts b/dist/utils/gas.d.cts -index d11f4d0e125386892ee2238ae19245cfe9272474..96e41882a167564b8d01f1951503a3b8765021e5 100644 +index 21d45c4b27d36d2ba8dbbfa23ca9040a11c99bb1..6bd465c93af5f4a91b91f51a9fea192092b069f9 100644 --- a/dist/utils/gas.d.cts +++ b/dist/utils/gas.d.cts -@@ -1,12 +1,14 @@ - /// - import type EthQuery from "@metamask/eth-query"; - import type { Hex } from "@metamask/utils"; -+import type { TransactionControllerMessenger } from "../index.cjs"; - import { type TransactionMeta, type TransactionParams } from "../types.cjs"; - export type UpdateGasRequest = { - chainId: Hex; - ethQuery: EthQuery; - isCustomNetwork: boolean; - isSimulationEnabled: boolean; -+ messenger: TransactionControllerMessenger; - txMeta: TransactionMeta; - }; - export declare const log: import("debug").Debugger; -@@ -41,6 +43,7 @@ export declare function estimateGas({ chainId, ethQuery, isSimulationEnabled, tx +@@ -44,6 +44,7 @@ export declare function estimateGas({ chainId, ethQuery, isSimulationEnabled, me }): Promise<{ blockGasLimit: string; estimatedGas: `0x${string}`; @@ -1025,25 +757,10 @@ index d11f4d0e125386892ee2238ae19245cfe9272474..96e41882a167564b8d01f1951503a3b8 reason?: string | undefined; errorKey?: string | undefined; diff --git a/dist/utils/gas.d.mts b/dist/utils/gas.d.mts -index 8b16db19489c7407a2f6f8cbba26f21587c8db11..0e34913db5efd07351ec2c4417e2ed90a2d2d8da 100644 +index 077e780ed1f446f2e4f01ea18acad2e18b06bcc1..78deadf8d995ff3cf7de4d29ef59a1779a60dcab 100644 --- a/dist/utils/gas.d.mts +++ b/dist/utils/gas.d.mts -@@ -1,12 +1,14 @@ - /// - import type EthQuery from "@metamask/eth-query"; - import type { Hex } from "@metamask/utils"; -+import type { TransactionControllerMessenger } from "../index.mjs"; - import { type TransactionMeta, type TransactionParams } from "../types.mjs"; - export type UpdateGasRequest = { - chainId: Hex; - ethQuery: EthQuery; - isCustomNetwork: boolean; - isSimulationEnabled: boolean; -+ messenger: TransactionControllerMessenger; - txMeta: TransactionMeta; - }; - export declare const log: import("debug").Debugger; -@@ -41,6 +43,7 @@ export declare function estimateGas({ chainId, ethQuery, isSimulationEnabled, tx +@@ -44,6 +44,7 @@ export declare function estimateGas({ chainId, ethQuery, isSimulationEnabled, me }): Promise<{ blockGasLimit: string; estimatedGas: `0x${string}`; @@ -1052,20 +769,21 @@ index 8b16db19489c7407a2f6f8cbba26f21587c8db11..0e34913db5efd07351ec2c4417e2ed90 reason?: string | undefined; errorKey?: string | undefined; diff --git a/dist/utils/gas.mjs b/dist/utils/gas.mjs -index 697fd3a0321be16f88c4ec2733f6975b9304538e..fe023e79e0de0c3422da8eced6ecdd98619e9a9e 100644 +index a029072ced066a52226bfbcc05643feacfa0aeb5..be2432cb770b2b9537eddc3306cf90b84b3ea8b5 100644 --- a/dist/utils/gas.mjs +++ b/dist/utils/gas.mjs -@@ -1,8 +1,8 @@ - import { BNToHex, fractionBN, hexToBN, query } from "@metamask/controller-utils"; +@@ -1,9 +1,8 @@ + import { BNToHex, fractionBN, hexToBN, query, toHex } from "@metamask/controller-utils"; import { add0x, createModuleLogger, remove0x } from "@metamask/utils"; import { DELEGATION_PREFIX } from "./eip7702.mjs"; -+import { getGasEstimateBuffer } from "./feature-flags.mjs"; +-import { getGasEstimateFallback } from "./feature-flags.mjs"; ++import { getGasEstimateBuffer, getGasEstimateFallback } from "./feature-flags.mjs"; import { simulateTransactions } from "./simulation-api.mjs"; -import { GAS_BUFFER_CHAIN_OVERRIDES } from "../constants.mjs"; import { projectLogger } from "../logger.mjs"; import { TransactionEnvelopeType } from "../types.mjs"; export const log = createModuleLogger(projectLogger, 'gas'); -@@ -58,8 +58,8 @@ export async function estimateGas({ chainId, ethQuery, isSimulationEnabled, txPa +@@ -63,8 +62,8 @@ export async function estimateGas({ chainId, ethQuery, isSimulationEnabled, mess let estimatedGas = fallback; let simulationFails; const isUpgradeWithDataToSelf = txParams.type === TransactionEnvelopeType.setCode && @@ -1076,7 +794,7 @@ index 697fd3a0321be16f88c4ec2733f6975b9304538e..fe023e79e0de0c3422da8eced6ecdd98 data !== '0x' && from?.toLowerCase() === to?.toLowerCase(); try { -@@ -85,6 +85,7 @@ export async function estimateGas({ chainId, ethQuery, isSimulationEnabled, txPa +@@ -90,6 +89,7 @@ export async function estimateGas({ chainId, ethQuery, isSimulationEnabled, mess return { blockGasLimit, estimatedGas, @@ -1084,7 +802,7 @@ index 697fd3a0321be16f88c4ec2733f6975b9304538e..fe023e79e0de0c3422da8eced6ecdd98 simulationFails, }; } -@@ -122,7 +123,7 @@ export function addGasBuffer(estimatedGas, blockGasLimit, multiplier) { +@@ -127,7 +127,7 @@ export function addGasBuffer(estimatedGas, blockGasLimit, multiplier) { * @returns The final gas value and the estimate used. */ async function getGas(request) { @@ -1093,7 +811,7 @@ index 697fd3a0321be16f88c4ec2733f6975b9304538e..fe023e79e0de0c3422da8eced6ecdd98 const { disableGasBuffer } = txMeta; if (txMeta.txParams.gas) { log('Using value from request', txMeta.txParams.gas); -@@ -132,24 +133,32 @@ async function getGas(request) { +@@ -137,25 +137,33 @@ async function getGas(request) { log('Using fixed value', FIXED_GAS); return [FIXED_GAS, undefined, FIXED_GAS]; } @@ -1102,6 +820,8 @@ index 697fd3a0321be16f88c4ec2733f6975b9304538e..fe023e79e0de0c3422da8eced6ecdd98 chainId: request.chainId, ethQuery: request.ethQuery, isSimulationEnabled, +- messenger: request.messenger, ++ messenger, txParams: txMeta.txParams, }); - if (isCustomNetwork || simulationFails) { @@ -1138,7 +858,7 @@ index 697fd3a0321be16f88c4ec2733f6975b9304538e..fe023e79e0de0c3422da8eced6ecdd98 /** * Determine if the gas for the provided request should be fixed. diff --git a/dist/utils/validation.cjs b/dist/utils/validation.cjs -index bd6fa9156ff04ab90e2ea538446e3def97792eba..9de7b7274d839b1e83d704ba00a76f61ba6674e2 100644 +index dfee2549d3cc76e1202e9849dfb90d4b9e4a99f9..71521677f3b61f3cc19c78707b09cb83a9a8505c 100644 --- a/dist/utils/validation.cjs +++ b/dist/utils/validation.cjs @@ -1,6 +1,6 @@ @@ -1161,26 +881,7 @@ index bd6fa9156ff04ab90e2ea538446e3def97792eba..9de7b7274d839b1e83d704ba00a76f61 const TRANSACTION_ENVELOPE_TYPES_FEE_MARKET = [ types_1.TransactionEnvelopeType.feeMarket, types_1.TransactionEnvelopeType.setCode, -@@ -62,15 +67,16 @@ exports.validateTransactionOrigin = validateTransactionOrigin; - * - * @param txParams - Transaction params object to validate. - * @param isEIP1559Compatible - whether or not the current network supports EIP-1559 transactions. -+ * @param chainId - The chain ID of the transaction. - */ --function validateTxParams(txParams, isEIP1559Compatible = true) { -+function validateTxParams(txParams, isEIP1559Compatible = true, chainId) { - validateEnvelopeType(txParams.type); - validateEIP1559Compatibility(txParams, isEIP1559Compatible); - validateParamFrom(txParams.from); - validateParamRecipient(txParams); - validateParamValue(txParams.value); - validateParamData(txParams.data); -- validateParamChainId(txParams.chainId); -+ validateParamChainId(txParams.chainId, chainId); - validateGasFeeParams(txParams); - validateAuthorizationList(txParams); - } -@@ -190,14 +196,19 @@ exports.validateParamTo = validateParamTo; +@@ -193,14 +198,19 @@ exports.validateParamTo = validateParamTo; function validateBatchRequest({ internalAccounts, request, sizeLimit, }) { const { origin } = request; const isExternal = origin && origin !== controller_utils_1.ORIGIN_METAMASK; @@ -1204,36 +905,12 @@ index bd6fa9156ff04ab90e2ea538446e3def97792eba..9de7b7274d839b1e83d704ba00a76f61 } } exports.validateBatchRequest = validateBatchRequest; -@@ -225,16 +236,14 @@ function validateParamData(value) { - /** - * Validates chainId type. - * -- * @param chainId - The chainId to validate. -+ * @param chainIdParams - The chain ID to validate. -+ * @param chainIdNetworkClient - The chain ID of the network client. - */ --function validateParamChainId(chainId) { -- if (chainId !== undefined && -- typeof chainId !== 'number' && -- typeof chainId !== 'string') { -- throw rpc_errors_1.rpcErrors.invalidParams( -- // TODO: Either fix this lint violation or explain why it's necessary to ignore. -- // eslint-disable-next-line @typescript-eslint/restrict-template-expressions -- `Invalid transaction params: chainId is not a Number or hex string. got: (${chainId})`); -+function validateParamChainId(chainIdParams, chainIdNetworkClient) { -+ if (chainIdParams && -+ chainIdNetworkClient && -+ chainIdParams.toLowerCase?.() !== chainIdNetworkClient.toLowerCase()) { -+ throw rpc_errors_1.rpcErrors.invalidParams(`Invalid transaction params: chainId must match the network client, got: ${chainIdParams}, expected: ${chainIdNetworkClient}`); - } - } - /** diff --git a/dist/utils/validation.d.cts b/dist/utils/validation.d.cts -index 7cb8efdfc990face2f6a9f0b8a35d46640635286..81a9ed5cc081a5eab3cc0f18943d774e0958c624 100644 +index 56ad2d71dfcfe9e11f3b438bba57e30b6c20ed3a..81a9ed5cc081a5eab3cc0f18943d774e0958c624 100644 --- a/dist/utils/validation.d.cts +++ b/dist/utils/validation.d.cts -@@ -1,5 +1,10 @@ -+import type { Hex } from "@metamask/utils"; +@@ -1,6 +1,10 @@ + import type { Hex } from "@metamask/utils"; import type { TransactionBatchRequest } from "../types.cjs"; import { TransactionType, type TransactionParams } from "../types.cjs"; +export declare enum ErrorCode { @@ -1243,23 +920,12 @@ index 7cb8efdfc990face2f6a9f0b8a35d46640635286..81a9ed5cc081a5eab3cc0f18943d774e /** * Validates whether a transaction initiated by a specific 'from' address is permitted by the origin. * -@@ -30,8 +35,9 @@ export declare function validateTransactionOrigin({ data, from, internalAccounts - * - * @param txParams - Transaction params object to validate. - * @param isEIP1559Compatible - whether or not the current network supports EIP-1559 transactions. -+ * @param chainId - The chain ID of the transaction. - */ --export declare function validateTxParams(txParams: TransactionParams, isEIP1559Compatible?: boolean): void; -+export declare function validateTxParams(txParams: TransactionParams, isEIP1559Compatible?: boolean, chainId?: Hex): void; - /** - * Validates the recipient address in a transaction's parameters. - * diff --git a/dist/utils/validation.d.mts b/dist/utils/validation.d.mts -index f4a60a3e1336e3754dde219ac7d68a50131ce37f..d0cb41b42a6747df194ac46922248c52f5f0667f 100644 +index dccb426ea9b78171a25a7baa8f2e78e11a4b1c2c..d0cb41b42a6747df194ac46922248c52f5f0667f 100644 --- a/dist/utils/validation.d.mts +++ b/dist/utils/validation.d.mts -@@ -1,5 +1,10 @@ -+import type { Hex } from "@metamask/utils"; +@@ -1,6 +1,10 @@ + import type { Hex } from "@metamask/utils"; import type { TransactionBatchRequest } from "../types.mjs"; import { TransactionType, type TransactionParams } from "../types.mjs"; +export declare enum ErrorCode { @@ -1269,19 +935,8 @@ index f4a60a3e1336e3754dde219ac7d68a50131ce37f..d0cb41b42a6747df194ac46922248c52 /** * Validates whether a transaction initiated by a specific 'from' address is permitted by the origin. * -@@ -30,8 +35,9 @@ export declare function validateTransactionOrigin({ data, from, internalAccounts - * - * @param txParams - Transaction params object to validate. - * @param isEIP1559Compatible - whether or not the current network supports EIP-1559 transactions. -+ * @param chainId - The chain ID of the transaction. - */ --export declare function validateTxParams(txParams: TransactionParams, isEIP1559Compatible?: boolean): void; -+export declare function validateTxParams(txParams: TransactionParams, isEIP1559Compatible?: boolean, chainId?: Hex): void; - /** - * Validates the recipient address in a transaction's parameters. - * diff --git a/dist/utils/validation.mjs b/dist/utils/validation.mjs -index 70d3d5a73f104d3c50c1d3bc746ac19a5dac281c..29a0fae2c4e7a121480cff03be04fc30188e7823 100644 +index 4c8b3b3362efc750edc5ebfd8aa03db7f4e6e92e..5d4d4cba5f494ce276eda44e96bb88467a39b21e 100644 --- a/dist/utils/validation.mjs +++ b/dist/utils/validation.mjs @@ -1,10 +1,15 @@ @@ -1301,26 +956,7 @@ index 70d3d5a73f104d3c50c1d3bc746ac19a5dac281c..29a0fae2c4e7a121480cff03be04fc30 const TRANSACTION_ENVELOPE_TYPES_FEE_MARKET = [ TransactionEnvelopeType.feeMarket, TransactionEnvelopeType.setCode, -@@ -58,15 +63,16 @@ export async function validateTransactionOrigin({ data, from, internalAccounts, - * - * @param txParams - Transaction params object to validate. - * @param isEIP1559Compatible - whether or not the current network supports EIP-1559 transactions. -+ * @param chainId - The chain ID of the transaction. - */ --export function validateTxParams(txParams, isEIP1559Compatible = true) { -+export function validateTxParams(txParams, isEIP1559Compatible = true, chainId) { - validateEnvelopeType(txParams.type); - validateEIP1559Compatibility(txParams, isEIP1559Compatible); - validateParamFrom(txParams.from); - validateParamRecipient(txParams); - validateParamValue(txParams.value); - validateParamData(txParams.data); -- validateParamChainId(txParams.chainId); -+ validateParamChainId(txParams.chainId, chainId); - validateGasFeeParams(txParams); - validateAuthorizationList(txParams); - } -@@ -184,14 +190,19 @@ export function validateParamTo(to) { +@@ -187,14 +192,19 @@ export function validateParamTo(to) { export function validateBatchRequest({ internalAccounts, request, sizeLimit, }) { const { origin } = request; const isExternal = origin && origin !== ORIGIN_METAMASK; @@ -1344,27 +980,3 @@ index 70d3d5a73f104d3c50c1d3bc746ac19a5dac281c..29a0fae2c4e7a121480cff03be04fc30 } } /** -@@ -218,16 +229,14 @@ function validateParamData(value) { - /** - * Validates chainId type. - * -- * @param chainId - The chainId to validate. -+ * @param chainIdParams - The chain ID to validate. -+ * @param chainIdNetworkClient - The chain ID of the network client. - */ --function validateParamChainId(chainId) { -- if (chainId !== undefined && -- typeof chainId !== 'number' && -- typeof chainId !== 'string') { -- throw rpcErrors.invalidParams( -- // TODO: Either fix this lint violation or explain why it's necessary to ignore. -- // eslint-disable-next-line @typescript-eslint/restrict-template-expressions -- `Invalid transaction params: chainId is not a Number or hex string. got: (${chainId})`); -+function validateParamChainId(chainIdParams, chainIdNetworkClient) { -+ if (chainIdParams && -+ chainIdNetworkClient && -+ chainIdParams.toLowerCase?.() !== chainIdNetworkClient.toLowerCase()) { -+ throw rpcErrors.invalidParams(`Invalid transaction params: chainId must match the network client, got: ${chainIdParams}, expected: ${chainIdNetworkClient}`); - } - } - /** diff --git a/.yarnrc.yml b/.yarnrc.yml index 05ad1f9750eb..a77108a323a5 100644 --- a/.yarnrc.yml +++ b/.yarnrc.yml @@ -64,6 +64,12 @@ npmAuditIgnoreAdvisories: # We are ignoring this on April 24, 2025 as it does not affect the codebase. - 1103932 + # Issue: React Router allows pre-render data spoofing on React-Router framework mode + # URL: https://github.com/MetaMask/metamask-extension/security/dependabot/228 + # will be fixed in https://github.com/MetaMask/MetaMask-planning/issues/3261 + - 1104031 + - 1104032 + # Temp fix for https://github.com/MetaMask/metamask-extension/pull/16920 for the sake of 11.7.1 hotfix # This will be removed in this ticket https://github.com/MetaMask/metamask-extension/issues/22299 - 'ts-custom-error (deprecation)' diff --git a/CHANGELOG.md b/CHANGELOG.md index 99cb009b5999..dff5e6fbf2d9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,115 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [12.17.0] +### Added +- Support gasless transactions via EIP-7702 ([#31593](https://github.com/MetaMask/metamask-extension/pull/31593)) +- Add splash page for smart account upgrade ([#31765](https://github.com/MetaMask/metamask-extension/pull/31765)) +- Add setting to dismiss prompt to enable smart contract ([#31609](https://github.com/MetaMask/metamask-extension/pull/31609)) +- Require network client ID when adding transactions ([#31456](https://github.com/MetaMask/metamask-extension/pull/31456)) +- Escape / sanitize signTypedData update ([#31377](https://github.com/MetaMask/metamask-extension/pull/31377)) +- Fetch user balance for transaction's network ([#31441](https://github.com/MetaMask/metamask-extension/pull/31441)) +- For batch transaction simulation section approve rows should be displayed at the top ([#31511](https://github.com/MetaMask/metamask-extension/pull/31511)) +- Gas fee token toast ([#31338](https://github.com/MetaMask/metamask-extension/pull/31338)) +- Sol 208 extension asset details UI ([#31407](https://github.com/MetaMask/metamask-extension/pull/31407)) +- Add deeply liquid stablecoin slippage value of 0.5 ([#31744](https://github.com/MetaMask/metamask-extension/pull/31744)) +- Support copying block explorer link in bridge page ([#31498](https://github.com/MetaMask/metamask-extension/pull/31498)) +- [Beta] Create solana account without redirecting ([#31493](https://github.com/MetaMask/metamask-extension/pull/31493)) +- Fetch asset metadata on search ([#31258](https://github.com/MetaMask/metamask-extension/pull/31258)) +- Add new way to customize the Snap account creation flow ([#31285](https://github.com/MetaMask/metamask-extension/pull/31285)) +- Add icon image for Plume network ([#31712](https://github.com/MetaMask/metamask-extension/pull/31712)) +- [Beta] Solana: update add account from opt in solana ([#31387](https://github.com/MetaMask/metamask-extension/pull/31387)) +- [Beta] Solana: update add account from network picker ([#31358](https://github.com/MetaMask/metamask-extension/pull/31358)) +- Add clear functionality to SRP import error banner ([#30673](https://github.com/MetaMask/metamask-extension/pull/30673)) +- Multichain tokens import ([#31201](https://github.com/MetaMask/metamask-extension/pull/31201)) +- Add remote-mode feature slide ([#31463](https://github.com/MetaMask/metamask-extension/pull/31463)) +- Implement the publishBatch hook for smart transactions ([#31267](https://github.com/MetaMask/metamask-extension/pull/31267)) +- [Beta] Create Solana account automatically on wallet creation or SRP import ([#32038](https://github.com/MetaMask/metamask-extension/pull/32038)) +- Prioritize available chainId / networkClientId over selected chainId when available in transaction ([#31776](https://github.com/MetaMask/metamask-extension/pull/31776)) + +### Changed +- Bump transaction controller version ([#31440](https://github.com/MetaMask/metamask-extension/pull/31440)) +- Update default account name visibility/width ([#31202](https://github.com/MetaMask/metamask-extension/pull/31202)) +- Updating Text component "body" font sizes ([#31494](https://github.com/MetaMask/metamask-extension/pull/31494)) +- Update popup width of extension from 357px to 400px ([#31443](https://github.com/MetaMask/metamask-extension/pull/31443)) +- Update font family from euclid to centra ([#31303](https://github.com/MetaMask/metamask-extension/pull/31303)) +- Refactor multichain activity tab ([#31439](https://github.com/MetaMask/metamask-extension/pull/31439)) +- Update alignment and hover effect for token cell ([#31615](https://github.com/MetaMask/metamask-extension/pull/31615)) +- Update font weights for balance price and other headers ([#31624](https://github.com/MetaMask/metamask-extension/pull/31624)) +- Update Soneium logo ([#31573](https://github.com/MetaMask/metamask-extension/pull/31573)) +- Add XRPL EVM Testnet network ([#31533](https://github.com/MetaMask/metamask-extension/pull/31533)) +- Update color of values to text-default ([#30886](https://github.com/MetaMask/metamask-extension/pull/30886)) +- Update tabs color hover and animations ([#30907](https://github.com/MetaMask/metamask-extension/pull/30907)) +- Updated institutional snap to version which includes a fix for dev mode to prevent unwanted logging and state reads ([#32208](https://github.com/MetaMask/metamask-extension/pull/32208)) +- Update: Bringing back SRP pills ([#32168](https://github.com/MetaMask/metamask-extension/pull/32168)) + +### Fixed +- Fix `wallet_getCapabilities` with missing networks ([#32237](https://github.com/MetaMask/metamask-extension/pull/32237)) +- Fix NFT removal on different networks ([#32102](https://github.com/MetaMask/metamask-extension/pull/32102)) +- [Beta] Fix exchange rate lookups on Solana Swap page to prevent crashing when values are undefined ([#32114](https://github.com/MetaMask/metamask-extension/pull/32114)) +- Fix Display "🦊 Smart contract" in "interacting with" row for batch[ transaction](https://github.com/MetaMask/metamask-extension/pull/31507) confirmations (#31507) +- Fix improvements in page to revert smart account to EOA account ([#31605](https://github.com/MetaMask/metamask-extension/pull/31605)) +- Fix Update blockaid friction modal copy ([#31475](https://github.com/MetaMask/metamask-extension/pull/31475)) +- Fix switch-ethereun-chain not passing rejectApprovalRequestsForOrigin hook[ correctly](https://github.com/MetaMask/metamask-extension/pull/31672) (#31672) +- Fix For batch transactions sum total of gas needed for all transactions in the[ batched](https://github.com/MetaMask/metamask-extension/pull/31555) should be check to show insufficient funds error (#31555) +- Fix unscrollable Remove Snap modal dialog ([#31413](https://github.com/MetaMask/metamask-extension/pull/31413)) +- Fix should not show NonContractAddressAlert for auth request ([#31503](https://github.com/MetaMask/metamask-extension/pull/31503)) +- Remove preference to enable incoming transaction polling for networks ([#31269](https://github.com/MetaMask/metamask-extension/pull/31269)) +- Fix select first gas fee token automatically ([#31508](https://github.com/MetaMask/metamask-extension/pull/31508)) +- Fix hide balance alert if selected gas fee token ([#31497](https://github.com/MetaMask/metamask-extension/pull/31497)) +- Fix `useTransactionGasFeeEstimate` to calculate gas estimate properly ([#31469](https://github.com/MetaMask/metamask-extension/pull/31469)) +- Add `enableTxParamsGasFeeUpdates` to `true` in `TransactionController` config ([#31476](https://github.com/MetaMask/metamask-extension/pull/31476)) +- Fix simulation of type-4 transactions ([#31335](https://github.com/MetaMask/metamask-extension/pull/31335)) +- Fix missing non-evm account modal bottom border-radius ([#31374](https://github.com/MetaMask/metamask-extension/pull/31374)) +- Fix confirmation responsiveness inconsistencies (redesign Snaps multichain permissions-connect confirmations-page) ([#31058](https://github.com/MetaMask/metamask-extension/pull/31058)) +- Hide import key error ([#31129](https://github.com/MetaMask/metamask-extension/pull/31129)) +- Fix Update routes callbacks per react-perf's warnings ([#31019](https://github.com/MetaMask/metamask-extension/pull/31019)) +- Move to activity tab before submitting a non-evm transaction ([#31505](https://github.com/MetaMask/metamask-extension/pull/31505)) +- Sol-267 remove pill for snap accounts ([#31716](https://github.com/MetaMask/metamask-extension/pull/31716)) +- Fix multichain swap transaction to show from amount ([#31592](https://github.com/MetaMask/metamask-extension/pull/31592)) +- Fix Swap to ethereum string ([#31715](https://github.com/MetaMask/metamask-extension/pull/31715)) +- Fix prevents unintended second redirection to activity tab ([#31822](https://github.com/MetaMask/metamask-extension/pull/31822)) +- [Beta] Fix missing solana fiat values in XChain swaps page ([#31686](https://github.com/MetaMask/metamask-extension/pull/31686)) +- Fix show account balances for selected XChain swap destination address ([#31684](https://github.com/MetaMask/metamask-extension/pull/31684)) +- Fix remove-duplicated-alerts ([#31695](https://github.com/MetaMask/metamask-extension/pull/31695)) +- mms-1799 unverified token ([#31462](https://github.com/MetaMask/metamask-extension/pull/31462)) +- Fix balance and token icons are unavailable when the bridge page is reopened ([#31343](https://github.com/MetaMask/metamask-extension/pull/31343)) +- Fix Prevent overflow in from Snaps UI header in confirmations ([#31595](https://github.com/MetaMask/metamask-extension/pull/31595)) +- Update balance display in `AssetSelector` ([#31428](https://github.com/MetaMask/metamask-extension/pull/31428)) +- Fix import srp error handling and style ([#31662](https://github.com/MetaMask/metamask-extension/pull/31662)) +- Fix dark mode styling and spacing ([#31661](https://github.com/MetaMask/metamask-extension/pull/31661)) +- Fix workaround for first party snap account name suggestion ([#31542](https://github.com/MetaMask/metamask-extension/pull/31542)) +- Fix small amounts on activity tab ([#31563](https://github.com/MetaMask/metamask-extension/pull/31563)) +- Fix prevent multiple account creations in the same flow. ([#31543](https://github.com/MetaMask/metamask-extension/pull/31543)) +- Fix activity tab aggregated amount ([#31514](https://github.com/MetaMask/metamask-extension/pull/31514)) +- Fix hide accounts by default in reveal srp flow ([#31395](https://github.com/MetaMask/metamask-extension/pull/31395)) +- Fix srp toast message ([#31312](https://github.com/MetaMask/metamask-extension/pull/31312)) +- Fix Failed to construct URL: Invalid URL at new URL ([#31502](https://github.com/MetaMask/metamask-extension/pull/31502)) +- [Beta] Fix add solana modal title ([#31660](https://github.com/MetaMask/metamask-extension/pull/31660)) +- Fix srp list padding ([#31697](https://github.com/MetaMask/metamask-extension/pull/31697)) +- Fix wrap long asset names ([#31657](https://github.com/MetaMask/metamask-extension/pull/31657)) +- Improve fetching nft details for custom contracts ([#31432](https://github.com/MetaMask/metamask-extension/pull/31432)) +- Update color for no balance and generic avatars ([#30891](https://github.com/MetaMask/metamask-extension/pull/30891)) +- Remove shadow from toast ([#31618](https://github.com/MetaMask/metamask-extension/pull/31618)) +- Fix nftController with modular init pattern ([#31658](https://github.com/MetaMask/metamask-extension/pull/31658)) +- Fix NFT balance in send flow ([#31239](https://github.com/MetaMask/metamask-extension/pull/31239)) +- Fix button disabled for long tokenId ([#31359](https://github.com/MetaMask/metamask-extension/pull/31359)) +- Fix token name sort ([#31302](https://github.com/MetaMask/metamask-extension/pull/31302)) +- Revert "feat(14507): improve error message for failed txn in activity… ([#31137](https://github.com/MetaMask/metamask-extension/pull/31137)) +- Fix should not auto-close notification window if loaded in a tab ([#30970](https://github.com/MetaMask/metamask-extension/pull/30970)) +- Fix solana account discovery ([#32198](https://github.com/MetaMask/metamask-extension/pull/32198)) +- Fix app crash that occurred when searching for non-existent tokens in the import dialog on mainnet ([#32213](https://github.com/MetaMask/metamask-extension/pull/32213) +- Fix Fiat conversion is not displayed on the assets list and in the aggregated balance as entry ([#31938](https://github.com/MetaMask/metamask-extension/pull/31938) +- Fix Bridge page showing high cost alert twice when bridging ([#32158](https://github.com/MetaMask/metamask-extension/pull/32158)) +- Fix Snap rate limiting issues ([#32042](https://github.com/MetaMask/metamask-extension/pull/32042)) +- Fix missing `includeMarketData` param from `onAssetsConversion` handler ([#32196](https://github.com/MetaMask/metamask-extension/pull/32196)) +- Fix remove duplicate label for insufficient gas ([#32267](https://github.com/MetaMask/metamask-extension/pull/32267)) +- Fix bridge for token with no decimals ([#32265](https://github.com/MetaMask/metamask-extension/pull/32265)) +- Fix: Removed timeout for messages requiring user actions ([#32046](https://github.com/MetaMask/metamask-extension/pull/32046)) +- Fix: Unable to send transaction low / high nonce transaction on any network when STX is enabled ([#32244](https://github.com/MetaMask/metamask-extension/pull/32244)) +- Fix: Ensure no duplicate accounts are persisted ([#32287](https://github.com/MetaMask/metamask-extension/pull/32287)) +- Fix: provide better native token names when bridging and swapping removed networks([#32293](https://github.com/MetaMask/metamask-extension/pull/32293)) + ## [12.16.2] ### Changed - Update onboarding flow for Firefox ([#32179](https://github.com/MetaMask/metamask-extension/pull/32179)) @@ -22,7 +131,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Fix confusing error shown when trying to unlock the wallet with the wrong password ([#31933](https://github.com/MetaMask/metamask-extension/pull/31933)) - Fix displaying full-size images of nft ([#31967](https://github.com/MetaMask/metamask-extension/pull/31967)) - ## [12.16.0] ### Added - Include 'Bitcoin' and 'Watch-only' accounts in settings search results for easier access. ([#31257](https://github.com/MetaMask/metamask-extension/pull/31257)) @@ -82,6 +190,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Prevent repeated HID connection prompts when paginating through Ledger accounts during the connection process. ([#30384](https://github.com/MetaMask/metamask-extension/pull/30384)) - Fix Profile Sync feature not appearing in settings search results. ([#30687](https://github.com/MetaMask/metamask-extension/pull/30687)) - Fix balance display potentially showing incorrect values when only non-EVM accounts are present. ([#30671](https://github.com/MetaMask/metamask-extension/pull/30671)) +- Changes in account modal to switch to smart account type ([#31899](https://github.com/MetaMask/metamask-extension/pull/31899)) +- Support for Solana Devnet ([#31702](https://github.com/MetaMask/metamask-extension/pull/31702)) +- Support for Solana on Firefox ([#32104](https://github.com/MetaMask/metamask-extension/pull/32104)) ## [12.15.2] ### Added @@ -5968,7 +6079,8 @@ Update styles and spacing on the critical error page ([#20350](https://github.c - Added the ability to restore accounts from seed words. -[Unreleased]: https://github.com/MetaMask/metamask-extension/compare/v12.16.2...HEAD +[Unreleased]: https://github.com/MetaMask/metamask-extension/compare/v12.17.0...HEAD +[12.17.0]: https://github.com/MetaMask/metamask-extension/compare/v12.16.2...v12.17.0 [12.16.2]: https://github.com/MetaMask/metamask-extension/compare/v12.16.1...v12.16.2 [12.16.1]: https://github.com/MetaMask/metamask-extension/compare/v12.16.0...v12.16.1 [12.16.0]: https://github.com/MetaMask/metamask-extension/compare/v12.15.2...v12.16.0 diff --git a/app/_locales/de/messages.json b/app/_locales/de/messages.json index 7c67a50f074d..be7224476060 100644 --- a/app/_locales/de/messages.json +++ b/app/_locales/de/messages.json @@ -44,6 +44,20 @@ "QRHardwareWalletSteps2Description": { "message": "Ngrave Zero" }, + "SrpListHideAccounts": { + "message": "$1 Konten verbergen", + "description": "$1 is the number of accounts" + }, + "SrpListHideSingleAccount": { + "message": "$1 Konto verbergen" + }, + "SrpListShowAccounts": { + "message": "$1-Konten anzeigen", + "description": "$1 is the number of accounts" + }, + "SrpListShowSingleAccount": { + "message": "1 Konto anzeigen" + }, "about": { "message": "Über" }, @@ -76,6 +90,9 @@ "accountDetails": { "message": "Kontodetails" }, + "accountDetailsRevokeDelegationButton": { + "message": " Zum regulƤren Konto zurückwechseln" + }, "accountIdenticon": { "message": "Konto-Identicon" }, @@ -153,6 +170,12 @@ "addAlias": { "message": "Alias hinzufügen" }, + "addBitcoinAccountLabel": { + "message": "Bitcoin-Konto (Beta)" + }, + "addBitcoinTestnetAccountLabel": { + "message": "Bitcoin-Konto (Testnet)" + }, "addBlockExplorer": { "message": "Einen Block-Explorer hinzufügen" }, @@ -193,6 +216,9 @@ "addFriendsAndAddresses": { "message": "Freunde und Adressen hinzufügen, welchen Sie vertrauen" }, + "addHardwareWalletLabel": { + "message": "Hardware-Wallet" + }, "addIPFSGateway": { "message": "Fügen Sie Ihr bevorzugtes IPFS-Gateway hinzu." }, @@ -212,12 +238,26 @@ "addNewAccount": { "message": "Ein neues Konto hinzufügen" }, + "addNewEthereumAccountLabel": { + "message": "Ethereum-Konto" + }, + "addNewSolanaAccountLabel": { + "message": "Solana-Konto" + }, "addNft": { "message": "NFT hinzufügen" }, "addNfts": { "message": "NFTs hinzufügen" }, + "addNonEvmAccount": { + "message": "$1-Konto hinzufügen", + "description": "$1 is the non EVM network where the account is going to be created, e.g. Bitcoin or Solana" + }, + "addNonEvmAccountFromNetworkPicker": { + "message": "Um das $1-Netzwerk zu aktivieren, müssen Sie ein $2-Konto erstellen.", + "description": "$1 is the non EVM network where the account is going to be created, e.g. Solana Mainnet or Solana Devnet. $2 is the account type, e.g. Bitcoin or Solana" + }, "addRpcUrl": { "message": "RPC-URL hinzufügen" }, @@ -300,14 +340,16 @@ "advancedPriorityFeeToolTip": { "message": "PrioritƤtsgebühr (alias ā€žMiner Tipā€œ) geht direkt an Miner und veranlasst sie, Ihre Transaktion zu priorisieren." }, - "aggregatedBalancePopover": { - "message": "Dies spiegelt den Wert aller Tokens wider, über die Sie in einem bestimmten Netzwerk verfügen. Sollten Sie diesen Wert lieber in ETH oder anderen WƤhrungen angezeigt bekommen wollen, wechseln Sie zu $1.", - "description": "$1 represents the settings page" - }, "agreeTermsOfUse": { "message": "Ich stimme MetaMasks $1 zu", "description": "$1 is the `terms` link" }, + "airDropPatternDescription": { + "message": "Der On-Chain-Verlauf des Tokens zeigt frühere FƤlle von verdƤchtigen Airdrop-AktivitƤten." + }, + "airDropPatternTitle": { + "message": "Airdrop-Muster" + }, "airgapVault": { "message": "AirGap-Tresor" }, @@ -726,9 +768,21 @@ "bridgeConfirmTwoTransactions": { "message": "Sie werden 2 Transaktionen auf Ihrer Hardware-Wallet bestƤtigen müssen:" }, + "bridgeCreateSolanaAccount": { + "message": "Solana-Konto erstellen" + }, + "bridgeCreateSolanaAccountDescription": { + "message": "Um zum Solana-Netzwerk zu swappen, benƶtigen Sie ein Konto und eine Empfangsadresse." + }, + "bridgeCreateSolanaAccountTitle": { + "message": "ZunƤchst benƶtigen Sie ein Solana-Konto." + }, "bridgeEnterAmount": { "message": "Betrag eingeben" }, + "bridgeEnterAmountAndSelectAccount": { + "message": "Betrag eingeben und Zielkonto auswƤhlen" + }, "bridgeExplorerLinkViewOn": { "message": "Auf $1 ansehen" }, @@ -751,9 +805,15 @@ "bridgeQuoteExpired": { "message": "Ihr Angebot ist abgelaufen." }, + "bridgeSelectDestinationAccount": { + "message": "Zielkonto auswƤhlen" + }, "bridgeSelectNetwork": { "message": "Netzwerk wƤhlen" }, + "bridgeSelectTokenAmountAndAccount": { + "message": "Token, Betrag und Zielkonto auswƤhlen" + }, "bridgeSelectTokenAndAmount": { "message": "Token und Betrag auswƤhlen" }, @@ -944,6 +1004,12 @@ "message": "Keine Option gefunden", "description": "Default text shown in the combo field dropdown if no options." }, + "concentratedSupplyDistributionDescription": { + "message": "Der Großteil des Token-Angebots wird von den wichtigsten Token-Inhabern gehalten, was das Risiko einer zentralisierten Preismanipulation birgt" + }, + "concentratedSupplyDistributionTitle": { + "message": "Konzentrierte Angebotsverteilung" + }, "configureSnapPopupDescription": { "message": "Sie verlassen jetzt MetaMask, um diesen Snap zu konfigurieren." }, @@ -962,6 +1028,15 @@ "confirm": { "message": "BestƤtigen" }, + "confirmAccountType": { + "message": "Typ" + }, + "confirmAccountTypeSmartContract": { + "message": "Smart-Konto" + }, + "confirmAccountTypeStandard": { + "message": "Standardkonto" + }, "confirmAlertModalAcknowledgeMultiple": { "message": "Ich habe die Benachrichtigungen zur Kenntnis genommen und mƶchte trotzdem fortfahren" }, @@ -974,12 +1049,36 @@ "confirmFieldTooltipPaymaster": { "message": "Die Gebühr für diese Transaktion wird durch den Paymaster Smart Contract bezahlt." }, + "confirmGasFeeTokenBalance": { + "message": "Guth:" + }, + "confirmGasFeeTokenInsufficientBalance": { + "message": "Unzureichende Gelder" + }, + "confirmGasFeeTokenMetaMaskFee": { + "message": "Einschließlich $1 Gebühr" + }, + "confirmGasFeeTokenModalTitle": { + "message": "Token auswƤhlen" + }, + "confirmGasFeeTokenToast": { + "message": "Sie bezahlen diese Netzwerkgebühr mit $1" + }, + "confirmGasFeeTokenTooltip": { + "message": "Diese Gebühr wird für die Bearbeitung Ihrer Transaktion an das Netzwerk gezahlt. Sie umfasst eine MetaMask-Gebühr von $1 für Nicht-ETH-Token." + }, + "confirmNestedTransactionTitle": { + "message": "Transaktion $1" + }, "confirmPassword": { "message": "Passwort bestƤtigen" }, "confirmRecoveryPhrase": { "message": "Geheime Wiederherstellungsphrase bestƤtigen" }, + "confirmSimulationApprove": { + "message": "Sie genehmigen" + }, "confirmTitleApproveTransactionNFT": { "message": "Auszahlungsanfrage" }, @@ -1022,9 +1121,24 @@ "confirmTitleTransaction": { "message": "Transaktionsanfrage" }, + "confirmUpgradeCancelModalButtonCancelTransaction": { + "message": "Transaktion stornieren" + }, + "confirmUpgradeCancelModalButtonCancelUpgrade": { + "message": "Aktualisierung abbrechen und Transaktion stornieren" + }, + "confirmUpgradeCancelModalDescription": { + "message": "Wenn Sie Ihr Konto nicht aktualisieren mƶchten, kƶnnen Sie es hier stornieren.\n\nUm diese Transaktion ohne Aktualisierung abzuschließen, müssen Sie diese Anfrage erneut auf der Website stellen. $1." + }, + "confirmUpgradeCancelModalTitle": { + "message": "Transaktion stornieren" + }, "confirmationAlertDetails": { "message": "Um Ihre Assets zu schützen, empfehlen wir die Ablehnung der Anfrage." }, + "confirmationAlertModalTitleDescription": { + "message": "Ihre Assets kƶnnten gefƤhrdet sein" + }, "confirmed": { "message": "BestƤtigt" }, @@ -1052,6 +1166,9 @@ "connectAccounts": { "message": "Konten verbinden" }, + "connectAnAccountHeader": { + "message": "Konten verbinden" + }, "connectManually": { "message": "Manuelle Verbindung zur aktuellen Seite" }, @@ -1158,6 +1275,9 @@ "message": "Abrufen von $1 fehlgeschlagen. Netzwerkverbindung überprüfen und erneut versuchen.", "description": "$1 is the name of the snap being fetched." }, + "connectionPopoverDescription": { + "message": "Um eine Verbindung zu einer Website herzustellen, klicken Sie auf die SchaltflƤche ā€žVerbindenā€œ. MetaMask kann sich nur mit web3-Websites verbinden." + }, "connectionRequest": { "message": "Verbindungsanfrage" }, @@ -1219,6 +1339,9 @@ "create": { "message": "Erstellen" }, + "createNewAccountHeader": { + "message": "Neues Konto erstellen" + }, "createNewWallet": { "message": "Eine neue Wallet erstellen" }, @@ -1231,6 +1354,9 @@ "createSnapAccountTitle": { "message": "Konto erstellen" }, + "createSolanaAccount": { + "message": "Solana-Konto erstellen" + }, "creatorAddress": { "message": "Adresse des Erstellers" }, @@ -1471,6 +1597,21 @@ "message": "Beschreibung von $1", "description": "$1 represents the name of the snap" }, + "destinationAccountPickerNoEligible": { + "message": "Keine berechtigten Konten gefunden" + }, + "destinationAccountPickerNoMatching": { + "message": "Keine übereinstimmenden Konten gefunden" + }, + "destinationAccountPickerReceiveAt": { + "message": "Empfangen am" + }, + "destinationAccountPickerSearchPlaceholderToMainnet": { + "message": "Empfangsadresse oder ENS" + }, + "destinationAccountPickerSearchPlaceholderToSolana": { + "message": "Empfangsadresse" + }, "details": { "message": "Details" }, @@ -1516,6 +1657,9 @@ "message": "$1 wurde von $2 getrennt", "description": "$1 is name of the name and $2 represents the dapp name`" }, + "discover": { + "message": "Entdecken" + }, "discoverSnaps": { "message": "Snaps entdecken", "description": "Text that links to the Snaps website. Displayed in a banner on Snaps list page in settings." @@ -1872,6 +2016,9 @@ "experimental": { "message": "Experimentell" }, + "exploreweb3": { + "message": "Web3 erkunden" + }, "exportYourData": { "message": "Ihre Daten exportieren" }, @@ -1885,6 +2032,9 @@ "message": "Erkunden Sie die von der Community erstellten Snaps, um Ihr web3-Erlebnis individuell zu gestalten.", "description": "Banner description displayed on Snaps list page in Settings when less than 6 Snaps is installed." }, + "externalAccount": { + "message": "Externes Konto" + }, "externalExtension": { "message": "Externe Erweiterung" }, @@ -2197,6 +2347,12 @@ "holdToRevealUnlockedLabel": { "message": "zur-Anzeige-Halten-Kreis entsperrt" }, + "honeypotDescription": { + "message": "Dieser Token kƶnnte ein Honeypot-Risiko bergen. Es empfiehlt sich, vor der Interaktion eine Sorgfaltsprüfung vorzunehmen, um einen mƶglichen finanziellen Verlust zu vermeiden." + }, + "honeypotTitle": { + "message": "Honeypot" + }, "howNetworkFeesWorkExplanation": { "message": "GeschƤtzte Gebühr für die Abwicklung der Transaktion. Die maximale Gebühr ist $1." }, @@ -2262,6 +2418,30 @@ "importNFTTokenIdToolTip": { "message": "Die ID eines NFTs ist eine eindeutige Kennung, da keine zwei NFTs gleich sind. Auch diese Nummer finden Sie in OpenSea unter ā€žDetailsā€œ. Notieren Sie diese oder kopieren Sie sie in Ihre Zwischenablage." }, + "importNWordSRP": { + "message": "Ich habe eine $1-Wort-Wiederherstellungsphrase", + "description": "$1 is the number of words in the recovery phrase" + }, + "importPrivateKey": { + "message": "Privater Schlüssel" + }, + "importSRPDescription": { + "message": "Importieren Sie eine bereits vorhandene Wallet mit Ihrer geheimen 12- oder 24-Wort-Wiederherstellungsphrase." + }, + "importSRPNumberOfWordsError": { + "message": "Geheime Wiederherstellungsphrasen bestehen aus 12 oder 24 Wƶrtern" + }, + "importSRPWordError": { + "message": "Das Wort $1 ist falsch oder falsch geschrieben.", + "description": "$1 is the word that is incorrect or misspelled" + }, + "importSRPWordErrorAlternative": { + "message": "Wort $1 und $2 sind falsch oder falsch geschrieben.", + "description": "$1 and $2 are multiple words that are mispelled." + }, + "importSecretRecoveryPhrase": { + "message": "Geheime Wiederherstellungsphrase importieren" + }, "importSelectedTokens": { "message": "AusgewƤhlte Tokens importieren?" }, @@ -2280,6 +2460,12 @@ "importTokensError": { "message": "Wir konnten die Tokens nicht importieren. Bitte versuchen Sie es spƤter erneut." }, + "importWallet": { + "message": "Wallet importieren" + }, + "importWalletOrAccountHeader": { + "message": "Wallet oder Konto importieren" + }, "importWithCount": { "message": "$1 importieren", "description": "$1 will the number of detected tokens that are selected for importing, if all of them are selected then $1 will be all" @@ -2327,6 +2513,12 @@ "insufficientFundsForGas": { "message": "Unzureichende Gelder für Gas" }, + "insufficientLockedLiquidityDescription": { + "message": "Aufgrund des Mangels an ausreichend gesicherter oder verbrannter LiquiditƤt ist das Token anfƤllig für plƶtzliche LiquiditƤtsabflüsse, was zu MarktinstabilitƤt führen kann." + }, + "insufficientLockedLiquidityTitle": { + "message": "Unzureichende gesperrte LiquiditƤt" + }, "insufficientTokens": { "message": "Nicht genügend Tokens." }, @@ -2362,6 +2554,9 @@ "invalidCustomNetworkAlertTitle": { "message": "Ungültiges benutzerdefiniertes Netzwerk" }, + "invalidHexData": { + "message": "Ungültige Hex-Daten" + }, "invalidHexNumber": { "message": "Ungültige Hexadezimalzahl." }, @@ -2540,6 +2735,9 @@ "ledgerLocked": { "message": "Keine Verbindung zum Ledger-GerƤt. Bitte stellen Sie sicher, dass Ihr GerƤt entsperrt ist und die Ethereum-App geƶffnet ist." }, + "ledgerMultipleDevicesUnsupportedErrorMessage": { + "message": "Es kƶnnen nicht mehrere Ledger-GerƤte gleichzeitig verbunden werden. Bevor ein neues Ledger-GerƤt verbunden werden kann, sollten Sie zunƤchst die Verbindung zum vorherigen GerƤt trennen." + }, "ledgerTimeout": { "message": "Ledger Live braucht zu lange für eine Reaktion oder um eine Verbindung herzustellen. Stellen Sie sicher, dass die Ledger Live-App geƶffnet und Ihr GerƤt entsperrt ist." }, @@ -2637,6 +2835,9 @@ "manageDefaultSettings": { "message": "Standard-Datenschutzeinstellungen verwalten" }, + "managePermissions": { + "message": "Genehmigungen verwalten" + }, "marketCap": { "message": "Marktkapitalisierung" }, @@ -2755,6 +2956,15 @@ "multichainAddEthereumChainConfirmationDescription": { "message": "Sie fügen dieses Netzwerk zu MetaMask hinzu und geben dieser Website die Genehmigung, es zu nutzen." }, + "multichainQuoteCardBridgingLabel": { + "message": "Bridging" + }, + "multichainQuoteCardQuoteLabel": { + "message": "Angebot" + }, + "multichainQuoteCardTimeLabel": { + "message": "Zeit" + }, "multipleSnapConnectionWarning": { "message": "$1 mƶchte $2 Snaps verwenden", "description": "$1 is the dapp and $2 is the number of snaps it wants to connect to." @@ -2869,6 +3079,13 @@ "network": { "message": "Netzwerk:" }, + "networkChanged": { + "message": "Netzwerk geƤndert" + }, + "networkChangedMessage": { + "message": "Sie führen jetzt eine Transaktion bei $1 durch.", + "description": "$1 is the name of the network" + }, "networkDetails": { "message": "Netzwerkdetails" }, @@ -3143,6 +3360,9 @@ "notEnoughGas": { "message": "Nicht genügend Gas" }, + "notNow": { + "message": "Nicht jetzt" + }, "notificationDetail": { "message": "Details" }, @@ -3505,6 +3725,13 @@ "origin": { "message": "Ursprung" }, + "originChanged": { + "message": "Website geƤndert" + }, + "originChangedMessage": { + "message": "Sie überprüfen gerade eine Anfrage von $1.", + "description": "$1 is the name of the origin" + }, "osTheme": { "message": "System" }, @@ -3559,6 +3786,14 @@ "pending": { "message": "Ausstehend" }, + "pendingConfirmationAddNetworkAlertMessage": { + "message": "Durch eine Aktualisierung des Netzwerks werden $1 ausstehende Transaktionen von dieser Website storniert.", + "description": "Number of transactions." + }, + "pendingConfirmationSwitchNetworkAlertMessage": { + "message": "Durch einen Netzwerkwechsel werden $1 ausstehende Transaktionen von dieser Website storniert.", + "description": "Number of transactions." + }, "pendingTransactionAlertMessage": { "message": "Diese Transaktion wird nicht ausgeführt, bevor eine vorherige Transaktion abgeschlossen ist. $1", "description": "$1 represents the words 'how to cancel or speed up a transaction' in a hyperlink" @@ -3842,6 +4077,9 @@ "permitSimulationChange_receive": { "message": "Sie empfangen" }, + "permitSimulationChange_revoke2": { + "message": "Widerrufen" + }, "permitSimulationChange_transfer": { "message": "Sie senden" }, @@ -4237,6 +4475,9 @@ "reusedTokenNameWarning": { "message": "Ein Token hier verwendet ein Symbol von einem anderen Token, das Sie beobachten. Dies kann verwirrend oder trügerisch sein." }, + "revealSecretRecoveryPhrase": { + "message": "Geheime Wiederherstellungsphrase offenlegen" + }, "revealSeedWords": { "message": "Geheime Wiederherstellungsphrase offenlegen" }, @@ -4286,12 +4527,19 @@ "reviewAlerts": { "message": "Benachrichtigungen überprüfen" }, + "reviewPendingTransactions": { + "message": "Ausstehende Transaktionen überprüfen" + }, "reviewPermissions": { "message": "Genehmigungen prüfen" }, "revokePermission": { "message": "Genehmigung widerrufen" }, + "revokePermissionTitle": { + "message": "$1 Genehmigung entfernen", + "description": "The token symbol that is being revoked" + }, "revokeSimulationDetailsDesc": { "message": "Sie entziehen einer Person die Genehmigung, Tokens von Ihrem Konto auszugeben." }, @@ -4334,6 +4582,10 @@ "secretRecoveryPhrase": { "message": "Geheime Wiederherstellungsphrase" }, + "secretRecoveryPhrasePlusNumber": { + "message": "Geheime Wiederherstellungsphrase $1", + "description": "The $1 is the order of the Secret Recovery Phrase" + }, "secureWallet": { "message": "Sichere Wallet" }, @@ -4424,6 +4676,9 @@ "select": { "message": "AuswƤhlen" }, + "selectAccountToConnect": { + "message": "Ein zu verbindendes Konto auswƤhlen" + }, "selectAccounts": { "message": "WƤhlen Sie das Konto/die Konten aus, um sie auf dieser Seite zu verwenden." }, @@ -4454,6 +4709,9 @@ "selectRpcUrl": { "message": "RPC-URL auswƤhlen" }, + "selectSecretRecoveryPhrase": { + "message": "Geheime Wiederherstellungsphrase auswƤhlen" + }, "selectType": { "message": "Typ auswƤhlen" }, @@ -4565,16 +4823,6 @@ "showHexDataDescription": { "message": "WƤhlen Sie dies aus, um das Hex-Datenfeld auf dem Sendebildschirm anzuzeigen." }, - "showIncomingTransactions": { - "message": "Eingehende Transaktionen anzeigen" - }, - "showIncomingTransactionsDescription": { - "message": "Das hƤngt von $1 ab, das Zugriff auf Ihre Ethereum-Adresse und Ihre IP-Adresse hat. $2", - "description": "$1 is the link to etherscan url and $2 is the link to the privacy policy of consensys APIs" - }, - "showIncomingTransactionsExplainer": { - "message": "Dies hƤngt bei jedem Netzwerk von unterschiedlichen APIs Dritter ab, die Ihre Ethereum- und IP-Adresse offenlegen." - }, "showLess": { "message": "Weniger anzeigen" }, @@ -4593,6 +4841,9 @@ "showPrivateKey": { "message": "Privaten Schlüssel anzeigen" }, + "showSRP": { + "message": "Geheime Wiederherstellungsphrase anzeigen" + }, "showTestnetNetworks": { "message": "Test-Netzwerke anzeigen" }, @@ -4714,12 +4965,24 @@ "slideCashOutTitle": { "message": "Bargeldauszahlung mit MetaMask" }, + "slideDebitCardDescription": { + "message": "In ausgewƤhlten Regionen verfügbar" + }, "slideDebitCardTitle": { "message": "MetaMask-Debitkarte" }, + "slideFundWalletDescription": { + "message": "Token hinzufügen oder übertragen, um loszulegen" + }, "slideFundWalletTitle": { "message": "Überweisen Sie Guthaben auf Ihre Wallet" }, + "slideSweepStakeDescription": { + "message": "Erstellen Sie gleich ein NFT für eine Gewinnchance" + }, + "slideSweepStakeTitle": { + "message": "Nehmen Sie am $5000-USDC-Giveaway teil!" + }, "smartContracts": { "message": "Smart Contracts" }, @@ -4866,6 +5129,9 @@ "snapResultSuccessDescription": { "message": "$1 ist einsatzbereit" }, + "snapUIAssetSelectorTitle": { + "message": "Asset auswƤhlen" + }, "snapUpdateAlertDescription": { "message": "Holen Sie sich die neueste Version von $1\n", "description": "Description used in Snap update alert banner when snap update is available. $1 is the Snap name." @@ -4925,6 +5191,27 @@ "message": "Kontaktieren Sie die Ersteller von $1 für weitere Unterstützung.", "description": "This is shown when the insight snap throws an error. $1 is the snap name" }, + "solanaImportAccounts": { + "message": "Solana-Konten importieren" + }, + "solanaImportAccountsDescription": { + "message": "Importieren Sie eine geheime Wiederherstellungsphrase, um Ihr Solana-Konto von einer anderen Wallet zu migrieren." + }, + "solanaMoreFeaturesComingSoon": { + "message": "Mehr Funktionen in Kürze" + }, + "solanaMoreFeaturesComingSoonDescription": { + "message": "Solana-DApps, NFTs, Unterstützung für Hardware-Wallets und bald noch viel mehr." + }, + "solanaOnMetaMask": { + "message": "Solana auf MetaMask" + }, + "solanaSendReceiveSwapTokens": { + "message": "Token senden, empfangen und swappen" + }, + "solanaSendReceiveSwapTokensDescription": { + "message": "Übertragen Sie Token wie SOL, USDC usw. und tƤtigen Sie damit Transaktionen." + }, "someNetworks": { "message": "$1 Netzwerke" }, @@ -4951,6 +5238,21 @@ "source": { "message": "Quelle" }, + "spamModalBlockedDescription": { + "message": "Diese Seite wird für 1 Minute gesperrt." + }, + "spamModalBlockedTitle": { + "message": "Sie haben diese Seite vorübergehend gesperrt" + }, + "spamModalDescription": { + "message": "Wenn Sie mit mehrfachen Anfragen überschüttet werden, kƶnnen Sie die Website vorübergehend sperren." + }, + "spamModalTemporaryBlockButton": { + "message": "Diese Seite vorübergehend sperren" + }, + "spamModalTitle": { + "message": "Wir haben mehrere Anfragen verzeichnet" + }, "speed": { "message": "Geschwindigkeit" }, @@ -5000,10 +5302,28 @@ "spendingCap": { "message": "Ausgabenobergrenze" }, + "spendingCaps": { + "message": "Ausgabenobergrenzen" + }, "srpInputNumberOfWords": { "message": "Ich habe eine $1-Wort-Phrase.", "description": "This is the text for each option in the dropdown where a user selects how many words their secret recovery phrase has during import. The $1 is the number of words (either 12, 15, 18, 21, or 24)." }, + "srpListName": { + "message": "Geheime Wiederherstellungsphrase $1", + "description": "$1 is the order of the Secret Recovery Phrase" + }, + "srpListNumberOfAccounts": { + "message": "$1 Konten", + "description": "$1 is the number of accounts in the list" + }, + "srpListSelectionDescription": { + "message": "Die geheime Wiederherstellungsphrase, mit der Ihr neues Konto erstellt wird" + }, + "srpListSingleOrZero": { + "message": "$1 Konto", + "description": "$1 is the number of accounts in the list, it is either 1 or 0" + }, "srpPasteFailedTooManyWords": { "message": "Das Einfügen schlug fehl, weil sie mehr als 24 Wƶrter enthielt. Eine geheime Wiederherstellungsphrase darf maximal 24 Wƶrter enthalten.", "description": "Description of SRP paste error when the pasted content has too many words" @@ -5158,6 +5478,9 @@ "message": "Plƶtzliche MarktverƤnderungen kƶnnen zu AusfƤllen führen. Wenn das Problem weiterhin besteht, wenden Sie sich bitte an $1.", "description": "This message is shown to a user if their swap fails. The $1 will be replaced by support.metamask.io" }, + "stxOptInSupportedNetworksDescription": { + "message": "Schalten Sie Smart Transactions für zuverlƤssigere und sicherere Transaktionen in unterstützten Netzwerken ein. $1" + }, "stxPendingPrivatelySubmittingSwap": { "message": "Ihr Swap wird privat abgesendet ..." }, @@ -5977,6 +6300,12 @@ "message": "Senden von NFT-Tokens (ERC-721) wird derzeit nicht unterstützt.", "description": "This is an error message we show the user if they attempt to send an NFT asset type, for which currently don't support sending" }, + "unstableTokenPriceDescription": { + "message": "Der Preis dieses Tokens in USD ist Ƥußerst volatil, was auf ein hohes Risiko hindeutet, durch Interaktion mit dem Token einen erheblichen Wert zu verlieren." + }, + "unstableTokenPriceTitle": { + "message": "UnbestƤndiger Token-Preis" + }, "upArrow": { "message": "AufwƤrtspfeil" }, @@ -6099,6 +6428,18 @@ "visitSite": { "message": "Seite besuchen" }, + "visitSupportDataConsentModalAccept": { + "message": "BestƤtigen" + }, + "visitSupportDataConsentModalDescription": { + "message": "Mƶchten Sie Ihre MetaMask-Kennung und Ihre App-Version mit unserem Support Center teilen? Dies kann uns bei der Lƶsung Ihres Problems helfen, ist aber optional." + }, + "visitSupportDataConsentModalReject": { + "message": "Nicht teilen" + }, + "visitSupportDataConsentModalTitle": { + "message": "GerƤtedetails mit dem Support teilen" + }, "visitWebSite": { "message": "Besuchen Sie unsere Webseite." }, diff --git a/app/_locales/el/messages.json b/app/_locales/el/messages.json index 15745875e5cf..c546a5c73afa 100644 --- a/app/_locales/el/messages.json +++ b/app/_locales/el/messages.json @@ -44,6 +44,20 @@ "QRHardwareWalletSteps2Description": { "message": "Ngrave Zero" }, + "SrpListHideAccounts": { + "message": "Ī‘Ļ€ĻŒĪŗĻĻ…ĻˆĪ· $1 Ī»ĪæĪ³Ī±ĻĪ¹Ī±ĻƒĪ¼ĻŽĪ½", + "description": "$1 is the number of accounts" + }, + "SrpListHideSingleAccount": { + "message": "Ī‘Ļ€ĻŒĪŗĻĻ…ĻˆĪ· 1 Ī»ĪæĪ³Ī±ĻĪ¹Ī±ĻƒĪ¼ĪæĻ" + }, + "SrpListShowAccounts": { + "message": "Ī•Ī¼Ļ†Ī¬Ī½Ī¹ĻƒĪ· $1 Ī»ĪæĪ³Ī±ĻĪ¹Ī±ĻƒĪ¼ĻŽĪ½", + "description": "$1 is the number of accounts" + }, + "SrpListShowSingleAccount": { + "message": "Ī•Ī¼Ļ†Ī¬Ī½Ī¹ĻƒĪ· 1 Ī»ĪæĪ³Ī±ĻĪ¹Ī±ĻƒĪ¼ĪæĻ" + }, "about": { "message": "Σχετικά" }, @@ -76,6 +90,9 @@ "accountDetails": { "message": "Στοιχεία Ī»ĪæĪ³Ī±ĻĪ¹Ī±ĻƒĪ¼ĪæĻ" }, + "accountDetailsRevokeDelegationButton": { + "message": " Επαναφορά σε κανονικό λογαριασμό" + }, "accountIdenticon": { "message": "Ī‘Ī½Ī±Ī³Ī½Ļ‰ĻĪ¹ĻƒĻ„Ī¹ĪŗĻŒ Ī›ĪæĪ³Ī±ĻĪ¹Ī±ĻƒĪ¼ĪæĻ" }, @@ -153,6 +170,12 @@ "addAlias": { "message": "Προσθήκη ĻˆĪµĻ…Ī“Ļ‰Ī½ĻĪ¼ĪæĻ…" }, + "addBitcoinAccountLabel": { + "message": "Ī›ĪæĪ³Ī±ĻĪ¹Ī±ĻƒĪ¼ĻŒĻ‚ Bitcoin (Beta)" + }, + "addBitcoinTestnetAccountLabel": { + "message": "Ī›ĪæĪ³Ī±ĻĪ¹Ī±ĻƒĪ¼ĻŒĻ‚ Bitcoin (Testnet)" + }, "addBlockExplorer": { "message": "Προσθήκη ĪµĪ½ĻŒĻ‚ block explorer" }, @@ -193,6 +216,9 @@ "addFriendsAndAddresses": { "message": "Ī ĻĪæĻƒĪøĪ­ĻƒĻ„Īµ φίλους και Ī“Ī¹ĪµĻ…ĪøĻĪ½ĻƒĪµĪ¹Ļ‚ που ĪµĪ¼Ļ€Ī¹ĻƒĻ„ĪµĻĪµĻƒĻ„Īµ" }, + "addHardwareWalletLabel": { + "message": "Ī ĪæĻĻ„ĪæĻ†ĻŒĪ»Ī¹ Ļ…Ī»Ī¹ĪŗĪæĻ" + }, "addIPFSGateway": { "message": "Ī ĻĪæĻƒĪøĪ­ĻƒĻ„Īµ την Ļ€ĻĪ»Ī· IPFS που προτιμάτε" }, @@ -212,12 +238,26 @@ "addNewAccount": { "message": "Προσθήκη νέου Ī»ĪæĪ³Ī±ĻĪ¹Ī±ĻƒĪ¼ĪæĻ Ethereum" }, + "addNewEthereumAccountLabel": { + "message": "Ī›ĪæĪ³Ī±ĻĪ¹Ī±ĻƒĪ¼ĻŒĻ‚ Ethereum" + }, + "addNewSolanaAccountLabel": { + "message": "Ī›ĪæĪ³Ī±ĻĪ¹Ī±ĻƒĪ¼ĻŒĻ‚ Solana" + }, "addNft": { "message": "Προσθήκη του NFT" }, "addNfts": { "message": "Προσθήκη των NFT" }, + "addNonEvmAccount": { + "message": "Προσθήκη $1 Ī»ĪæĪ³Ī±ĻĪ¹Ī±ĻƒĪ¼ĪæĻ", + "description": "$1 is the non EVM network where the account is going to be created, e.g. Bitcoin or Solana" + }, + "addNonEvmAccountFromNetworkPicker": { + "message": "Για να ĪµĪ½ĪµĻĪ³ĪæĻ€ĪæĪ¹Ī®ĻƒĪµĻ„Īµ το Γίκτυο $1, πρέπει να Ī“Ī·Ī¼Ī¹ĪæĻ…ĻĪ³Ī®ĻƒĪµĻ„Īµ έναν λογαριασμό $2.", + "description": "$1 is the non EVM network where the account is going to be created, e.g. Solana Mainnet or Solana Devnet. $2 is the account type, e.g. Bitcoin or Solana" + }, "addRpcUrl": { "message": "Προσθήκη Ī“Ī¹ĪµĻĪøĻ…Ī½ĻƒĪ·Ļ‚ URL RPC" }, @@ -300,14 +340,16 @@ "advancedPriorityFeeToolTip": { "message": "Το τέλος Ļ€ĻĪæĻ„ĪµĻĪ±Ī¹ĻŒĻ„Ī·Ļ„Ī±Ļ‚ (Ī³Ī½Ļ‰ĻƒĻ„ĻŒ και ως ā€œminer tipā€) πηγαίνει άμεσα ĻƒĻ„ĪæĻ…Ļ‚ miner και τους ĪµĪ½ĪøĪ±ĻĻĻĪ½ĪµĪ¹ να Ī“ĻŽĻƒĪæĻ…Ī½ Ļ€ĻĪæĻ„ĪµĻĪ±Ī¹ĻŒĻ„Ī·Ļ„Ī± ĻƒĻ„Ī· ĻƒĻ…Ī½Ī±Ī»Ī»Ī±Ī³Ī® ĻƒĪ±Ļ‚." }, - "aggregatedBalancePopover": { - "message": "Ī‘Ļ…Ļ„ĻŒ αντικατοπτρίζει την αξία ĻŒĪ»Ļ‰Ī½ των tokens που έχετε ĻƒĻ„Ī·Ī½ κατοχή ĻƒĪ±Ļ‚ σε ένα ĻƒĻ…Ī³ĪŗĪµĪŗĻĪ¹Ī¼Ī­Ī½Īæ Γίκτυο. Εάν προτιμάτε να βλέπετε αυτή την αξία σε ETH Ī® άλλα Ī½ĪæĪ¼ĪÆĻƒĪ¼Ī±Ļ„Ī±, μεταβείτε ĻƒĻ„Ī¹Ļ‚ $1.", - "description": "$1 represents the settings page" - }, "agreeTermsOfUse": { "message": "Ī£Ļ…Ī¼Ļ†Ļ‰Ī½ĻŽ με το $1 του MetaMask", "description": "$1 is the `terms` link" }, + "airDropPatternDescription": { + "message": "Το Ī¹ĻƒĻ„ĪæĻĪ¹ĪŗĻŒ του token ĻƒĻ„Ī·Ī½ Ī±Ī»Ļ…ĻƒĪÆĪ“Ī± Ī±Ļ€ĪæĪŗĪ±Ī»ĻĻ€Ļ„ĪµĪ¹ Ļ€ĻĪæĪ·Ī³ĪæĻĪ¼ĪµĪ½ĪµĻ‚ ĻĻ€ĪæĻ€Ļ„ĪµĻ‚ τακτικές airdrop." + }, + "airDropPatternTitle": { + "message": "ĪœĪæĻ„ĪÆĪ²Īæ Airdrop" + }, "airgapVault": { "message": "Ī˜Ī·ĻƒĪ±Ļ…ĻĪæĻ†Ļ…Ī»Ī¬ĪŗĪ¹Īæ AirGap" }, @@ -726,9 +768,21 @@ "bridgeConfirmTwoTransactions": { "message": "Θα πρέπει να ĪµĻ€Ī¹Ī²ĪµĪ²Ī±Ī¹ĻŽĻƒĪµĻ„Īµ 2 ĻƒĻ…Ī½Ī±Ī»Ī»Ī±Ī³Ī­Ļ‚ ĻƒĻ„Īæ Ļ€ĪæĻĻ„ĪæĻ†ĻŒĪ»Ī¹ Ļ…Ī»Ī¹ĪŗĪæĻ ĻƒĪ±Ļ‚:" }, + "bridgeCreateSolanaAccount": { + "message": "Δημιουργία Ī»ĪæĪ³Ī±ĻĪ¹Ī±ĻƒĪ¼ĪæĻ ĻƒĻ„Īæ Solana" + }, + "bridgeCreateSolanaAccountDescription": { + "message": "Για να αλλάξετε ĻƒĻ„Īæ Γίκτυο Solana, Ļ‡ĻĪµĪ¹Ī¬Ī¶ĪµĻƒĻ„Īµ έναν λογαριασμό και μια Ī“Ī¹ĪµĻĪøĻ…Ī½ĻƒĪ· Ī»Ī®ĻˆĪ·Ļ‚." + }, + "bridgeCreateSolanaAccountTitle": { + "message": "Θα πρέπει Ļ€ĻĻŽĻ„Ī± να Ī“Ī·Ī¼Ī¹ĪæĻ…ĻĪ³Ī®ĻƒĪµĻ„Īµ έναν λογαριασμό ĻƒĻ„Īæ Solana." + }, "bridgeEnterAmount": { "message": "Ī Ī»Ī·ĪŗĻ„ĻĪæĪ»ĪæĪ³Ī®ĻƒĻ„Īµ το Ļ€ĪæĻƒĻŒ" }, + "bridgeEnterAmountAndSelectAccount": { + "message": "Ī•Ī¹ĻƒĪ±Ī³Ī¬Ī³ĪµĻ„Īµ το Ļ€ĪæĻƒĻŒ και επιλέξτε τον λογαριασμό Ļ€ĻĪæĪæĻĪ¹ĻƒĪ¼ĪæĻ" + }, "bridgeExplorerLinkViewOn": { "message": "Προβολή σε $1" }, @@ -751,9 +805,15 @@ "bridgeQuoteExpired": { "message": "Ī— Ļ€ĻĪæĻƒĻ†ĪæĻĪ¬ ĻƒĪ±Ļ‚ έληξε." }, + "bridgeSelectDestinationAccount": { + "message": "Επιλέξτε λογαριασμό Ļ€ĻĪæĪæĻĪ¹ĻƒĪ¼ĪæĻ" + }, "bridgeSelectNetwork": { "message": "Επιλέξτε Γίκτυο" }, + "bridgeSelectTokenAmountAndAccount": { + "message": "Επιλέξτε το token, το Ļ€ĪæĻƒĻŒ και τον λογαριασμό Ļ€ĻĪæĪæĻĪ¹ĻƒĪ¼ĪæĻ" + }, "bridgeSelectTokenAndAmount": { "message": "Επιλέξτε token και Ļ€ĪæĻƒĻŒ" }, @@ -944,6 +1004,12 @@ "message": "Δεν βρέθηκαν επιλογές", "description": "Default text shown in the combo field dropdown if no options." }, + "concentratedSupplyDistributionDescription": { + "message": "ĪšĪæĻĻ…Ļ†Ī±ĪÆĪæĪ¹ επενΓυτές ελέγχουν την Ļ€Ī»ĪµĪ¹ĪæĻˆĪ·Ļ†ĪÆĪ± των tokens, Ī³ĪµĪ³ĪæĪ½ĻŒĻ‚ που ενέχει τον κίνΓυνο κεντρικής Ļ‡ĪµĪ¹ĻĪ±Ī³ĻŽĪ³Ī·ĻƒĪ·Ļ‚ των Ļ„Ī¹Ī¼ĻŽĪ½" + }, + "concentratedSupplyDistributionTitle": { + "message": "Διανομή ĻƒĻ…Ī³ĪŗĪµĪ½Ļ„ĻĻ‰Ī¼Ī­Ī½Ī·Ļ‚ Ļ€ĻĪæĻƒĻ†ĪæĻĪ¬Ļ‚" + }, "configureSnapPopupDescription": { "message": "Ī¤ĻŽĻĪ± αποχωρείτε Ī±Ļ€ĻŒ το MetaMask για να ĻĻ…ĪøĪ¼ĪÆĻƒĪµĻ„Īµ Ī±Ļ…Ļ„ĻŒ το snap." }, @@ -962,6 +1028,15 @@ "confirm": { "message": "Ī•Ļ€Ī¹Ī²ĪµĪ²Ī±ĪÆĻ‰ĻƒĪ·" }, + "confirmAccountType": { + "message": "Ī¤ĻĻ€ĪæĻ‚" + }, + "confirmAccountTypeSmartContract": { + "message": "ĪˆĪ¾Ļ…Ļ€Ī½ĪæĻ‚ Ī»ĪæĪ³Ī±ĻĪ¹Ī±ĻƒĪ¼ĻŒĻ‚" + }, + "confirmAccountTypeStandard": { + "message": "Ī’Ī±ĻƒĪ¹ĪŗĻŒĻ‚ Ī»ĪæĪ³Ī±ĻĪ¹Ī±ĻƒĪ¼ĻŒĻ‚" + }, "confirmAlertModalAcknowledgeMultiple": { "message": "ĪˆĻ‡Ļ‰ ενημερωθεί για τις ĪµĪ¹Ī“ĪæĻ€ĪæĪ¹Ī®ĻƒĪµĪ¹Ļ‚ και ĪµĪ¾Ī±ĪŗĪæĪ»ĪæĻ…ĪøĻŽ να θέλω να ĻƒĻ…Ī½ĪµĻ‡ĪÆĻƒĻ‰" }, @@ -974,12 +1049,36 @@ "confirmFieldTooltipPaymaster": { "message": "Τα τέλη για αυτή τη ĻƒĻ…Ī½Ī±Ī»Ī»Ī±Ī³Ī® θα ĪŗĪ±Ļ„Ī±Ī²Ī»Ī·ĪøĪæĻĪ½ Ī±Ļ€ĻŒ τον Ļ…Ļ€ĪµĻĪøĻ…Ī½Īæ Ļ€Ī»Ī·ĻĻ‰Ī¼ĻŽĪ½ του έξυπνου ĻƒĻ…Ī¼Ī²ĪæĪ»Ī±ĪÆĪæĻ…." }, + "confirmGasFeeTokenBalance": { + "message": "΄π.:" + }, + "confirmGasFeeTokenInsufficientBalance": { + "message": "Ανεπαρκή κεφάλαια" + }, + "confirmGasFeeTokenMetaMaskFee": { + "message": "Περιλαμβάνει $1 τέλη" + }, + "confirmGasFeeTokenModalTitle": { + "message": "Επιλέξτε ένα token" + }, + "confirmGasFeeTokenToast": { + "message": "Θα Ļ€Ī»Ī·ĻĻŽĻƒĪµĻ„Īµ αυτά τα τέλη Ī“Ī¹ĪŗĻ„ĻĪæĻ… με $1" + }, + "confirmGasFeeTokenTooltip": { + "message": "Το Ļ€ĪæĻƒĻŒ Ī±Ļ…Ļ„ĻŒ καταβάλλεται ĻƒĻ„Īæ Γίκτυο για την ĪµĻ€ĪµĪ¾ĪµĻĪ³Ī±ĻƒĪÆĪ± της ĻƒĻ…Ī½Ī±Ī»Ī»Ī±Ī³Ī®Ļ‚ ĻƒĪ±Ļ‚. Περιλαμβάνει μια Ļ‡ĻĪ­Ļ‰ĻƒĪ· $1 ĻƒĻ„Īæ MetaMask για tokens ĪµĪŗĻ„ĻŒĻ‚ ETH." + }, + "confirmNestedTransactionTitle": { + "message": "Συναλλαγή $1" + }, "confirmPassword": { "message": "Ī•Ļ€Ī¹Ī²ĪµĪ²Ī±ĪÆĻ‰ĻƒĪ· ĪšĻ‰Ī“Ī¹ĪŗĪæĻ Ī ĻĻŒĻƒĪ²Ī±ĻƒĪ·Ļ‚" }, "confirmRecoveryPhrase": { "message": "Ī•Ļ€Ī¹Ī²ĪµĪ²Ī±Ī¹ĻŽĻƒĻ„Īµ τη ĪœĻ…ĻƒĻ„Ī¹ĪŗĪ® Φράση Ī‘Ī½Ī¬ĪŗĻ„Ī·ĻƒĪ·Ļ‚" }, + "confirmSimulationApprove": { + "message": "Εγκρίνετε" + }, "confirmTitleApproveTransactionNFT": { "message": "Αίτημα Ī±Ī½Ī¬Ī»Ī·ĻˆĪ·Ļ‚" }, @@ -1022,9 +1121,24 @@ "confirmTitleTransaction": { "message": "Αίτημα ĻƒĻ…Ī½Ī±Ī»Ī»Ī±Ī³Ī®Ļ‚" }, + "confirmUpgradeCancelModalButtonCancelTransaction": { + "message": "Ī‘ĪŗĻĻĻ‰ĻƒĪ· ĻƒĻ…Ī½Ī±Ī»Ī»Ī±Ī³Ī®Ļ‚" + }, + "confirmUpgradeCancelModalButtonCancelUpgrade": { + "message": "Ī‘ĪŗĻĻĻ‰ĻƒĪ· Ī±Ī½Ī±Ī²Ī¬ĪøĪ¼Ī¹ĻƒĪ·Ļ‚ & ĻƒĻ…Ī½Ī±Ī»Ī»Ī±Ī³Ī®Ļ‚" + }, + "confirmUpgradeCancelModalDescription": { + "message": "Αν Γεν θέλετε να Ī±Ī½Ī±Ī²Ī±ĪøĪ¼ĪÆĻƒĪµĻ„Īµ τον λογαριασμό ĻƒĪ±Ļ‚, μπορείτε να το Ī±ĪŗĻ…ĻĻŽĻƒĪµĻ„Īµ ĪµĪ“ĻŽ.\n\nΓια να ĪæĪ»ĪæĪŗĪ»Ī·ĻĻŽĻƒĪµĻ„Īµ αυτή τη ĻƒĻ…Ī½Ī±Ī»Ī»Ī±Ī³Ī® χωρίς αναβάθμιση, θα πρέπει να υποβάλετε ξανά Ī±Ļ…Ļ„ĻŒ το αίτημα ĻƒĻ„ĪæĪ½ Ī¹ĻƒĻ„ĻŒĻ„ĪæĻ€Īæ. $1." + }, + "confirmUpgradeCancelModalTitle": { + "message": "Ī‘ĪŗĻĻĻ‰ĻƒĪ· ĻƒĻ…Ī½Ī±Ī»Ī»Ī±Ī³Ī®Ļ‚" + }, "confirmationAlertDetails": { "message": "Για να Ļ€ĻĪæĻƒĻ„Ī±Ļ„ĪµĻĻƒĪµĻ„Īµ τα Ļ€ĪµĻĪ¹ĪæĻ…ĻƒĪ¹Ī±ĪŗĪ¬ ĻƒĪ±Ļ‚ ĻƒĻ„ĪæĪ¹Ļ‡ĪµĪÆĪ±, ĻƒĪ±Ļ‚ προτείνουμε να Ī±Ļ€ĪæĻĻĪÆĻˆĪµĻ„Īµ το αίτημα." }, + "confirmationAlertModalTitleDescription": { + "message": "Τα Ļ€ĪµĻĪ¹ĪæĻ…ĻƒĪ¹Ī±ĪŗĪ¬ ĻƒĪ±Ļ‚ ĻƒĻ„ĪæĪ¹Ļ‡ĪµĪÆĪ± μπορεί να ĪŗĪ¹Ī½Ī“Ļ…Ī½ĪµĻĪæĻ…Ī½" + }, "confirmed": { "message": "Επιβεβαιωμένο" }, @@ -1052,6 +1166,9 @@ "connectAccounts": { "message": "Ī£ĻĪ½Ī“ĪµĻƒĪ· Ī»ĪæĪ³Ī±ĻĪ¹Ī±ĻƒĪ¼ĻŽĪ½" }, + "connectAnAccountHeader": { + "message": "Ī£ĻĪ½Ī“ĪµĻƒĪ· Ī»ĪæĪ³Ī±ĻĪ¹Ī±ĻƒĪ¼ĪæĻ" + }, "connectManually": { "message": "Χειροκίνητη ĻƒĻĪ½Ī“ĪµĻƒĪ· ĻƒĻ„ĪæĪ½ τρέχοντα Ī¹ĻƒĻ„ĻŒĻ„ĪæĻ€Īæ" }, @@ -1158,6 +1275,9 @@ "message": "Ī— λήψη του $1 απέτυχε, ελέγξτε το Ī“ĪÆĪŗĻ„Ļ…ĻŒ ĻƒĪ±Ļ‚ και Ļ€ĻĪæĻƒĻ€Ī±ĪøĪ®ĻƒĻ„Īµ ξανά.", "description": "$1 is the name of the snap being fetched." }, + "connectionPopoverDescription": { + "message": "Για να ĻƒĻ…Ī½Ī“ĪµĪøĪµĪÆĻ„Īµ σε έναν Ī¹ĻƒĻ„ĻŒĻ„ĪæĻ€Īæ, επιλέξτε το κουμπί ĻƒĻĪ½Ī“ĪµĻƒĪ·Ļ‚. Το MetaMask μπορεί να ĻƒĻ…Ī½Ī“ĪµĪøĪµĪÆ μόνο με Ī¹ĻƒĻ„ĻŒĻ„ĪæĻ€ĪæĻ…Ļ‚ web3." + }, "connectionRequest": { "message": "Αίτημα ĻƒĻĪ½Ī“ĪµĻƒĪ·Ļ‚" }, @@ -1219,6 +1339,9 @@ "create": { "message": "Δημιουργία" }, + "createNewAccountHeader": { + "message": "Δημιουργία νέου Ī»ĪæĪ³Ī±ĻĪ¹Ī±ĻƒĪ¼ĪæĻ" + }, "createNewWallet": { "message": "Δημιουργία νέου Ļ€ĪæĻĻ„ĪæĻ†ĪæĪ»Ī¹ĪæĻ" }, @@ -1231,6 +1354,9 @@ "createSnapAccountTitle": { "message": "Δημιουργία Ī»ĪæĪ³Ī±ĻĪ¹Ī±ĻƒĪ¼ĪæĻ" }, + "createSolanaAccount": { + "message": "Δημιουργία Ī»ĪæĪ³Ī±ĻĪ¹Ī±ĻƒĪ¼ĪæĻ ĻƒĻ„Īæ Solana" + }, "creatorAddress": { "message": "Ī”Ī¹ĪµĻĪøĻ…Ī½ĻƒĪ· Ī“Ī·Ī¼Ī¹ĪæĻ…ĻĪ³ĪæĻ" }, @@ -1471,6 +1597,21 @@ "message": "Περιγραφή Ī±Ļ€ĻŒ $1", "description": "$1 represents the name of the snap" }, + "destinationAccountPickerNoEligible": { + "message": "Δεν βρέθηκαν επιλέξιμοι λογαριασμοί" + }, + "destinationAccountPickerNoMatching": { + "message": "Δεν βρέθηκαν λογαριασμοί που να ταιριάζουν" + }, + "destinationAccountPickerReceiveAt": { + "message": "Ī›Ī®ĻˆĪ· σε" + }, + "destinationAccountPickerSearchPlaceholderToMainnet": { + "message": "Ī”Ī¹ĪµĻĪøĻ…Ī½ĻƒĪ· Ī»Ī®ĻˆĪ·Ļ‚ Ī® ENS" + }, + "destinationAccountPickerSearchPlaceholderToSolana": { + "message": "Ī”Ī¹ĪµĻĪøĻ…Ī½ĻƒĪ· Ī»Ī®ĻˆĪ·Ļ‚" + }, "details": { "message": "Λεπτομέρειες" }, @@ -1516,6 +1657,9 @@ "message": "Το $1 Ī±Ļ€ĪæĻƒĻ…Ī½Ī“Ī­ĪøĪ·ĪŗĪµ Ī±Ļ€ĻŒ το $2", "description": "$1 is name of the name and $2 represents the dapp name`" }, + "discover": { + "message": "Ī‘Ī½Ī±ĪŗĪ±Ī»ĻĻˆĻ„Īµ" + }, "discoverSnaps": { "message": "Ī‘Ī½Ī±ĪŗĪ±Ī»ĻĻˆĻ„Īµ τα Snaps", "description": "Text that links to the Snaps website. Displayed in a banner on Snaps list page in settings." @@ -1872,6 +2016,9 @@ "experimental": { "message": "Πειραματικά" }, + "exploreweb3": { + "message": "Ī•Ī¾ĪµĻĪµĻ…Ī½Ī®ĻƒĻ„Īµ το web3" + }, "exportYourData": { "message": "Εξαγωγή των ΓεΓομένων ĻƒĪ±Ļ‚" }, @@ -1885,6 +2032,9 @@ "message": "Ī ĻĪæĻƒĪ±ĻĪ¼ĻŒĻƒĻ„Īµ την εμπειρία του Ļ€ĪæĻĻ„ĪæĻ†ĪæĪ»Ī¹ĪæĻ ĻƒĪ±Ļ‚.", "description": "Banner description displayed on Snaps list page in Settings when less than 6 Snaps is installed." }, + "externalAccount": { + "message": "Ī•Ī¾Ļ‰Ļ„ĪµĻĪ¹ĪŗĻŒĻ‚ Ī»ĪæĪ³Ī±ĻĪ¹Ī±ĻƒĪ¼ĻŒĻ‚" + }, "externalExtension": { "message": "Εξωτερική ĪµĻ€Ī­ĪŗĻ„Ī±ĻƒĪ·" }, @@ -2197,6 +2347,12 @@ "holdToRevealUnlockedLabel": { "message": "ĪŗĻĪ±Ļ„Ī®ĻƒĻ„Īµ πατημένο για να μην Ī±Ļ€ĪæĪŗĪ±Ī»ĻĻˆĪµĻ„Īµ το κυκλάκι με κλειΓί" }, + "honeypotDescription": { + "message": "Ī‘Ļ…Ļ„ĻŒ το token μπορεί να αποτελεί κίνΓυνο για honeypot. Ī£Ļ…Ī½Ī¹ĻƒĻ„Ī¬Ļ„Ī±Ī¹ να Γιεξάγετε τη Ī“Ī­ĪæĻ…ĻƒĪ± έρευνα πριν Ī±Ļ€ĻŒ την Ī±Ī»Ī»Ī·Ī»ĪµĻ€ĪÆĪ“ĻĪ±ĻƒĪ· για να Ī±Ļ€ĪæĻ†ĻĪ³ĪµĻ„Īµ Ļ„Ļ…Ļ‡ĻŒĪ½ οικονομικές Ī±Ļ€ĻŽĪ»ĪµĪ¹ĪµĻ‚." + }, + "honeypotTitle": { + "message": "Honey Pot" + }, "howNetworkFeesWorkExplanation": { "message": "Ī•ĪŗĻ„Ī¹Ī¼ĻŽĪ¼ĪµĪ½Ī± τέλη που Ī±Ļ€Ī±Ī¹Ļ„ĪæĻĪ½Ļ„Ī±Ī¹ για τη Ī“Ī¹ĪµĪŗĻ€ĪµĻĪ±ĪÆĻ‰ĻƒĪ· της ĻƒĻ…Ī½Ī±Ī»Ī»Ī±Ī³Ī®Ļ‚. Ī— Ī¼Ī­Ī³Ī¹ĻƒĻ„Ī· Ļ‡ĻĪ­Ļ‰ĻƒĪ· είναι $1." }, @@ -2262,6 +2418,30 @@ "importNFTTokenIdToolTip": { "message": "Το Ī±Ī½Ī±Ī³Ī½Ļ‰ĻĪ¹ĻƒĻ„Ī¹ĪŗĻŒ ĪµĪ½ĻŒĻ‚ NFT είναι μοναΓικό ΓεΓομένου ĻŒĻ„Ī¹ Γεν υπάρχουν Ī“ĻĪæ ίΓια NFT. Και πάλι, ĻƒĻ„Īæ OpenSea Ī±Ļ…Ļ„ĻŒĻ‚ Īæ Ī±ĻĪ¹ĪøĪ¼ĻŒĻ‚ Ī²ĻĪÆĻƒĪŗĪµĻ„Ī±Ī¹ ĻƒĻ„Ī·Ī½ ĪµĪ½ĻŒĻ„Ī·Ļ„Ī± \"Λεπτομέρειες\". Ī£Ī·Ī¼ĪµĪ¹ĻŽĻƒĻ„Īµ τον Ī® Ī±Ī½Ļ„Ī¹Ī³ĻĪ¬ĻˆĻ„Īµ τον ĻƒĻ„Īæ Ļ€ĻĻŒĻ‡ĪµĪ¹ĻĪæ ĻƒĪ±Ļ‚." }, + "importNWordSRP": { + "message": "ĪˆĻ‡Ļ‰ μια Ļ†ĻĪ¬ĻƒĪ· Ī±Ī½Ī¬ĪŗĻ„Ī·ĻƒĪ·Ļ‚ $1 λέξεων", + "description": "$1 is the number of words in the recovery phrase" + }, + "importPrivateKey": { + "message": "Ī™Ī“Ī¹Ļ‰Ļ„Ī¹ĪŗĻŒ κλειΓί" + }, + "importSRPDescription": { + "message": "Ī•Ī¹ĻƒĪ¬Ī³ĪµĻ„Īµ ένα υπάρχον Ļ€ĪæĻĻ„ĪæĻ†ĻŒĪ»Ī¹ με τη Ī¼Ļ…ĻƒĻ„Ī¹ĪŗĪ® Ļ†ĻĪ¬ĻƒĪ· Ī±Ī½Ī¬ĪŗĻ„Ī·ĻƒĪ·Ļ‚ 12 Ī® 24 λέξεων." + }, + "importSRPNumberOfWordsError": { + "message": "Οι ĪœĻ…ĻƒĻ„Ī¹ĪŗĪ­Ļ‚ Ī¦ĻĪ¬ĻƒĪµĪ¹Ļ‚ Ī‘Ī½Ī¬ĪŗĻ„Ī·ĻƒĪ·Ļ‚ περιλαμβάνουν 12 Ī® 24 λέξεις" + }, + "importSRPWordError": { + "message": "Ī— λέξη $1 είναι λανθασμένη Ī® Ī±Ī½ĪæĻĪøĻŒĪ³ĻĪ±Ļ†Ī·.", + "description": "$1 is the word that is incorrect or misspelled" + }, + "importSRPWordErrorAlternative": { + "message": "Οι λέξεις $1 και $2 είναι Ī»Ī±Ī½ĪøĪ±ĻƒĪ¼Ī­Ī½ĪµĻ‚ Ī® Ī±Ī½ĪæĻĪøĻŒĪ³ĻĪ±Ļ†ĪµĻ‚.", + "description": "$1 and $2 are multiple words that are mispelled." + }, + "importSecretRecoveryPhrase": { + "message": "Ī•Ī¹ĻƒĪ±Ī³Ļ‰Ī³Ī® της ĪœĻ…ĻƒĻ„Ī¹ĪŗĪ®Ļ‚ Ī¦ĻĪ¬ĻƒĪ·Ļ‚ Ī‘Ī½Ī¬ĪŗĻ„Ī·ĻƒĪ·Ļ‚" + }, "importSelectedTokens": { "message": "Ī•Ī¹ĻƒĪ±Ī³Ļ‰Ī³Ī® επιλεγμένων tokens;" }, @@ -2280,6 +2460,12 @@ "importTokensError": { "message": "Δεν Ī¼Ļ€ĪæĻĪ­ĻƒĪ±Ī¼Īµ να ĪµĪ¹ĻƒĪ¬Ī³ĪæĻ…Ī¼Īµ τα tokens. Ī ĻĪæĻƒĻ€Ī±ĪøĪ®ĻƒĻ„Īµ ξανά Ī±ĻĪ³ĻŒĻ„ĪµĻĪ±." }, + "importWallet": { + "message": "Ī•Ī¹ĻƒĪ±Ī³Ļ‰Ī³Ī® Ļ€ĪæĻĻ„ĪæĻ†ĪæĪ»Ī¹ĪæĻ" + }, + "importWalletOrAccountHeader": { + "message": "Ī•Ī¹ĻƒĪ±Ī³Ļ‰Ī³Ī® Ļ€ĪæĻĻ„ĪæĻ†ĪæĪ»Ī¹ĪæĻ Ī® Ī»ĪæĪ³Ī±ĻĪ¹Ī±ĻƒĪ¼ĪæĻ" + }, "importWithCount": { "message": "Ī•Ī¹ĻƒĪ±Ī³Ļ‰Ī³Ī® $1", "description": "$1 will the number of detected tokens that are selected for importing, if all of them are selected then $1 will be all" @@ -2327,6 +2513,12 @@ "insufficientFundsForGas": { "message": "Ανεπαρκή κεφάλαια για το τέλος ĻƒĻ…Ī½Ī±Ī»Ī»Ī±Ī³Ī®Ļ‚" }, + "insufficientLockedLiquidityDescription": { + "message": "Ī— έλλειψη ĪµĻ€Ī±ĻĪŗĻŽĻ‚ κατοχυρωμένης Ī® ĪµĪ»ĪµĪ³Ļ‡ĻŒĪ¼ĪµĪ½Ī·Ļ‚ ĻĪµĻ…ĻƒĻ„ĻŒĻ„Ī·Ļ„Ī±Ļ‚ ĪŗĪ±ĪøĪ¹ĻƒĻ„Ī¬ τα tokens ευάλωτα σε ξαφνικές Ī±Ī½Ī±Ī»Ī®ĻˆĪµĪ¹Ļ‚, Ļ€ĻĪæĪŗĪ±Ī»ĻŽĪ½Ļ„Ī±Ļ‚ ενΓεχομένως Ī±ĻƒĻ„Ī¬ĪøĪµĪ¹Ī± ĻƒĻ„Ī·Ī½ αγορά." + }, + "insufficientLockedLiquidityTitle": { + "message": "Ανεπαρκής κατοχυρωμένη ĻĪµĻ…ĻƒĻ„ĻŒĻ„Ī·Ļ„Ī±" + }, "insufficientTokens": { "message": "Ανεπαρκή tokens." }, @@ -2362,6 +2554,9 @@ "invalidCustomNetworkAlertTitle": { "message": "Μη έγκυρο Ļ€ĻĪæĻƒĪ±ĻĪ¼ĪæĻƒĪ¼Ī­Ī½Īæ Γίκτυο" }, + "invalidHexData": { + "message": "Μη έγκυρα ΓεκαεξαΓικά ΓεΓομένα" + }, "invalidHexNumber": { "message": "Μη έγκυρος Ī“ĪµĪŗĪ±ĪµĪ¾Ī±Ī“Ī¹ĪŗĻŒĻ‚ Ī±ĻĪ¹ĪøĪ¼ĻŒĻ‚." }, @@ -2540,6 +2735,9 @@ "ledgerLocked": { "message": "Δεν είναι Γυνατή Ī· ĻƒĻĪ½Ī“ĪµĻƒĪ· με τη ĻƒĻ…ĻƒĪŗĪµĻ…Ī® Ledger. Βεβαιωθείτε ĻŒĻ„Ī¹ Ī· ĻƒĻ…ĻƒĪŗĪµĻ…Ī® ĻƒĪ±Ļ‚ είναι ξεκλειΓωμένη και ĻŒĻ„Ī¹ Ī· εφαρμογή Ethereum είναι ανοιχτή." }, + "ledgerMultipleDevicesUnsupportedErrorMessage": { + "message": "Δεν είναι Γυνατή Ī· Ļ„Ī±Ļ…Ļ„ĻŒĻ‡ĻĪæĪ½Ī· ĻƒĻĪ½Ī“ĪµĻƒĪ· Ļ€ĪæĪ»Ī»Ī±Ļ€Ī»ĻŽĪ½ ĻƒĻ…ĻƒĪŗĪµĻ…ĻŽĪ½ Ledger. Για να ĻƒĻ…Ī½Ī“Ī­ĻƒĪµĻ„Īµ μια νέα ĻƒĻ…ĻƒĪŗĪµĻ…Ī® Ledger, θα πρέπει Ļ€ĻĻŽĻ„Ī± να Ī±Ļ€ĪæĻƒĻ…Ī½Ī“Ī­ĻƒĪµĻ„Īµ την Ļ€ĻĪæĪ·Ī³ĪæĻĪ¼ĪµĪ½Ī·." + }, "ledgerTimeout": { "message": "Το Ledger Live χρειάζεται Ļ€ĪæĪ»Ļ Ļ‡ĻĻŒĪ½Īæ για να ανταποκριθεί Ī® Ī· ĻƒĻĪ½Ī“ĪµĻƒĪ· έχει Γιακοπεί. Βεβαιωθείτε ĻŒĻ„Ī¹ Ī· εφαρμογή Ledger Live είναι ανοιχτή και ĻŒĻ„Ī¹ Ī· ĻƒĻ…ĻƒĪŗĪµĻ…Ī® ĻƒĪ±Ļ‚ είναι ξεκλειΓωμένη." }, @@ -2637,6 +2835,9 @@ "manageDefaultSettings": { "message": "Ī”Ī¹Ī±Ļ‡ĪµĪÆĻĪ¹ĻƒĪ· προεπιλεγμένων ĻĻ…ĪøĪ¼ĪÆĻƒĪµĻ‰Ī½ απορρήτου" }, + "managePermissions": { + "message": "Ī”Ī¹Ī±Ļ‡ĪµĪÆĻĪ¹ĻƒĪ· Ī±Ī“ĪµĪ¹ĻŽĪ½" + }, "marketCap": { "message": "ĪšĪµĻ†Ī±Ī»Ī±Ī¹ĪæĻ€ĪæĪÆĪ·ĻƒĪ· αγοράς" }, @@ -2755,6 +2956,15 @@ "multichainAddEthereumChainConfirmationDescription": { "message": "Ī ĻĪæĻƒĪøĪ­Ļ„ĪµĻ„Īµ Ī±Ļ…Ļ„ĻŒ το Γίκτυο ĻƒĻ„Īæ MetaMask και Γίνετε σε Ī±Ļ…Ļ„ĻŒĪ½ τον Ī¹ĻƒĻ„ĻŒĻ„ĪæĻ€Īæ την άΓεια να το Ļ‡ĻĪ·ĻƒĪ¹Ī¼ĪæĻ€ĪæĪ¹ĪµĪÆ." }, + "multichainQuoteCardBridgingLabel": { + "message": "Ī”Ī¹Ī±ĻƒĻĪ½Ī“ĪµĻƒĪ·" + }, + "multichainQuoteCardQuoteLabel": { + "message": "Ī ĻĪæĻƒĻ†ĪæĻĪ¬" + }, + "multichainQuoteCardTimeLabel": { + "message": "ĪĻĪ±" + }, "multipleSnapConnectionWarning": { "message": "Το $1 θέλει να Ļ‡ĻĪ·ĻƒĪ¹Ī¼ĪæĻ€ĪæĪ¹Ī®ĻƒĪµĪ¹ $2 Snaps", "description": "$1 is the dapp and $2 is the number of snaps it wants to connect to." @@ -2869,6 +3079,13 @@ "network": { "message": "Δίκτυο:" }, + "networkChanged": { + "message": "Το Γίκτυο άλλαξε" + }, + "networkChangedMessage": { + "message": "Ī¤ĻŽĻĪ± κάνετε ĻƒĻ…Ī½Ī±Ī»Ī»Ī±Ī³Ī­Ļ‚ ĻƒĻ„Īæ $1.", + "description": "$1 is the name of the network" + }, "networkDetails": { "message": "Λεπτομέρειες Ī”Ī¹ĪŗĻ„ĻĪæĻ…" }, @@ -3143,6 +3360,9 @@ "notEnoughGas": { "message": "Δεν υπάρχει Ī±ĻĪŗĪµĻ„ĻŒ τέλος ĻƒĻ…Ī½Ī±Ī»Ī»Ī±Ī³Ī®Ļ‚" }, + "notNow": { + "message": "ĪŒĻ‡Ī¹ Ļ„ĻŽĻĪ±" + }, "notificationDetail": { "message": "Λεπτομέρειες" }, @@ -3505,6 +3725,13 @@ "origin": { "message": "Ī ĻĪæĪ­Ī»ĪµĻ…ĻƒĪ·" }, + "originChanged": { + "message": "Ο Ī¹ĻƒĻ„ĻŒĻ„ĪæĻ€ĪæĻ‚ άλλαξε" + }, + "originChangedMessage": { + "message": "Εξετάζετε Ļ„ĻŽĻĪ± ένα αίτημα Ī±Ļ€ĻŒ $1.", + "description": "$1 is the name of the origin" + }, "osTheme": { "message": "Ī£ĻĻƒĻ„Ī·Ī¼Ī±" }, @@ -3559,6 +3786,14 @@ "pending": { "message": "Σε ĪµĪŗĪŗĻĪµĪ¼ĻŒĻ„Ī·Ļ„Ī±" }, + "pendingConfirmationAddNetworkAlertMessage": { + "message": "Ī— ĪµĪ½Ī·Ī¼Ī­ĻĻ‰ĻƒĪ· του Ī“Ī¹ĪŗĻ„ĻĪæĻ… θα Ī±ĪŗĻ…ĻĻŽĻƒĪµĪ¹ $1 εκκρεμείς ĻƒĻ…Ī½Ī±Ī»Ī»Ī±Ī³Ī­Ļ‚ Ī±Ļ€ĻŒ Ī±Ļ…Ļ„ĻŒĪ½ τον Ī¹ĻƒĻ„ĻŒĻ„ĪæĻ€Īæ.", + "description": "Number of transactions." + }, + "pendingConfirmationSwitchNetworkAlertMessage": { + "message": "Ī— αλλαγή Ī“Ī¹ĪŗĻ„ĻĪæĻ… θα Ī±ĪŗĻ…ĻĻŽĻƒĪµĪ¹ $1 εκκρεμείς ĻƒĻ…Ī½Ī±Ī»Ī»Ī±Ī³Ī­Ļ‚ Ī±Ļ€ĻŒ Ī±Ļ…Ļ„ĻŒĪ½ τον Ī¹ĻƒĻ„ĻŒĻ„ĪæĻ€Īæ.", + "description": "Number of transactions." + }, "pendingTransactionAlertMessage": { "message": "Αυτή Ī· ĻƒĻ…Ī½Ī±Ī»Ī»Ī±Ī³Ī® Γεν θα πραγματοποιηθεί μέχρι να ολοκληρωθεί μια Ļ€ĻĪæĪ·Ī³ĪæĻĪ¼ĪµĪ½Ī· ĻƒĻ…Ī½Ī±Ī»Ī»Ī±Ī³Ī®. $1", "description": "$1 represents the words 'how to cancel or speed up a transaction' in a hyperlink" @@ -3842,6 +4077,9 @@ "permitSimulationChange_receive": { "message": "Θα λάβετε" }, + "permitSimulationChange_revoke2": { + "message": "Ī‘Ī½Ī±ĪÆĻĪµĻƒĪ·" + }, "permitSimulationChange_transfer": { "message": "Θα ĻƒĻ„ĪµĪÆĪ»ĪµĻ„Īµ" }, @@ -4237,6 +4475,9 @@ "reusedTokenNameWarning": { "message": "Ένα token ĪµĪ“ĻŽ ĪµĻ€Ī±Ī½Ī±Ļ‡ĻĪ·ĻƒĪ¹Ī¼ĪæĻ€ĪæĪ¹ĪµĪÆ ένα ĻƒĻĪ¼Ī²ĪæĪ»Īæ Ī±Ļ€ĻŒ ένα άλλο token που παρακολουθείτε, Ī±Ļ…Ļ„ĻŒ μπορεί να Ļ€ĻĪæĪŗĪ±Ī»Ī­ĻƒĪµĪ¹ ĻƒĻĪ³Ļ‡Ļ…ĻƒĪ· Ī® να είναι Ļ€Ī±ĻĪ±Ļ€Ī»Ī±Ī½Ī·Ļ„Ī¹ĪŗĻŒ." }, + "revealSecretRecoveryPhrase": { + "message": "Ī‘Ļ€ĪæĪŗĪ¬Ī»Ļ…ĻˆĪ· της ĪœĻ…ĻƒĻ„Ī¹ĪŗĪ®Ļ‚ Ī¦ĻĪ¬ĻƒĪ·Ļ‚ Ī‘Ī½Ī¬ĪŗĻ„Ī·ĻƒĪ·Ļ‚" + }, "revealSeedWords": { "message": "Ī‘Ļ€ĪæĪŗĪ¬Ī»Ļ…ĻˆĪ· της ĪœĻ…ĻƒĻ„Ī¹ĪŗĪ®Ļ‚ Ī¦ĻĪ¬ĻƒĪ·Ļ‚ Ī‘Ī½Ī¬ĪŗĻ„Ī·ĻƒĪ·Ļ‚" }, @@ -4286,12 +4527,19 @@ "reviewAlerts": { "message": "ĪˆĪ»ĪµĪ³Ļ‡ĪæĻ‚ ĪµĪ¹Ī“ĪæĻ€ĪæĪ¹Ī®ĻƒĪµĻ‰Ī½" }, + "reviewPendingTransactions": { + "message": "ĪˆĪ»ĪµĪ³Ļ‡ĪæĻ‚ ĪµĪŗĪŗĻĪµĪ¼ĻŽĪ½ ĻƒĻ…Ī½Ī±Ī»Ī»Ī±Ī³ĻŽĪ½" + }, "reviewPermissions": { "message": "ĪˆĪ»ĪµĪ³Ļ‡ĪæĻ‚ Ī±Ī“ĪµĪ¹ĻŽĪ½" }, "revokePermission": { "message": "Ī‘Ī½Ī¬ĪŗĪ»Ī·ĻƒĪ· άΓειας" }, + "revokePermissionTitle": { + "message": "ĪšĪ±Ļ„Ī¬ĻĪ³Ī·ĻƒĪ· $1 άΓειας", + "description": "The token symbol that is being revoked" + }, "revokeSimulationDetailsDesc": { "message": "Αφαιρείτε την άΓεια κάποιου να Ī¾ĪæĪ“ĪµĻĪµĪ¹ tokens Ī±Ļ€ĻŒ τον λογαριασμό ĻƒĪ±Ļ‚." }, @@ -4334,6 +4582,10 @@ "secretRecoveryPhrase": { "message": "ĪœĻ…ĻƒĻ„Ī¹ĪŗĪ® Φράση Ī‘Ī½Ī¬ĪŗĻ„Ī·ĻƒĪ·Ļ‚" }, + "secretRecoveryPhrasePlusNumber": { + "message": "ĪœĻ…ĻƒĻ„Ī¹ĪŗĪ® Φράση Ī‘Ī½Ī¬ĪŗĻ„Ī·ĻƒĪ·Ļ‚ $1", + "description": "The $1 is the order of the Secret Recovery Phrase" + }, "secureWallet": { "message": "Ī‘ĻƒĻ†Ī±Ī»Ī­Ļ‚ Ļ€ĪæĻĻ„ĪæĻ†ĻŒĪ»Ī¹" }, @@ -4424,6 +4676,9 @@ "select": { "message": "Επιλέξτε" }, + "selectAccountToConnect": { + "message": "Επιλέξτε έναν λογαριασμό για ĻƒĻĪ½Ī“ĪµĻƒĪ·" + }, "selectAccounts": { "message": "Επιλέξτε τον λογαριασμό (-ĪæĻĻ‚) που θέλετε να Ļ‡ĻĪ·ĻƒĪ¹Ī¼ĪæĻ€ĪæĪ¹Ī®ĻƒĪµĻ„Īµ σε Ī±Ļ…Ļ„ĻŒĪ½ τον Ī¹ĻƒĻ„ĻŒĻ„ĪæĻ€Īæ" }, @@ -4454,6 +4709,9 @@ "selectRpcUrl": { "message": "Επιλέξτε την Ī“Ī¹ĪµĻĪøĻ…Ī½ĻƒĪ· URL του RPC" }, + "selectSecretRecoveryPhrase": { + "message": "Επιλέξτε τη ĪœĻ…ĻƒĻ„Ī¹ĪŗĪ® Φράση Ī‘Ī½Ī¬ĪŗĻ„Ī·ĻƒĪ·Ļ‚" + }, "selectType": { "message": "Επιλέξτε Ī¤ĻĻ€Īæ" }, @@ -4565,16 +4823,6 @@ "showHexDataDescription": { "message": "Επιλέξτε το για να ĪµĪ¼Ļ†Ī±Ī½Ī¹ĻƒĻ„ĪµĪÆ το πεΓίο Ī“ĪµĪŗĪ±ĪµĪ¾Ī±Ī“Ī¹ĪŗĻŽĪ½ ΓεΓομένων ĻƒĻ„Ī·Ī½ οθόνη Ī±Ļ€ĪæĻƒĻ„ĪæĪ»Ī®Ļ‚" }, - "showIncomingTransactions": { - "message": "Ī•Ī¼Ļ†Ī¬Ī½Ī¹ĻƒĪ· ĪµĪ¹ĻƒĪµĻĻ‡ĻŒĪ¼ĪµĪ½Ļ‰Ī½ ĻƒĻ…Ī½Ī±Ī»Ī»Ī±Ī³ĻŽĪ½" - }, - "showIncomingTransactionsDescription": { - "message": "Ī‘Ļ…Ļ„ĻŒ Ī²Ī±ĻƒĪÆĪ¶ĪµĻ„Ī±Ī¹ ĻƒĻ„Īæ $1, το οποίο θα έχει Ļ€ĻĻŒĻƒĪ²Ī±ĻƒĪ· ĻƒĻ„Ī· Ī“Ī¹ĪµĻĪøĻ…Ī½ĻƒĪ· Ethereum και τη Ī“Ī¹ĪµĻĪøĻ…Ī½ĻƒĪ· IP ĻƒĪ±Ļ‚. $2", - "description": "$1 is the link to etherscan url and $2 is the link to the privacy policy of consensys APIs" - }, - "showIncomingTransactionsExplainer": { - "message": "Ī‘Ļ…Ļ„ĻŒ Ī²Ī±ĻƒĪÆĪ¶ĪµĻ„Ī±Ī¹ σε Γιαφορετικά API τρίτων για κάθε Γίκτυο, τα οποία εκθέτουν τη Ī“Ī¹ĪµĻĪøĻ…Ī½ĻƒĪ· Ethereum και τη Ī“Ī¹ĪµĻĪøĻ…Ī½ĻƒĪ· IP ĻƒĪ±Ļ‚." - }, "showLess": { "message": "Ī•Ī¼Ļ†Ī¬Ī½Ī¹ĻƒĪ· Ī»Ī¹Ī³ĻŒĻ„ĪµĻĻ‰Ī½" }, @@ -4593,6 +4841,9 @@ "showPrivateKey": { "message": "Ī•Ī¼Ļ†Ī¬Ī½Ī¹ĻƒĪ· Ī¹Ī“Ī¹Ļ‰Ļ„Ī¹ĪŗĪæĻ ĪŗĪ»ĪµĪ¹Ī“Ī¹ĪæĻ" }, + "showSRP": { + "message": "Ī•Ī¼Ļ†Ī¬Ī½Ī¹ĻƒĪ· της ĪœĻ…ĻƒĻ„Ī¹ĪŗĪ®Ļ‚ Ī¦ĻĪ¬ĻƒĪ·Ļ‚ Ī‘Ī½Ī¬ĪŗĻ„Ī·ĻƒĪ·Ļ‚" + }, "showTestnetNetworks": { "message": "Ī•Ī¼Ļ†Ī¬Ī½Ī¹ĻƒĪ· Ī“ĪæĪŗĪ¹Ī¼Ī±ĻƒĻ„Ī¹ĪŗĻŽĪ½ Ī“Ī¹ĪŗĻ„ĻĻ‰Ī½" }, @@ -4714,12 +4965,24 @@ "slideCashOutTitle": { "message": "ĪšĪ¬Ī½Ļ„Īµ ανάληψη με το MetaMask" }, + "slideDebitCardDescription": { + "message": "Διατίθεται σε επιλεγμένες περιοχές" + }, "slideDebitCardTitle": { "message": "Ī§ĻĪµĻ‰ĻƒĻ„Ī¹ĪŗĪ® κάρτα Ī±Ļ€ĻŒ το MetaMask" }, + "slideFundWalletDescription": { + "message": "Ī ĻĪæĻƒĪøĪ­ĻƒĻ„Īµ Ī® μεταφέρετε tokens για να Ī¾ĪµĪŗĪ¹Ī½Ī®ĻƒĪµĻ„Īµ" + }, "slideFundWalletTitle": { "message": "Ī§ĻĪ·Ī¼Ī±Ļ„ĪæĪ“ĪæĻ„Ī®ĻƒĻ„Īµ το Ļ€ĪæĻĻ„ĪæĻ†ĻŒĪ»Ī¹ ĻƒĪ±Ļ‚" }, + "slideSweepStakeDescription": { + "message": "Ī‘Ī½Ī±ĻĻ„Ī®ĻƒĻ„Īµ ένα NFT Ļ„ĻŽĻĪ± για μια ευκαιρία να ĪŗĪµĻĪ“ĪÆĻƒĪµĻ„Īµ" + }, + "slideSweepStakeTitle": { + "message": "Ī”Ī·Ī»ĻŽĻƒĻ„Īµ ĻƒĻ…Ī¼Ī¼ĪµĻ„ĪæĻ‡Ī® ĻƒĻ„ĪæĪ½ Ī“Ī¹Ī±Ī³Ļ‰Ī½Ī¹ĻƒĪ¼ĻŒ για $5000 USDC!" + }, "smartContracts": { "message": "ĪˆĪ¾Ļ…Ļ€Ī½Ī± ĻƒĻ…Ī¼Ī²ĻŒĪ»Ī±Ī¹Ī±" }, @@ -4866,6 +5129,9 @@ "snapResultSuccessDescription": { "message": "Το $1 είναι έτοιμο για Ļ‡ĻĪ®ĻƒĪ·" }, + "snapUIAssetSelectorTitle": { + "message": "Επιλέξτε ένα Ļ€ĪµĻĪ¹ĪæĻ…ĻƒĪ¹Ī±ĪŗĻŒ ĻƒĻ„ĪæĪ¹Ļ‡ĪµĪÆĪæ" + }, "snapUpdateAlertDescription": { "message": "Ī‘Ļ€ĪæĪŗĻ„Ī®ĻƒĻ„Īµ την τελευταία έκΓοση του $1", "description": "Description used in Snap update alert banner when snap update is available. $1 is the Snap name." @@ -4925,6 +5191,27 @@ "message": "Ī•Ļ€Ī¹ĪŗĪæĪ¹Ī½Ļ‰Ī½Ī®ĻƒĻ„Īµ με τους Ī“Ī¹Ī±Ļ‡ĪµĪ¹ĻĪ¹ĻƒĻ„Ī­Ļ‚ του $1 για περαιτέρω Ļ…Ļ€ĪæĻƒĻ„Ī®ĻĪ¹Ī¾Ī·.", "description": "This is shown when the insight snap throws an error. $1 is the snap name" }, + "solanaImportAccounts": { + "message": "Ī•Ī¹ĻƒĪ±Ī³Ļ‰Ī³Ī® Ī»ĪæĪ³Ī±ĻĪ¹Ī±ĻƒĪ¼ĻŽĪ½ ĻƒĻ„Īæ Solana" + }, + "solanaImportAccountsDescription": { + "message": "Ī•Ī¹ĻƒĪ¬Ī³ĪµĻ„Īµ μια ĪœĻ…ĻƒĻ„Ī¹ĪŗĪ® Φράση Ī‘Ī½Ī¬ĪŗĻ„Ī·ĻƒĪ·Ļ‚ για να μεταφέρετε τον λογαριασμό ĻƒĪ±Ļ‚ ĻƒĻ„Ī· Solana Ī±Ļ€ĻŒ άλλο Ļ€ĪæĻĻ„ĪæĻ†ĻŒĪ»Ī¹." + }, + "solanaMoreFeaturesComingSoon": { + "message": "Ī ĪµĻĪ¹ĻƒĻƒĻŒĻ„ĪµĻĪµĻ‚ λειτουργίες έρχονται ĻƒĻĪ½Ļ„ĪæĪ¼Ī±" + }, + "solanaMoreFeaturesComingSoonDescription": { + "message": "Solana dapps, NFT, Ļ…Ļ€ĪæĻƒĻ„Ī®ĻĪ¹Ī¾Ī· Ļ€ĪæĻĻ„ĪæĻ†ĪæĪ»Ī¹ĪæĻ Ļ…Ī»Ī¹ĪŗĪæĻ και πολλά άλλα ĻƒĻĪ½Ļ„ĪæĪ¼Ī±." + }, + "solanaOnMetaMask": { + "message": "Το Solana ĻƒĻ„Īæ MetaMask" + }, + "solanaSendReceiveSwapTokens": { + "message": "Ī‘Ļ€ĪæĻƒĻ„ĪæĪ»Ī®, λήψη και ανταλλαγή tokens" + }, + "solanaSendReceiveSwapTokensDescription": { + "message": "ĪœĪµĻ„Ī±Ļ†Ī­ĻĪµĻ„Īµ και κάντε ĻƒĻ…Ī½Ī±Ī»Ī»Ī±Ī³Ī­Ļ‚ με tokens ĻŒĻ€Ļ‰Ļ‚ SOL, USDC και άλλα." + }, "someNetworks": { "message": "$1 Γίκτυα" }, @@ -4951,6 +5238,21 @@ "source": { "message": "Πηγή" }, + "spamModalBlockedDescription": { + "message": "Ī‘Ļ…Ļ„ĻŒĻ‚ Īæ Ī¹ĻƒĻ„ĻŒĻ„ĪæĻ€ĪæĻ‚ θα Ī¼Ļ€Ī»ĪæĪŗĪ±ĻĪ¹ĻƒĻ„ĪµĪÆ για 1 Ī»ĪµĻ€Ļ„ĻŒ." + }, + "spamModalBlockedTitle": { + "message": "ĪˆĻ‡ĪµĻ„Īµ μπλοκάρει Ļ€ĻĪæĻƒĻ‰ĻĪ¹Ī½Ī¬ Ī±Ļ…Ļ„ĻŒĪ½ τον Ī¹ĻƒĻ„ĻŒĻ„ĪæĻ€Īæ" + }, + "spamModalDescription": { + "message": "Εάν ĻƒĪ±Ļ‚ ĻƒĻ„Ī­Ī»Ī½ĪæĻ…Ī½ Ī±Ī½ĪµĻ€Ī¹ĪøĻĪ¼Ī·Ļ„Ī± Ī¼Ī·Ī½ĻĪ¼Ī±Ļ„Ī± με πολλαπλά αιτήματα, μπορείτε να μπλοκάρετε Ļ€ĻĪæĻƒĻ‰ĻĪ¹Ī½Ī¬ τον Ī¹ĻƒĻ„ĻŒĻ„ĪæĻ€Īæ." + }, + "spamModalTemporaryBlockButton": { + "message": "ĪœĻ€Ī»ĪæĪŗĪ¬ĻĪµĻ„Īµ Ļ€ĻĪæĻƒĻ‰ĻĪ¹Ī½Ī¬ Ī±Ļ…Ļ„ĻŒĪ½ τον Ī¹ĻƒĻ„ĻŒĻ„ĪæĻ€Īæ" + }, + "spamModalTitle": { + "message": "Ī Ī±ĻĪ±Ļ„Ī·ĻĪ®ĻƒĪ±Ī¼Īµ πολλαπλά αιτήματα" + }, "speed": { "message": "Ī¤Ī±Ļ‡ĻĻ„Ī·Ļ„Ī±" }, @@ -5000,10 +5302,28 @@ "spendingCap": { "message": "Ī‘Ī½ĻŽĻ„Ī±Ļ„Īæ όριο Ī“Ī±Ļ€Ī±Ī½ĻŽĪ½" }, + "spendingCaps": { + "message": "Ī‘Ī½ĻŽĻ„Ī±Ļ„Ī± όριο Ī“Ī±Ļ€Ī±Ī½ĻŽĪ½" + }, "srpInputNumberOfWords": { "message": "ĪˆĻ‡Ļ‰ μια Ļ†ĻĪ¬ĻƒĪ· $1 λέξεων", "description": "This is the text for each option in the dropdown where a user selects how many words their secret recovery phrase has during import. The $1 is the number of words (either 12, 15, 18, 21, or 24)." }, + "srpListName": { + "message": "ĪœĻ…ĻƒĻ„Ī¹ĪŗĪ® Φράση Ī‘Ī½Ī¬ĪŗĻ„Ī·ĻƒĪ·Ļ‚ $1", + "description": "$1 is the order of the Secret Recovery Phrase" + }, + "srpListNumberOfAccounts": { + "message": "$1 λογαριασμοί", + "description": "$1 is the number of accounts in the list" + }, + "srpListSelectionDescription": { + "message": "Ī— ĪœĻ…ĻƒĻ„Ī¹ĪŗĪ® Φράση Ī‘Ī½Ī¬ĪŗĻ„Ī·ĻƒĪ·Ļ‚ Ī±Ļ€ĻŒ την οποία θα Γημιουργηθεί Īæ νέος ĻƒĪ±Ļ‚ Ī»ĪæĪ³Ī±ĻĪ¹Ī±ĻƒĪ¼ĻŒĻ‚" + }, + "srpListSingleOrZero": { + "message": "$1 Ī»ĪæĪ³Ī±ĻĪ¹Ī±ĻƒĪ¼ĻŒĻ‚", + "description": "$1 is the number of accounts in the list, it is either 1 or 0" + }, "srpPasteFailedTooManyWords": { "message": "Ī— ĪµĻ€Ī¹ĪŗĻŒĪ»Ī»Ī·ĻƒĪ· απέτυχε επειΓή περιείχε Ļ€ĪµĻĪ¹ĻƒĻƒĻŒĻ„ĪµĻĪµĻ‚ Ī±Ļ€ĻŒ 24 λέξεις. Μια Ī¼Ļ…ĻƒĻ„Ī¹ĪŗĪ® Ļ†ĻĪ¬ĻƒĪ· Ī±Ī½Ī¬ĪŗĻ„Ī·ĻƒĪ·Ļ‚ μπορεί να αποτελείται Ī±Ļ€ĻŒ το Ļ€ĪæĪ»Ļ 24 λέξεις.", "description": "Description of SRP paste error when the pasted content has too many words" @@ -5158,6 +5478,9 @@ "message": "Οι ξαφνικές αλλαγές ĻƒĻ„Ī·Ī½ αγορά μπορεί να Ļ€ĻĪæĪŗĪ±Ī»Ī­ĻƒĪæĻ…Ī½ αποτυχίες. Εάν το Ļ€ĻĻŒĪ²Ī»Ī·Ī¼Ī± επιμένει, Ļ€Ī±ĻĪ±ĪŗĪ±Ī»ĪæĻĪ¼Īµ ĪµĻ€Ī¹ĪŗĪæĪ¹Ī½Ļ‰Ī½Ī®ĻƒĻ„Īµ με το $1.", "description": "This message is shown to a user if their swap fails. The $1 will be replaced by support.metamask.io" }, + "stxOptInSupportedNetworksDescription": { + "message": "Ī•Ī½ĪµĻĪ³ĪæĻ€ĪæĪ¹Ī®ĻƒĻ„Īµ τις ĪˆĪ¾Ļ…Ļ€Ī½ĪµĻ‚ Συναλλαγές για πιο Ī±Ī¾Ī¹ĻŒĻ€Ī¹ĻƒĻ„ĪµĻ‚ και Ī±ĻƒĻ†Ī±Ī»ĪµĪÆĻ‚ ĻƒĻ…Ī½Ī±Ī»Ī»Ī±Ī³Ī­Ļ‚ σε Ļ…Ļ€ĪæĻƒĻ„Ī·ĻĪ¹Ī¶ĻŒĪ¼ĪµĪ½Ī± Γίκτυα. $1" + }, "stxPendingPrivatelySubmittingSwap": { "message": "ΙΓιωτική υποβολή της Ανταλλαγής ĻƒĪ±Ļ‚..." }, @@ -5977,6 +6300,12 @@ "message": "Ī— Ī±Ļ€ĪæĻƒĻ„ĪæĪ»Ī® NFT (ERC-721) tokens Γεν Ļ…Ļ€ĪæĻƒĻ„Ī·ĻĪÆĪ¶ĪµĻ„Ī±Ī¹ προς το Ļ€Ī±ĻĻŒĪ½", "description": "This is an error message we show the user if they attempt to send an NFT asset type, for which currently don't support sending" }, + "unstableTokenPriceDescription": { + "message": "Ī— τιμή Ī±Ļ…Ļ„ĪæĻ του token σε USD είναι εξαιρετικά ευμετάβλητη, Ļ…Ļ€ĪæĪ“ĪµĪ¹ĪŗĪ½ĻĪæĪ½Ļ„Ī±Ļ‚ Ļ…ĻˆĪ·Ī»ĻŒ κίνΓυνο Ī±Ļ€ĻŽĪ»ĪµĪ¹Ī±Ļ‚ ĻƒĪ·Ī¼Ī±Ī½Ļ„Ī¹ĪŗĪ®Ļ‚ αξίας Ī±Ļ€ĻŒ την Ī±Ī»Ī»Ī·Ī»ĪµĻ€ĪÆĪ“ĻĪ±ĻƒĪ· με Ī±Ļ…Ļ„ĻŒ." + }, + "unstableTokenPriceTitle": { + "message": "Ī‘ĻƒĻ„Ī±ĪøĪ®Ļ‚ τιμή του token" + }, "upArrow": { "message": "πάνω βέλος" }, @@ -6099,6 +6428,18 @@ "visitSite": { "message": "Ī•Ļ€Ī¹ĻƒĪŗĪµĻ†ĪøĪµĪÆĻ„Īµ τον Ī¹ĻƒĻ„ĻŒĻ„ĪæĻ€Īæ" }, + "visitSupportDataConsentModalAccept": { + "message": "Ī•Ļ€Ī¹Ī²ĪµĪ²Ī±ĪÆĻ‰ĻƒĪ·" + }, + "visitSupportDataConsentModalDescription": { + "message": "ĪœĻ€ĪæĻĪµĪÆĻ„Īµ να μας Ī“ĻŽĻƒĪµĻ„Īµ το MetaMask Identifier ĪŗĪ±ĪøĻŽĻ‚ και την έκΓοση της εφαρμογής ĻƒĪ±Ļ‚ ĻƒĻ„Īæ ĪšĪ­Ī½Ļ„ĻĪæ Ī„Ļ€ĪæĻƒĻ„Ī®ĻĪ¹Ī¾Ī·Ļ‚; Ī‘Ļ…Ļ„ĻŒ θα μας βοηθήσει να ĪŗĪ±Ļ„Ī±Ī½ĪæĪ®ĻƒĪæĻ…Ī¼Īµ ĪŗĪ±Ī»ĻĻ„ĪµĻĪ± το Ļ€ĻĻŒĪ²Ī»Ī·Ī¼Ī¬ ĻƒĪ±Ļ‚, αλλά είναι Ļ€ĻĪæĪ±Ī¹ĻĪµĻ„Ī¹ĪŗĻŒ." + }, + "visitSupportDataConsentModalReject": { + "message": "Δεν θέλω" + }, + "visitSupportDataConsentModalTitle": { + "message": "Παρέχετε τα ĻƒĻ„ĪæĪ¹Ļ‡ĪµĪÆĪ± της ĻƒĻ…ĻƒĪŗĪµĻ…Ī®Ļ‚ ĻƒĻ„Ī·Ī½ Ļ…Ļ€ĪæĻƒĻ„Ī®ĻĪ¹Ī¾Ī·" + }, "visitWebSite": { "message": "Ī•Ļ€Ī¹ĻƒĪŗĪµĻ†ĪøĪµĪÆĻ„Īµ τον Ī¹ĻƒĻ„ĻŒĻ„ĪæĻ€ĻŒ μας" }, diff --git a/app/_locales/en/messages.json b/app/_locales/en/messages.json index d398519334e6..0cdc3aaade7e 100644 --- a/app/_locales/en/messages.json +++ b/app/_locales/en/messages.json @@ -161,6 +161,10 @@ "addAccount": { "message": "Add account" }, + "addAccountFromNetwork": { + "message": "Add $1 account", + "description": "$1 is the network name, e.g. Bitcoin or Solana" + }, "addAccountToMetaMask": { "message": "Add account to MetaMask" }, @@ -255,8 +259,8 @@ "description": "$1 is the non EVM network where the account is going to be created, e.g. Bitcoin or Solana" }, "addNonEvmAccountFromNetworkPicker": { - "message": "To enable the $1 network, you need to create a $1 account.", - "description": "$1 is the non EVM network where the account is going to be created, e.g. Bitcoin or Solana" + "message": "To enable the $1 network, you need to create a $2 account.", + "description": "$1 is the non EVM network where the account is going to be created, e.g. Solana Mainnet or Solana Devnet. $2 is the account type, e.g. Bitcoin or Solana" }, "addRpcUrl": { "message": "Add RPC URL" @@ -340,10 +344,6 @@ "advancedPriorityFeeToolTip": { "message": "Priority fee (aka ā€œminer tipā€) goes directly to miners and incentivizes them to prioritize your transaction." }, - "aggregatedBalancePopover": { - "message": "This reflects the value of all tokens you own on a given network. If you prefer seeing this value in ETH or other currencies, go to $1.", - "description": "$1 represents the settings page" - }, "agreeTermsOfUse": { "message": "I agree to MetaMask's $1", "description": "$1 is the `terms` link" @@ -710,26 +710,23 @@ "blockaid": { "message": "Blockaid" }, - "blockaidAlertInfoDescription": { - "message": "A third party known for scams has access to this site. If you proceed, you'll lose assets." - }, - "blockaidAlertInfoDescription2": { - "message": "The site may look safe, but a third party might have access to its information. If you sign in, your assets could get stolen." + "blockaidAlertDescriptionBlur": { + "message": "If you continue, all the assets you’ve listed on Blur could be at risk." }, - "blockaidAlertInfoDescription3": { - "message": "If you confirm, you could lose all your funds and assets." + "blockaidAlertDescriptionMalicious": { + "message": "You’re interacting with a malicious site. If you continue, you will lose your assets." }, - "blockaidAlertInfoDescription4": { - "message": "If you sign in, any or all assets you've listed on OpenSea are at risk." + "blockaidAlertDescriptionOpenSea": { + "message": "If you continue, all the assets you’ve listed on OpenSea could be at risk." }, - "blockaidAlertInfoDescription5": { - "message": "If you sign in, any or all assets you've listed on Blur are at risk." + "blockaidAlertDescriptionOthers": { + "message": "If you confirm this request, you could lose your assets. We recommend that you cancel this request." }, - "blockaidAlertInfoDescription6": { - "message": "This site is recognized as a malicious domain. If you sign in, you will lose funds and assets. We strongly suggest you cancel this request." + "blockaidAlertDescriptionTokenTransfer": { + "message": "You’re sending your assets to a scammer. If you continue, you’ll lose those assets." }, - "blockaidAlertInfoDescription7": { - "message": "If you sign in, you could lose all your assets. We recommend you cancel this request." + "blockaidAlertDescriptionWithdraw": { + "message": "If you confirm this request, you’re allowing a scammer to withdraw and spend your assets. You won’t get them back." }, "blockaidDescriptionApproveFarming": { "message": "If you approve this request, a third party known for scams might take all your assets." @@ -787,6 +784,9 @@ "bridgeApprovalWarningForHardware": { "message": "You will need to allow access to $1 $2 for bridging, and then approve bridging to $2. This will require two separate confirmations." }, + "bridgeBlockExplorerLinkCopied": { + "message": "Block explorer link copied!" + }, "bridgeCalculatingAmount": { "message": "Calculating..." }, @@ -802,6 +802,10 @@ "bridgeCreateSolanaAccountTitle": { "message": "You'll need a Solana account first." }, + "bridgeDetailsTitle": { + "message": "Bridge details", + "description": "Title for the modal showing details about a bridge transaction." + }, "bridgeEnterAmount": { "message": "Select amount" }, @@ -842,6 +846,21 @@ "bridgeSelectTokenAndAmount": { "message": "Select token and amount" }, + "bridgeSolanaAccountCreated": { + "message": "Solana account created" + }, + "bridgeStatusComplete": { + "message": "Complete", + "description": "Status text indicating a bridge transaction has successfully completed." + }, + "bridgeStatusFailed": { + "message": "Failed", + "description": "Status text indicating a bridge transaction has failed." + }, + "bridgeStatusInProgress": { + "message": "In Progress", + "description": "Status text indicating a bridge transaction is currently processing." + }, "bridgeStepActionBridgeComplete": { "message": "$1 received on $2", "description": "$1 is the amount of the destination asset, $2 is the name of the destination network" @@ -871,6 +890,15 @@ "bridgeToChain": { "message": "Bridge to $1" }, + "bridgeTokenCannotVerifyDescription": { + "message": "If you added this token manually, make sure you are aware of the risks to your funds before you bridge." + }, + "bridgeTokenCannotVerifyTitle": { + "message": "We can't verify this token." + }, + "bridgeTransactionProgress": { + "message": "Transaction $1 of 2" + }, "bridgeTxDetailsBridging": { "message": "Bridging" }, @@ -1107,12 +1135,18 @@ "confirmTitleApproveTransactionNFT": { "message": "Withdrawal request" }, + "confirmTitleDelegationRevoke": { + "message": "Account update" + }, "confirmTitleDeployContract": { "message": "Deploy a contract" }, "confirmTitleDescApproveTransaction": { "message": "This site wants permission to withdraw your NFTs" }, + "confirmTitleDescDelegationRevoke": { + "message": "You're switching back to a standard account (EOA)." + }, "confirmTitleDescDeployContract": { "message": "This site wants you to deploy a contract" }, @@ -1122,9 +1156,6 @@ "confirmTitleDescPermitSignature": { "message": "This site wants permission to spend your tokens." }, - "confirmTitleDescRevokeDelegation": { - "message": "This site is requesting to switch back to a standard account." - }, "confirmTitleDescSIWESignature": { "message": "A site wants you to sign in to prove you own this account." }, @@ -1137,9 +1168,6 @@ "confirmTitleRevokeApproveTransaction": { "message": "Remove permission" }, - "confirmTitleRevokeDelegation": { - "message": "Reset account" - }, "confirmTitleSIWESignature": { "message": "Sign-in request" }, @@ -1152,9 +1180,6 @@ "confirmTitleTransaction": { "message": "Transaction request" }, - "confirmUpgradeAcknowledge": { - "message": "If you confirm this request, your account will be updated to a smart account." - }, "confirmUpgradeCancelModalButtonCancelTransaction": { "message": "Cancel transaction" }, @@ -1646,6 +1671,10 @@ "destinationAccountPickerSearchPlaceholderToSolana": { "message": "Receiving address" }, + "destinationTransactionIdLabel": { + "message": "Destination Tx ID", + "description": "Label for the destination transaction ID field." + }, "details": { "message": "Details" }, @@ -1707,6 +1736,12 @@ "dismissReminderField": { "message": "Dismiss Secret Recovery Phrase backup reminder" }, + "dismissSmartAccountSuggestionEnabledDescription": { + "message": "Turn this on to no longer see the \"Switch to Smart Account\" suggestion on any account. Smart accounts unlocks faster transactions, lower network fees and more flexibility on payment for those." + }, + "dismissSmartAccountSuggestionEnabledTitle": { + "message": "Dismiss \"Switch to Smart Account\" suggestion" + }, "displayNftMedia": { "message": "Display NFT media" }, @@ -2510,7 +2545,8 @@ "message": "Import a wallet or account" }, "importWalletSuccess": { - "message": "Wallet successfully imported" + "message": "Secret Recovery Phrase $1 imported", + "description": "$1 is the index of the secret recovery phrase" }, "importWithCount": { "message": "Import $1", @@ -2568,12 +2604,18 @@ "insufficientTokens": { "message": "Insufficient tokens." }, + "interactWithSmartContract": { + "message": "Smart contract" + }, "interactingWith": { "message": "Interacting with" }, "interactingWithTransactionDescription": { "message": "This is the contract you're interacting with. Protect yourself from scammers by verifying the details." }, + "interaction": { + "message": "Interaction" + }, "invalidAddress": { "message": "Invalid address" }, @@ -2881,6 +2923,12 @@ "manageDefaultSettings": { "message": "Manage default privacy settings" }, + "manageInstitutionalWallets": { + "message": "Manage Institutional Wallets" + }, + "manageInstitutionalWalletsDescription": { + "message": "Turn this on to enable institutional wallets." + }, "managePermissions": { "message": "Manage permissions" }, @@ -4872,16 +4920,6 @@ "showHexDataDescription": { "message": "Select this to show the hex data field on the send screen" }, - "showIncomingTransactions": { - "message": "Show incoming transactions" - }, - "showIncomingTransactionsDescription": { - "message": "This relies on $1 which will have access to your Ethereum address and your IP address. $2", - "description": "$1 is the link to etherscan url and $2 is the link to the privacy policy of consensys APIs" - }, - "showIncomingTransactionsExplainer": { - "message": "This relies on different third-party APIs for each network, which expose your Ethereum address and your IP address." - }, "showLess": { "message": "Show less" }, @@ -5036,12 +5074,48 @@ "slideFundWalletTitle": { "message": "Fund your wallet" }, + "slideRemoteModeDescription": { + "message": "Access your hardware wallet without plugging it in" + }, + "slideRemoteModeTitle": { + "message": "Remote mode is here!" + }, "slideSweepStakeDescription": { "message": "Mint an NFT now for a chance to win" }, "slideSweepStakeTitle": { "message": "Enter the $5000 USDC Giveaway!" }, + "smartAccountAccept": { + "message": "Use smart account" + }, + "smartAccountBetterTransaction": { + "message": "Faster transactions, lower fees" + }, + "smartAccountBetterTransactionDescription": { + "message": "Save time and money by processing transactions together." + }, + "smartAccountFeatures": { + "message": "Same account, smarter features" + }, + "smartAccountFeaturesDescription": { + "message": "Keep the same account address, and you can switch back anytime." + }, + "smartAccountPayToken": { + "message": "Pay with any token, any time" + }, + "smartAccountPayTokenDescription": { + "message": "Use the tokens you already have to cover network fees." + }, + "smartAccountReject": { + "message": "Don’t use smart account" + }, + "smartAccountRequestFor": { + "message": "Request for" + }, + "smartAccountSplashTitle": { + "message": "Use smart account?" + }, "smartContracts": { "message": "Smart contracts" }, @@ -5250,6 +5324,12 @@ "message": "Contact the creators of $1 for further support.", "description": "This is shown when the insight snap throws an error. $1 is the snap name" }, + "solanaAccountRequested": { + "message": "This site is requesting a Solana account." + }, + "solanaAccountRequired": { + "message": "A Solana account is required to connect to this site." + }, "solanaImportAccounts": { "message": "Import Solana accounts" }, @@ -6217,6 +6297,10 @@ "transactionHistoryTotalGasFee": { "message": "Total gas fee" }, + "transactionIdLabel": { + "message": "Transaction ID", + "description": "Label for the source transaction ID field." + }, "transactionResubmitted": { "message": "Transaction resubmitted with estimated gas fee increased to $1 at $2" }, @@ -6226,6 +6310,10 @@ "transactionSubmitted": { "message": "Transaction submitted with estimated gas fee of $1 at $2." }, + "transactionTotalGasFee": { + "message": "Total gas fee", + "description": "Label for the total gas fee incurred in the transaction." + }, "transactionUpdated": { "message": "Transaction updated at $2." }, @@ -6602,6 +6690,14 @@ "youNeedToAllowCameraAccess": { "message": "You need to allow camera access to use this feature." }, + "youReceived": { + "message": "You received", + "description": "Label indicating the amount and asset the user received." + }, + "youSent": { + "message": "You sent", + "description": "Label indicating the amount and asset the user sent." + }, "yourAccounts": { "message": "Your accounts" }, diff --git a/app/_locales/en_GB/messages.json b/app/_locales/en_GB/messages.json index be356ae820f5..0cdc3aaade7e 100644 --- a/app/_locales/en_GB/messages.json +++ b/app/_locales/en_GB/messages.json @@ -161,6 +161,10 @@ "addAccount": { "message": "Add account" }, + "addAccountFromNetwork": { + "message": "Add $1 account", + "description": "$1 is the network name, e.g. Bitcoin or Solana" + }, "addAccountToMetaMask": { "message": "Add account to MetaMask" }, @@ -255,8 +259,8 @@ "description": "$1 is the non EVM network where the account is going to be created, e.g. Bitcoin or Solana" }, "addNonEvmAccountFromNetworkPicker": { - "message": "To enable the $1 network, you need to create a $1 account.", - "description": "$1 is the non EVM network where the account is going to be created, e.g. Bitcoin or Solana" + "message": "To enable the $1 network, you need to create a $2 account.", + "description": "$1 is the non EVM network where the account is going to be created, e.g. Solana Mainnet or Solana Devnet. $2 is the account type, e.g. Bitcoin or Solana" }, "addRpcUrl": { "message": "Add RPC URL" @@ -340,10 +344,6 @@ "advancedPriorityFeeToolTip": { "message": "Priority fee (aka ā€œminer tipā€) goes directly to miners and incentivizes them to prioritize your transaction." }, - "aggregatedBalancePopover": { - "message": "This reflects the value of all tokens you own on a given network. If you prefer seeing this value in ETH or other currencies, go to $1.", - "description": "$1 represents the settings page" - }, "agreeTermsOfUse": { "message": "I agree to MetaMask's $1", "description": "$1 is the `terms` link" @@ -710,26 +710,23 @@ "blockaid": { "message": "Blockaid" }, - "blockaidAlertInfoDescription": { - "message": "A third party known for scams has access to this site. If you proceed, you'll lose assets." - }, - "blockaidAlertInfoDescription2": { - "message": "The site may look safe, but a third party might have access to its information. If you sign in, your assets could get stolen." + "blockaidAlertDescriptionBlur": { + "message": "If you continue, all the assets you’ve listed on Blur could be at risk." }, - "blockaidAlertInfoDescription3": { - "message": "If you confirm, you could lose all your funds and assets." + "blockaidAlertDescriptionMalicious": { + "message": "You’re interacting with a malicious site. If you continue, you will lose your assets." }, - "blockaidAlertInfoDescription4": { - "message": "If you sign in, any or all assets you've listed on OpenSea are at risk." + "blockaidAlertDescriptionOpenSea": { + "message": "If you continue, all the assets you’ve listed on OpenSea could be at risk." }, - "blockaidAlertInfoDescription5": { - "message": "If you sign in, any or all assets you've listed on Blur are at risk." + "blockaidAlertDescriptionOthers": { + "message": "If you confirm this request, you could lose your assets. We recommend that you cancel this request." }, - "blockaidAlertInfoDescription6": { - "message": "This site is recognized as a malicious domain. If you sign in, you will lose funds and assets. We strongly suggest you cancel this request." + "blockaidAlertDescriptionTokenTransfer": { + "message": "You’re sending your assets to a scammer. If you continue, you’ll lose those assets." }, - "blockaidAlertInfoDescription7": { - "message": "If you sign in, you could lose all your assets. We recommend you cancel this request." + "blockaidAlertDescriptionWithdraw": { + "message": "If you confirm this request, you’re allowing a scammer to withdraw and spend your assets. You won’t get them back." }, "blockaidDescriptionApproveFarming": { "message": "If you approve this request, a third party known for scams might take all your assets." @@ -787,6 +784,9 @@ "bridgeApprovalWarningForHardware": { "message": "You will need to allow access to $1 $2 for bridging, and then approve bridging to $2. This will require two separate confirmations." }, + "bridgeBlockExplorerLinkCopied": { + "message": "Block explorer link copied!" + }, "bridgeCalculatingAmount": { "message": "Calculating..." }, @@ -802,6 +802,10 @@ "bridgeCreateSolanaAccountTitle": { "message": "You'll need a Solana account first." }, + "bridgeDetailsTitle": { + "message": "Bridge details", + "description": "Title for the modal showing details about a bridge transaction." + }, "bridgeEnterAmount": { "message": "Select amount" }, @@ -842,6 +846,21 @@ "bridgeSelectTokenAndAmount": { "message": "Select token and amount" }, + "bridgeSolanaAccountCreated": { + "message": "Solana account created" + }, + "bridgeStatusComplete": { + "message": "Complete", + "description": "Status text indicating a bridge transaction has successfully completed." + }, + "bridgeStatusFailed": { + "message": "Failed", + "description": "Status text indicating a bridge transaction has failed." + }, + "bridgeStatusInProgress": { + "message": "In Progress", + "description": "Status text indicating a bridge transaction is currently processing." + }, "bridgeStepActionBridgeComplete": { "message": "$1 received on $2", "description": "$1 is the amount of the destination asset, $2 is the name of the destination network" @@ -871,6 +890,15 @@ "bridgeToChain": { "message": "Bridge to $1" }, + "bridgeTokenCannotVerifyDescription": { + "message": "If you added this token manually, make sure you are aware of the risks to your funds before you bridge." + }, + "bridgeTokenCannotVerifyTitle": { + "message": "We can't verify this token." + }, + "bridgeTransactionProgress": { + "message": "Transaction $1 of 2" + }, "bridgeTxDetailsBridging": { "message": "Bridging" }, @@ -1107,12 +1135,18 @@ "confirmTitleApproveTransactionNFT": { "message": "Withdrawal request" }, + "confirmTitleDelegationRevoke": { + "message": "Account update" + }, "confirmTitleDeployContract": { "message": "Deploy a contract" }, "confirmTitleDescApproveTransaction": { "message": "This site wants permission to withdraw your NFTs" }, + "confirmTitleDescDelegationRevoke": { + "message": "You're switching back to a standard account (EOA)." + }, "confirmTitleDescDeployContract": { "message": "This site wants you to deploy a contract" }, @@ -1122,9 +1156,6 @@ "confirmTitleDescPermitSignature": { "message": "This site wants permission to spend your tokens." }, - "confirmTitleDescRevokeDelegation": { - "message": "This site is requesting to switch back to a standard account." - }, "confirmTitleDescSIWESignature": { "message": "A site wants you to sign in to prove you own this account." }, @@ -1137,9 +1168,6 @@ "confirmTitleRevokeApproveTransaction": { "message": "Remove permission" }, - "confirmTitleRevokeDelegation": { - "message": "Reset account" - }, "confirmTitleSIWESignature": { "message": "Sign-in request" }, @@ -1152,9 +1180,6 @@ "confirmTitleTransaction": { "message": "Transaction request" }, - "confirmUpgradeAcknowledge": { - "message": "If you confirm this request, your account will be updated to a smart account." - }, "confirmUpgradeCancelModalButtonCancelTransaction": { "message": "Cancel transaction" }, @@ -1646,6 +1671,10 @@ "destinationAccountPickerSearchPlaceholderToSolana": { "message": "Receiving address" }, + "destinationTransactionIdLabel": { + "message": "Destination Tx ID", + "description": "Label for the destination transaction ID field." + }, "details": { "message": "Details" }, @@ -1707,6 +1736,12 @@ "dismissReminderField": { "message": "Dismiss Secret Recovery Phrase backup reminder" }, + "dismissSmartAccountSuggestionEnabledDescription": { + "message": "Turn this on to no longer see the \"Switch to Smart Account\" suggestion on any account. Smart accounts unlocks faster transactions, lower network fees and more flexibility on payment for those." + }, + "dismissSmartAccountSuggestionEnabledTitle": { + "message": "Dismiss \"Switch to Smart Account\" suggestion" + }, "displayNftMedia": { "message": "Display NFT media" }, @@ -2510,7 +2545,8 @@ "message": "Import a wallet or account" }, "importWalletSuccess": { - "message": "Wallet successfully imported" + "message": "Secret Recovery Phrase $1 imported", + "description": "$1 is the index of the secret recovery phrase" }, "importWithCount": { "message": "Import $1", @@ -2568,12 +2604,18 @@ "insufficientTokens": { "message": "Insufficient tokens." }, + "interactWithSmartContract": { + "message": "Smart contract" + }, "interactingWith": { "message": "Interacting with" }, "interactingWithTransactionDescription": { "message": "This is the contract you're interacting with. Protect yourself from scammers by verifying the details." }, + "interaction": { + "message": "Interaction" + }, "invalidAddress": { "message": "Invalid address" }, @@ -2881,6 +2923,12 @@ "manageDefaultSettings": { "message": "Manage default privacy settings" }, + "manageInstitutionalWallets": { + "message": "Manage Institutional Wallets" + }, + "manageInstitutionalWalletsDescription": { + "message": "Turn this on to enable institutional wallets." + }, "managePermissions": { "message": "Manage permissions" }, @@ -4872,16 +4920,6 @@ "showHexDataDescription": { "message": "Select this to show the hex data field on the send screen" }, - "showIncomingTransactions": { - "message": "Show incoming transactions" - }, - "showIncomingTransactionsDescription": { - "message": "This relies on $1 which will have access to your Ethereum address and your IP address. $2", - "description": "$1 is the link to etherscan url and $2 is the link to the privacy policy of consensys APIs" - }, - "showIncomingTransactionsExplainer": { - "message": "This relies on different third-party APIs for each network, which expose your Ethereum address and your IP address." - }, "showLess": { "message": "Show less" }, @@ -5036,12 +5074,48 @@ "slideFundWalletTitle": { "message": "Fund your wallet" }, + "slideRemoteModeDescription": { + "message": "Access your hardware wallet without plugging it in" + }, + "slideRemoteModeTitle": { + "message": "Remote mode is here!" + }, "slideSweepStakeDescription": { "message": "Mint an NFT now for a chance to win" }, "slideSweepStakeTitle": { "message": "Enter the $5000 USDC Giveaway!" }, + "smartAccountAccept": { + "message": "Use smart account" + }, + "smartAccountBetterTransaction": { + "message": "Faster transactions, lower fees" + }, + "smartAccountBetterTransactionDescription": { + "message": "Save time and money by processing transactions together." + }, + "smartAccountFeatures": { + "message": "Same account, smarter features" + }, + "smartAccountFeaturesDescription": { + "message": "Keep the same account address, and you can switch back anytime." + }, + "smartAccountPayToken": { + "message": "Pay with any token, any time" + }, + "smartAccountPayTokenDescription": { + "message": "Use the tokens you already have to cover network fees." + }, + "smartAccountReject": { + "message": "Don’t use smart account" + }, + "smartAccountRequestFor": { + "message": "Request for" + }, + "smartAccountSplashTitle": { + "message": "Use smart account?" + }, "smartContracts": { "message": "Smart contracts" }, @@ -5250,6 +5324,12 @@ "message": "Contact the creators of $1 for further support.", "description": "This is shown when the insight snap throws an error. $1 is the snap name" }, + "solanaAccountRequested": { + "message": "This site is requesting a Solana account." + }, + "solanaAccountRequired": { + "message": "A Solana account is required to connect to this site." + }, "solanaImportAccounts": { "message": "Import Solana accounts" }, @@ -5379,7 +5459,6 @@ "srpListSelectionDescription": { "message": "The Secret Recovery Phrase your new account will be generated from" }, - "srpListSingleOrZero": { "message": "$1 account", "description": "$1 is the number of accounts in the list, it is either 1 or 0" @@ -6218,6 +6297,10 @@ "transactionHistoryTotalGasFee": { "message": "Total gas fee" }, + "transactionIdLabel": { + "message": "Transaction ID", + "description": "Label for the source transaction ID field." + }, "transactionResubmitted": { "message": "Transaction resubmitted with estimated gas fee increased to $1 at $2" }, @@ -6227,6 +6310,10 @@ "transactionSubmitted": { "message": "Transaction submitted with estimated gas fee of $1 at $2." }, + "transactionTotalGasFee": { + "message": "Total gas fee", + "description": "Label for the total gas fee incurred in the transaction." + }, "transactionUpdated": { "message": "Transaction updated at $2." }, @@ -6603,6 +6690,14 @@ "youNeedToAllowCameraAccess": { "message": "You need to allow camera access to use this feature." }, + "youReceived": { + "message": "You received", + "description": "Label indicating the amount and asset the user received." + }, + "youSent": { + "message": "You sent", + "description": "Label indicating the amount and asset the user sent." + }, "yourAccounts": { "message": "Your accounts" }, diff --git a/app/_locales/es/messages.json b/app/_locales/es/messages.json index 942626df6c26..5169cd2a6587 100644 --- a/app/_locales/es/messages.json +++ b/app/_locales/es/messages.json @@ -44,6 +44,20 @@ "QRHardwareWalletSteps2Description": { "message": "Ngrave Zero" }, + "SrpListHideAccounts": { + "message": "Ocultar cuentas de $1", + "description": "$1 is the number of accounts" + }, + "SrpListHideSingleAccount": { + "message": "Ocultar 1 cuenta" + }, + "SrpListShowAccounts": { + "message": "Mostrar $1 cuentas", + "description": "$1 is the number of accounts" + }, + "SrpListShowSingleAccount": { + "message": "Mostrar 1 cuenta" + }, "about": { "message": "Acerca de" }, @@ -76,6 +90,9 @@ "accountDetails": { "message": "Detalles de la cuenta" }, + "accountDetailsRevokeDelegationButton": { + "message": " Volver a la cuenta normal" + }, "accountIdenticon": { "message": "Identicon de cuenta" }, @@ -153,6 +170,12 @@ "addAlias": { "message": "Agregar alias" }, + "addBitcoinAccountLabel": { + "message": "Cuenta de Bitcoin (Beta)" + }, + "addBitcoinTestnetAccountLabel": { + "message": "Cuenta de Bitcoin (Testnet)" + }, "addBlockExplorer": { "message": "Agregar un explorador de bloque" }, @@ -193,6 +216,9 @@ "addFriendsAndAddresses": { "message": "Agregue amigos y direcciones de confianza" }, + "addHardwareWalletLabel": { + "message": "Monedero fĆ­sico" + }, "addIPFSGateway": { "message": "Agregue su puerta de enlace de IPFS preferida" }, @@ -212,12 +238,26 @@ "addNewAccount": { "message": "AƱadir una cuenta nueva de Ethereum" }, + "addNewEthereumAccountLabel": { + "message": "Cuenta de Ethereum" + }, + "addNewSolanaAccountLabel": { + "message": "Cuenta de Solana" + }, "addNft": { "message": "AƱadir NFT" }, "addNfts": { "message": "AƱadir NFT" }, + "addNonEvmAccount": { + "message": "AƱadir cuenta de $1", + "description": "$1 is the non EVM network where the account is going to be created, e.g. Bitcoin or Solana" + }, + "addNonEvmAccountFromNetworkPicker": { + "message": "Para habilitar la red de $1, debe crear una cuenta de $2.", + "description": "$1 is the non EVM network where the account is going to be created, e.g. Solana Mainnet or Solana Devnet. $2 is the account type, e.g. Bitcoin or Solana" + }, "addRpcUrl": { "message": "Agregar URL RPC" }, @@ -300,14 +340,16 @@ "advancedPriorityFeeToolTip": { "message": "La tarifa de prioridad (tambiĆ©n llamada ā€œpropina del mineroā€) va directamente a los mineros para incentivarlos a priorizar su transacción." }, - "aggregatedBalancePopover": { - "message": "Esto refleja el valor de todos los tokens que posee en una red determinada. Si prefiere ver este valor en ETH u otras monedas, vaya a $1.", - "description": "$1 represents the settings page" - }, "agreeTermsOfUse": { "message": "Acepto los $1 de MetaMask", "description": "$1 is the `terms` link" }, + "airDropPatternDescription": { + "message": "El historial en cadena del token revela instancias anteriores de actividades sospechosas de airdrop." + }, + "airDropPatternTitle": { + "message": "Patrón de airdrop" + }, "airgapVault": { "message": "Bóveda AirGap" }, @@ -726,9 +768,21 @@ "bridgeConfirmTwoTransactions": { "message": "DeberĆ” confirmar 2 transacciones en su monedero fĆ­sico:" }, + "bridgeCreateSolanaAccount": { + "message": "Crear cuenta de Solana" + }, + "bridgeCreateSolanaAccountDescription": { + "message": "Para cambiar a la red Solana, necesita una cuenta y una dirección receptora." + }, + "bridgeCreateSolanaAccountTitle": { + "message": "Primero necesitarĆ” una cuenta de Solana." + }, "bridgeEnterAmount": { "message": "Ingrese el monto" }, + "bridgeEnterAmountAndSelectAccount": { + "message": "Ingrese el monto y seleccione la cuenta de destino" + }, "bridgeExplorerLinkViewOn": { "message": "Ver en $1" }, @@ -751,9 +805,15 @@ "bridgeQuoteExpired": { "message": "Su cotización caducó." }, + "bridgeSelectDestinationAccount": { + "message": "Seleccione la cuenta de destino" + }, "bridgeSelectNetwork": { "message": "Seleccionar red" }, + "bridgeSelectTokenAmountAndAccount": { + "message": "Seleccione token, monto y cuenta de destino" + }, "bridgeSelectTokenAndAmount": { "message": "Seleccione token y monto" }, @@ -944,6 +1004,12 @@ "message": "No se encontraron opciones", "description": "Default text shown in the combo field dropdown if no options." }, + "concentratedSupplyDistributionDescription": { + "message": "La mayor parte del suministro del token estĆ” en manos de los principales poseedores del token, lo que plantea un riesgo de manipulación centralizada de precios" + }, + "concentratedSupplyDistributionTitle": { + "message": "Distribución de suministro concentrado" + }, "configureSnapPopupDescription": { "message": "Ahora estĆ” saliendo de MetaMask para configurar este snap." }, @@ -962,6 +1028,15 @@ "confirm": { "message": "Confirmar" }, + "confirmAccountType": { + "message": "Tipo" + }, + "confirmAccountTypeSmartContract": { + "message": "Cuenta inteligente" + }, + "confirmAccountTypeStandard": { + "message": "Cuenta estĆ”ndar" + }, "confirmAlertModalAcknowledgeMultiple": { "message": "Soy consciente de las alertas y aun asĆ­ deseo continuar" }, @@ -974,12 +1049,36 @@ "confirmFieldTooltipPaymaster": { "message": "La tarifa de esta transacción la pagarĆ” el contrato inteligente del pagador." }, + "confirmGasFeeTokenBalance": { + "message": "Saldo:" + }, + "confirmGasFeeTokenInsufficientBalance": { + "message": "Fondos insuficientes" + }, + "confirmGasFeeTokenMetaMaskFee": { + "message": "Incluye tarifa de $1" + }, + "confirmGasFeeTokenModalTitle": { + "message": "Seleccione un token" + }, + "confirmGasFeeTokenToast": { + "message": "EstĆ” pagando esta tarifa de red con $1" + }, + "confirmGasFeeTokenTooltip": { + "message": "Esto se paga a la red para procesar su transacción. Incluye una comisión de $1 de MetaMask para tokens que no sean ETH." + }, + "confirmNestedTransactionTitle": { + "message": "Transacción $1" + }, "confirmPassword": { "message": "Confirmar contraseƱa" }, "confirmRecoveryPhrase": { "message": "Confirmar frase secreta de recuperación" }, + "confirmSimulationApprove": { + "message": "Aprueba" + }, "confirmTitleApproveTransactionNFT": { "message": "Solicitud de retiro" }, @@ -1022,9 +1121,24 @@ "confirmTitleTransaction": { "message": "Solicitud de transacción" }, + "confirmUpgradeCancelModalButtonCancelTransaction": { + "message": "Cancelar transacción" + }, + "confirmUpgradeCancelModalButtonCancelUpgrade": { + "message": "Cancelar actualización y transacción" + }, + "confirmUpgradeCancelModalDescription": { + "message": "Si no desea actualizar su cuenta, puede cancelarla aquĆ­.\n\nPara finalizar esta transacción sin una actualización, deberĆ” realizar esta solicitud nuevamente en el sitio. $1." + }, + "confirmUpgradeCancelModalTitle": { + "message": "Cancelar transacción" + }, "confirmationAlertDetails": { "message": "Para proteger sus activos, le sugerimos que rechace la solicitud." }, + "confirmationAlertModalTitleDescription": { + "message": "Sus activos podrĆ­an estar en riesgo" + }, "confirmed": { "message": "Confirmado" }, @@ -1052,6 +1166,9 @@ "connectAccounts": { "message": "Conectar cuentas" }, + "connectAnAccountHeader": { + "message": "Conectar una cuenta" + }, "connectManually": { "message": "Conectarse manualmente al sitio actual" }, @@ -1158,6 +1275,9 @@ "message": "Error al obtener $1, verifique su red y vuelva a intentarlo.", "description": "$1 is the name of the snap being fetched." }, + "connectionPopoverDescription": { + "message": "Para conectarse a un sitio, seleccione el botón de conexión. MetaMask solo puede conectarse a sitios Web3." + }, "connectionRequest": { "message": "Solicitud de conexión" }, @@ -1219,6 +1339,9 @@ "create": { "message": "Crear" }, + "createNewAccountHeader": { + "message": "Crear una nueva cuenta" + }, "createNewWallet": { "message": "Crear un monedero nuevo" }, @@ -1231,6 +1354,9 @@ "createSnapAccountTitle": { "message": "Crear cuenta" }, + "createSolanaAccount": { + "message": "Crear cuenta de Solana" + }, "creatorAddress": { "message": "Dirección del creador" }, @@ -1471,6 +1597,21 @@ "message": "Descripción de $1", "description": "$1 represents the name of the snap" }, + "destinationAccountPickerNoEligible": { + "message": "No se encontraron cuentas elegibles" + }, + "destinationAccountPickerNoMatching": { + "message": "No se encontraron cuentas coincidentes" + }, + "destinationAccountPickerReceiveAt": { + "message": "Recibir en" + }, + "destinationAccountPickerSearchPlaceholderToMainnet": { + "message": "Dirección receptora o ENS" + }, + "destinationAccountPickerSearchPlaceholderToSolana": { + "message": "Dirección receptora" + }, "details": { "message": "Detalles" }, @@ -1516,6 +1657,9 @@ "message": "$1 desconectada de $2", "description": "$1 is name of the name and $2 represents the dapp name`" }, + "discover": { + "message": "Descubrir" + }, "discoverSnaps": { "message": "Descubrir Snaps", "description": "Text that links to the Snaps website. Displayed in a banner on Snaps list page in settings." @@ -1872,6 +2016,9 @@ "experimental": { "message": "Experimental" }, + "exploreweb3": { + "message": "Explorar la Web3" + }, "exportYourData": { "message": "Exporte sus datos" }, @@ -1885,6 +2032,9 @@ "message": "Explore los Snaps creados por la comunidad para personalizar su experiencia web3", "description": "Banner description displayed on Snaps list page in Settings when less than 6 Snaps is installed." }, + "externalAccount": { + "message": "Cuenta externa" + }, "externalExtension": { "message": "Extensión externa" }, @@ -2197,6 +2347,12 @@ "holdToRevealUnlockedLabel": { "message": "mantenga presionado para revelar el cĆ­rculo desbloqueado" }, + "honeypotDescription": { + "message": "Este token podrĆ­a representar un riesgo de honeypot. Se recomienda realizar la debida diligencia antes de interactuar para evitar posibles pĆ©rdidas financieras." + }, + "honeypotTitle": { + "message": "Honeypot" + }, "howNetworkFeesWorkExplanation": { "message": "Tarifa estimada necesaria para procesar la transacción. La tarifa mĆ”xima es $1." }, @@ -2262,6 +2418,30 @@ "importNFTTokenIdToolTip": { "message": "La ID de un NFT es un identificador Ćŗnico, ya que no hay dos NFT iguales. Nuevamente, en OpenSea, este nĆŗmero se encuentra en 'Detalles'. Tome nota de ello o cópielo en su portapapeles." }, + "importNWordSRP": { + "message": "Tengo una frase de recuperación de $1 palabras", + "description": "$1 is the number of words in the recovery phrase" + }, + "importPrivateKey": { + "message": "Clave privada" + }, + "importSRPDescription": { + "message": "Importe una billetera existente con su frase secreta de recuperación de 12 o 24 palabras." + }, + "importSRPNumberOfWordsError": { + "message": "Las frases secretas de recuperación contienen 12 o 24 palabras" + }, + "importSRPWordError": { + "message": "La palabra $1 es incorrecta o estĆ” mal escrita.", + "description": "$1 is the word that is incorrect or misspelled" + }, + "importSRPWordErrorAlternative": { + "message": "Las palabras $1 y $2 son incorrectas o estĆ”n mal escritas.", + "description": "$1 and $2 are multiple words that are mispelled." + }, + "importSecretRecoveryPhrase": { + "message": "Importar frase secreta de recuperación" + }, "importSelectedTokens": { "message": "ĀæAgregar los tokens seleccionados?" }, @@ -2280,6 +2460,12 @@ "importTokensError": { "message": "No pudimos importar los tokens. Por favor, intĆ©ntelo de nuevo mĆ”s tarde." }, + "importWallet": { + "message": "Importar monedero" + }, + "importWalletOrAccountHeader": { + "message": "Importar un monedero o una cuenta" + }, "importWithCount": { "message": "Importar $1", "description": "$1 will the number of detected tokens that are selected for importing, if all of them are selected then $1 will be all" @@ -2327,6 +2513,12 @@ "insufficientFundsForGas": { "message": "Fondos insuficientes para el gas" }, + "insufficientLockedLiquidityDescription": { + "message": "La falta de liquidez adecuadamente bloqueada o quemada hace que el token sea vulnerable a retiros repentinos de liquidez, lo que podrĆ­a causar inestabilidad en el mercado." + }, + "insufficientLockedLiquidityTitle": { + "message": "Liquidez bloqueada insuficiente" + }, "insufficientTokens": { "message": "Tokens insuficientes." }, @@ -2362,6 +2554,9 @@ "invalidCustomNetworkAlertTitle": { "message": "Red personalizada no vĆ”lida" }, + "invalidHexData": { + "message": "Datos hexadecimales no vĆ”lidos" + }, "invalidHexNumber": { "message": "NĆŗmero hexadecimal no vĆ”lido." }, @@ -2540,6 +2735,9 @@ "ledgerLocked": { "message": "No se pudo establecer la conexión con el dispositivo Ledger. AsegĆŗrese de que el dispositivo estĆ” desbloqueado y que la aplicación de Ethereum estĆ” abierta." }, + "ledgerMultipleDevicesUnsupportedErrorMessage": { + "message": "No se pueden conectar varios dispositivos Ledger simultĆ”neamente. Para conectar un nuevo dispositivo Ledger, primero deberĆ” desconectar el anterior." + }, "ledgerTimeout": { "message": "Ledger Live tardó mucho en responder o se excedió el tiempo de espera de la conexión. AsegĆŗrese de que la aplicación de Ledger Live estĆ” abierta y que su dispositivo estĆ” desbloqueado." }, @@ -2637,6 +2835,9 @@ "manageDefaultSettings": { "message": "Gestionar la configuración de privacidad por defecto" }, + "managePermissions": { + "message": "Administrar permisos" + }, "marketCap": { "message": "Capitalización bursĆ”til" }, @@ -2755,6 +2956,15 @@ "multichainAddEthereumChainConfirmationDescription": { "message": "EstĆ” agregando esta red a MetaMask y otorgando permiso a este sitio para usarla." }, + "multichainQuoteCardBridgingLabel": { + "message": "Puenteo" + }, + "multichainQuoteCardQuoteLabel": { + "message": "Cotización" + }, + "multichainQuoteCardTimeLabel": { + "message": "Hora" + }, "multipleSnapConnectionWarning": { "message": "$1 quiere conectarse a $2", "description": "$1 is the dapp and $2 is the number of snaps it wants to connect to." @@ -2869,6 +3079,13 @@ "network": { "message": "Red:" }, + "networkChanged": { + "message": "La red cambió" + }, + "networkChangedMessage": { + "message": "Ahora estĆ” realizando transacciones en $1.", + "description": "$1 is the name of the network" + }, "networkDetails": { "message": "Detalles de la red" }, @@ -3143,6 +3360,9 @@ "notEnoughGas": { "message": "No hay gas suficiente" }, + "notNow": { + "message": "Ahora no" + }, "notificationDetail": { "message": "Detalles" }, @@ -3505,6 +3725,13 @@ "origin": { "message": "Origen" }, + "originChanged": { + "message": "El sitio cambió" + }, + "originChangedMessage": { + "message": "Ahora estĆ” revisando una solicitud de $1.", + "description": "$1 is the name of the origin" + }, "osTheme": { "message": "Sistema" }, @@ -3559,6 +3786,14 @@ "pending": { "message": "Pendiente" }, + "pendingConfirmationAddNetworkAlertMessage": { + "message": "La actualización de la red cancelarĆ” $1 transacciones pendientes de este sitio.", + "description": "Number of transactions." + }, + "pendingConfirmationSwitchNetworkAlertMessage": { + "message": "Al cambiar de red se cancelarĆ”n $1 transacciones pendientes de este sitio.", + "description": "Number of transactions." + }, "pendingTransactionAlertMessage": { "message": "Esta transacción no se realizarĆ” hasta que haya finalizado una transacción anterior. $1", "description": "$1 represents the words 'how to cancel or speed up a transaction' in a hyperlink" @@ -3842,6 +4077,9 @@ "permitSimulationChange_receive": { "message": "Usted recibe" }, + "permitSimulationChange_revoke2": { + "message": "Revocar" + }, "permitSimulationChange_transfer": { "message": "Usted envĆ­a" }, @@ -4237,6 +4475,9 @@ "reusedTokenNameWarning": { "message": "Un token reutiliza un sĆ­mbolo de otro token que se le muestra. Esto puede ser confuso o engaƱoso." }, + "revealSecretRecoveryPhrase": { + "message": "Revelar frase secreta de recuperación" + }, "revealSeedWords": { "message": "Revelar frase secreta de recuperación" }, @@ -4286,12 +4527,19 @@ "reviewAlerts": { "message": "Revisar alertas" }, + "reviewPendingTransactions": { + "message": "Revisar transacciones pendientes" + }, "reviewPermissions": { "message": "Revisar permisos" }, "revokePermission": { "message": "Revocar permiso" }, + "revokePermissionTitle": { + "message": "Eliminar permiso de $1", + "description": "The token symbol that is being revoked" + }, "revokeSimulationDetailsDesc": { "message": "EstĆ” eliminando el permiso de una persona para gastar tokens de su cuenta." }, @@ -4334,6 +4582,10 @@ "secretRecoveryPhrase": { "message": "Frase secreta de recuperación" }, + "secretRecoveryPhrasePlusNumber": { + "message": "Frase secreta de recuperación $1", + "description": "The $1 is the order of the Secret Recovery Phrase" + }, "secureWallet": { "message": "Proteger monedero" }, @@ -4424,6 +4676,9 @@ "select": { "message": "Seleccionar" }, + "selectAccountToConnect": { + "message": "Seleccione una cuenta para conectarse" + }, "selectAccounts": { "message": "Seleccionar cuentas" }, @@ -4454,6 +4709,9 @@ "selectRpcUrl": { "message": "Seleccionar URL de RPC" }, + "selectSecretRecoveryPhrase": { + "message": "Seleccionar frase secreta de recuperación" + }, "selectType": { "message": "Seleccionar tipo" }, @@ -4565,16 +4823,6 @@ "showHexDataDescription": { "message": "Seleccione esta opción para mostrar el campo de datos hexadecimales en la pantalla de envĆ­o" }, - "showIncomingTransactions": { - "message": "Mostrar transacciones entrantes" - }, - "showIncomingTransactionsDescription": { - "message": "Seleccione esta opción para usar Etherscan para mostrar las transacciones entrantes en la lista de transacciones", - "description": "$1 is the link to etherscan url and $2 is the link to the privacy policy of consensys APIs" - }, - "showIncomingTransactionsExplainer": { - "message": "Esto se basa en diferentes API de terceros para cada red, que exponen su dirección Ethereum y su dirección IP." - }, "showLess": { "message": "Mostrar menos" }, @@ -4593,6 +4841,9 @@ "showPrivateKey": { "message": "Mostrar clave privada" }, + "showSRP": { + "message": "Mostrar frase secreta de recuperación" + }, "showTestnetNetworks": { "message": "Mostrar redes de prueba" }, @@ -4714,12 +4965,24 @@ "slideCashOutTitle": { "message": "Retire su dinero con MetaMask" }, + "slideDebitCardDescription": { + "message": "Disponible en regiones seleccionadas" + }, "slideDebitCardTitle": { "message": "Tarjeta de dĆ©bito MetaMask" }, + "slideFundWalletDescription": { + "message": "AƱada o transfiera tokens para comenzar" + }, "slideFundWalletTitle": { "message": "AƱada fondos a su monedero" }, + "slideSweepStakeDescription": { + "message": "AcuƱe un NFT ahora para tener la oportunidad de ganar" + }, + "slideSweepStakeTitle": { + "message": "Ā”Participe en el sorteo de $5000 USDC!" + }, "smartContracts": { "message": "Contratos inteligentes" }, @@ -4866,6 +5129,9 @@ "snapResultSuccessDescription": { "message": "$1 estĆ” listo para usar" }, + "snapUIAssetSelectorTitle": { + "message": "Seleccione un activo" + }, "snapUpdateAlertDescription": { "message": "Obtenga la Ćŗltima versión de $1", "description": "Description used in Snap update alert banner when snap update is available. $1 is the Snap name." @@ -4925,6 +5191,27 @@ "message": "Póngase en contacto con los creadores de $1 para obtener mĆ”s ayuda.", "description": "This is shown when the insight snap throws an error. $1 is the snap name" }, + "solanaImportAccounts": { + "message": "Importar cuentas de Solana" + }, + "solanaImportAccountsDescription": { + "message": "Importe una frase secreta de recuperación para migrar su cuenta de Solana desde otro monedero." + }, + "solanaMoreFeaturesComingSoon": { + "message": "Próximamente habrĆ” mĆ”s funciones" + }, + "solanaMoreFeaturesComingSoonDescription": { + "message": "Próximamente, dapps de Solana, compatibilidad con NFT, monederos fĆ­sicos y mĆ”s." + }, + "solanaOnMetaMask": { + "message": "Solana en MetaMask" + }, + "solanaSendReceiveSwapTokens": { + "message": "EnvĆ­e, reciba e intercambie tokens" + }, + "solanaSendReceiveSwapTokensDescription": { + "message": "Transfiera y realice transacciones con tokens como SOL, USDC y mĆ”s." + }, "someNetworks": { "message": "Redes de $1" }, @@ -4951,6 +5238,21 @@ "source": { "message": "Fuente" }, + "spamModalBlockedDescription": { + "message": "Este sitio se bloquearĆ” por 1 minuto." + }, + "spamModalBlockedTitle": { + "message": "Ha bloqueado este sitio temporalmente" + }, + "spamModalDescription": { + "message": "Si recibe spam con varias solicitudes, puede bloquear el sitio temporalmente." + }, + "spamModalTemporaryBlockButton": { + "message": "Bloquear temporalmente este sitio" + }, + "spamModalTitle": { + "message": "Hemos notado varias solicitudes" + }, "speed": { "message": "Velocidad" }, @@ -5000,10 +5302,28 @@ "spendingCap": { "message": "LĆ­mite de gasto" }, + "spendingCaps": { + "message": "LĆ­mites de gasto" + }, "srpInputNumberOfWords": { "message": "Tengo una frase de $1 palabras", "description": "This is the text for each option in the dropdown where a user selects how many words their secret recovery phrase has during import. The $1 is the number of words (either 12, 15, 18, 21, or 24)." }, + "srpListName": { + "message": "Frase secreta de recuperación $1", + "description": "$1 is the order of the Secret Recovery Phrase" + }, + "srpListNumberOfAccounts": { + "message": "$1 cuentas", + "description": "$1 is the number of accounts in the list" + }, + "srpListSelectionDescription": { + "message": "La frase secreta de recuperación a partir de la cual se generarĆ” su nueva cuenta" + }, + "srpListSingleOrZero": { + "message": "$1 cuenta", + "description": "$1 is the number of accounts in the list, it is either 1 or 0" + }, "srpPasteFailedTooManyWords": { "message": "Pegar falló porque contenĆ­a mĆ”s de 24 palabras. Una frase secreta de recuperación puede tener un mĆ”ximo de 24 palabras.", "description": "Description of SRP paste error when the pasted content has too many words" @@ -5158,6 +5478,9 @@ "message": "Los cambios repentinos del mercado pueden causar fallas. Si el problema persiste, comunĆ­quese con $1.", "description": "This message is shown to a user if their swap fails. The $1 will be replaced by support.metamask.io" }, + "stxOptInSupportedNetworksDescription": { + "message": "Active las Transacciones inteligentes para realizar transacciones mĆ”s confiables y seguras en las redes compatibles. $1" + }, "stxPendingPrivatelySubmittingSwap": { "message": "Enviando su intercambio de forma privada..." }, @@ -5977,6 +6300,12 @@ "message": "Actualmente no se admite el envĆ­o de tokens NFT (ERC-721)", "description": "This is an error message we show the user if they attempt to send an NFT asset type, for which currently don't support sending" }, + "unstableTokenPriceDescription": { + "message": "El precio de este token en USD es muy volĆ”til, lo que indica un alto riesgo de perder valor significativo al interactuar con Ć©l." + }, + "unstableTokenPriceTitle": { + "message": "Precio inestable del token" + }, "upArrow": { "message": "flecha ascendente" }, @@ -6099,6 +6428,18 @@ "visitSite": { "message": "Visitar sitio" }, + "visitSupportDataConsentModalAccept": { + "message": "Confirmar" + }, + "visitSupportDataConsentModalDescription": { + "message": "ĀæDesea compartir su identificador de MetaMask y la versión de la aplicación con nuestro Centro de soporte tĆ©cnico? Esto puede ayudarnos a resolver mejor su problema, pero es opcional." + }, + "visitSupportDataConsentModalReject": { + "message": "No compartir" + }, + "visitSupportDataConsentModalTitle": { + "message": "Compartir detalles del dispositivo con soporte" + }, "visitWebSite": { "message": "Visite nuestro sitio web" }, diff --git a/app/_locales/es_419/messages.json b/app/_locales/es_419/messages.json index 4c89dd3d1890..db4974108bfa 100644 --- a/app/_locales/es_419/messages.json +++ b/app/_locales/es_419/messages.json @@ -1626,13 +1626,6 @@ "showHexDataDescription": { "message": "Seleccione esta opción para mostrar el campo de datos hexadecimales en la pantalla de envĆ­o" }, - "showIncomingTransactions": { - "message": "Mostrar transacciones entrantes" - }, - "showIncomingTransactionsDescription": { - "message": "Seleccione esta opción para usar Etherscan para mostrar las transacciones entrantes en la lista de transacciones", - "description": "$1 is the link to etherscan url and $2 is the link to the privacy policy of consensys APIs" - }, "showPermissions": { "message": "Mostrar permisos" }, diff --git a/app/_locales/fr/messages.json b/app/_locales/fr/messages.json index 3a1c4508351a..d2b0edb3e23f 100644 --- a/app/_locales/fr/messages.json +++ b/app/_locales/fr/messages.json @@ -44,6 +44,20 @@ "QRHardwareWalletSteps2Description": { "message": "Ngrave Zero" }, + "SrpListHideAccounts": { + "message": "Masquer $1 comptes", + "description": "$1 is the number of accounts" + }, + "SrpListHideSingleAccount": { + "message": "Masquer 1 compte" + }, + "SrpListShowAccounts": { + "message": "Afficher $1 comptes", + "description": "$1 is the number of accounts" + }, + "SrpListShowSingleAccount": { + "message": "Afficher 1 compte" + }, "about": { "message": "ƀ propos" }, @@ -76,6 +90,9 @@ "accountDetails": { "message": "DĆ©tails du compte" }, + "accountDetailsRevokeDelegationButton": { + "message": " Revenir au compte normal" + }, "accountIdenticon": { "message": "Identicon de compte" }, @@ -153,6 +170,12 @@ "addAlias": { "message": "Ajouter un alias" }, + "addBitcoinAccountLabel": { + "message": "Compte Bitcoin (BĆŖta)" + }, + "addBitcoinTestnetAccountLabel": { + "message": "Compte Bitcoin (Testnet)" + }, "addBlockExplorer": { "message": "Ajouter un explorateur de blocs" }, @@ -193,6 +216,9 @@ "addFriendsAndAddresses": { "message": "Ajoutez uniquement des amis et des adresses de confiance" }, + "addHardwareWalletLabel": { + "message": "Portefeuille matĆ©riel" + }, "addIPFSGateway": { "message": "Ajoutez votre passerelle IPFS prĆ©fĆ©rĆ©e" }, @@ -212,12 +238,26 @@ "addNewAccount": { "message": "Ajouter un nouveau compte Ethereum" }, + "addNewEthereumAccountLabel": { + "message": "Compte Ethereum" + }, + "addNewSolanaAccountLabel": { + "message": "Compte Solana" + }, "addNft": { "message": "Ajouter un NFT" }, "addNfts": { "message": "Ajouter des NFT" }, + "addNonEvmAccount": { + "message": "Ajouter un compte $1", + "description": "$1 is the non EVM network where the account is going to be created, e.g. Bitcoin or Solana" + }, + "addNonEvmAccountFromNetworkPicker": { + "message": "Pour activer le rĆ©seau $1, vous devez crĆ©er un compte $2.", + "description": "$1 is the non EVM network where the account is going to be created, e.g. Solana Mainnet or Solana Devnet. $2 is the account type, e.g. Bitcoin or Solana" + }, "addRpcUrl": { "message": "Ajouter l’URL du RPC" }, @@ -300,14 +340,16 @@ "advancedPriorityFeeToolTip": { "message": "Les frais de prioritĆ© (aussi appelĆ©s « pourboire du mineurĀ Ā») vont directement aux mineurs et les incitent Ć  accorder la prioritĆ© Ć  votre transaction." }, - "aggregatedBalancePopover": { - "message": "Cette valeur reflĆØte la valeur de tous les jetons que vous possĆ©dez sur un rĆ©seau donnĆ©. Si vous prĆ©fĆ©rez que cette valeur soit affichĆ©e en ETH ou dans d’autres monnaies, veuillez accĆ©der Ć  $1.", - "description": "$1 represents the settings page" - }, "agreeTermsOfUse": { "message": "J’accepte les $1 de MetaMask", "description": "$1 is the `terms` link" }, + "airDropPatternDescription": { + "message": "L’historique du jeton sur la chaĆ®ne rĆ©vĆØle des cas antĆ©rieurs d’activitĆ©s d’airdrop suspectes." + }, + "airDropPatternTitle": { + "message": "ModĆØle d’airdrop" + }, "airgapVault": { "message": "Coffre-fort AirGap" }, @@ -726,9 +768,21 @@ "bridgeConfirmTwoTransactions": { "message": "Vous devrez confirmer 2Ā transactions sur votre portefeuille matĆ©rielĀ :" }, + "bridgeCreateSolanaAccount": { + "message": "CrĆ©er un compte Solana" + }, + "bridgeCreateSolanaAccountDescription": { + "message": "Pour Ć©changer avec le rĆ©seau Solana, vous avez besoin d’un compte et d’une adresse de rĆ©ception." + }, + "bridgeCreateSolanaAccountTitle": { + "message": "Vous devez d’abord avoir un compte Solana." + }, "bridgeEnterAmount": { "message": "Saisissez le montant" }, + "bridgeEnterAmountAndSelectAccount": { + "message": "Entrez le montant et sĆ©lectionnez le compte de destination" + }, "bridgeExplorerLinkViewOn": { "message": "Consulter sur $1" }, @@ -751,9 +805,15 @@ "bridgeQuoteExpired": { "message": "Votre cotation a expirĆ©." }, + "bridgeSelectDestinationAccount": { + "message": "SĆ©lectionnez le compte de destination" + }, "bridgeSelectNetwork": { "message": "SĆ©lectionner un rĆ©seau" }, + "bridgeSelectTokenAmountAndAccount": { + "message": "SĆ©lectionnez le jeton, le montant et le compte de destination" + }, "bridgeSelectTokenAndAmount": { "message": "SĆ©lectionnez le jeton et le montant" }, @@ -944,6 +1004,12 @@ "message": "Aucune option trouvĆ©e", "description": "Default text shown in the combo field dropdown if no options." }, + "concentratedSupplyDistributionDescription": { + "message": "La majoritĆ© de l’offre de jetons est dĆ©tenue par les principaux dĆ©tenteurs de jetons, ce qui prĆ©sente un risque de manipulation centralisĆ©e des prix" + }, + "concentratedSupplyDistributionTitle": { + "message": "Distribution concentrĆ©e de l'offre" + }, "configureSnapPopupDescription": { "message": "Vous devez maintenant quitter MetaMask pour configurer ce snap." }, @@ -962,6 +1028,15 @@ "confirm": { "message": "Confirmer" }, + "confirmAccountType": { + "message": "Type" + }, + "confirmAccountTypeSmartContract": { + "message": "Compte intelligent" + }, + "confirmAccountTypeStandard": { + "message": "Compte standard" + }, "confirmAlertModalAcknowledgeMultiple": { "message": "J’ai pris connaissance des alertes, mais je souhaite quand mĆŖme continuer" }, @@ -974,12 +1049,36 @@ "confirmFieldTooltipPaymaster": { "message": "Les frais de cette transaction seront payĆ©s par le contrat « PaymasterĀ Ā» intelligent." }, + "confirmGasFeeTokenBalance": { + "message": "SoldeĀ :" + }, + "confirmGasFeeTokenInsufficientBalance": { + "message": "Fonds insuffisants" + }, + "confirmGasFeeTokenMetaMaskFee": { + "message": "Comprend des frais de $1" + }, + "confirmGasFeeTokenModalTitle": { + "message": "SĆ©lectionner un jeton" + }, + "confirmGasFeeTokenToast": { + "message": "Vous payez ces frais de rĆ©seau avec $1" + }, + "confirmGasFeeTokenTooltip": { + "message": "Ces frais sont payĆ©s au rĆ©seau pour traiter votre transaction. Il inclut des frais de MetaMask de $1 pour les jetons non-ETH." + }, + "confirmNestedTransactionTitle": { + "message": "Transaction $1" + }, "confirmPassword": { "message": "Confirmer le mot de passe" }, "confirmRecoveryPhrase": { "message": "Confirmer la phrase secrĆØte de rĆ©cupĆ©ration" }, + "confirmSimulationApprove": { + "message": "Vous approuvez" + }, "confirmTitleApproveTransactionNFT": { "message": "Demande de retrait" }, @@ -1022,9 +1121,24 @@ "confirmTitleTransaction": { "message": "Demande de transaction" }, + "confirmUpgradeCancelModalButtonCancelTransaction": { + "message": "Annuler la transaction" + }, + "confirmUpgradeCancelModalButtonCancelUpgrade": { + "message": "Annuler la mise Ć  niveau et la transaction" + }, + "confirmUpgradeCancelModalDescription": { + "message": "Si vous ne souhaitez pas mettre Ć  niveau votre compte, vous pouvez l’annuler ici.\n\nPour finaliser cette transaction sans mise Ć  niveau, vous devrez soumettre Ć  nouveau cette demande sur le site. $1." + }, + "confirmUpgradeCancelModalTitle": { + "message": "Annuler la transaction" + }, "confirmationAlertDetails": { "message": "Pour protĆ©ger vos actifs, nous vous suggĆ©rons de rejeter la demande." }, + "confirmationAlertModalTitleDescription": { + "message": "Vous risquez de perdre une partie ou la totalitĆ© de vos actifs" + }, "confirmed": { "message": "ConfirmĆ©" }, @@ -1052,6 +1166,9 @@ "connectAccounts": { "message": "Connecter les comptes" }, + "connectAnAccountHeader": { + "message": "Connecter un compte" + }, "connectManually": { "message": "Se connecter manuellement au site actuel" }, @@ -1158,6 +1275,9 @@ "message": "L’extraction de $1 a Ć©chouĆ©, vĆ©rifiez votre connexion rĆ©seau et rĆ©essayez.", "description": "$1 is the name of the snap being fetched." }, + "connectionPopoverDescription": { + "message": "Pour vous connecter Ć  un site, sĆ©lectionnez le bouton de connexion. MetaMask ne peut se connecter qu’à des sitesĀ Web3." + }, "connectionRequest": { "message": "Demande de connexion" }, @@ -1219,6 +1339,9 @@ "create": { "message": "CrĆ©er" }, + "createNewAccountHeader": { + "message": "CrĆ©er un nouveau compte" + }, "createNewWallet": { "message": "CrĆ©er un nouveau portefeuille" }, @@ -1231,6 +1354,9 @@ "createSnapAccountTitle": { "message": "CrĆ©er un compte" }, + "createSolanaAccount": { + "message": "CrĆ©er un compte Solana" + }, "creatorAddress": { "message": "Adresse du crĆ©ateur" }, @@ -1471,6 +1597,21 @@ "message": "Description provenant de $1", "description": "$1 represents the name of the snap" }, + "destinationAccountPickerNoEligible": { + "message": "Aucun compte admissible n’a Ć©tĆ© trouvĆ©" + }, + "destinationAccountPickerNoMatching": { + "message": "Aucun compte correspondant n’a Ć©tĆ© trouvĆ©" + }, + "destinationAccountPickerReceiveAt": { + "message": "Recevoir sur" + }, + "destinationAccountPickerSearchPlaceholderToMainnet": { + "message": "Adresse de rĆ©ception ou ENS" + }, + "destinationAccountPickerSearchPlaceholderToSolana": { + "message": "Adresse de rĆ©ception" + }, "details": { "message": "DĆ©tails" }, @@ -1516,6 +1657,9 @@ "message": "$1 dĆ©connectĆ© de $2", "description": "$1 is name of the name and $2 represents the dapp name`" }, + "discover": { + "message": "DĆ©couvrir" + }, "discoverSnaps": { "message": "DĆ©couvrir des Snaps", "description": "Text that links to the Snaps website. Displayed in a banner on Snaps list page in settings." @@ -1872,6 +2016,9 @@ "experimental": { "message": "ExpĆ©rimental" }, + "exploreweb3": { + "message": "Explorer le Web3" + }, "exportYourData": { "message": "Exportez vos donnĆ©es" }, @@ -1885,6 +2032,9 @@ "message": "Explorez les Snaps crƩƩs par la communautĆ© pour personnaliser votre expĆ©rience web3", "description": "Banner description displayed on Snaps list page in Settings when less than 6 Snaps is installed." }, + "externalAccount": { + "message": "Compte externe" + }, "externalExtension": { "message": "Extension externe" }, @@ -2197,6 +2347,12 @@ "holdToRevealUnlockedLabel": { "message": "appuyez longuement pour rĆ©vĆ©ler le cercle dĆ©verrouillĆ©" }, + "honeypotDescription": { + "message": "Ce jeton peut prĆ©senter un risque d’arnaque au pot de miel. Il est conseillĆ© de faire preuve de diligence raisonnable avant d’interagir ce jeton afin d’éviter toute perte financiĆØre potentielle." + }, + "honeypotTitle": { + "message": "Pot de miel" + }, "howNetworkFeesWorkExplanation": { "message": "Estimation des frais requis pour traiter la transaction. Le montant maximum des frais est de $1." }, @@ -2262,6 +2418,30 @@ "importNFTTokenIdToolTip": { "message": "L’ID d’un NFT est un identifiant unique puisqu’il n’y a pas deux NFT identiques. Encore une fois, sur OpenSea, ce numĆ©ro se trouve dans la section « DĆ©tailsĀ Ā». Prenez-en note ou copiez-le dans votre presse-papiers." }, + "importNWordSRP": { + "message": "J’ai une phrase de rĆ©cupĆ©ration de $1Ā mots", + "description": "$1 is the number of words in the recovery phrase" + }, + "importPrivateKey": { + "message": "ClĆ© privĆ©e" + }, + "importSRPDescription": { + "message": "Importez un portefeuille existant en utilisant votre phrase secrĆØte de rĆ©cupĆ©ration de 12 ou 24Ā mots." + }, + "importSRPNumberOfWordsError": { + "message": "Les phrases secrĆØtes de rĆ©cupĆ©ration sont composĆ©es de 12 ou 24Ā mots" + }, + "importSRPWordError": { + "message": "Le mot $1 est incorrect ou mal orthographiĆ©.", + "description": "$1 is the word that is incorrect or misspelled" + }, + "importSRPWordErrorAlternative": { + "message": "Les mots $1 et $2 sont incorrects ou mal orthographiĆ©s.", + "description": "$1 and $2 are multiple words that are mispelled." + }, + "importSecretRecoveryPhrase": { + "message": "Importer la phrase secrĆØte de rĆ©cupĆ©ration" + }, "importSelectedTokens": { "message": "Voulez-vous importer les jetons sĆ©lectionnĆ©sĀ ?" }, @@ -2280,6 +2460,12 @@ "importTokensError": { "message": "Impossible d’importer les jetons. Veuillez ressayer plus tard." }, + "importWallet": { + "message": "Importer le portefeuille" + }, + "importWalletOrAccountHeader": { + "message": "Importer un portefeuille ou un compte" + }, "importWithCount": { "message": "Importer $1", "description": "$1 will the number of detected tokens that are selected for importing, if all of them are selected then $1 will be all" @@ -2327,6 +2513,12 @@ "insufficientFundsForGas": { "message": "Fonds insuffisants pour le carburant" }, + "insufficientLockedLiquidityDescription": { + "message": "L’absence de liquiditĆ©s bloquĆ©es ou brĆ»lĆ©es de maniĆØre adĆ©quate rend le jeton vulnĆ©rable aux retraits soudains de liquiditĆ©s, ce qui peut entraĆ®ner une instabilitĆ© du marchĆ©." + }, + "insufficientLockedLiquidityTitle": { + "message": "Insuffisance de liquiditĆ©s bloquĆ©es" + }, "insufficientTokens": { "message": "Jetons insuffisants." }, @@ -2362,6 +2554,9 @@ "invalidCustomNetworkAlertTitle": { "message": "RĆ©seau personnalisĆ© invalide" }, + "invalidHexData": { + "message": "DonnĆ©es hexadĆ©cimales non valides" + }, "invalidHexNumber": { "message": "NumĆ©ro hexadĆ©cimal invalide." }, @@ -2540,6 +2735,9 @@ "ledgerLocked": { "message": "Impossible de se connecter au dispositif Ledger. Veuillez vous assurer que votre pĆ©riphĆ©rique est dĆ©verrouillĆ© et que l’application Ethereum est ouverte." }, + "ledgerMultipleDevicesUnsupportedErrorMessage": { + "message": "Il n’est pas possible de connecter plusieurs dispositifs Ledger en mĆŖme temps. Vous devez d’abord dĆ©connecter le dispositif actuel avant d’en connecter un autre." + }, "ledgerTimeout": { "message": "Ledger Live met trop de temps Ć  rĆ©pondre ou la connexion est interrompue. Assurez-vous que l’application Ledger Live est bien ouverte et que votre appareil est dĆ©verrouillĆ©." }, @@ -2637,6 +2835,9 @@ "manageDefaultSettings": { "message": "GĆ©rer les paramĆØtres de confidentialitĆ© par dĆ©faut" }, + "managePermissions": { + "message": "GĆ©rer les autorisations" + }, "marketCap": { "message": "Capitalisation boursiĆØre" }, @@ -2755,6 +2956,15 @@ "multichainAddEthereumChainConfirmationDescription": { "message": "Vous allez ajouter ce rĆ©seau Ć  MetaMask et donner Ć  ce site l’autorisation de l’utiliser." }, + "multichainQuoteCardBridgingLabel": { + "message": "Ɖtablissement d’une passerelle" + }, + "multichainQuoteCardQuoteLabel": { + "message": "Cotation" + }, + "multichainQuoteCardTimeLabel": { + "message": "Temps" + }, "multipleSnapConnectionWarning": { "message": "$1 veut utiliser $2 Snaps", "description": "$1 is the dapp and $2 is the number of snaps it wants to connect to." @@ -2869,6 +3079,13 @@ "network": { "message": "RĆ©seauĀ :" }, + "networkChanged": { + "message": "Le rĆ©seau a Ć©tĆ© modifiĆ©" + }, + "networkChangedMessage": { + "message": "Vous effectuez maintenant une transaction sur $1.", + "description": "$1 is the name of the network" + }, "networkDetails": { "message": "DĆ©tails du rĆ©seau" }, @@ -3143,6 +3360,9 @@ "notEnoughGas": { "message": "Pas assez de gaz" }, + "notNow": { + "message": "Pas maintenant" + }, "notificationDetail": { "message": "DĆ©tails" }, @@ -3505,6 +3725,13 @@ "origin": { "message": "Origine" }, + "originChanged": { + "message": "Le site a Ć©tĆ© modifiĆ©" + }, + "originChangedMessage": { + "message": "Vous ĆŖtes en train d’examiner une demande de $1.", + "description": "$1 is the name of the origin" + }, "osTheme": { "message": "SystĆØme" }, @@ -3559,6 +3786,14 @@ "pending": { "message": "En attente" }, + "pendingConfirmationAddNetworkAlertMessage": { + "message": "La mise Ć  jour du rĆ©seau annulera $1 transactions en attente sur ce site.", + "description": "Number of transactions." + }, + "pendingConfirmationSwitchNetworkAlertMessage": { + "message": "Le changement de rĆ©seau annulera $1 transactions en attente sur ce site.", + "description": "Number of transactions." + }, "pendingTransactionAlertMessage": { "message": "La transaction prĆ©cĆ©dente doit ĆŖtre finalisĆ©e avant que celle-ci ne soit traitĆ©e. $1", "description": "$1 represents the words 'how to cancel or speed up a transaction' in a hyperlink" @@ -3842,6 +4077,9 @@ "permitSimulationChange_receive": { "message": "Vous recevez" }, + "permitSimulationChange_revoke2": { + "message": "RĆ©voquer" + }, "permitSimulationChange_transfer": { "message": "Vous envoyez" }, @@ -4237,6 +4475,9 @@ "reusedTokenNameWarning": { "message": "L’un de ces jetons rĆ©utilise le symbole d’un autre jeton que vous surveillez, ce qui peut ĆŖtre dĆ©routant ou trompeur." }, + "revealSecretRecoveryPhrase": { + "message": "RĆ©vĆ©ler la phrase secrĆØte de rĆ©cupĆ©ration" + }, "revealSeedWords": { "message": "RĆ©vĆ©ler la phrase secrĆØte de rĆ©cupĆ©ration" }, @@ -4286,12 +4527,19 @@ "reviewAlerts": { "message": "Examiner les alertes" }, + "reviewPendingTransactions": { + "message": "Revoir les transactions en attente" + }, "reviewPermissions": { "message": "Revoir les autorisations" }, "revokePermission": { "message": "Retirer l'autorisation" }, + "revokePermissionTitle": { + "message": "RĆ©voquer l’autorisation de $1", + "description": "The token symbol that is being revoked" + }, "revokeSimulationDetailsDesc": { "message": "Vous rĆ©voquez l’autorisation que vous avez accordĆ©e Ć  quelqu’un d’autre de dĆ©penser des jetons Ć  partir de votre compte." }, @@ -4334,6 +4582,10 @@ "secretRecoveryPhrase": { "message": "Phrase secrĆØte de rĆ©cupĆ©ration" }, + "secretRecoveryPhrasePlusNumber": { + "message": "Phrase secrĆØte de rĆ©cupĆ©ration $1", + "description": "The $1 is the order of the Secret Recovery Phrase" + }, "secureWallet": { "message": "Portefeuille sĆ©curisĆ©" }, @@ -4424,6 +4676,9 @@ "select": { "message": "SĆ©lectionner" }, + "selectAccountToConnect": { + "message": "SĆ©lectionner un compte Ć  connecter" + }, "selectAccounts": { "message": "SĆ©lectionnez le(s) compte(s) Ć  utiliser sur ce site" }, @@ -4454,6 +4709,9 @@ "selectRpcUrl": { "message": "SĆ©lectionner l’URL du RPC" }, + "selectSecretRecoveryPhrase": { + "message": "SĆ©lectionnez la phrase secrĆØte de rĆ©cupĆ©ration" + }, "selectType": { "message": "SĆ©lectionner le type" }, @@ -4565,16 +4823,6 @@ "showHexDataDescription": { "message": "Selectionner ici pour afficher le champs de donnĆ©es hex dans l’écran d’envoi" }, - "showIncomingTransactions": { - "message": "Afficher les transactions entrantes" - }, - "showIncomingTransactionsDescription": { - "message": "SĆ©lectionnez ceci pour utiliser Etherscan afin d’afficher les transactions entrantes dans la liste des transactions", - "description": "$1 is the link to etherscan url and $2 is the link to the privacy policy of consensys APIs" - }, - "showIncomingTransactionsExplainer": { - "message": "Ce processus fait appel Ć  diffĆ©rentes API tierces pour chaque rĆ©seau et expose ainsi votre adresse Ethereum et votre adresse IP." - }, "showLess": { "message": "Afficher moins" }, @@ -4593,6 +4841,9 @@ "showPrivateKey": { "message": "Afficher la clĆ© privĆ©e" }, + "showSRP": { + "message": "Afficher la phrase secrĆØte de rĆ©cupĆ©ration" + }, "showTestnetNetworks": { "message": "Afficher les rĆ©seaux de test" }, @@ -4714,12 +4965,24 @@ "slideCashOutTitle": { "message": "Effectuez des retraits avec MetaMask" }, + "slideDebitCardDescription": { + "message": "Disponible dans certaines rĆ©gions" + }, "slideDebitCardTitle": { "message": "Carte de dĆ©bit MetaMask" }, + "slideFundWalletDescription": { + "message": "Ajoutez ou transfĆ©rez des jetons pour commencer" + }, "slideFundWalletTitle": { "message": "Approvisionnez votre portefeuille" }, + "slideSweepStakeDescription": { + "message": "Mintez un NFT maintenant pour avoir une chance de gagner" + }, + "slideSweepStakeTitle": { + "message": "Participez au tirage au sort qui vous permet de gagner $5000 USDCĀ !" + }, "smartContracts": { "message": "Contrats intelligents" }, @@ -4866,6 +5129,9 @@ "snapResultSuccessDescription": { "message": "$1 est prĆŖt Ć  ĆŖtre utilisĆ©" }, + "snapUIAssetSelectorTitle": { + "message": "SĆ©lectionner un actif" + }, "snapUpdateAlertDescription": { "message": "Obtenez la derniĆØre version de $1", "description": "Description used in Snap update alert banner when snap update is available. $1 is the Snap name." @@ -4925,6 +5191,27 @@ "message": "L’interface utilisateur (IU) spĆ©cifiĆ©e par le snap n’est pas valide.", "description": "This is shown when the insight snap throws an error. $1 is the snap name" }, + "solanaImportAccounts": { + "message": "Importer des comptes Solana" + }, + "solanaImportAccountsDescription": { + "message": "Importez une phrase secrĆØte de rĆ©cupĆ©ration pour faire migrer votre compte Solana depuis un autre portefeuille." + }, + "solanaMoreFeaturesComingSoon": { + "message": "D’autres fonctionnalitĆ©s seront bientĆ“t disponibles" + }, + "solanaMoreFeaturesComingSoonDescription": { + "message": "Les dapps Solana, les NFT, la prise en charge des portefeuilles matĆ©riels, etc., seront bientĆ“t disponibles." + }, + "solanaOnMetaMask": { + "message": "Solana sur MetaMask" + }, + "solanaSendReceiveSwapTokens": { + "message": "Envoyez, recevez et Ć©changez des jetons" + }, + "solanaSendReceiveSwapTokensDescription": { + "message": "TransfĆ©rez et effectuez des transactions avec des jetons tels que SOL, USDC, etc." + }, "someNetworks": { "message": "$1Ā rĆ©seaux" }, @@ -4951,6 +5238,21 @@ "source": { "message": "Source" }, + "spamModalBlockedDescription": { + "message": "Ce site sera bloquĆ© pendant 1Ā minute." + }, + "spamModalBlockedTitle": { + "message": "Vous avez temporairement bloquĆ© ce site" + }, + "spamModalDescription": { + "message": "Si vous ĆŖtes inondĆ© de demandes, vous pouvez bloquer temporairement le site." + }, + "spamModalTemporaryBlockButton": { + "message": "Bloquer temporairement ce site" + }, + "spamModalTitle": { + "message": "Nous avons remarquĆ© un afflux de demandes" + }, "speed": { "message": "Vitesse" }, @@ -5000,10 +5302,28 @@ "spendingCap": { "message": "Plafond de dĆ©penses" }, + "spendingCaps": { + "message": "Plafonds de dĆ©penses" + }, "srpInputNumberOfWords": { "message": "J’ai une phrase de $1Ā mots", "description": "This is the text for each option in the dropdown where a user selects how many words their secret recovery phrase has during import. The $1 is the number of words (either 12, 15, 18, 21, or 24)." }, + "srpListName": { + "message": "Phrase secrĆØte de rĆ©cupĆ©ration $1", + "description": "$1 is the order of the Secret Recovery Phrase" + }, + "srpListNumberOfAccounts": { + "message": "$1Ā comptes", + "description": "$1 is the number of accounts in the list" + }, + "srpListSelectionDescription": { + "message": "La phrase secrĆØte de rĆ©cupĆ©ration Ć  partir de laquelle votre nouveau compte sera gĆ©nĆ©rĆ©" + }, + "srpListSingleOrZero": { + "message": "$1Ā compte", + "description": "$1 is the number of accounts in the list, it is either 1 or 0" + }, "srpPasteFailedTooManyWords": { "message": "Le collage a Ć©chouĆ© parce que la phrase contenait plus de 24Ā mots. Une phrase secrĆØte de rĆ©cupĆ©ration peut contenir un maximum de 24Ā mots.", "description": "Description of SRP paste error when the pasted content has too many words" @@ -5158,6 +5478,9 @@ "message": "Les fluctuations soudaines du marchĆ© peuvent provoquer des Ć©checs. Si le problĆØme persiste, veuillez contacter $1.", "description": "This message is shown to a user if their swap fails. The $1 will be replaced by support.metamask.io" }, + "stxOptInSupportedNetworksDescription": { + "message": "Activez les transactions intelligentes pour profiter de transactions plus fiables et plus sĆ»res sur les rĆ©seaux pris en charge. $1" + }, "stxPendingPrivatelySubmittingSwap": { "message": "Soumission privĆ©e de votre Swap..." }, @@ -5977,6 +6300,12 @@ "message": "L’envoi de jetons NFT (ERC-721) n’est pas pris en charge actuellement", "description": "This is an error message we show the user if they attempt to send an NFT asset type, for which currently don't support sending" }, + "unstableTokenPriceDescription": { + "message": "Le prix de ce jeton en USD est extrĆŖmement volatil, ce qui signifie qu’il peut perdre rapidement de sa valeur." + }, + "unstableTokenPriceTitle": { + "message": "Prix du jeton instable" + }, "upArrow": { "message": "flĆØche vers le haut" }, @@ -6099,6 +6428,18 @@ "visitSite": { "message": "Visiter le site" }, + "visitSupportDataConsentModalAccept": { + "message": "Confirmer" + }, + "visitSupportDataConsentModalDescription": { + "message": "Voulez-vous partager votre identifiant MetaMask et la version de l’application que vous utilisez actuellement avec notre centre d’assistanceĀ ? Cela peut nous aider Ć  rĆ©soudre le problĆØme, mais vous n’êtes pas obligĆ© Ć  le faire." + }, + "visitSupportDataConsentModalReject": { + "message": "Ne pas partager" + }, + "visitSupportDataConsentModalTitle": { + "message": "Partager les dĆ©tails de l’appareil avec le centre d’assistance" + }, "visitWebSite": { "message": "Visitez notre site web" }, diff --git a/app/_locales/hi/messages.json b/app/_locales/hi/messages.json index dca88eef7dbd..f92b865b7036 100644 --- a/app/_locales/hi/messages.json +++ b/app/_locales/hi/messages.json @@ -44,6 +44,20 @@ "QRHardwareWalletSteps2Description": { "message": "Ngrave ą¤œą¤¼ą„€ą¤°ą„‹" }, + "SrpListHideAccounts": { + "message": "$1 ą¤ą¤•ą¤¾ą¤‰ą¤‚ą¤Ÿą„ą¤ø ą¤›ą¤æą¤Ŗą¤¾ą¤ą¤‚", + "description": "$1 is the number of accounts" + }, + "SrpListHideSingleAccount": { + "message": "1 ą¤…ą¤•ą¤¾ą¤‰ą¤‚ą¤Ÿ ą¤›ą¤æą¤Ŗą¤¾ą¤ą¤‚" + }, + "SrpListShowAccounts": { + "message": "$1 ą¤ą¤•ą¤¾ą¤‰ą¤‚ą¤Ÿą„ą¤ø ą¤¦ą¤æą¤–ą¤¾ą¤ą¤‚", + "description": "$1 is the number of accounts" + }, + "SrpListShowSingleAccount": { + "message": "1 ą¤…ą¤•ą¤¾ą¤‰ą¤‚ą¤Ÿ ą¤¦ą¤æą¤–ą¤¾ą¤ą¤‚" + }, "about": { "message": "ą¤‡ą¤øą¤•ą„‡ ą¤¬ą¤¾ą¤°ą„‡ ą¤®ą„‡ą¤‚" }, @@ -76,6 +90,9 @@ "accountDetails": { "message": "ą¤…ą¤•ą¤¾ą¤‰ą¤‚ą¤Ÿ ą¤•ą„€ ą¤œą¤¾ą¤Øą¤•ą¤¾ą¤°ą„€" }, + "accountDetailsRevokeDelegationButton": { + "message": " नियमित ą¤…ą¤•ą¤¾ą¤‰ą¤‚ą¤Ÿ पर वापस ą¤œą¤¾ą¤ą¤‚" + }, "accountIdenticon": { "message": "ą¤…ą¤•ą¤¾ą¤‰ą¤‚ą¤Ÿ ą¤†ą¤‡ą¤”ą„‡ą¤‚ą¤Ÿą¤æą¤•ą„‰ą¤Ø" }, @@ -153,6 +170,12 @@ "addAlias": { "message": "उपनाम ą¤œą„‹ą¤”ą¤¼ą„‡ą¤‚" }, + "addBitcoinAccountLabel": { + "message": "Bitcoin ą¤…ą¤•ą¤¾ą¤‰ą¤‚ą¤Ÿ (ą¤¬ą„€ą¤Ÿą¤¾)" + }, + "addBitcoinTestnetAccountLabel": { + "message": "Bitcoin ą¤…ą¤•ą¤¾ą¤‰ą¤‚ą¤Ÿ (ą¤Ÿą„ˆą¤øą„ą¤Ÿą¤Øą„‡ą¤Ÿ (testnet))" + }, "addBlockExplorer": { "message": "ą¤¬ą„ą¤²ą„‰ą¤• ą¤ą¤•ą„ą¤øą¤Ŗą„ą¤²ą„‹ą¤°ą¤° ą¤œą„‹ą¤”ą¤¼ą„‡ą¤‚" }, @@ -193,6 +216,9 @@ "addFriendsAndAddresses": { "message": "उन ą¤®ą¤æą¤¤ą„ą¤°ą„‹ą¤‚ और ą¤Ŗą¤¤ą„‹ą¤‚ ą¤•ą„‹ ą¤œą„‹ą¤”ą¤¼ą„‡ą¤‚, जिन पर आप ą¤­ą¤°ą„‹ą¤øą¤¾ ą¤•ą¤°ą¤¤ą„‡ ą¤¹ą„ˆą¤‚" }, + "addHardwareWalletLabel": { + "message": "ą¤¹ą¤¾ą¤°ą„ą¤”ą¤µą„‡ą¤Æą¤° ą¤µą„‰ą¤²ą„‡ą¤Ÿ" + }, "addIPFSGateway": { "message": "अपना ą¤Ŗą¤øą¤‚ą¤¦ą„€ą¤¦ą¤¾ IPFS ą¤—ą„‡ą¤Ÿą¤µą„‡ ą¤œą„‹ą„œą„‡ą¤‚" }, @@ -212,12 +238,26 @@ "addNewAccount": { "message": "ą¤ą¤• नया Ethereum ą¤…ą¤•ą¤¾ą¤‰ą¤‚ą¤Ÿ ą¤œą„‹ą¤”ą¤¼ą„‡ą¤‚" }, + "addNewEthereumAccountLabel": { + "message": "Ethereum ą¤…ą¤•ą¤¾ą¤‰ą¤‚ą¤Ÿ" + }, + "addNewSolanaAccountLabel": { + "message": "Solana ą¤…ą¤•ą¤¾ą¤‰ą¤‚ą¤Ÿ" + }, "addNft": { "message": "NFT ą¤œą„‹ą¤”ą¤¼ą„‡ą¤‚" }, "addNfts": { "message": "NFTs ą¤œą„‹ą¤”ą¤¼ą„‡ą¤‚" }, + "addNonEvmAccount": { + "message": "$1 ą¤…ą¤•ą¤¾ą¤‰ą¤‚ą¤Ÿ ą¤œą„‹ą¤”ą¤¼ą„‡ą¤‚", + "description": "$1 is the non EVM network where the account is going to be created, e.g. Bitcoin or Solana" + }, + "addNonEvmAccountFromNetworkPicker": { + "message": "$1 ą¤Øą„‡ą¤Ÿą¤µą¤°ą„ą¤• ą¤•ą„‹ ą¤šą¤¾ą¤²ą„‚ ą¤•ą¤°ą¤Øą„‡ ą¤•ą„‡ ą¤²ą¤æą¤, ą¤†ą¤Ŗą¤•ą„‹ $2 ą¤…ą¤•ą¤¾ą¤‰ą¤‚ą¤Ÿ बनाना ą¤¹ą„‹ą¤—ą¤¾ą„¤", + "description": "$1 is the non EVM network where the account is going to be created, e.g. Solana Mainnet or Solana Devnet. $2 is the account type, e.g. Bitcoin or Solana" + }, "addRpcUrl": { "message": "RPC URL ą¤œą„‹ą„œą„‡ą¤‚" }, @@ -300,14 +340,16 @@ "advancedPriorityFeeToolTip": { "message": "ą¤Ŗą„ą¤°ą¤¾ą¤Æą„‹ą¤°ą¤æą¤Ÿą„€ ą„žą„€ą¤ø (ą¤‰ą¤°ą„ą¤« \"माइनर टिप\") ą¤øą„€ą¤§ą„‡ ą¤®ą¤¾ą¤‡ą¤Øą¤°ą„‹ą¤‚ ą¤•ą„‡ पास ą¤œą¤¾ą¤¤ą„€ ą¤¹ą„ˆ और ą¤‰ą¤Øą„ą¤¹ą„‡ą¤‚ ą¤†ą¤Ŗą¤•ą„‡ ą¤Ÿą„ą¤°ą¤¾ą¤‚ą¤øą„‡ą¤•ą„ą¤¶ą¤Ø ą¤•ą„‹ ą¤Ŗą„ą¤°ą¤¾ą¤„ą¤®ą¤æą¤•ą¤¤ą¤¾ ą¤¦ą„‡ą¤Øą„‡ ą¤•ą„‡ ą¤²ą¤æą¤ ą¤Ŗą„ą¤°ą„‹ą¤¤ą„ą¤øą¤¾ą¤¹ą¤æą¤¤ ą¤•ą¤°ą¤¤ą„€ ą¤¹ą„ˆą„¤" }, - "aggregatedBalancePopover": { - "message": "यह ą¤•ą¤æą¤øą„€ ą¤¦ą¤æą¤ ą¤—ą¤ ą¤Øą„‡ą¤Ÿą¤µą¤°ą„ą¤• पर ą¤†ą¤Ŗą¤•ą„‡ ą¤øą„ą¤µą¤¾ą¤®ą¤æą¤¤ą„ą¤µ ą¤µą¤¾ą¤²ą„‡ ą¤øą¤­ą„€ ą¤Ÿą„‹ą¤•ą¤Ø ą¤•ą„‡ ą¤®ą„‚ą¤²ą„ą¤Æ ą¤•ą„‹ ą¤¦ą¤°ą„ą¤¶ą¤¾ą¤¤ą¤¾ ą¤¹ą„ˆą„¤ यदि आप इस ą¤®ą„‚ą¤²ą„ą¤Æ ą¤•ą„‹ ETH या ą¤…ą¤Øą„ą¤Æ ą¤®ą„ą¤¦ą„ą¤°ą¤¾ą¤“ą¤‚ ą¤®ą„‡ą¤‚ ą¤¦ą„‡ą¤–ą¤Øą¤¾ पसंद ą¤•ą¤°ą¤¤ą„‡ ą¤¹ą„ˆą¤‚, ą¤¤ą„‹ $1 पर ą¤œą¤¾ą¤ą¤‚ą„¤", - "description": "$1 represents the settings page" - }, "agreeTermsOfUse": { "message": "ą¤®ą„ˆą¤‚ MetaMask ą¤•ą„‡ $1 ą¤øą„‡ सहमत ą¤¹ą„‚ą¤‚", "description": "$1 is the `terms` link" }, + "airDropPatternDescription": { + "message": "ą¤Ÿą„‹ą¤•ą¤Ø ą¤•ą„‡ ऑन-ą¤šą„‡ą¤Ø इतिहास ą¤øą„‡ ą¤øą¤‚ą¤¦ą¤æą¤—ą„ą¤§ ą¤ą¤Æą¤°ą¤”ą„ą¤°ą„‰ą¤Ŗ ą¤—ą¤¤ą¤æą¤µą¤æą¤§ą¤æą¤Æą„‹ą¤‚ ą¤•ą„‡ ą¤Ŗą„‚ą¤°ą„ą¤µ ą¤‰ą¤¦ą¤¾ą¤¹ą¤°ą¤£ą„‹ą¤‚ का पता चलता ą¤¹ą„ˆą„¤" + }, + "airDropPatternTitle": { + "message": "ą¤ą¤Æą¤°ą¤”ą„ą¤°ą„‰ą¤Ŗ ą¤Ŗą„ˆą¤Ÿą¤°ą„ą¤Ø" + }, "airgapVault": { "message": "AirGap Vault" }, @@ -726,9 +768,21 @@ "bridgeConfirmTwoTransactions": { "message": "ą¤†ą¤Ŗą¤•ą„‹ ą¤…ą¤Ŗą¤Øą„‡ ą¤¹ą¤¾ą¤°ą„ą¤”ą¤µą„‡ą¤Æą¤° ą¤µą„‰ą¤²ą„‡ą¤Ÿ पर 2 ą¤Ÿą„ą¤°ą¤¾ą¤‚ą¤øą„‡ą¤•ą„ą¤¶ą¤Ø ą¤•ą¤Øą„ą¤«ą¤°ą„ą¤® ą¤•ą¤°ą¤Øą„€ ą¤¹ą„‹ą¤—ą„€:" }, + "bridgeCreateSolanaAccount": { + "message": "Solana ą¤…ą¤•ą¤¾ą¤‰ą¤‚ą¤Ÿ ą¤¬ą¤Øą¤¾ą¤ą¤‚" + }, + "bridgeCreateSolanaAccountDescription": { + "message": "Solana ą¤Øą„‡ą¤Ÿą¤µą¤°ą„ą¤• पर ą¤øą„ą¤µą„ˆą¤Ŗ ą¤•ą¤°ą¤Øą„‡ ą¤•ą„‡ ą¤²ą¤æą¤, ą¤†ą¤Ŗą¤•ą„‹ ą¤ą¤• ą¤…ą¤•ą¤¾ą¤‰ą¤‚ą¤Ÿ और ą¤Ŗą„ą¤°ą¤¾ą¤Ŗą„ą¤¤ ą¤•ą¤°ą¤Øą„‡ ą¤µą¤¾ą¤²ą„€ ą¤ą¤”ą„ą¤°ą„‡ą¤ø ą¤•ą„€ ą¤†ą¤µą¤¶ą„ą¤Æą¤•ą¤¤ą¤¾ ą¤¹ą„‹ą¤—ą„€ą„¤" + }, + "bridgeCreateSolanaAccountTitle": { + "message": "ą¤øą¤¬ą¤øą„‡ ą¤Ŗą¤¹ą¤²ą„‡ ą¤†ą¤Ŗą¤•ą„‹ Solana ą¤…ą¤•ą¤¾ą¤‰ą¤‚ą¤Ÿ ą¤•ą„€ ą¤†ą¤µą¤¶ą„ą¤Æą¤•ą¤¤ą¤¾ ą¤¹ą„‹ą¤—ą„€ą„¤" + }, "bridgeEnterAmount": { "message": "रकम ą¤”ą¤¾ą¤²ą„‡ą¤‚" }, + "bridgeEnterAmountAndSelectAccount": { + "message": "राशि ą¤¦ą¤°ą„ą¤œ ą¤•ą¤°ą„‡ą¤‚ और ą¤—ą¤‚ą¤¤ą¤µą„ą¤Æ ą¤…ą¤•ą¤¾ą¤‰ą¤‚ą¤Ÿ ą¤šą„ą¤Øą„‡ą¤‚" + }, "bridgeExplorerLinkViewOn": { "message": "$1 पर ą¤¦ą„‡ą¤–ą„‡ą¤‚" }, @@ -751,9 +805,15 @@ "bridgeQuoteExpired": { "message": "आपका ą¤•ą„‹ą¤Ÿ ą¤•ą¤°ą¤Øą„‡ का समय ą¤øą¤®ą¤¾ą¤Ŗą„ą¤¤ ą¤¹ą„‹ गया ą¤¹ą„ˆ" }, + "bridgeSelectDestinationAccount": { + "message": "ą¤—ą¤‚ą¤¤ą¤µą„ą¤Æ ą¤…ą¤•ą¤¾ą¤‰ą¤‚ą¤Ÿ ą¤šą„ą¤Øą„‡ą¤‚" + }, "bridgeSelectNetwork": { "message": "ą¤Øą„‡ą¤Ÿą¤µą¤°ą„ą¤• ą¤•ą„‹ ą¤šą„ą¤Øą„‡ą¤‚" }, + "bridgeSelectTokenAmountAndAccount": { + "message": "ą¤Ÿą„‹ą¤•ą¤Ø, राशि और ą¤—ą¤‚ą¤¤ą¤µą„ą¤Æ ą¤…ą¤•ą¤¾ą¤‰ą¤‚ą¤Ÿ ą¤šą„ą¤Øą„‡ą¤‚" + }, "bridgeSelectTokenAndAmount": { "message": "ą¤Ÿą„‹ą¤•ą¤Ø और रकम का चयन ą¤•ą¤°ą„‡ą¤‚" }, @@ -944,6 +1004,12 @@ "message": "ą¤•ą„‹ą¤ˆ ą¤µą¤æą¤•ą¤²ą„ą¤Ŗ ą¤Øą¤¹ą„€ą¤‚ मिला", "description": "Default text shown in the combo field dropdown if no options." }, + "concentratedSupplyDistributionDescription": { + "message": "ą¤Ÿą„‹ą¤•ą¤Ø ą¤•ą„€ अधिकांश ą¤†ą¤Ŗą„‚ą¤°ą„ą¤¤ą¤æ ą¤¶ą„€ą¤°ą„ą¤· ą¤Ÿą„‹ą¤•ą¤Ø ą¤§ą¤¾ą¤°ą¤•ą„‹ą¤‚ ą¤•ą„‡ पास ą¤¹ą„‹ą¤¤ą„€ ą¤¹ą„ˆ, ą¤œą¤æą¤øą¤øą„‡ ą¤øą„‡ą¤‚ą¤Ÿą„ą¤°ą¤²ą¤¾ą¤‡ą¤œą„ą¤” ą¤®ą„‚ą¤²ą„ą¤Æ ą¤øą¤‚ą¤¬ą¤‚ą¤§ą„€ ą¤¹ą„‡ą¤°ą¤«ą„‡ą¤° का ą¤œą„‹ą¤–ą¤æą¤® ą¤Ŗą„ˆą¤¦ą¤¾ ą¤¹ą„‹ą¤¤ą¤¾ ą¤¹ą„ˆ" + }, + "concentratedSupplyDistributionTitle": { + "message": "ą¤øą¤‚ą¤•ą„‡ą¤Øą„ą¤¦ą„ą¤°ą¤æą¤¤ ą¤†ą¤Ŗą„‚ą¤°ą„ą¤¤ą¤æ वितरण" + }, "configureSnapPopupDescription": { "message": "अब आप इस Snap ą¤•ą„‹ ą¤•ą„‰ą¤Øą„ą¤«ą¤æą¤—ą¤° ą¤•ą¤°ą¤Øą„‡ ą¤•ą„‡ ą¤²ą¤æą¤ MetaMask ą¤øą„‡ बाहर जा ą¤°ą¤¹ą„‡ ą¤¹ą„ˆą¤‚ą„¤" }, @@ -962,6 +1028,15 @@ "confirm": { "message": "ą¤•ą¤Øą„ą¤«ą¤°ą„ą¤® ą¤•ą¤°ą„‡ą¤‚" }, + "confirmAccountType": { + "message": "ą¤Ŗą„ą¤°ą¤•ą¤¾ą¤°" + }, + "confirmAccountTypeSmartContract": { + "message": "ą¤øą„ą¤®ą¤¾ą¤°ą„ą¤Ÿ ą¤…ą¤•ą¤¾ą¤‰ą¤‚ą¤Ÿ" + }, + "confirmAccountTypeStandard": { + "message": "मानक ą¤…ą¤•ą¤¾ą¤‰ą¤‚ą¤Ÿ" + }, "confirmAlertModalAcknowledgeMultiple": { "message": "ą¤®ą„ˆą¤‚ą¤Øą„‡ ą¤ą¤²ą¤°ą„ą¤Ÿ ą¤•ą„‹ ą¤øą„ą¤µą„€ą¤•ą¤¾ą¤° कर लिया ą¤¹ą„ˆ और ą¤‡ą¤øą¤•ą„‡ ą¤¬ą¤¾ą¤µą¤œą„‚ą¤¦ ą¤†ą¤—ą„‡ बढ़ना चाहता/ą¤šą¤¾ą¤¹ą¤¤ą„€ ą¤¹ą„‚ą¤‚" }, @@ -974,12 +1049,36 @@ "confirmFieldTooltipPaymaster": { "message": "इस ą¤Ÿą„ą¤°ą¤¾ą¤‚ą¤øą„‡ą¤•ą„ą¤¶ą¤Ø ą¤•ą„‡ ą¤²ą¤æą¤ ą¤¶ą„ą¤²ą„ą¤• का ą¤­ą„ą¤—ą¤¤ą¤¾ą¤Ø ą¤Ŗą„‡ą¤®ą¤¾ą¤øą„ą¤Ÿą¤° ą¤øą„ą¤®ą¤¾ą¤°ą„ą¤Ÿ ą¤•ą„‰ą¤Øą„ą¤Ÿą„ą¤°ą„ˆą¤•ą„ą¤Ÿ ą¤¦ą„ą¤µą¤¾ą¤°ą¤¾ किया ą¤œą¤¾ą¤ą¤—ą¤¾ą„¤" }, + "confirmGasFeeTokenBalance": { + "message": "ą¤¬ą„ˆą¤²:" + }, + "confirmGasFeeTokenInsufficientBalance": { + "message": "ą¤…ą¤Ŗą¤°ą„ą¤Æą¤¾ą¤Ŗą„ą¤¤ फंऔ" + }, + "confirmGasFeeTokenMetaMaskFee": { + "message": "ą¤‡ą¤øą¤®ą„‡ą¤‚ $1 ą¤¶ą„ą¤²ą„ą¤• शामिल ą¤¹ą„ˆ" + }, + "confirmGasFeeTokenModalTitle": { + "message": "ą¤ą¤• ą¤Ÿą„‹ą¤•ą¤Ø ą¤šą„ą¤Øą„‡ą¤‚" + }, + "confirmGasFeeTokenToast": { + "message": "आप इस ą¤Øą„‡ą¤Ÿą¤µą¤°ą„ą¤• ą¤¶ą„ą¤²ą„ą¤• का ą¤­ą„ą¤—ą¤¤ą¤¾ą¤Ø $1 ą¤øą„‡ कर ą¤°ą¤¹ą„‡ ą¤¹ą„ˆą¤‚" + }, + "confirmGasFeeTokenTooltip": { + "message": "यह ą¤†ą¤Ŗą¤•ą„‡ ą¤Ÿą„ą¤°ą¤¾ą¤‚ą¤øą„‡ą¤•ą„ą¤¶ą¤Ø ą¤•ą„‹ ą¤Ŗą„ą¤°ą„‹ą¤øą„‡ą¤ø ą¤•ą¤°ą¤Øą„‡ ą¤•ą„‡ ą¤²ą¤æą¤ ą¤Øą„‡ą¤Ÿą¤µą¤°ą„ą¤• ą¤•ą„‹ ą¤­ą„ą¤—ą¤¤ą¤¾ą¤Ø किया जाता ą¤¹ą„ˆą„¤ ą¤‡ą¤øą¤®ą„‡ą¤‚ ą¤—ą„ˆą¤°-ETH ą¤Ÿą„‹ą¤•ą¤Ø ą¤•ą„‡ ą¤²ą¤æą¤ $1 MetaMask ą¤¶ą„ą¤²ą„ą¤• शामिल ą¤¹ą„ˆą„¤" + }, + "confirmNestedTransactionTitle": { + "message": "ą¤Ÿą„ą¤°ą¤¾ą¤‚ą¤øą„‡ą¤•ą„ą¤¶ą¤Ø $1" + }, "confirmPassword": { "message": "ą¤Ŗą¤¾ą¤øą¤µą¤°ą„ą¤” ą¤•ą¤Øą„ą¤«ą¤°ą„ą¤® ą¤•ą¤°ą„‡ą¤‚" }, "confirmRecoveryPhrase": { "message": "ą¤øą„€ą¤•ą„ą¤°ą„‡ą¤Ÿ ą¤°ą¤æą¤•ą¤µą¤°ą„€ ą¤«ą„ą¤°ą„‡ą¤œ ą¤•ą¤Øą„ą¤«ą¤°ą„ą¤® ą¤•ą¤°ą„‡ą¤‚" }, + "confirmSimulationApprove": { + "message": "आप ą¤ą¤Ŗą„ą¤°ą„‚ą¤µ ą¤•ą¤°ą¤¤ą„‡ ą¤¹ą„ˆą¤‚" + }, "confirmTitleApproveTransactionNFT": { "message": "ą¤µą¤æą¤¦ą¤”ą„ą¤°ą„‰ą¤µą¤² का ą¤…ą¤Øą„ą¤°ą„‹ą¤§" }, @@ -1022,9 +1121,24 @@ "confirmTitleTransaction": { "message": "ą¤Ÿą„ą¤°ą¤¾ą¤‚ą¤øą„‡ą¤•ą„ą¤¶ą¤Ø ą¤…ą¤Øą„ą¤°ą„‹ą¤§" }, + "confirmUpgradeCancelModalButtonCancelTransaction": { + "message": "ą¤Ÿą„ą¤°ą¤¾ą¤‚ą¤øą„‡ą¤•ą„ą¤¶ą¤Ø ą¤•ą„ˆą¤‚ą¤øą¤æą¤² ą¤•ą¤°ą„‡ą¤‚" + }, + "confirmUpgradeCancelModalButtonCancelUpgrade": { + "message": "ą¤…ą¤Ŗą¤”ą„‡ą¤Ÿ ą¤ą¤µą¤‚ ą¤Ÿą„ą¤°ą¤¾ą¤‚ą¤øą„‡ą¤•ą„ą¤¶ą¤Ø ą¤•ą„ˆą¤‚ą¤øą¤æą¤² ą¤•ą¤°ą„‡ą¤‚" + }, + "confirmUpgradeCancelModalDescription": { + "message": "यदि आप अपना ą¤…ą¤•ą¤¾ą¤‰ą¤‚ą¤Ÿ ą¤…ą¤Ŗą¤”ą„‡ą¤Ÿ ą¤Øą¤¹ą„€ą¤‚ करना ą¤šą¤¾ą¤¹ą¤¤ą„‡ ą¤¹ą„ˆą¤‚, ą¤¤ą„‹ आप ą¤‡ą¤øą„‡ यहाँ ą¤•ą„ˆą¤‚ą¤øą¤æą¤² कर ą¤øą¤•ą¤¤ą„‡ ą¤¹ą„ˆą¤‚ą„¤\n\nइस ą¤Ÿą„ą¤°ą¤¾ą¤‚ą¤øą„‡ą¤•ą„ą¤¶ą¤Ø ą¤•ą„‹ ą¤…ą¤Ŗą¤”ą„‡ą¤Ÿ ą¤•ą¤æą¤ बिना ą¤Ŗą„‚ą¤°ą¤¾ ą¤•ą¤°ą¤Øą„‡ ą¤•ą„‡ ą¤²ą¤æą¤, ą¤†ą¤Ŗą¤•ą„‹ ą¤øą¤¾ą¤‡ą¤Ÿ पर फिर ą¤øą„‡ यह ą¤…ą¤Øą„ą¤°ą„‹ą¤§ करना ą¤¹ą„‹ą¤—ą¤¾ą„¤ $1." + }, + "confirmUpgradeCancelModalTitle": { + "message": "ą¤Ÿą„ą¤°ą¤¾ą¤‚ą¤øą„‡ą¤•ą„ą¤¶ą¤Ø ą¤•ą„ˆą¤‚ą¤øą¤æą¤² ą¤•ą¤°ą„‡ą¤‚" + }, "confirmationAlertDetails": { "message": "ą¤†ą¤Ŗą¤•ą„€ ą¤ą¤øą„‡ą¤Ÿą„ą¤ø ą¤•ą„€ ą¤øą„ą¤°ą¤•ą„ą¤·ą¤¾ ą¤•ą„‡ ą¤²ą¤æą¤, हम ą¤†ą¤Ŗą¤•ą„‹ ą¤…ą¤Øą„ą¤°ą„‹ą¤§ ą¤•ą„‹ ą¤°ą¤æą¤œą„‡ą¤•ą„ą¤Ÿ ą¤•ą¤°ą¤Øą„‡ का ą¤øą„ą¤ą¤¾ą¤µ ą¤¦ą„‡ą¤¤ą„‡ ą¤¹ą„ˆą¤‚ą„¤" }, + "confirmationAlertModalTitleDescription": { + "message": "ą¤†ą¤Ŗą¤•ą„‡ ą¤ą¤øą„‡ą¤Ÿ ą¤–ą¤¤ą¤°ą„‡ ą¤®ą„‡ą¤‚ ą¤¹ą„‹ ą¤øą¤•ą¤¤ą„‡ ą¤¹ą„ˆą¤‚" + }, "confirmed": { "message": "ą¤•ą¤Øą„ą¤«ą¤°ą„ą¤® किया गया" }, @@ -1052,6 +1166,9 @@ "connectAccounts": { "message": "ą¤ą¤•ą¤¾ą¤‰ą¤‚ą¤Ÿą„ą¤ø ą¤•ą„‹ ą¤•ą¤Øą„‡ą¤•ą„ą¤Ÿ ą¤•ą¤°ą„‡ą¤‚" }, + "connectAnAccountHeader": { + "message": "ą¤•ą¤æą¤øą„€ ą¤…ą¤•ą¤¾ą¤‰ą¤‚ą¤Ÿ ą¤•ą„‹ ą¤•ą¤Øą„‡ą¤•ą„ą¤Ÿ ą¤•ą¤°ą„‡ą¤‚" + }, "connectManually": { "message": "ą¤µą¤°ą„ą¤¤ą¤®ą¤¾ą¤Ø ą¤øą¤¾ą¤‡ą¤Ÿ ą¤øą„‡ ą¤®ą„ˆą¤Øą„ą¤Æą„ą¤…ą¤² ą¤°ą„‚ą¤Ŗ ą¤øą„‡ ą¤•ą¤Øą„‡ą¤•ą„ą¤Ÿ ą¤•ą¤°ą„‡ą¤‚" }, @@ -1158,6 +1275,9 @@ "message": "$1 ą¤•ą„‹ लाना ą¤Øą¤¹ą„€ą¤‚ ą¤¹ą„‹ पाया, अपना ą¤Øą„‡ą¤Ÿą¤µą¤°ą„ą¤• ą¤œą¤¾ą¤‚ą¤šą„‡ą¤‚ और ą¤¦ą„‹ą¤¬ą¤¾ą¤°ą¤¾ ą¤•ą„‹ą¤¶ą¤æą¤¶ ą¤•ą¤°ą„‡ą¤‚ą„¤", "description": "$1 is the name of the snap being fetched." }, + "connectionPopoverDescription": { + "message": "ą¤•ą¤æą¤øą„€ ą¤øą¤¾ą¤‡ą¤Ÿ ą¤øą„‡ ą¤•ą¤Øą„‡ą¤•ą„ą¤Ÿ ą¤•ą¤°ą¤Øą„‡ ą¤•ą„‡ ą¤²ą¤æą¤, ą¤•ą¤Øą„‡ą¤•ą„ą¤Ÿ बटन का चयन ą¤•ą¤°ą„‡ą¤‚ą„¤ MetaMask ą¤•ą„‡ą¤µą¤² Web3 ą¤øą¤¾ą¤‡ą¤Ÿą„‹ą¤‚ ą¤øą„‡ ą¤•ą¤Øą„‡ą¤•ą„ą¤Ÿ ą¤¹ą„‹ सकता ą¤¹ą„ˆą„¤" + }, "connectionRequest": { "message": "ą¤•ą¤Øą„‡ą¤•ą„ą¤¶ą¤Ø ą¤…ą¤Øą„ą¤°ą„‹ą¤§" }, @@ -1219,6 +1339,9 @@ "create": { "message": "ą¤¬ą¤Øą¤¾ą¤ą¤‚" }, + "createNewAccountHeader": { + "message": "ą¤ą¤• नया ą¤…ą¤•ą¤¾ą¤‰ą¤‚ą¤Ÿ ą¤¬ą¤Øą¤¾ą¤ą¤‚" + }, "createNewWallet": { "message": "ą¤ą¤• नया ą¤µą„‰ą¤²ą„‡ą¤Ÿ ą¤¬ą¤Øą¤¾ą¤ą¤‚" }, @@ -1231,6 +1354,9 @@ "createSnapAccountTitle": { "message": "ą¤…ą¤•ą¤¾ą¤‰ą¤‚ą¤Ÿ ą¤¬ą¤Øą¤¾ą¤ą¤‚" }, + "createSolanaAccount": { + "message": "Solana ą¤…ą¤•ą¤¾ą¤‰ą¤‚ą¤Ÿ ą¤¬ą¤Øą¤¾ą¤ą¤‚" + }, "creatorAddress": { "message": "ą¤Øą¤æą¤°ą„ą¤®ą¤¾ą¤¤ą¤¾ का ą¤ą¤”ą„ą¤°ą„‡ą¤ø" }, @@ -1471,6 +1597,21 @@ "message": "$1 ą¤øą„‡ ą¤œą¤¾ą¤Øą¤•ą¤¾ą¤°ą„€", "description": "$1 represents the name of the snap" }, + "destinationAccountPickerNoEligible": { + "message": "ą¤•ą„‹ą¤ˆ ą¤Æą„‹ą¤—ą„ą¤Æ ą¤…ą¤•ą¤¾ą¤‰ą¤‚ą¤Ÿ ą¤Øą¤¹ą„€ą¤‚ मिला" + }, + "destinationAccountPickerNoMatching": { + "message": "ą¤•ą„‹ą¤ˆ ą¤®ą„ˆą¤šą¤æą¤‚ą¤— ą¤…ą¤•ą¤¾ą¤‰ą¤‚ą¤Ÿ ą¤Øą¤¹ą„€ą¤‚ मिला" + }, + "destinationAccountPickerReceiveAt": { + "message": "पर ą¤Ŗą„ą¤°ą¤¾ą¤Ŗą„ą¤¤ ą¤•ą¤°ą„‡ą¤‚" + }, + "destinationAccountPickerSearchPlaceholderToMainnet": { + "message": "ą¤Ŗą„ą¤°ą¤¾ą¤Ŗą„ą¤¤ą¤æ ą¤ą¤”ą„ą¤°ą„‡ą¤ø या ENS" + }, + "destinationAccountPickerSearchPlaceholderToSolana": { + "message": "ą¤Ŗą„ą¤°ą¤¾ą¤Ŗą„ą¤¤ą¤æ ą¤ą¤”ą„ą¤°ą„‡ą¤ø" + }, "details": { "message": "ą¤µą¤æą¤øą„ą¤¤ą„ƒą¤¤ ą¤œą¤¾ą¤Øą¤•ą¤¾ą¤°ą„€" }, @@ -1516,6 +1657,9 @@ "message": "$1, $2 ą¤øą„‡ ą¤”ą¤æą¤øą¤•ą¤Øą„‡ą¤•ą„ą¤Ÿ ą¤¹ą„‹ गया", "description": "$1 is name of the name and $2 represents the dapp name`" }, + "discover": { + "message": "ą¤–ą„‹ą¤œą„‡ą¤‚" + }, "discoverSnaps": { "message": "Snaps ą¤•ą„‡ ą¤¬ą¤¾ą¤°ą„‡ ą¤®ą„‡ą¤‚ और ą¤œą¤¾ą¤Øą„‡ą¤‚", "description": "Text that links to the Snaps website. Displayed in a banner on Snaps list page in settings." @@ -1872,6 +2016,9 @@ "experimental": { "message": "ą¤ą¤•ą„ą¤øą¤Ŗą„‡ą¤°ą¤æą¤®ą„‡ą¤‚ą¤Ÿą¤²" }, + "exploreweb3": { + "message": "Web3 ą¤ą¤•ą„ą¤øą¤Ŗą„ą¤²ą„‹ą¤° ą¤•ą¤°ą„‡ą¤‚" + }, "exportYourData": { "message": "अपना ą¤”ą„‡ą¤Ÿą¤¾ ą¤ą¤•ą„ą¤øą¤Ŗą„‹ą¤°ą„ą¤Ÿ ą¤•ą¤°ą„‡ą¤‚" }, @@ -1885,6 +2032,9 @@ "message": "ą¤…ą¤Ŗą¤Øą„‡ Web3 ą¤ą¤•ą„ą¤øą¤Ŗą„€ą¤°ą¤æą¤Æą¤‚ą¤ø ą¤•ą„‹ ą¤•ą¤øą„ą¤Ÿą¤®ą¤¾ą¤‡ą„› ą¤•ą¤°ą¤Øą„‡ ą¤•ą„‡ ą¤²ą¤æą¤ ą¤•ą¤®ą„ą¤Æą„ą¤Øą¤æą¤Ÿą„€-ą¤¬ą¤æą¤²ą„ą¤Ÿ Snaps ą¤•ą„‹ ą¤ą¤•ą„ą¤øą¤Ŗą„ą¤²ą„‹ą¤° ą¤•ą¤°ą„‡ą¤‚ą„¤", "description": "Banner description displayed on Snaps list page in Settings when less than 6 Snaps is installed." }, + "externalAccount": { + "message": "ą¤ą¤•ą„ą¤øą„ą¤Ÿą¤°ą„ą¤Øą¤² ą¤…ą¤•ą¤¾ą¤‰ą¤‚ą¤Ÿ" + }, "externalExtension": { "message": "ą¤¬ą¤¾ą¤¹ą¤°ą„€ ą¤ą¤•ą„ą¤øą„ą¤Ÿą„‡ą¤Øą„ą¤¶ą¤Ø" }, @@ -2197,6 +2347,12 @@ "holdToRevealUnlockedLabel": { "message": "ą¤²ą„‰ą¤• ą¤•ą¤æą¤ ą¤—ą¤ ą¤øą¤°ą„ą¤•ą¤² ą¤•ą„‹ ą¤¦ą¤æą¤–ą¤¾ą¤Øą„‡ ą¤•ą„‡ ą¤²ą¤æą¤ ą¤¹ą„‹ą¤²ą„ą¤” ą¤•ą¤°ą„‡ą¤‚" }, + "honeypotDescription": { + "message": "यह ą¤Ÿą„‹ą¤•ą¤Ø ą¤¹ą¤Øą„€ą¤Ŗą„‹ą¤Ÿ ą¤œą„‹ą¤–ą¤æą¤® ą¤Ŗą„ˆą¤¦ą¤¾ कर सकता ą¤¹ą„ˆą„¤ ą¤•ą¤æą¤øą„€ ą¤­ą„€ संभावित ą¤µą¤æą¤¤ą„ą¤¤ą„€ą¤Æ ą¤Øą„ą¤•ą¤øą¤¾ą¤Ø ą¤•ą„‹ ą¤°ą„‹ą¤•ą¤Øą„‡ ą¤•ą„‡ ą¤²ą¤æą¤ ą¤‡ą¤‚ą¤Ÿą¤°ą„ˆą¤•ą„ą¤Ÿ ą¤•ą¤°ą¤Øą„‡ ą¤øą„‡ ą¤Ŗą¤¹ą¤²ą„‡ ą¤Ŗą„‚ą¤°ą„€ ą¤œą¤¾ą¤‚ą¤š-ą¤Ŗą„œą¤¤ą¤¾ą¤² ą¤•ą¤°ą¤Øą„‡ ą¤•ą„€ सलाह ą¤¦ą„€ ą¤œą¤¾ą¤¤ą„€ ą¤¹ą„ˆą„¤" + }, + "honeypotTitle": { + "message": "ą¤¹ą¤Øą„€ ą¤Ŗą„‰ą¤Ÿ" + }, "howNetworkFeesWorkExplanation": { "message": "ą¤Ÿą„ą¤°ą¤¾ą¤‚ą¤øą„‡ą¤•ą„ą¤¶ą¤Ø ą¤•ą„‹ ą¤Ŗą„ą¤°ą„‹ą¤øą„‡ą¤ø ą¤•ą¤°ą¤Øą„‡ ą¤•ą„‡ ą¤²ą¤æą¤ ą¤†ą¤µą¤¶ą„ą¤Æą¤• ą¤…ą¤Øą„ą¤®ą¤¾ą¤Øą¤æą¤¤ ą¤¶ą„ą¤²ą„ą¤•ą„¤ अधिकतम ą¤¶ą„ą¤²ą„ą¤• $1 ą¤¹ą„ˆą„¤" }, @@ -2262,6 +2418,30 @@ "importNFTTokenIdToolTip": { "message": "ą¤•ą¤æą¤øą„€ NFT ą¤•ą„€ ID ą¤ą¤• ą¤µą¤æą¤¶ą¤æą¤·ą„ą¤Ÿ ą¤Ŗą¤¹ą¤šą¤¾ą¤Øą¤•ą¤°ą„ą¤¤ą¤¾ ą¤¹ą„ˆ ą¤•ą„ą¤Æą„‹ą¤‚ą¤•ą¤æ ą¤•ą„‹ą¤ˆ ą¤­ą„€ ą¤¦ą„‹ NFT ą¤ą¤• ą¤œą„ˆą¤øą„‡ ą¤Øą¤¹ą„€ą¤‚ ą¤¹ą„‹ą¤¤ą„‡ ą¤¹ą„ˆą¤‚ą„¤ फिर ą¤øą„‡, OpenSea पर यह ą¤øą¤‚ą¤–ą„ą¤Æą¤¾ 'ą¤”ą¤æą¤Ÿą„‡ą¤²ą„ą¤ø' ą¤•ą„‡ ą¤Øą„€ą¤šą„‡ ą¤¹ą„‹ą¤—ą„€ą„¤ ą¤‡ą¤øą„‡ ą¤Øą„‹ą¤Ÿ कर ą¤²ą„‡ą¤‚ या ą¤…ą¤Ŗą¤Øą„‡ ą¤•ą„ą¤²ą¤æą¤Ŗą¤¬ą„‹ą¤°ą„ą¤” पर ą¤•ą„‰ą¤Ŗą„€ कर ą¤²ą„‡ą¤‚ą„¤" }, + "importNWordSRP": { + "message": "ą¤®ą„‡ą¤°ą„‡ पास $1 ą¤¶ą¤¬ą„ą¤¦ का ą¤°ą¤æą¤•ą¤µą¤°ą„€ ą¤«ą„ą¤°ą„‡ą„› ą¤¹ą„ˆ", + "description": "$1 is the number of words in the recovery phrase" + }, + "importPrivateKey": { + "message": "ą¤Ŗą„ą¤°ą¤¾ą¤‡ą¤µą„‡ą¤Ÿ ą¤•ą„€ (key)" + }, + "importSRPDescription": { + "message": "ą¤…ą¤Ŗą¤Øą„‡ 12 या 24-ą¤¶ą¤¬ą„ą¤¦ ą¤øą„€ą¤•ą„ą¤°ą„‡ą¤Ÿ ą¤°ą¤æą¤•ą¤µą¤°ą„€ ą¤«ą„ą¤°ą„‡ą„› ą¤•ą„‡ साऄ ą¤ą¤• ą¤®ą„Œą¤œą„‚ą¤¦ą¤¾ ą¤µą„‰ą¤²ą„‡ą¤Ÿ ą¤‡ą¤‚ą¤Ŗą„‹ą¤°ą„ą¤Ÿ ą¤•ą¤°ą„‡ą¤‚ą„¤" + }, + "importSRPNumberOfWordsError": { + "message": "ą¤øą„€ą¤•ą„ą¤°ą„‡ą¤Ÿ ą¤°ą¤æą¤•ą¤µą¤°ą„€ ą¤«ą„ą¤°ą„‡ą„› ą¤®ą„‡ą¤‚ 12, या 24 ą¤¶ą¤¬ą„ą¤¦ ą¤¹ą„‹ą¤¤ą„‡ ą¤¹ą„ˆą¤‚" + }, + "importSRPWordError": { + "message": "ą¤¶ą¤¬ą„ą¤¦ $1 गलत ą¤¹ą„ˆ या ą¤‡ą¤øą¤•ą„€ ą¤øą„ą¤Ŗą„‡ą¤²ą¤æą¤‚ą¤— गलत ą¤¹ą„ˆą„¤", + "description": "$1 is the word that is incorrect or misspelled" + }, + "importSRPWordErrorAlternative": { + "message": "ą¤¶ą¤¬ą„ą¤¦ $1 और $2 गलत ą¤¹ą„ˆ या ą¤‡ą¤øą¤•ą„€ ą¤øą„ą¤Ŗą„‡ą¤²ą¤æą¤‚ą¤— गलत ą¤¹ą„ˆą„¤", + "description": "$1 and $2 are multiple words that are mispelled." + }, + "importSecretRecoveryPhrase": { + "message": "ą¤øą„€ą¤•ą„ą¤°ą„‡ą¤Ÿ ą¤°ą¤æą¤•ą¤µą¤°ą„€ ą¤«ą„ą¤°ą„‡ą„› ą¤‡ą¤‚ą¤Ŗą„‹ą¤°ą„ą¤Ÿ ą¤•ą¤°ą„‡ą¤‚" + }, "importSelectedTokens": { "message": "ą¤šą„ą¤Øą¤¾ गया ą¤Ÿą„‹ą¤•ą¤Ø ą¤‡ą¤®ą„ą¤Ŗą„‹ą¤°ą„ą¤Ÿ ą¤•ą¤°ą„‡ą¤‚?" }, @@ -2280,6 +2460,12 @@ "importTokensError": { "message": "हम ą¤Ÿą„‹ą¤•ą¤Øą„‹ą¤‚ ą¤•ą„‹ ą¤‡ą¤‚ą¤Ŗą„‹ą¤°ą„ą¤Ÿ ą¤Øą¤¹ą„€ą¤‚ कर ą¤øą¤•ą„‡ą„¤ ą¤•ą„ƒą¤Ŗą¤Æą¤¾ बाद ą¤®ą„‡ą¤‚ फिर ą¤øą„‡ ą¤•ą„‹ą¤¶ą¤æą¤¶ ą¤•ą¤°ą„‡ą¤‚ą„¤" }, + "importWallet": { + "message": "ą¤µą„‰ą¤²ą„‡ą¤Ÿ ą¤‡ą¤‚ą¤Ŗą„‹ą¤°ą„ą¤Ÿ ą¤•ą¤°ą„‡ą¤‚" + }, + "importWalletOrAccountHeader": { + "message": "ą¤µą„‰ą¤²ą„‡ą¤Ÿ या ą¤…ą¤•ą¤¾ą¤‰ą¤‚ą¤Ÿ ą¤‡ą¤‚ą¤Ŗą„‹ą¤°ą„ą¤Ÿ ą¤•ą¤°ą„‡ą¤‚" + }, "importWithCount": { "message": "$1 ą¤‡ą¤®ą„ą¤Ŗą„‹ą¤°ą„ą¤Ÿ ą¤•ą¤°ą„‡ą¤‚", "description": "$1 will the number of detected tokens that are selected for importing, if all of them are selected then $1 will be all" @@ -2327,6 +2513,12 @@ "insufficientFundsForGas": { "message": "ą¤—ą„ˆą¤ø ą¤•ą„‡ ą¤²ą¤æą¤ कम फंऔ" }, + "insufficientLockedLiquidityDescription": { + "message": "ą¤Ŗą¤°ą„ą¤Æą¤¾ą¤Ŗą„ą¤¤ ą¤°ą„‚ą¤Ŗ ą¤øą„‡ ą¤²ą„‰ą¤• या ą¤¬ą¤°ą„ą¤Ø ą¤•ą„€ ą¤—ą¤ˆ ą¤²ą¤æą¤•ą„ą¤µą¤æą¤”ą¤æą¤Ÿą„€ ą¤•ą„€ ą¤•ą¤®ą„€ ą¤•ą„‡ कारण ą¤Ÿą„‹ą¤•ą¤Ø ą¤…ą¤šą¤¾ą¤Øą¤• ą¤²ą¤æą¤•ą„ą¤µą¤æą¤”ą¤æą¤Ÿą„€ ą¤µą¤æą¤¦ą¤”ą„ą¤°ą„‰ą¤µą¤² ą¤•ą„‡ ą¤Ŗą„ą¤°ą¤¤ą¤æ ą¤øą¤‚ą¤µą„‡ą¤¦ą¤Øą¤¶ą„€ą¤² ą¤¹ą„‹ जाता ą¤¹ą„ˆ, ą¤œą¤æą¤øą¤øą„‡ संभावित ą¤°ą„‚ą¤Ŗ ą¤øą„‡ बाजार ą¤®ą„‡ą¤‚ ą¤…ą¤øą„ą¤„ą¤æą¤°ą¤¤ą¤¾ ą¤Ŗą„ˆą¤¦ą¤¾ ą¤¹ą„‹ ą¤øą¤•ą¤¤ą„€ ą¤¹ą„ˆą„¤" + }, + "insufficientLockedLiquidityTitle": { + "message": "ą¤…ą¤Ŗą¤°ą„ą¤Æą¤¾ą¤Ŗą„ą¤¤ ą¤²ą„‰ą¤•ą„ą¤” ą¤²ą¤æą¤•ą„ą¤µą¤æą¤”ą¤æą¤Ÿą„€" + }, "insufficientTokens": { "message": "कम ą¤Ÿą„‹ą¤•ą¤Øą„¤" }, @@ -2362,6 +2554,9 @@ "invalidCustomNetworkAlertTitle": { "message": "ą„šą¤²ą¤¤ ą¤•ą¤øą„ą¤Ÿą¤® ą¤Øą„‡ą¤Ÿą¤µą¤°ą„ą¤•" }, + "invalidHexData": { + "message": "ą„šą¤²ą¤¤ ą¤¹ą„‡ą¤•ą„ą¤ø ą¤”ą„‡ą¤Ÿą¤¾" + }, "invalidHexNumber": { "message": "ą„šą¤²ą¤¤ ą¤¹ą„‡ą¤•ą„ą¤øą¤¾ą¤”ą„‡ą¤øą¤æą¤®ą¤² ą¤øą¤‚ą¤–ą„ą¤Æą¤¾ą„¤" }, @@ -2540,6 +2735,9 @@ "ledgerLocked": { "message": "Ledger औिवाइस ą¤øą„‡ ą¤•ą¤Øą„‡ą¤•ą„ą¤Ÿ ą¤Øą¤¹ą„€ą¤‚ ą¤¹ą„‹ ą¤øą¤•ą¤¤ą¤¾ą„¤ ą¤•ą„ƒą¤Ŗą¤Æą¤¾ ą¤Ŗą¤•ą„ą¤•ą¤¾ ą¤•ą¤°ą„‡ą¤‚ कि आपका औिवाइस ą¤…ą¤Øą¤²ą„‰ą¤• ą¤¹ą„ˆ और Ethereum ऐप ą¤–ą„ą¤²ą¤¾ ą¤¹ą„ˆą„¤" }, + "ledgerMultipleDevicesUnsupportedErrorMessage": { + "message": "ą¤ą¤• ą¤¹ą„€ समय ą¤®ą„‡ą¤‚ ą¤•ą¤ˆ Ledger औिवाइस ą¤•ą¤Øą„‡ą¤•ą„ą¤Ÿ ą¤Øą¤¹ą„€ą¤‚ ą¤•ą¤æą¤ जा ą¤øą¤•ą¤¤ą„‡ą„¤ ą¤ą¤• नया Ledger औिवाइस ą¤•ą¤Øą„‡ą¤•ą„ą¤Ÿ ą¤•ą¤°ą¤Øą„‡ ą¤•ą„‡ ą¤²ą¤æą¤, ą¤†ą¤Ŗą¤•ą„‹ ą¤Ŗą¤¹ą¤²ą„‡ ą¤Ŗą¤æą¤›ą¤²ą„‡ औिवाइस ą¤•ą„‹ ą¤”ą¤æą¤øą„ą¤•ą¤Øą„‡ą¤•ą„ą¤Ÿ करना ą¤¹ą„‹ą¤—ą¤¾ą„¤" + }, "ledgerTimeout": { "message": "Ledger Live जवाब ą¤¦ą„‡ą¤Øą„‡ ą¤®ą„‡ą¤‚ ą¤¬ą¤¹ą„ą¤¤ अधिक समय ą¤²ą„‡ रहा ą¤¹ą„ˆ या ą¤•ą¤Øą„‡ą¤•ą„ą¤¶ą¤Ø ą¤Ÿą¤¾ą¤‡ą¤®ą¤†ą¤‰ą¤Ÿ ą¤¹ą„‹ गया ą¤¹ą„ˆą„¤ ą¤Ŗą¤•ą„ą¤•ą¤¾ ą¤•ą¤°ą„‡ą¤‚ कि Ledger Live ऐप ą¤–ą„ą¤²ą¤¾ ą¤¹ą„ˆ और आपका औिवाइस ą¤…ą¤Øą¤²ą„‰ą¤• ą¤¹ą„ˆą„¤" }, @@ -2637,6 +2835,9 @@ "manageDefaultSettings": { "message": "ą¤”ą¤æą¤«ą„‰ą¤²ą„ą¤Ÿ ą¤—ą„‹ą¤Ŗą¤Øą„€ą¤Æą¤¤ą¤¾ ą¤øą„‡ą¤Ÿą¤æą¤‚ą¤—ą„ą¤ø ą¤®ą„ˆą¤Øą„‡ą¤œ ą¤•ą¤°ą„‡ą¤‚" }, + "managePermissions": { + "message": "ą¤…ą¤Øą„ą¤®ą¤¤ą¤æą¤Æą¤¾ą¤ ą¤Ŗą„ą¤°ą¤¬ą¤‚ą¤§ą¤æą¤¤ ą¤•ą¤°ą„‡ą¤‚" + }, "marketCap": { "message": "ą¤®ą¤¾ą¤°ą„ą¤•ą„‡ą¤Ÿ ą¤•ą„ˆą¤Ŗ" }, @@ -2755,6 +2956,15 @@ "multichainAddEthereumChainConfirmationDescription": { "message": "आप इस ą¤Øą„‡ą¤Ÿą¤µą¤°ą„ą¤• ą¤•ą„‹ MetaMask ą¤®ą„‡ą¤‚ ą¤œą„‹ą¤”ą¤¼ ą¤°ą¤¹ą„‡ ą¤¹ą„ˆą¤‚ और इस ą¤øą¤¾ą¤‡ą¤Ÿ ą¤•ą„‹ इसका ą¤‰ą¤Ŗą¤Æą„‹ą¤— ą¤•ą¤°ą¤Øą„‡ ą¤•ą„€ ą¤…ą¤Øą„ą¤®ą¤¤ą¤æ ą¤¦ą„‡ ą¤°ą¤¹ą„‡ ą¤¹ą„ˆą¤‚ą„¤" }, + "multichainQuoteCardBridgingLabel": { + "message": "ą¤¬ą„ą¤°ą¤æą¤œ किया जा रहा ą¤¹ą„ˆ" + }, + "multichainQuoteCardQuoteLabel": { + "message": "ą¤•ą„‹ą¤Ÿą„‡ą¤¶ą¤Ø" + }, + "multichainQuoteCardTimeLabel": { + "message": "समय" + }, "multipleSnapConnectionWarning": { "message": "$1 $2 Snaps का ą¤‰ą¤Ŗą¤Æą„‹ą¤— करना चाहता ą¤¹ą„ˆ", "description": "$1 is the dapp and $2 is the number of snaps it wants to connect to." @@ -2869,6 +3079,13 @@ "network": { "message": "ą¤Øą„‡ą¤Ÿą¤µą¤°ą„ą¤•:" }, + "networkChanged": { + "message": "ą¤Øą„‡ą¤Ÿą¤µą¤°ą„ą¤• बदला गया" + }, + "networkChangedMessage": { + "message": "अब आप $1 पर ą¤²ą„‡ą¤Ø-ą¤¦ą„‡ą¤Ø कर ą¤°ą¤¹ą„‡ ą¤¹ą„ˆą¤‚ą„¤", + "description": "$1 is the name of the network" + }, "networkDetails": { "message": "ą¤Øą„‡ą¤Ÿą¤µą¤°ą„ą¤• विवरण" }, @@ -3143,6 +3360,9 @@ "notEnoughGas": { "message": "ą¤—ą„ˆą¤ø कम ą¤¹ą„ˆ" }, + "notNow": { + "message": "ą¤…ą¤­ą„€ ą¤Øą¤¹ą„€ą¤‚" + }, "notificationDetail": { "message": "विवरण" }, @@ -3505,6 +3725,13 @@ "origin": { "message": "ą¤“ą¤°ą¤æą¤œą¤æą¤Ø" }, + "originChanged": { + "message": "ą¤øą¤¾ą¤‡ą¤Ÿ बदला गया" + }, + "originChangedMessage": { + "message": "आप ą¤…ą¤­ą„€ $1 ą¤•ą„‡ ą¤…ą¤Øą„ą¤°ą„‹ą¤§ ą¤•ą„€ ą¤øą¤®ą„€ą¤•ą„ą¤·ą¤¾ कर ą¤°ą¤¹ą„‡ ą¤¹ą„ˆą¤‚ą„¤", + "description": "$1 is the name of the origin" + }, "osTheme": { "message": "ą¤øą¤æą¤øą„ą¤Ÿą¤®" }, @@ -3559,6 +3786,14 @@ "pending": { "message": "लंबित" }, + "pendingConfirmationAddNetworkAlertMessage": { + "message": "ą¤Øą„‡ą¤Ÿą¤µą¤°ą„ą¤• ą¤…ą¤Ŗą¤”ą„‡ą¤Ÿ ą¤•ą¤°ą¤Øą„‡ ą¤øą„‡ इस ą¤øą¤¾ą¤‡ą¤Ÿ ą¤øą„‡ ą¤…ą¤­ą„€ ą¤Ŗą„‚ą¤°ą¤¾ ą¤Øą¤¹ą„€ą¤‚ ą¤¹ą„ą¤† $1 का ą¤Ÿą„ą¤°ą¤¾ą¤‚ą¤øą„‡ą¤•ą„ą¤¶ą¤Ø ą¤•ą„ˆą¤‚ą¤øą¤æą¤² ą¤¹ą„‹ ą¤œą¤¾ą¤ą¤—ą¤¾ą„¤", + "description": "Number of transactions." + }, + "pendingConfirmationSwitchNetworkAlertMessage": { + "message": "ą¤Øą„‡ą¤Ÿą¤µą¤°ą„ą¤• ą¤øą„ą¤µą¤æą¤š ą¤•ą¤°ą¤Øą„‡ ą¤øą„‡ इस ą¤øą¤¾ą¤‡ą¤Ÿ ą¤øą„‡ ą¤…ą¤­ą„€ ą¤Ŗą„‚ą¤°ą¤¾ ą¤Øą¤¹ą„€ą¤‚ ą¤¹ą„ą¤† $1 का ą¤Ÿą„ą¤°ą¤¾ą¤‚ą¤øą„‡ą¤•ą„ą¤¶ą¤Ø ą¤•ą„ˆą¤‚ą¤øą¤æą¤² ą¤¹ą„‹ ą¤œą¤¾ą¤ą¤—ą¤¾ą„¤", + "description": "Number of transactions." + }, "pendingTransactionAlertMessage": { "message": "यह ą¤Ÿą„ą¤°ą¤¾ą¤‚ą¤øą„‡ą¤•ą„ą¤¶ą¤Ø तब तक ą¤Øą¤¹ą„€ą¤‚ ą¤¹ą„‹ą¤—ą¤¾ जब तक पिछला ą¤Ÿą„ą¤°ą¤¾ą¤‚ą¤øą„‡ą¤•ą„ą¤¶ą¤Ø ą¤Ŗą„‚ą¤°ą¤¾ न ą¤¹ą„‹ ą¤œą¤¾ą¤ą„¤ $1", "description": "$1 represents the words 'how to cancel or speed up a transaction' in a hyperlink" @@ -3842,6 +4077,9 @@ "permitSimulationChange_receive": { "message": "आप ą¤Ŗą„ą¤°ą¤¾ą¤Ŗą„ą¤¤ ą¤•ą¤°ą¤¤ą„‡ ą¤¹ą„ˆą¤‚" }, + "permitSimulationChange_revoke2": { + "message": "ą¤°ą¤¦ą„ą¤¦ ą¤•ą¤°ą„‡ą¤‚" + }, "permitSimulationChange_transfer": { "message": "आप ą¤­ą„‡ą¤œą¤¤ą„‡ ą¤¹ą„ˆą¤‚" }, @@ -4237,6 +4475,9 @@ "reusedTokenNameWarning": { "message": "यहां पर ą¤ą¤• ą¤Ÿą„‹ą¤•ą¤Ø ą¤†ą¤Ŗą¤•ą„‡ ą¤¦ą„ą¤µą¤¾ą¤°ą¤¾ ą¤¦ą„‡ą¤–ą„‡ ą¤œą¤¾ą¤Øą„‡ ą¤µą¤¾ą¤²ą„‡ ą¤¦ą„‚ą¤øą¤°ą„‡ ą¤Ÿą„‹ą¤•ą¤Ø ą¤øą„‡ ą¤Ŗą„ą¤°ą¤¤ą„€ą¤• का ą¤Ŗą„ą¤Øą¤ƒ ą¤‡ą¤øą„ą¤¤ą„‡ą¤®ą¤¾ą¤² करता ą¤¹ą„ˆ, यह ą¤­ą„ą¤°ą¤¾ą¤®ą¤• या ą¤§ą„‹ą¤–ą¤¾ą¤§ą¤”ą¤¼ą„€ वाला ą¤¹ą„‹ सकता ą¤¹ą„ˆą„¤" }, + "revealSecretRecoveryPhrase": { + "message": "ą¤øą„€ą¤•ą„ą¤°ą„‡ą¤Ÿ ą¤°ą¤æą¤•ą¤µą¤°ą„€ ą¤«ą„ą¤°ą„‡ą„› ą¤¦ą¤æą¤–ą¤¾ą¤ą¤‚" + }, "revealSeedWords": { "message": "ą¤øą„€ą¤•ą„ą¤°ą„‡ą¤Ÿ ą¤°ą¤æą¤•ą¤µą¤°ą„€ ą¤«ą„ą¤°ą„‡ą¤œ ą¤Ŗą„ą¤°ą¤•ą¤Ÿ ą¤•ą¤°ą„‡ą¤‚" }, @@ -4286,12 +4527,19 @@ "reviewAlerts": { "message": "ą¤ą¤²ą¤°ą„ą¤Ÿ ą¤•ą„€ ą¤øą¤®ą„€ą¤•ą„ą¤·ą¤¾ ą¤•ą¤°ą„‡ą¤‚" }, + "reviewPendingTransactions": { + "message": "ą¤…ą¤­ą„€ ą¤Ŗą„‚ą¤°ą„‡ ą¤Øą¤¹ą„€ą¤‚ ą¤¹ą„ą¤ ą¤Ÿą„ą¤°ą¤¾ą¤‚ą¤øą„‡ą¤•ą„ą¤¶ą¤Ø ą¤•ą„€ ą¤øą¤®ą„€ą¤•ą„ą¤·ą¤¾ ą¤•ą¤°ą„‡ą¤‚" + }, "reviewPermissions": { "message": "ą¤…ą¤Øą„ą¤®ą¤¤ą¤æą¤Æą„‹ą¤‚ ą¤•ą„€ ą¤øą¤®ą„€ą¤•ą„ą¤·ą¤¾ ą¤•ą¤°ą„‡ą¤‚" }, "revokePermission": { "message": "ą¤…ą¤Øą„ą¤®ą¤¤ą¤æ ą¤•ą„ˆą¤‚ą¤øą¤æą¤² ą¤•ą¤°ą¤Øą„‡ ą¤•ą„€" }, + "revokePermissionTitle": { + "message": "$1 ą¤…ą¤Øą„ą¤®ą¤¤ą¤æ ą¤¹ą¤Ÿą¤¾ą¤ą¤‚", + "description": "The token symbol that is being revoked" + }, "revokeSimulationDetailsDesc": { "message": "आप ą¤•ą¤æą¤øą„€ ą¤…ą¤Øą„ą¤Æ ą¤•ą„‹ ą¤†ą¤Ŗą¤•ą„‡ ą¤…ą¤•ą¤¾ą¤‰ą¤‚ą¤Ÿ ą¤øą„‡ ą¤Ÿą„‹ą¤•ą¤Ø ą„™ą¤°ą„ą¤š ą¤•ą¤°ą¤Øą„‡ ą¤•ą„‡ ą¤²ą¤æą¤ ą¤¦ą„€ ą¤—ą¤ˆ ą¤…ą¤Øą„ą¤®ą¤¤ą¤æ हटा ą¤°ą¤¹ą„‡ ą¤¹ą„ˆą¤‚ą„¤" }, @@ -4334,6 +4582,10 @@ "secretRecoveryPhrase": { "message": "ą¤øą„€ą¤•ą„ą¤°ą„‡ą¤Ÿ ą¤°ą¤æą¤•ą¤µą¤°ą„€ ą¤«ą„ą¤°ą„‡ą¤œ" }, + "secretRecoveryPhrasePlusNumber": { + "message": "ą¤øą„€ą¤•ą„ą¤°ą„‡ą¤Ÿ ą¤°ą¤æą¤•ą¤µą¤°ą„€ ą¤«ą„ą¤°ą„‡ą„› $1", + "description": "The $1 is the order of the Secret Recovery Phrase" + }, "secureWallet": { "message": "ą¤øą„ą¤°ą¤•ą„ą¤·ą¤æą¤¤ ą¤µą„‰ą¤²ą„‡ą¤Ÿ" }, @@ -4424,6 +4676,9 @@ "select": { "message": "चयन ą¤•ą¤°ą„‡ą¤‚" }, + "selectAccountToConnect": { + "message": "ą¤•ą¤Øą„‡ą¤•ą„ą¤Ÿ ą¤•ą¤°ą¤Øą„‡ ą¤•ą„‡ ą¤²ą¤æą¤ ą¤ą¤• ą¤…ą¤•ą¤¾ą¤‰ą¤‚ą¤Ÿ ą¤šą„ą¤Øą„‡ą¤‚" + }, "selectAccounts": { "message": "इस ą¤øą¤¾ą¤‡ą¤Ÿ पर ą¤‡ą¤øą„ą¤¤ą„‡ą¤®ą¤¾ą¤² ą¤•ą¤°ą¤Øą„‡ ą¤•ą„‡ ą¤²ą¤æą¤ ą¤…ą¤•ą¤¾ą¤‰ą¤‚ą¤Ÿ (ą¤ą¤•ą¤¾ą¤‰ą¤‚ą¤Ÿą„ą¤ø) ą¤•ą„‹ ą¤šą„ą¤Øą„‡ą¤‚" }, @@ -4454,6 +4709,9 @@ "selectRpcUrl": { "message": "RPC URL ą¤•ą„‹ ą¤šą„ą¤Øą„‡ą¤‚" }, + "selectSecretRecoveryPhrase": { + "message": "ą¤øą„€ą¤•ą„ą¤°ą„‡ą¤Ÿ ą¤°ą¤æą¤•ą¤µą¤°ą„€ ą¤«ą„ą¤°ą„‡ą„› ą¤šą„ą¤Øą„‡ą¤‚" + }, "selectType": { "message": "ą¤Ŗą„ą¤°ą¤•ą¤¾ą¤° ą¤•ą„‹ ą¤šą„ą¤Øą„‡ą¤‚" }, @@ -4565,16 +4823,6 @@ "showHexDataDescription": { "message": "ą¤­ą„‡ą¤œą¤Øą„‡ ą¤•ą„€ ą¤øą„ą¤•ą„ą¤°ą„€ą¤Ø पर ą¤¹ą„‡ą¤•ą„ą¤ø ą¤”ą„‡ą¤Ÿą¤¾ ą¤«ą„€ą¤²ą„ą¤” ą¤¦ą¤æą¤–ą¤¾ą¤Øą„‡ ą¤•ą„‡ ą¤²ą¤æą¤ ą¤‡ą¤øą¤•ą„‹ ą¤šą„ą¤Øą„‡ą¤‚" }, - "showIncomingTransactions": { - "message": "ą¤†ą¤Øą„‡ ą¤µą¤¾ą¤²ą„‡ ą¤Ÿą„ą¤°ą¤¾ą¤‚ą¤øą„‡ą¤•ą„ą¤¶ą¤Ø ą¤¦ą¤æą¤–ą¤¾ą¤ą¤‚" - }, - "showIncomingTransactionsDescription": { - "message": "ą¤²ą„‡ą¤Øą¤¦ą„‡ą¤Ø ą¤øą„‚ą¤šą„€ ą¤®ą„‡ą¤‚ ą¤†ą¤Øą„‡ ą¤µą¤¾ą¤²ą„‡ ą¤²ą„‡ą¤Øą¤¦ą„‡ą¤Ø ą¤•ą„‹ ą¤¦ą¤æą¤–ą¤¾ą¤Øą„‡ ą¤•ą„‡ ą¤²ą¤æą¤ Etherscan का ą¤‰ą¤Ŗą¤Æą„‹ą¤— ą¤•ą¤°ą¤Øą„‡ ą¤•ą„‡ ą¤²ą¤æą¤ इसका चयन ą¤•ą¤°ą„‡ą¤‚", - "description": "$1 is the link to etherscan url and $2 is the link to the privacy policy of consensys APIs" - }, - "showIncomingTransactionsExplainer": { - "message": "यह ą¤¹ą¤°ą„‡ą¤• ą¤Øą„‡ą¤Ÿą¤µą¤°ą„ą¤• ą¤•ą„‡ ą¤²ą¤æą¤ अलग-अलग ą¤„ą¤°ą„ą¤”-ą¤Ŗą¤¾ą¤°ą„ą¤Ÿą„€ API पर ą¤Øą¤æą¤°ą„ą¤­ą¤° करता ą¤¹ą„ˆ, ą¤œą„‹ ą¤†ą¤Ŗą¤•ą„‡ Ethereum ą¤ą¤”ą„ą¤°ą„‡ą¤ø और ą¤†ą¤Ŗą¤•ą„‡ ą¤†ą¤ˆą¤Ŗą„€ ā€‹ā€‹ą¤ą¤”ą„ą¤°ą„‡ą¤ø ą¤•ą„‹ ą¤ą¤•ą„ą¤øą„ą¤Ŗą„‹ą„› करता ą¤¹ą„ˆą„¤" - }, "showLess": { "message": "कम ą¤¦ą¤æą¤–ą¤¾ą¤ą¤‚" }, @@ -4593,6 +4841,9 @@ "showPrivateKey": { "message": "ą¤Ŗą„ą¤°ą¤¾ą¤‡ą¤µą„‡ą¤Ÿ ą¤•ą„€ (key) ą¤¦ą¤æą¤–ą¤¾ą¤ą¤‚" }, + "showSRP": { + "message": "ą¤øą„€ą¤•ą„ą¤°ą„‡ą¤Ÿ ą¤°ą¤æą¤•ą¤µą¤°ą„€ ą¤«ą„ą¤°ą„‡ą„› ą¤¦ą¤æą¤–ą¤¾ą¤ą¤‚" + }, "showTestnetNetworks": { "message": "ą¤Ŗą¤°ą„€ą¤•ą„ą¤·ą¤£ ą¤Øą„‡ą¤Ÿą¤µą¤°ą„ą¤• ą¤¦ą¤æą¤–ą¤¾ą¤ą¤‚" }, @@ -4714,12 +4965,24 @@ "slideCashOutTitle": { "message": "MetaMask ą¤•ą„‡ साऄ ą¤•ą„ˆą¤¶ ą¤†ą¤‰ą¤Ÿ ą¤•ą¤°ą„‡ą¤‚" }, + "slideDebitCardDescription": { + "message": "चयनित ą¤•ą„ą¤·ą„‡ą¤¤ą„ą¤°ą„‹ą¤‚ ą¤®ą„‡ą¤‚ ą¤‰ą¤Ŗą¤²ą¤¬ą„ą¤§ ą¤¹ą„ˆ" + }, "slideDebitCardTitle": { "message": "MetaMask ą¤”ą„‡ą¤¬ą¤æą¤Ÿ ą¤•ą¤¾ą¤°ą„ą¤”" }, + "slideFundWalletDescription": { + "message": "ą¤¶ą„ą¤°ą„‚ ą¤•ą¤°ą¤Øą„‡ ą¤•ą„‡ ą¤²ą¤æą¤ ą¤Ÿą„‹ą¤•ą¤Ø ą¤œą„‹ą¤”ą¤¼ą„‡ą¤‚ या ą¤øą„ą¤„ą¤¾ą¤Øą¤¾ą¤‚ą¤¤ą¤°ą¤æą¤¤ ą¤•ą¤°ą„‡ą¤‚" + }, "slideFundWalletTitle": { "message": "ą¤…ą¤Ŗą¤Øą„‡ ą¤µą„‰ą¤²ą„‡ą¤Ÿ और ą¤ą¤®ą¤ˆą¤µą„€ ą¤øą„ą¤°ą¤•ą„ą¤·ą¤¾ ą¤•ą„‹ फंऔ ą¤•ą¤°ą„‡ą¤‚ą„¤" }, + "slideSweepStakeDescription": { + "message": "ą¤œą„€ą¤¤ą¤Øą„‡ का ą¤®ą„Œą¤•ą¤¾ ą¤Ŗą¤¾ą¤Øą„‡ ą¤•ą„‡ ą¤²ą¤æą¤ ą¤…ą¤­ą„€ NFT ą¤®ą¤æą¤‚ą¤Ÿ ą¤•ą¤°ą„‡ą¤‚" + }, + "slideSweepStakeTitle": { + "message": "$5000 USDC ą¤—ą¤æą¤µą¤…ą¤µą„‡ ą¤®ą„‡ą¤‚ ą¤Ŗą„ą¤°ą¤µą„‡ą¤¶ ą¤•ą¤°ą„‡ą¤‚!" + }, "smartContracts": { "message": "ą¤øą„ą¤®ą¤¾ą¤°ą„ą¤Ÿ ą¤•ą„‰ą¤Øą„ą¤Ÿą„ą¤°ą„ˆą¤•ą„ą¤Ÿą„ą¤ø" }, @@ -4866,6 +5129,9 @@ "snapResultSuccessDescription": { "message": "$1 ą¤‡ą¤øą„ą¤¤ą„‡ą¤®ą¤¾ą¤² ą¤•ą„‡ ą¤²ą¤æą¤ ą¤¤ą„ˆą¤Æą¤¾ą¤° ą¤¹ą„ˆ" }, + "snapUIAssetSelectorTitle": { + "message": "ą¤•ą¤æą¤øą„€ ą¤ą¤øą„‡ą¤Ÿ ą¤•ą„‹ ą¤šą„ą¤Øą„‡ą¤‚" + }, "snapUpdateAlertDescription": { "message": "$1 का ą¤²ą„‡ą¤Ÿą„‡ą¤øą„ą¤Ÿ ą¤µą¤°ą„ą¤œą¤¼ą¤Ø ą¤Ŗą¤¾ą¤ą¤‚", "description": "Description used in Snap update alert banner when snap update is available. $1 is the Snap name." @@ -4925,6 +5191,27 @@ "message": "अधिक सहायता ą¤•ą„‡ ą¤²ą¤æą¤ $1 ą¤•ą„‡ ą¤Øą¤æą¤°ą„ą¤®ą¤¾ą¤¤ą¤¾ą¤“ą¤‚ ą¤øą„‡ ą¤•ą„‰ą¤Øą„ą¤Ÿą„‡ą¤•ą„ą¤Ÿ ą¤•ą¤°ą„‡ą¤‚ą„¤", "description": "This is shown when the insight snap throws an error. $1 is the snap name" }, + "solanaImportAccounts": { + "message": "Solana ą¤ą¤•ą¤¾ą¤‰ą¤‚ą¤Ÿą„ą¤ø ą¤‡ą¤‚ą¤Ŗą„‹ą¤°ą„ą¤Ÿ ą¤•ą¤°ą„‡ą¤‚" + }, + "solanaImportAccountsDescription": { + "message": "ą¤…ą¤Ŗą¤Øą„‡ Solana ą¤…ą¤•ą¤¾ą¤‰ą¤‚ą¤Ÿ ą¤•ą„‹ ą¤•ą¤æą¤øą„€ ą¤…ą¤Øą„ą¤Æ ą¤µą„‰ą¤²ą„‡ą¤Ÿ ą¤øą„‡ ą¤øą„ą¤„ą¤¾ą¤Øą¤¾ą¤‚ą¤¤ą¤°ą¤æą¤¤ ą¤•ą¤°ą¤Øą„‡ ą¤•ą„‡ ą¤²ą¤æą¤ ą¤ą¤• ą¤øą„€ą¤•ą„ą¤°ą„‡ą¤Ÿ ą¤°ą¤æą¤•ą¤µą¤°ą„€ ą¤«ą„ą¤°ą„‡ą„› ą¤‡ą¤‚ą¤Ŗą„‹ą¤°ą„ą¤Ÿ ą¤•ą¤°ą„‡ą¤‚ą„¤" + }, + "solanaMoreFeaturesComingSoon": { + "message": "ą¤œą¤²ą„ą¤¦ ą¤¹ą„€ और ą¤«ą„€ą¤šą¤°ą„ą¤ø ą¤‰ą¤Ŗą¤²ą¤¬ą„ą¤§ ą¤¹ą„‹ą¤‚ą¤—ą„‡" + }, + "solanaMoreFeaturesComingSoonDescription": { + "message": "Solana ą¤”ą„ˆą¤Ŗą„ą¤ø, NFTs, ą¤¹ą¤¾ą¤°ą„ą¤”ą¤µą„‡ą¤Æą¤° ą¤µą„‰ą¤²ą„‡ą¤Ÿ ą¤øą¤Ŗą„‹ą¤°ą„ą¤Ÿ और ą¤¬ą¤¹ą„ą¤¤ ą¤•ą„ą¤› ą¤œą¤²ą„ą¤¦ ą¤¹ą„€ आ रहा ą¤¹ą„ˆą„¤" + }, + "solanaOnMetaMask": { + "message": "MetaMask पर Solana" + }, + "solanaSendReceiveSwapTokens": { + "message": "ą¤Ÿą„‹ą¤•ą¤Ø ą¤­ą„‡ą¤œą„‡ą¤‚, ą¤Ŗą„ą¤°ą¤¾ą¤Ŗą„ą¤¤ ą¤•ą¤°ą„‡ą¤‚ और ą¤øą„ą¤µą„ˆą¤Ŗ ą¤•ą¤°ą„‡ą¤‚" + }, + "solanaSendReceiveSwapTokensDescription": { + "message": "SOL, USDC आदि ą¤œą„ˆą¤øą„‡ ą¤Ÿą„‹ą¤•ą¤Ø ą¤•ą„‡ साऄ ą¤Ÿą„ą¤°ą¤¾ą¤‚ą¤øą¤«ą¤° और ą¤²ą„‡ą¤Øą¤¦ą„‡ą¤Ø ą¤•ą¤°ą„‡ą¤‚ą„¤" + }, "someNetworks": { "message": "$1 ą¤Øą„‡ą¤Ÿą¤µą¤°ą„ą¤•" }, @@ -4951,6 +5238,21 @@ "source": { "message": "ą¤øą„ą¤¤ą„ą¤°ą„‹ą¤¤" }, + "spamModalBlockedDescription": { + "message": "यह ą¤øą¤¾ą¤‡ą¤Ÿ 1 मिनट ą¤•ą„‡ ą¤²ą¤æą¤ ą¤¬ą„ą¤²ą„‰ą¤• ą¤°ą¤¹ą„‡ą¤—ą„€ą„¤" + }, + "spamModalBlockedTitle": { + "message": "ą¤†ą¤Ŗą¤Øą„‡ इस ą¤øą¤¾ą¤‡ą¤Ÿ ą¤•ą„‹ ą¤…ą¤øą„ą¤„ą¤¾ą¤Æą„€ ą¤°ą„‚ą¤Ŗ ą¤øą„‡ ą¤¬ą„ą¤²ą„‰ą¤• कर दिया ą¤¹ą„ˆ" + }, + "spamModalDescription": { + "message": "यदि ą¤†ą¤Ŗą¤•ą„‹ ą¤…ą¤Øą„‡ą¤• ą¤…ą¤Øą„ą¤°ą„‹ą¤§ą„‹ą¤‚ ą¤•ą„‡ साऄ ą¤øą„ą¤Ŗą„ˆą¤® ą¤Ŗą„ą¤°ą¤¾ą¤Ŗą„ą¤¤ ą¤¹ą„‹ रहा ą¤¹ą„ˆ, ą¤¤ą„‹ आप ą¤øą¤¾ą¤‡ą¤Ÿ ą¤•ą„‹ ą¤…ą¤øą„ą¤„ą¤¾ą¤Æą„€ ą¤°ą„‚ą¤Ŗ ą¤øą„‡ ą¤¬ą„ą¤²ą„‰ą¤• कर ą¤øą¤•ą¤¤ą„‡ ą¤¹ą„ˆą¤‚ą„¤" + }, + "spamModalTemporaryBlockButton": { + "message": "इस ą¤øą¤¾ą¤‡ą¤Ÿ ą¤•ą„‹ ą¤…ą¤øą„ą¤„ą¤¾ą¤Æą„€ ą¤°ą„‚ą¤Ŗ ą¤øą„‡ ą¤¬ą„ą¤²ą„‰ą¤• ą¤•ą¤°ą„‡ą¤‚" + }, + "spamModalTitle": { + "message": "ą¤¹ą¤®ą¤Øą„‡ ą¤•ą¤ˆ ą¤…ą¤Øą„ą¤°ą„‹ą¤§ ą¤Øą„‹ą¤Ÿą¤æą¤ø ą¤•ą¤æą¤ ą¤¹ą„ˆą¤‚" + }, "speed": { "message": "गति" }, @@ -5000,10 +5302,28 @@ "spendingCap": { "message": "ą¤–ą¤°ą„ą¤š ą¤•ą¤°ą¤Øą„‡ ą¤•ą„€ लिमिट" }, + "spendingCaps": { + "message": "ą¤–ą¤°ą„ą¤š ą¤•ą¤°ą¤Øą„‡ ą¤•ą„€ लिमिट" + }, "srpInputNumberOfWords": { "message": "ą¤®ą„‡ą¤°ą„‡ पास ą¤ą¤• $1-ą¤¶ą¤¬ą„ą¤¦ का ą¤«ą¤¼ą„ą¤°ą„‡ą¤œą¤¼ ą¤¹ą„ˆ", "description": "This is the text for each option in the dropdown where a user selects how many words their secret recovery phrase has during import. The $1 is the number of words (either 12, 15, 18, 21, or 24)." }, + "srpListName": { + "message": "ą¤øą„€ą¤•ą„ą¤°ą„‡ą¤Ÿ ą¤°ą¤æą¤•ą¤µą¤°ą„€ ą¤«ą„ą¤°ą„‡ą„› $1", + "description": "$1 is the order of the Secret Recovery Phrase" + }, + "srpListNumberOfAccounts": { + "message": "$1 ą¤ą¤•ą¤¾ą¤‰ą¤‚ą¤Ÿą„ą¤ø", + "description": "$1 is the number of accounts in the list" + }, + "srpListSelectionDescription": { + "message": "ą¤øą„€ą¤•ą„ą¤°ą„‡ą¤Ÿ ą¤°ą¤æą¤•ą¤µą¤°ą„€ ą¤«ą„ą¤°ą„‡ą„› ą¤œą¤æą¤øą¤øą„‡ आपका नया ą¤…ą¤•ą¤¾ą¤‰ą¤‚ą¤Ÿ ą¤œą¤Øą¤°ą„‡ą¤Ÿ ą¤¹ą„‹ą¤—ą¤¾" + }, + "srpListSingleOrZero": { + "message": "$1 ą¤…ą¤•ą¤¾ą¤‰ą¤‚ą¤Ÿ", + "description": "$1 is the number of accounts in the list, it is either 1 or 0" + }, "srpPasteFailedTooManyWords": { "message": "ą¤Ŗą„‡ą¤øą„ą¤Ÿ ą¤Øą¤¹ą„€ą¤‚ ą¤¹ą„‹ पाया ą¤•ą„ą¤Æą„‹ą¤‚ą¤•ą¤æ ą¤‰ą¤øą¤®ą„‡ą¤‚ 24 ą¤øą„‡ ą¤œą¤¼ą„ą¤Æą¤¾ą¤¦ą¤¾ ą¤¶ą¤¬ą„ą¤¦ ą¤¹ą„ˆą¤‚ą„¤ ą¤øą„€ą¤•ą„ą¤°ą„‡ą¤Ÿ ą¤°ą¤æą¤•ą¤µą¤°ą„€ ą¤«ą¤¼ą„ą¤°ą„‡ą¤œą¤¼ ą¤®ą„‡ą¤‚ अधिकतम 24 ą¤¶ą¤¬ą„ą¤¦ ą¤¹ą„‹ ą¤øą¤•ą¤¤ą„‡ ą¤¹ą„ˆą¤‚ą„¤", "description": "Description of SRP paste error when the pasted content has too many words" @@ -5158,6 +5478,9 @@ "message": "ą¤®ą¤¾ą¤°ą„ą¤•ą„‡ą¤Ÿ ą¤•ą„‡ ą¤†ą¤•ą¤øą„ą¤®ą¤æą¤• ą¤¬ą¤¦ą¤²ą¤¾ą¤µą„‹ą¤‚ ą¤•ą„‡ कारण ą¤µą¤æą¤«ą¤²ą¤¤ą¤¾ą¤ą¤‚ ą¤¹ą„‹ ą¤øą¤•ą¤¤ą„€ ą¤¹ą„ˆą¤‚ą„¤ अगर ą¤øą¤®ą¤øą„ą¤Æą¤¾ ą¤œą¤¾ą¤°ą„€ ą¤°ą¤¹ą¤¤ą„€ ą¤¹ą„ˆ, ą¤¤ą„‹ ą¤•ą„ƒą¤Ŗą¤Æą¤¾ $1 ą¤øą„‡ ą¤•ą„‰ą¤Øą„ą¤Ÿą„‡ą¤•ą„ą¤Ÿ ą¤•ą¤°ą„‡ą¤‚ą„¤", "description": "This message is shown to a user if their swap fails. The $1 will be replaced by support.metamask.io" }, + "stxOptInSupportedNetworksDescription": { + "message": "ą¤øą¤®ą¤°ą„ą¤„ą¤æą¤¤ ą¤Øą„‡ą¤Ÿą¤µą¤°ą„ą¤• पर अधिक ą¤µą¤æą¤¶ą„ą¤µą¤øą¤Øą„€ą¤Æ और ą¤øą„ą¤°ą¤•ą„ą¤·ą¤æą¤¤ ą¤Ÿą„ą¤°ą¤¾ą¤‚ą¤øą„‡ą¤•ą„ą¤¶ą¤Ø ą¤•ą„‡ ą¤²ą¤æą¤ ą¤øą„ą¤®ą¤¾ą¤°ą„ą¤Ÿ ą¤Ÿą„ą¤°ą¤¾ą¤‚ą¤øą„‡ą¤•ą„ą¤¶ą¤Ø ą¤šą¤¾ą¤²ą„‚ ą¤•ą¤°ą„‡ą¤‚ą„¤ $1" + }, "stxPendingPrivatelySubmittingSwap": { "message": "आपका ą¤øą„ą¤µą„ˆą¤Ŗ ą¤Øą¤æą¤œą„€ ą¤°ą„‚ą¤Ŗ ą¤øą„‡ सबमिट किया जा रहा ą¤¹ą„ˆ..." }, @@ -5977,6 +6300,12 @@ "message": "ą¤µą¤°ą„ą¤¤ą¤®ą¤¾ą¤Ø ą¤®ą„‡ą¤‚ NFT (ERC-721) ą¤Ÿą„‹ą¤•ą¤Ø ą¤­ą„‡ą¤œą¤Øą¤¾ ą¤øą¤®ą¤°ą„ą¤„ą¤æą¤¤ ą¤Øą¤¹ą„€ą¤‚ ą¤¹ą„ˆ", "description": "This is an error message we show the user if they attempt to send an NFT asset type, for which currently don't support sending" }, + "unstableTokenPriceDescription": { + "message": "ą¤…ą¤®ą„‡ą¤°ą¤æą¤•ą„€ ą¤”ą„‰ą¤²ą¤° ą¤®ą„‡ą¤‚ इस ą¤Ÿą„‹ą¤•ą¤Ø ą¤•ą„€ ą¤•ą„€ą¤®ą¤¤ ą¤…ą¤¤ą„ą¤Æą¤§ą¤æą¤• ą¤…ą¤øą„ą¤„ą¤æą¤° ą¤¹ą„ˆ, ą¤œą„‹ ą¤‡ą¤øą¤•ą„‡ साऄ ą¤‡ą¤‚ą¤Ÿą¤°ą„ˆą¤•ą„ą¤Ÿ ą¤•ą¤°ą¤•ą„‡ ą¤®ą¤¹ą¤¤ą„ą¤µą¤Ŗą„‚ą¤°ą„ą¤£ ą¤®ą„‚ą¤²ą„ą¤Æ ą¤–ą„‹ą¤Øą„‡ ą¤•ą„‡ ą¤‰ą¤šą„ą¤š ą¤œą„‹ą¤–ą¤æą¤® ą¤•ą„‹ ą¤¦ą¤°ą„ą¤¶ą¤¾ą¤¤ą¤¾ ą¤¹ą„ˆą„¤" + }, + "unstableTokenPriceTitle": { + "message": "ą¤…ą¤øą„ą¤„ą¤æą¤° ą¤Ÿą„‹ą¤•ą¤Ø ą¤•ą„€ ą¤•ą„€ą¤®ą¤¤" + }, "upArrow": { "message": "अप ą¤ą¤°ą„‹" }, @@ -6099,6 +6428,18 @@ "visitSite": { "message": "ą¤øą¤¾ą¤‡ą¤Ÿ पर ą¤œą¤¾ą¤ą¤‚" }, + "visitSupportDataConsentModalAccept": { + "message": "ą¤•ą¤Øą„ą¤«ą¤°ą„ą¤® ą¤•ą¤°ą„‡ą¤‚" + }, + "visitSupportDataConsentModalDescription": { + "message": "ą¤•ą„ą¤Æą¤¾ आप अपना MetaMask ą¤Ŗą¤¹ą¤šą¤¾ą¤Øą¤•ą¤°ą„ą¤¤ą¤¾ और ऐप ą¤øą¤‚ą¤øą„ą¤•ą¤°ą¤£ ą¤¹ą¤®ą¤¾ą¤°ą„‡ ą¤øą¤Ŗą„‹ą¤°ą„ą¤Ÿ ą¤øą„‡ą¤‚ą¤Ÿą¤° ą¤•ą„‡ साऄ ą¤øą¤¾ą¤ą¤¾ करना ą¤šą¤¾ą¤¹ą¤¤ą„‡ ą¤¹ą„ˆą¤‚? ą¤‡ą¤øą¤øą„‡ ą¤¹ą¤®ą„‡ą¤‚ ą¤†ą¤Ŗą¤•ą„€ ą¤øą¤®ą¤øą„ą¤Æą¤¾ ą¤•ą„‹ ą¤¬ą„‡ą¤¹ą¤¤ą¤° ढंग ą¤øą„‡ हल ą¤•ą¤°ą¤Øą„‡ ą¤®ą„‡ą¤‚ मदद मिल ą¤øą¤•ą¤¤ą„€ ą¤¹ą„ˆ, ą¤²ą„‡ą¤•ą¤æą¤Ø यह ą¤µą„ˆą¤•ą¤²ą„ą¤Ŗą¤æą¤• ą¤¹ą„ˆą„¤" + }, + "visitSupportDataConsentModalReject": { + "message": "ą¤øą¤¾ą¤ą¤¾ न ą¤•ą¤°ą„‡ą¤‚" + }, + "visitSupportDataConsentModalTitle": { + "message": "ą¤øą¤Ŗą„‹ą¤°ą„ą¤Ÿ ą¤•ą„‡ साऄ औिवाइस विवरण ą¤øą¤¾ą¤ą¤¾ ą¤•ą¤°ą„‡ą¤‚" + }, "visitWebSite": { "message": "ą¤¹ą¤®ą¤¾ą¤°ą„€ ą¤µą„‡ą¤¬ą¤øą¤¾ą¤‡ą¤Ÿ पर ą¤œą¤¾ą¤ą¤‚" }, diff --git a/app/_locales/id/messages.json b/app/_locales/id/messages.json index e804be2c09ef..77a9cec928bc 100644 --- a/app/_locales/id/messages.json +++ b/app/_locales/id/messages.json @@ -44,6 +44,20 @@ "QRHardwareWalletSteps2Description": { "message": "Ngrave Zero" }, + "SrpListHideAccounts": { + "message": "Sembunyikan $1 akun", + "description": "$1 is the number of accounts" + }, + "SrpListHideSingleAccount": { + "message": "Sembunyikan 1 akun" + }, + "SrpListShowAccounts": { + "message": "Tampilkan $1 akun", + "description": "$1 is the number of accounts" + }, + "SrpListShowSingleAccount": { + "message": "Tampilkan 1 akun" + }, "about": { "message": "Tentang" }, @@ -76,6 +90,9 @@ "accountDetails": { "message": "Detail akun" }, + "accountDetailsRevokeDelegationButton": { + "message": " Beralih kembali ke akun reguler" + }, "accountIdenticon": { "message": "Identikon akun" }, @@ -153,6 +170,12 @@ "addAlias": { "message": "Tambahkan alias" }, + "addBitcoinAccountLabel": { + "message": "Akun Bitcoin (Beta)" + }, + "addBitcoinTestnetAccountLabel": { + "message": "Akun Bitcoin (Testnet)" + }, "addBlockExplorer": { "message": "Tambahkan block explorer" }, @@ -193,6 +216,9 @@ "addFriendsAndAddresses": { "message": "Tambahkan teman dan alamat yang Anda percayai" }, + "addHardwareWalletLabel": { + "message": "Dompet perangkat keras" + }, "addIPFSGateway": { "message": "Tambahkan gateway IPFS pilihan Anda" }, @@ -212,12 +238,26 @@ "addNewAccount": { "message": "Tambahkan akun Ethereum baru" }, + "addNewEthereumAccountLabel": { + "message": "Akun Ethereum" + }, + "addNewSolanaAccountLabel": { + "message": "Akun Solana" + }, "addNft": { "message": "Tambahkan NFT" }, "addNfts": { "message": "Tambahkan NFT" }, + "addNonEvmAccount": { + "message": "Tambahkan akun $1", + "description": "$1 is the non EVM network where the account is going to be created, e.g. Bitcoin or Solana" + }, + "addNonEvmAccountFromNetworkPicker": { + "message": "Untuk mengaktifkan jaringan $1, Anda perlu membuat akun $2.", + "description": "$1 is the non EVM network where the account is going to be created, e.g. Solana Mainnet or Solana Devnet. $2 is the account type, e.g. Bitcoin or Solana" + }, "addRpcUrl": { "message": "Tambahkan URL RPC" }, @@ -300,14 +340,16 @@ "advancedPriorityFeeToolTip": { "message": "Biaya prioritas (alias ā€œtip penambangā€) langsung masuk ke penambang dan memberi insentif kepada mereka untuk memprioritaskan transaksi Anda." }, - "aggregatedBalancePopover": { - "message": "Ini mencerminkan nilai semua token yang Anda miliki di jaringan tertentu. Jika Anda lebih suka melihat nilai ini dalam ETH atau mata uang lainnya, pilih $1.", - "description": "$1 represents the settings page" - }, "agreeTermsOfUse": { "message": "Saya menyetujui $1 MetaMask", "description": "$1 is the `terms` link" }, + "airDropPatternDescription": { + "message": "Riwayat token on-chain menampilkan kejadian sebelumnya mengenai aktivitas airdrop yang mencurigakan." + }, + "airDropPatternTitle": { + "message": "Pola Airdrop" + }, "airgapVault": { "message": "AirGap Vault" }, @@ -726,9 +768,21 @@ "bridgeConfirmTwoTransactions": { "message": "Anda perlu mengonfirmasikan 2 transaksi pada dompet perangkat keras:" }, + "bridgeCreateSolanaAccount": { + "message": "Buat akun Solana" + }, + "bridgeCreateSolanaAccountDescription": { + "message": "Untuk beralih ke jaringan Solana, Anda memerlukan akun dan alamat penerima." + }, + "bridgeCreateSolanaAccountTitle": { + "message": "Anda memerlukan akun Solana terlebih dahulu." + }, "bridgeEnterAmount": { "message": "Masukkan jumlah" }, + "bridgeEnterAmountAndSelectAccount": { + "message": "Masukkan jumlah dan pilih akun tujuan" + }, "bridgeExplorerLinkViewOn": { "message": "Lihat di $1" }, @@ -751,9 +805,15 @@ "bridgeQuoteExpired": { "message": "Waktu kuotasi telah habis." }, + "bridgeSelectDestinationAccount": { + "message": "Pilih akun tujuan" + }, "bridgeSelectNetwork": { "message": "Pilih jaringan" }, + "bridgeSelectTokenAmountAndAccount": { + "message": "Pilih token, jumlah, dan akun tujuan" + }, "bridgeSelectTokenAndAmount": { "message": "Pilih token dan jumlah" }, @@ -944,6 +1004,12 @@ "message": "Opsi tidak ditemukan", "description": "Default text shown in the combo field dropdown if no options." }, + "concentratedSupplyDistributionDescription": { + "message": "Mayoritas suplai token dipegang oleh pemegang token teratas, sehingga menimbulkan risiko manipulasi harga terpusat" + }, + "concentratedSupplyDistributionTitle": { + "message": "Distribusi Suplai Terkonsentrasi" + }, "configureSnapPopupDescription": { "message": "Sekarang, Anda akan meninggalkan MetaMask untuk mengonfigurasi snap ini." }, @@ -962,6 +1028,15 @@ "confirm": { "message": "Konfirmasikan" }, + "confirmAccountType": { + "message": "Jenis" + }, + "confirmAccountTypeSmartContract": { + "message": "Akun cerdas" + }, + "confirmAccountTypeStandard": { + "message": "Akun standar" + }, "confirmAlertModalAcknowledgeMultiple": { "message": "Saya telah mengetahui peringatannya dan tetap ingin melanjutkan" }, @@ -974,12 +1049,36 @@ "confirmFieldTooltipPaymaster": { "message": "Biaya untuk transaksi ini akan dibayar oleh kontrak cerdas paymaster." }, + "confirmGasFeeTokenBalance": { + "message": "Saldo:" + }, + "confirmGasFeeTokenInsufficientBalance": { + "message": "Dana tidak cukup" + }, + "confirmGasFeeTokenMetaMaskFee": { + "message": "Termasuk biaya $1" + }, + "confirmGasFeeTokenModalTitle": { + "message": "Pilih token" + }, + "confirmGasFeeTokenToast": { + "message": "Anda membayar biaya jaringan ini dengan $1" + }, + "confirmGasFeeTokenTooltip": { + "message": "Biaya ini dibayarkan ke jaringan untuk memproses transaksi Anda. Biaya ini mencakup biaya MetaMask sebesar $1 untuk token non-ETH." + }, + "confirmNestedTransactionTitle": { + "message": "Transaksi $1" + }, "confirmPassword": { "message": "Konfirmasikan kata sandi" }, "confirmRecoveryPhrase": { "message": "Konfirmasikan Frasa Pemulihan Rahasia" }, + "confirmSimulationApprove": { + "message": "Anda menyetujui" + }, "confirmTitleApproveTransactionNFT": { "message": "Permintaan penarikan" }, @@ -1022,9 +1121,24 @@ "confirmTitleTransaction": { "message": "Permintaan transaksi" }, + "confirmUpgradeCancelModalButtonCancelTransaction": { + "message": "Batalkan transaksi" + }, + "confirmUpgradeCancelModalButtonCancelUpgrade": { + "message": "Batalkan pembaruan & transaksi" + }, + "confirmUpgradeCancelModalDescription": { + "message": "Jika tidak ingin memperbarui akun, Anda dapat membatalkannya di sini.\n\nUntuk menyelesaikan transaksi ini tanpa pembaruan, Anda harus mengajukan permintaan ini lagi di situs. $1." + }, + "confirmUpgradeCancelModalTitle": { + "message": "Batalkan transaksi" + }, "confirmationAlertDetails": { "message": "Untuk melindungi aset Anda, sebaiknya tolak permintaan tersebut." }, + "confirmationAlertModalTitleDescription": { + "message": "Aset Anda berpotensi hilang" + }, "confirmed": { "message": "Dikonfirmasikan" }, @@ -1052,6 +1166,9 @@ "connectAccounts": { "message": "Hubungkan akun" }, + "connectAnAccountHeader": { + "message": "Hubungkan akun" + }, "connectManually": { "message": "Hubungkan ke situs saat ini secara manual" }, @@ -1158,6 +1275,9 @@ "message": "Pengambilan $1 gagal, periksa jaringan Anda dan coba lagi.", "description": "$1 is the name of the snap being fetched." }, + "connectionPopoverDescription": { + "message": "Untuk terhubung ke situs, pilih tombol hubungkan. MetaMask hanya dapat terhubung ke situs web3." + }, "connectionRequest": { "message": "Permintaan koneksi" }, @@ -1219,6 +1339,9 @@ "create": { "message": "Buat" }, + "createNewAccountHeader": { + "message": "Buat akun baru" + }, "createNewWallet": { "message": "Buat dompet baru" }, @@ -1231,6 +1354,9 @@ "createSnapAccountTitle": { "message": "Buat akun" }, + "createSolanaAccount": { + "message": "Buat akun Solana" + }, "creatorAddress": { "message": "Alamat pembuat" }, @@ -1471,6 +1597,21 @@ "message": "Deskripsi dari $1", "description": "$1 represents the name of the snap" }, + "destinationAccountPickerNoEligible": { + "message": "Tidak ditemukan akun yang memenuhi syarat" + }, + "destinationAccountPickerNoMatching": { + "message": "Tidak ditemukan akun yang cocok" + }, + "destinationAccountPickerReceiveAt": { + "message": "Terima di" + }, + "destinationAccountPickerSearchPlaceholderToMainnet": { + "message": "Alamat penerima atau ENS" + }, + "destinationAccountPickerSearchPlaceholderToSolana": { + "message": "Alamat penerima" + }, "details": { "message": "Detail" }, @@ -1516,6 +1657,9 @@ "message": "$1 terputus koneksinya dari $2", "description": "$1 is name of the name and $2 represents the dapp name`" }, + "discover": { + "message": "Temukan" + }, "discoverSnaps": { "message": "Temukan Snap", "description": "Text that links to the Snaps website. Displayed in a banner on Snaps list page in settings." @@ -1872,6 +2016,9 @@ "experimental": { "message": "Eksperimental" }, + "exploreweb3": { + "message": "Jelajahi web3" + }, "exportYourData": { "message": "Ekspor data Anda" }, @@ -1885,6 +2032,9 @@ "message": "Jelajahi Snap yang dibuat oleh komunitas untuk menyesuaikan pengalaman web3 Anda", "description": "Banner description displayed on Snaps list page in Settings when less than 6 Snaps is installed." }, + "externalAccount": { + "message": "Akun Eksternal" + }, "externalExtension": { "message": "Ekstensi eksternal" }, @@ -2197,6 +2347,12 @@ "holdToRevealUnlockedLabel": { "message": "tahan untuk mengungkapkan lingkaran terbuka" }, + "honeypotDescription": { + "message": "Token ini dapat menimbulkan risiko honeypot. Disarankan untuk melakukan uji tuntas sebelum berinteraksi untuk mencegah potensi kerugian finansial." + }, + "honeypotTitle": { + "message": "Honey Pot" + }, "howNetworkFeesWorkExplanation": { "message": "Estimasi biaya yang diperlukan untuk memproses transaksi. Biaya maksimumnya adalah $1." }, @@ -2262,6 +2418,30 @@ "importNFTTokenIdToolTip": { "message": "ID NFT merupakan pengenal unik karena tidak ada dua NFT yang sama. Sekali lagi, angka ini berada di bawah 'Detail' pada OpenSea. Catat atau salin ke papan klip." }, + "importNWordSRP": { + "message": "Saya memiliki frasa pemulihan $1 kata", + "description": "$1 is the number of words in the recovery phrase" + }, + "importPrivateKey": { + "message": "Kunci Pribadi" + }, + "importSRPDescription": { + "message": "Impor dompet yang ada dengan frasa pemulihan rahasia 12 atau 24 kata." + }, + "importSRPNumberOfWordsError": { + "message": "Frasa Pemulihan Rahasia terdiri dari 12 atau 24 kata" + }, + "importSRPWordError": { + "message": "Kata $1 salah atau salah eja.", + "description": "$1 is the word that is incorrect or misspelled" + }, + "importSRPWordErrorAlternative": { + "message": "Kata $1 dan $2 salah atau salah eja.", + "description": "$1 and $2 are multiple words that are mispelled." + }, + "importSecretRecoveryPhrase": { + "message": "Impor Frasa Pemulihan Rahasia" + }, "importSelectedTokens": { "message": "Impor token yang dipilih?" }, @@ -2280,6 +2460,12 @@ "importTokensError": { "message": "Kami tidak dapat mengimpor token. Coba lagi nanti." }, + "importWallet": { + "message": "Impor dompet" + }, + "importWalletOrAccountHeader": { + "message": "Impor dompet atau akun" + }, "importWithCount": { "message": "Impor $1", "description": "$1 will the number of detected tokens that are selected for importing, if all of them are selected then $1 will be all" @@ -2327,6 +2513,12 @@ "insufficientFundsForGas": { "message": "Dana untuk gas tidak cukup" }, + "insufficientLockedLiquidityDescription": { + "message": "Kurangnya likuiditas yang dikunci atau dibakar secara memadai membuat token rentan terhadap penarikan likuiditas secara tiba-tiba, yang berpotensi menyebabkan ketidakstabilan pasar." + }, + "insufficientLockedLiquidityTitle": { + "message": "Likuiditas Terkunci Tidak Cukup" + }, "insufficientTokens": { "message": "Token tidak cukup." }, @@ -2362,6 +2554,9 @@ "invalidCustomNetworkAlertTitle": { "message": "Jaringan kustom tidak valid" }, + "invalidHexData": { + "message": "Data hex tidak valid" + }, "invalidHexNumber": { "message": "Bilangan heksadesimal tidak valid." }, @@ -2540,6 +2735,9 @@ "ledgerLocked": { "message": "Tidak dapat terhubung ke perangkat Ledger. Pastikan perangkat Anda tidak terkunci dan aplikasi Ethereum terbuka." }, + "ledgerMultipleDevicesUnsupportedErrorMessage": { + "message": "Beberapa perangkat Ledger tidak dapat dihubungkan pada saat bersamaan. Untuk menghubungkan perangkat Ledger yang baru, Anda harus memutus koneksi perangkat sebelumnya terlebih dahulu." + }, "ledgerTimeout": { "message": "Respons Ledger Live terlalu lama atau waktu koneksi habis. Pastikan aplikasi Ledger Live terbuka dan perangkat Anda tidak terkunci." }, @@ -2637,6 +2835,9 @@ "manageDefaultSettings": { "message": "Kelola pengaturan privasi default" }, + "managePermissions": { + "message": "Kelola izin" + }, "marketCap": { "message": "Kap pasar" }, @@ -2755,6 +2956,15 @@ "multichainAddEthereumChainConfirmationDescription": { "message": "Anda menambahkan jaringan ini ke MetaMask dan memberikan situs ini izin untuk menggunakannya." }, + "multichainQuoteCardBridgingLabel": { + "message": "Bridge" + }, + "multichainQuoteCardQuoteLabel": { + "message": "Kuotasi" + }, + "multichainQuoteCardTimeLabel": { + "message": "Waktu" + }, "multipleSnapConnectionWarning": { "message": "$1 ingin menggunakan Snap $2", "description": "$1 is the dapp and $2 is the number of snaps it wants to connect to." @@ -2869,6 +3079,13 @@ "network": { "message": "Jaringan:" }, + "networkChanged": { + "message": "Jaringan diubah" + }, + "networkChangedMessage": { + "message": "Saat ini Anda bertransaksi pada $1.", + "description": "$1 is the name of the network" + }, "networkDetails": { "message": "Detail jaringan" }, @@ -3143,6 +3360,9 @@ "notEnoughGas": { "message": "Gas tidak cukup" }, + "notNow": { + "message": "Tidak sekarang" + }, "notificationDetail": { "message": "Detail" }, @@ -3505,6 +3725,13 @@ "origin": { "message": "Asal" }, + "originChanged": { + "message": "Situs diubah" + }, + "originChangedMessage": { + "message": "Saat ini Anda sedang meninjau permintaan dari $1.", + "description": "$1 is the name of the origin" + }, "osTheme": { "message": "Sistem" }, @@ -3559,6 +3786,14 @@ "pending": { "message": "Menunggu" }, + "pendingConfirmationAddNetworkAlertMessage": { + "message": "Memperbarui jaringan akan membatalkan $1 transaksi tertunda dari situs ini.", + "description": "Number of transactions." + }, + "pendingConfirmationSwitchNetworkAlertMessage": { + "message": "Beralih jaringan akan membatalkan $1 transaksi tertunda dari situs ini.", + "description": "Number of transactions." + }, "pendingTransactionAlertMessage": { "message": "Transaksi ini tidak akan berhasil sampai transaksi sebelumnya selesai. $1", "description": "$1 represents the words 'how to cancel or speed up a transaction' in a hyperlink" @@ -3842,6 +4077,9 @@ "permitSimulationChange_receive": { "message": "Anda menerima" }, + "permitSimulationChange_revoke2": { + "message": "Cabut" + }, "permitSimulationChange_transfer": { "message": "Anda mengirim" }, @@ -4237,6 +4475,9 @@ "reusedTokenNameWarning": { "message": "Token di sini menggunakan kembali simbol dari token lain yang Anda lihat, ini bisa jadi membingungkan atau menipu." }, + "revealSecretRecoveryPhrase": { + "message": "Tampilkan Frasa Pemulihan Rahasia" + }, "revealSeedWords": { "message": "Tampilkan Frasa Pemulihan Rahasia" }, @@ -4286,12 +4527,19 @@ "reviewAlerts": { "message": "Tinjau peringatan" }, + "reviewPendingTransactions": { + "message": "Tinjau transaksi tertunda" + }, "reviewPermissions": { "message": "Tinjau izin" }, "revokePermission": { "message": "Cabut izin" }, + "revokePermissionTitle": { + "message": "Hapus izin $1", + "description": "The token symbol that is being revoked" + }, "revokeSimulationDetailsDesc": { "message": "Anda menghapus izin orang lain untuk menggunakan token dari akun Anda." }, @@ -4334,6 +4582,10 @@ "secretRecoveryPhrase": { "message": "Frasa Pemulihan Rahasia" }, + "secretRecoveryPhrasePlusNumber": { + "message": "Frasa Pemulihan Rahasia $1", + "description": "The $1 is the order of the Secret Recovery Phrase" + }, "secureWallet": { "message": "Amankan dompet" }, @@ -4424,6 +4676,9 @@ "select": { "message": "Pilih" }, + "selectAccountToConnect": { + "message": "Pilih akun yang akan dihubungkan" + }, "selectAccounts": { "message": "Pilih akun untuk menggunakan situs ini" }, @@ -4454,6 +4709,9 @@ "selectRpcUrl": { "message": "Pilih URL RPC" }, + "selectSecretRecoveryPhrase": { + "message": "Pilih Frasa Pemulihan Rahasia" + }, "selectType": { "message": "Pilih Jenis" }, @@ -4565,16 +4823,6 @@ "showHexDataDescription": { "message": "Pilih ini untuk menampilkan bidang data hex di layar kirim" }, - "showIncomingTransactions": { - "message": "Tampilkan transaksi masuk" - }, - "showIncomingTransactionsDescription": { - "message": "Pilih ini untuk menggunakan Etherscan untuk menampilkan transaksi yang masuk di daftar transaksi", - "description": "$1 is the link to etherscan url and $2 is the link to the privacy policy of consensys APIs" - }, - "showIncomingTransactionsExplainer": { - "message": "Ini bergantung pada API pihak ketiga yang berbeda untuk setiap jaringan, yang mengungkap alamat Ethereum dan alamat IP Anda." - }, "showLess": { "message": "Ciutkan" }, @@ -4593,6 +4841,9 @@ "showPrivateKey": { "message": "Tampilkan kunci pribadi" }, + "showSRP": { + "message": "Tampilkan Frasa Pemulihan Rahasia" + }, "showTestnetNetworks": { "message": "Tampilkan jaringan pengujian" }, @@ -4714,12 +4965,24 @@ "slideCashOutTitle": { "message": "Cairkan uang tunai dengan MetaMask" }, + "slideDebitCardDescription": { + "message": "Tersedia di wilayah tertentu" + }, "slideDebitCardTitle": { "message": "Kartu debit MetaMask" }, + "slideFundWalletDescription": { + "message": "Tambah atau transfer token untuk memulai" + }, "slideFundWalletTitle": { "message": "Danai dompet Anda" }, + "slideSweepStakeDescription": { + "message": "Cetak NFT sekarang dan raih peluang untuk menang" + }, + "slideSweepStakeTitle": { + "message": "Ikuti Giveaway USDC senilai $5000!" + }, "smartContracts": { "message": "Kontrak cerdas" }, @@ -4866,6 +5129,9 @@ "snapResultSuccessDescription": { "message": "$1 siap digunakan" }, + "snapUIAssetSelectorTitle": { + "message": "Pilih aset" + }, "snapUpdateAlertDescription": { "message": "Dapatkan versi terbaru $1", "description": "Description used in Snap update alert banner when snap update is available. $1 is the Snap name." @@ -4925,6 +5191,27 @@ "message": "Hubungi pembuat $1 untuk dukungan lebih lanjut.", "description": "This is shown when the insight snap throws an error. $1 is the snap name" }, + "solanaImportAccounts": { + "message": "Impor akun Solana" + }, + "solanaImportAccountsDescription": { + "message": "Impor Frasa Pemulihan Rahasia untuk memindahkan akun Solana dari dompet lain." + }, + "solanaMoreFeaturesComingSoon": { + "message": "Fitur lainnya segera hadir" + }, + "solanaMoreFeaturesComingSoonDescription": { + "message": "Dapp Solana, NFT, dukungan dompet perangkat keras, dan lainnya segera hadir." + }, + "solanaOnMetaMask": { + "message": "Solana di MetaMask" + }, + "solanaSendReceiveSwapTokens": { + "message": "Kirim, terima, dan tukar token" + }, + "solanaSendReceiveSwapTokensDescription": { + "message": "Transfer dan bertransaksi dengan token seperti SOL, USDC, dan lainnya." + }, "someNetworks": { "message": "$1 jaringan" }, @@ -4951,6 +5238,21 @@ "source": { "message": "Sumber" }, + "spamModalBlockedDescription": { + "message": "Situs ini akan diblokir selama 1 menit." + }, + "spamModalBlockedTitle": { + "message": "Anda telah memblokir situs ini untuk sementara" + }, + "spamModalDescription": { + "message": "Jika dibombardir dengan banyak permintaan, Anda dapat memblokir situs tersebut untuk sementara." + }, + "spamModalTemporaryBlockButton": { + "message": "Blokir situs ini untuk sementara" + }, + "spamModalTitle": { + "message": "Kami telah melihat banyak permintaan" + }, "speed": { "message": "Kecepatan" }, @@ -5000,10 +5302,28 @@ "spendingCap": { "message": "Batas penggunaan" }, + "spendingCaps": { + "message": "Batas penggunaan" + }, "srpInputNumberOfWords": { "message": "Frasa milik saya memiliki $1 kata", "description": "This is the text for each option in the dropdown where a user selects how many words their secret recovery phrase has during import. The $1 is the number of words (either 12, 15, 18, 21, or 24)." }, + "srpListName": { + "message": "Frasa Pemulihan Rahasia $1", + "description": "$1 is the order of the Secret Recovery Phrase" + }, + "srpListNumberOfAccounts": { + "message": "$1 akun", + "description": "$1 is the number of accounts in the list" + }, + "srpListSelectionDescription": { + "message": "Frasa Pemulihan Rahasia akun baru Anda akan dibuat dari" + }, + "srpListSingleOrZero": { + "message": "$1 akun", + "description": "$1 is the number of accounts in the list, it is either 1 or 0" + }, "srpPasteFailedTooManyWords": { "message": "Gagal ditempel karena memuat lebih dari 24 kata. Frasa pemulihan rahasia dapat memuat maksimum 24 kata.", "description": "Description of SRP paste error when the pasted content has too many words" @@ -5158,6 +5478,9 @@ "message": "Perubahan pasar yang terjadi secara tiba-tiba dapat menyebabkan kegagalan. Jika masalah berlanjut, hubungi $1.", "description": "This message is shown to a user if their swap fails. The $1 will be replaced by support.metamask.io" }, + "stxOptInSupportedNetworksDescription": { + "message": "Aktifkan Transaksi Pintar untuk transaksi yang lebih andal dan aman di jaringan yang didukung. $1" + }, "stxPendingPrivatelySubmittingSwap": { "message": "Kirimkan Swap Anda secara pribadi..." }, @@ -5977,6 +6300,12 @@ "message": "Tidak mendukung pengiriman token NFT (ERC-721) untuk saat ini", "description": "This is an error message we show the user if they attempt to send an NFT asset type, for which currently don't support sending" }, + "unstableTokenPriceDescription": { + "message": "Harga token ini dalam USD sangat fluktuatif, menunjukkan risiko tinggi kehilangan nilai yang signifikan saat berinteraksi dengannya." + }, + "unstableTokenPriceTitle": { + "message": "Harga Token Tidak Stabil" + }, "upArrow": { "message": "panah naik" }, @@ -6099,6 +6428,18 @@ "visitSite": { "message": "Kunjungi situs" }, + "visitSupportDataConsentModalAccept": { + "message": "Konfirmasikan" + }, + "visitSupportDataConsentModalDescription": { + "message": "Ingin membagikan Pengidentifikasi MetaMask dan versi aplikasi dengan Pusat Dukungan kami? Ini dapat membantu kami menyelesaikan masalah Anda dengan lebih baik, tetapi tindakan ini bersifat opsional." + }, + "visitSupportDataConsentModalReject": { + "message": "Jangan bagikan" + }, + "visitSupportDataConsentModalTitle": { + "message": "Bagikan detail perangkat kepada dukungan" + }, "visitWebSite": { "message": "Kunjungi situs web kami" }, diff --git a/app/_locales/it/messages.json b/app/_locales/it/messages.json index 046be230a4f5..c1ad7b9b0af9 100644 --- a/app/_locales/it/messages.json +++ b/app/_locales/it/messages.json @@ -1144,13 +1144,6 @@ "showHexDataDescription": { "message": "Seleziona per mostrare il campo dei dati hex nella schermata di invio" }, - "showIncomingTransactions": { - "message": "Mostra Transazioni in Ingresso" - }, - "showIncomingTransactionsDescription": { - "message": "Usa Etherscan per visualizzare le transazioni in ingresso nella lista delle transazioni", - "description": "$1 is the link to etherscan url and $2 is the link to the privacy policy of consensys APIs" - }, "showPermissions": { "message": "Mostra permessi" }, diff --git a/app/_locales/ja/messages.json b/app/_locales/ja/messages.json index fe8081d52a57..8b61ff25bf98 100644 --- a/app/_locales/ja/messages.json +++ b/app/_locales/ja/messages.json @@ -44,6 +44,20 @@ "QRHardwareWalletSteps2Description": { "message": "Ngrave Zero" }, + "SrpListHideAccounts": { + "message": "$1ä»¶ć®ć‚¢ć‚«ć‚¦ćƒ³ćƒˆć‚’éžč”Øē¤ŗ", + "description": "$1 is the number of accounts" + }, + "SrpListHideSingleAccount": { + "message": "1ä»¶ć®ć‚¢ć‚«ć‚¦ćƒ³ćƒˆć‚’éžč”Øē¤ŗ" + }, + "SrpListShowAccounts": { + "message": "$1ä»¶ć®ć‚¢ć‚«ć‚¦ćƒ³ćƒˆć‚’č”Øē¤ŗ", + "description": "$1 is the number of accounts" + }, + "SrpListShowSingleAccount": { + "message": "1ä»¶ć®ć‚¢ć‚«ć‚¦ćƒ³ćƒˆć‚’č”Øē¤ŗ" + }, "about": { "message": "åŸŗęœ¬ęƒ…å ±" }, @@ -76,6 +90,9 @@ "accountDetails": { "message": "ć‚¢ć‚«ć‚¦ćƒ³ćƒˆć®č©³ē“°" }, + "accountDetailsRevokeDelegationButton": { + "message": "å†ć³é€šåøøć‚¢ć‚«ć‚¦ćƒ³ćƒˆć«åˆ‡ć‚Šę›æćˆć¾ć™" + }, "accountIdenticon": { "message": "ć‚¢ć‚«ć‚¦ćƒ³ćƒˆć®ć‚¢ć‚¤ćƒ‡ćƒ³ćƒ†ć‚£ć‚³ćƒ³" }, @@ -153,6 +170,12 @@ "addAlias": { "message": "åˆ„åć‚’čæ½åŠ " }, + "addBitcoinAccountLabel": { + "message": "ćƒ“ćƒƒćƒˆć‚³ć‚¤ćƒ³ć‚¢ć‚«ć‚¦ćƒ³ćƒˆ (ćƒ™ćƒ¼ć‚æ)" + }, + "addBitcoinTestnetAccountLabel": { + "message": "ćƒ“ćƒƒćƒˆć‚³ć‚¤ćƒ³ć‚¢ć‚«ć‚¦ćƒ³ćƒˆ (ćƒ†ć‚¹ćƒˆćƒćƒƒćƒˆ)" + }, "addBlockExplorer": { "message": "ćƒ–ćƒ­ćƒƒć‚Æć‚Øć‚Æć‚¹ćƒ—ćƒ­ćƒ¼ćƒ©ćƒ¼ć‚’čæ½åŠ " }, @@ -193,6 +216,9 @@ "addFriendsAndAddresses": { "message": "äæ”é ¼ć§ćć‚‹å‹é”ćØć‚¢ćƒ‰ćƒ¬ć‚¹ć‚’čæ½åŠ ć™ć‚‹" }, + "addHardwareWalletLabel": { + "message": "ćƒćƒ¼ćƒ‰ć‚¦ć‚§ć‚¢ć‚¦ć‚©ćƒ¬ćƒƒćƒˆ" + }, "addIPFSGateway": { "message": "å„Ŗå…ˆIPFSć‚²ćƒ¼ćƒˆć‚¦ć‚§ć‚¤ć‚’čæ½åŠ " }, @@ -212,12 +238,26 @@ "addNewAccount": { "message": "ę–°ć—ć„ć‚¤ćƒ¼ć‚µćƒŖć‚¢ćƒ ć‚¢ć‚«ć‚¦ćƒ³ćƒˆć‚’čæ½åŠ " }, + "addNewEthereumAccountLabel": { + "message": "ć‚¤ćƒ¼ć‚µćƒŖć‚¢ćƒ ć‚¢ć‚«ć‚¦ćƒ³ćƒˆ" + }, + "addNewSolanaAccountLabel": { + "message": "Solanać‚¢ć‚«ć‚¦ćƒ³ćƒˆ" + }, "addNft": { "message": "NFTć‚’čæ½åŠ " }, "addNfts": { "message": "NFTć‚’čæ½åŠ " }, + "addNonEvmAccount": { + "message": "$1ć‚¢ć‚«ć‚¦ćƒ³ćƒˆć‚’čæ½åŠ ", + "description": "$1 is the non EVM network where the account is going to be created, e.g. Bitcoin or Solana" + }, + "addNonEvmAccountFromNetworkPicker": { + "message": "$1ćƒćƒƒćƒˆćƒÆćƒ¼ć‚Æć‚’ęœ‰åŠ¹ć«ć™ć‚‹ć«ćÆć€$2ć‚¢ć‚«ć‚¦ćƒ³ćƒˆć‚’ä½œęˆć™ć‚‹åæ…č¦ćŒć‚ć‚Šć¾ć™ć€‚", + "description": "$1 is the non EVM network where the account is going to be created, e.g. Solana Mainnet or Solana Devnet. $2 is the account type, e.g. Bitcoin or Solana" + }, "addRpcUrl": { "message": "RPC URLć‚’čæ½åŠ " }, @@ -300,14 +340,16 @@ "advancedPriorityFeeToolTip": { "message": "å„Ŗå…ˆę‰‹ę•°ę–™ (åˆ„åć€Œćƒžć‚¤ćƒŠćƒ¼ćƒćƒƒćƒ—ć€) ćÆćƒžć‚¤ćƒŠćƒ¼ć«ē›“ęŽ„ę”Æę‰•ć‚ć‚Œć€ćƒˆćƒ©ćƒ³ć‚¶ć‚Æć‚·ćƒ§ćƒ³ć‚’å„Ŗå…ˆć™ć‚‹ć‚¤ćƒ³ć‚»ćƒ³ćƒ†ć‚£ćƒ–ćØćŖć‚Šć¾ć™ć€‚" }, - "aggregatedBalancePopover": { - "message": "ć“ć‚Œć«ćÆē‰¹å®šć®ćƒćƒƒćƒˆćƒÆćƒ¼ć‚Æć§ę‰€ęœ‰ć—ć¦ć„ć‚‹ć™ć¹ć¦ć®ćƒˆćƒ¼ć‚Æćƒ³ć®ä¾”å€¤ćŒåę˜ ć•ć‚Œć¦ć„ć¾ć™ć€‚ć“ć®å€¤ć‚’ETHć¾ćŸćÆćć®ä»–é€šč²Øć§č”Øē¤ŗć—ćŸć„å “åˆćÆć€$1に移動します。", - "description": "$1 represents the settings page" - }, "agreeTermsOfUse": { "message": "MetaMask恮$1ć«åŒę„ć—ć¾ć™", "description": "$1 is the `terms` link" }, + "airDropPatternDescription": { + "message": "ćƒˆćƒ¼ć‚Æćƒ³ć®ć‚Ŗćƒ³ćƒć‚§ćƒ¼ćƒ³å±„ę­“ć§ć€äøåÆ©ćŖć‚Øć‚¢ćƒ‰ćƒ­ćƒƒćƒ—ć‚¢ć‚Æćƒ†ć‚£ćƒ“ćƒ†ć‚£ć®ä»„å‰ć®ć‚¤ćƒ³ć‚¹ć‚æćƒ³ć‚¹ć‚’ē¢ŗčŖć§ćć¾ć™ć€‚" + }, + "airDropPatternTitle": { + "message": "ć‚Øć‚¢ćƒ‰ćƒ­ćƒƒćƒ—ćƒ‘ć‚æćƒ¼ćƒ³" + }, "airgapVault": { "message": "AirGap Vault" }, @@ -726,9 +768,21 @@ "bridgeConfirmTwoTransactions": { "message": "ćƒćƒ¼ćƒ‰ć‚¦ć‚§ć‚¢ć‚¦ć‚©ćƒ¬ćƒƒćƒˆć§2ć¤ć®ćƒˆćƒ©ćƒ³ć‚¶ć‚Æć‚·ćƒ§ćƒ³ć‚’ē¢ŗå®šć™ć‚‹åæ…č¦ćŒć‚ć‚Šć¾ć™:" }, + "bridgeCreateSolanaAccount": { + "message": "Solanać‚¢ć‚«ć‚¦ćƒ³ćƒˆć‚’ä½œęˆ" + }, + "bridgeCreateSolanaAccountDescription": { + "message": "SolanaćƒćƒƒćƒˆćƒÆćƒ¼ć‚Æć«ć‚¹ćƒÆćƒƒćƒ—ć™ć‚‹ć«ćÆć€ć‚¢ć‚«ć‚¦ćƒ³ćƒˆćØå—å–ć‚¢ćƒ‰ćƒ¬ć‚¹ćŒåæ…č¦ć§ć™ć€‚" + }, + "bridgeCreateSolanaAccountTitle": { + "message": "ćÆć˜ć‚ć«Solanać‚¢ć‚«ć‚¦ćƒ³ćƒˆćŒåæ…č¦ć§ć™ć€‚" + }, "bridgeEnterAmount": { "message": "é‡‘é”ć‚’å…„åŠ›" }, + "bridgeEnterAmountAndSelectAccount": { + "message": "é‡‘é”ć‚’å…„åŠ›ć—ć¦ć€é€é‡‘å…ˆć‚¢ć‚«ć‚¦ćƒ³ćƒˆć‚’éøęŠžć—ć¾ć™" + }, "bridgeExplorerLinkViewOn": { "message": "$1で蔨示" }, @@ -751,9 +805,15 @@ "bridgeQuoteExpired": { "message": "ć‚Æć‚©ćƒ¼ćƒˆćŒć‚æć‚¤ćƒ ć‚¢ć‚¦ćƒˆć—ć¾ć—ćŸć€‚" }, + "bridgeSelectDestinationAccount": { + "message": "é€é‡‘å…ˆć‚¢ć‚«ć‚¦ćƒ³ćƒˆć‚’éøęŠžć—ć¾ć™" + }, "bridgeSelectNetwork": { "message": "ćƒćƒƒćƒˆćƒÆćƒ¼ć‚Æć‚’éøęŠž" }, + "bridgeSelectTokenAmountAndAccount": { + "message": "ćƒˆćƒ¼ć‚Æćƒ³ć€é‡‘é”ć€é€é‡‘å…ˆć‚¢ć‚«ć‚¦ćƒ³ćƒˆć‚’éøęŠžć—ć¾ć™" + }, "bridgeSelectTokenAndAmount": { "message": "ćƒˆćƒ¼ć‚Æćƒ³ćØé‡‘é”ć‚’éøęŠž" }, @@ -944,6 +1004,12 @@ "message": "ć‚Ŗćƒ—ć‚·ćƒ§ćƒ³ćŒč¦‹ć¤ć‹ć‚Šć¾ć›ć‚“", "description": "Default text shown in the combo field dropdown if no options." }, + "concentratedSupplyDistributionDescription": { + "message": "ä¾›ēµ¦ć•ć‚Œć¦ć„ć‚‹ćƒˆćƒ¼ć‚Æćƒ³ć®å¤§éƒØåˆ†ćŒäøŠä½ćƒˆćƒ¼ć‚Æćƒ³äæęœ‰č€…ć«ć‚ˆć£ć¦äæęœ‰ć•ć‚Œć¦ć„ć‚‹ćŸć‚ć€äø­å¤®é›†ęØ©åž‹ć®ä¾”ę ¼ę“ä½œć®å±é™ŗćŒć‚ć‚Šć¾ć™ć€‚" + }, + "concentratedSupplyDistributionTitle": { + "message": "ä¾›ēµ¦é‡ć®é›†äø­" + }, "configureSnapPopupDescription": { "message": "MetaMaskから移動してこのsnapć‚’ę§‹ęˆć—ć¾ć™ć€‚" }, @@ -962,6 +1028,15 @@ "confirm": { "message": "ē¢ŗčŖ" }, + "confirmAccountType": { + "message": "ć‚æć‚¤ćƒ—" + }, + "confirmAccountTypeSmartContract": { + "message": "ć‚¹ćƒžćƒ¼ćƒˆć‚¢ć‚«ć‚¦ćƒ³ćƒˆ" + }, + "confirmAccountTypeStandard": { + "message": "ć‚¹ć‚æćƒ³ćƒ€ćƒ¼ćƒ‰ć‚¢ć‚«ć‚¦ćƒ³ćƒˆ" + }, "confirmAlertModalAcknowledgeMultiple": { "message": "ć‚¢ćƒ©ćƒ¼ćƒˆć‚’ē¢ŗčŖć—ćŸć†ćˆć§ē¶šč”Œć—ć¾ć™" }, @@ -974,12 +1049,36 @@ "confirmFieldTooltipPaymaster": { "message": "ć“ć®ćƒˆćƒ©ćƒ³ć‚¶ć‚Æć‚·ćƒ§ćƒ³ć®ę‰‹ę•°ę–™ćÆć€ćƒšć‚¤ćƒžć‚¹ć‚æćƒ¼ć®ć‚¹ćƒžćƒ¼ćƒˆć‚³ćƒ³ćƒˆćƒ©ć‚Æćƒˆć«ć‚ˆć‚Šę”Æę‰•ć‚ć‚Œć¾ć™ć€‚" }, + "confirmGasFeeTokenBalance": { + "message": "ę®‹é«˜:" + }, + "confirmGasFeeTokenInsufficientBalance": { + "message": "č³‡é‡‘äøč¶³" + }, + "confirmGasFeeTokenMetaMaskFee": { + "message": "$1の手数料を含む" + }, + "confirmGasFeeTokenModalTitle": { + "message": "ćƒˆćƒ¼ć‚Æćƒ³ć‚’éøęŠž" + }, + "confirmGasFeeTokenToast": { + "message": "ć“ć®ćƒćƒƒćƒˆćƒÆćƒ¼ć‚Æę‰‹ę•°ę–™ćÆ$1で支払います" + }, + "confirmGasFeeTokenTooltip": { + "message": "ć“ć‚ŒćÆćƒˆćƒ©ćƒ³ć‚¶ć‚Æć‚·ćƒ§ćƒ³ć‚’å‡¦ē†ć™ć‚‹ćŸć‚ć«ć€ćƒćƒƒćƒˆćƒÆćƒ¼ć‚Æć«ę”Æę‰•ć‚ć‚Œć¾ć™ć€‚ETHä»„å¤–ć®ćƒˆćƒ¼ć‚Æćƒ³ć«åÆ¾ć™ć‚‹$1恮MetaMaskę‰‹ę•°ę–™ć‚‚å«ć¾ć‚Œć¦ć„ć¾ć™ć€‚" + }, + "confirmNestedTransactionTitle": { + "message": "ćƒˆćƒ©ćƒ³ć‚¶ć‚Æć‚·ćƒ§ćƒ³$1" + }, "confirmPassword": { "message": "ćƒ‘ć‚¹ćƒÆćƒ¼ćƒ‰ć®ē¢ŗčŖ" }, "confirmRecoveryPhrase": { "message": "ć‚·ćƒ¼ć‚Æćƒ¬ćƒƒćƒˆćƒŖć‚«ćƒćƒŖćƒ¼ćƒ•ćƒ¬ćƒ¼ć‚ŗć®ē¢ŗčŖ" }, + "confirmSimulationApprove": { + "message": "ę‰æčŖ" + }, "confirmTitleApproveTransactionNFT": { "message": "å‡ŗé‡‘ć®ćƒŖć‚Æć‚Øć‚¹ćƒˆ" }, @@ -1022,9 +1121,24 @@ "confirmTitleTransaction": { "message": "ćƒˆćƒ©ćƒ³ć‚¶ć‚Æć‚·ćƒ§ćƒ³ć®č¦ę±‚" }, + "confirmUpgradeCancelModalButtonCancelTransaction": { + "message": "ćƒˆćƒ©ćƒ³ć‚¶ć‚Æć‚·ćƒ§ćƒ³ć‚’ć‚­ćƒ£ćƒ³ć‚»ćƒ«" + }, + "confirmUpgradeCancelModalButtonCancelUpgrade": { + "message": "ę›“ę–°ćØćƒˆćƒ©ćƒ³ć‚¶ć‚Æć‚·ćƒ§ćƒ³ć‚’ć‚­ćƒ£ćƒ³ć‚»ćƒ«" + }, + "confirmUpgradeCancelModalDescription": { + "message": "ć‚¢ć‚«ć‚¦ćƒ³ćƒˆć‚’ę›“ę–°ć—ćŖć„å “åˆćÆć€ć“ć”ć‚‰ć‹ć‚‰ć‚­ćƒ£ćƒ³ć‚»ćƒ«ć§ćć¾ć™ć€‚\n\nę›“ę–°ć›ćšć«ć“ć®ćƒˆćƒ©ćƒ³ć‚¶ć‚Æć‚·ćƒ§ćƒ³ć‚’å®Œäŗ†ć•ć›ć‚‹ć«ćÆć€ć‚µć‚¤ćƒˆć§ć“ć®č¦ę±‚ć‚’ć‚‚ć†äø€åŗ¦č”Œć†åæ…č¦ćŒć‚ć‚Šć¾ć™ć€‚$1怂" + }, + "confirmUpgradeCancelModalTitle": { + "message": "ćƒˆćƒ©ćƒ³ć‚¶ć‚Æć‚·ćƒ§ćƒ³ć®ć‚­ćƒ£ćƒ³ć‚»ćƒ«" + }, "confirmationAlertDetails": { "message": "č³‡ē”£ć‚’å®ˆć‚‹ćŸć‚ć€ćƒŖć‚Æć‚Øć‚¹ćƒˆć‚’ę‹’å¦ć™ć‚‹ć“ćØć‚’ćŠå‹§ć‚ć—ć¾ć™ć€‚" }, + "confirmationAlertModalTitleDescription": { + "message": "č³‡ē”£ćŒå±é™ŗć«ć•ć‚‰ć•ć‚Œć¦ć„ć‚‹åÆčƒ½ę€§ćŒć‚ć‚Šć¾ć™" + }, "confirmed": { "message": "ē¢ŗčŖć•ć‚Œć¾ć—ćŸ" }, @@ -1052,6 +1166,9 @@ "connectAccounts": { "message": "ć‚¢ć‚«ć‚¦ćƒ³ćƒˆć‚’ęŽ„ē¶š" }, + "connectAnAccountHeader": { + "message": "ć‚¢ć‚«ć‚¦ćƒ³ćƒˆć®ęŽ„ē¶š" + }, "connectManually": { "message": "ē¾åœØć®ć‚µć‚¤ćƒˆć«ę‰‹å‹•ć§ęŽ„ē¶š" }, @@ -1158,6 +1275,9 @@ "message": "$1ć‚’å–å¾—ć§ćć¾ć›ć‚“ć§ć—ćŸć€‚ćƒćƒƒćƒˆćƒÆćƒ¼ć‚Æć‚’ē¢ŗčŖć—ć¦ć‚‚ć†äø€åŗ¦ćŠč©¦ć—ćć ć•ć„ć€‚", "description": "$1 is the name of the snap being fetched." }, + "connectionPopoverDescription": { + "message": "ć‚µć‚¤ćƒˆć«ęŽ„ē¶šć™ć‚‹ć«ćÆć€ć€ŒęŽ„ē¶šć€ćƒœć‚æćƒ³ć‚’éøęŠžć—ć¾ć™ć€‚MetaMaskはWeb3ć®ć‚µć‚¤ćƒˆć«ć—ć‹ęŽ„ē¶šć§ćć¾ć›ć‚“ć€‚" + }, "connectionRequest": { "message": "ęŽ„ē¶šćƒŖć‚Æć‚Øć‚¹ćƒˆ" }, @@ -1219,6 +1339,9 @@ "create": { "message": "作成" }, + "createNewAccountHeader": { + "message": "ę–°ć—ć„ć‚¢ć‚«ć‚¦ćƒ³ćƒˆć®ä½œęˆ" + }, "createNewWallet": { "message": "ę–°č¦ć‚¦ć‚©ćƒ¬ćƒƒćƒˆć‚’ä½œęˆ" }, @@ -1231,6 +1354,9 @@ "createSnapAccountTitle": { "message": "ć‚¢ć‚«ć‚¦ćƒ³ćƒˆć®ä½œęˆ" }, + "createSolanaAccount": { + "message": "Solanać‚¢ć‚«ć‚¦ćƒ³ćƒˆć‚’ä½œęˆ" + }, "creatorAddress": { "message": "ć‚ÆćƒŖć‚Øć‚¤ć‚æćƒ¼ć®ć‚¢ćƒ‰ćƒ¬ć‚¹" }, @@ -1471,6 +1597,21 @@ "message": "$1ć‹ć‚‰ć®čŖ¬ę˜Ž", "description": "$1 represents the name of the snap" }, + "destinationAccountPickerNoEligible": { + "message": "åÆ¾č±”ć®ć‚¢ć‚«ć‚¦ćƒ³ćƒˆćŒč¦‹ć¤ć‹ć‚Šć¾ć›ć‚“ć§ć—ćŸ" + }, + "destinationAccountPickerNoMatching": { + "message": "äø€č‡“ć™ć‚‹ć‚¢ć‚«ć‚¦ćƒ³ćƒˆćŒč¦‹ć¤ć‹ć‚Šć¾ć›ć‚“ć§ć—ćŸ" + }, + "destinationAccountPickerReceiveAt": { + "message": "受取先:" + }, + "destinationAccountPickerSearchPlaceholderToMainnet": { + "message": "å—å–ć‚¢ćƒ‰ćƒ¬ć‚¹ć¾ćŸćÆENS" + }, + "destinationAccountPickerSearchPlaceholderToSolana": { + "message": "å—å–ć‚¢ćƒ‰ćƒ¬ć‚¹" + }, "details": { "message": "詳瓰" }, @@ -1516,6 +1657,9 @@ "message": "$1恮$2ćøć®ęŽ„ē¶šćŒč§£é™¤ć•ć‚Œć¾ć—ćŸ", "description": "$1 is name of the name and $2 represents the dapp name`" }, + "discover": { + "message": "ćƒ‡ć‚£ć‚¹ć‚«ćƒćƒŖ" + }, "discoverSnaps": { "message": "Snapのご瓹介", "description": "Text that links to the Snaps website. Displayed in a banner on Snaps list page in settings." @@ -1872,6 +2016,9 @@ "experimental": { "message": "試験運用" }, + "exploreweb3": { + "message": "Web3を閲覧" + }, "exportYourData": { "message": "ćƒ‡ćƒ¼ć‚æć®ć‚Øć‚Æć‚¹ćƒćƒ¼ćƒˆ" }, @@ -1885,6 +2032,9 @@ "message": "Web3ć®ć‚Øć‚Æć‚¹ćƒšćƒŖć‚Øćƒ³ć‚¹ć‚’ć‚«ć‚¹ć‚æćƒžć‚¤ć‚ŗć™ć‚‹ć€ć‚³ćƒŸćƒ„ćƒ‹ćƒ†ć‚£ćŒé–‹ē™ŗć—ćŸSnapć‚’ć”č¦§ćć ć•ć„", "description": "Banner description displayed on Snaps list page in Settings when less than 6 Snaps is installed." }, + "externalAccount": { + "message": "å¤–éƒØć‚¢ć‚«ć‚¦ćƒ³ćƒˆ" + }, "externalExtension": { "message": "å¤–éƒØę‹”å¼µę©Ÿčƒ½" }, @@ -2197,6 +2347,12 @@ "holdToRevealUnlockedLabel": { "message": "é•·ęŠ¼ć—ć—ć¦ćƒ­ćƒƒć‚ÆćŒč§£é™¤ć•ć‚ŒćŸå††ć‚’č”Øē¤ŗć—ć¾ć™" }, + "honeypotDescription": { + "message": "ć“ć®ćƒˆćƒ¼ć‚Æćƒ³ćÆćƒćƒ‹ćƒ¼ćƒćƒƒćƒˆć®å±é™ŗę€§ćŒć‚ć‚Šć¾ć™ć€‚é‡‘éŠ­ēš„ćŖęå¤±ć‚’é˜²ććŸć‚ć«ć€ć‚„ć‚Šå–ć‚Šć™ć‚‹å‰ć«ćƒ‡ćƒ„ćƒ¼ćƒ‡ć‚£ćƒŖć‚øć‚§ćƒ³ć‚¹ć‚’č”Œć†ć“ćØć‚’ćŠå‹§ć‚ć—ć¾ć™ć€‚" + }, + "honeypotTitle": { + "message": "ćƒćƒ‹ćƒ¼ćƒćƒƒćƒˆ" + }, "howNetworkFeesWorkExplanation": { "message": "ćƒˆćƒ©ćƒ³ć‚¶ć‚Æć‚·ćƒ§ćƒ³ć®å‡¦ē†ć«åæ…č¦ćŖę‰‹ę•°ę–™ć®č¦‹ē©ć‚‚ć‚Šć§ć™ć€‚ęœ€å¤§ę‰‹ę•°ę–™ćÆ$1恧恙怂" }, @@ -2262,6 +2418,30 @@ "importNFTTokenIdToolTip": { "message": "NFT恮IDćÆäø€ę„ć®č­˜åˆ„å­ć§ć€åŒć˜NFTは2ć¤ćØć—ć¦å­˜åœØć—ć¾ć›ć‚“ć€‚å‰čæ°ć®é€šć‚Šć€OpenSeać§ćÆć“ć®ē•Ŗå·ćÆć€Œč©³ē“°ć€ć«č”Øē¤ŗć•ć‚Œć¾ć™ć€‚ć“ć®IDć‚’ę›øćē•™ć‚ć‚‹ć‹ć€ć‚ÆćƒŖćƒƒćƒ—ćƒœćƒ¼ćƒ‰ć«ć‚³ćƒ”ćƒ¼ć—ć¦ćć ć•ć„ć€‚" }, + "importNWordSRP": { + "message": "$1å˜čŖžć®ćƒŖć‚«ćƒćƒŖćƒ¼ćƒ•ćƒ¬ćƒ¼ć‚ŗćŒć‚ć‚Šć¾ć™", + "description": "$1 is the number of words in the recovery phrase" + }, + "importPrivateKey": { + "message": "ē§˜åÆ†éµ" + }, + "importSRPDescription": { + "message": "12å˜čŖžć¾ćŸćÆ24å˜čŖžć®ć‚·ćƒ¼ć‚Æćƒ¬ćƒƒćƒˆćƒŖć‚«ćƒćƒŖćƒ¼ćƒ•ćƒ¬ćƒ¼ć‚ŗć‚’ä½æē”Øć—ć¦ć€ę—¢å­˜ć®ć‚¦ć‚©ćƒ¬ćƒƒćƒˆć‚’ć‚¤ćƒ³ćƒćƒ¼ćƒˆć—ć¾ć™ć€‚" + }, + "importSRPNumberOfWordsError": { + "message": "ć‚·ćƒ¼ć‚Æćƒ¬ćƒƒćƒˆćƒŖć‚«ćƒćƒŖćƒ¼ćƒ•ćƒ¬ćƒ¼ć‚ŗćÆć€12å˜čŖžć¾ćŸćÆ24å˜čŖžć§ę§‹ęˆć•ć‚Œć¦ć„ć¾ć™" + }, + "importSRPWordError": { + "message": "å˜čŖžć€Œ$1ć€ćŒę­£ć—ććŖć„ć‹ć€ć‚¹ćƒšćƒ«ćŒé•ć„ć¾ć™ć€‚", + "description": "$1 is the word that is incorrect or misspelled" + }, + "importSRPWordErrorAlternative": { + "message": "å˜čŖžć€Œ$1ć€ćØć€Œ$2ć€ćŒę­£ć—ććŖć„ć‹ć€ć‚¹ćƒšćƒ«ćŒé•ć„ć¾ć™ć€‚", + "description": "$1 and $2 are multiple words that are mispelled." + }, + "importSecretRecoveryPhrase": { + "message": "ć‚·ćƒ¼ć‚Æćƒ¬ćƒƒćƒˆćƒŖć‚«ćƒćƒŖćƒ¼ćƒ•ćƒ¬ćƒ¼ć‚ŗć‚’ć‚¤ćƒ³ćƒćƒ¼ćƒˆ" + }, "importSelectedTokens": { "message": "éøęŠžć—ćŸćƒˆćƒ¼ć‚Æćƒ³ć‚’ć‚¤ćƒ³ćƒćƒ¼ćƒˆć—ć¾ć™ć‹ļ¼Ÿ" }, @@ -2280,6 +2460,12 @@ "importTokensError": { "message": "ćƒˆćƒ¼ć‚Æćƒ³ć‚’ć‚¤ćƒ³ćƒćƒ¼ćƒˆć§ćć¾ć›ć‚“ć§ć—ćŸć€‚å¾Œć»ć©å†åŗ¦ćŠč©¦ć—ćć ć•ć„ć€‚" }, + "importWallet": { + "message": "ć‚¦ć‚©ćƒ¬ćƒƒćƒˆć‚’ć‚¤ćƒ³ćƒćƒ¼ćƒˆ" + }, + "importWalletOrAccountHeader": { + "message": "ć‚¦ć‚©ćƒ¬ćƒƒćƒˆć¾ćŸćÆć‚¢ć‚«ć‚¦ćƒ³ćƒˆć®ć‚¤ćƒ³ćƒćƒ¼ćƒˆ" + }, "importWithCount": { "message": "$1ć‚’ć‚¤ćƒ³ćƒćƒ¼ćƒˆ", "description": "$1 will the number of detected tokens that are selected for importing, if all of them are selected then $1 will be all" @@ -2327,6 +2513,12 @@ "insufficientFundsForGas": { "message": "ć‚¬ć‚¹ä»£ćŒč¶³ć‚Šć¾ć›ć‚“" }, + "insufficientLockedLiquidityDescription": { + "message": "ęµå‹•ę€§ćŒååˆ†ć«ćƒ­ćƒƒć‚Æć¾ćŸćÆćƒćƒ¼ćƒ³ć•ć‚Œć¦ć„ćŖć„ćØć€ćƒˆćƒ¼ć‚Æćƒ³ć®ęµå‹•ę€§ćŒēŖē„¶ä½Žäø‹ć—ć‚„ć™ććŖć‚Šć€åø‚å “ćŒäøå®‰å®šć«ćŖć‚‹åÆčƒ½ę€§ćŒć‚ć‚Šć¾ć™ć€‚" + }, + "insufficientLockedLiquidityTitle": { + "message": "ęµå‹•ę€§ć®ćƒ­ćƒƒć‚ÆćŒäøååˆ†ć§ć™" + }, "insufficientTokens": { "message": "ćƒˆćƒ¼ć‚Æćƒ³ćŒäøååˆ†ć§ć™ć€‚" }, @@ -2362,6 +2554,9 @@ "invalidCustomNetworkAlertTitle": { "message": "ć‚«ć‚¹ć‚æćƒ ćƒćƒƒćƒˆćƒÆćƒ¼ć‚ÆćŒē„”åŠ¹ć§ć™" }, + "invalidHexData": { + "message": "16é€²ćƒ‡ćƒ¼ć‚æćŒē„”åŠ¹ć§ć™" + }, "invalidHexNumber": { "message": "ē„”åŠ¹ćŖ16進数です。" }, @@ -2540,6 +2735,9 @@ "ledgerLocked": { "message": "Ledgerćƒ‡ćƒć‚¤ć‚¹ć«ęŽ„ē¶šć§ćć¾ć›ć‚“ć€‚ćƒ‡ćƒć‚¤ć‚¹ć®ćƒ­ćƒƒć‚ÆćŒč§£é™¤ć•ć‚Œć€ć‚¤ćƒ¼ć‚µćƒŖć‚¢ćƒ ć‚¢ćƒ—ćƒŖćŒé–‹ć‹ć‚Œć¦ć„ć‚‹ć“ćØć‚’ē¢ŗčŖć—ć¦ćć ć•ć„ć€‚" }, + "ledgerMultipleDevicesUnsupportedErrorMessage": { + "message": "複ꕰ恮Ledgerćƒ‡ćƒć‚¤ć‚¹ć‚’åŒę™‚ć«ęŽ„ē¶šć™ć‚‹ć“ćØćÆć§ćć¾ć›ć‚“ć€‚ę–°ć—ć„Ledgerćƒ‡ćƒć‚¤ć‚¹ć‚’ęŽ„ē¶šć™ć‚‹ć«ćÆć€ćÆć˜ć‚ć«ä»„å‰ć®ćƒ‡ćƒć‚¤ć‚¹ć®ęŽ„ē¶šć‚’č§£é™¤ć™ć‚‹åæ…č¦ćŒć‚ć‚Šć¾ć™ć€‚" + }, "ledgerTimeout": { "message": "Ledger LivećŒåæœē­”ć«ę™‚é–“ćŒć‹ć‹ć‚Šć™ćŽć¦ć„ć‚‹ć‹ć€ęŽ„ē¶šćŒć‚æć‚¤ćƒ ć‚¢ć‚¦ćƒˆć—ć¾ć—ćŸć€‚Ledger Liveć®ć‚¢ćƒ—ćƒŖćŒé–‹ć‹ć‚Œć¦ć„ć¦ć€ćƒ‡ćƒć‚¤ć‚¹ć®ćƒ­ćƒƒć‚ÆćŒč§£é™¤ć•ć‚Œć¦ć„ć‚‹ć“ćØć‚’ē¢ŗčŖć—ć¦ćć ć•ć„ć€‚" }, @@ -2637,6 +2835,9 @@ "manageDefaultSettings": { "message": "ćƒ‡ćƒ•ć‚©ćƒ«ćƒˆć®ćƒ—ćƒ©ć‚¤ćƒć‚·ćƒ¼čØ­å®šć®ē®”ē†" }, + "managePermissions": { + "message": "ć‚¢ć‚Æć‚»ć‚¹čØ±åÆć®ē®”ē†" + }, "marketCap": { "message": "ę™‚ä¾”ē·é”" }, @@ -2755,6 +2956,15 @@ "multichainAddEthereumChainConfirmationDescription": { "message": "ć“ć®ćƒćƒƒćƒˆćƒÆćƒ¼ć‚Æć‚’MetaMaskć«čæ½åŠ ć—ć€ć‚µć‚¤ćƒˆćŒćć‚Œć‚’ä½æē”Øć™ć‚‹ć“ćØć‚’čØ±åÆć—ć‚ˆć†ćØć—ć¦ć„ć¾ć™ć€‚" }, + "multichainQuoteCardBridgingLabel": { + "message": "ćƒ–ćƒŖćƒƒć‚ø" + }, + "multichainQuoteCardQuoteLabel": { + "message": "ć‚Æć‚©ćƒ¼ćƒˆ" + }, + "multichainQuoteCardTimeLabel": { + "message": "Ꙃ間" + }, "multipleSnapConnectionWarning": { "message": "$1が$2 Snapの使用を求めています", "description": "$1 is the dapp and $2 is the number of snaps it wants to connect to." @@ -2869,6 +3079,13 @@ "network": { "message": "ćƒćƒƒćƒˆćƒÆćƒ¼ć‚Æ:" }, + "networkChanged": { + "message": "ćƒćƒƒćƒˆćƒÆćƒ¼ć‚ÆćŒå¤‰ę›“ć•ć‚Œć¾ć—ćŸ" + }, + "networkChangedMessage": { + "message": "ē¾åœØ$1ć§å–å¼•ć—ć¦ć„ć¾ć™ć€‚", + "description": "$1 is the name of the network" + }, "networkDetails": { "message": "ćƒćƒƒćƒˆćƒÆćƒ¼ć‚Æć®č©³ē“°" }, @@ -3143,6 +3360,9 @@ "notEnoughGas": { "message": "ć‚¬ć‚¹ćŒäøč¶³ć—ć¦ć„ć¾ć™" }, + "notNow": { + "message": "また後で" + }, "notificationDetail": { "message": "詳瓰" }, @@ -3505,6 +3725,13 @@ "origin": { "message": "起点" }, + "originChanged": { + "message": "ć‚µć‚¤ćƒˆćŒå¤‰ę›“ć•ć‚Œć¾ć—ćŸ" + }, + "originChangedMessage": { + "message": "ē¾åœØ$1ć‹ć‚‰ć®č¦ę±‚ć‚’ē¢ŗčŖć—ć¦ć„ć¾ć™ć€‚", + "description": "$1 is the name of the origin" + }, "osTheme": { "message": "ć‚·ć‚¹ćƒ†ćƒ " }, @@ -3559,6 +3786,14 @@ "pending": { "message": "äæē•™äø­" }, + "pendingConfirmationAddNetworkAlertMessage": { + "message": "ćƒćƒƒćƒˆćƒÆćƒ¼ć‚Æć‚’ę›“ę–°ć™ć‚‹ćØć€ć“ć®ć‚µć‚¤ćƒˆć‹ć‚‰ć®$1ä»¶ć®äæē•™äø­ć®ćƒˆćƒ©ćƒ³ć‚¶ć‚Æć‚·ćƒ§ćƒ³ćŒć‚­ćƒ£ćƒ³ć‚»ćƒ«ć•ć‚Œć¾ć™ć€‚", + "description": "Number of transactions." + }, + "pendingConfirmationSwitchNetworkAlertMessage": { + "message": "ćƒćƒƒćƒˆćƒÆćƒ¼ć‚Æć‚’åˆ‡ć‚Šę›æćˆć‚‹ćØć€ć“ć®ć‚µć‚¤ćƒˆć‹ć‚‰ć®$1ä»¶ć®äæē•™äø­ć®ćƒˆćƒ©ćƒ³ć‚¶ć‚Æć‚·ćƒ§ćƒ³ćŒć‚­ćƒ£ćƒ³ć‚»ćƒ«ć•ć‚Œć¾ć™ć€‚", + "description": "Number of transactions." + }, "pendingTransactionAlertMessage": { "message": "ć“ć®ćƒˆćƒ©ćƒ³ć‚¶ć‚Æć‚·ćƒ§ćƒ³ćÆć€å‰ć®ćƒˆćƒ©ćƒ³ć‚¶ć‚Æć‚·ćƒ§ćƒ³ćŒå®Œäŗ†ć™ć‚‹ć¾ć§å®Ÿč”Œć•ć‚Œć¾ć›ć‚“ć€‚$1", "description": "$1 represents the words 'how to cancel or speed up a transaction' in a hyperlink" @@ -3842,6 +4077,9 @@ "permitSimulationChange_receive": { "message": "受取" }, + "permitSimulationChange_revoke2": { + "message": "å–ć‚Šę¶ˆć™" + }, "permitSimulationChange_transfer": { "message": "送金" }, @@ -4237,6 +4475,9 @@ "reusedTokenNameWarning": { "message": "ć“ć“ć®ćƒˆćƒ¼ć‚Æćƒ³ćÆć€ē›£č¦–ć™ć‚‹åˆ„ć®ćƒˆćƒ¼ć‚Æćƒ³ć®ć‚·ćƒ³ćƒœćƒ«ć‚’å†ä½æē”Øć—ć¾ć™ć€‚ć“ć‚ŒćÆę··ä¹±ć‚’ę‹›ć„ćŸć‚Šē“›ć‚‰ć‚ć—ć„å “åˆćŒć‚ć‚Šć¾ć™ć€‚" }, + "revealSecretRecoveryPhrase": { + "message": "ć‚·ćƒ¼ć‚Æćƒ¬ćƒƒćƒˆćƒŖć‚«ćƒćƒŖćƒ¼ćƒ•ćƒ¬ćƒ¼ć‚ŗć‚’ē¢ŗčŖ" + }, "revealSeedWords": { "message": "ć‚·ćƒ¼ć‚Æćƒ¬ćƒƒćƒˆćƒŖć‚«ćƒćƒŖćƒ¼ćƒ•ćƒ¬ćƒ¼ć‚ŗć‚’ē¢ŗčŖ" }, @@ -4286,12 +4527,19 @@ "reviewAlerts": { "message": "ć‚¢ćƒ©ćƒ¼ćƒˆć‚’ē¢ŗčŖć™ć‚‹" }, + "reviewPendingTransactions": { + "message": "äæē•™äø­ć®ćƒˆćƒ©ćƒ³ć‚¶ć‚Æć‚·ćƒ§ćƒ³ć‚’ē¢ŗčŖ" + }, "reviewPermissions": { "message": " ć‚¢ć‚Æć‚»ć‚¹čØ±åÆć‚’ē¢ŗčŖć™ć‚‹" }, "revokePermission": { "message": "čØ±åÆć‚’å–ć‚Šę¶ˆć™" }, + "revokePermissionTitle": { + "message": "$1ć®ć‚¢ć‚Æć‚»ć‚¹čØ±åÆć‚’å–ć‚Šę¶ˆć™", + "description": "The token symbol that is being revoked" + }, "revokeSimulationDetailsDesc": { "message": "åˆ„ć®ćƒ¦ćƒ¼ć‚¶ćƒ¼ć«ä»˜äøŽć—ćŸć‚¢ć‚«ć‚¦ćƒ³ćƒˆć®ćƒˆćƒ¼ć‚Æćƒ³ä½æē”ØčØ±åÆć‚’å–ć‚Šę¶ˆćć†ćØć—ć¦ć„ć¾ć™ć€‚" }, @@ -4334,6 +4582,10 @@ "secretRecoveryPhrase": { "message": "ć‚·ćƒ¼ć‚Æćƒ¬ćƒƒćƒˆćƒŖć‚«ćƒćƒŖćƒ¼ćƒ•ćƒ¬ćƒ¼ć‚ŗ" }, + "secretRecoveryPhrasePlusNumber": { + "message": "ć‚·ćƒ¼ć‚Æćƒ¬ćƒƒćƒˆćƒŖć‚«ćƒćƒŖćƒ¼ćƒ•ćƒ¬ćƒ¼ć‚ŗ$1", + "description": "The $1 is the order of the Secret Recovery Phrase" + }, "secureWallet": { "message": "å®‰å…ØćŖć‚¦ć‚©ćƒ¬ćƒƒćƒˆ" }, @@ -4424,6 +4676,9 @@ "select": { "message": "éøęŠž" }, + "selectAccountToConnect": { + "message": "ęŽ„ē¶šć™ć‚‹ć‚¢ć‚«ć‚¦ćƒ³ćƒˆć‚’éøęŠžć—ć¾ć™" + }, "selectAccounts": { "message": "ć“ć®ć‚µć‚¤ćƒˆć«ä½æē”Øć™ć‚‹ć‚¢ć‚«ć‚¦ćƒ³ćƒˆć‚’éøęŠžć—ć¦ćć ć•ć„" }, @@ -4454,6 +4709,9 @@ "selectRpcUrl": { "message": "RPC URLć‚’éøęŠž" }, + "selectSecretRecoveryPhrase": { + "message": "ć‚·ćƒ¼ć‚Æćƒ¬ćƒƒćƒˆćƒŖć‚«ćƒćƒŖćƒ¼ćƒ•ćƒ¬ćƒ¼ć‚ŗć‚’éøęŠž" + }, "selectType": { "message": "ēØ®é”žć‚’éøęŠž" }, @@ -4565,16 +4823,6 @@ "showHexDataDescription": { "message": "ć“ć‚Œć‚’éøęŠžć™ć‚‹ćØć€é€é‡‘ē”»é¢ć«16é€²ćƒ‡ćƒ¼ć‚æćƒ•ć‚£ćƒ¼ćƒ«ćƒ‰ćŒč”Øē¤ŗć•ć‚Œć¾ć™" }, - "showIncomingTransactions": { - "message": "å—äæ”ćƒˆćƒ©ćƒ³ć‚¶ć‚Æć‚·ćƒ§ćƒ³ć‚’č”Øē¤ŗ" - }, - "showIncomingTransactionsDescription": { - "message": "ć“ć‚ŒćÆć€ćƒ¦ćƒ¼ć‚¶ćƒ¼ć®ć‚¤ćƒ¼ć‚µćƒŖć‚¢ćƒ ć‚¢ćƒ‰ćƒ¬ć‚¹ćŠć‚ˆć³IPć‚¢ćƒ‰ćƒ¬ć‚¹ć«ć‚¢ć‚Æć‚»ć‚¹ć™ć‚‹$1ć«ä¾å­˜ć—ć¾ć™ć€‚$2", - "description": "$1 is the link to etherscan url and $2 is the link to the privacy policy of consensys APIs" - }, - "showIncomingTransactionsExplainer": { - "message": "ć“ć‚ŒćÆć€ćƒćƒƒćƒˆćƒÆćƒ¼ć‚Æć”ćØć«ē•°ćŖć‚‹ć‚µćƒ¼ćƒ‰ćƒ‘ćƒ¼ćƒ†ć‚£APIć«ä¾å­˜ć—ć¾ć™ć€‚ć“ć‚Œć«ć‚ˆć‚Šć€ć‚¤ćƒ¼ć‚µćƒŖć‚¢ćƒ ć‚¢ćƒ‰ćƒ¬ć‚¹ćØIPć‚¢ćƒ‰ćƒ¬ć‚¹ćŒå…¬é–‹ć•ć‚Œć¾ć™ć€‚" - }, "showLess": { "message": "č”Øē¤ŗé‡ć‚’ęø›ć‚‰ć™" }, @@ -4593,6 +4841,9 @@ "showPrivateKey": { "message": "ē§˜åÆ†éµć‚’č”Øē¤ŗ" }, + "showSRP": { + "message": "ć‚·ćƒ¼ć‚Æćƒ¬ćƒƒćƒˆćƒŖć‚«ćƒćƒŖćƒ¼ćƒ•ćƒ¬ćƒ¼ć‚ŗć‚’č”Øē¤ŗ" + }, "showTestnetNetworks": { "message": "ćƒ†ć‚¹ćƒˆćƒćƒƒćƒˆćƒÆćƒ¼ć‚Æć‚’č”Øē¤ŗ" }, @@ -4714,12 +4965,24 @@ "slideCashOutTitle": { "message": "MetaMaskć§ć‚­ćƒ£ćƒƒć‚·ćƒ„ć‚¢ć‚¦ćƒˆ" }, + "slideDebitCardDescription": { + "message": "äø€éƒØåœ°åŸŸć§åˆ©ē”ØåÆčƒ½" + }, "slideDebitCardTitle": { "message": "MetaMaskćƒ‡ćƒ“ćƒƒćƒˆć‚«ćƒ¼ćƒ‰" }, + "slideFundWalletDescription": { + "message": "ćƒˆćƒ¼ć‚Æćƒ³ć‚’čæ½åŠ ć¾ćŸćÆé€é‡‘ć—ć¦é–‹å§‹ć—ć¾ć™" + }, "slideFundWalletTitle": { "message": "ć‚¦ć‚©ćƒ¬ćƒƒćƒˆć«å…„é‡‘" }, + "slideSweepStakeDescription": { + "message": "今NFTć‚’ćƒŸćƒ³ćƒˆć™ć‚‹ćØć€ę¬”ć®ć‚‚ć®ćŒå½“ćŸć‚‹ćƒćƒ£ćƒ³ć‚¹ć§ć™:" + }, + "slideSweepStakeTitle": { + "message": "$5000 USDCćƒ—ćƒ¬ć‚¼ćƒ³ćƒˆć«ć”åæœå‹Ÿćć ć•ć„ļ¼" + }, "smartContracts": { "message": "ć‚¹ćƒžćƒ¼ćƒˆć‚³ćƒ³ćƒˆćƒ©ć‚Æćƒˆ" }, @@ -4866,6 +5129,9 @@ "snapResultSuccessDescription": { "message": "$1ć‚’ä½æē”Øć™ć‚‹ęŗ–å‚™ćŒę•“ć„ć¾ć—ćŸ" }, + "snapUIAssetSelectorTitle": { + "message": "č³‡ē”£ć®éøęŠž" + }, "snapUpdateAlertDescription": { "message": "$1ć®ęœ€ę–°ćƒćƒ¼ć‚øćƒ§ćƒ³ć‚’å…„ę‰‹", "description": "Description used in Snap update alert banner when snap update is available. $1 is the Snap name." @@ -4925,6 +5191,27 @@ "message": "ä»Šå¾Œć®ć‚µćƒćƒ¼ćƒˆćÆć€$1ć®ä½œęˆč€…ć«ćŠå•ć„åˆć‚ć›ćć ć•ć„ć€‚", "description": "This is shown when the insight snap throws an error. $1 is the snap name" }, + "solanaImportAccounts": { + "message": "Solanać‚¢ć‚«ć‚¦ćƒ³ćƒˆć‚’ć‚¤ćƒ³ćƒćƒ¼ćƒˆ" + }, + "solanaImportAccountsDescription": { + "message": "ć‚·ćƒ¼ć‚Æćƒ¬ćƒƒćƒˆćƒŖć‚«ćƒćƒŖćƒ¼ćƒ•ćƒ¬ćƒ¼ć‚ŗć‚’ć‚¤ćƒ³ćƒćƒ¼ćƒˆć—ć¦ć€ä»–ć®ć‚¦ć‚©ćƒ¬ćƒƒćƒˆć‹ć‚‰Solanać‚¢ć‚«ć‚¦ćƒ³ćƒˆć‚’ē§»č”Œć—ć¾ć™ć€‚" + }, + "solanaMoreFeaturesComingSoon": { + "message": "ä»–ć®ę©Ÿčƒ½ć‚‚čæ‘ę—„čæ½åŠ äŗˆå®š" + }, + "solanaMoreFeaturesComingSoonDescription": { + "message": "Solana DApp态NFTć€ćƒćƒ¼ćƒ‰ć‚¦ć‚§ć‚¢ć‚¦ć‚©ćƒ¬ćƒƒćƒˆć®ć‚µćƒćƒ¼ćƒˆć€ćć®ä»–ę©Ÿčƒ½ć‚‚čæ‘ę—„čæ½åŠ äŗˆå®šć€‚" + }, + "solanaOnMetaMask": { + "message": "MetaMask恧Solana" + }, + "solanaSendReceiveSwapTokens": { + "message": "ćƒˆćƒ¼ć‚Æćƒ³ć®é€é‡‘ć€å—å–ć€ć‚¹ćƒÆćƒƒćƒ—" + }, + "solanaSendReceiveSwapTokensDescription": { + "message": "SOL悄USDCćŖć©ć®ćƒˆćƒ¼ć‚Æćƒ³ć§ć®é€é‡‘ćƒ»å–å¼•ć€‚" + }, "someNetworks": { "message": "$1å€‹ć®ćƒćƒƒćƒˆćƒÆćƒ¼ć‚Æ" }, @@ -4951,6 +5238,21 @@ "source": { "message": "ć‚½ćƒ¼ć‚¹" }, + "spamModalBlockedDescription": { + "message": "ć“ć®ć‚µć‚¤ćƒˆćÆ1åˆ†é–“ćƒ–ćƒ­ćƒƒć‚Æć•ć‚Œć¾ć™" + }, + "spamModalBlockedTitle": { + "message": "ć“ć®ć‚µć‚¤ćƒˆć‚’äø€ę™‚ēš„ć«ćƒ–ćƒ­ćƒƒć‚Æć—ć¾ć—ćŸ" + }, + "spamModalDescription": { + "message": "č¤‡ę•°ć®č¦ę±‚ćŒč”Œć‚ć‚Œčæ·ęƒ‘ćŖå “åˆćÆć€äø€ę™‚ēš„ć«ć‚µć‚¤ćƒˆć‚’ćƒ–ćƒ­ćƒƒć‚Æć§ćć¾ć™ć€‚" + }, + "spamModalTemporaryBlockButton": { + "message": "ć“ć®ć‚µć‚¤ćƒˆć‚’äø€ę™‚ēš„ć«ćƒ–ćƒ­ćƒƒć‚Æ" + }, + "spamModalTitle": { + "message": "č¤‡ę•°ć®č¦ę±‚ćŒę¤œå‡ŗć•ć‚Œć¾ć—ćŸ" + }, "speed": { "message": "é€Ÿåŗ¦" }, @@ -5000,10 +5302,28 @@ "spendingCap": { "message": "ä½æē”ØäøŠé™" }, + "spendingCaps": { + "message": "ä½æē”ØäøŠé™" + }, "srpInputNumberOfWords": { "message": "$1čŖžć®ćƒ•ćƒ¬ćƒ¼ć‚ŗćŒć‚ć‚Šć¾ć™", "description": "This is the text for each option in the dropdown where a user selects how many words their secret recovery phrase has during import. The $1 is the number of words (either 12, 15, 18, 21, or 24)." }, + "srpListName": { + "message": "ć‚·ćƒ¼ć‚Æćƒ¬ćƒƒćƒˆćƒŖć‚«ćƒćƒŖćƒ¼ćƒ•ćƒ¬ćƒ¼ć‚ŗ$1", + "description": "$1 is the order of the Secret Recovery Phrase" + }, + "srpListNumberOfAccounts": { + "message": "$1ä»¶ć®ć‚¢ć‚«ć‚¦ćƒ³ćƒˆ", + "description": "$1 is the number of accounts in the list" + }, + "srpListSelectionDescription": { + "message": "ę–°ć—ć„ć‚¢ć‚«ć‚¦ćƒ³ćƒˆć®ē”Ÿęˆå…ƒćØćŖć‚‹ć‚·ćƒ¼ć‚Æćƒ¬ćƒƒćƒˆćƒŖć‚«ćƒćƒŖćƒ¼ćƒ•ćƒ¬ćƒ¼ć‚ŗ" + }, + "srpListSingleOrZero": { + "message": "$1ä»¶ć®ć‚¢ć‚«ć‚¦ćƒ³ćƒˆ", + "description": "$1 is the number of accounts in the list, it is either 1 or 0" + }, "srpPasteFailedTooManyWords": { "message": "24ć‚’č¶…ćˆć‚‹å˜čŖžćŒå«ć¾ć‚Œć¦ć„ćŸćŸć‚ć€č²¼ć‚Šä»˜ć‘ć«å¤±ę•—ć—ć¾ć—ćŸć€‚ć‚·ćƒ¼ć‚Æćƒ¬ćƒƒćƒˆćƒŖć‚«ćƒćƒŖćƒ¼ćƒ•ćƒ¬ćƒ¼ć‚ŗćÆ24čŖžć¾ć§ć§ć™ć€‚", "description": "Description of SRP paste error when the pasted content has too many words" @@ -5158,6 +5478,9 @@ "message": "ēŖē„¶ć®åø‚å “å¤‰å‹•ćŒå¤±ę•—ć®åŽŸå› ć«ćŖć‚Šć¾ć™ć€‚å•é”ŒćŒč§£ę±ŗć•ć‚ŒćŖć„ć‚ˆć†ć§ć—ćŸć‚‰ć€$1ć«ćŠå•ć„åˆć‚ć›ćć ć•ć„ć€‚", "description": "This message is shown to a user if their swap fails. The $1 will be replaced by support.metamask.io" }, + "stxOptInSupportedNetworksDescription": { + "message": "ć‚¹ćƒžćƒ¼ćƒˆćƒˆćƒ©ćƒ³ć‚¶ć‚Æć‚·ćƒ§ćƒ³ć‚’ć‚Ŗćƒ³ć«ć—ć¦ć€ć‚µćƒćƒ¼ćƒˆć•ć‚Œć¦ć„ć‚‹ćƒćƒƒćƒˆćƒÆćƒ¼ć‚ÆäøŠć§ć®ćƒˆćƒ©ćƒ³ć‚¶ć‚Æć‚·ćƒ§ćƒ³ć®äæ”é ¼ę€§ćØå®‰å…Øę€§ć‚’é«˜ć‚ć¾ć—ć‚‡ć†ć€‚$1" + }, "stxPendingPrivatelySubmittingSwap": { "message": "ć‚¹ćƒÆćƒƒćƒ—ć‚’éžå…¬é–‹ć§é€äæ”äø­..." }, @@ -5977,6 +6300,12 @@ "message": "NFT (ERC-721) ćƒˆćƒ¼ć‚Æćƒ³ć®é€äæ”ćÆē¾åœØć‚µćƒćƒ¼ćƒˆć•ć‚Œć¦ć„ć¾ć›ć‚“", "description": "This is an error message we show the user if they attempt to send an NFT asset type, for which currently don't support sending" }, + "unstableTokenPriceDescription": { + "message": "ć“ć®ćƒˆćƒ¼ć‚Æćƒ³ć®USDć§ć®ä¾”ę ¼ćÆéžåøøć«äøå®‰å®šć§ć€ć‚„ć‚Šå–ć‚Šć™ć‚‹ćØé«˜é”ć‚’å¤±ć†å±é™ŗę€§ćŒé«˜ć„ć§ć™ć€‚" + }, + "unstableTokenPriceTitle": { + "message": "ćƒˆćƒ¼ć‚Æćƒ³ä¾”ę ¼ćŒäøå®‰å®šć§ć™" + }, "upArrow": { "message": "äøŠēŸ¢å°" }, @@ -6099,6 +6428,18 @@ "visitSite": { "message": "ć‚µć‚¤ćƒˆć«ć‚¢ć‚Æć‚»ć‚¹" }, + "visitSupportDataConsentModalAccept": { + "message": "確定" + }, + "visitSupportDataConsentModalDescription": { + "message": "MetaMaskć®č­˜åˆ„å­ćØć‚¢ćƒ—ćƒŖć®ćƒćƒ¼ć‚øćƒ§ćƒ³ć‚’ć‚µćƒćƒ¼ćƒˆć‚»ćƒ³ć‚æćƒ¼ćØå…±ęœ‰ć—ć¾ć™ć‹ļ¼Ÿć“ć‚Œć«ć‚ˆć‚Šå•é”Œć‚’č§£ę±ŗć—ć‚„ć™ććŖć‚Šć¾ć™ćŒć€ć‚ćć¾ć§ć‚‚ć‚Ŗćƒ—ć‚·ćƒ§ćƒ³ć§ć™ć€‚" + }, + "visitSupportDataConsentModalReject": { + "message": "å…±ęœ‰ć—ćŖć„" + }, + "visitSupportDataConsentModalTitle": { + "message": "ćƒ‡ćƒć‚¤ć‚¹ęƒ…å ±ć‚’ć‚µćƒćƒ¼ćƒˆćØå…±ęœ‰ć™ć‚‹" + }, "visitWebSite": { "message": "弊社Webć‚µć‚¤ćƒˆć«ć‚¢ć‚Æć‚»ć‚¹" }, diff --git a/app/_locales/ko/messages.json b/app/_locales/ko/messages.json index 67773d043cc0..3409b375a207 100644 --- a/app/_locales/ko/messages.json +++ b/app/_locales/ko/messages.json @@ -44,6 +44,20 @@ "QRHardwareWalletSteps2Description": { "message": "Nź·øė ˆģ“ėøŒ 제딜" }, + "SrpListHideAccounts": { + "message": "계정 $1개 숨기기", + "description": "$1 is the number of accounts" + }, + "SrpListHideSingleAccount": { + "message": "계정 1개 숨기기" + }, + "SrpListShowAccounts": { + "message": "계정 $1개 ķ‘œģ‹œ", + "description": "$1 is the number of accounts" + }, + "SrpListShowSingleAccount": { + "message": "계정 1개 ķ‘œģ‹œ" + }, "about": { "message": "정볓" }, @@ -76,6 +90,9 @@ "accountDetails": { "message": "계정 세부 정볓" }, + "accountDetailsRevokeDelegationButton": { + "message": " ģ¼ė°˜ ź³„ģ •ģœ¼ė”œ ģ „ķ™˜" + }, "accountIdenticon": { "message": "계정 ģ‹ė³„ ģ•„ģ“ģ½˜" }, @@ -153,6 +170,12 @@ "addAlias": { "message": "별칭 추가" }, + "addBitcoinAccountLabel": { + "message": "ė¹„ķŠøģ½”ģø 계정 (ė² ķƒ€)" + }, + "addBitcoinTestnetAccountLabel": { + "message": "ė¹„ķŠøģ½”ģø 계정 (ķ…ŒģŠ¤ķŠøė„·)" + }, "addBlockExplorer": { "message": "ėø”ė” ķƒģƒ‰źø° 추가" }, @@ -193,6 +216,9 @@ "addFriendsAndAddresses": { "message": "ģ‹ ė¢°ķ•˜ėŠ” 친구 ė° ģ£¼ģ†Œ 추가" }, + "addHardwareWalletLabel": { + "message": "ķ•˜ė“œģ›Øģ–“ 지갑" + }, "addIPFSGateway": { "message": "ģ„ ķ˜øķ•˜ėŠ” IPFS ź²Œģ“ķŠøģ›Øģ“ė„¼ ģ¶”ź°€ķ•˜ģ„øģš”" }, @@ -212,12 +238,26 @@ "addNewAccount": { "message": "새 ģ“ė”ė¦¬ģ›€ 계정 추가" }, + "addNewEthereumAccountLabel": { + "message": "ģ“ė”ė¦¬ģ›€ 계정" + }, + "addNewSolanaAccountLabel": { + "message": "ģ†”ė¼ė‚˜ 계정" + }, "addNft": { "message": "NFT 추가" }, "addNfts": { "message": "NFT 추가" }, + "addNonEvmAccount": { + "message": "$1 계정 추가", + "description": "$1 is the non EVM network where the account is going to be created, e.g. Bitcoin or Solana" + }, + "addNonEvmAccountFromNetworkPicker": { + "message": "$1 ė„¤ķŠøģ›Œķ¬ė„¼ ķ™œģ„±ķ™”ķ•˜ė ¤ė©“ $2 ź³„ģ •ģ„ ė§Œė“¤ģ–“ģ•¼ ķ•©ė‹ˆė‹¤.", + "description": "$1 is the non EVM network where the account is going to be created, e.g. Solana Mainnet or Solana Devnet. $2 is the account type, e.g. Bitcoin or Solana" + }, "addRpcUrl": { "message": "RPC URL 추가" }, @@ -300,14 +340,16 @@ "advancedPriorityFeeToolTip": { "message": "ģš°ģ„  ģš”źøˆ(ģ¼ėŖ… \"ģ±„źµ“ģž 팁\")ģ“ėž€ ė‚“ ķŠøėžœģž­ģ…˜ģ„ ģš°ģ„  ź±°ėž˜ķ•œ ź²ƒģ— ėŒ€ķ•œ ģøģ„¼ķ‹°ėøŒė”œ ģ±„źµ“ģžģ—ź²Œ 직접 ģ „ė‹¬ė˜ėŠ” źøˆģ•”ģž…ė‹ˆė‹¤." }, - "aggregatedBalancePopover": { - "message": "ģ“ėŠ” ķŠ¹ģ • ė„¤ķŠøģ›Œķ¬ģ—ģ„œ ģ†Œģœ ķ•œ ėŖØė“  ķ† ķ°ģ˜ ź°€ģ¹˜ė„¼ ė°˜ģ˜ķ•©ė‹ˆė‹¤. ģ“ ź°€ģ¹˜ė„¼ ETH ė˜ėŠ” 다넸 ķ†µķ™”ė”œ 볓고 싶다멓 $1(으)딜 ģ“ė™ķ•˜ģ„øģš”.", - "description": "$1 represents the settings page" - }, "agreeTermsOfUse": { "message": "MetaMaskģ˜ $1에 ė™ģ˜ķ•©ė‹ˆė‹¤", "description": "$1 is the `terms` link" }, + "airDropPatternDescription": { + "message": "핓당 ķ† ķ°ģ˜ ģ˜Øģ²“ģø źø°ė”ģ—ģ„œ ģ˜ģ‹¬ģŠ¤ėŸ¬ģš“ ģ—ģ–“ė“œė”­ ķ™œė™ģ“ ķ™•ģøė˜ģ—ˆģŠµė‹ˆė‹¤." + }, + "airDropPatternTitle": { + "message": "ģ—ģ–“ė“œė”­ ķŒØķ„“" + }, "airgapVault": { "message": "에얓갭 볼트" }, @@ -726,9 +768,21 @@ "bridgeConfirmTwoTransactions": { "message": "ķ•˜ė“œģ›Øģ–“ ģ§€ź°‘ģ—ģ„œ 2ź±“ģ˜ ķŠøėžœģž­ģ…˜ģ„ ģ»ØķŽŒķ•“ģ•¼ ķ•©ė‹ˆė‹¤." }, + "bridgeCreateSolanaAccount": { + "message": "ģ†”ė¼ė‚˜ 계정 ė§Œė“¤źø°" + }, + "bridgeCreateSolanaAccountDescription": { + "message": "ģ†”ė¼ė‚˜ ė„¤ķŠøģ›Œķ¬ė”œ ģŠ¤ģ™‘ķ•˜ė ¤ė©“ 계정과 ģˆ˜ģ‹  ģ£¼ģ†Œź°€ ķ•„ģš”ķ•©ė‹ˆė‹¤." + }, + "bridgeCreateSolanaAccountTitle": { + "message": "ģš°ģ„  ģ†”ė¼ė‚˜ ź³„ģ •ģ“ ķ•„ģš”ķ•©ė‹ˆė‹¤." + }, "bridgeEnterAmount": { "message": "źøˆģ•” ģž…ė „" }, + "bridgeEnterAmountAndSelectAccount": { + "message": "źøˆģ•”ģ„ ģž…ė „ķ•˜ź³  ėŒ€ģƒ ź³„ģ •ģ„ ģ„ ķƒķ•˜ģ„øģš”" + }, "bridgeExplorerLinkViewOn": { "message": "$1ģ—ģ„œ 볓기" }, @@ -751,9 +805,15 @@ "bridgeQuoteExpired": { "message": "ź²¬ģ ģ“ ė§Œė£Œė˜ģ—ˆģŠµė‹ˆė‹¤." }, + "bridgeSelectDestinationAccount": { + "message": "ėŒ€ģƒ 계정 ģ„ ķƒ" + }, "bridgeSelectNetwork": { "message": "ė„¤ķŠøģ›Œķ¬ ģ„ ķƒ" }, + "bridgeSelectTokenAmountAndAccount": { + "message": "토큰, źøˆģ•”, ėŒ€ģƒ ź³„ģ •ģ„ ģ„ ķƒķ•˜ģ„øģš”" + }, "bridgeSelectTokenAndAmount": { "message": "토큰 ė° źøˆģ•” ģ„ ķƒ" }, @@ -944,6 +1004,12 @@ "message": "ģ˜µģ…˜ģ„ ģ°¾ģ„ 수 ģ—†ģŠµė‹ˆė‹¤", "description": "Default text shown in the combo field dropdown if no options." }, + "concentratedSupplyDistributionDescription": { + "message": "ģƒģœ„ ė³“ģœ ģžģ—ź²Œ ėŒ€ė¶€ė¶„ģ˜ 토큰 공급 ź¶Œķ•œģ“ ģžˆģ–“ ģ¤‘ģ•™ģ§‘ģ¤‘ģ‹ 가격 ģ”°ģž‘ ģœ„ķ—˜ģ“ ģžˆģŠµė‹ˆė‹¤" + }, + "concentratedSupplyDistributionTitle": { + "message": "집중적 공급 ė¶„ė°°" + }, "configureSnapPopupDescription": { "message": "ģ“ģ œ ģ“ ģŠ¤ėƒ… źµ¬ģ„±ģ„ ģœ„ķ•“ MetaMask ķŽ˜ģ“ģ§€ė„¼ ė– ė‚˜ź²Œ ė©ė‹ˆė‹¤." }, @@ -962,6 +1028,15 @@ "confirm": { "message": "ģ»ØķŽŒ" }, + "confirmAccountType": { + "message": "ģœ ķ˜•" + }, + "confirmAccountTypeSmartContract": { + "message": "스마트 계정" + }, + "confirmAccountTypeStandard": { + "message": "ģ¼ė°˜ 계정" + }, "confirmAlertModalAcknowledgeMultiple": { "message": "경고넼 ģøģ§€ķ–ˆģœ¼ė©°, ź³„ģ† ģ§„ķ–‰ķ•©ė‹ˆė‹¤" }, @@ -974,12 +1049,36 @@ "confirmFieldTooltipPaymaster": { "message": "ģ“ ķŠøėžœģž­ģ…˜ģ— ėŒ€ķ•œ ģˆ˜ģˆ˜ė£ŒėŠ” Paymaster 스마트 ź³„ģ•½ģ—ģ„œ ģ§€ė¶ˆķ•©ė‹ˆė‹¤." }, + "confirmGasFeeTokenBalance": { + "message": "ģž”ģ•”:" + }, + "confirmGasFeeTokenInsufficientBalance": { + "message": "ģžźøˆ 부씱" + }, + "confirmGasFeeTokenMetaMaskFee": { + "message": "$1 수수료 ķ¬ķ•Ø" + }, + "confirmGasFeeTokenModalTitle": { + "message": "토큰 ģ„ ķƒ" + }, + "confirmGasFeeTokenToast": { + "message": "ģ“ ė„¤ķŠøģ›Œķ¬ ģˆ˜ģˆ˜ė£ŒėŠ” $1(으)딜 ģ§€ė¶ˆė©ė‹ˆė‹¤" + }, + "confirmGasFeeTokenTooltip": { + "message": "ģ“ ģˆ˜ģˆ˜ė£ŒėŠ” ķŠøėžœģž­ģ…˜ 처리넼 ģœ„ķ•“ ė„¤ķŠøģ›Œķ¬ģ— ģ§€ė¶ˆķ•˜ėŠ” 것으딜, ETH ķ† ķ°ģ“ ģ•„ė‹Œ 경우 $1ģ˜ MetaMask ģˆ˜ģˆ˜ė£Œź°€ ķ¬ķ•Øė©ė‹ˆė‹¤." + }, + "confirmNestedTransactionTitle": { + "message": "ķŠøėžœģž­ģ…˜ $1" + }, "confirmPassword": { "message": "ė¹„ė°€ė²ˆķ˜ø ģ»ØķŽŒ" }, "confirmRecoveryPhrase": { "message": "비밀복구구문 ģ»ØķŽŒ" }, + "confirmSimulationApprove": { + "message": "ģŠ¹ģø:" + }, "confirmTitleApproveTransactionNFT": { "message": "출금 ģš”ģ²­" }, @@ -1022,9 +1121,24 @@ "confirmTitleTransaction": { "message": "ķŠøėžœģ ģ…˜ ģš”ģ²­" }, + "confirmUpgradeCancelModalButtonCancelTransaction": { + "message": "ķŠøėžœģž­ģ…˜ ģ·Øģ†Œ" + }, + "confirmUpgradeCancelModalButtonCancelUpgrade": { + "message": "ģ—…ė°ģ“ķŠø ė° ķŠøėžœģž­ģ…˜ ģ·Øģ†Œ" + }, + "confirmUpgradeCancelModalDescription": { + "message": "ź³„ģ •ģ„ ģ—…ė°ģ“ķŠøķ•˜ź³  ģ‹¶ģ§€ ģ•Šė‹¤ė©“ ģ—¬źø°ģ—ģ„œ ģ·Øģ†Œķ•  수 ģžˆģŠµė‹ˆė‹¤.\n\nģ—…ė°ģ“ķŠø ģ—†ģ“ ķŠøėžœģž­ģ…˜ģ„ ģ™„ė£Œķ•˜ė ¤ė©“ ģ‚¬ģ“ķŠøģ—ģ„œ ģ“ ģš”ģ²­ģ„ ė‹¤ģ‹œ ģˆ˜ķ–‰ķ•“ģ•¼ ķ•©ė‹ˆė‹¤. $1." + }, + "confirmUpgradeCancelModalTitle": { + "message": "ķŠøėžœģž­ģ…˜ ģ·Øģ†Œ" + }, "confirmationAlertDetails": { "message": "ģžģ‚°ģ„ ė³“ķ˜øķ•˜źø° ģœ„ķ•“ ģš”ģ²­ģ„ ź±°ė¶€ķ•˜ėŠ” ź²ƒģ“ ģ¢‹ģŠµė‹ˆė‹¤." }, + "confirmationAlertModalTitleDescription": { + "message": "ģžģ‚°ģ“ ģœ„ķ—˜ķ•  수 ģžˆģŠµė‹ˆė‹¤" + }, "confirmed": { "message": "ģ»ØķŽŒėØ" }, @@ -1052,6 +1166,9 @@ "connectAccounts": { "message": "계정 ģ—°ź²°" }, + "connectAnAccountHeader": { + "message": "계정 ģ—°ź²°" + }, "connectManually": { "message": "ķ˜„ģž¬ ģ‚¬ģ“ķŠøģ— 직접 ģ—°ź²°" }, @@ -1158,6 +1275,9 @@ "message": "$1 ė¶ˆėŸ¬ģ˜¤źø°ģ— ģ‹¤ķŒØķ–ˆģŠµė‹ˆė‹¤. ė„¤ķŠøģ›Œķ¬ė„¼ ķ™•ģøķ•˜ź³  ė‹¤ģ‹œ ģ‹œė„ķ•˜ģ„øģš”.", "description": "$1 is the name of the snap being fetched." }, + "connectionPopoverDescription": { + "message": "ģ‚¬ģ“ķŠøģ— ģ—°ź²°ķ•˜ė ¤ė©“ ģ—°ź²° ė²„ķŠ¼ģ„ ģ„ ķƒķ•˜ģ„øģš”. MetaMaskėŠ” 웹3 ģ‚¬ģ“ķŠøģ—ė§Œ ģ—°ź²°ķ•  수 ģžˆģŠµė‹ˆė‹¤." + }, "connectionRequest": { "message": "ģ—°ź²° ģš”ģ²­" }, @@ -1219,6 +1339,9 @@ "create": { "message": "ģƒģ„±" }, + "createNewAccountHeader": { + "message": "새 계정 ė§Œė“¤źø°" + }, "createNewWallet": { "message": "새 지갑 ģƒģ„±" }, @@ -1231,6 +1354,9 @@ "createSnapAccountTitle": { "message": "계정 ģƒģ„±" }, + "createSolanaAccount": { + "message": "ģ†”ė¼ė‚˜ 계정 ė§Œė“¤źø°" + }, "creatorAddress": { "message": "ķ¬ė¦¬ģ—ģ“ķ„° ģ£¼ģ†Œ" }, @@ -1471,6 +1597,21 @@ "message": "$1 설명", "description": "$1 represents the name of the snap" }, + "destinationAccountPickerNoEligible": { + "message": "ģ ķ•©ķ•œ ź³„ģ •ģ„ ģ°¾ģ„ 수 ģ—†ģŠµė‹ˆė‹¤" + }, + "destinationAccountPickerNoMatching": { + "message": "ģ¼ģ¹˜ķ•˜ėŠ” ź³„ģ •ģ„ ģ°¾ģ„ 수 ģ—†ģŠµė‹ˆė‹¤" + }, + "destinationAccountPickerReceiveAt": { + "message": "ģˆ˜ģ‹  ģœ„ģ¹˜" + }, + "destinationAccountPickerSearchPlaceholderToMainnet": { + "message": "ģˆ˜ģ‹  ģ£¼ģ†Œ ė˜ėŠ” ENS" + }, + "destinationAccountPickerSearchPlaceholderToSolana": { + "message": "ģˆ˜ģ‹  ģ£¼ģ†Œ" + }, "details": { "message": "세부 정볓" }, @@ -1516,6 +1657,9 @@ "message": "$1, $2ģ—ģ„œ ģ—°ź²° ķ•“ģ œėØ", "description": "$1 is name of the name and $2 represents the dapp name`" }, + "discover": { + "message": "발견" + }, "discoverSnaps": { "message": "Snap ģ•Œģ•„ė³“źø°", "description": "Text that links to the Snaps website. Displayed in a banner on Snaps list page in settings." @@ -1872,6 +2016,9 @@ "experimental": { "message": "ģ‹¤ķ—˜ģ " }, + "exploreweb3": { + "message": "웹3 ķƒģƒ‰" + }, "exportYourData": { "message": "ė°ģ“ķ„° 낓볓낓기" }, @@ -1885,6 +2032,9 @@ "message": "ģ»¤ė®¤ė‹ˆķ‹°ģ—ģ„œ ė§Œė“¤ģ–“ģ§„ Snapģ„ ģ•Œģ•„ė³“ź³  웹3 ź²½ķ—˜ģ„ ź°œģø ė§žģ¶¤ķ•˜ģ„øģš”.", "description": "Banner description displayed on Snaps list page in Settings when less than 6 Snaps is installed." }, + "externalAccount": { + "message": "외부 계정" + }, "externalExtension": { "message": "외부 ķ™•ģž„" }, @@ -2197,6 +2347,12 @@ "holdToRevealUnlockedLabel": { "message": "ėˆŒėŸ¬ģ„œ ģž źøˆķ•“ģ œėœ ģ„œķ“ 공개" }, + "honeypotDescription": { + "message": "ģ“ ķ† ķ°ģ€ ķ—ˆė‹ˆķŒŸ ģœ„ķ—˜ģ“ ģžˆģ„ 수 ģžˆģŠµė‹ˆė‹¤. ģƒķ˜øģž‘ģš© 전에 ģ‹ ģ¤‘ķžˆ ģ”°ģ‚¬ķ•˜ģ—¬ ģž ģž¬ģ ģø ģ†ģ‹¤ģ„ ģ˜ˆė°©ķ•˜ģ„øģš”." + }, + "honeypotTitle": { + "message": "ķ—ˆė‹ˆķŒŸ" + }, "howNetworkFeesWorkExplanation": { "message": "ķŠøėžœģž­ģ…˜ģ„ ģ²˜ė¦¬ķ•˜źø° ģœ„ķ•“ ķ•„ģš”ķ•œ 예상 ģˆ˜ģˆ˜ė£Œģž…ė‹ˆė‹¤. ģµœėŒ€ ģˆ˜ģˆ˜ė£ŒėŠ” $1ģž…ė‹ˆė‹¤." }, @@ -2262,6 +2418,30 @@ "importNFTTokenIdToolTip": { "message": "NFTģ˜ IDėŠ” ź³ ģœ ķ•œ ģ‹ė³„ģžģ“ėÆ€ė”œ ė™ģ¼ķ•œ NFTėŠ” ģ”“ģž¬ķ•˜ģ§€ ģ•ŠģŠµė‹ˆė‹¤. ė‹¤ģ‹œ ė§ķ•˜ģ§€ė§Œ, OpenSeaģ—ģ„œ ģ“ ė²ˆķ˜øėŠ” '세부 정볓'ģ—ģ„œ 찾아볼 수 ģžˆģŠµė‹ˆė‹¤. ģ“ė„¼ źø°ė”ķ•˜ź±°ė‚˜ ķ“ė¦½ė³“ė“œģ— 복사핓 ė‘ģ„øģš”." }, + "importNWordSRP": { + "message": "$1단얓 복구 źµ¬ė¬øģ“ ģžˆģŠµė‹ˆė‹¤", + "description": "$1 is the number of words in the recovery phrase" + }, + "importPrivateKey": { + "message": "ź°œģø 키" + }, + "importSRPDescription": { + "message": "12개 ė˜ėŠ” 24ź°œģ˜ ė‹Øģ–“ė”œ 된 ė¹„ė°€ė³µźµ¬źµ¬ė¬øģœ¼ė”œ 기씓 ģ§€ź°‘ģ„ ź°€ģ øģ˜¤ģ„øģš”." + }, + "importSRPNumberOfWordsError": { + "message": "ė¹„ė°€ė³µźµ¬źµ¬ė¬øģ€ 12개 ė˜ėŠ” 24ź°œģ˜ ė‹Øģ–“ė”œ źµ¬ģ„±ė˜ģ–“ ģžˆģŠµė‹ˆė‹¤" + }, + "importSRPWordError": { + "message": "$1 단얓가 ģž˜ėŖ»ė˜ģ—ˆź±°ė‚˜ ģ² ģžź°€ ķ‹€ė øģŠµė‹ˆė‹¤.", + "description": "$1 is the word that is incorrect or misspelled" + }, + "importSRPWordErrorAlternative": { + "message": "$1 ė° $2 단얓가 ģž˜ėŖ»ė˜ģ—ˆź±°ė‚˜ ģ² ģžź°€ ķ‹€ė øģŠµė‹ˆė‹¤.", + "description": "$1 and $2 are multiple words that are mispelled." + }, + "importSecretRecoveryPhrase": { + "message": "비밀복구구문 ź°€ģ øģ˜¤źø°" + }, "importSelectedTokens": { "message": "ģ„ ķƒķ•œ ķ† ķ°ģ„ ė¶ˆėŸ¬ģ˜¬ź¹Œģš”?" }, @@ -2280,6 +2460,12 @@ "importTokensError": { "message": "ķ† ķ°ģ„ ź°€ģ øģ˜¬ 수 ģ—†ģŠµė‹ˆė‹¤. ė‚˜ģ¤‘ģ— ė‹¤ģ‹œ ģ‹œė„ķ•˜ģ„øģš”." }, + "importWallet": { + "message": "지갑 ź°€ģ øģ˜¤źø°" + }, + "importWalletOrAccountHeader": { + "message": "지갑 ė˜ėŠ” 계정 ź°€ģ øģ˜¤źø°" + }, "importWithCount": { "message": "$1 불러오기", "description": "$1 will the number of detected tokens that are selected for importing, if all of them are selected then $1 will be all" @@ -2327,6 +2513,12 @@ "insufficientFundsForGas": { "message": "ź°€ģŠ¤ ģžźøˆ 부씱" }, + "insufficientLockedLiquidityDescription": { + "message": "ģœ ė™ģ„± ķ† ķ°ģ„ ģ ģ ˆķžˆ ė½ģ—…ķ•˜ź±°ė‚˜ ģ†Œź°ķ•˜ģ§€ ģ•Šģ•„ ķ† ķ°ģ“ źø‰ź²©ķ•œ ģœ ė™ģ„± ģ“ķƒˆģ— ģ·Øģ•½ķ•˜ėÆ€ė”œ ģ‹œģž„ ė¶ˆģ•ˆģ •ģ„ ģ“ˆėž˜ķ•  수 ģžˆģŠµė‹ˆė‹¤." + }, + "insufficientLockedLiquidityTitle": { + "message": "ģœ ė™ģ„± ė½ģ—… 부씱" + }, "insufficientTokens": { "message": "ķ† ķ°ģ“ ė¶€ģ”±ķ•©ė‹ˆė‹¤." }, @@ -2362,6 +2554,9 @@ "invalidCustomNetworkAlertTitle": { "message": "ģž˜ėŖ»ėœ ė§žģ¶¤ ė„¤ķŠøģ›Œķ¬" }, + "invalidHexData": { + "message": "ģž˜ėŖ»ėœ ķ—„ģŠ¤ ė°ģ“ķ„°" + }, "invalidHexNumber": { "message": "ģž˜ėŖ»ėœ 16ģ§„ģˆ˜ģž…ė‹ˆė‹¤." }, @@ -2540,6 +2735,9 @@ "ledgerLocked": { "message": "Ledger ģž„ģ¹˜ģ— ģ—°ź²°ķ•  수 ģ—†ģŠµė‹ˆė‹¤. ģž„ģ¹˜ģ˜ ģž źøˆģ“ ķ•“ģ œė˜ģ–“ ģžˆź³  ģ“ė”ė¦¬ģ›€ ģ•±ģ“ ģ—“ė ¤ ģžˆėŠ”ģ§€ ķ™•ģøķ•˜ģ„øģš”." }, + "ledgerMultipleDevicesUnsupportedErrorMessage": { + "message": "ģ—¬ėŸ¬ Ledger ģž„ģ¹˜ė„¼ ė™ģ‹œģ— ģ—°ź²°ķ•  수 ģ—†ģŠµė‹ˆė‹¤. 새 Ledger ģž„ģ¹˜ė„¼ ģ—°ź²°ķ•˜ė ¤ė©“ ģ“ģ „ ģž„ģ¹˜ė„¼ 먼저 ģ—°ź²° ķ•“ģ œķ•“ģ•¼ ķ•©ė‹ˆė‹¤." + }, "ledgerTimeout": { "message": "Ledger Liveģ˜ ģ‘ė‹µ ģ‹œź°„ģ“ ė„ˆė¬“ źøøź±°ė‚˜ ģ—°ź²° ģ‹œź°„ģ„ ģ“ˆź³¼ķ–ˆģŠµė‹ˆė‹¤. Ledger Live ģ•±ģ“ ģ—“ė ¤ ģžˆź³  ģž„ģ¹˜ģ˜ ģž źøˆģ“ ķ•“ģ œė˜ģ–“ ģžˆėŠ”ģ§€ ķ™•ģøķ•˜ģ„øģš”." }, @@ -2637,6 +2835,9 @@ "manageDefaultSettings": { "message": "źø°ė³ø ź°œģøģ •ė³“ 볓호 설정 ꓀리" }, + "managePermissions": { + "message": "ź¶Œķ•œ ꓀리" + }, "marketCap": { "message": "ģ‹œź°€ ģ“ģ•”" }, @@ -2755,6 +2956,15 @@ "multichainAddEthereumChainConfirmationDescription": { "message": "MetaMask에 ģ“ ė„¤ķŠøģ›Œķ¬ė„¼ ģ¶”ź°€ķ•˜ź³  ģ“ ģ‚¬ģ“ķŠøģ— ģ‚¬ģš© ź¶Œķ•œģ„ ķ—ˆģš©ķ•©ė‹ˆė‹¤." }, + "multichainQuoteCardBridgingLabel": { + "message": "ėøŒė¦æģ§•" + }, + "multichainQuoteCardQuoteLabel": { + "message": "견적" + }, + "multichainQuoteCardTimeLabel": { + "message": "ģ‹œź°„" + }, "multipleSnapConnectionWarning": { "message": "$1ģ—ģ„œ $2 Snap ģ‚¬ģš©ģ„ ģ›ķ•©ė‹ˆė‹¤.", "description": "$1 is the dapp and $2 is the number of snaps it wants to connect to." @@ -2869,6 +3079,13 @@ "network": { "message": "ė„¤ķŠøģ›Œķ¬:" }, + "networkChanged": { + "message": "ė„¤ķŠøģ›Œķ¬ 변경됨" + }, + "networkChangedMessage": { + "message": "ģ“ģ œ $1 ė„¤ķŠøģ›Œķ¬ģ—ģ„œ ķŠøėžœģž­ģ…˜ ģ¤‘ģž…ė‹ˆė‹¤.", + "description": "$1 is the name of the network" + }, "networkDetails": { "message": "ė„¤ķŠøģ›Œķ¬ 세부 정볓" }, @@ -3143,6 +3360,9 @@ "notEnoughGas": { "message": "ź°€ģŠ¤ 부씱" }, + "notNow": { + "message": "ė‚˜ģ¤‘ģ—" + }, "notificationDetail": { "message": "세부 정볓" }, @@ -3505,6 +3725,13 @@ "origin": { "message": "원본" }, + "originChanged": { + "message": "ģ‚¬ģ“ķŠø 변경됨" + }, + "originChangedMessage": { + "message": "ķ˜„ģž¬ $1ģ˜ ģš”ģ²­ģ„ 검토 ģ¤‘ģž…ė‹ˆė‹¤.", + "description": "$1 is the name of the origin" + }, "osTheme": { "message": "ģ‹œģŠ¤ķ…œ" }, @@ -3559,6 +3786,14 @@ "pending": { "message": "볓넘 중" }, + "pendingConfirmationAddNetworkAlertMessage": { + "message": "ė„¤ķŠøģ›Œķ¬ė„¼ ģ—…ė°ģ“ķŠøķ•˜ė©“ ģ“ ģ‚¬ģ“ķŠøģ—ģ„œ ėŒ€źø° ģ¤‘ģø ķŠøėžœģž­ģ…˜ $1ź±“ģ“ ģ·Øģ†Œė©ė‹ˆė‹¤.", + "description": "Number of transactions." + }, + "pendingConfirmationSwitchNetworkAlertMessage": { + "message": "ė„¤ķŠøģ›Œķ¬ė„¼ ģ „ķ™˜ķ•˜ė©“ ģ“ ģ‚¬ģ“ķŠøģ—ģ„œ ėŒ€źø° ģ¤‘ģø ķŠøėžœģž­ģ…˜ $1ź±“ģ“ ģ·Øģ†Œė©ė‹ˆė‹¤.", + "description": "Number of transactions." + }, "pendingTransactionAlertMessage": { "message": "ģ“ģ „ ķŠøėžœģž­ģ…˜ģ“ ģ™„ė£Œė  ė•Œź¹Œģ§€ ģ“ ķŠøėžœģž­ģ…˜ģ€ ģ§„ķ–‰ė˜ģ§€ ģ•ŠģŠµė‹ˆė‹¤. $1", "description": "$1 represents the words 'how to cancel or speed up a transaction' in a hyperlink" @@ -3842,6 +4077,9 @@ "permitSimulationChange_receive": { "message": "ė°›ģŒ:" }, + "permitSimulationChange_revoke2": { + "message": "철회" + }, "permitSimulationChange_transfer": { "message": "ė³“ėƒ„:" }, @@ -4237,6 +4475,9 @@ "reusedTokenNameWarning": { "message": "여기에 ģžˆėŠ” ķ† ķ°ģ€ ģ‚¬ģš©ģžź°€ ģ£¼ģ‹œ ģ¤‘ģø 다넸 ķ† ķ°ģ˜ 기호넼 ģž¬ģ‚¬ģš©ķ•˜źø° ė•Œė¬øģ— ķ˜¼ė™ė˜ź±°ė‚˜ ģ†źø° ģ‰½ģŠµė‹ˆė‹¤." }, + "revealSecretRecoveryPhrase": { + "message": "비밀복구구문 공개" + }, "revealSeedWords": { "message": "비밀복구구문 공개" }, @@ -4286,12 +4527,19 @@ "reviewAlerts": { "message": "경고 ź²€ķ† ķ•˜źø°" }, + "reviewPendingTransactions": { + "message": "ėŒ€źø° ģ¤‘ģø ķŠøėžœģž­ģ…˜ 검토" + }, "reviewPermissions": { "message": "ź¶Œķ•œ 검토" }, "revokePermission": { "message": "ź¶Œķ•œ 철회" }, + "revokePermissionTitle": { + "message": "$1 ź¶Œķ•œ 제거", + "description": "The token symbol that is being revoked" + }, "revokeSimulationDetailsDesc": { "message": "ź³„ģ •ģ—ģ„œ ķ† ķ°ģ„ ģ‚¬ģš©ķ•  수 ģžˆėŠ” 다넸 ģ‚¬ėžŒģ˜ ź¶Œķ•œģ„ ģ œź±°ķ•©ė‹ˆė‹¤." }, @@ -4334,6 +4582,10 @@ "secretRecoveryPhrase": { "message": "비밀복구구문" }, + "secretRecoveryPhrasePlusNumber": { + "message": "비밀복구구문 $1", + "description": "The $1 is the order of the Secret Recovery Phrase" + }, "secureWallet": { "message": "ė³“ģ•ˆ 지갑" }, @@ -4424,6 +4676,9 @@ "select": { "message": "ģ„ ķƒ" }, + "selectAccountToConnect": { + "message": "ģ—°ź²°ķ•  계정 ģ„ ķƒ" + }, "selectAccounts": { "message": "계정 ģ„ ķƒ" }, @@ -4454,6 +4709,9 @@ "selectRpcUrl": { "message": "RPC URL ģ„ ķƒ" }, + "selectSecretRecoveryPhrase": { + "message": "비밀복구구문 ģ„ ķƒ" + }, "selectType": { "message": "ģœ ķ˜• ģ„ ķƒ" }, @@ -4565,16 +4823,6 @@ "showHexDataDescription": { "message": "ģ“ ķ•­ėŖ©ģ„ ģ„ ķƒķ•˜ė©“ 볓낓기 화멓에 16ģ§„ģˆ˜ ė°ģ“ķ„° ķ•„ė“œź°€ ķ‘œģ‹œė©ė‹ˆė‹¤." }, - "showIncomingTransactions": { - "message": "ģˆ˜ģ‹ ė˜ėŠ” ķŠøėžœģž­ģ…˜ ķ‘œģ‹œ" - }, - "showIncomingTransactionsDescription": { - "message": "ģ“ ķ•­ėŖ©ģ„ ģ„ ķƒķ•˜ė©“ Etherscanģ„ ģ‚¬ģš©ķ•“ ź±°ėž˜ ėŖ©ė”ģ— ģˆ˜ģ‹  ź±°ėž˜ė„¼ ķ‘œģ‹œķ•  수 ģžˆģŠµė‹ˆė‹¤.", - "description": "$1 is the link to etherscan url and $2 is the link to the privacy policy of consensys APIs" - }, - "showIncomingTransactionsExplainer": { - "message": "ģ“ėŠ” ė„¤ķŠøģ›Œķ¬ė§ˆė‹¤ 다넸 ģ œģ‚¼ģž API에 ģ˜ģ”“ķ•˜ė©°, ģ“ė”ė¦¬ģ›€ ģ£¼ģ†Œģ™€ IP ģ£¼ģ†Œź°€ ė…øģ¶œė©ė‹ˆė‹¤." - }, "showLess": { "message": "ź°„ėžµķžˆ 볓기" }, @@ -4593,6 +4841,9 @@ "showPrivateKey": { "message": "ź°œģø 키 ķ‘œģ‹œ" }, + "showSRP": { + "message": "비밀복구구문 ķ‘œģ‹œ" + }, "showTestnetNetworks": { "message": "ķ…ŒģŠ¤ķŠø ė„¤ķŠøģ›Œķ¬ 볓기" }, @@ -4714,12 +4965,24 @@ "slideCashOutTitle": { "message": "MetaMask딜 ķ˜„źøˆķ™”" }, + "slideDebitCardDescription": { + "message": "ģ¼ė¶€ ģ§€ģ—­ģ—ģ„œ ģ‚¬ģš© ź°€ėŠ„" + }, "slideDebitCardTitle": { "message": "MetaMask ģ§ė¶ˆģ¹“ė“œ" }, + "slideFundWalletDescription": { + "message": "ģ‹œģž‘ķ•˜ė ¤ė©“ ķ† ķ°ģ„ ģ¶”ź°€ķ•˜ź±°ė‚˜ ģ „ģ†”ķ•˜ģ„øģš”" + }, "slideFundWalletTitle": { "message": "지갑에 ģžźøˆ 추가" }, + "slideSweepStakeDescription": { + "message": "NFT넼 ėÆ¼ķŒ…ķ•˜ź³  당첨 기회넼 ģž”ģœ¼ģ„øģš”" + }, + "slideSweepStakeTitle": { + "message": "$5000 USDC ź²½ķ’ˆ ģ“ė²¤ķŠøģ— ģ°øģ—¬ķ•˜ģ„øģš”!" + }, "smartContracts": { "message": "스마트 계약" }, @@ -4866,6 +5129,9 @@ "snapResultSuccessDescription": { "message": "$1 ģ‚¬ģš© ź°€ėŠ„" }, + "snapUIAssetSelectorTitle": { + "message": "ģžģ‚° ģ„ ķƒ" + }, "snapUpdateAlertDescription": { "message": "$1ģ˜ ģµœģ‹  버전 받기", "description": "Description used in Snap update alert banner when snap update is available. $1 is the Snap name." @@ -4925,6 +5191,27 @@ "message": "$1 ģž‘ģ„±ģžģ—ź²Œ ģ—°ė½ķ•˜ģ—¬ 햄후 ģ§€ģ›ģ„ ģš”ģ²­ķ•˜ģ„øģš”.", "description": "This is shown when the insight snap throws an error. $1 is the snap name" }, + "solanaImportAccounts": { + "message": "ģ†”ė¼ė‚˜ 계정 ź°€ģ øģ˜¤źø°" + }, + "solanaImportAccountsDescription": { + "message": "다넸 ģ§€ź°‘ģ—ģ„œ ģ†”ė¼ė‚˜ ź³„ģ •ģ„ ź°€ģ øģ˜¤ė ¤ė©“ ė¹„ė°€ė³µźµ¬źµ¬ė¬øģ„ ģž…ė „ķ•˜ģ„øģš”." + }, + "solanaMoreFeaturesComingSoon": { + "message": "ė” ė§Žģ€ źø°ėŠ„ģ“ ź³§ ģ¶”ź°€ė©ė‹ˆė‹¤" + }, + "solanaMoreFeaturesComingSoonDescription": { + "message": "ģ†”ė¼ė‚˜ 디앱, NFT, ķ•˜ė“œģ›Øģ–“ 지갑 지원 ė“±ģ“ ź³§ ģ¶”ź°€ė©ė‹ˆė‹¤." + }, + "solanaOnMetaMask": { + "message": "MetaMask ķ”Œėž«ķ¼ģ—ģ„œģ˜ ģ†”ė¼ė‚˜ ģ“ģš©" + }, + "solanaSendReceiveSwapTokens": { + "message": "토큰 ģ†”źøˆ, 받기, ģŠ¤ģ™‘" + }, + "solanaSendReceiveSwapTokensDescription": { + "message": "SOL, USDC ė“±ģ˜ ķ† ķ°ģ„ 전솔 ė° ķŠøėžœģž­ģ…˜ķ•˜ģ„øģš”." + }, "someNetworks": { "message": "ė„¤ķŠøģ›Œķ¬ $1개" }, @@ -4951,6 +5238,21 @@ "source": { "message": "ģ†ŒģŠ¤" }, + "spamModalBlockedDescription": { + "message": "ģ“ ģ‚¬ģ“ķŠøėŠ” 1ė¶„ź°„ ģ°Øė‹Øė©ė‹ˆė‹¤." + }, + "spamModalBlockedTitle": { + "message": "ģ“ ģ‚¬ģ“ķŠøė„¼ ģ¼ģ‹œģ ģœ¼ė”œ ģ°Øė‹Øķ–ˆģŠµė‹ˆė‹¤" + }, + "spamModalDescription": { + "message": "ģ—¬ėŸ¬ ģš”ģ²­ģ“ 반복될 경우 ģ‚¬ģ“ķŠøė„¼ ģ¼ģ‹œģ ģœ¼ė”œ 차단할 수 ģžˆģŠµė‹ˆė‹¤." + }, + "spamModalTemporaryBlockButton": { + "message": "ģ“ ģ‚¬ģ“ķŠø ģ¼ģ‹œģ ģœ¼ė”œ 차단" + }, + "spamModalTitle": { + "message": "ģ—¬ėŸ¬ ģš”ģ²­ģ“ ź°ģ§€ė˜ģ—ˆģŠµė‹ˆė‹¤" + }, "speed": { "message": "ģ†ė„" }, @@ -5000,10 +5302,28 @@ "spendingCap": { "message": "ģ§€ģ¶œ ķ•œė„" }, + "spendingCaps": { + "message": "ģ§€ģ¶œ ķ•œė„" + }, "srpInputNumberOfWords": { "message": "제 źµ¬ė¬øģ€ $1ź°œģ˜ ė‹Øģ–“ė”œ ģ“ė£Øģ–“ģ ø ģžˆģŠµė‹ˆė‹¤", "description": "This is the text for each option in the dropdown where a user selects how many words their secret recovery phrase has during import. The $1 is the number of words (either 12, 15, 18, 21, or 24)." }, + "srpListName": { + "message": "비밀복구구문 $1", + "description": "$1 is the order of the Secret Recovery Phrase" + }, + "srpListNumberOfAccounts": { + "message": "계정 $1개", + "description": "$1 is the number of accounts in the list" + }, + "srpListSelectionDescription": { + "message": "새 ź³„ģ •ģ“ ģƒģ„±ė  ė•Œ ģ‚¬ģš©ė  비밀복구구문" + }, + "srpListSingleOrZero": { + "message": "계정 $1개", + "description": "$1 is the number of accounts in the list, it is either 1 or 0" + }, "srpPasteFailedTooManyWords": { "message": "단얓가 24개넼 ģ“ˆź³¼ķ•˜ģ—¬ 붙여넣기에 ģ‹¤ķŒØķ–ˆģŠµė‹ˆė‹¤. ė¹„ė°€ė³µźµ¬źµ¬ė¬øģ€ 24개 ģ“ķ•˜ģ˜ ė‹Øģ–“ė”œ ģ“ė£Øģ–“ģ§‘ė‹ˆė‹¤.", "description": "Description of SRP paste error when the pasted content has too many words" @@ -5158,6 +5478,9 @@ "message": "ģ‹œģž„ ģƒķ™©ģ“ ź°‘ģžźø° ė³€ķ•˜ė©“ ģ‹¤ķŒØķ•  수 ģžˆģŠµė‹ˆė‹¤. ė¬øģ œź°€ ģ§€ģ†ė˜ė©“ $1(으)딜 ė¬øģ˜ķ•˜ģ„øģš”.", "description": "This message is shown to a user if their swap fails. The $1 will be replaced by support.metamask.io" }, + "stxOptInSupportedNetworksDescription": { + "message": "스마트 ķŠøėžœģž­ģ…˜ģ„ ķ™œģ„±ķ™”ķ•˜ė©“ ģ§€ģ›ė˜ėŠ” ė„¤ķŠøģ›Œķ¬ģ—ģ„œ ė” ģ•ˆģ „ķ•˜ź³  신뢰할 수 ģžˆėŠ” ķŠøėžœģž­ģ…˜ģ„ ķ•  수 ģžˆģŠµė‹ˆė‹¤. $1" + }, "stxPendingPrivatelySubmittingSwap": { "message": "ģŠ¤ģ™‘ģ„ ė¹„ź³µź°œė”œ ģ œģ¶œķ•˜ėŠ” 중..." }, @@ -5977,6 +6300,12 @@ "message": "NFT(ERC-721) 토큰 ģ „ģ†”ģ€ ķ˜„ģž¬ ģ§€ģ›ė˜ģ§€ ģ•ŠģŠµė‹ˆė‹¤.", "description": "This is an error message we show the user if they attempt to send an NFT asset type, for which currently don't support sending" }, + "unstableTokenPriceDescription": { + "message": "ģ“ ķ† ķ°ģ˜ USD ź°€ź²©ģ€ ė³€ė™ģ„±ģ“ 매우 ģ»¤ģ„œ ģƒķ˜øģž‘ģš© ģ‹œ 큰 손실 ģœ„ķ—˜ģ“ ģžˆģŠµė‹ˆė‹¤." + }, + "unstableTokenPriceTitle": { + "message": "ė¶ˆģ•ˆģ •ķ•œ 토큰 가격" + }, "upArrow": { "message": "상승 ķ™”ģ‚“ķ‘œ" }, @@ -6099,6 +6428,18 @@ "visitSite": { "message": "ģ‚¬ģ“ķŠø 방문" }, + "visitSupportDataConsentModalAccept": { + "message": "ģ»ØķŽŒ" + }, + "visitSupportDataConsentModalDescription": { + "message": "MetaMask ģ‹ė³„ģžģ™€ 앱 ė²„ģ „ģ„ 지원 센터에 ź³µģœ ķ•˜ģ‹œź² ģŠµė‹ˆź¹Œ? 문제 핓결에 ė„ģ›€ģ“ 될 수 ģžˆģœ¼ė©°, ģ„ ķƒ ģ‚¬ķ•­ģž…ė‹ˆė‹¤." + }, + "visitSupportDataConsentModalReject": { + "message": "ź³µģœ ķ•˜ģ§€ ģ•Šźø°" + }, + "visitSupportDataConsentModalTitle": { + "message": "ģ§€ģ›ķŒ€ź³¼ ģž„ģ¹˜ 세부정볓 공유" + }, "visitWebSite": { "message": "ģ›¹ģ‚¬ģ“ķŠøė„¼ ė°©ė¬øķ•˜ģ„øģš”" }, diff --git a/app/_locales/ph/messages.json b/app/_locales/ph/messages.json index 98efbc040e6e..bb033092f475 100644 --- a/app/_locales/ph/messages.json +++ b/app/_locales/ph/messages.json @@ -1080,13 +1080,6 @@ "showHexDataDescription": { "message": "Piliin ito para ipakita ang field ng hex data sa screen ng pagpapadala" }, - "showIncomingTransactions": { - "message": "Ipakita ang Mga Papasok na Transaksyon" - }, - "showIncomingTransactionsDescription": { - "message": "Piliin ito para gamitin ang Etherscan sa pagpapakita ng mga papasok na transaksyon sa listahan ng mga transaksyon", - "description": "$1 is the link to etherscan url and $2 is the link to the privacy policy of consensys APIs" - }, "showPermissions": { "message": "Ipakita ang mga pahintulot" }, diff --git a/app/_locales/pt/messages.json b/app/_locales/pt/messages.json index 47a9c92130fa..ac184661617f 100644 --- a/app/_locales/pt/messages.json +++ b/app/_locales/pt/messages.json @@ -44,6 +44,20 @@ "QRHardwareWalletSteps2Description": { "message": "Ngrave Zero" }, + "SrpListHideAccounts": { + "message": "Ocultar $1 contas", + "description": "$1 is the number of accounts" + }, + "SrpListHideSingleAccount": { + "message": "Ocultar 1 conta" + }, + "SrpListShowAccounts": { + "message": "Exibir $1 contas", + "description": "$1 is the number of accounts" + }, + "SrpListShowSingleAccount": { + "message": "Exibir 1 conta" + }, "about": { "message": "Sobre" }, @@ -76,6 +90,9 @@ "accountDetails": { "message": "Detalhes da conta" }, + "accountDetailsRevokeDelegationButton": { + "message": " Voltar para a conta normal" + }, "accountIdenticon": { "message": "Identicon da conta" }, @@ -153,6 +170,12 @@ "addAlias": { "message": "Adicionar pseudĆ“nimo" }, + "addBitcoinAccountLabel": { + "message": "Conta Bitcoin (Beta)" + }, + "addBitcoinTestnetAccountLabel": { + "message": "Conta Bitcoin (Testnet)" + }, "addBlockExplorer": { "message": "Adicionar um explorador de blocos" }, @@ -193,6 +216,9 @@ "addFriendsAndAddresses": { "message": "Adicionar amigos e endereƧos confiĆ”veis" }, + "addHardwareWalletLabel": { + "message": "Carteira de hardware" + }, "addIPFSGateway": { "message": "Adicione seu gateway IPFS preferencial" }, @@ -212,12 +238,26 @@ "addNewAccount": { "message": "Adicionar uma nova conta Ethereum" }, + "addNewEthereumAccountLabel": { + "message": "Conta Ethereum" + }, + "addNewSolanaAccountLabel": { + "message": "Conta Solana" + }, "addNft": { "message": "Adicionar NFT" }, "addNfts": { "message": "Adicionar NFTs" }, + "addNonEvmAccount": { + "message": "Adicionar $1 conta", + "description": "$1 is the non EVM network where the account is going to be created, e.g. Bitcoin or Solana" + }, + "addNonEvmAccountFromNetworkPicker": { + "message": "Para ativar a rede $1, Ć© necessĆ”rio criar uma conta $2.", + "description": "$1 is the non EVM network where the account is going to be created, e.g. Solana Mainnet or Solana Devnet. $2 is the account type, e.g. Bitcoin or Solana" + }, "addRpcUrl": { "message": "Adicionar URL da RPC" }, @@ -300,14 +340,16 @@ "advancedPriorityFeeToolTip": { "message": "A taxa de prioridade (ou seja, \"gorjeta do minerador\") vai diretamente para os mineradores e os incentiva a priorizar a sua transação." }, - "aggregatedBalancePopover": { - "message": "Isso reflete o valor de todos os tokens que vocĆŖ possui em uma dada rede. Se vocĆŖ preferir ver esse valor em ETH ou outras moedas, acesse a $1.", - "description": "$1 represents the settings page" - }, "agreeTermsOfUse": { "message": "Concordo com os $1 da MetaMask", "description": "$1 is the `terms` link" }, + "airDropPatternDescription": { + "message": "O histórico do token na rede revela ocorrĆŖncias anteriores de atividades de airdrop suspeitas." + }, + "airDropPatternTitle": { + "message": "PadrĆ£o de airdrop" + }, "airgapVault": { "message": "AirGap Vault" }, @@ -726,9 +768,21 @@ "bridgeConfirmTwoTransactions": { "message": "SerĆ” necessĆ”rio confirmar 2 transaƧƵes na sua carteira de hardware:" }, + "bridgeCreateSolanaAccount": { + "message": "Criar conta Solana" + }, + "bridgeCreateSolanaAccountDescription": { + "message": "Para trocar para a rede Solana, Ć© necessĆ”rio ter uma conta e um endereƧo de recebimento." + }, + "bridgeCreateSolanaAccountTitle": { + "message": "Antes, vocĆŖ precisarĆ” de uma conta Solana." + }, "bridgeEnterAmount": { "message": "Insira o valor" }, + "bridgeEnterAmountAndSelectAccount": { + "message": "Insira o valor e selecione a conta de destino" + }, "bridgeExplorerLinkViewOn": { "message": "Visualizar em $1" }, @@ -751,9 +805,15 @@ "bridgeQuoteExpired": { "message": "O prazo da sua cotação esgotou." }, + "bridgeSelectDestinationAccount": { + "message": "Selecione a conta de destino" + }, "bridgeSelectNetwork": { "message": "Selecionar rede" }, + "bridgeSelectTokenAmountAndAccount": { + "message": "Selecione token, valor e conta de destino" + }, "bridgeSelectTokenAndAmount": { "message": "Selecionar token e valor" }, @@ -944,6 +1004,12 @@ "message": "Nenhuma opção encontrada", "description": "Default text shown in the combo field dropdown if no options." }, + "concentratedSupplyDistributionDescription": { + "message": "A maior parte do suprimento de tokens estĆ” em posse dos principais detentores do token, o que representa um risco de manipulação centralizada de preƧos" + }, + "concentratedSupplyDistributionTitle": { + "message": "Suprimento com distribuição concentrada" + }, "configureSnapPopupDescription": { "message": "VocĆŖ estĆ” saindo da MetaMask para configurar esse snap." }, @@ -962,6 +1028,15 @@ "confirm": { "message": "Confirmar" }, + "confirmAccountType": { + "message": "Tipo" + }, + "confirmAccountTypeSmartContract": { + "message": "Conta inteligente" + }, + "confirmAccountTypeStandard": { + "message": "Conta padrĆ£o" + }, "confirmAlertModalAcknowledgeMultiple": { "message": "Confirmo que recebi os alertas e ainda quero prosseguir" }, @@ -974,12 +1049,36 @@ "confirmFieldTooltipPaymaster": { "message": "A taxa dessa transação serĆ” paga pelo contrato inteligente do tesoureiro." }, + "confirmGasFeeTokenBalance": { + "message": "Saldo:" + }, + "confirmGasFeeTokenInsufficientBalance": { + "message": "Fundos insuficientes" + }, + "confirmGasFeeTokenMetaMaskFee": { + "message": "Inclui taxa de $1" + }, + "confirmGasFeeTokenModalTitle": { + "message": "Selecione um token" + }, + "confirmGasFeeTokenToast": { + "message": "VocĆŖ estĆ” pagando esta taxa de rede com $1" + }, + "confirmGasFeeTokenTooltip": { + "message": "Isso Ć© pago Ć  rede para processar sua transação. Inclui uma taxa de $1 da MetaMask para tokens nĆ£o ETH." + }, + "confirmNestedTransactionTitle": { + "message": "Transação: $1" + }, "confirmPassword": { "message": "Confirmar a senha" }, "confirmRecoveryPhrase": { "message": "Confirmar Frase de Recuperação Secreta" }, + "confirmSimulationApprove": { + "message": "VocĆŖ aprova" + }, "confirmTitleApproveTransactionNFT": { "message": "Solicitação de saque" }, @@ -1022,9 +1121,24 @@ "confirmTitleTransaction": { "message": "Solicitação de transação" }, + "confirmUpgradeCancelModalButtonCancelTransaction": { + "message": "Cancelar transação" + }, + "confirmUpgradeCancelModalButtonCancelUpgrade": { + "message": "Cancelar atualização e transação" + }, + "confirmUpgradeCancelModalDescription": { + "message": "Se vocĆŖ nĆ£o deseja atualizar sua conta, pode cancelar a atualização aqui.\n\nPara terminar esta transação sem uma atualização, Ć© necessĆ”rio fazer esta solicitação novamente no site. $1." + }, + "confirmUpgradeCancelModalTitle": { + "message": "Cancelar transação" + }, "confirmationAlertDetails": { "message": "Para proteger seus ativos, Ć© recomendĆ”vel que vocĆŖ recuse a solicitação." }, + "confirmationAlertModalTitleDescription": { + "message": "Seus ativos podem estar em risco" + }, "confirmed": { "message": "Confirmada" }, @@ -1052,6 +1166,9 @@ "connectAccounts": { "message": "Conectar contas" }, + "connectAnAccountHeader": { + "message": "Conectar uma conta" + }, "connectManually": { "message": "Conectar manualmente ao site atual" }, @@ -1158,6 +1275,9 @@ "message": "Falha ao buscar $1. Verifique sua rede e tente de novo.", "description": "$1 is the name of the snap being fetched." }, + "connectionPopoverDescription": { + "message": "Para se conectar a um site, selecione o botĆ£o \"conectar\". A MetaMask só pode se conectar a sites Web3." + }, "connectionRequest": { "message": "Solicitação de conexĆ£o" }, @@ -1219,6 +1339,9 @@ "create": { "message": "Criar" }, + "createNewAccountHeader": { + "message": "Crie uma conta" + }, "createNewWallet": { "message": "Criar uma nova carteira" }, @@ -1231,6 +1354,9 @@ "createSnapAccountTitle": { "message": "Criar conta" }, + "createSolanaAccount": { + "message": "Criar conta Solana" + }, "creatorAddress": { "message": "EndereƧo do criador" }, @@ -1471,6 +1597,21 @@ "message": "Descrição de $1", "description": "$1 represents the name of the snap" }, + "destinationAccountPickerNoEligible": { + "message": "Nenhuma conta qualificada encontrada" + }, + "destinationAccountPickerNoMatching": { + "message": "Nenhuma conta correspondentes encontrada" + }, + "destinationAccountPickerReceiveAt": { + "message": "Receber em" + }, + "destinationAccountPickerSearchPlaceholderToMainnet": { + "message": "EndereƧo de recebimento ou ENS" + }, + "destinationAccountPickerSearchPlaceholderToSolana": { + "message": "EndereƧo de recebimento" + }, "details": { "message": "Detalhes" }, @@ -1516,6 +1657,9 @@ "message": "$1 desconectada de $2", "description": "$1 is name of the name and $2 represents the dapp name`" }, + "discover": { + "message": "Descobrir" + }, "discoverSnaps": { "message": "Descobrir Snaps", "description": "Text that links to the Snaps website. Displayed in a banner on Snaps list page in settings." @@ -1872,6 +2016,9 @@ "experimental": { "message": "Experimental" }, + "exploreweb3": { + "message": "Explore a Web3" + }, "exportYourData": { "message": "Exportar seus dados" }, @@ -1885,6 +2032,9 @@ "message": "Explore Snaps desenvolvidos pela comunidade para personalizar sua experiĆŖncia na web3", "description": "Banner description displayed on Snaps list page in Settings when less than 6 Snaps is installed." }, + "externalAccount": { + "message": "Conta externa" + }, "externalExtension": { "message": "ExtensĆ£o externa" }, @@ -2197,6 +2347,12 @@ "holdToRevealUnlockedLabel": { "message": "cĆ­rculo \"segure para revelar\" desbloqueado" }, + "honeypotDescription": { + "message": "Este token pode representar um risco de honeypot (armadilha). Ɖ recomendado realizar a devida diligĆŖncia antes de interagir para evitar possĆ­veis perdas financeiras." + }, + "honeypotTitle": { + "message": "Honeypot" + }, "howNetworkFeesWorkExplanation": { "message": "Taxa estimada necessĆ”ria para processar a transação. A taxa mĆ”xima Ć© $1." }, @@ -2262,6 +2418,30 @@ "importNFTTokenIdToolTip": { "message": "O ID de um NFT Ć© um identificador Ćŗnico, pois nĆ£o hĆ” dois NFTs iguais. Novamente, na OpenSea, esse nĆŗmero se encontra em \"Detalhes\". Anote-o ou copie-o para sua Ć”rea de transferĆŖncia." }, + "importNWordSRP": { + "message": "Tenho uma Frase de Recuperação de $1 palavra(s)", + "description": "$1 is the number of words in the recovery phrase" + }, + "importPrivateKey": { + "message": "Chave privada" + }, + "importSRPDescription": { + "message": "Importe uma carteira existente com sua Frase de Recuperação Secreta de 12 ou 24 palavras." + }, + "importSRPNumberOfWordsError": { + "message": "Frases de Recuperação Secretas contĆŖm 12 ou 24 palavras" + }, + "importSRPWordError": { + "message": "A palavra $1 estĆ” incorreta ou contĆ©m erros de ortografia.", + "description": "$1 is the word that is incorrect or misspelled" + }, + "importSRPWordErrorAlternative": { + "message": "Palavras $1 e $2 estĆ£o incorretas ou contĆŖm erros de ortografia.", + "description": "$1 and $2 are multiple words that are mispelled." + }, + "importSecretRecoveryPhrase": { + "message": "Importar Frase de Recuperação Secreta" + }, "importSelectedTokens": { "message": "Importar tokens selecionados?" }, @@ -2280,6 +2460,12 @@ "importTokensError": { "message": "NĆ£o foi possĆ­vel importar os tokens. Volte a tentar mais tarde." }, + "importWallet": { + "message": "Importar carteira" + }, + "importWalletOrAccountHeader": { + "message": "Importe uma carteira ou conta" + }, "importWithCount": { "message": "Importar $1", "description": "$1 will the number of detected tokens that are selected for importing, if all of them are selected then $1 will be all" @@ -2327,6 +2513,12 @@ "insufficientFundsForGas": { "message": "Fundos insuficientes para o gĆ”s" }, + "insufficientLockedLiquidityDescription": { + "message": "Quando nĆ£o se faz o bloqueio ou queima adequada de tokens de liquidez, o token se torna vulnerĆ”vel a saques repentinos de liquidez, potencialmente causando instabilidade no mercado." + }, + "insufficientLockedLiquidityTitle": { + "message": "Liquidez bloqueada insuficiente" + }, "insufficientTokens": { "message": "Tokens insuficientes." }, @@ -2362,6 +2554,9 @@ "invalidCustomNetworkAlertTitle": { "message": "Rede personalizada invĆ”lida" }, + "invalidHexData": { + "message": "Dados hexa invĆ”lidos" + }, "invalidHexNumber": { "message": "NĆŗmero hexadecimal invĆ”lido." }, @@ -2540,6 +2735,9 @@ "ledgerLocked": { "message": "NĆ£o Ć© possĆ­vel conectar ao dispositivo Ledger. Certifique-se de que seu dispositivo esteja desbloqueado e que o aplicativo Ethereum esteja aberto." }, + "ledgerMultipleDevicesUnsupportedErrorMessage": { + "message": "NĆ£o Ć© possĆ­vel conectar vĆ”rios dispositivos Ledger ao mesmo tempo. Para conectar um novo dispositivo Ledger, primeiro Ć© necessĆ”rio desconectar o anterior." + }, "ledgerTimeout": { "message": "O Ledger Live estĆ” demorando muito para responder ou a conexĆ£o expirou. Certifique-se de que o aplicativo do Ledger Live esteja aberto e que seu dispositivo esteja desbloqueado." }, @@ -2637,6 +2835,9 @@ "manageDefaultSettings": { "message": "Gerenciar configuraƧƵes de privacidade padrĆ£o" }, + "managePermissions": { + "message": "Gerenciar permissƵes" + }, "marketCap": { "message": "Capitalização de mercado" }, @@ -2755,6 +2956,15 @@ "multichainAddEthereumChainConfirmationDescription": { "message": "VocĆŖ estĆ” adicionando esta rede Ć  MetaMask e dando a este site permissĆ£o para usĆ”-la." }, + "multichainQuoteCardBridgingLabel": { + "message": "Fazer ponte" + }, + "multichainQuoteCardQuoteLabel": { + "message": "Cotação" + }, + "multichainQuoteCardTimeLabel": { + "message": "Hora" + }, "multipleSnapConnectionWarning": { "message": "$1 quer usar Snaps de $2", "description": "$1 is the dapp and $2 is the number of snaps it wants to connect to." @@ -2869,6 +3079,13 @@ "network": { "message": "Ethereum:" }, + "networkChanged": { + "message": "Rede alterada" + }, + "networkChangedMessage": { + "message": "Agora vocĆŖ estĆ” realizando transaƧƵes na $1.", + "description": "$1 is the name of the network" + }, "networkDetails": { "message": "Detalhes da rede" }, @@ -3143,6 +3360,9 @@ "notEnoughGas": { "message": "NĆ£o hĆ” gĆ”s suficiente" }, + "notNow": { + "message": "Agora nĆ£o" + }, "notificationDetail": { "message": "Detalhes" }, @@ -3505,6 +3725,13 @@ "origin": { "message": "Origem" }, + "originChanged": { + "message": "Site alterado" + }, + "originChangedMessage": { + "message": "Agora vocĆŖ estĆ” analisando uma solicitação de $1.", + "description": "$1 is the name of the origin" + }, "osTheme": { "message": "Sistema" }, @@ -3559,6 +3786,14 @@ "pending": { "message": "Pendente" }, + "pendingConfirmationAddNetworkAlertMessage": { + "message": "Atualizar a rede cancelarĆ” $1 transaƧƵes pendentes deste site.", + "description": "Number of transactions." + }, + "pendingConfirmationSwitchNetworkAlertMessage": { + "message": "Trocar de rede cancelarĆ” $1 transaƧƵes pendentes deste site.", + "description": "Number of transactions." + }, "pendingTransactionAlertMessage": { "message": "Esta transação só serĆ” realizada após a conclusĆ£o de uma transação anterior. $1", "description": "$1 represents the words 'how to cancel or speed up a transaction' in a hyperlink" @@ -3842,6 +4077,9 @@ "permitSimulationChange_receive": { "message": "VocĆŖ recebe" }, + "permitSimulationChange_revoke2": { + "message": "Revogar" + }, "permitSimulationChange_transfer": { "message": "VocĆŖ envia" }, @@ -4237,6 +4475,9 @@ "reusedTokenNameWarning": { "message": "Um token aqui reutiliza um sĆ­mbolo de outro token que vocĆŖ acompanha; isso pode causar confusĆ£o ou induzir a erros." }, + "revealSecretRecoveryPhrase": { + "message": "Revelar Frase de Recuperação Secreta" + }, "revealSeedWords": { "message": "Revelar Frase de Recuperação Secreta" }, @@ -4286,12 +4527,19 @@ "reviewAlerts": { "message": "Conferir alertas" }, + "reviewPendingTransactions": { + "message": "Analisar transaƧƵes pendentes" + }, "reviewPermissions": { "message": "Revisar permissƵes" }, "revokePermission": { "message": "Revogar permissĆ£o" }, + "revokePermissionTitle": { + "message": "Remover permissĆ£o de $1", + "description": "The token symbol that is being revoked" + }, "revokeSimulationDetailsDesc": { "message": "VocĆŖ estĆ” removendo a permissĆ£o para alguĆ©m gastar tokens da sua conta." }, @@ -4334,6 +4582,10 @@ "secretRecoveryPhrase": { "message": "Frase de Recuperação Secreta" }, + "secretRecoveryPhrasePlusNumber": { + "message": "Frase de Recuperação Secreta $1", + "description": "The $1 is the order of the Secret Recovery Phrase" + }, "secureWallet": { "message": "Carteira segura" }, @@ -4424,6 +4676,9 @@ "select": { "message": "Selecionar" }, + "selectAccountToConnect": { + "message": "Selecione uma conta para se conectar" + }, "selectAccounts": { "message": "Selecione a(s) conta(s) para usar nesse site" }, @@ -4454,6 +4709,9 @@ "selectRpcUrl": { "message": "Selecionar URL da RPC" }, + "selectSecretRecoveryPhrase": { + "message": "Selecionar Frase de Recuperação Secreta" + }, "selectType": { "message": "Selecione o tipo" }, @@ -4565,16 +4823,6 @@ "showHexDataDescription": { "message": "Selecione essa opção para exibir o campo de dados hexa na tela de envio" }, - "showIncomingTransactions": { - "message": "Exibir transaƧƵes recebidas" - }, - "showIncomingTransactionsDescription": { - "message": "Isso depende de $1, que terĆ” acesso ao seu endereƧo Ethereum e ao seu endereƧo IP. $2", - "description": "$1 is the link to etherscan url and $2 is the link to the privacy policy of consensys APIs" - }, - "showIncomingTransactionsExplainer": { - "message": "Isso depende de diferentes APIs de terceiros para cada rede, o que expƵe seu endereƧo Ethereum e seu endereƧo IP." - }, "showLess": { "message": "Mostrar menos" }, @@ -4593,6 +4841,9 @@ "showPrivateKey": { "message": "Exibir chave privada" }, + "showSRP": { + "message": "Mostrar Frase de Recuperação Secreta" + }, "showTestnetNetworks": { "message": "Exibir redes de teste" }, @@ -4714,12 +4965,24 @@ "slideCashOutTitle": { "message": "Saque com a MetaMask" }, + "slideDebitCardDescription": { + "message": "DisponĆ­vel em regiƵes selecionadas" + }, "slideDebitCardTitle": { "message": "CartĆ£o de dĆ©bito MetaMask" }, + "slideFundWalletDescription": { + "message": "Adicione ou transfira tokens para comeƧar" + }, "slideFundWalletTitle": { "message": "Adicione valores Ć  sua carteira" }, + "slideSweepStakeDescription": { + "message": "Cunhe um NFT agora para concorrer" + }, + "slideSweepStakeTitle": { + "message": "Participe do sorteio de $5000 em USDC!" + }, "smartContracts": { "message": "Contratos inteligentes" }, @@ -4866,6 +5129,9 @@ "snapResultSuccessDescription": { "message": "$1 estĆ” pronto para ser usado" }, + "snapUIAssetSelectorTitle": { + "message": "Selecione um ativo" + }, "snapUpdateAlertDescription": { "message": "Baixe a Ćŗltima versĆ£o de $1", "description": "Description used in Snap update alert banner when snap update is available. $1 is the Snap name." @@ -4925,6 +5191,27 @@ "message": "Contate os criadores de $1 para receber mais suporte.", "description": "This is shown when the insight snap throws an error. $1 is the snap name" }, + "solanaImportAccounts": { + "message": "Importar contas Solana" + }, + "solanaImportAccountsDescription": { + "message": "Importe uma Frase de Recuperação Secreta para migrar sua conta Solana a partir de outra carteira." + }, + "solanaMoreFeaturesComingSoon": { + "message": "Mais recursos em breve" + }, + "solanaMoreFeaturesComingSoonDescription": { + "message": "Em breve, adicionaremos suporte para dapps e NFTs Solana, alĆ©m de carteiras de hardware e outras novidades." + }, + "solanaOnMetaMask": { + "message": "Solana na MetaMask" + }, + "solanaSendReceiveSwapTokens": { + "message": "Envie, receba e troque tokens" + }, + "solanaSendReceiveSwapTokensDescription": { + "message": "FaƧa transferĆŖncias e transaƧƵes com tokens como SOL, USDC e muitos outros." + }, "someNetworks": { "message": "Redes de $1" }, @@ -4951,6 +5238,21 @@ "source": { "message": "Fonte" }, + "spamModalBlockedDescription": { + "message": "Este site serĆ” bloqueado por 1 minuto." + }, + "spamModalBlockedTitle": { + "message": "VocĆŖ bloqueou temporariamente este site" + }, + "spamModalDescription": { + "message": "Se vocĆŖ estiver sendo bombardeado com diversas solicitaƧƵes indesejadas, pode bloquear temporariamente o site." + }, + "spamModalTemporaryBlockButton": { + "message": "Bloquear temporariamente este site" + }, + "spamModalTitle": { + "message": "Notamos vĆ”rias solicitaƧƵes" + }, "speed": { "message": "Velocidade" }, @@ -5000,10 +5302,28 @@ "spendingCap": { "message": "Limite de gastos" }, + "spendingCaps": { + "message": "Limites de gastos" + }, "srpInputNumberOfWords": { "message": "Eu tenho uma frase com $1 palavras", "description": "This is the text for each option in the dropdown where a user selects how many words their secret recovery phrase has during import. The $1 is the number of words (either 12, 15, 18, 21, or 24)." }, + "srpListName": { + "message": "Frase de Recuperação Secreta $1", + "description": "$1 is the order of the Secret Recovery Phrase" + }, + "srpListNumberOfAccounts": { + "message": "$1 contas", + "description": "$1 is the number of accounts in the list" + }, + "srpListSelectionDescription": { + "message": "A Frase de Recuperação Secreta de sua nova conta serĆ” gerada a partir de" + }, + "srpListSingleOrZero": { + "message": "$1 conta", + "description": "$1 is the number of accounts in the list, it is either 1 or 0" + }, "srpPasteFailedTooManyWords": { "message": "Ocorreu uma falha ao colar porque hĆ” mais de 24 palavras. A Frase de Recuperação Secreta pode ter no mĆ”ximo 24 palavras.", "description": "Description of SRP paste error when the pasted content has too many words" @@ -5158,6 +5478,9 @@ "message": "MudanƧas repentinas no mercado podem causar falhas. Se o problema persistir, entre em contato com $1.", "description": "This message is shown to a user if their swap fails. The $1 will be replaced by support.metamask.io" }, + "stxOptInSupportedNetworksDescription": { + "message": "Ative as transaƧƵes inteligentes para realizar transaƧƵes mais confiĆ”veis ​​e seguras em redes suportadas. $1" + }, "stxPendingPrivatelySubmittingSwap": { "message": "Enviando sua troca de forma privada..." }, @@ -5977,6 +6300,12 @@ "message": "O envio de tokens NFT (ERC-721) nĆ£o Ć© suportado no momento", "description": "This is an error message we show the user if they attempt to send an NFT asset type, for which currently don't support sending" }, + "unstableTokenPriceDescription": { + "message": "O preƧo desse token em USD Ć© altamente volĆ”til, indicando alto risco de perder valor significativo em caso de interação com ele." + }, + "unstableTokenPriceTitle": { + "message": "PreƧo de token instĆ”vel" + }, "upArrow": { "message": "seta para cima" }, @@ -6099,6 +6428,18 @@ "visitSite": { "message": "Visitar site" }, + "visitSupportDataConsentModalAccept": { + "message": "Confirmar" + }, + "visitSupportDataConsentModalDescription": { + "message": "Deseja compartilhar seu identificador e versĆ£o do aplicativo MetaMask com a nossa Central de Suporte? Isso pode nos ajudar a resolver melhor o seu problema, mas Ć© opcional." + }, + "visitSupportDataConsentModalReject": { + "message": "NĆ£o compartilhar" + }, + "visitSupportDataConsentModalTitle": { + "message": "Compartilhar detalhes do dispositivo com o suporte" + }, "visitWebSite": { "message": "Visite nosso site" }, diff --git a/app/_locales/pt_BR/messages.json b/app/_locales/pt_BR/messages.json index 9d781a0ec4ab..8edd9c8358b1 100644 --- a/app/_locales/pt_BR/messages.json +++ b/app/_locales/pt_BR/messages.json @@ -1626,13 +1626,6 @@ "showHexDataDescription": { "message": "Selecione essa opção para mostrar o campo de dados hexadecimais na tela de envio" }, - "showIncomingTransactions": { - "message": "Mostrar transaƧƵes recebidas" - }, - "showIncomingTransactionsDescription": { - "message": "Selecione essa opção para usar o Etherscan e mostrar as transaƧƵes recebidas na lista de transaƧƵes", - "description": "$1 is the link to etherscan url and $2 is the link to the privacy policy of consensys APIs" - }, "showPermissions": { "message": "Mostrar permissƵes" }, diff --git a/app/_locales/ru/messages.json b/app/_locales/ru/messages.json index d8259f9b1c73..e98b1b4b66e0 100644 --- a/app/_locales/ru/messages.json +++ b/app/_locales/ru/messages.json @@ -44,6 +44,20 @@ "QRHardwareWalletSteps2Description": { "message": "Ngrave Zero" }, + "SrpListHideAccounts": { + "message": "Š”ŠŗŃ€Ń‹Ń‚ŃŒ $1 счета(-ов)", + "description": "$1 is the number of accounts" + }, + "SrpListHideSingleAccount": { + "message": "Š”ŠŗŃ€Ń‹Ń‚ŃŒ 1 счет" + }, + "SrpListShowAccounts": { + "message": "ŠŸŠ¾ŠŗŠ°Š·Š°Ń‚ŃŒ $1 счета(-ов)", + "description": "$1 is the number of accounts" + }, + "SrpListShowSingleAccount": { + "message": "ŠŸŠ¾ŠŗŠ°Š·Š°Ń‚ŃŒ 1 счет" + }, "about": { "message": "Šž MetaMask" }, @@ -76,6 +90,9 @@ "accountDetails": { "message": "Реквизиты счета" }, + "accountDetailsRevokeDelegationButton": { + "message": " ŠŸŠµŃ€ŠµŠŗŠ»ŃŽŃ‡ŠøŃ‚ŃŒŃŃ назаГ на обычный счет" + }, "accountIdenticon": { "message": "Š˜Š“ŠµŠ½Ń‚ŠøŠŗŠ¾Š½ счета" }, @@ -153,6 +170,12 @@ "addAlias": { "message": "Š”Š¾Š±Š°Š²ŠøŃ‚ŃŒ псевГоним" }, + "addBitcoinAccountLabel": { + "message": "Дчет Биткойн (бета-Š²ŠµŃ€ŃŠøŃ)" + }, + "addBitcoinTestnetAccountLabel": { + "message": "Дчет Биткойн (тестнет)" + }, "addBlockExplorer": { "message": "Š”Š¾Š±Š°Š²ŠøŃ‚ŃŒ Š¾Š±Š¾Š·Ń€ŠµŠ²Š°Ń‚ŠµŠ»ŃŒ блоков" }, @@ -193,6 +216,9 @@ "addFriendsAndAddresses": { "message": "Š”Š¾Š±Š°Š²ŃŒŃ‚Šµ Š“Ń€ŃƒŠ·ŠµŠ¹ Šø аГреса, которым Š“Š¾Š²ŠµŃ€ŃŠµŃ‚Šµ" }, + "addHardwareWalletLabel": { + "message": "Аппаратный кошелек" + }, "addIPFSGateway": { "message": "Š”Š¾Š±Š°Š²ŃŒŃ‚Šµ ŠæŃ€ŠµŠ“ŠæŠ¾Ń‡Ń‚ŠøŃ‚ŠµŠ»ŃŒŠ½Ń‹Š¹ ŃˆŠ»ŃŽŠ· IPFS" }, @@ -212,12 +238,26 @@ "addNewAccount": { "message": "Š”Š¾Š±Š°Š²ŠøŃ‚ŃŒ новый счет Ethereum" }, + "addNewEthereumAccountLabel": { + "message": "Дчет Ethereum" + }, + "addNewSolanaAccountLabel": { + "message": "Дчет Solana" + }, "addNft": { "message": "Š”Š¾Š±Š°Š²ŠøŃ‚ŃŒ NFT" }, "addNfts": { "message": "Š”Š¾Š±Š°Š²ŠøŃ‚ŃŒ NFT" }, + "addNonEvmAccount": { + "message": "Š”Š¾Š±Š°Š²ŠøŃ‚ŃŒ $1 счет", + "description": "$1 is the non EVM network where the account is going to be created, e.g. Bitcoin or Solana" + }, + "addNonEvmAccountFromNetworkPicker": { + "message": "Чтобы Š°ŠŗŃ‚ŠøŠ²ŠøŃ€Š¾Š²Š°Ń‚ŃŒ ŃŠµŃ‚ŃŒ $1, нужно ŃŠ¾Š·Š“Š°Ń‚ŃŒ счет $2.", + "description": "$1 is the non EVM network where the account is going to be created, e.g. Solana Mainnet or Solana Devnet. $2 is the account type, e.g. Bitcoin or Solana" + }, "addRpcUrl": { "message": "Š”Š¾Š±Š°Š²ŠøŃ‚ŃŒ URL-аГрес RPC" }, @@ -300,14 +340,16 @@ "advancedPriorityFeeToolTip": { "message": "ŠŸŠ»Š°Ń‚Š° за приоритет (также ŠøŠ·Š²ŠµŃŃ‚Š½Š°Ń как «чаевые» Š¼Š°Š¹Š½ŠµŃ€Ńƒ) Š½Š°ŠæŃ€Š°Š²Š»ŃŠµŃ‚ŃŃ непосреГственно майнерам, чтобы они уГелили приоритетное внимание вашей транзакции." }, - "aggregatedBalancePopover": { - "message": "Это значение отражает ŃŃ‚Š¾ŠøŠ¼Š¾ŃŃ‚ŃŒ всех токенов, которыми вы влаГеете в Ганной сети. Если вы преГпочитаете Š²ŠøŠ“ŠµŃ‚ŃŒ ŃŃ‚Š¾ значение в ETH или Š“Ń€ŃƒŠ³ŠøŃ… Š²Š°Š»ŃŽŃ‚Š°Ń…, перейГите Šŗ $1.", - "description": "$1 represents the settings page" - }, "agreeTermsOfUse": { "message": "ŠÆ ŃŠ¾Š³Š»Š°ŃˆŠ°ŃŽŃŃŒ с $1 MetaMask", "description": "$1 is the `terms` link" }, + "airDropPatternDescription": { + "message": "Š’ истории токена в блокчейне уже были ŃŠ»ŃƒŃ‡Š°Šø ŠæŠ¾Š“Š¾Š·Ń€ŠøŃ‚ŠµŠ»ŃŒŠ½Ń‹Ń… аирГропов." + }, + "airDropPatternTitle": { + "message": "Дхема Гействий при аирГропе" + }, "airgapVault": { "message": "AirGap Vault" }, @@ -726,9 +768,21 @@ "bridgeConfirmTwoTransactions": { "message": "Вам нужно Š±ŃƒŠ“ет ŠæŠ¾Š“Ń‚Š²ŠµŃ€Š“ŠøŃ‚ŃŒ 2 транзакции в Š’Š°ŃˆŠµŠ¼ аппаратном кошельке:" }, + "bridgeCreateSolanaAccount": { + "message": "Š”Š¾Š·Š“Š°Ń‚ŃŒ счет Solana" + }, + "bridgeCreateSolanaAccountDescription": { + "message": "Š”Š»Ń Š²Ń‹ŠæŠ¾Š»Š½ŠµŠ½ŠøŃ свопа в ŃŠµŃ‚ŃŒ Solana ŠæŠ¾Š½Š°Š“Š¾Š±ŠøŃ‚ŃŃ счет Šø ŠæŃ€ŠøŠ½ŠøŠ¼Š°ŃŽŃ‰ŠøŠ¹ аГрес." + }, + "bridgeCreateSolanaAccountTitle": { + "message": "Дначала вам ŠæŠ¾Š½Š°Š“Š¾Š±ŠøŃ‚ŃŃ счет Solana." + }, "bridgeEnterAmount": { "message": "ВвеГите сумму" }, + "bridgeEnterAmountAndSelectAccount": { + "message": "ВвеГите сумму Šø выберите целевой счет" + }, "bridgeExplorerLinkViewOn": { "message": "Š”Š¼Š¾Ń‚Ń€ŠµŃ‚ŃŒ на $1" }, @@ -751,9 +805,15 @@ "bridgeQuoteExpired": { "message": "Дрок Š“ŠµŠ¹ŃŃ‚Š²ŠøŃ Š’Š°ŃˆŠµŠ¹ котировки истек." }, + "bridgeSelectDestinationAccount": { + "message": "Выберите целевой счет" + }, "bridgeSelectNetwork": { "message": "Выбор сети" }, + "bridgeSelectTokenAmountAndAccount": { + "message": "Выберите токен, сумму Šø целевой счет" + }, "bridgeSelectTokenAndAmount": { "message": "Выберите токен Šø сумму" }, @@ -944,6 +1004,12 @@ "message": "Вариантов не найГено", "description": "Default text shown in the combo field dropdown if no options." }, + "concentratedSupplyDistributionDescription": { + "message": "Š‘Š¾Š»ŃŒŃˆŠ°Ń Ń‡Š°ŃŃ‚ŃŒ запаса токенов принаГлежит ŠøŃ… ŠŗŃ€ŃƒŠæŠ½ŠµŠ¹ŃˆŠøŠ¼ Š“ŠµŃ€Š¶Š°Ń‚ŠµŠ»ŃŠ¼, что созГает риск централизованного Š¼Š°Š½ŠøŠæŃƒŠ»ŠøŃ€Š¾Š²Š°Š½ŠøŃ ценой" + }, + "concentratedSupplyDistributionTitle": { + "message": "ŠšŠ¾Š½Ń†ŠµŠ½Ń‚Ń€ŠøŃ€Š¾Š²Š°Š½Š½Š¾Šµ распреГеление запаса" + }, "configureSnapPopupDescription": { "message": "Š¢ŠµŠæŠµŃ€ŃŒ вы покиГаете MetaMask, чтобы Š½Š°ŃŃ‚Ń€Š¾ŠøŃ‚ŃŒ ŃŃ‚Š¾Ń‚ snap." }, @@ -962,6 +1028,15 @@ "confirm": { "message": "ŠŸŠ¾Š“Ń‚Š²ŠµŃ€Š“ŠøŃ‚ŃŒ" }, + "confirmAccountType": { + "message": "Тип" + }, + "confirmAccountTypeSmartContract": { + "message": "Дмарт-счет" + }, + "confirmAccountTypeStandard": { + "message": "ДтанГартный счет" + }, "confirmAlertModalAcknowledgeMultiple": { "message": "ŠÆ поГтверГил(-а) ŠæŠ¾Š»ŃƒŃ‡ŠµŠ½ŠøŠµ оповещений Šø все еще Ń…Š¾Ń‡Ńƒ ŠæŃ€Š¾Š“Š¾Š»Š¶ŠøŃ‚ŃŒ" }, @@ -974,12 +1049,36 @@ "confirmFieldTooltipPaymaster": { "message": "ŠšŠ¾Š¼ŠøŃŃŠøŃ за эту Ń‚Ń€Š°Š½Š·Š°ŠŗŃ†ŠøŃŽ Š±ŃƒŠ“ŠµŃ‚ оплачена смарт-контрактом paymaster." }, + "confirmGasFeeTokenBalance": { + "message": "Баланс:" + }, + "confirmGasFeeTokenInsufficientBalance": { + "message": "ŠŠµŠ“Š¾ŃŃ‚Š°Ń‚Š¾Ń‡Š½Š¾ среГств" + }, + "confirmGasFeeTokenMetaMaskFee": { + "message": "Š’ŠŗŠ»ŃŽŃ‡Š°ŠµŃ‚ ŠŗŠ¾Š¼ŠøŃŃŠøŃŽ $1" + }, + "confirmGasFeeTokenModalTitle": { + "message": "Š’Ń‹Š±Ń€Š°Ń‚ŃŒ токен" + }, + "confirmGasFeeTokenToast": { + "message": "Š’Ń‹ оплачиваете эту ŃŠµŃ‚ŠµŠ²ŃƒŃŽ ŠŗŠ¾Š¼ŠøŃŃŠøŃŽ с ŠæŠ¾Š¼Š¾Ń‰ŃŒŃŽ $1" + }, + "confirmGasFeeTokenTooltip": { + "message": "Эта сумма Š²Ń‹ŠæŠ»Š°Ń‡ŠøŠ²Š°ŠµŃ‚ся сети за Š¾Š±Ń€Š°Š±Š¾Ń‚ŠŗŃƒ вашей транзакции. Š’ŠŗŠ»ŃŽŃ‡Š°ŠµŃ‚ ŠŗŠ¾Š¼ŠøŃŃŠøŃŽ MetaMask в размере $1 за токены, не Š¾Ń‚Š½Š¾ŃŃŃ‰ŠøŠµŃŃ Šŗ ETH." + }, + "confirmNestedTransactionTitle": { + "message": "Š¢Ń€Š°Š½Š·Š°ŠŗŃ†ŠøŃ $1" + }, "confirmPassword": { "message": "ŠŸŠ¾Š“Ń‚Š²ŠµŃ€Š“ŠøŃ‚ŃŒ ŠæŠ°Ń€Š¾Š»ŃŒ" }, "confirmRecoveryPhrase": { "message": "ŠŸŠ¾Š“Ń‚Š²ŠµŃ€Š“ŠøŃ‚Šµ ŃŠµŠŗŃ€ŠµŃ‚Š½ŃƒŃŽ Ń„Ń€Š°Š·Ńƒ Š“Š»Ń Š²Š¾ŃŃŃ‚Š°Š½Š¾Š²Š»ŠµŠ½ŠøŃ" }, + "confirmSimulationApprove": { + "message": "Š’Ń‹ Š¾Š“Š¾Š±Ń€ŃŠµŃ‚Šµ" + }, "confirmTitleApproveTransactionNFT": { "message": "Запрос на вывоГ среГств" }, @@ -1022,9 +1121,24 @@ "confirmTitleTransaction": { "message": "Запрос транзакции" }, + "confirmUpgradeCancelModalButtonCancelTransaction": { + "message": "ŠžŃ‚Š¼ŠµŠ½ŠøŃ‚ŃŒ Ń‚Ń€Š°Š½Š·Š°ŠŗŃ†ŠøŃŽ" + }, + "confirmUpgradeCancelModalButtonCancelUpgrade": { + "message": "ŠžŃ‚Š¼ŠµŠ½ŠøŃ‚ŃŒ обновление Šø Ń‚Ń€Š°Š½Š·Š°ŠŗŃ†ŠøŃŽ" + }, + "confirmUpgradeCancelModalDescription": { + "message": "Если вы не хотите Š¾Š±Š½Š¾Š²Š»ŃŃ‚ŃŒ свой счет, вы можете Š°Š½Š½ŃƒŠ»ŠøŃ€Š¾Š²Š°Ń‚ŃŒ его зГесь.\n\nЧтобы Š·Š°Š²ŠµŃ€ŃˆŠøŃ‚ŃŒ эту Ń‚Ń€Š°Š½Š·Š°ŠŗŃ†ŠøŃŽ без Š¾Š±Š½Š¾Š²Š»ŠµŠ½ŠøŃ, необхоГимо Š±ŃƒŠ“ет снова ŃŠ“ŠµŠ»Š°Ń‚ŃŒ ŃŃ‚Š¾Ń‚ запрос на сайте. $1." + }, + "confirmUpgradeCancelModalTitle": { + "message": "ŠžŃ‚Š¼ŠµŠ½ŠøŃ‚ŃŒ Ń‚Ń€Š°Š½Š·Š°ŠŗŃ†ŠøŃŽ" + }, "confirmationAlertDetails": { "message": "Чтобы Š·Š°Ń‰ŠøŃ‚ŠøŃ‚ŃŒ свои активы, Ń€ŠµŠŗŠ¾Š¼ŠµŠ½Š“ŃƒŠµŠ¼ Š¾Ń‚ŠŗŠ»Š¾Š½ŠøŃ‚ŃŒ запрос." }, + "confirmationAlertModalTitleDescription": { + "message": "Š’Š°ŃˆŠø активы Š¼Š¾Š³ŃƒŃ‚ Š±Ń‹Ń‚ŃŒ в опасности" + }, "confirmed": { "message": "ŠŸŠ¾Š“Ń‚Š²ŠµŃ€Š¶Š“ŠµŠ½(-а/о)" }, @@ -1052,6 +1166,9 @@ "connectAccounts": { "message": "ŠŸŠ¾Š“ŠŗŠ»ŃŽŃ‡ŠøŃ‚ŃŒ счета" }, + "connectAnAccountHeader": { + "message": "ŠŸŠ¾Š“ŠŗŠ»ŃŽŃ‡ŠøŃ‚ŃŒ счет" + }, "connectManually": { "message": "ŠŸŠ¾Š“ŠŗŠ»ŃŽŃ‡ŠøŃ‚ŃŒŃŃ Šŗ Ń‚ŠµŠŗŃƒŃ‰ŠµŠ¼Ńƒ ŃŠ°Š¹Ń‚Ńƒ Š²Ń€ŃƒŃ‡Š½ŃƒŃŽ" }, @@ -1158,6 +1275,9 @@ "message": "ŠŠµ уГалось ŠæŠ¾Š»ŃƒŃ‡ŠøŃ‚ŃŒ $1, ŠæŃ€Š¾Š²ŠµŃ€ŃŒŃ‚Šµ ŃŠ²Š¾ŃŽ ŃŠµŃ‚ŃŒ Šø повторите ŠæŠ¾ŠæŃ‹Ń‚ŠŗŃƒ.", "description": "$1 is the name of the snap being fetched." }, + "connectionPopoverDescription": { + "message": "Š”Š»Ń ŠæŠ¾Š“ŠŗŠ»ŃŽŃ‡ŠµŠ½ŠøŃ Šŗ ŃŠ°Š¹Ń‚Ńƒ нажмите кнопку ŠæŠ¾Š“ŠŗŠ»ŃŽŃ‡ŠµŠ½ŠøŃ. MetaMask может ŠæŠ¾Š“ŠŗŠ»ŃŽŃ‡Š°Ń‚ŃŒŃŃ Ń‚Š¾Š»ŃŒŠŗŠ¾ Šŗ сайтам web3." + }, "connectionRequest": { "message": "Запрос ŠæŠ¾Š“ŠŗŠ»ŃŽŃ‡ŠµŠ½ŠøŃ" }, @@ -1219,6 +1339,9 @@ "create": { "message": "Š”Š¾Š·Š“Š°Ń‚ŃŒ" }, + "createNewAccountHeader": { + "message": "Š”Š¾Š·Š“Š°Ń‚ŃŒ новый счет" + }, "createNewWallet": { "message": "Š”Š¾Š·Š“Š°Ń‚ŃŒ новый кошелек" }, @@ -1231,6 +1354,9 @@ "createSnapAccountTitle": { "message": "Š”Š¾Š·Š“Š°Ń‚ŃŒ счет" }, + "createSolanaAccount": { + "message": "Š”Š¾Š·Š“Š°Ń‚ŃŒ счет Solana" + }, "creatorAddress": { "message": "АГрес автора" }, @@ -1471,6 +1597,21 @@ "message": "ŠžŠæŠøŃŠ°Š½ŠøŠµ ŠøŠ· $1", "description": "$1 represents the name of the snap" }, + "destinationAccountPickerNoEligible": { + "message": "Š£Š“Š¾Š²Š»ŠµŃ‚Š²Š¾Ń€ŃŃŽŃ‰ŠøŠµ Ń‚Ń€ŠµŠ±Š¾Š²Š°Š½ŠøŃŠ¼ счета не найГены" + }, + "destinationAccountPickerNoMatching": { + "message": "ŠŸŠ¾Š“Ń…Š¾Š“ŃŃ‰ŠøŠµ счета не найГены" + }, + "destinationAccountPickerReceiveAt": { + "message": "ŠŸŠ¾Š»ŃƒŃ‡ŠøŃ‚ŃŒ в" + }, + "destinationAccountPickerSearchPlaceholderToMainnet": { + "message": "АГрес ŠæŠ¾Š»ŃƒŃ‡ŠµŠ½ŠøŃ или ENS" + }, + "destinationAccountPickerSearchPlaceholderToSolana": { + "message": "АГрес ŠæŠ¾Š»ŃƒŃ‡ŠµŠ½ŠøŃ" + }, "details": { "message": "ŠŸŠ¾Š“Ń€Š¾Š±Š½Š¾ŃŃ‚Šø" }, @@ -1516,6 +1657,9 @@ "message": "$1 Š¾Ń‚ŠŗŠ»ŃŽŃ‡ŠµŠ½ от $2", "description": "$1 is name of the name and $2 represents the dapp name`" }, + "discover": { + "message": "ŠžŠ±Š·Š¾Ń€" + }, "discoverSnaps": { "message": "ŠžŃ‚ŠŗŃ€Š¾Š¹Ń‚Šµ Š“Š»Ń ŃŠµŠ±Ń Snaps", "description": "Text that links to the Snaps website. Displayed in a banner on Snaps list page in settings." @@ -1867,11 +2011,14 @@ "message": "Чтобы ŠæŃ€Š¾ŃŠ¼Š¾Ń‚Ń€ŠµŃ‚ŃŒ Šø ŠæŠ¾Š“Ń‚Š²ŠµŃ€Š“ŠøŃ‚ŃŒ свой послеГний запрос, вам необхоГимо сначала ŃƒŃ‚Š²ŠµŃ€Š“ŠøŃ‚ŃŒ или Š¾Ń‚ŠŗŠ»Š¾Š½ŠøŃ‚ŃŒ ŃŃƒŃ‰ŠµŃŃ‚Š²ŃƒŃŽŃ‰ŠøŠµ запросы." }, "expandView": { - "message": "Š Š°Š·Š²ŠµŃ€Š½ŃƒŃ‚ŃŒ преГставление" + "message": "ŠžŃ‚ŠŗŃ€Ń‹Ń‚ŃŒ в новой вклаГке" }, "experimental": { "message": "Š­ŠŗŃŠæŠµŃ€ŠøŠ¼ŠµŠ½Ń‚Š°Š»ŃŒŠ½Ń‹Šµ" }, + "exploreweb3": { + "message": "Š˜ŃŃŠ»ŠµŠ“ŃƒŠ¹Ń‚Šµ web3" + }, "exportYourData": { "message": "Š­ŠŗŃŠæŠ¾Ń€Ń‚ŠøŃ€ŃƒŠ¹Ń‚Šµ свои Ганные" }, @@ -1885,6 +2032,9 @@ "message": "Š˜Š·ŃƒŃ‡ŠøŃ‚Šµ Snaps, созГанные сообществом, чтобы ŠæŠµŃ€ŃŠ¾Š½Š°Š»ŠøŠ·ŠøŃ€Š¾Š²Š°Ń‚ŃŒ Ń€Š°Š±Š¾Ń‚Ńƒ с web3", "description": "Banner description displayed on Snaps list page in Settings when less than 6 Snaps is installed." }, + "externalAccount": { + "message": "Š’Š½ŠµŃˆŠ½ŠøŠ¹ счет" + }, "externalExtension": { "message": "Š’Š½ŠµŃˆŠ½ŠµŠµ Ń€Š°ŃŃˆŠøŃ€ŠµŠ½ŠøŠµ" }, @@ -2197,6 +2347,12 @@ "holdToRevealUnlockedLabel": { "message": "ŃƒŠ“ŠµŃ€Š¶ŠøŠ²Š°Š¹Ń‚Šµ, чтобы ŠæŠ¾ŠŗŠ°Š·Š°Ń‚ŃŒ разблокированный ŠŗŃ€ŃƒŠ³" }, + "honeypotDescription": { + "message": "Этот токен может Š±Ń‹Ń‚ŃŒ ловушкой. Š ŠµŠŗŠ¾Š¼ŠµŠ½Š“ŃƒŠµŃ‚ŃŃ провести ŠŗŠ¾Š¼ŠæŠ»ŠµŠŗŃŠ½ŃƒŃŽ ŠæŃ€Š¾Š²ŠµŃ€ŠŗŃƒ переГ началом Š²Š·Š°ŠøŠ¼Š¾Š“ŠµŠ¹ŃŃ‚Š²ŠøŃ, чтобы ŠæŃ€ŠµŠ“Š¾Ń‚Š²Ń€Š°Ń‚ŠøŃ‚ŃŒ возможные финансовые потери." + }, + "honeypotTitle": { + "message": "Š›Š¾Š²ŃƒŃˆŠŗŠ°" + }, "howNetworkFeesWorkExplanation": { "message": "Š Š°ŃŃ‡ŠµŃ‚Š½Š°Ń ŠŗŠ¾Š¼ŠøŃŃŠøŃ, Š½ŠµŠ¾Š±Ń…Š¾Š“ŠøŠ¼Š°Ń Š“Š»Ń обработки транзакции. ŠœŠ°ŠŗŃŠøŠ¼Š°Š»ŃŒŠ½Š°Ń ŠŗŠ¾Š¼ŠøŃŃŠøŃ ŃŠ¾ŃŃ‚Š°Š²Š»ŃŠµŃ‚ $1." }, @@ -2262,6 +2418,30 @@ "importNFTTokenIdToolTip": { "message": "ID NFT ŃŠ²Š»ŃŠµŃ‚ŃŃ ŃƒŠ½ŠøŠŗŠ°Š»ŃŒŠ½Ń‹Š¼ иГентификатором, поскольку нет Š“Š²ŃƒŃ… оГинаковых NFT. ŠžŠæŃŃ‚ŃŒ же, в OpenSea ŃŃ‚Š¾Ń‚ номер Š½Š°Ń…Š¾Š“ŠøŃ‚ŃŃ в разГеле Ā«ŠŸŠ¾Š“Ń€Š¾Š±Š½Š¾ŃŃ‚ŠøĀ». Š—Š°ŠæŠøŃˆŠøŃ‚Šµ его или ŃŠŗŠ¾ŠæŠøŃ€ŃƒŠ¹Ń‚Šµ в Š±ŃƒŃ„ер обмена." }, + "importNWordSRP": { + "message": "Š£ Š¼ŠµŠ½Ń ŠµŃŃ‚ŃŒ фраза Š“Š»Ń Š²Š¾ŃŃŃ‚Š°Š½Š¾Š²Š»ŠµŠ½ŠøŃ ŠøŠ· $1 слов", + "description": "$1 is the number of words in the recovery phrase" + }, + "importPrivateKey": { + "message": "Закрытый ŠŗŠ»ŃŽŃ‡" + }, + "importSRPDescription": { + "message": "Š˜Š¼ŠæŠ¾Ń€Ń‚ŠøŃ€ŃƒŠ¹Ń‚Šµ ŃŃƒŃ‰ŠµŃŃ‚Š²ŃƒŃŽŃ‰ŠøŠ¹ кошелек с ŠæŠ¾Š¼Š¾Ń‰ŃŒŃŽ секретной фразы Š“Š»Ń Š²Š¾ŃŃŃ‚Š°Š½Š¾Š²Š»ŠµŠ½ŠøŃ ŠøŠ· 12 или 24 слов." + }, + "importSRPNumberOfWordsError": { + "message": "Декретные фразы Š“Š»Ń Š²Š¾ŃŃŃ‚Š°Š½Š¾Š²Š»ŠµŠ½ŠøŃ соГержат 12 слов или 24 слова" + }, + "importSRPWordError": { + "message": "Длово $1 неверное или соГержит орфографические ошибки.", + "description": "$1 is the word that is incorrect or misspelled" + }, + "importSRPWordErrorAlternative": { + "message": "Длова $1 Šø $2 неверные или соГержат орфографические ошибки.", + "description": "$1 and $2 are multiple words that are mispelled." + }, + "importSecretRecoveryPhrase": { + "message": "Š˜Š¼ŠæŠ¾Ń€Ń‚ŠøŃ€Š¾Š²Š°Ń‚ŃŒ ŃŠµŠŗŃ€ŠµŃ‚Š½ŃƒŃŽ Ń„Ń€Š°Š·Ńƒ Š“Š»Ń Š²Š¾ŃŃŃ‚Š°Š½Š¾Š²Š»ŠµŠ½ŠøŃ" + }, "importSelectedTokens": { "message": "Š˜Š¼ŠæŠ¾Ń€Ń‚ŠøŃ€Š¾Š²Š°Ń‚ŃŒ выбранные токены?" }, @@ -2280,6 +2460,12 @@ "importTokensError": { "message": "ŠŠ°Š¼ не уГалось ŠøŠ¼ŠæŠ¾Ń€Ń‚ŠøŃ€Š¾Š²Š°Ń‚ŃŒ токены. ŠŸŠ¾Š²Ń‚Š¾Ń€ŠøŃ‚Šµ ŠæŠ¾ŠæŃ‹Ń‚ŠŗŃƒ позже." }, + "importWallet": { + "message": "Š˜Š¼ŠæŠ¾Ń€Ń‚ŠøŃ€Š¾Š²Š°Ń‚ŃŒ кошелек" + }, + "importWalletOrAccountHeader": { + "message": "Š˜Š¼ŠæŠ¾Ń€Ń‚ŠøŃ€Š¾Š²Š°Ń‚ŃŒ кошелек или счет" + }, "importWithCount": { "message": "Š˜Š¼ŠæŠ¾Ń€Ń‚ŠøŃ€Š¾Š²Š°Ń‚ŃŒ $1", "description": "$1 will the number of detected tokens that are selected for importing, if all of them are selected then $1 will be all" @@ -2327,6 +2513,12 @@ "insufficientFundsForGas": { "message": "ŠŠµŠ“Š¾ŃŃ‚Š°Ń‚Š¾Ń‡Š½Š¾ среГств Š“Š»Ń оплаты газа" }, + "insufficientLockedLiquidityDescription": { + "message": "ŠžŃ‚ŃŃƒŃ‚ŃŃ‚Š²ŠøŠµ аГекватно заблокированной или сожженной ликвиГности Гелает токен ŃƒŃŠ·Š²ŠøŠ¼Ń‹Š¼ Šŗ внезапному ŠøŠ·ŃŠŃŃ‚ŠøŃŽ ликвиГности, что может привести Šŗ Š½ŠµŃŃ‚Š°Š±ŠøŠ»ŃŒŠ½Š¾ŃŃ‚Šø рынка." + }, + "insufficientLockedLiquidityTitle": { + "message": "ŠŠµŠ“Š¾ŃŃ‚Š°Ń‚Š¾Ń‡Š½Š¾ заблокированной ликвиГности" + }, "insufficientTokens": { "message": "ŠŠµŠ“Š¾ŃŃ‚Š°Ń‚Š¾Ń‡Š½Š¾ токенов." }, @@ -2362,6 +2554,9 @@ "invalidCustomNetworkAlertTitle": { "message": "ŠŠµŠ“ŠµŠ¹ŃŃ‚Š²ŠøŃ‚ŠµŠ»ŃŒŠ½Š°Ń ŠæŠ¾Š»ŃŒŠ·Š¾Š²Š°Ń‚ŠµŠ»ŃŒŃŠŗŠ°Ń ŃŠµŃ‚ŃŒ" }, + "invalidHexData": { + "message": "ŠŠµŠ²ŠµŃ€Š½Ń‹Šµ ŃˆŠµŃŃ‚Š½Š°Š“Ń†Š°Ń‚ŠµŃ€ŠøŃ‡Š½Ń‹Šµ Ганные" + }, "invalidHexNumber": { "message": "ŠŠµŠ“ŠµŠ¹ŃŃ‚Š²ŠøŃ‚ŠµŠ»ŃŒŠ½Š¾Šµ ŃˆŠµŃŃ‚Š½Š°Š“Ń†Š°Ń‚ŠµŃ€ŠøŃ‡Š½Š¾Šµ число." }, @@ -2540,6 +2735,9 @@ "ledgerLocked": { "message": "ŠŠµ уГалось ŠæŠ¾Š“ŠŗŠ»ŃŽŃ‡ŠøŃ‚ŃŒŃŃ Šŗ Ledger. Š£Š±ŠµŠ“ŠøŃ‚ŠµŃŃŒ, что ŃƒŃŃ‚Ń€Š¾Š¹ŃŃ‚Š²Š¾ разблокировано Šø приложение Ethereum открыто." }, + "ledgerMultipleDevicesUnsupportedErrorMessage": { + "message": "ŠŠµŃŠŗŠ¾Š»ŃŒŠŗŠ¾ ŃƒŃŃ‚Ń€Š¾Š¹ŃŃ‚Š² Ledger Š½ŠµŠ»ŃŒŠ·Ń ŠæŠ¾Š“ŠŗŠ»ŃŽŃ‡ŠøŃ‚ŃŒ оГновременно. Š”Š»Ń ŠæŠ¾Š“ŠŗŠ»ŃŽŃ‡ŠµŠ½ŠøŃ нового ŃƒŃŃ‚Ń€Š¾Š¹ŃŃ‚Š²Š° Ledger сначала нужно Š¾Ń‚ŠŗŠ»ŃŽŃ‡ŠøŃ‚ŃŒ ŠæŃ€ŠµŠ“Ń‹Š“ŃƒŃ‰ŠµŠµ." + }, "ledgerTimeout": { "message": "Ledger Live слишком Голго не отвечает, или Š²Ń€ŠµŠ¼Ń Š¾Š¶ŠøŠ“Š°Š½ŠøŃ ŠæŠ¾Š“ŠŗŠ»ŃŽŃ‡ŠµŠ½ŠøŃ истекло. Š£Š±ŠµŠ“ŠøŃ‚ŠµŃŃŒ, что приложение Ledger Live открыто Šø ŃƒŃŃ‚Ń€Š¾Š¹ŃŃ‚Š²Š¾ разблокировано." }, @@ -2637,6 +2835,9 @@ "manageDefaultSettings": { "message": "Управление настройками ŠŗŠ¾Š½Ń„ŠøŠ“ŠµŠ½Ń†ŠøŠ°Š»ŃŒŠ½Š¾ŃŃ‚Šø по ŃƒŠ¼Š¾Š»Ń‡Š°Š½ŠøŃŽ" }, + "managePermissions": { + "message": "Управление Ń€Š°Š·Ń€ŠµŃˆŠµŠ½ŠøŃŠ¼Šø" + }, "marketCap": { "message": "Š Ń‹Š½Š¾Ń‡Š½Š°Ń ŠŗŠ°ŠæŠøŃ‚Š°Š»ŠøŠ·Š°Ń†ŠøŃ" }, @@ -2755,6 +2956,15 @@ "multichainAddEthereumChainConfirmationDescription": { "message": "Š’Ń‹ Š“Š¾Š±Š°Š²Š»ŃŠµŃ‚Šµ эту ŃŠµŃ‚ŃŒ в MetaMask Šø Ń€Š°Š·Ń€ŠµŃˆŠ°ŠµŃ‚Šµ ŃŃ‚Š¾Š¼Ńƒ ŃŠ°Š¹Ń‚Ńƒ ŠøŃŠæŠ¾Š»ŃŒŠ·Š¾Š²Š°Ń‚ŃŒ ее." }, + "multichainQuoteCardBridgingLabel": { + "message": "ДозГание моста" + }, + "multichainQuoteCardQuoteLabel": { + "message": "ŠšŠ¾Ń‚ŠøŃ€Š¾Š²ŠŗŠ°" + }, + "multichainQuoteCardTimeLabel": { + "message": "Š’Ń€ŠµŠ¼Ń" + }, "multipleSnapConnectionWarning": { "message": "$1 хочет ŠøŃŠæŠ¾Š»ŃŒŠ·Š¾Š²Š°Ń‚ŃŒ $2 Snaps", "description": "$1 is the dapp and $2 is the number of snaps it wants to connect to." @@ -2869,6 +3079,13 @@ "network": { "message": "Š”ŠµŃ‚ŃŒ:" }, + "networkChanged": { + "message": "Š”ŠµŃ‚ŃŒ изменена" + }, + "networkChangedMessage": { + "message": "Дейчас вы Š²Ń‹ŠæŠ¾Š»Š½ŃŠµŃ‚Šµ транзакции на $1.", + "description": "$1 is the name of the network" + }, "networkDetails": { "message": "Š”Š²ŠµŠ“ŠµŠ½ŠøŃ о сети" }, @@ -3143,6 +3360,9 @@ "notEnoughGas": { "message": "ŠŠµŠ“Š¾ŃŃ‚Š°Ń‚Š¾Ń‡Š½Š¾ газа" }, + "notNow": { + "message": "ŠŠµ сейчас" + }, "notificationDetail": { "message": "ŠŸŠ¾Š“Ń€Š¾Š±Š½Š¾ŃŃ‚Šø" }, @@ -3505,6 +3725,13 @@ "origin": { "message": "Š˜ŃŃ‚Š¾Ń‡Š½ŠøŠŗ" }, + "originChanged": { + "message": "Дайт ŠøŠ·Š¼ŠµŠ½ŠøŠ»ŃŃ" + }, + "originChangedMessage": { + "message": "Дейчас вы рассматриваете запрос от $1.", + "description": "$1 is the name of the origin" + }, "osTheme": { "message": "Š”ŠøŃŃ‚ŠµŠ¼Š½Š°Ń" }, @@ -3559,6 +3786,14 @@ "pending": { "message": "ŠžŠ¶ŠøŠ“Š°ŃŽŃ‰ŠøŠ¹" }, + "pendingConfirmationAddNetworkAlertMessage": { + "message": "ŠžŠ±Š½Š¾Š²Š»ŠµŠ½ŠøŠµ сети привеГет Šŗ отмене $1 Š¾Š¶ŠøŠ“Š°ŃŽŃ‰ŠøŃ… транзакций, ŠæŠ¾ŃŃ‚ŃƒŠæŠøŠ²ŃˆŠøŃ… с ŃŃ‚Š¾Š³Š¾ сайта.", + "description": "Number of transactions." + }, + "pendingConfirmationSwitchNetworkAlertMessage": { + "message": "Дмена сети привеГет Šŗ отмене $1 Š¾Š¶ŠøŠ“Š°ŃŽŃ‰ŠøŃ… транзакций, ŠæŠ¾ŃŃ‚ŃƒŠæŠøŠ²ŃˆŠøŃ… с ŃŃ‚Š¾Š³Š¾ сайта.", + "description": "Number of transactions." + }, "pendingTransactionAlertMessage": { "message": "Эта Ń‚Ń€Š°Š½Š·Š°ŠŗŃ†ŠøŃ не пройГет, пока не Š·Š°Š²ŠµŃ€ŃˆŠøŃ‚ся ŠæŃ€ŠµŠ“Ń‹Š“ŃƒŃ‰Š°Ń Ń‚Ń€Š°Š½Š·Š°ŠŗŃ†ŠøŃ. $1", "description": "$1 represents the words 'how to cancel or speed up a transaction' in a hyperlink" @@ -3842,6 +4077,9 @@ "permitSimulationChange_receive": { "message": "Š’Ń‹ ŠæŠ¾Š»ŃƒŃ‡Š°ŠµŃ‚Šµ" }, + "permitSimulationChange_revoke2": { + "message": "ŠžŃ‚Š¾Š·Š²Š°Ń‚ŃŒ" + }, "permitSimulationChange_transfer": { "message": "Š’Ń‹ Š¾Ń‚ŠæŃ€Š°Š²Š»ŃŠµŃ‚Šµ" }, @@ -4237,6 +4475,9 @@ "reusedTokenNameWarning": { "message": "Š’ токене зГесь ŠøŃŠæŠ¾Š»ŃŒŠ·ŃƒŠµŃ‚ŃŃ символ Š“Ń€ŃƒŠ³Š¾Š³Š¾ токена, который вы отслеживаете. Это может Š·Š°ŠæŃƒŃ‚Š°Ń‚ŃŒ или ввести в заблужГение." }, + "revealSecretRecoveryPhrase": { + "message": "ŠŸŠ¾ŠŗŠ°Š·Š°Ń‚ŃŒ ŃŠµŠŗŃ€ŠµŃ‚Š½ŃƒŃŽ Ń„Ń€Š°Š·Ńƒ Š“Š»Ń Š²Š¾ŃŃŃ‚Š°Š½Š¾Š²Š»ŠµŠ½ŠøŃ" + }, "revealSeedWords": { "message": "ŠŸŠ¾ŠŗŠ°Š·Š°Ń‚ŃŒ ŃŠµŠŗŃ€ŠµŃ‚Š½ŃƒŃŽ Ń„Ń€Š°Š·Ńƒ Š“Š»Ń Š²Š¾ŃŃŃ‚Š°Š½Š¾Š²Š»ŠµŠ½ŠøŃ" }, @@ -4286,12 +4527,19 @@ "reviewAlerts": { "message": "ŠŸŃ€Š¾ŃŠ¼Š¾Ń‚Ń€ŠµŃ‚ŃŒ Š¾ŠæŠ¾Š²ŠµŃ‰ŠµŠ½ŠøŃ" }, + "reviewPendingTransactions": { + "message": "ŠŸŃ€Š¾Š²ŠµŃ€ŠøŃ‚ŃŒ Š¾Š¶ŠøŠ“Š°ŃŽŃ‰ŠøŠµ транзакции" + }, "reviewPermissions": { "message": "ŠŸŃ€Š¾Š²ŠµŃ€ŠøŃ‚ŃŒ Ń€Š°Š·Ń€ŠµŃˆŠµŠ½ŠøŃ" }, "revokePermission": { "message": "ŠžŃ‚Š¾Š·Š²Š°Ń‚ŃŒ Ń€Š°Š·Ń€ŠµŃˆŠµŠ½ŠøŠµ" }, + "revokePermissionTitle": { + "message": "Š£Š“Š°Š»ŠøŃ‚ŃŒ Ń€Š°Š·Ń€ŠµŃˆŠµŠ½ŠøŠµ Š“Š»Ń $1", + "description": "The token symbol that is being revoked" + }, "revokeSimulationDetailsDesc": { "message": "Š’Ń‹ ŃƒŠ“Š°Š»ŃŠµŃ‚Šµ Ń‡ŃŒŠµ-либо Ń€Š°Š·Ń€ŠµŃˆŠµŠ½ŠøŠµ на Ń‚Ń€Š°Ń‚Ńƒ токенов с вашего счета." }, @@ -4334,6 +4582,10 @@ "secretRecoveryPhrase": { "message": "Š”ŠµŠŗŃ€ŠµŃ‚Š½Š°Ń фраза Š“Š»Ń Š²Š¾ŃŃŃ‚Š°Š½Š¾Š²Š»ŠµŠ½ŠøŃ" }, + "secretRecoveryPhrasePlusNumber": { + "message": "Š”ŠµŠŗŃ€ŠµŃ‚Š½Š°Ń фраза Š“Š»Ń Š²Š¾ŃŃŃ‚Š°Š½Š¾Š²Š»ŠµŠ½ŠøŃ $1", + "description": "The $1 is the order of the Secret Recovery Phrase" + }, "secureWallet": { "message": "Безопасный кошелек" }, @@ -4424,6 +4676,9 @@ "select": { "message": "Š’Ń‹Š±Ń€Š°Ń‚ŃŒ" }, + "selectAccountToConnect": { + "message": "Выберите счет Š“Š»Ń ŠæŠ¾Š“ŠŗŠ»ŃŽŃ‡ŠµŠ½ŠøŃ" + }, "selectAccounts": { "message": "Выберите счета(-а) Š“Š»Ń ŠøŃŠæŠ¾Š»ŃŒŠ·Š¾Š²Š°Š½ŠøŃ на ŃŃ‚Š¾Š¼ сайте" }, @@ -4454,6 +4709,9 @@ "selectRpcUrl": { "message": "Выберите URL RPC" }, + "selectSecretRecoveryPhrase": { + "message": "Выберите ŃŠµŠŗŃ€ŠµŃ‚Š½ŃƒŃŽ Ń„Ń€Š°Š·Ńƒ Š“Š»Ń Š²Š¾ŃŃŃ‚Š°Š½Š¾Š²Š»ŠµŠ½ŠøŃ" + }, "selectType": { "message": "Š’Ń‹Š±Ń€Š°Ń‚ŃŒ тип" }, @@ -4565,16 +4823,6 @@ "showHexDataDescription": { "message": "Выберите эту Š¾ŠæŃ†ŠøŃŽ, чтобы Š¾Ń‚Š¾Š±Ń€Š°Š·ŠøŃ‚ŃŒ поле ŃˆŠµŃŃ‚Š½Š°Š“Ń†Š°Ń‚ŠµŃ€ŠøŃ‡Š½Ń‹Ń… Ганных на ŃŠŗŃ€Š°Š½Šµ отправки" }, - "showIncomingTransactions": { - "message": "ŠŸŠ¾ŠŗŠ°Š·Š°Ń‚ŃŒ Š²Ń…Š¾Š“ŃŃ‰ŠøŠµ транзакции" - }, - "showIncomingTransactionsDescription": { - "message": "Это ŠøŃŠæŠ¾Š»ŃŒŠ·ŃƒŠµŃ‚ $1, который Š±ŃƒŠ“ет ŠøŠ¼ŠµŃ‚ŃŒ Š“Š¾ŃŃ‚ŃƒŠæ Šŗ вашему Š°Š“Ń€ŠµŃŃƒ Ethereum Šø вашему IP-Š°Š“Ń€ŠµŃŃƒ. $2", - "description": "$1 is the link to etherscan url and $2 is the link to the privacy policy of consensys APIs" - }, - "showIncomingTransactionsExplainer": { - "message": "Это Š±Š°Š·ŠøŃ€ŃƒŠµŃ‚ся на различных сторонних API Š“Š»Ń кажГой сети, которые Ń€Š°ŃŠŗŃ€Ń‹Š²Š°ŃŽŃ‚ ваш аГрес Ethereum Šø ваш IP-аГрес." - }, "showLess": { "message": "ŠŸŠ¾ŠŗŠ°Š·Š°Ń‚ŃŒ меньше" }, @@ -4593,6 +4841,9 @@ "showPrivateKey": { "message": "ŠŸŠ¾ŠŗŠ°Š·Š°Ń‚ŃŒ закрытый ŠŗŠ»ŃŽŃ‡" }, + "showSRP": { + "message": "ŠŸŠ¾ŠŗŠ°Š·Š°Ń‚ŃŒ ŃŠµŠŗŃ€ŠµŃ‚Š½ŃƒŃŽ Ń„Ń€Š°Š·Ńƒ Š“Š»Ń Š²Š¾ŃŃŃ‚Š°Š½Š¾Š²Š»ŠµŠ½ŠøŃ" + }, "showTestnetNetworks": { "message": "ŠŸŠ¾ŠŗŠ°Š·Š°Ń‚ŃŒ тестовые сети" }, @@ -4714,12 +4965,24 @@ "slideCashOutTitle": { "message": "Вывести Геньги с ŠæŠ¾Š¼Š¾Ń‰ŃŒŃŽ MetaMask" }, + "slideDebitCardDescription": { + "message": "Š”Š¾ŃŃ‚ŃƒŠæŠ½Š° в некоторых регионах" + }, "slideDebitCardTitle": { "message": "Š”ŠµŠ±ŠµŃ‚Š¾Š²Š°Ń карта MetaMask" }, + "slideFundWalletDescription": { + "message": "Š”Š¾Š±Š°Š²ŃŒŃ‚Šµ или перевеГите токены, чтобы Š½Š°Ń‡Š°Ń‚ŃŒ" + }, "slideFundWalletTitle": { "message": "ŠŸŠ¾ŠæŠ¾Š»Š½ŠøŃ‚Šµ свой кошелек" }, + "slideSweepStakeDescription": { + "message": "Выполните минтинг NFT Šø ŠæŠ¾Š»ŃƒŃ‡ŠøŃ‚Šµ шанс Š²Ń‹ŠøŠ³Ń€Š°Ń‚ŃŒ" + }, + "slideSweepStakeTitle": { + "message": "ŠŸŃ€ŠøŠ¼ŠøŃ‚Šµ ŃƒŃ‡Š°ŃŃ‚ŠøŠµ в Ń€Š¾Š·Ń‹Š³Ń€Ń‹ŃˆŠµ USDC на $5000!" + }, "smartContracts": { "message": "Дмарт-контракты" }, @@ -4866,6 +5129,9 @@ "snapResultSuccessDescription": { "message": "$1 готово Šŗ ŠøŃŠæŠ¾Š»ŃŒŠ·Š¾Š²Š°Š½ŠøŃŽ" }, + "snapUIAssetSelectorTitle": { + "message": "Š’Ń‹Š±Ń€Š°Ń‚ŃŒ актив" + }, "snapUpdateAlertDescription": { "message": "ŠŸŠ¾Š»ŃƒŃ‡ŠøŃ‚Šµ ŠæŠ¾ŃŠ»ŠµŠ“Š½ŃŽŃŽ Š²ŠµŃ€ŃŠøŃŽ $1", "description": "Description used in Snap update alert banner when snap update is available. $1 is the Snap name." @@ -4925,6 +5191,27 @@ "message": "Š”Š²ŃŠ¶ŠøŃ‚ŠµŃŃŒ с авторами $1 Š“Š»Ń ŠæŠ¾Š»ŃƒŃ‡ŠµŠ½ŠøŃ Š“Š¾ŠæŠ¾Š»Š½ŠøŃ‚ŠµŠ»ŃŒŠ½Š¾Š¹ поГГержки.", "description": "This is shown when the insight snap throws an error. $1 is the snap name" }, + "solanaImportAccounts": { + "message": "Š˜Š¼ŠæŠ¾Ń€Ń‚ŠøŃ€Š¾Š²Š°Ń‚ŃŒ счета Solana" + }, + "solanaImportAccountsDescription": { + "message": "Š˜Š¼ŠæŠ¾Ń€Ń‚ŠøŃ€ŃƒŠ¹Ń‚Šµ ŃŠµŠŗŃ€ŠµŃ‚Š½ŃƒŃŽ Ń„Ń€Š°Š·Ńƒ Š“Š»Ń Š²Š¾ŃŃŃ‚Š°Š½Š¾Š²Š»ŠµŠ½ŠøŃ, чтобы перенести свой счет Solana ŠøŠ· Š“Ń€ŃƒŠ³Š¾Š³Š¾ кошелька." + }, + "solanaMoreFeaturesComingSoon": { + "message": "Дкоро ŠæŠ¾ŃŠ²ŃŃ‚ŃŃ Š“Ń€ŃƒŠ³ŠøŠµ Ń„ŃƒŠ½ŠŗŃ†ŠøŠø" + }, + "solanaMoreFeaturesComingSoonDescription": { + "message": "Дкоро ŠæŠ¾ŃŠ²ŃŃ‚ŃŃ dapps Solana, NFT, поГГержка аппаратного кошелька Šø многое Š“Ń€ŃƒŠ³Š¾Šµ." + }, + "solanaOnMetaMask": { + "message": "Solana в MetaMask" + }, + "solanaSendReceiveSwapTokens": { + "message": "ŠžŃ‚ŠæŃ€Š°Š²Š»ŃŠ¹Ń‚Šµ, ŠæŠ¾Š»ŃƒŃ‡Š°Š¹Ń‚Šµ Šø обменивайте токены" + }, + "solanaSendReceiveSwapTokensDescription": { + "message": "Š’Ń‹ŠæŠ¾Š»Š½ŃŠ¹Ń‚Šµ пеервоГы Šø ŃŠ¾Š²ŠµŃ€ŃˆŠ°Š¹Ń‚Šµ транзакции с ŠæŠ¾Š¼Š¾Ń‰ŃŒŃŽ токенов, таких как SOL, USDC Šø Š“Ń€ŃƒŠ³ŠøŠµ." + }, "someNetworks": { "message": "Дети $1" }, @@ -4951,6 +5238,21 @@ "source": { "message": "Š˜ŃŃ‚Š¾Ń‡Š½ŠøŠŗ" }, + "spamModalBlockedDescription": { + "message": "Этот сайт Š±ŃƒŠ“ŠµŃ‚ заблокирован на 1 Š¼ŠøŠ½ŃƒŃ‚Ńƒ." + }, + "spamModalBlockedTitle": { + "message": "Š’Ń‹ временно заблокировали ŃŃ‚Š¾Ń‚ сайт" + }, + "spamModalDescription": { + "message": "Если вы ŠæŠ¾Š»ŃƒŃ‡Š°ŠµŃ‚Šµ спам в виГе многочисленных запросов, вы можете временно Š·Š°Š±Š»Š¾ŠŗŠøŃ€Š¾Š²Š°Ń‚ŃŒ сайт." + }, + "spamModalTemporaryBlockButton": { + "message": "Временно Š·Š°Š±Š»Š¾ŠŗŠøŃ€Š¾Š²Š°Ń‚ŃŒ ŃŃ‚Š¾Ń‚ сайт" + }, + "spamModalTitle": { + "message": "ŠœŃ‹ заметили многочисленные запросы" + }, "speed": { "message": "Š”ŠŗŠ¾Ń€Š¾ŃŃ‚ŃŒ" }, @@ -5000,10 +5302,28 @@ "spendingCap": { "message": "Лимит расхоГов" }, + "spendingCaps": { + "message": "Лимиты расхоГов" + }, "srpInputNumberOfWords": { "message": "Š£ Š¼ŠµŠ½Ń ŠµŃŃ‚ŃŒ фраза ŠøŠ· $1 слов(-а)", "description": "This is the text for each option in the dropdown where a user selects how many words their secret recovery phrase has during import. The $1 is the number of words (either 12, 15, 18, 21, or 24)." }, + "srpListName": { + "message": "Š”ŠµŠŗŃ€ŠµŃ‚Š½Š°Ń фраза Š“Š»Ń Š²Š¾ŃŃŃ‚Š°Š½Š¾Š²Š»ŠµŠ½ŠøŃ $1", + "description": "$1 is the order of the Secret Recovery Phrase" + }, + "srpListNumberOfAccounts": { + "message": "$1 счета(-ов)", + "description": "$1 is the number of accounts in the list" + }, + "srpListSelectionDescription": { + "message": "Š”ŠµŠŗŃ€ŠµŃ‚Š½Š°Ń фраза Š“Š»Ń Š²Š¾ŃŃŃ‚Š°Š½Š¾Š²Š»ŠµŠ½ŠøŃ, на основе которой Š±ŃƒŠ“ет созГан ваш новый счет" + }, + "srpListSingleOrZero": { + "message": "$1 счет(-ов)", + "description": "$1 is the number of accounts in the list, it is either 1 or 0" + }, "srpPasteFailedTooManyWords": { "message": "ŠŠµ уГалось Š²ŃŃ‚Š°Š²ŠøŃ‚ŃŒ, так как он соГержит более 24 слов. Š”ŠµŠŗŃ€ŠµŃ‚Š½Š°Ń фраза Š“Š»Ń Š²Š¾ŃŃŃ‚Š°Š½Š¾Š²Š»ŠµŠ½ŠøŃ может ŃŠ¾Š“ŠµŃ€Š¶Š°Ń‚ŃŒ не более 24 слов.", "description": "Description of SRP paste error when the pasted content has too many words" @@ -5158,6 +5478,9 @@ "message": "Внезапные ŠøŠ·Š¼ŠµŠ½ŠµŠ½ŠøŃ на рынке Š¼Š¾Š³ŃƒŃ‚ привести Šŗ отказам. Если проблема не ŃƒŃŃ‚Ń€Š°Š½ŠµŠ½Š°, Š¾Š±Ń€Š°Ń‚ŠøŃ‚ŠµŃŃŒ по Š°Š“Ń€ŠµŃŃƒ $1.", "description": "This message is shown to a user if their swap fails. The $1 will be replaced by support.metamask.io" }, + "stxOptInSupportedNetworksDescription": { + "message": "Š’ŠŗŠ»ŃŽŃ‡ŠøŃ‚Šµ Ń„ŃƒŠ½ŠŗŃ†ŠøŃŽ «Дмарт-транзакции» Š“Š»Ń более наГежных Šø безопасных транзакций в поГГерживаемых ŃŠµŃ‚ŃŃ…. $1" + }, "stxPendingPrivatelySubmittingSwap": { "message": "ŠŸŃ€ŠøŠ²Š°Ń‚Š½Š°Ń отправка вашего свопа..." }, @@ -5977,6 +6300,12 @@ "message": "ŠžŃ‚ŠæŃ€Š°Š²ŠŗŠ° токенов NFT (ERC-721) сейчас не ŠæŠ¾Š“Š“ŠµŃ€Š¶ŠøŠ²Š°ŠµŃ‚ŃŃ", "description": "This is an error message we show the user if they attempt to send an NFT asset type, for which currently don't support sending" }, + "unstableTokenPriceDescription": { + "message": "Цена ŃŃ‚Š¾Š³Š¾ токена в Голларах ДША крайне Š½ŠµŃŃ‚Š°Š±ŠøŠ»ŃŒŠ½Š°, что ŃƒŠŗŠ°Š·Ń‹Š²Š°ŠµŃ‚ на высокий риск потери Š·Š½Š°Ń‡ŠøŃ‚ŠµŠ»ŃŒŠ½Š¾Š¹ стоимости при взаимоГействии с ним." + }, + "unstableTokenPriceTitle": { + "message": "ŠŠµŃŃ‚Š°Š±ŠøŠ»ŃŒŠ½Š°Ń цена токена" + }, "upArrow": { "message": "стрелка «вверх»" }, @@ -6099,6 +6428,18 @@ "visitSite": { "message": "ŠŸŠ¾ŃŠµŃ‚ŠøŃ‚ŃŒ сайт" }, + "visitSupportDataConsentModalAccept": { + "message": "ŠŸŠ¾Š“Ń‚Š²ŠµŃ€Š“ŠøŃ‚ŃŒ" + }, + "visitSupportDataConsentModalDescription": { + "message": "Єотите ŃŠ¾Š¾Š±Ń‰ŠøŃ‚ŃŒ свой иГентификатор MetaMask Šø Š²ŠµŃ€ŃŠøŃŽ ŠæŃ€ŠøŠ»Š¾Š¶ŠµŠ½ŠøŃ в наш Центр поГГержки? Возможно, ŃŃ‚Š¾ поможет нам Š»ŃƒŃ‡ŃˆŠµ Ń€ŠµŃˆŠøŃ‚ŃŒ вашу ŠæŃ€Š¾Š±Š»ŠµŠ¼Ńƒ, Ń…Š¾Ń‚Ń ŃŃ‚Š¾ не Š³Š°Ń€Š°Š½Ń‚ŠøŃ€ŃƒŠµŃ‚ŃŃ." + }, + "visitSupportDataConsentModalReject": { + "message": "ŠŠµ ŃŠ¾Š¾Š±Ń‰Š°Ń‚ŃŒ" + }, + "visitSupportDataConsentModalTitle": { + "message": "ŠŸŠµŃ€ŠµŠ“Š°Ń‚ŃŒ ŃŠ²ŠµŠ“ŠµŠ½ŠøŃ об ŃƒŃŃ‚Ń€Š¾Š¹ŃŃ‚Š²Šµ в службу поГГержки" + }, "visitWebSite": { "message": "ŠŸŠ¾ŃŠµŃ‚ŠøŃ‚Šµ наш веб-сайт" }, diff --git a/app/_locales/tl/messages.json b/app/_locales/tl/messages.json index 0285b2539f44..647ac406336c 100644 --- a/app/_locales/tl/messages.json +++ b/app/_locales/tl/messages.json @@ -44,6 +44,20 @@ "QRHardwareWalletSteps2Description": { "message": "Ngrave Zero" }, + "SrpListHideAccounts": { + "message": "Itago ang $1 (na) account", + "description": "$1 is the number of accounts" + }, + "SrpListHideSingleAccount": { + "message": "Itago ang 1 account" + }, + "SrpListShowAccounts": { + "message": "Ipakita ang $1 (na) account", + "description": "$1 is the number of accounts" + }, + "SrpListShowSingleAccount": { + "message": "Ipakita ang 1 account" + }, "about": { "message": "Tungkol Dito" }, @@ -76,6 +90,9 @@ "accountDetails": { "message": "Mga detalye ng account" }, + "accountDetailsRevokeDelegationButton": { + "message": " Bumalik sa regular na account" + }, "accountIdenticon": { "message": "Identicon ng Account" }, @@ -153,6 +170,12 @@ "addAlias": { "message": "Magdagdag ng alias" }, + "addBitcoinAccountLabel": { + "message": "Bitcoin account (Beta)" + }, + "addBitcoinTestnetAccountLabel": { + "message": "Bitcoin account (Testnet)" + }, "addBlockExplorer": { "message": "Magdagdag ng block explorer" }, @@ -193,6 +216,9 @@ "addFriendsAndAddresses": { "message": "Magdagdag ng mga kaibigan at address na pinagkakatiwalaan mo" }, + "addHardwareWalletLabel": { + "message": "Hardware wallet" + }, "addIPFSGateway": { "message": "Idagdag ang mas gusto mong IPFS gateway" }, @@ -212,12 +238,26 @@ "addNewAccount": { "message": "Magdagdag ng bagong account sa Ethereum" }, + "addNewEthereumAccountLabel": { + "message": "Ethereum account" + }, + "addNewSolanaAccountLabel": { + "message": "Solana account" + }, "addNft": { "message": "Magdagdag ng NFT" }, "addNfts": { "message": "Magdagdag ng mga NFT" }, + "addNonEvmAccount": { + "message": "Magdagdag ng $1 account", + "description": "$1 is the non EVM network where the account is going to be created, e.g. Bitcoin or Solana" + }, + "addNonEvmAccountFromNetworkPicker": { + "message": "Para i-enable ang $1 network, kailangan mong gumawa ng $2 account.", + "description": "$1 is the non EVM network where the account is going to be created, e.g. Solana Mainnet or Solana Devnet. $2 is the account type, e.g. Bitcoin or Solana" + }, "addRpcUrl": { "message": "Magdagdag ng RPC URL" }, @@ -300,14 +340,16 @@ "advancedPriorityFeeToolTip": { "message": "Ang bayad sa priyoridad (kilala rin bilang ā€œtip ng mineroā€) ay direktang napupunta sa mga minero at ginagawang insentibo ang mga ito upang unahin ang iyong mga transaksyon." }, - "aggregatedBalancePopover": { - "message": "Ipinapakita nito ang halaga ng lahat ng token na pagmamay-ari mo sa ibinigay na network. Kung mas gusto mong makita ang halagang ito sa ETH o sa ibang currency, pumunta sa $1.", - "description": "$1 represents the settings page" - }, "agreeTermsOfUse": { "message": "Sumasang-ayon ako sa $1 ng MetaMask", "description": "$1 is the `terms` link" }, + "airDropPatternDescription": { + "message": "Isinasaad ng on-chain history ng token na may mga dati nang kahina-hinalang aktibidad ng airdrop." + }, + "airDropPatternTitle": { + "message": "Pattern ng Airdrop" + }, "airgapVault": { "message": "AirGap Vault" }, @@ -726,9 +768,21 @@ "bridgeConfirmTwoTransactions": { "message": "Kakailanganin mong kumpirmahin ang 2 transaksyon sa iyong hardware wallet:" }, + "bridgeCreateSolanaAccount": { + "message": "Gumawa ng Solana account" + }, + "bridgeCreateSolanaAccountDescription": { + "message": "Para mag-swap papunta sa Solana network, kailangan mo ng account at tatanggap na address." + }, + "bridgeCreateSolanaAccountTitle": { + "message": "Kailangan mo muna ng Solana account." + }, "bridgeEnterAmount": { "message": "Ilagay ang halaga" }, + "bridgeEnterAmountAndSelectAccount": { + "message": "Ilagay ang halaga at pumili ng destinasyong account" + }, "bridgeExplorerLinkViewOn": { "message": "Tingnan sa $1" }, @@ -751,9 +805,15 @@ "bridgeQuoteExpired": { "message": "Nag-time out ang quote mo." }, + "bridgeSelectDestinationAccount": { + "message": "Pumili ng destinasyong account" + }, "bridgeSelectNetwork": { "message": "Pumili ng network" }, + "bridgeSelectTokenAmountAndAccount": { + "message": "Pumili ng token, halaga, at destinasyong account" + }, "bridgeSelectTokenAndAmount": { "message": "Piliin ang token at halaga" }, @@ -944,6 +1004,12 @@ "message": "Walang opsyon na nahanap", "description": "Default text shown in the combo field dropdown if no options." }, + "concentratedSupplyDistributionDescription": { + "message": "Karamihan ng supply ng token ay hawak ng mga nangungunang may-ari ng token, na nangangahulugang may panganib ng sentralisadong pagmamanipula sa presyo" + }, + "concentratedSupplyDistributionTitle": { + "message": "Nakatuong Pamamahagi ng Supply" + }, "configureSnapPopupDescription": { "message": "Papaalis ka na ngayon sa MetaMask para ma-configure ang snap na ito." }, @@ -962,6 +1028,15 @@ "confirm": { "message": "Kumpirmahin" }, + "confirmAccountType": { + "message": "Uri" + }, + "confirmAccountTypeSmartContract": { + "message": "Smart account" + }, + "confirmAccountTypeStandard": { + "message": "Standard account" + }, "confirmAlertModalAcknowledgeMultiple": { "message": "Kinikilala ko ang mga alerto at nais ko pa ring magpatuloy" }, @@ -974,12 +1049,36 @@ "confirmFieldTooltipPaymaster": { "message": "Ang bayarin para sa transaksyong ito ay babayaran ng paymaster smart contract." }, + "confirmGasFeeTokenBalance": { + "message": "Bal:" + }, + "confirmGasFeeTokenInsufficientBalance": { + "message": "Hindi sapat na pondo" + }, + "confirmGasFeeTokenMetaMaskFee": { + "message": "Kasama ang bayad na $1" + }, + "confirmGasFeeTokenModalTitle": { + "message": "Pumili ng token" + }, + "confirmGasFeeTokenToast": { + "message": "Babayaran mo ang bayad sa network na ito ng $1" + }, + "confirmGasFeeTokenTooltip": { + "message": "Ibabayad ito sa network para iproseso ang transaksyon mo. Kasama rito ang bayad sa MetaMask na $1 para sa mga hindi ETH na token." + }, + "confirmNestedTransactionTitle": { + "message": "Transaksyong $1" + }, "confirmPassword": { "message": "Kumpirmahin ang password" }, "confirmRecoveryPhrase": { "message": "Kumpirmahin ang Lihim na Parirala sa Pagbawi" }, + "confirmSimulationApprove": { + "message": "Inaaprubahan mo ang" + }, "confirmTitleApproveTransactionNFT": { "message": "Kahilingan sa pag-withdraw" }, @@ -1022,9 +1121,24 @@ "confirmTitleTransaction": { "message": "Hiling na Transaksyon" }, + "confirmUpgradeCancelModalButtonCancelTransaction": { + "message": "Kanselahin ang transaksyon" + }, + "confirmUpgradeCancelModalButtonCancelUpgrade": { + "message": "Kanselahin ang pag-update at transaksyon" + }, + "confirmUpgradeCancelModalDescription": { + "message": "Kung ayaw mong i-update ang account mo, puwede mo itong kanselahin dito. $1." + }, + "confirmUpgradeCancelModalTitle": { + "message": "Kanselahin ang transaksyon" + }, "confirmationAlertDetails": { "message": "Para protektahan ang iyong mga asset, iminumungkahi namin na tanggihan mo ang kahilingan." }, + "confirmationAlertModalTitleDescription": { + "message": "Maaaring nasa panganib ang iyong mga asset" + }, "confirmed": { "message": "Nakumpirma" }, @@ -1052,6 +1166,9 @@ "connectAccounts": { "message": "Ikonekta ang mga account" }, + "connectAnAccountHeader": { + "message": "Magkonekta ng account" + }, "connectManually": { "message": "Manu-manong kumonekta sa kasalukuyang site" }, @@ -1158,6 +1275,9 @@ "message": "Nabigo ang pagkuha ng $1, suriin ang iyong network at subukan ulit.", "description": "$1 is the name of the snap being fetched." }, + "connectionPopoverDescription": { + "message": "Upang kumonekta sa isang site, piliin ang button para sa pagkonekta. Sa mga web3 site lang puwedeng kumonekta ang MetaMask." + }, "connectionRequest": { "message": "Kahilingan sa koneksyon" }, @@ -1219,6 +1339,9 @@ "create": { "message": "Gumawa" }, + "createNewAccountHeader": { + "message": "Gumawa ng bagong account" + }, "createNewWallet": { "message": "Gumawa ng bagong wallet" }, @@ -1231,6 +1354,9 @@ "createSnapAccountTitle": { "message": "Gumawa ng account" }, + "createSolanaAccount": { + "message": "Gumawa ng Solana account" + }, "creatorAddress": { "message": "Address ng creator" }, @@ -1471,6 +1597,21 @@ "message": "Deskripsyon mula sa $1", "description": "$1 represents the name of the snap" }, + "destinationAccountPickerNoEligible": { + "message": "Walang nahanap na kwalipikadong account" + }, + "destinationAccountPickerNoMatching": { + "message": "Walang nahanap na katugmang account" + }, + "destinationAccountPickerReceiveAt": { + "message": "Tanggapin sa" + }, + "destinationAccountPickerSearchPlaceholderToMainnet": { + "message": "Tatanggap na address o ENS" + }, + "destinationAccountPickerSearchPlaceholderToSolana": { + "message": "Tatanggap na address" + }, "details": { "message": "Mga Detalye" }, @@ -1516,6 +1657,9 @@ "message": "Ang $1 ay nadiskonekta mula sa $2", "description": "$1 is name of the name and $2 represents the dapp name`" }, + "discover": { + "message": "Tuklasin" + }, "discoverSnaps": { "message": "Diskubrehin ang mga Snap", "description": "Text that links to the Snaps website. Displayed in a banner on Snaps list page in settings." @@ -1872,6 +2016,9 @@ "experimental": { "message": "Eksperimental" }, + "exploreweb3": { + "message": "Tuklasin ang web3" + }, "exportYourData": { "message": "I-export ang data mo" }, @@ -1885,6 +2032,9 @@ "message": "Tuklasin ang mga Snap na binuo ng komunidad para i-customize ang iyong karanasan sa web3", "description": "Banner description displayed on Snaps list page in Settings when less than 6 Snaps is installed." }, + "externalAccount": { + "message": "External Account" + }, "externalExtension": { "message": "External Extension" }, @@ -2197,6 +2347,12 @@ "holdToRevealUnlockedLabel": { "message": "i-hold para ibunyag ang bilog na naka-unlock" }, + "honeypotDescription": { + "message": "Puwede may panganib ng honeypot ang token na ito. Ipinapayong magsagawa ng sariling pagsusuri bago gamitin ito para maiwasan ang anumang potensyal na pagkalugi." + }, + "honeypotTitle": { + "message": "Honey Pot" + }, "howNetworkFeesWorkExplanation": { "message": "Tinatayang bayad na kinakailangan para maproseso ang transaksyon. Ang max na bayad ay $1." }, @@ -2262,6 +2418,30 @@ "importNFTTokenIdToolTip": { "message": "Ang ID ng NFT ay isang natatanging pagkakakilanlan dahil walang dalawang NFT ang magkatulad. Muli, sa OpenSea ang numerong ito ay nasa ilalim ng 'Mga Detalye'. Itala ito, o kopyahin ito sa iyong clipboard." }, + "importNWordSRP": { + "message": "Mayroon akong $1 (na) word recovery phrase", + "description": "$1 is the number of words in the recovery phrase" + }, + "importPrivateKey": { + "message": "Pribadong Key" + }, + "importSRPDescription": { + "message": "Mag-import ng dati nang wallet gamit ang iyong 12 o 24 word secret recovery phrase." + }, + "importSRPNumberOfWordsError": { + "message": "Naglalaman ang Secret Recovery Phrase ng 12 o 24 na salita" + }, + "importSRPWordError": { + "message": "Mali ang salitang $1 o mali ang baybay nito.", + "description": "$1 is the word that is incorrect or misspelled" + }, + "importSRPWordErrorAlternative": { + "message": "Mali ang salitang $1 at $2 o mali ang baybay ng mga ito.", + "description": "$1 and $2 are multiple words that are mispelled." + }, + "importSecretRecoveryPhrase": { + "message": "Mag-import ng Secret Recovery Phrase" + }, "importSelectedTokens": { "message": "I-import ang mga napiling token?" }, @@ -2280,6 +2460,12 @@ "importTokensError": { "message": "Hindi namin ma-import ang mga token. Pakisubukan ulit mamaya." }, + "importWallet": { + "message": "Mag-import ng wallet" + }, + "importWalletOrAccountHeader": { + "message": "Mag-import ng wallet o account" + }, "importWithCount": { "message": "Mag-import ng $1", "description": "$1 will the number of detected tokens that are selected for importing, if all of them are selected then $1 will be all" @@ -2327,6 +2513,12 @@ "insufficientFundsForGas": { "message": "Di sapat na pondo para sa gas" }, + "insufficientLockedLiquidityDescription": { + "message": "Dahil sa hindi sapat na naka-lock o na-burn na liquidity, nanganganib sa mga biglaang pag-withdraw ng liquidity ang token, na nagiging sanhi ng pagbabago-bago ng market." + }, + "insufficientLockedLiquidityTitle": { + "message": "Hindi Sapat na Naka-lock na Liquidity" + }, "insufficientTokens": { "message": "Hindi sapat ang token." }, @@ -2362,6 +2554,9 @@ "invalidCustomNetworkAlertTitle": { "message": "Di-wastong custom na network" }, + "invalidHexData": { + "message": "Di-wastong hex data" + }, "invalidHexNumber": { "message": "Di-wastong hexadecimal number." }, @@ -2540,6 +2735,9 @@ "ledgerLocked": { "message": "Hindi makakonekta sa Ledger device. Siguruhin na ang device mo ay naka-unlock at bukas ang Ethereum." }, + "ledgerMultipleDevicesUnsupportedErrorMessage": { + "message": "Hindi puwedeng magkonekta ng maraming Ledger device nang sabay-sabay. Para magkonekta ng bagong Ledger device, kailangan mo munang idiskonekta ang dati." + }, "ledgerTimeout": { "message": "Masyadong natatagalan ang Ledger Live upang tumugon o mag-timeout ng koneksyon. Tiyaking nakabukas ang Ledger Live app at naka-unlock ang iyong device." }, @@ -2637,6 +2835,9 @@ "manageDefaultSettings": { "message": "Pamahalaan ang mga default na setting sa pagkapribado" }, + "managePermissions": { + "message": "Pamahalaan ang mga pahintulot" + }, "marketCap": { "message": "Market cap" }, @@ -2755,6 +2956,15 @@ "multichainAddEthereumChainConfirmationDescription": { "message": "Idinadagdag mo ang network na ito sa MetaMask at binibigyan ng pahintulot ang site na ito na gamitin ito." }, + "multichainQuoteCardBridgingLabel": { + "message": "Bridging" + }, + "multichainQuoteCardQuoteLabel": { + "message": "Quote" + }, + "multichainQuoteCardTimeLabel": { + "message": "Oras" + }, "multipleSnapConnectionWarning": { "message": "Si $1 ay gustong gumamit ng $2 Snaps", "description": "$1 is the dapp and $2 is the number of snaps it wants to connect to." @@ -2869,6 +3079,13 @@ "network": { "message": "Network:" }, + "networkChanged": { + "message": "Nagbago ang network" + }, + "networkChangedMessage": { + "message": "Nagsasagawa ka ng transaksyon sa $1.", + "description": "$1 is the name of the network" + }, "networkDetails": { "message": "Mga Detalye ng Network" }, @@ -3143,6 +3360,9 @@ "notEnoughGas": { "message": "Hindi Sapat ang Gas" }, + "notNow": { + "message": "Hindi ngayon" + }, "notificationDetail": { "message": "Mga detalye" }, @@ -3505,6 +3725,13 @@ "origin": { "message": "Pinagmulan" }, + "originChanged": { + "message": "Nagbago ang site" + }, + "originChangedMessage": { + "message": "Nagsusuri ka ngayon ng kahilingan mula sa $1.", + "description": "$1 is the name of the origin" + }, "osTheme": { "message": "Sistema" }, @@ -3559,6 +3786,14 @@ "pending": { "message": "Nakabinbin" }, + "pendingConfirmationAddNetworkAlertMessage": { + "message": "Kapag nag-update ng network, makakansela ang $1 (na) nakabinbing transaksyon mula sa site na ito.", + "description": "Number of transactions." + }, + "pendingConfirmationSwitchNetworkAlertMessage": { + "message": "Kapag lumipat ng network, makakansela ang $1 (na) nakabinbing transaksyon mula sa site na ito.", + "description": "Number of transactions." + }, "pendingTransactionAlertMessage": { "message": "Hindi magpapatuloy ang transaksyong ito hangga't hindi pa nakukumpleto ang naunang transaksyon. $1", "description": "$1 represents the words 'how to cancel or speed up a transaction' in a hyperlink" @@ -3842,6 +4077,9 @@ "permitSimulationChange_receive": { "message": "Nakatanggap ka ng" }, + "permitSimulationChange_revoke2": { + "message": "Bawiin" + }, "permitSimulationChange_transfer": { "message": "Nagpadala ka ng" }, @@ -4237,6 +4475,9 @@ "reusedTokenNameWarning": { "message": "Ang isang token dito ay muling ginagamit ang isang simbolo mula sa ibang token na tinitingnan mo, maaari itong maging nakakalito." }, + "revealSecretRecoveryPhrase": { + "message": "Ipakita ang Secret Recovery Phrase" + }, "revealSeedWords": { "message": "Ibunyag ang Lihim na Parirala sa Pagbawi" }, @@ -4286,12 +4527,19 @@ "reviewAlerts": { "message": "Suriin ang mga alerto" }, + "reviewPendingTransactions": { + "message": "Suriin ang mga nakabinbing transaksyon" + }, "reviewPermissions": { "message": "Suriin ang mga pahintulot" }, "revokePermission": { "message": "Bawiin ang pahintulot" }, + "revokePermissionTitle": { + "message": "Alisin ang $1 pahintulot", + "description": "The token symbol that is being revoked" + }, "revokeSimulationDetailsDesc": { "message": "Aalisin mo ang pahintulot sa ibang tao na gumastos ng mga token mula sa account mo." }, @@ -4334,6 +4582,10 @@ "secretRecoveryPhrase": { "message": "Lihim na Parirala sa Pagbawi" }, + "secretRecoveryPhrasePlusNumber": { + "message": "Secret Recovery Phrase $1", + "description": "The $1 is the order of the Secret Recovery Phrase" + }, "secureWallet": { "message": "Secure Wallet" }, @@ -4424,6 +4676,9 @@ "select": { "message": "Piliin ang" }, + "selectAccountToConnect": { + "message": "Piliin ang account na ikokonekta" + }, "selectAccounts": { "message": "Pumili ng (mga) account" }, @@ -4454,6 +4709,9 @@ "selectRpcUrl": { "message": "Pumili ng RPC URL" }, + "selectSecretRecoveryPhrase": { + "message": "Piliin ang Secret Recovery Phrase" + }, "selectType": { "message": "Pumili ng Uri" }, @@ -4565,16 +4823,6 @@ "showHexDataDescription": { "message": "Piliin ito para ipakita ang field ng hex na data sa screen ng pagpapadala" }, - "showIncomingTransactions": { - "message": "Ipakita ang mga papasok na transaksyon" - }, - "showIncomingTransactionsDescription": { - "message": "Umaasa ito sa $1 na magkakaroon ng access sa iyong Ethereum address at sa iyong IP address. $2", - "description": "$1 is the link to etherscan url and $2 is the link to the privacy policy of consensys APIs" - }, - "showIncomingTransactionsExplainer": { - "message": "Ito ay umaasa sa ibang third party na API para sa bawat network, na naglalantad sa iyong address sa Ethereum at iyong IP address." - }, "showLess": { "message": "Magpakita ng mas kaunti" }, @@ -4593,6 +4841,9 @@ "showPrivateKey": { "message": "Ipakita ang pribadong key" }, + "showSRP": { + "message": "Ipakita ang Secret Recovery Phrase" + }, "showTestnetNetworks": { "message": "Ipakita ang mga test network" }, @@ -4714,12 +4965,24 @@ "slideCashOutTitle": { "message": "Mag-cash out gamit ang MetaMask" }, + "slideDebitCardDescription": { + "message": "Available sa mga piling rehiyon" + }, "slideDebitCardTitle": { "message": "MetaMask debit card" }, + "slideFundWalletDescription": { + "message": "Magdagdag o maglipat ng mga token para magsimula" + }, "slideFundWalletTitle": { "message": "Pondohan ang iyong wallet" }, + "slideSweepStakeDescription": { + "message": "Mag-mint na ng NFT para sa tsansang manalo" + }, + "slideSweepStakeTitle": { + "message": "Sumali sa $5000 USDC na Giveaway!" + }, "smartContracts": { "message": "Mga smart na kontrata" }, @@ -4866,6 +5129,9 @@ "snapResultSuccessDescription": { "message": "Handa nang gamitin ang $1" }, + "snapUIAssetSelectorTitle": { + "message": "Pumili ng asset" + }, "snapUpdateAlertDescription": { "message": "Kunin ang pinakabagong bersyon ng $1", "description": "Description used in Snap update alert banner when snap update is available. $1 is the Snap name." @@ -4925,6 +5191,27 @@ "message": "Makipag-ugnayan sa mga tagalikha ng $1 para sa karagdagang suporta.", "description": "This is shown when the insight snap throws an error. $1 is the snap name" }, + "solanaImportAccounts": { + "message": "Mag-import ng mga Solana account" + }, + "solanaImportAccountsDescription": { + "message": "Mag-importa ng Lihim na Parirala sa Pagbawi para ilipat ang Solana account mo mula sa ibang wallet." + }, + "solanaMoreFeaturesComingSoon": { + "message": "Parating na ang mas maraming feature" + }, + "solanaMoreFeaturesComingSoonDescription": { + "message": "Parating na ang mga Solana dapp, NFT, suporta sa hardware wallet at iba pa." + }, + "solanaOnMetaMask": { + "message": "Solana sa MetaMask" + }, + "solanaSendReceiveSwapTokens": { + "message": "Magpadala, tumanggap, at mag-swap ng mga token" + }, + "solanaSendReceiveSwapTokensDescription": { + "message": "Maglipat at makipagtransaksyon gamit ang mga token gaya ng SOL, USDC, at iba pa." + }, "someNetworks": { "message": "Mga network ng $1" }, @@ -4951,6 +5238,21 @@ "source": { "message": "Pinagmulan" }, + "spamModalBlockedDescription": { + "message": "Maba-block ang site na ito nang 1 minuto." + }, + "spamModalBlockedTitle": { + "message": "Pansamantala mong blinock ang site na ito" + }, + "spamModalDescription": { + "message": "Kung nakakatanggap ka ng masyadong maraming kahilingan, puwede mong pansamantalang i-block ang site." + }, + "spamModalTemporaryBlockButton": { + "message": "Pansamantalang i-block ang site na ito" + }, + "spamModalTitle": { + "message": "May napansin kaming maraming kahilingan" + }, "speed": { "message": "Bilis" }, @@ -5000,10 +5302,28 @@ "spendingCap": { "message": "Limitasyon sa paggastos" }, + "spendingCaps": { + "message": "Mga limitasyon sa paggastos" + }, "srpInputNumberOfWords": { "message": "Mayroon akong word phrase ng $1", "description": "This is the text for each option in the dropdown where a user selects how many words their secret recovery phrase has during import. The $1 is the number of words (either 12, 15, 18, 21, or 24)." }, + "srpListName": { + "message": "Secret Recovery Phrase $1", + "description": "$1 is the order of the Secret Recovery Phrase" + }, + "srpListNumberOfAccounts": { + "message": "$1 (na) account", + "description": "$1 is the number of accounts in the list" + }, + "srpListSelectionDescription": { + "message": "Ang bagong account mula kung saan bubuuin ang Secret Recovery Phrase" + }, + "srpListSingleOrZero": { + "message": "$1 account", + "description": "$1 is the number of accounts in the list, it is either 1 or 0" + }, "srpPasteFailedTooManyWords": { "message": "Nabigong i-paste dahil naglalaman ito ng higit sa 24 na salita. Ang lihim na parirala sa pagbawi ay mayroong hanggang 24 na salita lang.", "description": "Description of SRP paste error when the pasted content has too many words" @@ -5158,6 +5478,9 @@ "message": "Ang biglaang pagbabago sa merkado ay maaaring maging sanhi ng pagkabigo. Kung magpatuloy ang problema, makipag-ugnyan sa $1.", "description": "This message is shown to a user if their swap fails. The $1 will be replaced by support.metamask.io" }, + "stxOptInSupportedNetworksDescription": { + "message": "I-on ang mga Smart Transaction para sa mas maaasahan at ligtas na mga transaksyon sa mga sinusuportahang network. $1" + }, "stxPendingPrivatelySubmittingSwap": { "message": "Pribadong isinusumite ang iyong Swap..." }, @@ -5977,6 +6300,12 @@ "message": "Ang pagpapadala ng mga token ng NFT (ERC-721) ay kasalukuyang hindi suportado", "description": "This is an error message we show the user if they attempt to send an NFT asset type, for which currently don't support sending" }, + "unstableTokenPriceDescription": { + "message": "Lubhang pabago-bago ang presyo ng token na ito sa USD, na nagpapahiwatig ng matinding panganib ng pagkalugi nang malaki kapag ginamit ito." + }, + "unstableTokenPriceTitle": { + "message": "Pabago-bagong Presyo ng Token" + }, "upArrow": { "message": "arrow pataas" }, @@ -6099,6 +6428,18 @@ "visitSite": { "message": "Bisitahin ang site" }, + "visitSupportDataConsentModalAccept": { + "message": "Kumpirmahin" + }, + "visitSupportDataConsentModalDescription": { + "message": "Gusto mo bang ibahagi ang Identifier at bersyon ng app ng MetaMask sa aming Sentro ng Suporta? Makakatulong ito sa amin na malutas ang problema mo, pero opsyonal ito." + }, + "visitSupportDataConsentModalReject": { + "message": "Huwag ibahagi" + }, + "visitSupportDataConsentModalTitle": { + "message": "Magbahagi ng mga detalye ng device sa suporta" + }, "visitWebSite": { "message": "Bisitahin ang aming website" }, diff --git a/app/_locales/tr/messages.json b/app/_locales/tr/messages.json index ee9cbe2efc8c..b04530917458 100644 --- a/app/_locales/tr/messages.json +++ b/app/_locales/tr/messages.json @@ -44,6 +44,20 @@ "QRHardwareWalletSteps2Description": { "message": "Ngrave Zero" }, + "SrpListHideAccounts": { + "message": "$1 hesabı gizle", + "description": "$1 is the number of accounts" + }, + "SrpListHideSingleAccount": { + "message": "1 hesabı gizle" + }, + "SrpListShowAccounts": { + "message": "$1 hesabı gƶster", + "description": "$1 is the number of accounts" + }, + "SrpListShowSingleAccount": { + "message": "1 hesabı gƶster" + }, "about": { "message": "Hakkında" }, @@ -76,6 +90,9 @@ "accountDetails": { "message": "Hesap bilgileri" }, + "accountDetailsRevokeDelegationButton": { + "message": " Normal hesaba geri dƶn" + }, "accountIdenticon": { "message": "Hesap Identicon" }, @@ -153,6 +170,12 @@ "addAlias": { "message": "Diğer adı ekle" }, + "addBitcoinAccountLabel": { + "message": "Bitcoin hesabı (Beta)" + }, + "addBitcoinTestnetAccountLabel": { + "message": "Bitcoin hesabı (Test Ağı)" + }, "addBlockExplorer": { "message": "Bir blok gezgini ekle" }, @@ -193,6 +216,9 @@ "addFriendsAndAddresses": { "message": "Güvendiğiniz arkadaşlarınızı ve adresleri ekleyin" }, + "addHardwareWalletLabel": { + "message": "Donanım cüzdanı" + }, "addIPFSGateway": { "message": "Tercih ettiğiniz IPFS ağ geƧidini ekleyin" }, @@ -212,12 +238,26 @@ "addNewAccount": { "message": "Yeni bir Ethereum hesabı ekle" }, + "addNewEthereumAccountLabel": { + "message": "Ethereum hesabı" + }, + "addNewSolanaAccountLabel": { + "message": "Solana hesabı" + }, "addNft": { "message": "NFT ekleyin" }, "addNfts": { "message": "NFT ekleyin" }, + "addNonEvmAccount": { + "message": "$1 hesap ekle", + "description": "$1 is the non EVM network where the account is going to be created, e.g. Bitcoin or Solana" + }, + "addNonEvmAccountFromNetworkPicker": { + "message": "$1 ağını etkinleştirmek iƧin bir $2 hesabı oluşturmanız gerekir.", + "description": "$1 is the non EVM network where the account is going to be created, e.g. Solana Mainnet or Solana Devnet. $2 is the account type, e.g. Bitcoin or Solana" + }, "addRpcUrl": { "message": "RPC URL adresi ekle" }, @@ -300,14 +340,16 @@ "advancedPriorityFeeToolTip": { "message": "Maks. ƶncelik ücreti (başka bir deyişle \"madenci bahşişi\") doğrudan madencilere gider ve işleminizin ƶncelikli olarak gerƧekleştirilmesini teşvik eder." }, - "aggregatedBalancePopover": { - "message": "Bu, belirli bir ağda sahip olduğunuz tüm token'lerin değerini yansıtır. Bu değeri ETH olarak veya diğer para birimlerinde gƶrmeyi tercih ediyorsanız $1 alanına gidin.", - "description": "$1 represents the settings page" - }, "agreeTermsOfUse": { "message": "MetaMask'in $1 bƶlümünü kabul ediyorum", "description": "$1 is the `terms` link" }, + "airDropPatternDescription": { + "message": "Token'ın zincir iƧi geƧmişi, daha ƶnce şüpheli airdrop faaliyetlerinin olduğu durumları açığa Ƨıkarır." + }, + "airDropPatternTitle": { + "message": "Airdrop Modeli" + }, "airgapVault": { "message": "AirGap Vault" }, @@ -726,9 +768,21 @@ "bridgeConfirmTwoTransactions": { "message": "Donanım cüzdanınızda 2 işlemi onaylamanız gerekecek:" }, + "bridgeCreateSolanaAccount": { + "message": "Solana hesabı oluştur" + }, + "bridgeCreateSolanaAccountDescription": { + "message": "Solana ağına swap gerƧekleştirmek iƧin bir hesaba ve alıcı adresine ihtiyacınız var." + }, + "bridgeCreateSolanaAccountTitle": { + "message": "Ɩnce bir Solana hesabına ihtiyacınız olacak." + }, "bridgeEnterAmount": { "message": "Miktar girin" }, + "bridgeEnterAmountAndSelectAccount": { + "message": "Tutar girin ve hedef hesabı seƧin" + }, "bridgeExplorerLinkViewOn": { "message": "$1 üzerinde gƶrüntüle" }, @@ -751,9 +805,15 @@ "bridgeQuoteExpired": { "message": "Teklifiniz zaman aşımına uğradı." }, + "bridgeSelectDestinationAccount": { + "message": "Hedef hesabı seƧin" + }, "bridgeSelectNetwork": { "message": "Ağ seƧ" }, + "bridgeSelectTokenAmountAndAccount": { + "message": "Token, tutar ve hedef hesabı seƧin" + }, "bridgeSelectTokenAndAmount": { "message": "Token ve miktar seƧin" }, @@ -944,6 +1004,12 @@ "message": "HiƧbir seƧenek bulunamadı", "description": "Default text shown in the combo field dropdown if no options." }, + "concentratedSupplyDistributionDescription": { + "message": "Token arzının Ƨoğunluğu en fazla token sahibi olanlar tarafından tutulur ve merkezi fiyat manipülasyonu riski teşkil eder" + }, + "concentratedSupplyDistributionTitle": { + "message": "Konsantre Arz Dağılımı" + }, "configureSnapPopupDescription": { "message": "Şu anda bu snapi yapılandırmak iƧin MetaMask'ten ayrılıyorsunuz." }, @@ -962,6 +1028,15 @@ "confirm": { "message": "Onayla" }, + "confirmAccountType": { + "message": "Tür" + }, + "confirmAccountTypeSmartContract": { + "message": "Akıllı hesap" + }, + "confirmAccountTypeStandard": { + "message": "Standart hesap" + }, "confirmAlertModalAcknowledgeMultiple": { "message": "Uyarıları kabul ediyorum ve yine de ilerlemek istiyorum" }, @@ -974,12 +1049,36 @@ "confirmFieldTooltipPaymaster": { "message": "Bu işlemin ücreti paymaster akıllı sƶzleşmesi tarafından ƶdenecektir." }, + "confirmGasFeeTokenBalance": { + "message": "Bak:" + }, + "confirmGasFeeTokenInsufficientBalance": { + "message": "Para yetersiz" + }, + "confirmGasFeeTokenMetaMaskFee": { + "message": "$1 ücret dahildir" + }, + "confirmGasFeeTokenModalTitle": { + "message": "Bir token seƧin" + }, + "confirmGasFeeTokenToast": { + "message": "Bu ağ ücretini $1 ile ƶdüyorsunuz" + }, + "confirmGasFeeTokenTooltip": { + "message": "Bu ücret, işleminizi gerƧekleştirmek iƧin ağa ƶdenir. ETH dışı token'lar iƧin $1 MetaMask ücreti dahildir." + }, + "confirmNestedTransactionTitle": { + "message": "İşlem $1" + }, "confirmPassword": { "message": "Şifreyi onayla" }, "confirmRecoveryPhrase": { "message": "Gizli Kurtarma İfadesini Onayla" }, + "confirmSimulationApprove": { + "message": "Onaylıyorsunuz" + }, "confirmTitleApproveTransactionNFT": { "message": "Para Ƨekme talebi" }, @@ -1022,9 +1121,24 @@ "confirmTitleTransaction": { "message": "İşlem talebi" }, + "confirmUpgradeCancelModalButtonCancelTransaction": { + "message": "İşlemi iptal et" + }, + "confirmUpgradeCancelModalButtonCancelUpgrade": { + "message": "Güncellemeyi ve işlemi iptal et" + }, + "confirmUpgradeCancelModalDescription": { + "message": "Hesabınızı güncellemek istemiyorsanız burada iptal edebilirsiniz.\n\nBu işlemi bir güncelleme olmadan bitirmek iƧin sitede tekrar bu talebi sunmanız gerekecek. $1." + }, + "confirmUpgradeCancelModalTitle": { + "message": "İşlemi iptal et" + }, "confirmationAlertDetails": { "message": "Varlıklarınızı korumak iƧin talebi reddetmenizi ƶneririz." }, + "confirmationAlertModalTitleDescription": { + "message": "Varlıklarınız risk altında olabilir" + }, "confirmed": { "message": "Onaylandı" }, @@ -1052,6 +1166,9 @@ "connectAccounts": { "message": "Hesapları bağla" }, + "connectAnAccountHeader": { + "message": "Bir hesabı bağla" + }, "connectManually": { "message": "Mevcut siteye manuel olarak bağlan" }, @@ -1158,6 +1275,9 @@ "message": "$1 getirme başarısız oldu, ağınızı kontrol edip tekrar deneyin.", "description": "$1 is the name of the snap being fetched." }, + "connectionPopoverDescription": { + "message": "Bir siteye bağlanmak iƧin bağlan düğmesini seƧin. MetaMask yalnızca web3 sitelerine bağlanabilir." + }, "connectionRequest": { "message": "Bağlantı talebi" }, @@ -1219,6 +1339,9 @@ "create": { "message": "Oluştur" }, + "createNewAccountHeader": { + "message": "Yeni bir hesap oluştur" + }, "createNewWallet": { "message": "Yeni bir cüzdan oluştur" }, @@ -1231,6 +1354,9 @@ "createSnapAccountTitle": { "message": "Hesap oluştur" }, + "createSolanaAccount": { + "message": "Solana hesabı oluştur" + }, "creatorAddress": { "message": "Oluşturucu adresi" }, @@ -1471,6 +1597,21 @@ "message": "$1 aƧıklaması", "description": "$1 represents the name of the snap" }, + "destinationAccountPickerNoEligible": { + "message": "Uygun hesap bulunamadı" + }, + "destinationAccountPickerNoMatching": { + "message": "Eşleşen hesap bulunamadı" + }, + "destinationAccountPickerReceiveAt": { + "message": "Alım adresi:" + }, + "destinationAccountPickerSearchPlaceholderToMainnet": { + "message": "Alıcı adres veya ENS" + }, + "destinationAccountPickerSearchPlaceholderToSolana": { + "message": "Alıcı adres" + }, "details": { "message": "Ayrıntılar" }, @@ -1516,6 +1657,9 @@ "message": "$1 iƧin $2 bağlantısı kesildi", "description": "$1 is name of the name and $2 represents the dapp name`" }, + "discover": { + "message": "Keşfet" + }, "discoverSnaps": { "message": "Snap'leri keşfedin", "description": "Text that links to the Snaps website. Displayed in a banner on Snaps list page in settings." @@ -1872,6 +2016,9 @@ "experimental": { "message": "Deneysel" }, + "exploreweb3": { + "message": "Web3'ü keşfet" + }, "exportYourData": { "message": "Verilerinizi dışa aktarın" }, @@ -1885,6 +2032,9 @@ "message": "web3 deneyiminizi kişiselleştirmek iƧin topluluk tarafından oluşturulmuş Snapleri keşfedin", "description": "Banner description displayed on Snaps list page in Settings when less than 6 Snaps is installed." }, + "externalAccount": { + "message": "Harici Hesap" + }, "externalExtension": { "message": "Harici uzantı" }, @@ -2197,6 +2347,12 @@ "holdToRevealUnlockedLabel": { "message": "kilidi aƧılmış daireyi açığa Ƨıkarmak iƧin tut" }, + "honeypotDescription": { + "message": "Bu token bir bal tuzağı riski taşıyor olabilir. Olası mali kayıpları ƶnlemek iƧin etkileşimde bulunmadan ƶnce gerekli ƶzeni gƶstermeniz tavsiye edilir." + }, + "honeypotTitle": { + "message": "Bal Tuzağı" + }, "howNetworkFeesWorkExplanation": { "message": "İşlemi gerƧekleştirmek iƧin tahmini ücret gereklidir. Maksimum ücret $1." }, @@ -2262,6 +2418,30 @@ "importNFTTokenIdToolTip": { "message": "HiƧbir iki NFT kimliği birbiriyle aynı olmadığı iƧin her NFT kimliği benzersiz bir tanımlayıcıdır. Yine, OpenSea'de bu sayı 'Detaylar' kısmının altında yer alır. Not alın veya panonuza kopyalayın." }, + "importNWordSRP": { + "message": "$1 sƶzcükten oluşan kurtarma ifadem var", + "description": "$1 is the number of words in the recovery phrase" + }, + "importPrivateKey": { + "message": "Ɩzel Anahtar" + }, + "importSRPDescription": { + "message": "12 veya 24 sƶzcükten oluşan gizli kurtarma ifadenizle mevcut bir cüzdanı iƧe aktarın." + }, + "importSRPNumberOfWordsError": { + "message": "Gizli Kurtarma İfadeleri 12 veya 24 sƶzcükten oluşur" + }, + "importSRPWordError": { + "message": "$1 sƶzcüğü yanlış veya yanlış yazılmış.", + "description": "$1 is the word that is incorrect or misspelled" + }, + "importSRPWordErrorAlternative": { + "message": "$1 ve $2 sƶzcükleri yanlış veya yanlış yazılmış.", + "description": "$1 and $2 are multiple words that are mispelled." + }, + "importSecretRecoveryPhrase": { + "message": "Gizli Kurtarma İfadesini İƧe Aktar" + }, "importSelectedTokens": { "message": "SeƧilen tokenleri iƧe aktar?" }, @@ -2280,6 +2460,12 @@ "importTokensError": { "message": "Tokenleri iƧe aktaramadık. Lütfen daha sonra tekrar deneyin." }, + "importWallet": { + "message": "Cüzdanı iƧe aktar" + }, + "importWalletOrAccountHeader": { + "message": "Bir cüzdanı veya hesabı iƧe aktar" + }, "importWithCount": { "message": "$1 tokeni iƧe aktar", "description": "$1 will the number of detected tokens that are selected for importing, if all of them are selected then $1 will be all" @@ -2327,6 +2513,12 @@ "insufficientFundsForGas": { "message": "Gaz iƧin para yetersiz" }, + "insufficientLockedLiquidityDescription": { + "message": "Yeterince kilitlenmemiş veya kalıcı olarak kullanılmamış likidite eksikliği token'ı ani likidite Ƨekimlerine karşı savunmasız bırakır ve potansiyel olarak piyasa istikrarsızlığına neden olur." + }, + "insufficientLockedLiquidityTitle": { + "message": "Yetersiz Kilitlenmiş Likidite" + }, "insufficientTokens": { "message": "Token yetersiz." }, @@ -2362,6 +2554,9 @@ "invalidCustomNetworkAlertTitle": { "message": "Ɩzel ağ geƧersiz" }, + "invalidHexData": { + "message": "On altılı veri geƧersiz" + }, "invalidHexNumber": { "message": "On altılı sayı geƧersiz." }, @@ -2540,6 +2735,9 @@ "ledgerLocked": { "message": "Ledger cihazına bağlanılamıyor. Lütfen cihazınızın kilidinin aƧık ve Ethereum uygulamasının aƧık olduğundan emin olun." }, + "ledgerMultipleDevicesUnsupportedErrorMessage": { + "message": "Aynı anda birden fazla Ledger cihazı bağlanabilir. Yeni bir Ledger cihazı bağlamak iƧin ƶnceki cihazın bağlantısını kesmeniz gerekecek." + }, "ledgerTimeout": { "message": "Ledger Live'ın yanıt vermesi Ƨok uzun sürdü ya da bağlantı zaman aşımına uğradı. Ledger Live uygulamasının aƧık olduğundan ve cihazınızın kilidinin aƧık olduğundan emin olun." }, @@ -2637,6 +2835,9 @@ "manageDefaultSettings": { "message": "Varsayılan gizlilik ayarlarını yƶnet" }, + "managePermissions": { + "message": "İzinleri yƶnet" + }, "marketCap": { "message": "Piyasa değeri" }, @@ -2755,6 +2956,15 @@ "multichainAddEthereumChainConfirmationDescription": { "message": "Bu ağı MetaMask'e ekliyor ve bu siteye ağı kullanma izni veriyorsunuz." }, + "multichainQuoteCardBridgingLabel": { + "message": "Kƶprü" + }, + "multichainQuoteCardQuoteLabel": { + "message": "Fiyat Teklifi" + }, + "multichainQuoteCardTimeLabel": { + "message": "Zaman" + }, "multipleSnapConnectionWarning": { "message": "$1 $2 Snap kullanmak istiyor", "description": "$1 is the dapp and $2 is the number of snaps it wants to connect to." @@ -2869,6 +3079,13 @@ "network": { "message": "Ağ:" }, + "networkChanged": { + "message": "Ağ değişti" + }, + "networkChangedMessage": { + "message": "Şu anda $1 üzerinde işlem yapıyorsunuz.", + "description": "$1 is the name of the network" + }, "networkDetails": { "message": "Ağ bilgileri" }, @@ -3143,6 +3360,9 @@ "notEnoughGas": { "message": "Yeterli gaz yok" }, + "notNow": { + "message": "Şimdi değil" + }, "notificationDetail": { "message": "Ayrıntılar" }, @@ -3505,6 +3725,13 @@ "origin": { "message": "Kƶken" }, + "originChanged": { + "message": "Site değişti" + }, + "originChangedMessage": { + "message": "Şu anda $1 alanından bir talebi inceliyorsunuz.", + "description": "$1 is the name of the origin" + }, "osTheme": { "message": "Sistem" }, @@ -3559,6 +3786,14 @@ "pending": { "message": "Bekleyen" }, + "pendingConfirmationAddNetworkAlertMessage": { + "message": "Ağ güncellenirse bu siteden $1 bekleyen işlem iptal edilecektir.", + "description": "Number of transactions." + }, + "pendingConfirmationSwitchNetworkAlertMessage": { + "message": "Ağ değiştirilirse bu siteden $1 bekleyen işlem iptal edilecektir.", + "description": "Number of transactions." + }, "pendingTransactionAlertMessage": { "message": "Bu işlem bir ƶnceki işlem tamamlanana kadar gerƧekleşmeyecek. $1", "description": "$1 represents the words 'how to cancel or speed up a transaction' in a hyperlink" @@ -3842,6 +4077,9 @@ "permitSimulationChange_receive": { "message": "Aldığınız:" }, + "permitSimulationChange_revoke2": { + "message": "İptal" + }, "permitSimulationChange_transfer": { "message": "Gƶnderdiğiniz:" }, @@ -4237,6 +4475,9 @@ "reusedTokenNameWarning": { "message": "Buradaki bir token izlediğiniz başka bir tokenden sembol kullanıyor, bu kafa karıştırıcı veya aldatıcı olabilir." }, + "revealSecretRecoveryPhrase": { + "message": "Gizli Kurtarma İfadesini Açığa Ƈıkar" + }, "revealSeedWords": { "message": "Gizli Kurtarma İfadesini Gƶster" }, @@ -4286,12 +4527,19 @@ "reviewAlerts": { "message": "Uyarıları incele" }, + "reviewPendingTransactions": { + "message": "Bekleyen işlemleri incele" + }, "reviewPermissions": { "message": "İzinleri incele" }, "revokePermission": { "message": "İzni geri al" }, + "revokePermissionTitle": { + "message": "$1 iznini kaldır", + "description": "The token symbol that is being revoked" + }, "revokeSimulationDetailsDesc": { "message": "Birisinin sizin hesabınızdan token harcama iznini kaldırıyorsunuz." }, @@ -4334,6 +4582,10 @@ "secretRecoveryPhrase": { "message": "Gizli Kurtarma İfadesi" }, + "secretRecoveryPhrasePlusNumber": { + "message": "Gizli Kurtarma İfadesi $1", + "description": "The $1 is the order of the Secret Recovery Phrase" + }, "secureWallet": { "message": "Güvenli cüzdan" }, @@ -4424,6 +4676,9 @@ "select": { "message": "SeƧ" }, + "selectAccountToConnect": { + "message": "Bağlamak iƧin bir hesap seƧ" + }, "selectAccounts": { "message": "Bu sitede kullanılacak hesap veya hesapları seƧin" }, @@ -4454,6 +4709,9 @@ "selectRpcUrl": { "message": "RPC URL adresini seƧin" }, + "selectSecretRecoveryPhrase": { + "message": "Gizli Kurtarma İfadesi SeƧ" + }, "selectType": { "message": "Tür SeƧ" }, @@ -4565,16 +4823,6 @@ "showHexDataDescription": { "message": "Gƶnder ekranında on altılı veri alanını gƶstermek iƧin bunu seƧin" }, - "showIncomingTransactions": { - "message": "Gelen işlemleri gƶster" - }, - "showIncomingTransactionsDescription": { - "message": "Etherscan'in işlemler listesinde gelecek işlemleri gƶstermesi iƧin bunu seƧin", - "description": "$1 is the link to etherscan url and $2 is the link to the privacy policy of consensys APIs" - }, - "showIncomingTransactionsExplainer": { - "message": "Ethereum adresinizi ve IP adresinizi açığa Ƨıkaran her ağ iƧin farklı üçüncü taraf API'lerine güvenir." - }, "showLess": { "message": "Daha az gƶster" }, @@ -4593,6 +4841,9 @@ "showPrivateKey": { "message": "Ɩzel anahtarı gƶster" }, + "showSRP": { + "message": "Gizli Kurtarma İfadesini Gƶster" + }, "showTestnetNetworks": { "message": "Test ağlarını gƶster" }, @@ -4714,12 +4965,24 @@ "slideCashOutTitle": { "message": "MetaMask ile paraya Ƨevirin" }, + "slideDebitCardDescription": { + "message": "Belirli bƶlgelerde mevcuttur" + }, "slideDebitCardTitle": { "message": "MetaMask banka kartı" }, + "slideFundWalletDescription": { + "message": "Başlamak iƧin token ekleyin veya transfer edin" + }, "slideFundWalletTitle": { "message": "Cüzdanınıza para ekleyin" }, + "slideSweepStakeDescription": { + "message": "Kazanma şansı iƧin şimdi bir NFT mint edin" + }, + "slideSweepStakeTitle": { + "message": "$5000 USDC Ƈekilişine katılın!" + }, "smartContracts": { "message": "Akıllı sƶzleşmeler" }, @@ -4866,6 +5129,9 @@ "snapResultSuccessDescription": { "message": "$1 kullanıma hazır" }, + "snapUIAssetSelectorTitle": { + "message": "Bir varlık seƧ" + }, "snapUpdateAlertDescription": { "message": "En son $1 güncellemesini alın", "description": "Description used in Snap update alert banner when snap update is available. $1 is the Snap name." @@ -4925,6 +5191,27 @@ "message": "Daha fazla destek iƧin $1 oluşturucuları ile iletişime geƧin.", "description": "This is shown when the insight snap throws an error. $1 is the snap name" }, + "solanaImportAccounts": { + "message": "Solana hesaplarını iƧe aktar" + }, + "solanaImportAccountsDescription": { + "message": "Başka bir cüzdandan Solana hesabınızı taşımak iƧin bir Gizli Kurtarma İfadesini iƧe aktarın." + }, + "solanaMoreFeaturesComingSoon": { + "message": "Daha fazla ƶzellik Ƨok yakında" + }, + "solanaMoreFeaturesComingSoonDescription": { + "message": "Solana dapp'leri, NFT'ler, donanım cüzdanı desteği ve daha fazlası Ƨok yakında." + }, + "solanaOnMetaMask": { + "message": "Solana MetaMask'te" + }, + "solanaSendReceiveSwapTokens": { + "message": "Token gƶnder, al ve swap yap" + }, + "solanaSendReceiveSwapTokensDescription": { + "message": "SOL, USDC ve daha fazlası gibi token'lar ile transfer ve işlem gerƧekleştir." + }, "someNetworks": { "message": "$1 ağ" }, @@ -4951,6 +5238,21 @@ "source": { "message": "Kaynak" }, + "spamModalBlockedDescription": { + "message": "Bu site 1 dakika boyunca engellenecek." + }, + "spamModalBlockedTitle": { + "message": "Bu siteyi geƧici olarak engellediniz" + }, + "spamModalDescription": { + "message": "Birden fazla istenmeyen talep alıyorsanız siteyi geƧici olarak engelleyebilirsiniz." + }, + "spamModalTemporaryBlockButton": { + "message": "Bu siteyi geƧici olarak engelle" + }, + "spamModalTitle": { + "message": "Birden fazla talep fark ettik" + }, "speed": { "message": "Hız" }, @@ -5000,10 +5302,28 @@ "spendingCap": { "message": "Harcama üst limiti" }, + "spendingCaps": { + "message": "Harcama üst limitleri" + }, "srpInputNumberOfWords": { "message": "$1 sƶzcükten oluşan bir ifadem var", "description": "This is the text for each option in the dropdown where a user selects how many words their secret recovery phrase has during import. The $1 is the number of words (either 12, 15, 18, 21, or 24)." }, + "srpListName": { + "message": "Gizli Kurtarma İfadesi $1", + "description": "$1 is the order of the Secret Recovery Phrase" + }, + "srpListNumberOfAccounts": { + "message": "$1 hesap", + "description": "$1 is the number of accounts in the list" + }, + "srpListSelectionDescription": { + "message": "Yeni hesabınızın oluşturulacağı Gizli Kurtarma İfadesi" + }, + "srpListSingleOrZero": { + "message": "$1 hesap", + "description": "$1 is the number of accounts in the list, it is either 1 or 0" + }, "srpPasteFailedTooManyWords": { "message": "24'ten fazla sƶzcük iƧerdiği iƧin yapıştırma başarısız oldu. Gizli bir kurtarma ifadesi en fazla 24 sƶzcükten oluşabilir.", "description": "Description of SRP paste error when the pasted content has too many words" @@ -5158,6 +5478,9 @@ "message": "Ani piyasa değişiklikleri başarısızlıklara neden olabilir. Sorun devam ederse lütfen $1 ile iletişime geƧ.", "description": "This message is shown to a user if their swap fails. The $1 will be replaced by support.metamask.io" }, + "stxOptInSupportedNetworksDescription": { + "message": "Desteklenen ağlarda daha güvenilir ve güvenli işlemler iƧin Akıllı İşlemleri aƧın. $1" + }, "stxPendingPrivatelySubmittingSwap": { "message": "Swap işlemin ƶzel olarak gƶnderiliyor..." }, @@ -5977,6 +6300,12 @@ "message": "NFT (ERC-721) tokenlerin gƶnderilmesi şu anda desteklenmiyor", "description": "This is an error message we show the user if they attempt to send an NFT asset type, for which currently don't support sending" }, + "unstableTokenPriceDescription": { + "message": "Bu token'ın USD cinsinden fiyatı son derece değişken olup bununla etkileşimde bulunulursa büyük ƶlçüde değer kaybetmeye yƶnelik yüksek risk gƶsteriyor." + }, + "unstableTokenPriceTitle": { + "message": "İstikrarsız Token Fiyatı" + }, "upArrow": { "message": "yukarı ok" }, @@ -6099,6 +6428,18 @@ "visitSite": { "message": "Siteyi ziyaret edin" }, + "visitSupportDataConsentModalAccept": { + "message": "Onayla" + }, + "visitSupportDataConsentModalDescription": { + "message": "MetaMask Tanımlayıcınızı ve uygulama sürümünüzü Destek Merkezimizle paylaşmak ister misiniz? Probleminizi daha iyi bir şekilde Ƨƶzmemize yardımcı olabilir ancak isteğe bağlıdır." + }, + "visitSupportDataConsentModalReject": { + "message": "Paylaşma" + }, + "visitSupportDataConsentModalTitle": { + "message": "Cihaz bilgilerini destek ile paylaş" + }, "visitWebSite": { "message": "Web sitemizi ziyaret et" }, diff --git a/app/_locales/vi/messages.json b/app/_locales/vi/messages.json index fb0ce8b20c89..9cac4f28ba1b 100644 --- a/app/_locales/vi/messages.json +++ b/app/_locales/vi/messages.json @@ -44,6 +44,20 @@ "QRHardwareWalletSteps2Description": { "message": "Ngrave Zero" }, + "SrpListHideAccounts": { + "message": "įŗØn $1 tĆ i khoįŗ£n", + "description": "$1 is the number of accounts" + }, + "SrpListHideSingleAccount": { + "message": "įŗØn 1 tĆ i khoįŗ£n" + }, + "SrpListShowAccounts": { + "message": "Hiển thị $1 tĆ i khoįŗ£n", + "description": "$1 is the number of accounts" + }, + "SrpListShowSingleAccount": { + "message": "Hiển thị 1 tĆ i khoįŗ£n" + }, "about": { "message": "Giį»›i thiệu" }, @@ -76,6 +90,9 @@ "accountDetails": { "message": "Chi tiįŗæt tĆ i khoįŗ£n" }, + "accountDetailsRevokeDelegationButton": { + "message": " Chuyển về tĆ i khoįŗ£n thĆ“ng thĘ°į»ng" + }, "accountIdenticon": { "message": "Biểu tượng nhįŗ­n dįŗ”ng tĆ i khoįŗ£n" }, @@ -153,6 +170,12 @@ "addAlias": { "message": "ThĆŖm biệt danh" }, + "addBitcoinAccountLabel": { + "message": "TĆ i khoįŗ£n Bitcoin (Beta)" + }, + "addBitcoinTestnetAccountLabel": { + "message": "TĆ i khoįŗ£n Bitcoin (Mįŗ”ng thį»­ nghiệm)" + }, "addBlockExplorer": { "message": "ThĆŖm mį»™t trƬnh khĆ”m phĆ” khối" }, @@ -193,6 +216,9 @@ "addFriendsAndAddresses": { "message": "ThĆŖm bįŗ”n bĆØ vĆ  địa chỉ mĆ  bįŗ”n tin tưởng" }, + "addHardwareWalletLabel": { + "message": "VĆ­ cứng" + }, "addIPFSGateway": { "message": "ThĆŖm cổng IPFS ʰa thĆ­ch cį»§a bįŗ”n" }, @@ -212,12 +238,26 @@ "addNewAccount": { "message": "ThĆŖm tĆ i khoįŗ£n Ethereum mį»›i" }, + "addNewEthereumAccountLabel": { + "message": "TĆ i khoįŗ£n Ethereum" + }, + "addNewSolanaAccountLabel": { + "message": "TĆ i khoįŗ£n Solana" + }, "addNft": { "message": "ThĆŖm NFT" }, "addNfts": { "message": "ThĆŖm NFT" }, + "addNonEvmAccount": { + "message": "ThĆŖm tĆ i khoįŗ£n $1", + "description": "$1 is the non EVM network where the account is going to be created, e.g. Bitcoin or Solana" + }, + "addNonEvmAccountFromNetworkPicker": { + "message": "Để kĆ­ch hoįŗ”t mįŗ”ng $1, bįŗ”n cįŗ§n tįŗ”o tĆ i khoįŗ£n $2.", + "description": "$1 is the non EVM network where the account is going to be created, e.g. Solana Mainnet or Solana Devnet. $2 is the account type, e.g. Bitcoin or Solana" + }, "addRpcUrl": { "message": "ThĆŖm URL RPC" }, @@ -300,14 +340,16 @@ "advancedPriorityFeeToolTip": { "message": "PhĆ­ ʰu tiĆŖn (hay còn được gį»i lĆ  \"tiền thưởng cho thợ đƠo\") được chuyển trį»±c tiįŗæp cho cĆ”c thợ đƠo vĆ  khuyįŗæn khĆ­ch hį» ʰu tiĆŖn giao dịch cį»§a bįŗ”n." }, - "aggregatedBalancePopover": { - "message": "Điều nĆ y phįŗ£n Ć”nh giĆ” trị cį»§a tįŗ„t cįŗ£ cĆ”c token mĆ  bįŗ”n sở hữu trĆŖn mį»™t mįŗ”ng nhįŗ„t định. Nįŗæu bįŗ”n muốn xem giĆ” trị nĆ y bįŗ±ng ETH hoįŗ·c cĆ”c loįŗ”i tiền tệ khĆ”c, hĆ£y truy cįŗ­p $1.", - "description": "$1 represents the settings page" - }, "agreeTermsOfUse": { "message": "TĆ“i đồng ý vį»›i $1 cį»§a MetaMask", "description": "$1 is the `terms` link" }, + "airDropPatternDescription": { + "message": "Lịch sį»­ trĆŖn chuį»—i cį»§a token cho thįŗ„y trước đây đã từng có hoįŗ”t động tįŗ·ng thưởng đƔng ngį»." + }, + "airDropPatternTitle": { + "message": "MĆ“ hƬnh tįŗ·ng thưởng" + }, "airgapVault": { "message": "AirGap Vault" }, @@ -726,9 +768,21 @@ "bridgeConfirmTwoTransactions": { "message": "Bįŗ”n sįŗ½ cįŗ§n xĆ”c nhįŗ­n 2 giao dịch trĆŖn vĆ­ cứng cį»§a mƬnh:" }, + "bridgeCreateSolanaAccount": { + "message": "Tįŗ”o tĆ i khoįŗ£n Solana" + }, + "bridgeCreateSolanaAccountDescription": { + "message": "Để hoĆ”n đổi sang mįŗ”ng Solana, bįŗ”n cįŗ§n có tĆ i khoįŗ£n vĆ  địa chỉ nhįŗ­n." + }, + "bridgeCreateSolanaAccountTitle": { + "message": "Bįŗ”n sįŗ½ cįŗ§n có tĆ i khoįŗ£n Solana trước." + }, "bridgeEnterAmount": { "message": "Nhįŗ­p số tiền" }, + "bridgeEnterAmountAndSelectAccount": { + "message": "Nhįŗ­p số tiền vĆ  chį»n tĆ i khoįŗ£n đƭch" + }, "bridgeExplorerLinkViewOn": { "message": "Xem trĆŖn $1" }, @@ -751,9 +805,15 @@ "bridgeQuoteExpired": { "message": "BĆ”o giĆ” cį»§a bįŗ”n đã hįŗæt hįŗ”n." }, + "bridgeSelectDestinationAccount": { + "message": "Chį»n tĆ i khoįŗ£n đƭch" + }, "bridgeSelectNetwork": { "message": "Chį»n mįŗ”ng" }, + "bridgeSelectTokenAmountAndAccount": { + "message": "Chį»n token, số tiền vĆ  tĆ i khoįŗ£n đƭch" + }, "bridgeSelectTokenAndAmount": { "message": "Chį»n token vĆ  số tiền" }, @@ -944,6 +1004,12 @@ "message": "KhĆ“ng tƬm thįŗ„y tùy chį»n nĆ o", "description": "Default text shown in the combo field dropdown if no options." }, + "concentratedSupplyDistributionDescription": { + "message": "Phįŗ§n lį»›n nguồn cung token được những ngĘ°į»i nįŗÆm giữ token hĆ ng đầu nįŗÆm giữ, gĆ¢y rį»§i ro thao tĆŗng giĆ” tįŗ­p trung" + }, + "concentratedSupplyDistributionTitle": { + "message": "PhĆ¢n bổ nguồn cung tįŗ­p trung" + }, "configureSnapPopupDescription": { "message": "BĆ¢y giį» bįŗ”n đang rį»i MetaMask Ä‘į»ƒ định cįŗ„u hƬnh Snap nĆ y." }, @@ -962,6 +1028,15 @@ "confirm": { "message": "XĆ”c nhįŗ­n" }, + "confirmAccountType": { + "message": "Loįŗ”i" + }, + "confirmAccountTypeSmartContract": { + "message": "TĆ i khoįŗ£n thĆ“ng minh" + }, + "confirmAccountTypeStandard": { + "message": "TĆ i khoįŗ£n tiĆŖu chuįŗ©n" + }, "confirmAlertModalAcknowledgeMultiple": { "message": "TĆ“i đã hiểu rƵ cĆ”c cįŗ£nh bĆ”o vĆ  vįŗ«n muốn tiįŗæp tỄc" }, @@ -974,12 +1049,36 @@ "confirmFieldTooltipPaymaster": { "message": "PhĆ­ cho giao dịch nĆ y sįŗ½ được thanh toĆ”n bởi hợp đồng thĆ“ng minh Paymaster." }, + "confirmGasFeeTokenBalance": { + "message": "Số dʰ:" + }, + "confirmGasFeeTokenInsufficientBalance": { + "message": "KhĆ“ng đủ tiền" + }, + "confirmGasFeeTokenMetaMaskFee": { + "message": "Bao gồm phĆ­ $1" + }, + "confirmGasFeeTokenModalTitle": { + "message": "Chį»n mį»™t token" + }, + "confirmGasFeeTokenToast": { + "message": "Bįŗ”n đang thanh toĆ”n phĆ­ mįŗ”ng nĆ y bįŗ±ng $1" + }, + "confirmGasFeeTokenTooltip": { + "message": "Khoįŗ£n nĆ y được thanh toĆ”n cho mįŗ”ng Ä‘į»ƒ xį»­ lý giao dịch cį»§a bįŗ”n. Bao gồm phĆ­ $1 cį»§a MetaMask cho cĆ”c token khĆ“ng phįŗ£i ETH." + }, + "confirmNestedTransactionTitle": { + "message": "Giao dịch $1" + }, "confirmPassword": { "message": "XĆ”c nhįŗ­n mįŗ­t khįŗ©u" }, "confirmRecoveryPhrase": { "message": "XĆ”c nhįŗ­n CỄm từ khĆ“i phỄc bĆ­ mįŗ­t" }, + "confirmSimulationApprove": { + "message": "Bįŗ”n chįŗ„p thuįŗ­n" + }, "confirmTitleApproveTransactionNFT": { "message": "YĆŖu cįŗ§u rĆŗt tiền" }, @@ -1022,9 +1121,24 @@ "confirmTitleTransaction": { "message": "YĆŖu cįŗ§u giao dịch" }, + "confirmUpgradeCancelModalButtonCancelTransaction": { + "message": "Hį»§y giao dịch" + }, + "confirmUpgradeCancelModalButtonCancelUpgrade": { + "message": "Hį»§y cįŗ­p nhįŗ­t & giao dịch" + }, + "confirmUpgradeCancelModalDescription": { + "message": "Nįŗæu bįŗ”n khĆ“ng muốn cįŗ­p nhįŗ­t tĆ i khoįŗ£n cį»§a mƬnh, bįŗ”n có thể hį»§y tįŗ”i đây.\n\nĐể hoĆ n tįŗ„t giao dịch nĆ y mĆ  khĆ“ng cįŗ­p nhįŗ­t, bįŗ”n sįŗ½ cįŗ§n thį»±c hiện lįŗ”i yĆŖu cįŗ§u nĆ y trĆŖn trang web. $1." + }, + "confirmUpgradeCancelModalTitle": { + "message": "Hį»§y giao dịch" + }, "confirmationAlertDetails": { "message": "Để bįŗ£o vệ tĆ i sįŗ£n cį»§a bįŗ”n, chĆŗng tĆ“i đề nghị bįŗ”n từ chối yĆŖu cįŗ§u nĆ y." }, + "confirmationAlertModalTitleDescription": { + "message": "TĆ i sįŗ£n cį»§a bįŗ”n có thể gįŗ·p rį»§i ro" + }, "confirmed": { "message": "Đã xĆ”c nhįŗ­n" }, @@ -1052,6 +1166,9 @@ "connectAccounts": { "message": "Kįŗæt nối tĆ i khoįŗ£n" }, + "connectAnAccountHeader": { + "message": "Kįŗæt nối tĆ i khoįŗ£n" + }, "connectManually": { "message": "Kįŗæt nối thį»§ cĆ“ng vį»›i trang web hiện tįŗ”i" }, @@ -1158,6 +1275,9 @@ "message": "TƬm nįŗ”p $1 thįŗ„t bįŗ”i, hĆ£y kiểm tra mįŗ”ng cį»§a bįŗ”n vĆ  thį»­ lįŗ”i.", "description": "$1 is the name of the snap being fetched." }, + "connectionPopoverDescription": { + "message": "Để kįŗæt nối vį»›i trang web, hĆ£y chį»n nĆŗt kįŗæt nối. MetaMask chỉ có thể kįŗæt nối vį»›i cĆ”c trang web web3." + }, "connectionRequest": { "message": "YĆŖu cįŗ§u kįŗæt nối" }, @@ -1219,6 +1339,9 @@ "create": { "message": "Tįŗ”o" }, + "createNewAccountHeader": { + "message": "Tįŗ”o tĆ i khoįŗ£n mį»›i" + }, "createNewWallet": { "message": "Tįŗ”o vĆ­ mį»›i" }, @@ -1231,6 +1354,9 @@ "createSnapAccountTitle": { "message": "Tįŗ”o tĆ i khoįŗ£n" }, + "createSolanaAccount": { + "message": "Tįŗ”o tĆ i khoįŗ£n Solana" + }, "creatorAddress": { "message": "Địa chỉ cį»§a ngĘ°į»i tįŗ”o" }, @@ -1471,6 +1597,21 @@ "message": "MĆ“ tįŗ£ từ $1", "description": "$1 represents the name of the snap" }, + "destinationAccountPickerNoEligible": { + "message": "KhĆ“ng tƬm thįŗ„y tĆ i khoįŗ£n đủ điều kiện" + }, + "destinationAccountPickerNoMatching": { + "message": "KhĆ“ng tƬm thįŗ„y tĆ i khoįŗ£n trùng khį»›p" + }, + "destinationAccountPickerReceiveAt": { + "message": "Nhįŗ­n tįŗ”i" + }, + "destinationAccountPickerSearchPlaceholderToMainnet": { + "message": "Địa chỉ nhįŗ­n hoįŗ·c ENS" + }, + "destinationAccountPickerSearchPlaceholderToSolana": { + "message": "Địa chỉ nhįŗ­n" + }, "details": { "message": "Chi tiįŗæt" }, @@ -1516,6 +1657,9 @@ "message": "Đã ngįŗÆt kįŗæt nối $1 khį»i $2", "description": "$1 is name of the name and $2 represents the dapp name`" }, + "discover": { + "message": "KhĆ”m phĆ”" + }, "discoverSnaps": { "message": "KhĆ”m phĆ” Snap", "description": "Text that links to the Snaps website. Displayed in a banner on Snaps list page in settings." @@ -1872,6 +2016,9 @@ "experimental": { "message": "Thį»­ nghiệm" }, + "exploreweb3": { + "message": "KhĆ”m phĆ” web3" + }, "exportYourData": { "message": "Xuįŗ„t dữ liệu cį»§a bįŗ”n" }, @@ -1885,6 +2032,9 @@ "message": "KhĆ”m phĆ” cĆ”c Snap do cį»™ng đồng xĆ¢y dį»±ng Ä‘į»ƒ tùy chỉnh trįŗ£i nghiệm web3 cį»§a bįŗ”n", "description": "Banner description displayed on Snaps list page in Settings when less than 6 Snaps is installed." }, + "externalAccount": { + "message": "TĆ i khoįŗ£n bĆŖn ngoĆ i" + }, "externalExtension": { "message": "Tiện Ć­ch bĆŖn ngoĆ i" }, @@ -2197,6 +2347,12 @@ "holdToRevealUnlockedLabel": { "message": "giữ Ä‘į»ƒ hiển thị vòng tròn được mở khóa" }, + "honeypotDescription": { + "message": "Token nĆ y có thể tiềm įŗ©n rį»§i ro honeypot (bįŗ«y trong bįŗ«y). Bįŗ”n nĆŖn thįŗ©m định kỹ trước khi tʰʔng tĆ”c Ä‘į»ƒ trĆ”nh thiệt hįŗ”i tĆ i chĆ­nh." + }, + "honeypotTitle": { + "message": "Honey Pot (Bįŗ«y trong bįŗ«y)" + }, "howNetworkFeesWorkExplanation": { "message": "PhĆ­ ước tĆ­nh cįŗ§n thiįŗæt Ä‘į»ƒ xį»­ lý giao dịch. PhĆ­ tối đa lĆ  $1." }, @@ -2262,6 +2418,30 @@ "importNFTTokenIdToolTip": { "message": "ID cį»§a NFT lĆ  mį»™t mĆ£ nhįŗ­n dįŗ”ng duy nhįŗ„t vƬ khĆ“ng có hai NFT nĆ o giống hệt nhau. Mį»™t lįŗ§n nữa, trĆŖn OpenSea, mĆ£ số nĆ y nįŗ±m bĆŖn dưới mỄc \"Chi tiįŗæt\". HĆ£y ghi chĆŗ lįŗ”i hoįŗ·c sao chĆ©p vĆ o bį»™ nhį»› đệm." }, + "importNWordSRP": { + "message": "TĆ“i có cỄm từ khĆ“i phỄc gồm $1 từ", + "description": "$1 is the number of words in the recovery phrase" + }, + "importPrivateKey": { + "message": "Khóa riĆŖng tʰ" + }, + "importSRPDescription": { + "message": "Nhįŗ­p vĆ­ hiện có bįŗ±ng cỄm từ khĆ“i phỄc gồm 12 hoįŗ·c 24 từ cį»§a bįŗ”n." + }, + "importSRPNumberOfWordsError": { + "message": "CỄm từ khĆ“i phỄc bĆ­ mįŗ­t gồm 12 hoįŗ·c 24 từ" + }, + "importSRPWordError": { + "message": "Từ $1 khĆ“ng đúng hoįŗ·c sai chĆ­nh tįŗ£.", + "description": "$1 is the word that is incorrect or misspelled" + }, + "importSRPWordErrorAlternative": { + "message": "Từ $1 vĆ  $2 khĆ“ng đúng hoįŗ·c sai chĆ­nh tįŗ£.", + "description": "$1 and $2 are multiple words that are mispelled." + }, + "importSecretRecoveryPhrase": { + "message": "Nhįŗ­p CỄm từ khĆ“i phỄc bĆ­ mįŗ­t" + }, "importSelectedTokens": { "message": "Nhįŗ­p cĆ”c token đã chį»n?" }, @@ -2280,6 +2460,12 @@ "importTokensError": { "message": "ChĆŗng tĆ“i khĆ“ng thể nhįŗ­p token. Vui lòng thį»­ lįŗ”i sau." }, + "importWallet": { + "message": "Nhįŗ­p vĆ­" + }, + "importWalletOrAccountHeader": { + "message": "Nhįŗ­p vĆ­ hoįŗ·c tĆ i khoįŗ£n" + }, "importWithCount": { "message": "Nhįŗ­p $1", "description": "$1 will the number of detected tokens that are selected for importing, if all of them are selected then $1 will be all" @@ -2327,6 +2513,12 @@ "insufficientFundsForGas": { "message": "KhĆ“ng đủ tiền thanh toĆ”n phĆ­ gas" }, + "insufficientLockedLiquidityDescription": { + "message": "Việc thiįŗæu tĆ­nh thanh khoįŗ£n bị khóa hoįŗ·c đốt hợp lý khiįŗæn token dį»… bị rĆŗt thanh khoįŗ£n đột ngį»™t, có thể gĆ¢y bįŗ„t ổn thị trĘ°į»ng." + }, + "insufficientLockedLiquidityTitle": { + "message": "TĆ­nh thanh khoįŗ£n bị khóa khĆ“ng đủ" + }, "insufficientTokens": { "message": "KhĆ“ng đủ token." }, @@ -2362,6 +2554,9 @@ "invalidCustomNetworkAlertTitle": { "message": "Mįŗ”ng tùy chỉnh khĆ“ng hợp lệ" }, + "invalidHexData": { + "message": "Dữ liệu thįŗ­p lỄc phĆ¢n khĆ“ng hợp lệ" + }, "invalidHexNumber": { "message": "Số thįŗ­p lỄc phĆ¢n khĆ“ng hợp lệ." }, @@ -2540,6 +2735,9 @@ "ledgerLocked": { "message": "KhĆ“ng thể kįŗæt nối vį»›i thiįŗæt bị Ledger. Vui lòng đảm bįŗ£o bįŗ”n đã mở khóa thiįŗæt bị vĆ  mở ứng dỄng Ethereum." }, + "ledgerMultipleDevicesUnsupportedErrorMessage": { + "message": "KhĆ“ng thể kįŗæt nối nhiều thiįŗæt bị Ledger cùng lĆŗc. Để kįŗæt nối thiįŗæt bị Ledger mį»›i, trước tiĆŖn bįŗ”n cįŗ§n ngįŗÆt kįŗæt nối thiįŗæt bị trước đó." + }, "ledgerTimeout": { "message": "Ledger Live mįŗ„t quĆ” nhiều thį»i gian Ä‘į»ƒ phįŗ£n hồi hoįŗ·c đã hįŗæt thį»i gian chį» kįŗæt nối. HĆ£y đảm bįŗ£o bįŗ”n đã mở ứng dỄng Ledger Live vĆ  đã mở khóa thiįŗæt bị." }, @@ -2637,6 +2835,9 @@ "manageDefaultSettings": { "message": "Quįŗ£n lý chįŗæ độ cĆ i đặt quyền riĆŖng tʰ mįŗ·c định" }, + "managePermissions": { + "message": "Quįŗ£n lý quyền" + }, "marketCap": { "message": "Vốn hóa thị trĘ°į»ng" }, @@ -2755,6 +2956,15 @@ "multichainAddEthereumChainConfirmationDescription": { "message": "Bįŗ”n đang thĆŖm mįŗ”ng nĆ y vĆ o MetaMask vĆ  cįŗ„p cho trang web nĆ y quyền sį»­ dỄng mįŗ”ng nĆ y." }, + "multichainQuoteCardBridgingLabel": { + "message": "Cįŗ§u nối" + }, + "multichainQuoteCardQuoteLabel": { + "message": "BĆ”o giĆ”" + }, + "multichainQuoteCardTimeLabel": { + "message": "Thį»i gian" + }, "multipleSnapConnectionWarning": { "message": "$1 muốn sį»­ dỄng $2 Snap", "description": "$1 is the dapp and $2 is the number of snaps it wants to connect to." @@ -2869,6 +3079,13 @@ "network": { "message": "Mįŗ”ng:" }, + "networkChanged": { + "message": "Đã thay đổi mįŗ”ng" + }, + "networkChangedMessage": { + "message": "Bįŗ”n hiện đang giao dịch trĆŖn $1.", + "description": "$1 is the name of the network" + }, "networkDetails": { "message": "ThĆ“ng tin về mįŗ”ng" }, @@ -3143,6 +3360,9 @@ "notEnoughGas": { "message": "KhĆ“ng đủ phĆ­ gas" }, + "notNow": { + "message": "KhĆ“ng phįŗ£i bĆ¢y giį»" + }, "notificationDetail": { "message": "Chi tiįŗæt" }, @@ -3505,6 +3725,13 @@ "origin": { "message": "Nguồn gốc" }, + "originChanged": { + "message": "Đã thay đổi trang web" + }, + "originChangedMessage": { + "message": "Bįŗ”n hiện đang xem xĆ©t mį»™t yĆŖu cįŗ§u từ $1.", + "description": "$1 is the name of the origin" + }, "osTheme": { "message": "Hệ thống" }, @@ -3559,6 +3786,14 @@ "pending": { "message": "Đang chį» xį»­ lý" }, + "pendingConfirmationAddNetworkAlertMessage": { + "message": "Nįŗæu bįŗ”n cįŗ­p nhįŗ­t mįŗ”ng, giao dịch $1 đang chį» xį»­ lý từ trang web nĆ y sįŗ½ bị hį»§y.", + "description": "Number of transactions." + }, + "pendingConfirmationSwitchNetworkAlertMessage": { + "message": "Nįŗæu bįŗ”n chuyển mįŗ”ng, giao dịch $1 đang chį» xį»­ lý từ trang web nĆ y sįŗ½ bị hį»§y.", + "description": "Number of transactions." + }, "pendingTransactionAlertMessage": { "message": "Giao dịch nĆ y sįŗ½ khĆ“ng được thį»±c hiện cho đến khi mį»™t giao dịch trước đó hoĆ n thĆ nh. $1", "description": "$1 represents the words 'how to cancel or speed up a transaction' in a hyperlink" @@ -3842,6 +4077,9 @@ "permitSimulationChange_receive": { "message": "Bįŗ”n nhįŗ­n được" }, + "permitSimulationChange_revoke2": { + "message": "Thu hồi" + }, "permitSimulationChange_transfer": { "message": "Bįŗ”n gį»­i" }, @@ -4237,6 +4475,9 @@ "reusedTokenNameWarning": { "message": "Mį»™t token trong đây sį»­ dỄng lįŗ”i ký hiệu cį»§a mį»™t token khĆ”c mĆ  bįŗ”n thįŗ„y, điều nĆ y có thể gĆ¢y nhįŗ§m lįŗ«n hoįŗ·c mang tĆ­nh lừa dối." }, + "revealSecretRecoveryPhrase": { + "message": "Hiện CỄm từ khĆ“i phỄc bĆ­ mįŗ­t" + }, "revealSeedWords": { "message": "Hiện CỄm từ khĆ“i phỄc bĆ­ mįŗ­t" }, @@ -4286,12 +4527,19 @@ "reviewAlerts": { "message": "Xem lįŗ”i cįŗ£nh bĆ”o" }, + "reviewPendingTransactions": { + "message": "Xem xĆ©t cĆ”c giao dịch đang chį» xį»­ lý" + }, "reviewPermissions": { "message": "Xem lįŗ”i quyền" }, "revokePermission": { "message": "Thu hồi quyền" }, + "revokePermissionTitle": { + "message": "Xóa quyền $1", + "description": "The token symbol that is being revoked" + }, "revokeSimulationDetailsDesc": { "message": "Bįŗ”n đang xóa quyền chi tiĆŖu token cį»§a ngĘ°į»i khĆ”c khį»i tĆ i khoįŗ£n cį»§a bįŗ”n." }, @@ -4334,6 +4582,10 @@ "secretRecoveryPhrase": { "message": "CỄm từ khĆ“i phỄc bĆ­ mįŗ­t" }, + "secretRecoveryPhrasePlusNumber": { + "message": "CỄm từ khĆ“i phỄc bĆ­ mįŗ­t $1", + "description": "The $1 is the order of the Secret Recovery Phrase" + }, "secureWallet": { "message": "VĆ­ an toĆ n" }, @@ -4424,6 +4676,9 @@ "select": { "message": "Chį»n" }, + "selectAccountToConnect": { + "message": "Chį»n tĆ i khoįŗ£n Ä‘į»ƒ kįŗæt nối" + }, "selectAccounts": { "message": "Chį»n (cĆ”c) tĆ i khoįŗ£n Ä‘į»ƒ sį»­ dỄng trĆŖn trang web nĆ y" }, @@ -4454,6 +4709,9 @@ "selectRpcUrl": { "message": "Chį»n URL RPC" }, + "selectSecretRecoveryPhrase": { + "message": "Chį»n CỄm từ khĆ“i phỄc bĆ­ mįŗ­t" + }, "selectType": { "message": "Chį»n loįŗ”i" }, @@ -4565,16 +4823,6 @@ "showHexDataDescription": { "message": "Chį»n tùy chį»n nĆ y Ä‘į»ƒ hiển thị trĘ°į»ng dữ liệu thįŗ­p lỄc phĆ¢n trĆŖn mĆ n hƬnh gį»­i" }, - "showIncomingTransactions": { - "message": "Hiển thị cĆ”c giao dịch đến" - }, - "showIncomingTransactionsDescription": { - "message": "Chį»n tùy chį»n nĆ y nįŗæu bįŗ”n muốn dùng Etherscan Ä‘į»ƒ hiển thị cĆ”c giao dịch đến trong danh sĆ”ch giao dịch", - "description": "$1 is the link to etherscan url and $2 is the link to the privacy policy of consensys APIs" - }, - "showIncomingTransactionsExplainer": { - "message": "Điều nĆ y dį»±a trĆŖn cĆ”c API khĆ”c nhau cį»§a bĆŖn thứ ba cho mį»—i mįŗ”ng, có thể lĆ m lį»™ địa chỉ Ethereum vĆ  địa chỉ IP cį»§a bįŗ”n." - }, "showLess": { "message": "Thu gį»n" }, @@ -4593,6 +4841,9 @@ "showPrivateKey": { "message": "Hiển thị khóa riĆŖng tʰ" }, + "showSRP": { + "message": "Hiển thị CỄm mįŗ­t khįŗ©u khĆ“i phỄc bĆ­ mįŗ­t" + }, "showTestnetNetworks": { "message": "Hiển thị cĆ”c mįŗ”ng thį»­ nghiệm" }, @@ -4714,12 +4965,24 @@ "slideCashOutTitle": { "message": "RĆŗt tiền vį»›i MetaMask" }, + "slideDebitCardDescription": { + "message": "Có sįŗµn ở mį»™t số khu vį»±c được chį»n" + }, "slideDebitCardTitle": { "message": "Thįŗ» ghi nợ MetaMask" }, + "slideFundWalletDescription": { + "message": "ThĆŖm hoįŗ·c chuyển token Ä‘į»ƒ bįŗÆt đầu" + }, "slideFundWalletTitle": { "message": "Nįŗ”p tiền vĆ o vĆ­ cį»§a bįŗ”n" }, + "slideSweepStakeDescription": { + "message": "Đúc NFT ngay Ä‘į»ƒ có cĘ” hį»™i trĆŗng thưởng" + }, + "slideSweepStakeTitle": { + "message": "Tham gia chʰʔng trƬnh Tįŗ·ng thưởng $5000 USDC!" + }, "smartContracts": { "message": "Hợp đồng thĆ“ng minh" }, @@ -4866,6 +5129,9 @@ "snapResultSuccessDescription": { "message": "$1 đã sįŗµn sĆ ng Ä‘į»ƒ sį»­ dỄng" }, + "snapUIAssetSelectorTitle": { + "message": "Chį»n tĆ i sįŗ£n" + }, "snapUpdateAlertDescription": { "message": "Tįŗ£i phiĆŖn bįŗ£n mį»›i nhįŗ„t cį»§a $1", "description": "Description used in Snap update alert banner when snap update is available. $1 is the Snap name." @@ -4925,6 +5191,27 @@ "message": "LiĆŖn hệ vį»›i những ngĘ°į»i tįŗ”o ra $1 Ä‘į»ƒ được hį»— trợ thĆŖm.", "description": "This is shown when the insight snap throws an error. $1 is the snap name" }, + "solanaImportAccounts": { + "message": "Nhįŗ­p tĆ i khoįŗ£n Solana" + }, + "solanaImportAccountsDescription": { + "message": "Nhįŗ­p CỄm từ khĆ“i phỄc bĆ­ mįŗ­t Ä‘į»ƒ di chuyển tĆ i khoįŗ£n Solana từ vĆ­ khĆ”c." + }, + "solanaMoreFeaturesComingSoon": { + "message": "Nhiều tĆ­nh năng khĆ”c sįŗ½ sį»›m ra mįŗÆt" + }, + "solanaMoreFeaturesComingSoonDescription": { + "message": "CĆ”c dapp Solana, NFT, hį»— trợ vĆ­ cứng, v.v. sįŗ½ sį»›m ra mįŗÆt." + }, + "solanaOnMetaMask": { + "message": "Solana trĆŖn MetaMask" + }, + "solanaSendReceiveSwapTokens": { + "message": "Gį»­i, nhįŗ­n vĆ  hoĆ”n đổi token" + }, + "solanaSendReceiveSwapTokensDescription": { + "message": "Chuyển tiền vĆ  giao dịch bįŗ±ng cĆ”c token nhʰ SOL, USDC, v.v." + }, "someNetworks": { "message": "$1 mįŗ”ng" }, @@ -4951,6 +5238,21 @@ "source": { "message": "Nguồn" }, + "spamModalBlockedDescription": { + "message": "Trang web nĆ y sįŗ½ bị chįŗ·n trong 1 phĆŗt." + }, + "spamModalBlockedTitle": { + "message": "Bįŗ”n đã tįŗ”m thį»i chįŗ·n trang web nĆ y" + }, + "spamModalDescription": { + "message": "Nįŗæu bįŗ”n đang bị spam bởi nhiều yĆŖu cįŗ§u, bįŗ”n có thể tįŗ”m thį»i chįŗ·n trang web." + }, + "spamModalTemporaryBlockButton": { + "message": "Tįŗ”m thį»i chįŗ·n trang web nĆ y" + }, + "spamModalTitle": { + "message": "ChĆŗng tĆ“i đã phĆ”t hiện có nhiều yĆŖu cįŗ§u" + }, "speed": { "message": "Tốc độ" }, @@ -5000,10 +5302,28 @@ "spendingCap": { "message": "Hįŗ”n mức chi tiĆŖu" }, + "spendingCaps": { + "message": "Hįŗ”n mức chi tiĆŖu" + }, "srpInputNumberOfWords": { "message": "TĆ“i có mį»™t cỄm từ gồm $1 từ", "description": "This is the text for each option in the dropdown where a user selects how many words their secret recovery phrase has during import. The $1 is the number of words (either 12, 15, 18, 21, or 24)." }, + "srpListName": { + "message": "CỄm từ khĆ“i phỄc bĆ­ mįŗ­t $1", + "description": "$1 is the order of the Secret Recovery Phrase" + }, + "srpListNumberOfAccounts": { + "message": "$1 tĆ i khoįŗ£n", + "description": "$1 is the number of accounts in the list" + }, + "srpListSelectionDescription": { + "message": "TĆ i khoįŗ£n mį»›i cį»§a bįŗ”n sįŗ½ được tįŗ”o từ CỄm từ khĆ“i phỄc bĆ­ mįŗ­t nĆ y" + }, + "srpListSingleOrZero": { + "message": "$1 tĆ i khoįŗ£n", + "description": "$1 is the number of accounts in the list, it is either 1 or 0" + }, "srpPasteFailedTooManyWords": { "message": "DĆ”n khĆ“ng thĆ nh cĆ“ng vƬ cỄm từ có nhiều hĘ”n 24 từ. CỄm từ khĆ“i phỄc bĆ­ mįŗ­t chỉ có tối đa 24 từ.", "description": "Description of SRP paste error when the pasted content has too many words" @@ -5158,6 +5478,9 @@ "message": "Thị trĘ°į»ng thay đổi đột ngį»™t có thể gĆ¢y thįŗ„t bįŗ”i. Nįŗæu sį»± cố vįŗ«n tiįŗæp diį»…n, vui lòng liĆŖn hệ $1.", "description": "This message is shown to a user if their swap fails. The $1 will be replaced by support.metamask.io" }, + "stxOptInSupportedNetworksDescription": { + "message": "Bįŗ­t Giao dịch thĆ“ng minh Ä‘į»ƒ có cĆ”c giao dịch đƔng tin cįŗ­y vĆ  an toĆ n hĘ”n trĆŖn cĆ”c mįŗ”ng được hį»— trợ. $1" + }, "stxPendingPrivatelySubmittingSwap": { "message": "Đang bĆ­ mįŗ­t gį»­i yĆŖu cįŗ§u HoĆ”n đổi cį»§a bįŗ”n..." }, @@ -5977,6 +6300,12 @@ "message": "Hiện khĆ“ng hį»— trợ gį»­i token NFT (ERC-721)", "description": "This is an error message we show the user if they attempt to send an NFT asset type, for which currently don't support sending" }, + "unstableTokenPriceDescription": { + "message": "GiĆ” cį»§a token nĆ y tĆ­nh theo USD rįŗ„t biįŗæn động, bįŗ”n có nguy cĘ” mįŗ„t giĆ” trị lį»›n khi tʰʔng tĆ”c vį»›i token nĆ y." + }, + "unstableTokenPriceTitle": { + "message": "GiĆ” token khĆ“ng ổn định" + }, "upArrow": { "message": "mÅ©i tĆŖn lĆŖn" }, @@ -6099,6 +6428,18 @@ "visitSite": { "message": "Truy cįŗ­p trang web" }, + "visitSupportDataConsentModalAccept": { + "message": "XĆ”c nhįŗ­n" + }, + "visitSupportDataConsentModalDescription": { + "message": "Bįŗ”n có muốn chia sįŗ» MĆ£ định danh MetaMask vĆ  phiĆŖn bįŗ£n ứng dỄng cį»§a mƬnh vį»›i Trung tĆ¢m hį»— trợ khĆ“ng? Điều nĆ y có thể giĆŗp chĆŗng tĆ“i giįŗ£i quyįŗæt vįŗ„n đề cį»§a bįŗ”n tốt hĘ”n, nhʰng khĆ“ng bįŗÆt buį»™c." + }, + "visitSupportDataConsentModalReject": { + "message": "KhĆ“ng chia sįŗ»" + }, + "visitSupportDataConsentModalTitle": { + "message": "Chia sįŗ» thĆ“ng tin thiįŗæt bị vį»›i bį»™ phįŗ­n hį»— trợ" + }, "visitWebSite": { "message": "Truy cįŗ­p trang web cį»§a chĆŗng tĆ“i" }, diff --git a/app/_locales/zh_CN/messages.json b/app/_locales/zh_CN/messages.json index 318374ab9a60..d7586173f681 100644 --- a/app/_locales/zh_CN/messages.json +++ b/app/_locales/zh_CN/messages.json @@ -44,6 +44,20 @@ "QRHardwareWalletSteps2Description": { "message": "Ngrave Zero" }, + "SrpListHideAccounts": { + "message": "隐藏 $1 个蓦户", + "description": "$1 is the number of accounts" + }, + "SrpListHideSingleAccount": { + "message": "隐藏 1 个蓦户" + }, + "SrpListShowAccounts": { + "message": "显示 $1 个蓦户", + "description": "$1 is the number of accounts" + }, + "SrpListShowSingleAccount": { + "message": "显示 1 个蓦户" + }, "about": { "message": "å…³äŗŽ" }, @@ -76,6 +90,9 @@ "accountDetails": { "message": "č“¦ęˆ·čÆ¦ęƒ…" }, + "accountDetailsRevokeDelegationButton": { + "message": " åˆ‡ę¢å›žåøøč§„č“¦ęˆ·" + }, "accountIdenticon": { "message": "蓦ꈷ Identicon" }, @@ -153,6 +170,12 @@ "addAlias": { "message": "ę·»åŠ åˆ«å" }, + "addBitcoinAccountLabel": { + "message": "ęÆ”ē‰¹åøč“¦ęˆ·ļ¼ˆęµ‹čÆ•ē‰ˆļ¼‰" + }, + "addBitcoinTestnetAccountLabel": { + "message": "ęÆ”ē‰¹åøč“¦ęˆ·ļ¼ˆęµ‹čÆ•ē½‘ļ¼‰" + }, "addBlockExplorer": { "message": "ę·»åŠ åŒŗå—ęµč§ˆå™Ø" }, @@ -193,6 +216,9 @@ "addFriendsAndAddresses": { "message": "ę·»åŠ ę‚Øäæ”ä»»ēš„ęœ‹å‹å’Œåœ°å€" }, + "addHardwareWalletLabel": { + "message": "ē”¬ä»¶é’±åŒ…" + }, "addIPFSGateway": { "message": "ę·»åŠ ę‚Øé¦–é€‰ēš„IPFS网关" }, @@ -212,12 +238,26 @@ "addNewAccount": { "message": "ę·»åŠ ę–°č“¦ęˆ·" }, + "addNewEthereumAccountLabel": { + "message": "ä»„å¤ŖåŠč“¦ęˆ·" + }, + "addNewSolanaAccountLabel": { + "message": "Solana 蓦ꈷ" + }, "addNft": { "message": "添加 NFT" }, "addNfts": { "message": "添加 NFT" }, + "addNonEvmAccount": { + "message": "添加 $1 蓦ꈷ", + "description": "$1 is the non EVM network where the account is going to be created, e.g. Bitcoin or Solana" + }, + "addNonEvmAccountFromNetworkPicker": { + "message": "要启用 $1 ē½‘ē»œļ¼Œę‚Øéœ€č¦åˆ›å»ŗ $2 č“¦ęˆ·ć€‚", + "description": "$1 is the non EVM network where the account is going to be created, e.g. Solana Mainnet or Solana Devnet. $2 is the account type, e.g. Bitcoin or Solana" + }, "addRpcUrl": { "message": "添加 RPCļ¼ˆčæœēØ‹čæ‡ēØ‹č°ƒē”Øļ¼‰URL" }, @@ -300,14 +340,16 @@ "advancedPriorityFeeToolTip": { "message": "ä¼˜å…ˆč“¹ē”Øļ¼ˆåˆē§°ā€œēŸæå·„č“¹ā€ļ¼‰ē›“ęŽ„å‘ēŸæå·„ę”Æä»˜ļ¼Œęæ€åŠ±ä»–ä»¬ä¼˜å…ˆå¤„ē†ę‚Øēš„äŗ¤ę˜“ć€‚" }, - "aggregatedBalancePopover": { - "message": "čæ™åę˜ äŗ†ę‚ØåœØē»™å®šē½‘ē»œäøŠę‹„ęœ‰ēš„ę‰€ęœ‰ä»£åøēš„ä»·å€¼ć€‚å¦‚ęžœę‚Øę›“ę„æę„ēœ‹åˆ°ä»„ ETH ęˆ–å…¶ä»–č“§åøåę˜ ä»£åøä»·å€¼ļ¼ŒčÆ·č½¬åˆ° $1怂", - "description": "$1 represents the settings page" - }, "agreeTermsOfUse": { "message": "ęˆ‘åŒę„MetaMaskēš„$1", "description": "$1 is the `terms` link" }, + "airDropPatternDescription": { + "message": "čÆ„ä»£åøēš„é“¾äøŠåŽ†å²č®°å½•ę˜¾ē¤ŗļ¼Œę­¤å‰å­˜åœØåÆē–‘ēš„ē©ŗęŠ•ę“»åŠØå®žä¾‹ć€‚" + }, + "airDropPatternTitle": { + "message": "ē©ŗęŠ•ęØ”å¼" + }, "airgapVault": { "message": "AirGap Vault" }, @@ -726,9 +768,21 @@ "bridgeConfirmTwoTransactions": { "message": "ę‚Øéœ€č¦åœØę‚Øēš„ē”¬ä»¶é’±åŒ…äøŠē”®č®¤ 2 ē¬”äŗ¤ę˜“ļ¼š" }, + "bridgeCreateSolanaAccount": { + "message": "åˆ›å»ŗ Solana 蓦ꈷ" + }, + "bridgeCreateSolanaAccountDescription": { + "message": "如要将资产转移至 Solana ē½‘ē»œļ¼Œę‚Øéœ€ę‹„ęœ‰äø€äøŖč“¦ęˆ·åŠęŽ„ę”¶åœ°å€ć€‚" + }, + "bridgeCreateSolanaAccountTitle": { + "message": "ę‚Øéœ€č¦å…ˆåˆ›å»ŗäø€äøŖ Solana č“¦ęˆ·ć€‚" + }, "bridgeEnterAmount": { "message": "č¾“å…„é‡‘é¢" }, + "bridgeEnterAmountAndSelectAccount": { + "message": "č¾“å…„é‡‘é¢å¹¶é€‰ę‹©ē›®ę ‡č“¦ęˆ·" + }, "bridgeExplorerLinkViewOn": { "message": "在 $1 äøŠęŸ„ēœ‹" }, @@ -751,9 +805,15 @@ "bridgeQuoteExpired": { "message": "ę‚Øēš„ęŠ„ä»·å·²č¶…ę—¶ć€‚" }, + "bridgeSelectDestinationAccount": { + "message": "é€‰ę‹©ē›®ę ‡č“¦ęˆ·" + }, "bridgeSelectNetwork": { "message": "é€‰ę‹©ē½‘ē»œ" }, + "bridgeSelectTokenAmountAndAccount": { + "message": "é€‰ę‹©ä»£åøć€é‡‘é¢å’Œē›®ę ‡č“¦ęˆ·" + }, "bridgeSelectTokenAndAmount": { "message": "é€‰ę‹©ä»£åøå’Œé‡‘é¢" }, @@ -944,6 +1004,12 @@ "message": "ę‰¾äøåˆ°ä»»ä½•é€‰é”¹", "description": "Default text shown in the combo field dropdown if no options." }, + "concentratedSupplyDistributionDescription": { + "message": "čÆ„ä»£åøä¾›åŗ”é‡ēš„ē»å¤§éƒØåˆ†ē”±å¤“éƒØä»£åøęŒęœ‰č€…ęŽŒęŽ§ļ¼Œčæ™åø¦ę„äŗ†é›†äø­åŒ–ä»·ę ¼ę“ēŗµēš„é£Žé™©" + }, + "concentratedSupplyDistributionTitle": { + "message": "ä¾›åŗ”åˆ†åøƒé›†äø­åŒ–" + }, "configureSnapPopupDescription": { "message": "ę‚ØēŽ°åœØč¦ē¦»å¼€MetaMaskę„é…ē½®ę­¤snap怂" }, @@ -962,6 +1028,15 @@ "confirm": { "message": "甮认" }, + "confirmAccountType": { + "message": "ē±»åž‹" + }, + "confirmAccountTypeSmartContract": { + "message": "ę™ŗčƒ½č“¦ęˆ·" + }, + "confirmAccountTypeStandard": { + "message": "ę ‡å‡†č“¦ęˆ·" + }, "confirmAlertModalAcknowledgeMultiple": { "message": "ęˆ‘å·²ēŸ„ę™“ęé†’å¹¶ä»ęƒ³ē»§ē»­" }, @@ -974,12 +1049,36 @@ "confirmFieldTooltipPaymaster": { "message": "ę­¤äŗ¤ę˜“ēš„č“¹ē”Øå°†ē”± paymaster ę™ŗčƒ½åˆēŗ¦ę”Æä»˜ć€‚" }, + "confirmGasFeeTokenBalance": { + "message": "ä½™é¢ļ¼š" + }, + "confirmGasFeeTokenInsufficientBalance": { + "message": "čµ„é‡‘äøč¶³" + }, + "confirmGasFeeTokenMetaMaskFee": { + "message": "包含 $1 蓹用" + }, + "confirmGasFeeTokenModalTitle": { + "message": "é€‰ę‹©äø€ē§ä»£åø" + }, + "confirmGasFeeTokenToast": { + "message": "ę‚Øę­£åœØä½æē”Ø $1 ę”Æä»˜ę­¤ē½‘ē»œč“¹" + }, + "confirmGasFeeTokenTooltip": { + "message": "ę­¤č“¹ē”Øę”Æä»˜ē»™ē½‘ē»œä»„å¤„ē†ę‚Øēš„äŗ¤ę˜“ļ¼Œå…¶äø­åŒ…å«é’ˆåÆ¹éž ETH ä»£åøę”¶å–ēš„ $1 MetaMask 手续蓹。" + }, + "confirmNestedTransactionTitle": { + "message": "äŗ¤ę˜“ $1" + }, "confirmPassword": { "message": "甮认密码" }, "confirmRecoveryPhrase": { "message": "ē”®č®¤ē§é’„åŠ©č®°čÆ" }, + "confirmSimulationApprove": { + "message": "您批准" + }, "confirmTitleApproveTransactionNFT": { "message": "ęå–čÆ·ę±‚" }, @@ -1022,9 +1121,24 @@ "confirmTitleTransaction": { "message": "äŗ¤ę˜“čÆ·ę±‚" }, + "confirmUpgradeCancelModalButtonCancelTransaction": { + "message": "å–ę¶ˆäŗ¤ę˜“" + }, + "confirmUpgradeCancelModalButtonCancelUpgrade": { + "message": "å–ę¶ˆå‡ēŗ§å’Œäŗ¤ę˜“" + }, + "confirmUpgradeCancelModalDescription": { + "message": "å¦‚ęžœę‚Øäøęƒ³å‡ēŗ§ę‚Øēš„č“¦ęˆ·ļ¼Œę‚ØåÆä»„åœØę­¤å–ę¶ˆć€‚\n\nå¦‚č¦åœØäøå‡ēŗ§ēš„ęƒ…å†µäø‹å®ŒęˆčÆ„äŗ¤ę˜“ļ¼Œę‚Øå°†éœ€č¦åœØē½‘ē«™äøŠé‡ę–°ęå‡ŗę­¤čÆ·ę±‚ć€‚$1怂" + }, + "confirmUpgradeCancelModalTitle": { + "message": "å–ę¶ˆäŗ¤ę˜“" + }, "confirmationAlertDetails": { "message": "äøŗäŗ†äæęŠ¤ę‚Øēš„čµ„äŗ§ļ¼Œęˆ‘ä»¬å»ŗč®®ę‚Øę‹’ē»čÆ„čÆ·ę±‚ć€‚" }, + "confirmationAlertModalTitleDescription": { + "message": "ę‚Øēš„čµ„äŗ§åÆčƒ½é¢äø“é£Žé™©" + }, "confirmed": { "message": "已甮认" }, @@ -1052,6 +1166,9 @@ "connectAccounts": { "message": "čæžęŽ„č“¦ęˆ·" }, + "connectAnAccountHeader": { + "message": "čæžęŽ„č“¦ęˆ·" + }, "connectManually": { "message": "ę‰‹åŠØčæžęŽ„åˆ°å½“å‰ē«™ē‚¹" }, @@ -1158,6 +1275,9 @@ "message": "čŽ·å–$1å¤±č“„ļ¼ŒčÆ·ę£€ęŸ„ę‚Øēš„ē½‘ē»œļ¼Œē„¶åŽé‡čÆ•ć€‚", "description": "$1 is the name of the snap being fetched." }, + "connectionPopoverDescription": { + "message": "å¦‚č¦čæžęŽ„ē½‘ē«™ļ¼ŒčÆ·é€‰ę‹©ā€œčæžęŽ„ā€ęŒ‰é’®ć€‚MetaMask ä»…ę”ÆęŒčæžęŽ„ Web3 网站。" + }, "connectionRequest": { "message": "čæžęŽ„čÆ·ę±‚" }, @@ -1219,6 +1339,9 @@ "create": { "message": "åˆ›å»ŗ" }, + "createNewAccountHeader": { + "message": "åˆ›å»ŗę–°č“¦ęˆ·" + }, "createNewWallet": { "message": "åˆ›å»ŗę–°é’±åŒ…" }, @@ -1231,6 +1354,9 @@ "createSnapAccountTitle": { "message": "åˆ›å»ŗč“¦ęˆ·" }, + "createSolanaAccount": { + "message": "åˆ›å»ŗ Solana 蓦ꈷ" + }, "creatorAddress": { "message": "åˆ›å»ŗč€…åœ°å€" }, @@ -1471,6 +1597,21 @@ "message": "ę„č‡Ŗ $1 ēš„ęčæ°", "description": "$1 represents the name of the snap" }, + "destinationAccountPickerNoEligible": { + "message": "ęœŖę‰¾åˆ°ē¬¦åˆę”ä»¶ēš„č“¦ęˆ·" + }, + "destinationAccountPickerNoMatching": { + "message": "ęœŖę‰¾åˆ°åŒ¹é…ēš„č“¦ęˆ·" + }, + "destinationAccountPickerReceiveAt": { + "message": "ęŽ„ę”¶č‡³" + }, + "destinationAccountPickerSearchPlaceholderToMainnet": { + "message": "ęŽ„ę”¶åœ°å€ęˆ– ENS(Ethereum åŸŸåęœåŠ”ļ¼‰" + }, + "destinationAccountPickerSearchPlaceholderToSolana": { + "message": "ęŽ„ę”¶åœ°å€" + }, "details": { "message": "详细俔息" }, @@ -1516,6 +1657,9 @@ "message": "$1 å·²äøŽ $2 ę–­å¼€čæžęŽ„", "description": "$1 is name of the name and $2 represents the dapp name`" }, + "discover": { + "message": "å‘ēŽ°" + }, "discoverSnaps": { "message": "ęŽ¢ē“¢ Snap", "description": "Text that links to the Snaps website. Displayed in a banner on Snaps list page in settings." @@ -1872,6 +2016,9 @@ "experimental": { "message": "å®žéŖŒę€§" }, + "exploreweb3": { + "message": "ęŽ¢ē“¢ Web3" + }, "exportYourData": { "message": "åÆ¼å‡ŗę‚Øēš„ę•°ę®" }, @@ -1885,6 +2032,9 @@ "message": "ęŽ¢ē“¢ē¤¾åŒŗęž„å»ŗēš„ Snapļ¼Œå®šåˆ¶ę‚Øēš„ Web3 ä½“éŖŒ", "description": "Banner description displayed on Snaps list page in Settings when less than 6 Snaps is installed." }, + "externalAccount": { + "message": "å¤–éƒØč“¦ęˆ·" + }, "externalExtension": { "message": "å¤–éƒØę‰©å±•ēØ‹åŗ" }, @@ -2197,6 +2347,12 @@ "holdToRevealUnlockedLabel": { "message": "ęŒ‰ä½ä»„ę˜¾ē¤ŗåœ†åœˆč§£é”" }, + "honeypotDescription": { + "message": "čÆ„ä»£åøåÆčƒ½å­˜åœØčœœē½é£Žé™©ć€‚å»ŗč®®åœØčæ›č”Œä»£åøäŗ¤äŗ’å‰čæ›č”Œå®”ę…Žč°ƒęŸ„ļ¼Œä»„é˜²čŒƒę½œåœØčµ„é‡‘ęŸå¤±ć€‚" + }, + "honeypotTitle": { + "message": "蜜罐" + }, "howNetworkFeesWorkExplanation": { "message": "å¤„ē†äŗ¤ę˜“ę‰€éœ€ēš„é¢„ä¼°č“¹ē”Øć€‚ęœ€å¤§č“¹ē”Øäøŗ $1怂" }, @@ -2262,6 +2418,30 @@ "importNFTTokenIdToolTip": { "message": "NFTēš„IDę˜Æå”Æäø€ę ‡čÆ†ē¬¦ļ¼Œå› äøŗę‰€ęœ‰NFTéƒ½ę˜Æē‹¬äø€ę— äŗŒēš„ć€‚åŒę ·ļ¼ŒåœØOpenSeaäøŠļ¼Œę­¤ę•°å­—ä½äŗŽā€œčÆ¦ęƒ…ā€äø‹ę–¹ć€‚č®°äø‹å®ƒļ¼Œęˆ–å°†å®ƒå¤åˆ¶åˆ°å‰Ŗč““ęæäøŠć€‚" }, + "importNWordSRP": { + "message": "ꈑ꜉ $1 äøŖå•čÆē»„ęˆēš„åŠ©č®°čÆ", + "description": "$1 is the number of words in the recovery phrase" + }, + "importPrivateKey": { + "message": "私钄" + }, + "importSRPDescription": { + "message": "é€ščæ‡ę‚Øēš„ 12 äøŖęˆ– 24 äøŖå•čÆē§é’„åŠ©č®°čÆåÆ¼å…„ēŽ°ęœ‰é’±åŒ…ć€‚" + }, + "importSRPNumberOfWordsError": { + "message": "ē§é’„åŠ©č®°čÆåŒ…å« 12 äøŖęˆ– 24 äøŖå•čÆ" + }, + "importSRPWordError": { + "message": "å•čÆ $1 äøę­£ē”®ęˆ–ę‹¼å†™é”™čÆÆć€‚", + "description": "$1 is the word that is incorrect or misspelled" + }, + "importSRPWordErrorAlternative": { + "message": "å•čÆ $1 和 $2 äøę­£ē”®ęˆ–ę‹¼å†™é”™čÆÆć€‚", + "description": "$1 and $2 are multiple words that are mispelled." + }, + "importSecretRecoveryPhrase": { + "message": "åÆ¼å…„ē§é’„åŠ©č®°čÆ" + }, "importSelectedTokens": { "message": "č¦åÆ¼å…„ę‰€é€‰ä»£åøå—ļ¼Ÿ" }, @@ -2280,6 +2460,12 @@ "importTokensError": { "message": "ęˆ‘ä»¬ę— ę³•åÆ¼å…„ä»£åøć€‚čÆ·ēØåŽå†čÆ•ć€‚" }, + "importWallet": { + "message": "åÆ¼å…„é’±åŒ…" + }, + "importWalletOrAccountHeader": { + "message": "åÆ¼å…„é’±åŒ…ęˆ–č“¦ęˆ·" + }, "importWithCount": { "message": "导兄$1", "description": "$1 will the number of detected tokens that are selected for importing, if all of them are selected then $1 will be all" @@ -2327,6 +2513,12 @@ "insufficientFundsForGas": { "message": "ē‡ƒę–™čµ„é‡‘äøč¶³" }, + "insufficientLockedLiquidityDescription": { + "message": "čÆ„ä»£åøå› ē¼ŗä¹å……č¶³ēš„é”å®šęˆ–é”€ęÆęµåŠØę€§ļ¼ŒåÆčƒ½é¢äø“ēŖå‘ę€§ęµåŠØę€§ę’¤å‡ŗé£Žé™©ļ¼Œčæ›č€ŒåÆčƒ½å¼•å‘åø‚åœŗåŠØč”ć€‚" + }, + "insufficientLockedLiquidityTitle": { + "message": "é”å®šęµåŠØę€§äøč¶³" + }, "insufficientTokens": { "message": "ä»£åøäøč¶³ć€‚" }, @@ -2362,6 +2554,9 @@ "invalidCustomNetworkAlertTitle": { "message": "ę— ę•ˆēš„č‡Ŗå®šä¹‰ē½‘ē»œ" }, + "invalidHexData": { + "message": "åå…­čæ›åˆ¶ę•°ę®ę— ę•ˆ" + }, "invalidHexNumber": { "message": "ę— ę•ˆēš„åå…­čæ›åˆ¶ę•°å­—ć€‚" }, @@ -2540,6 +2735,9 @@ "ledgerLocked": { "message": "ę— ę³•čæžęŽ„åˆ° Ledger č®¾å¤‡ć€‚čÆ·ē”®äæę‚Øēš„č®¾å¤‡å·²č§£é”å¹¶ę‰“å¼€ Etherum åŗ”ē”ØēØ‹åŗć€‚" }, + "ledgerMultipleDevicesUnsupportedErrorMessage": { + "message": "ę— ę³•åŒę—¶čæžęŽ„å¤šäøŖ Ledger č®¾å¤‡ć€‚å¦‚éœ€čæžęŽ„ę–°ēš„ Ledger č®¾å¤‡ļ¼Œéœ€å…ˆę–­å¼€åŽŸęœ‰č®¾å¤‡ć€‚" + }, "ledgerTimeout": { "message": "Ledger Live å“åŗ”ę—¶é—“čæ‡é•æęˆ–čæžęŽ„č¶…ę—¶ć€‚čÆ·ē”®äæ Ledger Live åŗ”ē”ØēØ‹åŗå·²ę‰“å¼€äø”ę‚Øēš„č®¾å¤‡å·²č§£é”ć€‚" }, @@ -2637,6 +2835,9 @@ "manageDefaultSettings": { "message": "ē®”ē†é»˜č®¤éšē§č®¾ē½®" }, + "managePermissions": { + "message": "ē®”ē†č®øåÆ" + }, "marketCap": { "message": "市值" }, @@ -2755,6 +2956,15 @@ "multichainAddEthereumChainConfirmationDescription": { "message": "ę‚Øę­£åœØå°†ę­¤ē½‘ē»œę·»åŠ åˆ° MetaMask å¹¶ęŽˆäŗˆčÆ„ē½‘ē«™å…¶ä½æē”Øč®øåÆć€‚" }, + "multichainQuoteCardBridgingLabel": { + "message": "ꔄꎄ" + }, + "multichainQuoteCardQuoteLabel": { + "message": "抄价" + }, + "multichainQuoteCardTimeLabel": { + "message": "ę—¶é—“" + }, "multipleSnapConnectionWarning": { "message": "$1 ęƒ³čæžęŽ„ $2 äøŖ snap怂", "description": "$1 is the dapp and $2 is the number of snaps it wants to connect to." @@ -2869,6 +3079,13 @@ "network": { "message": "ē½‘ē»œļ¼š " }, + "networkChanged": { + "message": "ē½‘ē»œå·²ę›“ę”¹" + }, + "networkChangedMessage": { + "message": "ę‚Øę­£åœØ $1 äøŠäŗ¤ę˜“ć€‚", + "description": "$1 is the name of the network" + }, "networkDetails": { "message": "ē½‘ē»œčÆ¦ęƒ…" }, @@ -3143,6 +3360,9 @@ "notEnoughGas": { "message": "ē‡ƒę–™äøč¶³" }, + "notNow": { + "message": "ęš‚ę—¶äø" + }, "notificationDetail": { "message": "čÆ¦ęƒ…" }, @@ -3505,6 +3725,13 @@ "origin": { "message": "ę„ęŗ" }, + "originChanged": { + "message": "网站已曓改" + }, + "originChangedMessage": { + "message": "ę‚Øę­£åœØå®”ę øę„č‡Ŗ $1 ēš„čÆ·ę±‚ć€‚", + "description": "$1 is the name of the origin" + }, "osTheme": { "message": "系统" }, @@ -3559,6 +3786,14 @@ "pending": { "message": "待处理" }, + "pendingConfirmationAddNetworkAlertMessage": { + "message": "å‡ēŗ§ē½‘ē»œå°†å–ę¶ˆčÆ„ē½‘ē«™ēš„ $1 ē¬”å¾…å®šäŗ¤ę˜“ć€‚", + "description": "Number of transactions." + }, + "pendingConfirmationSwitchNetworkAlertMessage": { + "message": "åˆ‡ę¢ē½‘ē»œå°†å–ę¶ˆčÆ„ē½‘ē«™ēš„ $1 ē¬”å¾…å®šäŗ¤ę˜“ć€‚", + "description": "Number of transactions." + }, "pendingTransactionAlertMessage": { "message": "ę‚Øēš„äøŠäø€ē¬”äŗ¤ę˜“å®ŒęˆåŽļ¼Œę­¤äŗ¤ę˜“ę‰čƒ½ē»§ē»­čæ›č”Œć€‚$1", "description": "$1 represents the words 'how to cancel or speed up a transaction' in a hyperlink" @@ -3842,6 +4077,9 @@ "permitSimulationChange_receive": { "message": "ę‚Øę”¶åˆ°" }, + "permitSimulationChange_revoke2": { + "message": "꒤销" + }, "permitSimulationChange_transfer": { "message": "ę‚Øå‘é€" }, @@ -4237,6 +4475,9 @@ "reusedTokenNameWarning": { "message": "ę­¤å¤„ēš„ä»£åøä½æē”Øäŗ†äøŽę‚Øå…³ę³Øēš„å¦äø€ē§ä»£åøē›øåŒēš„ē¬¦å·ļ¼Œčæ™åÆčƒ½ä¼šč®©äŗŗę„Ÿåˆ°å›°ęƒ‘ęˆ–å…·ęœ‰ę¬ŗéŖ—ę€§ć€‚" }, + "revealSecretRecoveryPhrase": { + "message": "ę˜¾ē¤ŗē§é’„åŠ©č®°čÆ" + }, "revealSeedWords": { "message": "ę˜¾ē¤ŗē§é’„åŠ©č®°čÆ" }, @@ -4286,12 +4527,19 @@ "reviewAlerts": { "message": "ęŸ„ēœ‹ęé†’" }, + "reviewPendingTransactions": { + "message": "å®”ę øå¾…å®šäŗ¤ę˜“" + }, "reviewPermissions": { "message": "ęŸ„ēœ‹č®øåÆ" }, "revokePermission": { "message": "꒤销ꝃ限" }, + "revokePermissionTitle": { + "message": "꒤销 $1 č®øåÆ", + "description": "The token symbol that is being revoked" + }, "revokeSimulationDetailsDesc": { "message": "ę‚Øę­£åœØä»Žę‚Øēš„č“¦ęˆ·äø­åˆ é™¤ęŸäŗŗä½æē”Øä»£åøēš„ęƒé™ć€‚" }, @@ -4334,6 +4582,10 @@ "secretRecoveryPhrase": { "message": "ē§é’„åŠ©č®°čÆ" }, + "secretRecoveryPhrasePlusNumber": { + "message": "ē§é’„åŠ©č®°čÆ $1", + "description": "The $1 is the order of the Secret Recovery Phrase" + }, "secureWallet": { "message": "å®‰å…Øé’±åŒ…" }, @@ -4424,6 +4676,9 @@ "select": { "message": "选ꋩ" }, + "selectAccountToConnect": { + "message": "é€‰ę‹©č¦čæžęŽ„ēš„č“¦ęˆ·" + }, "selectAccounts": { "message": "é€‰ę‹©č¦åœØę­¤ē½‘ē«™äøŠä½æē”Øēš„č“¦ęˆ·" }, @@ -4454,6 +4709,9 @@ "selectRpcUrl": { "message": "选ꋩ RPCļ¼ˆčæœēØ‹čæ‡ēØ‹č°ƒē”Øļ¼‰URL" }, + "selectSecretRecoveryPhrase": { + "message": "é€‰ę‹©ē§é’„åŠ©č®°čÆ" + }, "selectType": { "message": "é€‰ę‹©ē±»åž‹" }, @@ -4565,16 +4823,6 @@ "showHexDataDescription": { "message": "é€‰ę‹©ę­¤é”¹ä»„åœØå‘é€å±å¹•äøŠę˜¾ē¤ŗåå…­čæ›åˆ¶ę•°ę®å­—ę®µ" }, - "showIncomingTransactions": { - "message": "ę˜¾ē¤ŗä¼ å…„ēš„äŗ¤ę˜“" - }, - "showIncomingTransactionsDescription": { - "message": "čæ™å–å†³äŗŽ$1ļ¼Œå³åÆä»„č®æé—®ę‚Øēš„ä»„å¤ŖåŠåœ°å€å’Œ IP åœ°å€ēš„ē½‘ē»œć€‚$2", - "description": "$1 is the link to etherscan url and $2 is the link to the privacy policy of consensys APIs" - }, - "showIncomingTransactionsExplainer": { - "message": "čæ™ä¾čµ–äŗŽęÆäøŖē½‘ē»œēš„äøåŒē¬¬äø‰ę–¹ APIļ¼Œčæ™äŗ› API ä¼šåÆ¼č‡“ę‚Øēš„ä»„å¤ŖåŠåœ°å€å’Œ IP åœ°å€č¢«čŽ·ę‚‰ć€‚" - }, "showLess": { "message": "ę”¶čµ·" }, @@ -4593,6 +4841,9 @@ "showPrivateKey": { "message": "ę˜¾ē¤ŗē§é’„" }, + "showSRP": { + "message": "ę˜¾ē¤ŗē§é’„åŠ©č®°čÆ" + }, "showTestnetNetworks": { "message": "ę˜¾ē¤ŗęµ‹čÆ•ē½‘ē»œ" }, @@ -4714,12 +4965,24 @@ "slideCashOutTitle": { "message": "é€ščæ‡ MetaMask å…‘ēŽ°" }, + "slideDebitCardDescription": { + "message": "ē‰¹å®šåœ°åŒŗåÆē”Ø" + }, "slideDebitCardTitle": { "message": "MetaMask å€Ÿč®°å”" }, + "slideFundWalletDescription": { + "message": "ę·»åŠ ęˆ–č½¬å…„ä»£åøå³åÆå¼€å§‹ä½æē”Ø" + }, "slideFundWalletTitle": { "message": "äøŗę‚Øēš„é’±åŒ…å­˜å…„čµ„é‡‘" }, + "slideSweepStakeDescription": { + "message": "ē«‹å³é“øé€  NFTļ¼Œčµ¢å–ęƒŠå–œå„–åŠ±" + }, + "slideSweepStakeTitle": { + "message": "å‚äøŽ $5000 USDC čµ¢å„–ę“»åŠØļ¼" + }, "smartContracts": { "message": "ę™ŗčƒ½åˆēŗ¦" }, @@ -4866,6 +5129,9 @@ "snapResultSuccessDescription": { "message": "$1å·²åÆä»„ä½æē”Ø" }, + "snapUIAssetSelectorTitle": { + "message": "é€‰ę‹©äø€ē§čµ„äŗ§" + }, "snapUpdateAlertDescription": { "message": "čŽ·å– $1 ēš„ęœ€ę–°ē‰ˆęœ¬", "description": "Description used in Snap update alert banner when snap update is available. $1 is the Snap name." @@ -4925,6 +5191,27 @@ "message": "联系 $1 ēš„åˆ›å»ŗč€…ä»„čŽ·å¾—čæ›äø€ę­„ę”ÆęŒć€‚", "description": "This is shown when the insight snap throws an error. $1 is the snap name" }, + "solanaImportAccounts": { + "message": "导兄 Solana 蓦ꈷ" + }, + "solanaImportAccountsDescription": { + "message": "åÆ¼å…„ē§é’„åŠ©č®°čÆä»„å°† Solana č“¦ęˆ·ä»Žå…¶ä»–é’±åŒ…čæē§»ć€‚" + }, + "solanaMoreFeaturesComingSoon": { + "message": "å³å°†ęŽØå‡ŗę›“å¤šåŠŸčƒ½" + }, + "solanaMoreFeaturesComingSoonDescription": { + "message": "Solana åŽ»äø­åæƒåŒ–åŗ”ē”Øć€NFTć€ē”¬ä»¶é’±åŒ…ę”ÆęŒē­‰åŠŸčƒ½å³å°†äøŠēŗæć€‚" + }, + "solanaOnMetaMask": { + "message": "MetaMask ę”ÆęŒ Solana" + }, + "solanaSendReceiveSwapTokens": { + "message": "å‘é€ć€ęŽ„ę”¶å’Œå…‘ę¢ä»£åø" + }, + "solanaSendReceiveSwapTokensDescription": { + "message": "使用 SOL态USDC ē­‰ä»£åøčæ›č”Œč½¬č“¦å’Œäŗ¤ę˜“ć€‚" + }, "someNetworks": { "message": "$1 ē½‘ē»œ" }, @@ -4951,6 +5238,21 @@ "source": { "message": "ę„ęŗ" }, + "spamModalBlockedDescription": { + "message": "评网站将被封禁 1 åˆ†é’Ÿć€‚" + }, + "spamModalBlockedTitle": { + "message": "ę‚Øå·²ęš‚ę—¶å°ē¦čÆ„ē½‘ē«™" + }, + "spamModalDescription": { + "message": "å¦‚ę‚Øę­£é¢‘ē¹ę”¶åˆ°å¤§é‡čÆ·ę±‚éŖšę‰°ļ¼ŒåÆęš‚ę—¶å°ē¦čÆ„ē½‘ē«™ć€‚" + }, + "spamModalTemporaryBlockButton": { + "message": "ęš‚ę—¶å°ē¦čÆ„ē½‘ē«™" + }, + "spamModalTitle": { + "message": "ęˆ‘ä»¬ę£€ęµ‹åˆ°å¤šę¬”čÆ·ę±‚" + }, "speed": { "message": "é€Ÿåŗ¦" }, @@ -5000,10 +5302,28 @@ "spendingCap": { "message": "ę”Æå‡ŗäøŠé™" }, + "spendingCaps": { + "message": "ę”Æå‡ŗäøŠé™" + }, "srpInputNumberOfWords": { "message": "ęˆ‘ęœ‰äø€äøŖåŒ…å«$1äøŖå•čÆēš„ē§é’„åŠ©č®°čÆ", "description": "This is the text for each option in the dropdown where a user selects how many words their secret recovery phrase has during import. The $1 is the number of words (either 12, 15, 18, 21, or 24)." }, + "srpListName": { + "message": "ē§é’„åŠ©č®°čÆ $1", + "description": "$1 is the order of the Secret Recovery Phrase" + }, + "srpListNumberOfAccounts": { + "message": "$1 个蓦户", + "description": "$1 is the number of accounts in the list" + }, + "srpListSelectionDescription": { + "message": "ē”ØäŗŽē”Ÿęˆę‚Øēš„ę–°č“¦ęˆ·ēš„ē§é’„åŠ©č®°čÆ" + }, + "srpListSingleOrZero": { + "message": "$1 个蓦户", + "description": "$1 is the number of accounts in the list, it is either 1 or 0" + }, "srpPasteFailedTooManyWords": { "message": "ē²˜č““å¤±č“„ļ¼Œå› äøŗå®ƒåŒ…å«č¶…čæ‡24äøŖå•čÆć€‚äø€äøŖē§é’„åŠ©č®°čÆęœ€å¤šåÆåŒ…å«24äøŖå•čÆć€‚", "description": "Description of SRP paste error when the pasted content has too many words" @@ -5158,6 +5478,9 @@ "message": "ēŖē„¶ēš„åø‚åœŗå˜åŒ–åÆčƒ½åÆ¼č‡“å¤±č“„ć€‚å¦‚ęžœé—®é¢˜ä»ē„¶å­˜åœØļ¼ŒčÆ·č”ē³»$1怂", "description": "This message is shown to a user if their swap fails. The $1 will be replaced by support.metamask.io" }, + "stxOptInSupportedNetworksDescription": { + "message": "å¼€åÆę™ŗčƒ½äŗ¤ę˜“ļ¼Œä»„ä¾æåœØę”ÆęŒēš„ē½‘ē»œäøŠå®žēŽ°ę›“åŠ å®‰å…ØåÆé ēš„äŗ¤ę˜“ć€‚$1" + }, "stxPendingPrivatelySubmittingSwap": { "message": "ę­£åœØē§˜åÆ†ęäŗ¤ę‚Øēš„Swap..." }, @@ -5977,6 +6300,12 @@ "message": "å½“å‰äøę”ÆęŒå‘é€NFT (ERC-721)代币", "description": "This is an error message we show the user if they attempt to send an NFT asset type, for which currently don't support sending" }, + "unstableTokenPriceDescription": { + "message": "čÆ„ä»£åøē¾Žå…ƒä»·ę ¼å‘ˆēŽ°é«˜åŗ¦ę³¢åŠØę€§ļ¼ŒäøŽå…¶äŗ¤äŗ’åÆčƒ½åÆ¼č‡“é‡å¤§ä»·å€¼ęŸå¤±ēš„é«˜é£Žé™©ć€‚" + }, + "unstableTokenPriceTitle": { + "message": "ä»£åøä»·ę ¼äøēØ³å®š" + }, "upArrow": { "message": "å‘äøŠē®­å¤“" }, @@ -6099,6 +6428,18 @@ "visitSite": { "message": "访问网站" }, + "visitSupportDataConsentModalAccept": { + "message": "甮认" + }, + "visitSupportDataConsentModalDescription": { + "message": "ę‚Øę˜Æå¦ę„æę„å°† MetaMask ę ‡čÆ†ē¬¦å’Œåŗ”ē”ØēØ‹åŗē‰ˆęœ¬äæ”ęÆåˆ†äŗ«ē»™ęˆ‘ä»¬ēš„ę”ÆęŒäø­åæƒļ¼Ÿčæ™å°†ęœ‰åŠ©äŗŽęˆ‘ä»¬ę›“å„½åœ°č§£å†³ę‚Øēš„é—®é¢˜ļ¼Œä½†ę­¤ę“ä½œäøŗåÆé€‰ć€‚" + }, + "visitSupportDataConsentModalReject": { + "message": "äøåˆ†äŗ«" + }, + "visitSupportDataConsentModalTitle": { + "message": "äøŽę”ÆęŒå›¢é˜Ÿåˆ†äŗ«č®¾å¤‡äæ”ęÆ" + }, "visitWebSite": { "message": "č®æé—®ęˆ‘ä»¬ēš„ē½‘ē«™" }, diff --git a/app/_locales/zh_TW/messages.json b/app/_locales/zh_TW/messages.json index b19f99637367..1d6f30d3f441 100644 --- a/app/_locales/zh_TW/messages.json +++ b/app/_locales/zh_TW/messages.json @@ -1042,13 +1042,6 @@ "showHexDataDescription": { "message": "åœØäŗ¤ę˜“ę™‚é”Æē¤ŗåå…­é€²ä½č³‡ę–™" }, - "showIncomingTransactions": { - "message": "é”Æē¤ŗå‚³å…„ēš„äŗ¤ę˜“" - }, - "showIncomingTransactionsDescription": { - "message": "éøę“‡ę­¤é …ä¾†åˆ©ē”Ø Etherscan åœØäŗ¤ę˜“åˆ—č”Øč£”é”Æē¤ŗå‚³å…„ēš„äŗ¤ę˜“", - "description": "$1 is the link to etherscan url and $2 is the link to the privacy policy of consensys APIs" - }, "showPermissions": { "message": "é”Æē¤ŗę¬Šé™" }, diff --git a/app/build-types/beta/manifest/_base.json b/app/build-types/beta/manifest/_base.json index bfdb451ed647..8ec1d503ba85 100644 --- a/app/build-types/beta/manifest/_base.json +++ b/app/build-types/beta/manifest/_base.json @@ -11,6 +11,10 @@ }, "default_title": "MetaMask Beta" }, + "externally_connectable": { + "matches": ["http://*/*", "https://*/*"], + "ids": ["*"] + }, "icons": { "16": "images/icon-16.png", "19": "images/icon-19.png", diff --git a/app/images/petrol-pump.svg b/app/images/petrol-pump.svg new file mode 100644 index 000000000000..3f13acb633e5 --- /dev/null +++ b/app/images/petrol-pump.svg @@ -0,0 +1,4 @@ + + + + diff --git a/app/images/plume-native.svg b/app/images/plume-native.svg new file mode 100644 index 000000000000..4a2d34e2c071 --- /dev/null +++ b/app/images/plume-native.svg @@ -0,0 +1,4 @@ + + + + diff --git a/app/images/plume.svg b/app/images/plume.svg new file mode 100644 index 000000000000..eb4fdbc310bc --- /dev/null +++ b/app/images/plume.svg @@ -0,0 +1,3 @@ + + + diff --git a/app/images/smart-transactions/smart-account-update.svg b/app/images/smart-transactions/smart-account-update.svg new file mode 100644 index 000000000000..93a37a042606 --- /dev/null +++ b/app/images/smart-transactions/smart-account-update.svg @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/app/images/solana-devnet-logo.svg b/app/images/solana-devnet-logo.svg new file mode 100644 index 000000000000..53904d7cbe01 --- /dev/null +++ b/app/images/solana-devnet-logo.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/app/images/solana-testnet-logo.svg b/app/images/solana-testnet-logo.svg new file mode 100644 index 000000000000..f9cf7d785898 --- /dev/null +++ b/app/images/solana-testnet-logo.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/app/images/soneium.svg b/app/images/soneium.svg index f045afaef99a..fdac30416193 100644 --- a/app/images/soneium.svg +++ b/app/images/soneium.svg @@ -1,5 +1,5 @@ - - - - + + + + diff --git a/app/images/sparkle.svg b/app/images/sparkle.svg new file mode 100644 index 000000000000..f5d81c27aa6f --- /dev/null +++ b/app/images/sparkle.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/app/images/speedometer.svg b/app/images/speedometer.svg new file mode 100644 index 000000000000..a227a8b3fdbd --- /dev/null +++ b/app/images/speedometer.svg @@ -0,0 +1,4 @@ + + + + diff --git a/app/images/xrp-logo.svg b/app/images/xrp-logo.svg new file mode 100644 index 000000000000..272a5815c0ab --- /dev/null +++ b/app/images/xrp-logo.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/app/images/xrplevm-testnet.svg b/app/images/xrplevm-testnet.svg new file mode 100644 index 000000000000..bc980eac8903 --- /dev/null +++ b/app/images/xrplevm-testnet.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/app/popup-init.html b/app/popup-init.html index 2fb79fefcfde..2914fbd62af0 100644 --- a/app/popup-init.html +++ b/app/popup-init.html @@ -25,7 +25,7 @@ * page may be a further UX improvement. */ html { - width: 357px; + width: 400px; height: 600px; background: #f2f4f6; } diff --git a/app/popup.html b/app/popup.html index 760ec6683203..fff2c7923163 100644 --- a/app/popup.html +++ b/app/popup.html @@ -1,5 +1,5 @@ - + @@ -7,7 +7,7 @@ - +
diff --git a/app/scripts/background.js b/app/scripts/background.js index 03e42c0a8079..5a5fd77881eb 100644 --- a/app/scripts/background.js +++ b/app/scripts/background.js @@ -283,6 +283,7 @@ function maybeDetectPhishing(theController) { // is shipped. if ( details.initiator && + details.initiator !== 'null' && // compare normalized URLs new URL(details.initiator).host === phishingPageUrl.host ) { diff --git a/app/scripts/constants/sentry-state.ts b/app/scripts/constants/sentry-state.ts index 7d60c0a4140f..ca5a238a6276 100644 --- a/app/scripts/constants/sentry-state.ts +++ b/app/scripts/constants/sentry-state.ts @@ -242,7 +242,6 @@ export const SENTRY_BACKGROUND_STATE = { featureFlags: true, forgottenPassword: true, identities: false, - incomingTransactionsPreferences: true, isIpfsGatewayEnabled: false, ipfsGateway: false, knownMethodData: false, diff --git a/app/scripts/constants/snaps.ts b/app/scripts/constants/snaps.ts new file mode 100644 index 000000000000..b02bcf745815 --- /dev/null +++ b/app/scripts/constants/snaps.ts @@ -0,0 +1,44 @@ +// Needed for webpack to analyze the preinstalled snaps +export const PREINSTALLED_SNAPS_URLS = [ + new URL( + '@metamask/message-signing-snap/dist/preinstalled-snap.json', + // @ts-expect-error TS1470: 'import.meta' is not allowed in CommonJS + import.meta.url, + ), + new URL( + '@metamask/ens-resolver-snap/dist/preinstalled-snap.json', + // @ts-expect-error TS1470: 'import.meta' is not allowed in CommonJS + import.meta.url, + ), + new URL( + '@metamask/institutional-wallet-snap/dist/preinstalled-snap.json', + // @ts-expect-error TS1470: 'import.meta' is not allowed in CommonJS + import.meta.url, + ), + ///: BEGIN:ONLY_INCLUDE_IF(build-flask) + new URL( + '@metamask/account-watcher/dist/preinstalled-snap.json', + // @ts-expect-error TS1470: 'import.meta' is not allowed in CommonJS + import.meta.url, + ), + new URL( + '@metamask/preinstalled-example-snap/dist/preinstalled-snap.json', + // @ts-expect-error TS1470: 'import.meta' is not allowed in CommonJS + import.meta.url, + ), + ///: END:ONLY_INCLUDE_IF + ///: BEGIN:ONLY_INCLUDE_IF(bitcoin) + new URL( + '@metamask/bitcoin-wallet-snap/dist/preinstalled-snap.json', + // @ts-expect-error TS1470: 'import.meta' is not allowed in CommonJS + import.meta.url, + ), + ///: END:ONLY_INCLUDE_IF + ///: BEGIN:ONLY_INCLUDE_IF(solana) + new URL( + '@metamask/solana-wallet-snap/dist/preinstalled-snap.json', + // @ts-expect-error TS1470: 'import.meta' is not allowed in CommonJS + import.meta.url, + ), + ///: END:ONLY_INCLUDE_IF +]; diff --git a/app/scripts/controller-init/assets/assets-contract-controller-init.test.ts b/app/scripts/controller-init/assets/assets-contract-controller-init.test.ts new file mode 100644 index 000000000000..a08e5bf9759a --- /dev/null +++ b/app/scripts/controller-init/assets/assets-contract-controller-init.test.ts @@ -0,0 +1,49 @@ +import { Messenger } from '@metamask/base-controller'; +import { AssetsContractController } from '@metamask/assets-controllers'; +import { buildControllerInitRequestMock } from '../test/utils'; +import { ControllerInitRequest } from '../types'; +import { + AssetsContractControllerMessenger, + getAssetsContractControllerMessenger, +} from '../messengers/assets'; +import { AssetsContractControllerInit } from './assets-contract-controller-init'; + +jest.mock('@metamask/assets-controllers'); + +function buildInitRequestMock(): jest.Mocked< + ControllerInitRequest +> { + const baseControllerMessenger = new Messenger(); + + return { + ...buildControllerInitRequestMock(), + controllerMessenger: getAssetsContractControllerMessenger( + baseControllerMessenger, + ), + initMessenger: undefined, + }; +} + +describe('AssetsContractControllerInit', () => { + const assetsContractControllerClassMock = jest.mocked( + AssetsContractController, + ); + + beforeEach(() => { + jest.resetAllMocks(); + }); + + it('returns controller instance', () => { + const requestMock = buildInitRequestMock(); + expect(AssetsContractControllerInit(requestMock).controller).toBeInstanceOf( + AssetsContractController, + ); + }); + + it('initializes with correct messenger and state', () => { + const requestMock = buildInitRequestMock(); + AssetsContractControllerInit(requestMock); + + expect(assetsContractControllerClassMock).toHaveBeenCalled(); + }); +}); diff --git a/app/scripts/controller-init/assets/assets-contract-controller-init.ts b/app/scripts/controller-init/assets/assets-contract-controller-init.ts new file mode 100644 index 000000000000..7864ff83403b --- /dev/null +++ b/app/scripts/controller-init/assets/assets-contract-controller-init.ts @@ -0,0 +1,26 @@ +import { AssetsContractController } from '@metamask/assets-controllers'; +import { ControllerInitFunction } from '../types'; +import { AssetsContractControllerMessenger } from '../messengers/assets/assets-contract-controller-messenger'; + +/** + * Initialize the AssetsContractController. + * + * @param request - The request object. + * @param request.controllerMessenger - The messenger to use for the controller. + * @param request.getGlobalChainId - The function to get the global chain id. + * @returns The initialized controller. + */ +export const AssetsContractControllerInit: ControllerInitFunction< + AssetsContractController, + AssetsContractControllerMessenger +> = ({ controllerMessenger, getGlobalChainId }) => { + const controller = new AssetsContractController({ + messenger: controllerMessenger, + chainId: getGlobalChainId(), + }); + + return { + controller, + memStateKey: null, + }; +}; diff --git a/app/scripts/controller-init/assets/index.ts b/app/scripts/controller-init/assets/index.ts new file mode 100644 index 000000000000..0b4dc2532cd0 --- /dev/null +++ b/app/scripts/controller-init/assets/index.ts @@ -0,0 +1,4 @@ +export { TokenRatesControllerInit } from './token-rates-controller-init'; +export { NftControllerInit } from './nft-controller-init'; +export { NftDetectionControllerInit } from './nft-detection-controller-init'; +export { AssetsContractControllerInit } from './assets-contract-controller-init'; diff --git a/app/scripts/controller-init/assets/nft-controller-init.test.ts b/app/scripts/controller-init/assets/nft-controller-init.test.ts new file mode 100644 index 000000000000..ee5080997e2a --- /dev/null +++ b/app/scripts/controller-init/assets/nft-controller-init.test.ts @@ -0,0 +1,45 @@ +import { + NftController, + NftControllerMessenger, +} from '@metamask/assets-controllers'; +import { Messenger } from '@metamask/base-controller'; +import { buildControllerInitRequestMock } from '../test/utils'; +import { ControllerInitRequest } from '../types'; +import { getNftControllerMessenger } from '../messengers/assets'; +import { NftControllerInit } from './nft-controller-init'; + +jest.mock('@metamask/assets-controllers'); + +function buildInitRequestMock(): jest.Mocked< + ControllerInitRequest +> { + const baseControllerMessenger = new Messenger(); + + return { + ...buildControllerInitRequestMock(), + controllerMessenger: getNftControllerMessenger(baseControllerMessenger), + initMessenger: undefined, + }; +} + +describe('NftControllerInit', () => { + const nftControllerClassMock = jest.mocked(NftController); + + beforeEach(() => { + jest.resetAllMocks(); + }); + + it('returns controller instance', () => { + const requestMock = buildInitRequestMock(); + expect(NftControllerInit(requestMock).controller).toBeInstanceOf( + NftController, + ); + }); + + it('initializes with correct messenger and state', () => { + const requestMock = buildInitRequestMock(); + NftControllerInit(requestMock); + + expect(nftControllerClassMock).toHaveBeenCalled(); + }); +}); diff --git a/app/scripts/controller-init/assets/nft-controller-init.ts b/app/scripts/controller-init/assets/nft-controller-init.ts new file mode 100644 index 000000000000..1de89b6a3d53 --- /dev/null +++ b/app/scripts/controller-init/assets/nft-controller-init.ts @@ -0,0 +1,46 @@ +import { NftController } from '@metamask/assets-controllers'; +import { AssetType } from '@metamask/bridge-controller'; +import { ControllerInitFunction } from '../types'; +import { NftControllerMessenger } from '../messengers/assets/nft-controller-messenger'; +import { + MetaMetricsEventCategory, + MetaMetricsEventName, +} from '../../../../shared/constants/metametrics'; + +/** + * Initialize the NFT controller. + * + * @param request - The request object. + * @param request.controllerMessenger - The messenger to use for the controller. + * @param request.persistedState - The persisted state of the extension. + * @param request.getGlobalChainId - The function to get the global chain id. + * @param request.trackEvent - The function to track events. + * @returns The initialized controller. + */ +export const NftControllerInit: ControllerInitFunction< + NftController, + NftControllerMessenger +> = ({ controllerMessenger, persistedState, getGlobalChainId, trackEvent }) => { + const controller = new NftController({ + state: persistedState.NftController, + messenger: controllerMessenger, + chainId: getGlobalChainId(), + onNftAdded: ({ address, symbol, tokenId, standard, source }) => + trackEvent({ + event: MetaMetricsEventName.NftAdded, + category: MetaMetricsEventCategory.Wallet, + sensitiveProperties: { + token_contract_address: address, + token_symbol: symbol ?? null, + token_id: tokenId, + token_standard: standard, + asset_type: AssetType.NFT, + source, + }, + }), + }); + + return { + controller, + }; +}; diff --git a/app/scripts/controller-init/assets/nft-detection-controller-init.test.ts b/app/scripts/controller-init/assets/nft-detection-controller-init.test.ts new file mode 100644 index 000000000000..7ff562097894 --- /dev/null +++ b/app/scripts/controller-init/assets/nft-detection-controller-init.test.ts @@ -0,0 +1,73 @@ +import { + NftDetectionController, + NftDetectionControllerMessenger, +} from '@metamask/assets-controllers'; +import { Messenger } from '@metamask/base-controller'; +import { PreferencesController } from '@metamask/preferences-controller'; +import { buildControllerInitRequestMock } from '../test/utils'; +import { ControllerInitRequest } from '../types'; +import { getNftDetectionControllerMessenger } from '../messengers/assets'; +import { NftDetectionControllerInit } from './nft-detection-controller-init'; + +jest.mock('@metamask/assets-controllers'); + +/** + * Build a mock PreferencesController. + * + * @param partialMock - A partial mock object for the PreferencesController, merged + * with the default mock. + * @returns A mock PreferencesController. + */ +function buildControllerMock( + partialMock?: Partial, +): PreferencesController { + const defaultPreferencesControllerMock = { + state: { useNftDetection: true }, + }; + + // @ts-expect-error Incomplete mock, just includes properties used by code-under-test. + return { + ...defaultPreferencesControllerMock, + ...partialMock, + }; +} + +function buildInitRequestMock(): jest.Mocked< + ControllerInitRequest +> { + const baseControllerMessenger = new Messenger(); + + const requestMock = { + ...buildControllerInitRequestMock(), + controllerMessenger: getNftDetectionControllerMessenger( + baseControllerMessenger, + ), + initMessenger: undefined, + }; + // @ts-expect-error Incomplete mock, just includes properties used by code-under-test. + requestMock.getController.mockReturnValue(buildControllerMock()); + + return requestMock; +} + +describe('NftDetectionControllerInit', () => { + const nftDetectionControllerClassMock = jest.mocked(NftDetectionController); + + beforeEach(() => { + jest.resetAllMocks(); + }); + + it('returns controller instance', () => { + const requestMock = buildInitRequestMock(); + expect(NftDetectionControllerInit(requestMock).controller).toBeInstanceOf( + NftDetectionController, + ); + }); + + it('initializes with correct messenger and state', () => { + const requestMock = buildInitRequestMock(); + NftDetectionControllerInit(requestMock); + + expect(nftDetectionControllerClassMock).toHaveBeenCalled(); + }); +}); diff --git a/app/scripts/controller-init/assets/nft-detection-controller-init.ts b/app/scripts/controller-init/assets/nft-detection-controller-init.ts new file mode 100644 index 000000000000..8df32740d87c --- /dev/null +++ b/app/scripts/controller-init/assets/nft-detection-controller-init.ts @@ -0,0 +1,33 @@ +import { NftDetectionController } from '@metamask/assets-controllers'; +import { ControllerInitFunction } from '../types'; +import { NftDetectionControllerMessenger } from '../messengers/assets'; + +/** + * Initialize the NFT detection controller. + * + * @param request - The request object. + * @param request.controllerMessenger - The messenger to use for the controller. + * @param request.getController - The function to get the controller. + * @returns The initialized controller. + */ +export const NftDetectionControllerInit: ControllerInitFunction< + NftDetectionController, + NftDetectionControllerMessenger +> = (request) => { + const { controllerMessenger, getController } = request; + + const preferencesController = () => getController('PreferencesController'); + const nftController = () => getController('NftController'); + + const controller = new NftDetectionController({ + messenger: controllerMessenger, + addNft: (...args) => nftController().addNft(...args), + getNftState: () => nftController().state, + // added this to track previous value of useNftDetection, should be true on very first initializing of controller[] + disabled: !preferencesController().state.useNftDetection, + }); + + return { + controller, + }; +}; diff --git a/app/scripts/controller-init/assets/token-rates-controller-init.test.ts b/app/scripts/controller-init/assets/token-rates-controller-init.test.ts new file mode 100644 index 000000000000..0d25e7063338 --- /dev/null +++ b/app/scripts/controller-init/assets/token-rates-controller-init.test.ts @@ -0,0 +1,81 @@ +import { + TokenRatesController, + TokenRatesControllerMessenger, +} from '@metamask/assets-controllers'; +import { Messenger } from '@metamask/base-controller'; +import { PreferencesController } from '@metamask/preferences-controller'; +import { buildControllerInitRequestMock } from '../test/utils'; +import { ControllerInitRequest } from '../types'; +import { getTokenRatesControllerMessenger } from '../messengers/assets'; +import { TokenRatesControllerInit } from './token-rates-controller-init'; + +jest.mock('@metamask/assets-controllers'); + +/** + * Build a mock PreferencesController. + * This returns a partial mock that includes the state property expected by the TokenRatesController (for example, `useCurrencyRateCheck`). + * + * @param {Partial} partialMock - The partial mock to be merged with the default mock. + * @returns {PreferencesController} The mock PreferencesController. + */ + +function buildControllerMock( + partialMock?: Partial, +): PreferencesController { + const defaultPreferencesControllerMock = { + state: { useCurrencyRateCheck: true }, + }; + + // @ts-expect-error Incomplete mock, just includes properties used by code-under-test. + return { + ...defaultPreferencesControllerMock, + ...partialMock, + }; +} + +/** + * Build a mock init request. + * + * Notice that we also mock the getController method to return the + * stubbed PreferencesController. + */ +function buildInitRequestMock(): jest.Mocked< + ControllerInitRequest +> { + const baseControllerMessenger = new Messenger(); + + const requestMock = { + ...buildControllerInitRequestMock(), + controllerMessenger: getTokenRatesControllerMessenger( + baseControllerMessenger, + ), + initMessenger: undefined, + }; + + // @ts-expect-error Incomplete mock, just includes properties used by code-under-test. + requestMock.getController.mockReturnValue(buildControllerMock()); + + return requestMock; +} + +describe('TokenRatesControllerInit', () => { + const tokenRatesControllerClassMock = jest.mocked(TokenRatesController); + + beforeEach(() => { + jest.resetAllMocks(); + }); + + it('returns controller instance', () => { + const requestMock = buildInitRequestMock(); + expect(TokenRatesControllerInit(requestMock).controller).toBeInstanceOf( + TokenRatesController, + ); + }); + + it('initializes with correct messenger and state', () => { + const requestMock = buildInitRequestMock(); + TokenRatesControllerInit(requestMock); + + expect(tokenRatesControllerClassMock).toHaveBeenCalled(); + }); +}); diff --git a/app/scripts/controller-init/assets/token-rates-controller-init.ts b/app/scripts/controller-init/assets/token-rates-controller-init.ts new file mode 100644 index 000000000000..d220eb5c5a5f --- /dev/null +++ b/app/scripts/controller-init/assets/token-rates-controller-init.ts @@ -0,0 +1,33 @@ +import { + CodefiTokenPricesServiceV2, + TokenRatesController, +} from '@metamask/assets-controllers'; +import { ControllerInitFunction } from '../types'; +import { TokenRatesControllerMessenger } from '../messengers/assets'; + +/** + * Initialize the Token Rates controller. + * + * @param request - The request object. + * @param request.controllerMessenger - The messenger to use for the controller. + * @param request.persistedState - The persisted state of the extension. + * @returns The initialized controller. + */ +export const TokenRatesControllerInit: ControllerInitFunction< + TokenRatesController, + TokenRatesControllerMessenger +> = (request) => { + const { controllerMessenger, getController, persistedState } = request; + const preferencesController = () => getController('PreferencesController'); + + const controller = new TokenRatesController({ + messenger: controllerMessenger, + state: persistedState.TokenRatesController, + tokenPricesService: new CodefiTokenPricesServiceV2(), + disabled: !preferencesController().state?.useCurrencyRateCheck, + }); + + return { + controller, + }; +}; diff --git a/app/scripts/controller-init/confirmations/transaction-controller-init.test.ts b/app/scripts/controller-init/confirmations/transaction-controller-init.test.ts index 155f41e29ba9..f8a321f2715f 100644 --- a/app/scripts/controller-init/confirmations/transaction-controller-init.test.ts +++ b/app/scripts/controller-init/confirmations/transaction-controller-init.test.ts @@ -115,15 +115,13 @@ describe('Transaction Controller Init', () => { }); describe('determines incoming transactions is enabled', () => { - it('when enabled in preferences and onboarding complete', () => { + it('when useExternalServices is enabled in preferences and onboarding complete', () => { const incomingTransactionsIsEnabled = testConstructorOption( 'incomingTransactions', { state: { completedOnboarding: true, - incomingTransactionsPreferences: { - [CHAIN_ID_MOCK]: true, - }, + useExternalServices: true, }, }, )?.isEnabled; @@ -137,9 +135,7 @@ describe('Transaction Controller Init', () => { { state: { completedOnboarding: false, - incomingTransactionsPreferences: { - [CHAIN_ID_MOCK]: true, - }, + useExternalServices: true, }, }, )?.isEnabled; @@ -153,9 +149,7 @@ describe('Transaction Controller Init', () => { { state: { completedOnboarding: true, - incomingTransactionsPreferences: { - [CHAIN_ID_MOCK]: false, - }, + useExternalServices: false, }, }, )?.isEnabled; diff --git a/app/scripts/controller-init/confirmations/transaction-controller-init.ts b/app/scripts/controller-init/confirmations/transaction-controller-init.ts index cc3c9ab1548d..d5970cc6e2f3 100644 --- a/app/scripts/controller-init/confirmations/transaction-controller-init.ts +++ b/app/scripts/controller-init/confirmations/transaction-controller-init.ts @@ -10,7 +10,7 @@ import SmartTransactionsController from '@metamask/smart-transactions-controller import { SmartTransactionStatuses } from '@metamask/smart-transactions-controller/dist/types'; import { Hex } from '@metamask/utils'; import { - getCurrentChainSupportsSmartTransactions, + getChainSupportsSmartTransactions, getFeatureFlagsByChainId, getIsSmartTransaction, getSmartTransactionsPreferenceEnabled, @@ -23,14 +23,7 @@ import { } from '../../lib/transaction/smart-transactions'; import { getTransactionById } from '../../lib/transaction/util'; import { trace } from '../../../../shared/lib/trace'; -///: BEGIN:ONLY_INCLUDE_IF(build-mmi) -import { - afterTransactionSign as afterTransactionSignMMI, - beforeCheckPendingTransaction as beforeCheckPendingTransactionMMI, - beforeTransactionPublish as beforeTransactionPublishMMI, - getAdditionalSignArguments as getAdditionalSignArgumentsMMI, -} from '../../lib/transaction/mmi-hooks'; -///: END:ONLY_INCLUDE_IF + import { handlePostTransactionBalanceUpdate, handleTransactionAdded, @@ -49,6 +42,7 @@ import { import { TransactionControllerInitMessenger } from '../messengers/transaction-controller-messenger'; import { ControllerFlatState } from '../controller-list'; import { TransactionMetricsRequest } from '../../../../shared/types/metametrics'; +import { Delegation7702PublishHook } from '../../lib/transaction/hooks/delegation-7702-publish'; export const TransactionControllerInit: ControllerInitFunction< TransactionController, @@ -62,6 +56,7 @@ export const TransactionControllerInit: ControllerInitFunction< getGlobalChainId, getPermittedAccounts, getTransactionMetricsRequest, + updateAccountBalanceForTransactionNetwork, persistedState, } = request; @@ -72,9 +67,6 @@ export const TransactionControllerInit: ControllerInitFunction< onboardingController, preferencesController, smartTransactionsController, - ///: BEGIN:ONLY_INCLUDE_IF(build-mmi) - transactionUpdateController, - ///: END:ONLY_INCLUDE_IF } = getControllers(request); const controller: TransactionController = new TransactionController({ @@ -106,13 +98,12 @@ export const TransactionControllerInit: ControllerInitFunction< }, includeTokenTransfers: false, isEnabled: () => - preferencesController().state.incomingTransactionsPreferences?.[ - // @ts-expect-error PreferencesController incorrectly expects number index - getGlobalChainId() - ] && onboardingController().state.completedOnboarding, + preferencesController().state.useExternalServices && + onboardingController().state.completedOnboarding, queryEntireHistory: false, updateTransactions: false, }, + isAutomaticGasFeeUpdateEnabled: () => true, isFirstTimeInteractionEnabled: () => preferencesController().state.securityAlertsEnabled, isSimulationEnabled: () => @@ -123,7 +114,7 @@ export const TransactionControllerInit: ControllerInitFunction< const uiState = getUIState(getFlatState()); return !( getSmartTransactionsPreferenceEnabled(uiState) && - getCurrentChainSupportsSmartTransactions(uiState) + getChainSupportsSmartTransactions(uiState) ); }, }, @@ -132,31 +123,32 @@ export const TransactionControllerInit: ControllerInitFunction< // @ts-expect-error Controller uses string for names rather than enum trace, hooks: { - ///: BEGIN:ONLY_INCLUDE_IF(build-mmi) - afterSign: (txMeta, signedEthTx) => - afterTransactionSignMMI( - txMeta, - signedEthTx, - transactionUpdateController().addTransactionToWatchList.bind( - transactionUpdateController(), - ), - ), - beforeCheckPendingTransaction: - beforeCheckPendingTransactionMMI.bind(this), - beforePublish: beforeTransactionPublishMMI.bind(this), - getAdditionalSignArguments: getAdditionalSignArgumentsMMI.bind(this), - ///: END:ONLY_INCLUDE_IF + beforePublish: (transactionMeta: TransactionMeta) => { + const response = initMessenger.call( + 'InstitutionalSnapController:publishHook', + transactionMeta, + ); + return response; + }, + + beforeCheckPendingTransactions: (transactionMeta: TransactionMeta) => { + const response = initMessenger.call( + 'InstitutionalSnapController:beforeCheckPendingTransactionHook', + transactionMeta, + ); + + return response; + }, // @ts-expect-error Controller type does not support undefined return value - publish: (transactionMeta, rawTx: Hex) => - publishSmartTransactionHook( - controller, - smartTransactionsController(), - // Init messenger cannot yet be further restricted so is a superset of what is needed - initMessenger as SmartTransactionHookMessenger, - getFlatState(), + publish: (transactionMeta, signedTx) => + publishHook({ + flatState: getFlatState(), + initMessenger, + signedTx, + smartTransactionsController: smartTransactionsController(), + transactionController: controller, transactionMeta, - rawTx, - ), + }), publishBatch: async (_request: PublishBatchHookRequest) => await publishBatchSmartTransactionHook({ transactionController: controller, @@ -175,6 +167,7 @@ export const TransactionControllerInit: ControllerInitFunction< addTransactionControllerListeners( initMessenger, getTransactionMetricsRequest, + updateAccountBalanceForTransactionNetwork, ); const api = getApi(controller); @@ -190,6 +183,7 @@ function getApi( controller.abortTransactionSigning.bind(controller), getLayer1GasFee: controller.getLayer1GasFee.bind(controller), getTransactions: controller.getTransactions.bind(controller), + isAtomicBatchSupported: controller.isAtomicBatchSupported.bind(controller), updateAtomicBatchData: controller.updateAtomicBatchData.bind(controller), updateBatchTransactions: controller.updateBatchTransactions.bind(controller), @@ -221,19 +215,24 @@ function getControllers( request.getController('SmartTransactionsController'), transactionUpdateController: () => request.getController('TransactionUpdateController'), + institutionalSnapController: () => + request.getController('InstitutionalSnapController'), }; } -function getSmartTransactionCommonParams(flatState: ControllerFlatState) { +function getSmartTransactionCommonParams( + flatState: ControllerFlatState, + chainId?: string, +) { // UI state is required to support shared selectors to avoid duplicate logic in frontend and backend. // Ideally all backend logic would instead rely on messenger event / state subscriptions. const uiState = getUIState(flatState); // @ts-expect-error Smart transaction selector types does not match controller state - const isSmartTransaction = getIsSmartTransaction(uiState); + const isSmartTransaction = getIsSmartTransaction(uiState, chainId); // @ts-expect-error Smart transaction selector types does not match controller state - const featureFlags = getFeatureFlagsByChainId(uiState); + const featureFlags = getFeatureFlagsByChainId(uiState, chainId); const isHardwareWalletAccount = isHardwareWallet(uiState); @@ -244,7 +243,45 @@ function getSmartTransactionCommonParams(flatState: ControllerFlatState) { }; } -function publishSmartTransactionHook( +async function publishHook({ + flatState, + initMessenger, + signedTx, + smartTransactionsController, + transactionController, + transactionMeta, +}: { + flatState: ControllerFlatState; + initMessenger: TransactionControllerInitMessenger; + signedTx: string; + smartTransactionsController: SmartTransactionsController; + transactionController: TransactionController; + transactionMeta: TransactionMeta; +}) { + const result = await publishSmartTransactionHook( + transactionController, + smartTransactionsController, + initMessenger, + flatState, + transactionMeta, + signedTx as Hex, + ); + + if (result?.transactionHash) { + return result; + } + + const hook = new Delegation7702PublishHook({ + isAtomicBatchSupported: transactionController.isAtomicBatchSupported.bind( + transactionController, + ), + messenger: initMessenger, + }).getHook(); + + return await hook(transactionMeta, signedTx); +} + +async function publishSmartTransactionHook( transactionController: TransactionController, smartTransactionsController: SmartTransactionsController, hookControllerMessenger: SmartTransactionHookMessenger, @@ -253,14 +290,14 @@ function publishSmartTransactionHook( signedTransactionInHex: Hex, ) { const { isSmartTransaction, featureFlags, isHardwareWalletAccount } = - getSmartTransactionCommonParams(flatState); + getSmartTransactionCommonParams(flatState, transactionMeta.chainId); if (!isSmartTransaction) { // Will cause TransactionController to publish to the RPC provider as normal. return { transactionHash: undefined }; } - return submitSmartTransactionHook({ + return await submitSmartTransactionHook({ transactionMeta, signedTransactionInHex, transactionController, @@ -286,16 +323,6 @@ function publishBatchSmartTransactionHook({ flatState: ControllerFlatState; transactions: PublishBatchHookTransaction[]; }) { - const { isSmartTransaction, featureFlags, isHardwareWalletAccount } = - getSmartTransactionCommonParams(flatState); - - if (!isSmartTransaction) { - // Will cause TransactionController to publish to the RPC provider as normal. - throw new Error( - 'publishBatchSmartTransactionHook: Smart Transaction is required for batch submissions', - ); - } - // Get transactionMeta based on the last transaction ID const lastTransaction = transactions[transactions.length - 1]; const transactionMeta = getTransactionById( @@ -310,6 +337,15 @@ function publishBatchSmartTransactionHook({ ); } + const { isSmartTransaction, featureFlags, isHardwareWalletAccount } = + getSmartTransactionCommonParams(flatState, transactionMeta.chainId); + + if (!isSmartTransaction) { + throw new Error( + 'publishBatchSmartTransactionHook: Smart Transaction is required for batch submissions', + ); + } + return submitBatchSmartTransactionHook({ transactions, transactionController, @@ -336,9 +372,22 @@ function getExternalPendingTransactions( function addTransactionControllerListeners( initMessenger: TransactionControllerInitMessenger, getTransactionMetricsRequest: () => TransactionMetricsRequest, + updateAccountBalanceForTransactionNetwork: ( + transactionMeta: TransactionMeta, + ) => void, ) { const transactionMetricsRequest = getTransactionMetricsRequest(); + initMessenger.subscribe( + 'TransactionController:unapprovedTransactionAdded', + updateAccountBalanceForTransactionNetwork, + ); + + initMessenger.subscribe( + 'TransactionController:transactionConfirmed', + updateAccountBalanceForTransactionNetwork, + ); + initMessenger.subscribe( 'TransactionController:postTransactionBalanceUpdated', handlePostTransactionBalanceUpdate.bind(null, transactionMetricsRequest), diff --git a/app/scripts/controller-init/controller-list.ts b/app/scripts/controller-init/controller-list.ts index 4eabd2302e0d..37cf761d6e30 100644 --- a/app/scripts/controller-init/controller-list.ts +++ b/app/scripts/controller-init/controller-list.ts @@ -12,9 +12,13 @@ import { TransactionController } from '@metamask/transaction-controller'; import { TransactionUpdateController } from '@metamask-institutional/transaction-update'; import { AccountsController } from '@metamask/accounts-controller'; import { + AssetsContractController, MultichainAssetsController, MultichainAssetsRatesController, MultichainBalancesController, + NftController, + NftDetectionController, + TokenRatesController, } from '@metamask/assets-controllers'; import { MultichainNetworkController } from '@metamask/multichain-network-controller'; import { MultichainTransactionsController } from '@metamask/multichain-transactions-controller'; @@ -37,6 +41,7 @@ import { Controller as NotificationServicesPushController } from '@metamask/noti import OnboardingController from '../controllers/onboarding'; import { PreferencesController } from '../controllers/preferences-controller'; import SwapsController from '../controllers/swaps'; +import { InstitutionalSnapController } from '../controllers/institutional-snap/InstitutionalSnapController'; /** * Union of all controllers supporting or required by modular initialization. @@ -73,7 +78,12 @@ export type Controller = name: 'TransactionUpdateController'; state: Record; }) - | UserStorageController; + | InstitutionalSnapController + | UserStorageController + | TokenRatesController + | NftController + | NftDetectionController + | AssetsContractController; /** * Flat state object for all controllers supporting or required by modular initialization. @@ -104,4 +114,7 @@ export type ControllerFlatState = AccountsController['state'] & SnapInterfaceController['state'] & TransactionController['state'] & SwapsController['state'] & - UserStorageController['state']; + UserStorageController['state'] & + TokenRatesController['state'] & + NftController['state'] & + NftDetectionController['state']; diff --git a/app/scripts/controller-init/institutional-snap/institutional-snap-controller-init.test.ts b/app/scripts/controller-init/institutional-snap/institutional-snap-controller-init.test.ts new file mode 100644 index 000000000000..1d2aea58ec1f --- /dev/null +++ b/app/scripts/controller-init/institutional-snap/institutional-snap-controller-init.test.ts @@ -0,0 +1,49 @@ +import { Messenger } from '@metamask/base-controller'; +import { + InstitutionalSnapController, + InstitutionalSnapControllerMessenger, +} from '../../controllers/institutional-snap/InstitutionalSnapController'; +import { buildControllerInitRequestMock } from '../test/utils'; +import { ControllerInitRequest } from '../types'; +import { getInstitutionalSnapControllerMessenger } from '../messengers/accounts/institutional-snap-controller-messenger'; +import { InstitutionalSnapControllerInit } from './institutional-snap-controller-init'; + +jest.mock('../../controllers/institutional-snap/InstitutionalSnapController'); + +function buildInitRequestMock(): jest.Mocked< + ControllerInitRequest +> { + const baseControllerMessenger = new Messenger(); + + return { + ...buildControllerInitRequestMock(), + controllerMessenger: getInstitutionalSnapControllerMessenger( + baseControllerMessenger, + ), + initMessenger: undefined, + }; +} + +describe('InstitutionalSnapControllerInit', () => { + const institutionalSnapControllerClassMock = jest.mocked( + InstitutionalSnapController, + ); + + beforeEach(() => { + jest.resetAllMocks(); + }); + + it('returns controller instance', () => { + const requestMock = buildInitRequestMock(); + expect( + InstitutionalSnapControllerInit(requestMock).controller, + ).toBeInstanceOf(InstitutionalSnapController); + }); + + it('initializes with correct messenger and state', () => { + const requestMock = buildInitRequestMock(); + InstitutionalSnapControllerInit(requestMock); + + expect(institutionalSnapControllerClassMock).toHaveBeenCalled(); + }); +}); diff --git a/app/scripts/controller-init/institutional-snap/institutional-snap-controller-init.ts b/app/scripts/controller-init/institutional-snap/institutional-snap-controller-init.ts new file mode 100644 index 000000000000..0036e3138b5d --- /dev/null +++ b/app/scripts/controller-init/institutional-snap/institutional-snap-controller-init.ts @@ -0,0 +1,16 @@ +import { InstitutionalSnapController } from '../../controllers/institutional-snap/InstitutionalSnapController'; +import { InstitutionalSnapControllerMessenger } from '../messengers/accounts/institutional-snap-controller-messenger'; +import { ControllerInitFunction } from '../types'; + +export const InstitutionalSnapControllerInit: ControllerInitFunction< + InstitutionalSnapController, + InstitutionalSnapControllerMessenger +> = (request) => { + const controller = new InstitutionalSnapController({ + messenger: request.controllerMessenger, + }); + + return { + controller, + }; +}; diff --git a/app/scripts/controller-init/messengers/accounts/institutional-snap-controller-messenger.ts b/app/scripts/controller-init/messengers/accounts/institutional-snap-controller-messenger.ts new file mode 100644 index 000000000000..511f9ec8d418 --- /dev/null +++ b/app/scripts/controller-init/messengers/accounts/institutional-snap-controller-messenger.ts @@ -0,0 +1,66 @@ +import { AccountsControllerGetAccountByAddressAction } from '@metamask/accounts-controller'; +import { Messenger, RestrictedMessenger } from '@metamask/base-controller'; +import { HandleSnapRequest } from '@metamask/snaps-controllers'; +import { TransactionControllerUpdateCustodialTransactionAction } from '@metamask/transaction-controller'; +import { InstitutionalSnapController } from '../../../controllers/institutional-snap/InstitutionalSnapController'; + +const controllerName = 'InstitutionalSnapController'; + +export type InstitutionalSnapControllerPublishHookAction = { + type: `${typeof controllerName}:publishHook`; + handler: InstitutionalSnapController['deferPublicationHook']; +}; + +export type InstitutionalSnapControllerBeforeCheckPendingTransactionHookAction = + { + type: `${typeof controllerName}:beforeCheckPendingTransactionHook`; + handler: InstitutionalSnapController['beforeCheckPendingTransactionHook']; + }; + +export type InstitutionalSnapRequestSearchParameters = { + from: string; + to: string; + value: string; + data: string; + chainId: string; +}; + +type AllowedActions = + | HandleSnapRequest + | AccountsControllerGetAccountByAddressAction + | TransactionControllerUpdateCustodialTransactionAction; + +type Actions = + | AllowedActions + | InstitutionalSnapControllerPublishHookAction + | InstitutionalSnapControllerBeforeCheckPendingTransactionHookAction; + +export type InstitutionalSnapControllerMessenger = RestrictedMessenger< + 'InstitutionalSnapControllerMessenger', + Actions, + never, + Actions['type'], + never +>; + +/** + * Get a restricted controller messenger for the rate limit controller. This is + * scoped to the actions and events that the rate limit controller is allowed to + * handle. + * + * @param messenger - The messenger to restrict. + * @returns The restricted controller messenger. + */ +export function getInstitutionalSnapControllerMessenger( + messenger: Messenger, +) { + return messenger.getRestricted({ + name: 'InstitutionalSnapController', + allowedActions: [ + 'AccountsController:getAccountByAddress', + 'SnapController:handleRequest', + 'TransactionController:updateCustodialTransaction', + ], + allowedEvents: [], + }); +} diff --git a/app/scripts/controller-init/messengers/assets/assets-contract-controller-messenger.test.ts b/app/scripts/controller-init/messengers/assets/assets-contract-controller-messenger.test.ts new file mode 100644 index 000000000000..28f16d74afc3 --- /dev/null +++ b/app/scripts/controller-init/messengers/assets/assets-contract-controller-messenger.test.ts @@ -0,0 +1,14 @@ +import { Messenger, RestrictedMessenger } from '@metamask/base-controller'; +import { getAssetsContractControllerMessenger } from './assets-contract-controller-messenger'; + +describe('getAssetsContractControllerMessenger', () => { + it('returns a restricted messenger', () => { + const messenger = new Messenger(); + const assetsContractControllerMessenger = + getAssetsContractControllerMessenger(messenger); + + expect(assetsContractControllerMessenger).toBeInstanceOf( + RestrictedMessenger, + ); + }); +}); diff --git a/app/scripts/controller-init/messengers/assets/assets-contract-controller-messenger.ts b/app/scripts/controller-init/messengers/assets/assets-contract-controller-messenger.ts new file mode 100644 index 000000000000..527bccee69a1 --- /dev/null +++ b/app/scripts/controller-init/messengers/assets/assets-contract-controller-messenger.ts @@ -0,0 +1,48 @@ +import { Messenger } from '@metamask/base-controller'; +import { + NetworkControllerGetNetworkClientByIdAction, + NetworkControllerGetNetworkConfigurationByNetworkClientId, + NetworkControllerGetSelectedNetworkClientAction, + NetworkControllerGetStateAction, + NetworkControllerNetworkDidChangeEvent, +} from '@metamask/network-controller'; +import { PreferencesControllerStateChangeEvent } from '@metamask/preferences-controller'; + +type Actions = + | NetworkControllerGetNetworkClientByIdAction + | NetworkControllerGetNetworkConfigurationByNetworkClientId + | NetworkControllerGetSelectedNetworkClientAction + | NetworkControllerGetStateAction; + +type Events = + | PreferencesControllerStateChangeEvent + | NetworkControllerNetworkDidChangeEvent; + +export type AssetsContractControllerMessenger = ReturnType< + typeof getAssetsContractControllerMessenger +>; + +/** + * Get a restricted messenger for the AssetsContractController. This is scoped to the + * actions and events that the AssetsContractController is allowed to handle. + * + * @param messenger - The controller messenger to restrict. + * @returns The restricted controller messenger. + */ +export function getAssetsContractControllerMessenger( + messenger: Messenger, +) { + return messenger.getRestricted({ + name: 'AssetsContractController', + allowedActions: [ + 'NetworkController:getNetworkClientById', + 'NetworkController:getNetworkConfigurationByNetworkClientId', + 'NetworkController:getSelectedNetworkClient', + 'NetworkController:getState', + ], + allowedEvents: [ + 'PreferencesController:stateChange', + 'NetworkController:networkDidChange', + ], + }); +} diff --git a/app/scripts/controller-init/messengers/assets/index.ts b/app/scripts/controller-init/messengers/assets/index.ts new file mode 100644 index 000000000000..faa4125ac672 --- /dev/null +++ b/app/scripts/controller-init/messengers/assets/index.ts @@ -0,0 +1,11 @@ +export { getTokenRatesControllerMessenger } from './token-rates-controller-messenger'; +export type { TokenRatesControllerMessenger } from './token-rates-controller-messenger'; + +export { getNftControllerMessenger } from './nft-controller-messenger'; +export type { NftControllerMessenger } from './nft-controller-messenger'; + +export { getNftDetectionControllerMessenger } from './nft-detection-controller-messenger'; +export type { NftDetectionControllerMessenger } from './nft-detection-controller-messenger'; + +export { getAssetsContractControllerMessenger } from './assets-contract-controller-messenger'; +export type { AssetsContractControllerMessenger } from './assets-contract-controller-messenger'; diff --git a/app/scripts/controller-init/messengers/assets/nft-controller-messenger.test.ts b/app/scripts/controller-init/messengers/assets/nft-controller-messenger.test.ts new file mode 100644 index 000000000000..f94befe1b8e0 --- /dev/null +++ b/app/scripts/controller-init/messengers/assets/nft-controller-messenger.test.ts @@ -0,0 +1,11 @@ +import { Messenger, RestrictedMessenger } from '@metamask/base-controller'; +import { getNftControllerMessenger } from './nft-controller-messenger'; + +describe('getNftControllerMessenger', () => { + it('returns a restricted messenger', () => { + const messenger = new Messenger(); + const nftControllerMessenger = getNftControllerMessenger(messenger); + + expect(nftControllerMessenger).toBeInstanceOf(RestrictedMessenger); + }); +}); diff --git a/app/scripts/controller-init/messengers/assets/nft-controller-messenger.ts b/app/scripts/controller-init/messengers/assets/nft-controller-messenger.ts new file mode 100644 index 000000000000..1817b3abb1f8 --- /dev/null +++ b/app/scripts/controller-init/messengers/assets/nft-controller-messenger.ts @@ -0,0 +1,73 @@ +import { Messenger } from '@metamask/base-controller'; +import { + NetworkControllerGetNetworkClientByIdAction, + NetworkControllerNetworkDidChangeEvent, +} from '@metamask/network-controller'; +import { + AccountsControllerGetSelectedAccountAction, + AccountsControllerGetAccountAction, + AccountsControllerSelectedEvmAccountChangeEvent, +} from '@metamask/accounts-controller'; +import { PreferencesControllerStateChangeEvent } from '@metamask/preferences-controller'; +import { + AssetsContractControllerGetERC1155BalanceOfAction, + AssetsContractControllerGetERC1155TokenURIAction, + AssetsContractControllerGetERC721AssetNameAction, + AssetsContractControllerGetERC721AssetSymbolAction, + AssetsContractControllerGetERC721OwnerOfAction, + AssetsContractControllerGetERC721TokenURIAction, +} from '@metamask/assets-controllers'; +import { AddApprovalRequest } from '@metamask/approval-controller'; + +type Actions = + | AddApprovalRequest + | AccountsControllerGetAccountAction + | AccountsControllerGetSelectedAccountAction + | NetworkControllerGetNetworkClientByIdAction + | AssetsContractControllerGetERC721AssetNameAction + | AssetsContractControllerGetERC721AssetSymbolAction + | AssetsContractControllerGetERC721TokenURIAction + | AssetsContractControllerGetERC721OwnerOfAction + | AssetsContractControllerGetERC1155BalanceOfAction + | AssetsContractControllerGetERC1155TokenURIAction; + +type Events = + | PreferencesControllerStateChangeEvent + | NetworkControllerNetworkDidChangeEvent + | AccountsControllerSelectedEvmAccountChangeEvent; + +export type NftControllerMessenger = ReturnType< + typeof getNftControllerMessenger +>; + +/** + * Get a restricted messenger for the NFT controller. This is scoped to the + * actions and events that the NFT controller is allowed to handle. + * + * @param messenger - The controller messenger to restrict. + * @returns The restricted controller messenger. + */ +export function getNftControllerMessenger( + messenger: Messenger, +) { + return messenger.getRestricted({ + name: 'NftController', + allowedEvents: [ + 'PreferencesController:stateChange', + 'NetworkController:networkDidChange', + 'AccountsController:selectedEvmAccountChange', + ], + allowedActions: [ + 'ApprovalController:addRequest', + 'NetworkController:getNetworkClientById', + 'AccountsController:getSelectedAccount', + 'AccountsController:getAccount', + 'AssetsContractController:getERC721AssetName', + 'AssetsContractController:getERC721AssetSymbol', + 'AssetsContractController:getERC721TokenURI', + 'AssetsContractController:getERC721OwnerOf', + 'AssetsContractController:getERC1155BalanceOf', + 'AssetsContractController:getERC1155TokenURI', + ], + }); +} diff --git a/app/scripts/controller-init/messengers/assets/nft-detection-controller-messenger.test.ts b/app/scripts/controller-init/messengers/assets/nft-detection-controller-messenger.test.ts new file mode 100644 index 000000000000..d071f401f78a --- /dev/null +++ b/app/scripts/controller-init/messengers/assets/nft-detection-controller-messenger.test.ts @@ -0,0 +1,12 @@ +import { Messenger, RestrictedMessenger } from '@metamask/base-controller'; +import { getNftDetectionControllerMessenger } from './nft-detection-controller-messenger'; + +describe('getNftDetectionControllerMessenger', () => { + it('returns a restricted messenger', () => { + const messenger = new Messenger(); + const nftDetectionControllerMessenger = + getNftDetectionControllerMessenger(messenger); + + expect(nftDetectionControllerMessenger).toBeInstanceOf(RestrictedMessenger); + }); +}); diff --git a/app/scripts/controller-init/messengers/assets/nft-detection-controller-messenger.ts b/app/scripts/controller-init/messengers/assets/nft-detection-controller-messenger.ts new file mode 100644 index 000000000000..6ba5d1bc84a6 --- /dev/null +++ b/app/scripts/controller-init/messengers/assets/nft-detection-controller-messenger.ts @@ -0,0 +1,48 @@ +import { Messenger } from '@metamask/base-controller'; +import { + NetworkControllerGetNetworkClientByIdAction, + NetworkControllerGetStateAction, + NetworkControllerStateChangeEvent, +} from '@metamask/network-controller'; +import { AccountsControllerGetSelectedAccountAction } from '@metamask/accounts-controller'; +import { PreferencesControllerStateChangeEvent } from '@metamask/preferences-controller'; +import { AddApprovalRequest } from '@metamask/approval-controller'; + +type Actions = + | AddApprovalRequest + | NetworkControllerGetStateAction + | AccountsControllerGetSelectedAccountAction + | NetworkControllerGetNetworkClientByIdAction; + +type Events = + | PreferencesControllerStateChangeEvent + | NetworkControllerStateChangeEvent; + +export type NftDetectionControllerMessenger = ReturnType< + typeof getNftDetectionControllerMessenger +>; + +/** + * Get a restricted messenger for the NFT detection controller. This is scoped to the + * actions and events that the NFT controller is allowed to handle. + * + * @param messenger - The controller messenger to restrict. + * @returns The restricted controller messenger. + */ +export function getNftDetectionControllerMessenger( + messenger: Messenger, +) { + return messenger.getRestricted({ + name: 'NftDetectionController', + allowedEvents: [ + 'NetworkController:stateChange', + 'PreferencesController:stateChange', + ], + allowedActions: [ + 'ApprovalController:addRequest', + 'NetworkController:getState', + 'NetworkController:getNetworkClientById', + 'AccountsController:getSelectedAccount', + ], + }); +} diff --git a/app/scripts/controller-init/messengers/assets/token-rates-controller-messenger.test.ts b/app/scripts/controller-init/messengers/assets/token-rates-controller-messenger.test.ts new file mode 100644 index 000000000000..400f5ebc9b6f --- /dev/null +++ b/app/scripts/controller-init/messengers/assets/token-rates-controller-messenger.test.ts @@ -0,0 +1,12 @@ +import { Messenger, RestrictedMessenger } from '@metamask/base-controller'; +import { getTokenRatesControllerMessenger } from './token-rates-controller-messenger'; + +describe('getTokenRatesControllerMessenger', () => { + it('returns a restricted messenger', () => { + const messenger = new Messenger(); + const tokenRatesControllerMessenger = + getTokenRatesControllerMessenger(messenger); + + expect(tokenRatesControllerMessenger).toBeInstanceOf(RestrictedMessenger); + }); +}); diff --git a/app/scripts/controller-init/messengers/assets/token-rates-controller-messenger.ts b/app/scripts/controller-init/messengers/assets/token-rates-controller-messenger.ts new file mode 100644 index 000000000000..c19824dc33e2 --- /dev/null +++ b/app/scripts/controller-init/messengers/assets/token-rates-controller-messenger.ts @@ -0,0 +1,61 @@ +import { Messenger } from '@metamask/base-controller'; +import { + NetworkControllerGetStateAction, + NetworkControllerGetNetworkClientByIdAction, + NetworkControllerStateChangeEvent, +} from '@metamask/network-controller'; +import { + AccountsControllerGetSelectedAccountAction, + AccountsControllerGetAccountAction, + AccountsControllerSelectedEvmAccountChangeEvent, +} from '@metamask/accounts-controller'; +import { PreferencesControllerStateChangeEvent } from '@metamask/preferences-controller'; +import { + TokensControllerGetStateAction, + TokensControllerStateChangeEvent, +} from '@metamask/assets-controllers'; + +type Actions = + | TokensControllerGetStateAction + | NetworkControllerGetNetworkClientByIdAction + | NetworkControllerGetStateAction + | AccountsControllerGetAccountAction + | AccountsControllerGetSelectedAccountAction; + +type Events = + | NetworkControllerStateChangeEvent + | AccountsControllerSelectedEvmAccountChangeEvent + | PreferencesControllerStateChangeEvent + | TokensControllerStateChangeEvent; + +export type TokenRatesControllerMessenger = ReturnType< + typeof getTokenRatesControllerMessenger +>; + +/** + * Get a restricted messenger for the Token Rates controller. This is scoped to the + * actions and events that the Token Rates controller is allowed to handle. + * + * @param messenger - The controller messenger to restrict. + * @returns The restricted controller messenger. + */ +export function getTokenRatesControllerMessenger( + messenger: Messenger, +) { + return messenger.getRestricted({ + name: 'TokenRatesController', + allowedActions: [ + 'TokensController:getState', + 'NetworkController:getNetworkClientById', + 'NetworkController:getState', + 'AccountsController:getAccount', + 'AccountsController:getSelectedAccount', + ], + allowedEvents: [ + 'NetworkController:stateChange', + 'AccountsController:selectedEvmAccountChange', + 'PreferencesController:stateChange', + 'TokensController:stateChange', + ], + }); +} diff --git a/app/scripts/controller-init/messengers/index.ts b/app/scripts/controller-init/messengers/index.ts index 4a3c23a7529a..a959dca3ca8f 100644 --- a/app/scripts/controller-init/messengers/index.ts +++ b/app/scripts/controller-init/messengers/index.ts @@ -25,10 +25,17 @@ import { getMultichainNetworkControllerMessenger, getMultichainAssetsRatesControllerMessenger, } from './multichain'; +import { getInstitutionalSnapControllerMessenger } from './accounts/institutional-snap-controller-messenger'; import { getAuthenticationControllerMessenger, getUserStorageControllerMessenger, } from './identity'; +import { + getAssetsContractControllerMessenger, + getNftControllerMessenger, + getNftDetectionControllerMessenger, + getTokenRatesControllerMessenger, +} from './assets'; import { getNotificationServicesControllerMessenger, getNotificationServicesPushControllerMessenger, @@ -47,6 +54,10 @@ export const CONTROLLER_MESSENGERS = { getMessenger: getExecutionServiceMessenger, getInitMessenger: noop, }, + InstitutionalSnapController: { + getMessenger: getInstitutionalSnapControllerMessenger, + getInitMessenger: noop, + }, MultichainAssetsController: { getMessenger: getMultichainAssetsControllerMessenger, getInitMessenger: noop, @@ -107,4 +118,20 @@ export const CONTROLLER_MESSENGERS = { getMessenger: getUserStorageControllerMessenger, getInitMessenger: noop, }, + TokenRatesController: { + getMessenger: getTokenRatesControllerMessenger, + getInitMessenger: noop, + }, + NftController: { + getMessenger: getNftControllerMessenger, + getInitMessenger: noop, + }, + NftDetectionController: { + getMessenger: getNftDetectionControllerMessenger, + getInitMessenger: noop, + }, + AssetsContractController: { + getMessenger: getAssetsContractControllerMessenger, + getInitMessenger: noop, + }, } as const; diff --git a/app/scripts/controller-init/messengers/transaction-controller-messenger.ts b/app/scripts/controller-init/messengers/transaction-controller-messenger.ts index 68ed9a2e02b2..6a0bfb9a64b6 100644 --- a/app/scripts/controller-init/messengers/transaction-controller-messenger.ts +++ b/app/scripts/controller-init/messengers/transaction-controller-messenger.ts @@ -25,17 +25,27 @@ import { } from '@metamask/transaction-controller'; import { SmartTransactionsControllerSmartTransactionEvent } from '@metamask/smart-transactions-controller'; import { RemoteFeatureFlagControllerGetStateAction } from '@metamask/remote-feature-flag-controller'; -import { KeyringControllerSignEip7702AuthorizationAction } from '@metamask/keyring-controller'; +import { + KeyringControllerSignEip7702AuthorizationAction, + KeyringControllerSignTypedMessageAction, +} from '@metamask/keyring-controller'; import { SwapsControllerSetApproveTxIdAction, SwapsControllerSetTradeTxIdAction, } from '../../controllers/swaps/swaps.types'; +import { + InstitutionalSnapControllerPublishHookAction, + InstitutionalSnapControllerBeforeCheckPendingTransactionHookAction, +} from './accounts/institutional-snap-controller-messenger'; type MessengerActions = | ApprovalControllerActions | AccountsControllerGetSelectedAccountAction | AccountsControllerGetStateAction + | InstitutionalSnapControllerPublishHookAction + | InstitutionalSnapControllerBeforeCheckPendingTransactionHookAction | KeyringControllerSignEip7702AuthorizationAction + | KeyringControllerSignTypedMessageAction | NetworkControllerFindNetworkClientIdByChainIdAction | NetworkControllerGetEIP1559CompatibilityAction | NetworkControllerGetNetworkClientByIdAction @@ -103,6 +113,10 @@ export function getTransactionControllerInitMessenger( 'ApprovalController:endFlow', 'ApprovalController:startFlow', 'ApprovalController:updateRequestState', + 'InstitutionalSnapController:beforeCheckPendingTransactionHook', + 'InstitutionalSnapController:publishHook', + 'KeyringController:signEip7702Authorization', + 'KeyringController:signTypedMessage', 'NetworkController:getEIP1559Compatibility', 'RemoteFeatureFlagController:getState', 'SwapsController:setApproveTxId', diff --git a/app/scripts/controller-init/test/utils.ts b/app/scripts/controller-init/test/utils.ts index 93b105d3cc0d..30c836c9507b 100644 --- a/app/scripts/controller-init/test/utils.ts +++ b/app/scripts/controller-init/test/utils.ts @@ -21,6 +21,7 @@ export function buildControllerInitRequestMock(): jest.Mocked< getPermittedAccounts: jest.fn(), getProvider: jest.fn(), getTransactionMetricsRequest: jest.fn(), + updateAccountBalanceForTransactionNetwork: jest.fn(), offscreenPromise: Promise.resolve(), persistedState: {}, removeAllConnections: jest.fn(), diff --git a/app/scripts/controller-init/types.ts b/app/scripts/controller-init/types.ts index 67f35d3da8e6..a47abccf4731 100644 --- a/app/scripts/controller-init/types.ts +++ b/app/scripts/controller-init/types.ts @@ -8,6 +8,7 @@ import { import { Hex } from '@metamask/utils'; import { Duplex } from 'readable-stream'; import { SubjectType } from '@metamask/permission-controller'; +import { TransactionMeta } from '@metamask/transaction-controller'; import type { TransactionMetricsRequest } from '../../../shared/types/metametrics'; import { MessageSender } from '../../../types/global'; import { @@ -29,7 +30,11 @@ export type ControllerByName = { * e.g. `{ TransactionController: { transactions: [] } }`. */ export type ControllerPersistedState = Partial<{ - [name in ControllerName]: Partial; + [name in ControllerName]: Partial< + ControllerByName[name] extends { state: unknown } + ? ControllerByName[name]['state'] + : never + >; }>; /** Generic controller messenger using base template types. */ @@ -117,6 +122,13 @@ export type ControllerInitRequest< */ getTransactionMetricsRequest(): TransactionMetricsRequest; + /** + * Function to update account balance for network of the transaction + */ + updateAccountBalanceForTransactionNetwork( + transactionMeta: TransactionMeta, + ): void; + /** * A promise that resolves when the offscreen document is ready. */ diff --git a/app/scripts/controllers/account-tracker-controller.test.ts b/app/scripts/controllers/account-tracker-controller.test.ts index d182b1c68ce3..6b1db2ae1b4a 100644 --- a/app/scripts/controllers/account-tracker-controller.test.ts +++ b/app/scripts/controllers/account-tracker-controller.test.ts @@ -767,6 +767,114 @@ describe('AccountTrackerController', () => { }); }); + describe('updateAccountByAddress', () => { + it('does not update account by address if completedOnboarding is false', async () => { + await withController( + { + completedOnboarding: false, + }, + async ({ controller }) => { + const VALID_ADDRESS_TO_UPDATE = '0x1234'; + await controller.updateAccountByAddress({ + address: VALID_ADDRESS_TO_UPDATE, + }); + + expect(controller.state).toStrictEqual({ + accounts: {}, + currentBlockGasLimit: '', + accountsByChainId: {}, + currentBlockGasLimitByChainId: {}, + }); + }, + ); + }); + + it('updates an account by address if completedOnboarding is true', async () => { + const VALID_ADDRESS_TO_UPDATE = '0x1234'; + await withController( + { + completedOnboarding: true, + state: { + accounts: { + [VALID_ADDRESS_TO_UPDATE]: { + address: VALID_ADDRESS_TO_UPDATE, + balance: null, + }, + }, + }, + }, + async ({ controller }) => { + await controller.updateAccountByAddress({ + address: VALID_ADDRESS_TO_UPDATE, + }); + + expect(controller.state).toStrictEqual({ + accounts: { + [VALID_ADDRESS_TO_UPDATE]: { + address: VALID_ADDRESS_TO_UPDATE, + balance: '0xabc', + }, + }, + currentBlockGasLimit: '', + accountsByChainId: { + [currentChainId]: { + [VALID_ADDRESS_TO_UPDATE]: { + address: VALID_ADDRESS_TO_UPDATE, + balance: '0xabc', + }, + }, + }, + currentBlockGasLimitByChainId: {}, + }); + }, + ); + }); + + it('updates an account for selected address if no address is provided', async () => { + await withController( + { + completedOnboarding: true, + state: { + accounts: { + [VALID_ADDRESS]: { + address: VALID_ADDRESS, + balance: null, + }, + }, + accountsByChainId: { + [currentChainId]: { + [VALID_ADDRESS]: { + address: VALID_ADDRESS, + balance: null, + }, + }, + }, + }, + }, + async ({ controller }) => { + expect(controller.state).toStrictEqual({ + accounts: { + [VALID_ADDRESS]: { + address: VALID_ADDRESS, + balance: null, + }, + }, + accountsByChainId: { + [currentChainId]: { + [VALID_ADDRESS]: { + address: VALID_ADDRESS, + balance: null, + }, + }, + }, + currentBlockGasLimit: '', + currentBlockGasLimitByChainId: {}, + }); + }, + ); + }); + }); + describe('onAccountRemoved', () => { it('should remove an account from state', async () => { await withController( diff --git a/app/scripts/controllers/account-tracker-controller.ts b/app/scripts/controllers/account-tracker-controller.ts index 80b04458af2f..382146dfe9d2 100644 --- a/app/scripts/controllers/account-tracker-controller.ts +++ b/app/scripts/controllers/account-tracker-controller.ts @@ -703,6 +703,35 @@ export default class AccountTrackerController extends BaseController< } } + async updateAccountByAddress({ + address, + networkClientId, + }: { + address?: string; + networkClientId?: NetworkClientId; + } = {}): Promise { + const { completedOnboarding } = this.messagingSystem.call( + 'OnboardingController:getState', + ); + if (!completedOnboarding) { + return; + } + + const selectedAddress = + address || + this.messagingSystem.call('AccountsController:getSelectedAccount') + .address; + + if (!selectedAddress) { + return; + } + + const { chainId, provider } = + this.#getCorrectNetworkClient(networkClientId); + + await this.#updateAccount(selectedAddress, provider, chainId); + } + /** * Updates the current balance of an account. * diff --git a/app/scripts/controllers/app-state-controller.ts b/app/scripts/controllers/app-state-controller.ts index 075397dca721..7106edc64bc7 100644 --- a/app/scripts/controllers/app-state-controller.ts +++ b/app/scripts/controllers/app-state-controller.ts @@ -563,34 +563,27 @@ export class AppStateController extends BaseController< } /** - * Updates slides by adding new slides that don't already exist in state + * Replaces slides in state with new slides. If a slide with the same id + * already exists, it will be merged with the new slide. * - * @param slides - Array of new slides to add + * @param slides - Array of new slides */ updateSlides(slides: CarouselSlide[]): void { this.update((state) => { const currentSlides = state.slides || []; - // Updates the undismissable property for slides that already exist in state - const updatedCurrentSlides = currentSlides.map((currentSlide) => { - const matchingNewSlide = slides.find((s) => s.id === currentSlide.id); - if (matchingNewSlide) { + const newSlides = slides.map((slide) => { + const existingSlide = currentSlides.find((s) => s.id === slide.id); + if (existingSlide) { return { - ...currentSlide, - undismissable: matchingNewSlide.undismissable, + ...existingSlide, + ...slide, }; } - return currentSlide; - }); - - // Adds new slides that don't already exist in state - const newSlides = slides.filter((newSlide) => { - return !currentSlides.some( - (currentSlide) => currentSlide.id === newSlide.id, - ); + return slide; }); - state.slides = [...newSlides, ...updatedCurrentSlides]; + state.slides = [...newSlides]; }); } diff --git a/app/scripts/controllers/bridge-status/validators.test.ts b/app/scripts/controllers/bridge-status/validators.test.ts index c294121dc6bf..fb2f4f904e8e 100644 --- a/app/scripts/controllers/bridge-status/validators.test.ts +++ b/app/scripts/controllers/bridge-status/validators.test.ts @@ -218,7 +218,6 @@ const BridgeTxStatusResponses = { describe('validators', () => { describe('bridgeStatusValidator', () => { - // @ts-expect-error - it.each is a function it.each([ { input: BridgeTxStatusResponses.STATUS_PENDING_VALID, diff --git a/app/scripts/controllers/encryption-public-key.test.ts b/app/scripts/controllers/encryption-public-key.test.ts index dc3550a891fb..c5764ee1628b 100644 --- a/app/scripts/controllers/encryption-public-key.test.ts +++ b/app/scripts/controllers/encryption-public-key.test.ts @@ -191,7 +191,6 @@ describe('EncryptionPublicKeyController', () => { }); describe('newRequestEncryptionPublicKey', () => { - // @ts-expect-error This function is missing from the Mocha type definitions it.each([ ['Ledger', KeyringType.ledger], ['Trezor', KeyringType.trezor], diff --git a/app/scripts/controllers/institutional-snap/InstitutionalSnapController.test.ts b/app/scripts/controllers/institutional-snap/InstitutionalSnapController.test.ts new file mode 100644 index 000000000000..56425442fe78 --- /dev/null +++ b/app/scripts/controllers/institutional-snap/InstitutionalSnapController.test.ts @@ -0,0 +1,233 @@ +import { Messenger } from '@metamask/base-controller'; +import { ORIGIN_METAMASK } from '@metamask/controller-utils'; +import { HandlerType } from '@metamask/snaps-utils'; +import { + TransactionStatus, + TransactionEnvelopeType, + TransactionMeta, +} from '@metamask/transaction-controller'; +import InstitutionalWalletSnap from '@metamask/institutional-wallet-snap/dist/preinstalled-snap.json'; +import { + InstitutionalSnapController, + InstitutionalSnapControllerMessenger, + AllowedActions, + InstitutionalSnapControllerPublishHookAction, + InstitutionalSnapControllerBeforeCheckPendingTransactionHookAction, +} from './InstitutionalSnapController'; + +describe('InstitutionalSnapController', () => { + let controller: InstitutionalSnapController; + let messenger: InstitutionalSnapControllerMessenger; + + const mockTransactionMeta: TransactionMeta = { + id: '123', + chainId: '0x1', + txParams: { + from: '0x123', + to: '0x456', + value: '0x1', + data: '0x', + }, + networkClientId: '1', + status: TransactionStatus.unapproved, + time: Date.now(), + }; + + const mockSnapResponse = { + keyringRequest: { + id: '123', + scope: 'scope', + account: '0x123', + request: { + method: 'method', + params: [ + { + chainId: '1', + nonce: '0x1', + maxPriorityFeePerGas: '0x1', + maxFeePerGas: '0x1', + gasLimit: '0x1', + to: '0x456', + value: '0x1', + data: '0x', + accessList: [], + from: '0x123', + type: '0x2', + }, + ], + }, + }, + type: 'type', + fulfilled: true, + rejected: false, + lastUpdated: 123456789, + transaction: { + custodianTransactionId: 'custodian-123', + transactionStatus: { + finished: true, + success: true, + displayText: 'Success', + submitted: true, + reason: '', + signed: true, + }, + from: '0x123', + custodianPublishesTransaction: true, + maxFeePerGas: '0x1', + maxPriorityFeePerGas: '0x1', + gasLimit: '0x1', + nonce: '0x1', + to: '0x456', + transactionHash: '0xhash', + type: '0x2', + }, + result: { + v: '0x1', + r: '0x2', + s: '0x3', + }, + }; + + beforeEach(() => { + const baseMessenger = new Messenger< + | AllowedActions + | InstitutionalSnapControllerPublishHookAction + | InstitutionalSnapControllerBeforeCheckPendingTransactionHookAction, + never + >(); + + messenger = baseMessenger.getRestricted({ + name: 'InstitutionalSnapController', + allowedActions: [ + 'SnapController:handleRequest', + 'AccountsController:getAccountByAddress', + 'TransactionController:updateCustodialTransaction', + ], + allowedEvents: [], + }) as InstitutionalSnapControllerMessenger; + + // Mock messenger calls + messenger.registerActionHandler = jest.fn(); + messenger.call = jest.fn().mockImplementation((method, ..._args) => { + switch (method) { + case 'SnapController:handleRequest': + return mockSnapResponse; + case 'AccountsController:getAccountByAddress': + return { + options: { + custodian: { + deferPublication: true, + }, + }, + }; + case 'TransactionController:updateCustodialTransaction': + return {}; + default: + return {}; + } + }); + + controller = new InstitutionalSnapController({ messenger }); + }); + + describe('constructor', () => { + it('should initialize correctly', () => { + expect(messenger.registerActionHandler).toHaveBeenCalledTimes(3); + expect(messenger.registerActionHandler).toHaveBeenCalledWith( + 'InstitutionalSnapController:getState', + expect.any(Function), + ); + expect(messenger.registerActionHandler).toHaveBeenCalledWith( + 'InstitutionalSnapController:publishHook', + expect.any(Function), + ); + + expect(messenger.registerActionHandler).toHaveBeenCalledWith( + 'InstitutionalSnapController:beforeCheckPendingTransactionHook', + expect.any(Function), + ); + }); + }); + + describe('deferPublicationHook', () => { + it('should handle deferred publication', async () => { + const result = await controller.deferPublicationHook(mockTransactionMeta); + + expect(result).toBe(false); + expect(messenger.call).toHaveBeenCalledWith( + 'SnapController:handleRequest', + expect.objectContaining({ + snapId: InstitutionalWalletSnap.snapId, + origin: ORIGIN_METAMASK, + handler: HandlerType.OnRpcRequest, + request: { + method: 'transactions.getMutableTransactionParameters', + params: expect.any(Object), + }, + }), + ); + + expect(messenger.call).toHaveBeenCalledWith( + 'TransactionController:updateCustodialTransaction', + expect.objectContaining({ + transactionId: mockTransactionMeta.id, + status: TransactionStatus.submitted, + hash: mockSnapResponse.transaction.transactionHash, + nonce: mockSnapResponse.transaction.nonce, + gasLimit: mockSnapResponse.transaction.gasLimit, + maxFeePerGas: mockSnapResponse.transaction.maxFeePerGas, + maxPriorityFeePerGas: + mockSnapResponse.transaction.maxPriorityFeePerGas, + type: mockSnapResponse.transaction.type as TransactionEnvelopeType, + }), + ); + }); + + it('should handle non-deferred publication', async () => { + messenger.call = jest.fn().mockImplementation((method) => { + if (method === 'AccountsController:getAccountByAddress') { + return { + options: { + custodian: { + deferPublication: false, + }, + }, + }; + } + return {}; + }); + + const result = await controller.deferPublicationHook(mockTransactionMeta); + expect(result).toBe(true); + }); + }); + + describe('beforeCheckPendingTransactionHook', () => { + it('should return false for deferred transactions', async () => { + const result = await controller.beforeCheckPendingTransactionHook( + mockTransactionMeta, + ); + expect(result).toBe(false); + }); + + it('should return true for non-deferred transactions', async () => { + messenger.call = jest.fn().mockImplementation((method) => { + if (method === 'AccountsController:getAccountByAddress') { + return { + options: { + custodian: { + deferPublication: false, + }, + }, + }; + } + return {}; + }); + + const result = await controller.beforeCheckPendingTransactionHook( + mockTransactionMeta, + ); + expect(result).toBe(true); + }); + }); +}); diff --git a/app/scripts/controllers/institutional-snap/InstitutionalSnapController.ts b/app/scripts/controllers/institutional-snap/InstitutionalSnapController.ts new file mode 100644 index 000000000000..0f7637c90fdc --- /dev/null +++ b/app/scripts/controllers/institutional-snap/InstitutionalSnapController.ts @@ -0,0 +1,211 @@ +import { + TransactionControllerUpdateCustodialTransactionAction, + TransactionEnvelopeType, + TransactionMeta, + TransactionStatus, +} from '@metamask/transaction-controller'; +import type { HandleSnapRequest } from '@metamask/snaps-controllers'; +import { HandlerType } from '@metamask/snaps-utils'; +import { BaseController, RestrictedMessenger } from '@metamask/base-controller'; +import { AccountsControllerGetAccountByAddressAction } from '@metamask/accounts-controller'; +import { ORIGIN_METAMASK } from '@metamask/controller-utils'; + +import { INSTITUTIONAL_WALLET_SNAP_ID } from '../../../../shared/lib/accounts/institutional-wallet-snap'; +import { + InstitutionalSnapRequestSearchParameters, + InstitutionalSnapResponse, +} from './institutional-snap-controller.types'; + +const SNAP_ID = INSTITUTIONAL_WALLET_SNAP_ID; + +const controllerName = 'InstitutionalSnapController'; + +type SnapRPCRequest = Parameters[0]; + +export type AllowedActions = + | HandleSnapRequest + | AccountsControllerGetAccountByAddressAction + | TransactionControllerUpdateCustodialTransactionAction; + +export type InstitutionalSnapControllerPublishHookAction = { + type: `${typeof controllerName}:publishHook`; + handler: InstitutionalSnapController['deferPublicationHook']; +}; + +export type InstitutionalSnapControllerBeforeCheckPendingTransactionHookAction = + { + type: `${typeof controllerName}:beforeCheckPendingTransactionHook`; + handler: InstitutionalSnapController['beforeCheckPendingTransactionHook']; + }; + +type Actions = + | AllowedActions + | InstitutionalSnapControllerPublishHookAction + | InstitutionalSnapControllerBeforeCheckPendingTransactionHookAction; + +export type InstitutionalSnapControllerMessenger = RestrictedMessenger< + typeof controllerName, + Actions, + never, + Actions['type'], + never +>; + +type DeferrableTransactionAccount = { + options: { + custodian: { + deferPublication: boolean; + }; + }; +}; + +type InstitutionalSnapControllerControllerState = Record; + +const metadata = {}; + +export class InstitutionalSnapController extends BaseController< + 'InstitutionalSnapController', + InstitutionalSnapControllerControllerState, + InstitutionalSnapControllerMessenger +> { + constructor({ + messenger, + }: { + messenger: InstitutionalSnapControllerMessenger; + }) { + super({ + messenger, + name: controllerName, + state: {}, + metadata, + }); + + this.#registerMessageHandlers(); + } + + async deferPublicationHook( + transactionMeta: TransactionMeta, + ): Promise { + const shouldDefer = await this.#shouldDeferPublication(transactionMeta); + + if (shouldDefer) { + const updatedTransactionParameters = + await this.#getUpdatedTransactionParameters(transactionMeta); + + await this.#updateTransaction( + transactionMeta.id, + updatedTransactionParameters, + ); + return false; + } + + return true; + } + + async beforeCheckPendingTransactionHook( + transactionMeta: TransactionMeta, + ): Promise { + return !(await this.#shouldDeferPublication(transactionMeta)); + } + + #registerMessageHandlers() { + this.messagingSystem.registerActionHandler( + `${controllerName}:publishHook`, + this.deferPublicationHook.bind(this), + ); + + this.messagingSystem.registerActionHandler( + `${controllerName}:beforeCheckPendingTransactionHook`, + this.beforeCheckPendingTransactionHook.bind(this), + ); + } + + async #handleSnapRequest(args: SnapRPCRequest) { + const response = await this.messagingSystem.call( + 'SnapController:handleRequest', + args, + ); + return response as InstitutionalSnapResponse; + } + + async #getUpdatedTransactionParameters(transactionMeta: TransactionMeta) { + const searchParams: InstitutionalSnapRequestSearchParameters = { + from: transactionMeta.txParams.from as string, + to: transactionMeta.txParams.to as string, + value: transactionMeta.txParams.value as string, + data: transactionMeta.txParams.data as string, + chainId: transactionMeta.chainId as string, + }; + + const snapGetMutableTransactionParamsPayload: SnapRPCRequest = { + snapId: SNAP_ID, + origin: ORIGIN_METAMASK, + handler: HandlerType.OnRpcRequest, + request: { + method: 'transactions.getMutableTransactionParameters', + params: searchParams, + }, + }; + + const snapResponse = await this.#handleSnapRequest( + snapGetMutableTransactionParamsPayload, + ); + + const hash = snapResponse.transaction.transactionHash; + + return { + hash, + nonce: snapResponse.transaction.nonce, + gasLimit: snapResponse.transaction.gasLimit, + maxFeePerGas: snapResponse.transaction.maxFeePerGas, + maxPriorityFeePerGas: snapResponse.transaction.maxPriorityFeePerGas, + type: snapResponse.transaction.type as TransactionEnvelopeType, + status: TransactionStatus.submitted, + }; + } + + async #updateTransaction( + transactionId: string, + { + status, + hash, + nonce, + gasLimit, + maxFeePerGas, + maxPriorityFeePerGas, + type, + }: { + status: TransactionStatus; + hash: string; + nonce: string; + gasLimit: string; + maxFeePerGas: string; + maxPriorityFeePerGas: string; + type: TransactionEnvelopeType; + }, + ) { + const response = await this.messagingSystem.call( + 'TransactionController:updateCustodialTransaction', + { + transactionId, + status, + hash, + nonce, + gasLimit, + maxFeePerGas, + maxPriorityFeePerGas, + type, + }, + ); + return response; + } + + async #shouldDeferPublication(transactionMeta: TransactionMeta) { + const account = (await this.messagingSystem.call( + 'AccountsController:getAccountByAddress', + transactionMeta.txParams.from as string, + )) as unknown as DeferrableTransactionAccount; + + return account?.options.custodian?.deferPublication; + } +} diff --git a/app/scripts/controllers/institutional-snap/institutional-snap-controller.types.ts b/app/scripts/controllers/institutional-snap/institutional-snap-controller.types.ts new file mode 100644 index 000000000000..71205a8e5623 --- /dev/null +++ b/app/scripts/controllers/institutional-snap/institutional-snap-controller.types.ts @@ -0,0 +1,64 @@ +// Response from the `transactions.getMutableTransactionParameters` method of the Institutional Snap +export type InstitutionalSnapResponse = { + keyringRequest: { + id: string; + scope: string; + account: string; + request: { + method: string; + params: [ + { + chainId: string; + nonce: string; + maxPriorityFeePerGas: string; + maxFeePerGas: string; + gasLimit: string; + to: string; + value: string; + data: string; + accessList: string[]; + from: string; + type: string; + }, + ]; + }; + }; + type: string; + fulfilled: boolean; + rejected: boolean; + lastUpdated: number; + transaction: { + custodianTransactionId: string; + transactionStatus: { + finished: boolean; + success: boolean; + displayText: string; + submitted: boolean; + reason: string; + signed: boolean; + }; + from: string; + custodianPublishesTransaction: boolean; + maxFeePerGas: string; + maxPriorityFeePerGas: string; + gasLimit: string; + nonce: string; + to: string; + transactionHash: string; + type: string; + }; + result: { + v: string; + r: string; + s: string; + }; +}; + +// Parameters for the `transactions.getMutableTransactionParameters` method of the Institutional Snap +export type InstitutionalSnapRequestSearchParameters = { + from: string; + to: string; + value: string; + data: string; + chainId: string; +}; diff --git a/app/scripts/controllers/metametrics-controller.test.ts b/app/scripts/controllers/metametrics-controller.test.ts index ea597ae79dc6..65f1e991dbd6 100644 --- a/app/scripts/controllers/metametrics-controller.test.ts +++ b/app/scripts/controllers/metametrics-controller.test.ts @@ -873,7 +873,6 @@ describe('MetaMetricsController', function () { }); describe('Change Signature XXX anonymous event names', function () { - // @ts-expect-error This function is missing from the Mocha type definitions it.each([ ['Signature Requested', 'Signature Requested Anon'], ['Signature Rejected', 'Signature Rejected Anon'], diff --git a/app/scripts/controllers/permissions/background-api.js b/app/scripts/controllers/permissions/background-api.js index bb4c50dcef38..ac7da6c1e7c1 100644 --- a/app/scripts/controllers/permissions/background-api.js +++ b/app/scripts/controllers/permissions/background-api.js @@ -6,16 +6,24 @@ import { import { Caip25CaveatType, Caip25EndowmentPermissionName, - getEthAccounts, - setEthAccounts, - getPermittedEthChainIds, - setPermittedEthChainIds, -} from '@metamask/multichain'; + setPermittedChainIds, + setPermittedAccounts, +} from '@metamask/chain-agnostic-permission'; import { isSnapId } from '@metamask/snaps-utils'; +import { parseCaipAccountId, parseCaipChainId } from '@metamask/utils'; +import { + getCaipAccountIdsFromCaip25CaveatValue, + isInternalAccountInPermittedAccountIds, +} from '../../../../shared/lib/multichain/chain-agnostic-permission-utils/caip-accounts'; +import { getAllScopesFromCaip25CaveatValue } from '../../../../shared/lib/multichain/chain-agnostic-permission-utils/caip-chainids'; +import { getNetworkConfigurationsByCaipChainId } from '../../../../shared/modules/selectors/networks'; export function getPermissionBackgroundApiMethods({ permissionController, approvalController, + accountsController, + networkController, + multichainNetworkController, }) { // Returns the CAIP-25 caveat or undefined if it does not exist const getCaip25Caveat = (origin) => { @@ -38,7 +46,7 @@ export function getPermissionBackgroundApiMethods({ }; // To add more than one account when already connected to the dapp - const addMoreAccounts = (origin, accounts) => { + const addMoreAccounts = (origin, addresses) => { const caip25Caveat = getCaip25Caveat(origin); if (!caip25Caveat) { throw new Error( @@ -46,22 +54,90 @@ export function getPermissionBackgroundApiMethods({ ); } - const ethAccounts = getEthAccounts(caip25Caveat.value); + const internalAccounts = addresses.map((address) => { + return accountsController.getAccountByAddress(address); + }); + + // Only the first scope in the scopes array is needed because + // setPermittedAccounts currently sets accounts on all matching + // namespaces, not just the exact CaipChainId. + const caipAccountIds = internalAccounts.map((internalAccount) => { + return `${internalAccount.scopes[0]}:${internalAccount.address}`; + }); - const updatedEthAccounts = Array.from( - new Set([...ethAccounts, ...accounts]), + const existingPermittedAccountIds = getCaipAccountIdsFromCaip25CaveatValue( + caip25Caveat.value, ); - const updatedCaveatValue = setEthAccounts( + const existingPermittedChainIds = getAllScopesFromCaip25CaveatValue( caip25Caveat.value, - updatedEthAccounts, + ); + + const updatedAccountIds = Array.from( + new Set([...existingPermittedAccountIds, ...caipAccountIds]), + ); + + let updatedPermittedChainIds = [...existingPermittedChainIds]; + + const allNetworksList = Object.keys( + getNetworkConfigurationsByCaipChainId({ + networkConfigurationsByChainId: + networkController.state.networkConfigurationsByChainId, + multichainNetworkConfigurationsByChainId: + multichainNetworkController.state + .multichainNetworkConfigurationsByChainId, + internalAccounts: accountsController.state.internalAccounts, + }), + ); + + updatedAccountIds.forEach((caipAccountAddress) => { + const { + chain: { namespace: accountNamespace }, + } = parseCaipAccountId(caipAccountAddress); + + const existsSelectedChainForNamespace = updatedPermittedChainIds.some( + (caipChainId) => { + try { + const { namespace: chainNamespace } = parseCaipChainId(caipChainId); + return accountNamespace === chainNamespace; + } catch (err) { + return false; + } + }, + ); + + if (!existsSelectedChainForNamespace) { + const chainIdsForNamespace = allNetworksList.filter((caipChainId) => { + try { + const { namespace: chainNamespace } = parseCaipChainId(caipChainId); + return accountNamespace === chainNamespace; + } catch (err) { + return false; + } + }); + + updatedPermittedChainIds = [ + ...updatedPermittedChainIds, + ...chainIdsForNamespace, + ]; + } + }); + + const updatedCaveatValueWithChainIds = setPermittedChainIds( + caip25Caveat.value, + updatedPermittedChainIds, + ); + + const updatedCaveatValueWithAccountIds = setPermittedAccounts( + updatedCaveatValueWithChainIds, + updatedAccountIds, ); permissionController.updateCaveat( origin, Caip25EndowmentPermissionName, Caip25CaveatType, - updatedCaveatValue, + updatedCaveatValueWithAccountIds, ); }; @@ -73,22 +149,26 @@ export function getPermissionBackgroundApiMethods({ ); } - const ethChainIds = getPermittedEthChainIds(caip25Caveat.value); + const updatedChainIds = Array.from( + new Set([ + ...getAllScopesFromCaip25CaveatValue(caip25Caveat.value), + ...chainIds, + ]), + ); - const updatedEthChainIds = Array.from( - new Set([...ethChainIds, ...chainIds]), + const caveatValueWithChainIds = setPermittedChainIds( + caip25Caveat.value, + updatedChainIds, ); - const caveatValueWithChains = setPermittedEthChainIds( + const permittedAccountIds = getCaipAccountIdsFromCaip25CaveatValue( caip25Caveat.value, - updatedEthChainIds, ); - // ensure that the list of permitted eth accounts is set for the newly added eth scopes - const ethAccounts = getEthAccounts(caveatValueWithChains); - const caveatValueWithAccountsSynced = setEthAccounts( - caveatValueWithChains, - ethAccounts, + // ensure that the list of permitted accounts is set for the newly added scopes + const caveatValueWithAccountsSynced = setPermittedAccounts( + caveatValueWithChainIds, + permittedAccountIds, ); permissionController.updateCaveat( @@ -147,33 +227,41 @@ export function getPermissionBackgroundApiMethods({ addPermittedAccounts: (origin, accounts) => addMoreAccounts(origin, accounts), - removePermittedAccount: (origin, account) => { + removePermittedAccount: (origin, address) => { const caip25Caveat = getCaip25Caveat(origin); if (!caip25Caveat) { throw new Error( - `Cannot remove account "${account}": No permissions exist for origin "${origin}".`, + `Cannot remove account "${address}": No permissions exist for origin "${origin}".`, ); } - const existingAccounts = getEthAccounts(caip25Caveat.value); + const existingAccountIds = getCaipAccountIdsFromCaip25CaveatValue( + caip25Caveat.value, + ); - const remainingAccounts = existingAccounts.filter( - (existingAccount) => existingAccount !== account, + const internalAccount = accountsController.getAccountByAddress(address); + + const remainingAccountIds = existingAccountIds.filter( + (existingAccountId) => { + return !isInternalAccountInPermittedAccountIds(internalAccount, [ + existingAccountId, + ]); + }, ); - if (remainingAccounts.length === existingAccounts.length) { + if (remainingAccountIds.length === existingAccountIds.length) { return; } - if (remainingAccounts.length === 0) { + if (remainingAccountIds.length === 0) { permissionController.revokePermission( origin, Caip25EndowmentPermissionName, ); } else { - const updatedCaveatValue = setEthAccounts( + const updatedCaveatValue = setPermittedAccounts( caip25Caveat.value, - remainingAccounts, + remainingAccountIds, ); permissionController.updateCaveat( origin, @@ -196,13 +284,15 @@ export function getPermissionBackgroundApiMethods({ ); } - const existingEthChainIds = getPermittedEthChainIds(caip25Caveat.value); + const existingChainIds = getAllScopesFromCaip25CaveatValue( + caip25Caveat.value, + ); - const remainingChainIds = existingEthChainIds.filter( + const remainingChainIds = existingChainIds.filter( (existingChainId) => existingChainId !== chainId, ); - if (remainingChainIds.length === existingEthChainIds.length) { + if (remainingChainIds.length === existingChainIds.length) { return; } @@ -212,7 +302,7 @@ export function getPermissionBackgroundApiMethods({ Caip25EndowmentPermissionName, ); } else { - const updatedCaveatValue = setPermittedEthChainIds( + const updatedCaveatValue = setPermittedChainIds( caip25Caveat.value, remainingChainIds, ); diff --git a/app/scripts/controllers/permissions/background-api.test.js b/app/scripts/controllers/permissions/background-api.test.js index b469ce120cb9..9e0f2062b69b 100644 --- a/app/scripts/controllers/permissions/background-api.test.js +++ b/app/scripts/controllers/permissions/background-api.test.js @@ -5,13 +5,56 @@ import { import { Caip25CaveatType, Caip25EndowmentPermissionName, -} from '@metamask/multichain'; +} from '@metamask/chain-agnostic-permission'; import { flushPromises } from '../../../../test/lib/timer-helpers'; +import * as NetworkSelectors from '../../../../shared/modules/selectors/networks'; import { getPermissionBackgroundApiMethods } from './background-api'; +jest.mock('../../../../shared/modules/selectors/networks', () => ({ + ...jest.requireActual('../../../../shared/modules/selectors/networks'), + getNetworkConfigurationsByCaipChainId: jest.fn(), +})); +const MockNetworkSelectors = jest.mocked(NetworkSelectors); + +const setupPermissionBackgroundApiMethods = (overrides) => { + const params = { + permissionController: { + getCaveat: jest.fn(), + updateCaveat: jest.fn(), + grantPermissions: jest.fn(), + revokePermission: jest.fn(), + }, + approvalController: { + addAndShowApprovalRequest: jest.fn(), + }, + accountsController: { + getAccountByAddress: jest.fn(), + state: { + internalAccounts: {}, + }, + }, + networkController: { + state: { + networkConfigurationsByChainId: {}, + }, + }, + multichainNetworkController: { + state: { + multichainNetworkConfigurationsByChainId: {}, + }, + }, + ...overrides, + }; + + return getPermissionBackgroundApiMethods(params); +}; + describe('permission background API methods', () => { afterEach(() => { jest.resetAllMocks(); + MockNetworkSelectors.getNetworkConfigurationsByCaipChainId.mockReturnValue( + {}, + ); }); describe('addPermittedAccount', () => { @@ -21,7 +64,7 @@ describe('permission background API methods', () => { }; try { - getPermissionBackgroundApiMethods({ + setupPermissionBackgroundApiMethods({ permissionController, }).addPermittedAccount('foo.com', '0x1'); } catch (err) { @@ -43,7 +86,7 @@ describe('permission background API methods', () => { }; expect(() => - getPermissionBackgroundApiMethods({ + setupPermissionBackgroundApiMethods({ permissionController, }).addPermittedAccount('foo.com', '0x1'), ).toThrow( @@ -61,13 +104,124 @@ describe('permission background API methods', () => { }; expect(() => - getPermissionBackgroundApiMethods({ + setupPermissionBackgroundApiMethods({ permissionController, }).addPermittedAccount('foo.com', '0x1'), ).toThrow(new Error(`unexpected getCaveat error`)); }); - it('calls updateCaveat with the account added', () => { + it('gets the account for the passed in address', () => { + const permissionController = { + getCaveat: jest.fn().mockReturnValue({ + value: { + requiredScopes: {}, + optionalScopes: {}, + isMultichainOrigin: true, + }, + }), + updateCaveat: jest.fn(), + }; + + const accountsController = { + getAccountByAddress: jest.fn(), + state: { + internalAccounts: {}, + }, + }; + + try { + setupPermissionBackgroundApiMethods({ + permissionController, + accountsController, + }).addPermittedAccount('foo.com', '0x4'); + } catch (err) { + // noop + } + + expect(accountsController.getAccountByAddress).toHaveBeenCalledTimes(1); + expect(accountsController.getAccountByAddress).toHaveBeenCalledWith( + '0x4', + ); + }); + + it('calls updateCaveat with the caip account address added and all matching scopes added when no matching permitted scopes already exist', () => { + const permissionController = { + getCaveat: jest.fn().mockReturnValue({ + value: { + requiredScopes: { + 'eip155:1': { + accounts: [], + }, + }, + optionalScopes: { + 'bip122:000000000019d6689c085ae165831e93': { + accounts: [ + 'bip122:000000000019d6689c085ae165831e93:128Lkh3S7CkDTBZ8W7BbpsN3YYizJMp8p6', + ], + }, + }, + isMultichainOrigin: true, + }, + }), + updateCaveat: jest.fn(), + }; + + const accountsController = { + getAccountByAddress: jest.fn().mockReturnValue({ + address: '0x4', + scopes: ['solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp'], + }), + state: { + internalAccounts: {}, + }, + }; + + MockNetworkSelectors.getNetworkConfigurationsByCaipChainId.mockReturnValue( + { + 'solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp': {}, + 'solana:foo': {}, + 'solana:bar': {}, + }, + ); + + setupPermissionBackgroundApiMethods({ + permissionController, + accountsController, + }).addPermittedAccount('foo.com', '0x4'); + + expect(permissionController.updateCaveat).toHaveBeenCalledTimes(1); + expect(permissionController.updateCaveat).toHaveBeenCalledWith( + 'foo.com', + Caip25EndowmentPermissionName, + Caip25CaveatType, + { + requiredScopes: { + 'eip155:1': { + accounts: [], + }, + }, + optionalScopes: { + 'bip122:000000000019d6689c085ae165831e93': { + accounts: [ + 'bip122:000000000019d6689c085ae165831e93:128Lkh3S7CkDTBZ8W7BbpsN3YYizJMp8p6', + ], + }, + 'solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp': { + accounts: ['solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp:0x4'], + }, + 'solana:foo': { + accounts: ['solana:foo:0x4'], + }, + 'solana:bar': { + accounts: ['solana:bar:0x4'], + }, + }, + isMultichainOrigin: true, + }, + ); + }); + + it('calls updateCaveat with the caip account address added to existing matching permitted scopes', () => { const permissionController = { getCaveat: jest.fn().mockReturnValue({ value: { @@ -95,8 +249,19 @@ describe('permission background API methods', () => { updateCaveat: jest.fn(), }; - getPermissionBackgroundApiMethods({ + const accountsController = { + getAccountByAddress: jest.fn().mockReturnValue({ + address: '0x4', + scopes: ['eip155:0'], + }), + state: { + internalAccounts: {}, + }, + }; + + setupPermissionBackgroundApiMethods({ permissionController, + accountsController, }).addPermittedAccount('foo.com', '0x4'); expect(permissionController.updateCaveat).toHaveBeenCalledTimes(1); @@ -151,7 +316,7 @@ describe('permission background API methods', () => { }; try { - getPermissionBackgroundApiMethods({ + setupPermissionBackgroundApiMethods({ permissionController, }).addPermittedAccounts('foo.com', ['0x1']); } catch (err) { @@ -173,7 +338,7 @@ describe('permission background API methods', () => { }; expect(() => - getPermissionBackgroundApiMethods({ + setupPermissionBackgroundApiMethods({ permissionController, }).addPermittedAccounts('foo.com', ['0x1']), ).toThrow( @@ -191,13 +356,50 @@ describe('permission background API methods', () => { }; expect(() => - getPermissionBackgroundApiMethods({ + setupPermissionBackgroundApiMethods({ permissionController, }).addPermittedAccounts('foo.com', ['0x1']), ).toThrow(new Error(`unexpected getCaveat error`)); }); - it('calls updateCaveat with the accounts added to only eip155 scopes and all accounts for eip155 scopes synced', () => { + it('gets the accounts for the passed in addresses', () => { + const permissionController = { + getCaveat: jest.fn().mockReturnValue({ + value: { + requiredScopes: {}, + optionalScopes: {}, + isMultichainOrigin: true, + }, + }), + updateCaveat: jest.fn(), + }; + + const accountsController = { + getAccountByAddress: jest.fn(), + state: { + internalAccounts: {}, + }, + }; + + try { + setupPermissionBackgroundApiMethods({ + permissionController, + accountsController, + }).addPermittedAccounts('foo.com', ['0x4', '0x5']); + } catch (err) { + // noop + } + + expect(accountsController.getAccountByAddress).toHaveBeenCalledTimes(2); + expect(accountsController.getAccountByAddress).toHaveBeenCalledWith( + '0x4', + ); + expect(accountsController.getAccountByAddress).toHaveBeenCalledWith( + '0x5', + ); + }); + + it('calls updateCaveat with the caip account addresses added to respective scopes and all accounts for each scopes synced', () => { const permissionController = { getCaveat: jest.fn().mockReturnValue({ value: { @@ -225,8 +427,25 @@ describe('permission background API methods', () => { updateCaveat: jest.fn(), }; - getPermissionBackgroundApiMethods({ + const accountsController = { + getAccountByAddress: jest + .fn() + .mockReturnValueOnce({ + address: '0x4', + scopes: ['eip155:0'], + }) + .mockReturnValueOnce({ + address: '0x5', + scopes: ['eip155:0'], + }), + state: { + internalAccounts: {}, + }, + }; + + setupPermissionBackgroundApiMethods({ permissionController, + accountsController, }).addPermittedAccounts('foo.com', ['0x4', '0x5']); expect(permissionController.updateCaveat).toHaveBeenCalledTimes(1); @@ -275,6 +494,92 @@ describe('permission background API methods', () => { }, ); }); + + it('calls updateCaveat with the caip account addresses added when no matching permitted scopes already exist', () => { + const permissionController = { + getCaveat: jest.fn().mockReturnValue({ + value: { + requiredScopes: { + 'eip155:1': { + accounts: [], + }, + }, + optionalScopes: { + 'bip122:000000000019d6689c085ae165831e93': { + accounts: [ + 'bip122:000000000019d6689c085ae165831e93:128Lkh3S7CkDTBZ8W7BbpsN3YYizJMp8p6', + ], + }, + }, + isMultichainOrigin: true, + }, + }), + updateCaveat: jest.fn(), + }; + + const accountsController = { + getAccountByAddress: jest + .fn() + .mockReturnValueOnce({ + address: '0x4', + scopes: ['solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp'], + }) + .mockReturnValueOnce({ + address: '0x5', + scopes: ['solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp'], + }), + state: { + internalAccounts: {}, + }, + }; + + MockNetworkSelectors.getNetworkConfigurationsByCaipChainId.mockReturnValue( + { + 'solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp': {}, + 'solana:foo': {}, + 'solana:bar': {}, + }, + ); + + setupPermissionBackgroundApiMethods({ + permissionController, + accountsController, + }).addPermittedAccounts('foo.com', ['0x4', '0x5']); + + expect(permissionController.updateCaveat).toHaveBeenCalledTimes(1); + expect(permissionController.updateCaveat).toHaveBeenCalledWith( + 'foo.com', + Caip25EndowmentPermissionName, + Caip25CaveatType, + { + requiredScopes: { + 'eip155:1': { + accounts: [], + }, + }, + optionalScopes: { + 'bip122:000000000019d6689c085ae165831e93': { + accounts: [ + 'bip122:000000000019d6689c085ae165831e93:128Lkh3S7CkDTBZ8W7BbpsN3YYizJMp8p6', + ], + }, + 'solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp': { + accounts: [ + 'solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp:0x4', + 'solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp:0x5', + ], + }, + 'solana:foo': { + accounts: ['solana:foo:0x4', 'solana:foo:0x5'], + }, + 'solana:bar': { + accounts: ['solana:bar:0x4', 'solana:bar:0x5'], + }, + }, + isMultichainOrigin: true, + }, + ); + }); }); describe('removePermittedAccount', () => { @@ -284,7 +589,7 @@ describe('permission background API methods', () => { }; try { - getPermissionBackgroundApiMethods({ + setupPermissionBackgroundApiMethods({ permissionController, }).removePermittedAccount('foo.com', '0x1'); } catch (err) { @@ -306,7 +611,7 @@ describe('permission background API methods', () => { }; expect(() => - getPermissionBackgroundApiMethods({ + setupPermissionBackgroundApiMethods({ permissionController, }).removePermittedAccount('foo.com', '0x1'), ).toThrow( @@ -324,12 +629,46 @@ describe('permission background API methods', () => { }; expect(() => - getPermissionBackgroundApiMethods({ + setupPermissionBackgroundApiMethods({ permissionController, }).removePermittedAccount('foo.com', '0x1'), ).toThrow(new Error(`unexpected getCaveat error`)); }); + it('gets the account for the passed in address', () => { + const permissionController = { + getCaveat: jest.fn().mockReturnValue({ + value: { + requiredScopes: {}, + optionalScopes: {}, + isMultichainOrigin: true, + }, + }), + updateCaveat: jest.fn(), + }; + + const accountsController = { + getAccountByAddress: jest.fn(), + state: { + internalAccounts: {}, + }, + }; + + try { + setupPermissionBackgroundApiMethods({ + permissionController, + accountsController, + }).removePermittedAccount('foo.com', '0x1'); + } catch (err) { + // noop + } + + expect(accountsController.getAccountByAddress).toHaveBeenCalledTimes(1); + expect(accountsController.getAccountByAddress).toHaveBeenCalledWith( + '0x1', + ); + }); + it('does nothing if the account being removed does not exist', () => { const permissionController = { getCaveat: jest.fn().mockReturnValue({ @@ -359,15 +698,26 @@ describe('permission background API methods', () => { revokePermission: jest.fn(), }; - getPermissionBackgroundApiMethods({ + const accountsController = { + getAccountByAddress: jest.fn().mockReturnValue({ + address: '0xdeadbeef', + scopes: ['eip155:0'], + }), + state: { + internalAccounts: {}, + }, + }; + + setupPermissionBackgroundApiMethods({ permissionController, + accountsController, }).removePermittedAccount('foo.com', '0xdeadbeef'); expect(permissionController.updateCaveat).not.toHaveBeenCalled(); expect(permissionController.revokePermission).not.toHaveBeenCalled(); }); - it('revokes the entire permission if the removed account is the only eip:155 scoped account', () => { + it('revokes the entire permission if the removed account is the only account', () => { const permissionController = { getCaveat: jest.fn().mockReturnValue({ value: { @@ -381,9 +731,7 @@ describe('permission background API methods', () => { }, optionalScopes: { 'bip122:000000000019d6689c085ae165831e93': { - accounts: [ - 'bip122:000000000019d6689c085ae165831e93:128Lkh3S7CkDTBZ8W7BbpsN3YYizJMp8p6', - ], + accounts: [], }, }, isMultichainOrigin: true, @@ -392,8 +740,19 @@ describe('permission background API methods', () => { revokePermission: jest.fn(), }; - getPermissionBackgroundApiMethods({ + const accountsController = { + getAccountByAddress: jest.fn().mockReturnValue({ + address: '0x1', + scopes: ['eip155:0'], + }), + state: { + internalAccounts: {}, + }, + }; + + setupPermissionBackgroundApiMethods({ permissionController, + accountsController, }).removePermittedAccount('foo.com', '0x1'); expect(permissionController.revokePermission).toHaveBeenCalledWith( @@ -402,7 +761,7 @@ describe('permission background API methods', () => { ); }); - it('updates the caveat with the account removed and all eip155 accounts synced', () => { + it('updates the caveat with the account removed and all accounts synced across respective scope', () => { const permissionController = { getCaveat: jest.fn().mockReturnValue({ value: { @@ -430,8 +789,19 @@ describe('permission background API methods', () => { updateCaveat: jest.fn(), }; - getPermissionBackgroundApiMethods({ + const accountsController = { + getAccountByAddress: jest.fn().mockReturnValue({ + address: '0x2', + scopes: ['eip155:0'], + }), + state: { + internalAccounts: {}, + }, + }; + + setupPermissionBackgroundApiMethods({ permissionController, + accountsController, }).removePermittedAccount('foo.com', '0x2'); expect(permissionController.updateCaveat).toHaveBeenCalledWith( @@ -497,7 +867,7 @@ describe('permission background API methods', () => { grantPermissions: jest.fn(), }; - const result = getPermissionBackgroundApiMethods({ + const result = setupPermissionBackgroundApiMethods({ approvalController, permissionController, }).requestAccountsAndChainPermissionsWithId('foo.com'); @@ -546,7 +916,7 @@ describe('permission background API methods', () => { grantPermissions: jest.fn(), }; - getPermissionBackgroundApiMethods({ + setupPermissionBackgroundApiMethods({ approvalController, permissionController, }).requestAccountsAndChainPermissionsWithId('foo.com'); @@ -569,9 +939,9 @@ describe('permission background API methods', () => { }; try { - getPermissionBackgroundApiMethods({ + setupPermissionBackgroundApiMethods({ permissionController, - }).addPermittedChain('foo.com', '0x1'); + }).addPermittedChain('foo.com', 'eip155:1'); } catch (err) { // noop } @@ -591,9 +961,9 @@ describe('permission background API methods', () => { }; expect(() => - getPermissionBackgroundApiMethods({ + setupPermissionBackgroundApiMethods({ permissionController, - }).addPermittedChain('foo.com', '0x1'), + }).addPermittedChain('foo.com', 'eip155:1'), ).toThrow( new Error( `Cannot add chain permissions for origin "foo.com": no permission currently exists for this origin.`, @@ -609,13 +979,13 @@ describe('permission background API methods', () => { }; expect(() => - getPermissionBackgroundApiMethods({ + setupPermissionBackgroundApiMethods({ permissionController, - }).addPermittedChain('foo.com', '0x1'), + }).addPermittedChain('foo.com', 'eip155:1'), ).toThrow(new Error(`unexpected getCaveat error`)); }); - it('calls updateCaveat with the chain added and all eip155 accounts synced', () => { + it('calls updateCaveat with the chain added and all accounts synced across respective scopes', () => { const permissionController = { getCaveat: jest.fn().mockReturnValue({ value: { @@ -643,9 +1013,9 @@ describe('permission background API methods', () => { updateCaveat: jest.fn(), }; - getPermissionBackgroundApiMethods({ + setupPermissionBackgroundApiMethods({ permissionController, - }).addPermittedChain('foo.com', '0x539'); // 1337 + }).addPermittedChain('foo.com', 'eip155:1337'); expect(permissionController.updateCaveat).toHaveBeenCalledTimes(1); expect(permissionController.updateCaveat).toHaveBeenCalledWith( @@ -687,9 +1057,9 @@ describe('permission background API methods', () => { }; try { - getPermissionBackgroundApiMethods({ + setupPermissionBackgroundApiMethods({ permissionController, - }).addPermittedChains('foo.com', ['0x1']); + }).addPermittedChains('foo.com', ['eip155:1']); } catch (err) { // noop } @@ -709,9 +1079,9 @@ describe('permission background API methods', () => { }; expect(() => - getPermissionBackgroundApiMethods({ + setupPermissionBackgroundApiMethods({ permissionController, - }).addPermittedChains('foo.com', ['0x1']), + }).addPermittedChains('foo.com', ['eip155:1']), ).toThrow( new Error( `Cannot add chain permissions for origin "foo.com": no permission currently exists for this origin.`, @@ -727,13 +1097,13 @@ describe('permission background API methods', () => { }; expect(() => - getPermissionBackgroundApiMethods({ + setupPermissionBackgroundApiMethods({ permissionController, - }).addPermittedChains('foo.com', ['0x1']), + }).addPermittedChains('foo.com', ['eip155:1']), ).toThrow(new Error(`unexpected getCaveat error`)); }); - it('calls updateCaveat with the chains added and all eip155 accounts synced', () => { + it('calls updateCaveat with the chains added and all accounts synced across respective scopes', () => { const permissionController = { getCaveat: jest.fn().mockReturnValue({ value: { @@ -761,9 +1131,9 @@ describe('permission background API methods', () => { updateCaveat: jest.fn(), }; - getPermissionBackgroundApiMethods({ + setupPermissionBackgroundApiMethods({ permissionController, - }).addPermittedChains('foo.com', ['0x4', '0x5']); + }).addPermittedChains('foo.com', ['eip155:4', 'eip155:5']); expect(permissionController.updateCaveat).toHaveBeenCalledTimes(1); expect(permissionController.updateCaveat).toHaveBeenCalledWith( @@ -808,9 +1178,9 @@ describe('permission background API methods', () => { }; try { - getPermissionBackgroundApiMethods({ + setupPermissionBackgroundApiMethods({ permissionController, - }).removePermittedChain('foo.com', '0x1'); + }).removePermittedChain('foo.com', 'eip155:1'); } catch (err) { // noop } @@ -830,12 +1200,12 @@ describe('permission background API methods', () => { }; expect(() => - getPermissionBackgroundApiMethods({ + setupPermissionBackgroundApiMethods({ permissionController, - }).removePermittedChain('foo.com', '0x1'), + }).removePermittedChain('foo.com', 'eip155:1'), ).toThrow( new Error( - `Cannot remove permission for chainId "0x1": No permissions exist for origin "foo.com".`, + `Cannot remove permission for chainId "eip155:1": No permissions exist for origin "foo.com".`, ), ); }); @@ -848,9 +1218,9 @@ describe('permission background API methods', () => { }; expect(() => - getPermissionBackgroundApiMethods({ + setupPermissionBackgroundApiMethods({ permissionController, - }).removePermittedChain('foo.com', '0x1'), + }).removePermittedChain('foo.com', 'eip155:1'), ).toThrow(new Error(`unexpected getCaveat error`)); }); @@ -880,37 +1250,32 @@ describe('permission background API methods', () => { revokePermission: jest.fn(), }; - getPermissionBackgroundApiMethods({ + setupPermissionBackgroundApiMethods({ permissionController, - }).removePermittedChain('foo.com', '0xdeadbeef'); + }).removePermittedChain('foo.com', 'eip155:12345'); expect(permissionController.updateCaveat).not.toHaveBeenCalled(); expect(permissionController.revokePermission).not.toHaveBeenCalled(); }); - it('revokes the entire permission if the removed chain is the only eip:155 scope', () => { + // TODO: Verify this behavior (wallet vs non-wallet scopes) + it('revokes the entire permission if the removed chain is the only scope', () => { const permissionController = { getCaveat: jest.fn().mockReturnValue({ value: { requiredScopes: { 'eip155:1': {}, }, - optionalScopes: { - 'bip122:000000000019d6689c085ae165831e93': { - accounts: [ - 'bip122:000000000019d6689c085ae165831e93:128Lkh3S7CkDTBZ8W7BbpsN3YYizJMp8p6', - ], - }, - }, + optionalScopes: {}, isMultichainOrigin: true, }, }), revokePermission: jest.fn(), }; - getPermissionBackgroundApiMethods({ + setupPermissionBackgroundApiMethods({ permissionController, - }).removePermittedChain('foo.com', '0x1'); + }).removePermittedChain('foo.com', 'eip155:1'); expect(permissionController.revokePermission).toHaveBeenCalledWith( 'foo.com', @@ -943,9 +1308,9 @@ describe('permission background API methods', () => { updateCaveat: jest.fn(), }; - getPermissionBackgroundApiMethods({ + setupPermissionBackgroundApiMethods({ permissionController, - }).removePermittedChain('foo.com', '0xa'); // 10 + }).removePermittedChain('foo.com', 'eip155:10'); expect(permissionController.updateCaveat).toHaveBeenCalledWith( 'foo.com', diff --git a/app/scripts/controllers/permissions/differs.test.ts b/app/scripts/controllers/permissions/differs.test.ts index 1f17ce42bc6a..80e023f2f6fa 100644 --- a/app/scripts/controllers/permissions/differs.test.ts +++ b/app/scripts/controllers/permissions/differs.test.ts @@ -76,6 +76,7 @@ describe('PermissionController selectors', () => { }, }, isMultichainOrigin: true, + sessionProperties: {}, }, ], ]); @@ -95,6 +96,7 @@ describe('PermissionController selectors', () => { }, }, isMultichainOrigin: true, + sessionProperties: {}, }, ], ]); @@ -141,6 +143,7 @@ describe('PermissionController selectors', () => { }, }, isMultichainOrigin: true, + sessionProperties: {}, }, ], ]); @@ -196,6 +199,7 @@ describe('PermissionController selectors', () => { }, }, isMultichainOrigin: true, + sessionProperties: {}, }, ], ]); @@ -215,6 +219,7 @@ describe('PermissionController selectors', () => { }, }, isMultichainOrigin: true, + sessionProperties: {}, }, ], ]); @@ -247,6 +252,7 @@ describe('PermissionController selectors', () => { }, optionalScopes: {}, isMultichainOrigin: true, + sessionProperties: {}, }; const previousAuthorizations = new Map([ ['foo.bar', mockAuthorization], diff --git a/app/scripts/controllers/permissions/differs.ts b/app/scripts/controllers/permissions/differs.ts index f770d5131544..b50086d78296 100644 --- a/app/scripts/controllers/permissions/differs.ts +++ b/app/scripts/controllers/permissions/differs.ts @@ -2,7 +2,7 @@ import { Caip25CaveatValue, InternalScopesObject, InternalScopeString, -} from '@metamask/multichain'; +} from '@metamask/chain-agnostic-permission'; /** * Returns a map containing key/value pairs for those that have been diff --git a/app/scripts/controllers/permissions/enums.ts b/app/scripts/controllers/permissions/enums.ts index 53237cab9b07..03228d3594e2 100644 --- a/app/scripts/controllers/permissions/enums.ts +++ b/app/scripts/controllers/permissions/enums.ts @@ -1,5 +1,4 @@ export enum NOTIFICATION_NAMES { accountsChanged = 'metamask_accountsChanged', chainChanged = 'metamask_chainChanged', - sessionChanged = 'wallet_sessionChanged', } diff --git a/app/scripts/controllers/permissions/selectors.js b/app/scripts/controllers/permissions/selectors.js index 9f5f29b8eabc..41b3869ef00e 100644 --- a/app/scripts/controllers/permissions/selectors.js +++ b/app/scripts/controllers/permissions/selectors.js @@ -2,8 +2,9 @@ import { Caip25CaveatType, Caip25EndowmentPermissionName, getEthAccounts, + getPermittedAccountsForScopes, getPermittedEthChainIds, -} from '@metamask/multichain'; +} from '@metamask/chain-agnostic-permission'; import { createSelector } from 'reselect'; /** @@ -29,7 +30,8 @@ const getSubjects = (state) => state.subjects; export const getPermittedAccountsByOrigin = createSelector( getSubjects, (subjects) => { - return Object.values(subjects).reduce((originToAccountsMap, subject) => { + const originToAccountsMap = new Map(); + Object.values(subjects).forEach((subject) => { const caveats = subject.permissions?.[Caip25EndowmentPermissionName]?.caveats || []; @@ -39,8 +41,69 @@ export const getPermittedAccountsByOrigin = createSelector( const ethAccounts = getEthAccounts(caveat.value); originToAccountsMap.set(subject.origin, ethAccounts); } - return originToAccountsMap; - }, new Map()); + }); + return originToAccountsMap; + }, +); + +/** + * Get the permitted accounts for the given scopes by origin + * + * @param {Record>} state - The PermissionController state + * @param {string[]} scopes - The scopes to get the permitted accounts for + * @returns {Map} A map of origins to permitted accounts for the given scopes + */ +export const getPermittedAccountsForScopesByOrigin = createSelector( + getSubjects, + (_, scopes) => scopes, + (subjects, scopes) => { + const originToAccountsMap = new Map(); + Object.values(subjects).forEach((subject) => { + const caveats = + subject.permissions?.[Caip25EndowmentPermissionName]?.caveats || []; + + const caveat = caveats.find(({ type }) => type === Caip25CaveatType); + + if (caveat) { + const scopeAccounts = getPermittedAccountsForScopes( + caveat.value, + scopes, + ); + + if (scopeAccounts.length > 0) { + originToAccountsMap.set(subject.origin, scopeAccounts); + } + } + }); + return originToAccountsMap; + }, +); + +/** + * Get the origins with a given session property. + * + * @param state - The PermissionController state + * @param property - The property to check for + * @returns An object with keys of origins and values of session properties + */ +export const getOriginsWithSessionProperty = createSelector( + getSubjects, + (_, property) => property, + (subjects, property) => { + const result = {}; + + Object.values(subjects).forEach((subject) => { + const caveats = + subject.permissions?.[Caip25EndowmentPermissionName]?.caveats || []; + + const caveat = caveats.find(({ type }) => type === Caip25CaveatType); + const sessionProperty = caveat?.value?.sessionProperties?.[property]; + if (sessionProperty !== undefined) { + result[subject.origin] = sessionProperty; + } + }); + + return result; }, ); diff --git a/app/scripts/controllers/permissions/selectors.test.js b/app/scripts/controllers/permissions/selectors.test.js index c06c9e88e7cf..e481305f9d50 100644 --- a/app/scripts/controllers/permissions/selectors.test.js +++ b/app/scripts/controllers/permissions/selectors.test.js @@ -2,10 +2,11 @@ import { cloneDeep } from 'lodash'; import { Caip25CaveatType, Caip25EndowmentPermissionName, -} from '@metamask/multichain'; +} from '@metamask/chain-agnostic-permission'; import { getPermittedAccountsByOrigin, getPermittedChainsByOrigin, + getOriginsWithSessionProperty, } from './selectors'; describe('PermissionController selectors', () => { @@ -244,4 +245,272 @@ describe('PermissionController selectors', () => { expect(selected2).toBe(getPermittedChainsByOrigin(state2)); }); }); + + describe('getOriginsWithSessionProperty', () => { + it('returns origins that have the specified session property', () => { + const state = { + subjects: { + 'dapp1.example.com': { + origin: 'dapp1.example.com', + permissions: { + [Caip25EndowmentPermissionName]: { + caveats: [ + { + type: Caip25CaveatType, + value: { + requiredScopes: {}, + optionalScopes: {}, + sessionProperties: { + solana_accountChanged_notifications: true, + }, + }, + }, + ], + }, + }, + }, + 'dapp2.example.com': { + origin: 'dapp2.example.com', + permissions: { + [Caip25EndowmentPermissionName]: { + caveats: [ + { + type: Caip25CaveatType, + value: { + requiredScopes: {}, + optionalScopes: {}, + sessionProperties: { + another_property: 'value', + }, + }, + }, + ], + }, + }, + }, + }, + }; + + const result = getOriginsWithSessionProperty( + state, + 'solana_accountChanged_notifications', + ); + + expect(result).toStrictEqual({ + 'dapp1.example.com': true, + }); + }); + + it('returns empty object when no origins have the specified session property', () => { + const state = { + subjects: { + 'dapp1.example.com': { + origin: 'dapp1.example.com', + permissions: { + [Caip25EndowmentPermissionName]: { + caveats: [ + { + type: Caip25CaveatType, + value: { + requiredScopes: {}, + optionalScopes: {}, + sessionProperties: { + some_property: 'value', + }, + }, + }, + ], + }, + }, + }, + }, + }; + + const result = getOriginsWithSessionProperty( + state, + 'non_existent_property', + ); + + expect(result).toStrictEqual({}); + }); + + it('returns multiple origins that have the specified session property', () => { + const state = { + subjects: { + 'dapp1.example.com': { + origin: 'dapp1.example.com', + permissions: { + [Caip25EndowmentPermissionName]: { + caveats: [ + { + type: Caip25CaveatType, + value: { + requiredScopes: {}, + optionalScopes: {}, + sessionProperties: { + solana_accountChanged_notifications: true, + }, + }, + }, + ], + }, + }, + }, + 'dapp2.example.com': { + origin: 'dapp2.example.com', + permissions: { + [Caip25EndowmentPermissionName]: { + caveats: [ + { + type: Caip25CaveatType, + value: { + requiredScopes: {}, + optionalScopes: {}, + sessionProperties: { + solana_accountChanged_notifications: false, + }, + }, + }, + ], + }, + }, + }, + 'dapp3.example.com': { + origin: 'dapp3.example.com', + permissions: { + [Caip25EndowmentPermissionName]: { + caveats: [ + { + type: Caip25CaveatType, + value: { + requiredScopes: {}, + optionalScopes: {}, + sessionProperties: { + other_property: 'value', + }, + }, + }, + ], + }, + }, + }, + }, + }; + + const result = getOriginsWithSessionProperty( + state, + 'solana_accountChanged_notifications', + ); + + expect(result).toStrictEqual({ + 'dapp1.example.com': true, + 'dapp2.example.com': false, + }); + }); + + it('ignores origins without CAIP-25 permissions', () => { + const state = { + subjects: { + 'dapp1.example.com': { + origin: 'dapp1.example.com', + permissions: { + [Caip25EndowmentPermissionName]: { + caveats: [ + { + type: Caip25CaveatType, + value: { + requiredScopes: {}, + optionalScopes: {}, + sessionProperties: { + solana_accountChanged_notifications: true, + }, + }, + }, + ], + }, + }, + }, + 'dapp2.example.com': { + origin: 'dapp2.example.com', + permissions: { + eth_accounts: { + caveats: [], + }, + }, + }, + }, + }; + + const result = getOriginsWithSessionProperty( + state, + 'solana_accountChanged_notifications', + ); + + expect(result).toStrictEqual({ + 'dapp1.example.com': true, + }); + }); + + it('ignores origins with CAIP-25 permissions but without sessionProperties', () => { + const state = { + subjects: { + 'dapp1.example.com': { + origin: 'dapp1.example.com', + permissions: { + [Caip25EndowmentPermissionName]: { + caveats: [ + { + type: Caip25CaveatType, + value: { + requiredScopes: {}, + optionalScopes: {}, + // No sessionProperties + }, + }, + ], + }, + }, + }, + 'dapp2.example.com': { + origin: 'dapp2.example.com', + permissions: { + [Caip25EndowmentPermissionName]: { + caveats: [ + { + type: Caip25CaveatType, + value: { + requiredScopes: {}, + optionalScopes: {}, + sessionProperties: { + solana_accountChanged_notifications: true, + }, + }, + }, + ], + }, + }, + }, + }, + }; + + const result = getOriginsWithSessionProperty( + state, + 'solana_accountChanged_notifications', + ); + + expect(result).toStrictEqual({ + 'dapp2.example.com': true, + }); + }); + + it('handles empty subjects', () => { + const state = { + subjects: {}, + }; + + const result = getOriginsWithSessionProperty(state, 'any_property'); + + expect(result).toStrictEqual({}); + }); + }); }); diff --git a/app/scripts/controllers/permissions/specifications.js b/app/scripts/controllers/permissions/specifications.js index 9f921cf9e5ea..5b8eca07d747 100644 --- a/app/scripts/controllers/permissions/specifications.js +++ b/app/scripts/controllers/permissions/specifications.js @@ -7,7 +7,7 @@ import { Caip25CaveatType, caip25EndowmentBuilder, caip25CaveatBuilder, -} from '@metamask/multichain'; +} from '@metamask/chain-agnostic-permission'; import { EndowmentTypes, RestrictedMethods, @@ -45,16 +45,24 @@ export const CaveatFactories = Object.freeze({ * `AccountsController` internalAccount objects for all evm accounts. * @param options.findNetworkClientIdByChainId - A function that * returns the networkClientId given a chainId. + * @param options.isNonEvmScopeSupported - A function that returns true if + * a non-evm scope is supported. + * @param options.getNonEvmAccountAddresses - A function that returns the + * supported CAIP-10 account addresses for a non-evm scope. * @returns the caveat specifications to construct the PermissionController. */ export const getCaveatSpecifications = ({ listAccounts, findNetworkClientIdByChainId, + isNonEvmScopeSupported, + getNonEvmAccountAddresses, }) => { return { [Caip25CaveatType]: caip25CaveatBuilder({ listAccounts, findNetworkClientIdByChainId, + isNonEvmScopeSupported, + getNonEvmAccountAddresses, }), ...snapsCaveatsSpecifications, ...snapsEndowmentCaveatSpecifications, diff --git a/app/scripts/controllers/permissions/specifications.test.js b/app/scripts/controllers/permissions/specifications.test.js index 819945e4745d..5f1ef744feb9 100644 --- a/app/scripts/controllers/permissions/specifications.test.js +++ b/app/scripts/controllers/permissions/specifications.test.js @@ -2,7 +2,7 @@ import { SnapCaveatType } from '@metamask/snaps-rpc-methods'; import { Caip25CaveatType, Caip25EndowmentPermissionName, -} from '@metamask/multichain'; +} from '@metamask/chain-agnostic-permission'; import { getCaveatSpecifications, getPermissionSpecifications, diff --git a/app/scripts/controllers/preferences-controller.test.ts b/app/scripts/controllers/preferences-controller.test.ts index b07534beddaa..b7d983a3dd8b 100644 --- a/app/scripts/controllers/preferences-controller.test.ts +++ b/app/scripts/controllers/preferences-controller.test.ts @@ -6,7 +6,6 @@ import { AccountsController } from '@metamask/accounts-controller'; import { KeyringControllerStateChangeEvent } from '@metamask/keyring-controller'; import type { MultichainNetworkControllerNetworkDidChangeEvent } from '@metamask/multichain-network-controller'; import { SnapControllerStateChangeEvent } from '@metamask/snaps-controllers'; -import { Hex } from '@metamask/utils'; import { SnapKeyringAccountAssetListUpdatedEvent, SnapKeyringAccountBalancesUpdatedEvent, @@ -499,45 +498,6 @@ describe('preferences controller', () => { }); }); - describe('setIncomingTransactionsPreferences', () => { - const { controller } = setupController({}); - const addedNonTestNetworks = Object.keys(NETWORK_CONFIGURATION_DATA); - - it('should have default value combined', () => { - const { state } = controller; - expect(state.incomingTransactionsPreferences).toStrictEqual({ - [CHAIN_IDS.MAINNET]: true, - [CHAIN_IDS.LINEA_MAINNET]: true, - [NETWORK_CONFIGURATION_DATA[addedNonTestNetworks[0] as Hex].chainId]: - true, - [NETWORK_CONFIGURATION_DATA[addedNonTestNetworks[1] as Hex].chainId]: - true, - [CHAIN_IDS.GOERLI]: true, - [CHAIN_IDS.SEPOLIA]: true, - [CHAIN_IDS.LINEA_SEPOLIA]: true, - }); - }); - - it('should update incomingTransactionsPreferences with given value set', () => { - controller.setIncomingTransactionsPreferences( - CHAIN_IDS.LINEA_MAINNET, - false, - ); - const { state } = controller; - expect(state.incomingTransactionsPreferences).toStrictEqual({ - [CHAIN_IDS.MAINNET]: true, - [CHAIN_IDS.LINEA_MAINNET]: false, - [NETWORK_CONFIGURATION_DATA[addedNonTestNetworks[0] as Hex].chainId]: - true, - [NETWORK_CONFIGURATION_DATA[addedNonTestNetworks[1] as Hex].chainId]: - true, - [CHAIN_IDS.GOERLI]: true, - [CHAIN_IDS.SEPOLIA]: true, - [CHAIN_IDS.LINEA_SEPOLIA]: true, - }); - }); - }); - describe('AccountsController:stateChange subscription', () => { const { controller, messenger, accountsController } = setupController({}); it('sync the identities with the accounts in the accounts controller', () => { @@ -748,6 +708,7 @@ describe('preferences controller', () => { hideZeroBalanceTokens: false, petnamesEnabled: true, shouldShowAggregatedBalancePopover: true, + dismissSmartAccountSuggestionEnabled: false, featureNotificationsEnabled: false, showConfirmationAdvancedDetails: false, showMultiRpcModal: false, @@ -776,6 +737,7 @@ describe('preferences controller', () => { petnamesEnabled: true, privacyMode: false, shouldShowAggregatedBalancePopover: true, + dismissSmartAccountSuggestionEnabled: false, featureNotificationsEnabled: false, showConfirmationAdvancedDetails: true, showMultiRpcModal: false, @@ -936,4 +898,19 @@ describe('preferences controller', () => { ]); }); }); + + describe('manageInstitutionalWallets', () => { + it('defaults manageInstitutionalWallets to false', () => { + const { controller } = setupController({}); + expect(controller.state.manageInstitutionalWallets).toStrictEqual(false); + }); + }); + + describe('setManageInstitutionalWallets', () => { + it('sets manageInstitutionalWallets to true', () => { + const { controller } = setupController({}); + controller.setManageInstitutionalWallets(true); + expect(controller.state.manageInstitutionalWallets).toStrictEqual(true); + }); + }); }); diff --git a/app/scripts/controllers/preferences-controller.ts b/app/scripts/controllers/preferences-controller.ts index c671ed167936..703eb36f25b4 100644 --- a/app/scripts/controllers/preferences-controller.ts +++ b/app/scripts/controllers/preferences-controller.ts @@ -6,7 +6,7 @@ import { AccountsControllerSetSelectedAccountAction, AccountsControllerState, } from '@metamask/accounts-controller'; -import { Hex, Json } from '@metamask/utils'; +import { Json } from '@metamask/utils'; import { BaseController, ControllerGetStateAction, @@ -18,10 +18,7 @@ import { ETHERSCAN_SUPPORTED_CHAIN_IDS, type PreferencesState, } from '@metamask/preferences-controller'; -import { - CHAIN_IDS, - IPFS_DEFAULT_GATEWAY_URL, -} from '../../../shared/constants/network'; +import { IPFS_DEFAULT_GATEWAY_URL } from '../../../shared/constants/network'; import { LedgerTransportTypes } from '../../../shared/constants/hardware-wallets'; import { ThemeType } from '../../../shared/constants/preferences'; @@ -31,17 +28,6 @@ type AccountIdentityEntry = { lastSelected?: number; }; -const mainNetworks = { - [CHAIN_IDS.MAINNET]: true, - [CHAIN_IDS.LINEA_MAINNET]: true, -}; - -const testNetworks = { - [CHAIN_IDS.GOERLI]: true, - [CHAIN_IDS.SEPOLIA]: true, - [CHAIN_IDS.LINEA_SEPOLIA]: true, -}; - const controllerName = 'PreferencesController'; /** @@ -120,6 +106,7 @@ export type Preferences = { }; tokenNetworkFilter: Record; shouldShowAggregatedBalancePopover: boolean; + dismissSmartAccountSuggestionEnabled: boolean; }; // Omitting properties that already exist in the PreferencesState, as part of the preferences property. @@ -148,7 +135,6 @@ export type PreferencesControllerState = Omit< ///: END:ONLY_INCLUDE_IF addSnapAccountEnabled?: boolean; advancedGasFee: Record>; - incomingTransactionsPreferences: Record; knownMethodData: Record; currentLocale: string; forgottenPassword: boolean; @@ -163,6 +149,7 @@ export type PreferencesControllerState = Omit< enableMV3TimestampSave: boolean; useExternalServices: boolean; textDirection?: string; + manageInstitutionalWallets: boolean; accountUpgradeDisabledChains?: string[]; }; @@ -194,10 +181,6 @@ export const getDefaultPreferencesControllerState = ///: END:ONLY_INCLUDE_IF advancedGasFee: {}, featureFlags: {}, - incomingTransactionsPreferences: { - ...mainNetworks, - ...testNetworks, - }, knownMethodData: {}, currentLocale: '', identities: {}, @@ -219,6 +202,7 @@ export const getDefaultPreferencesControllerState = showMultiRpcModal: false, privacyMode: false, shouldShowAggregatedBalancePopover: true, // by default user should see popover; + dismissSmartAccountSuggestionEnabled: false, tokenSortConfig: { key: 'tokenFiatAmount', order: 'dsc', @@ -271,6 +255,7 @@ export const getDefaultPreferencesControllerState = [ETHERSCAN_SUPPORTED_CHAIN_IDS.MOONRIVER]: true, [ETHERSCAN_SUPPORTED_CHAIN_IDS.GNOSIS]: true, }, + manageInstitutionalWallets: false, }); /** @@ -357,10 +342,6 @@ const controllerMetadata = { persist: true, anonymous: true, }, - incomingTransactionsPreferences: { - persist: true, - anonymous: true, - }, knownMethodData: { persist: true, anonymous: false, @@ -445,6 +426,7 @@ const controllerMetadata = { }, isMultiAccountBalancesEnabled: { persist: true, anonymous: true }, showIncomingTransactions: { persist: true, anonymous: true }, + manageInstitutionalWallets: { persist: true, anonymous: false }, accountUpgradeDisabledChains: { persist: true, anonymous: false }, }; @@ -461,27 +443,12 @@ export class PreferencesController extends BaseController< * @param options.state - The initial controller state */ constructor({ messenger, state }: PreferencesControllerOptions) { - const { networkConfigurationsByChainId } = messenger.call( - 'NetworkController:getState', - ); - - const addedNonMainNetwork: Record = Object.values( - networkConfigurationsByChainId ?? {}, - ).reduce((acc: Record, element) => { - acc[element.chainId] = true; - return acc; - }, {}); super({ messenger, metadata: controllerMetadata, name: controllerName, state: { ...getDefaultPreferencesControllerState(), - incomingTransactionsPreferences: { - ...mainNetworks, - ...addedNonMainNetwork, - ...testNetworks, - }, ...state, }, }); @@ -979,16 +946,13 @@ export class PreferencesController extends BaseController< } /** - * A setter for the incomingTransactions in preference to be updated + * A setter for the user preference to manage institutional wallets * - * @param chainId - chainId of the network - * @param value - preference of certain network, true to be enabled + * @param manageInstitutionalWallets - User preference for managing institutional wallets. */ - setIncomingTransactionsPreferences(chainId: Hex, value: boolean): void { - const previousValue = this.state.incomingTransactionsPreferences; - const updatedValue = { ...previousValue, [chainId]: value }; + setManageInstitutionalWallets(manageInstitutionalWallets: boolean): void { this.update((state) => { - state.incomingTransactionsPreferences = updatedValue; + state.manageInstitutionalWallets = manageInstitutionalWallets; }); } diff --git a/app/scripts/inpage.js b/app/scripts/inpage.js index 9aca84081406..8270e8113a41 100644 --- a/app/scripts/inpage.js +++ b/app/scripts/inpage.js @@ -35,7 +35,21 @@ import log from 'loglevel'; import { v4 as uuid } from 'uuid'; import { WindowPostMessageStream } from '@metamask/post-message-stream'; import { initializeProvider } from '@metamask/providers/initializeInpageProvider'; +import ObjectMultiplex from '@metamask/object-multiplex'; +import { pipeline } from 'readable-stream'; + +// this is currently equivalent to process.env.MULTICHAIN_API +// which can't be used for conditional imports +///: BEGIN:ONLY_INCLUDE_IF(build-beta,build-flask) +import { + getMultichainClient, + getDefaultTransport, +} from '@metamask/multichain-api-client'; +import { registerSolanaWalletStandard } from '@metamask/solana-wallet-standard'; +///: END:ONLY_INCLUDE_IF + import shouldInjectProvider from '../../shared/modules/provider-injection'; +import { METAMASK_PROVIDER } from './constants/stream'; // contexts const CONTENT_SCRIPT = 'metamask-contentscript'; @@ -56,8 +70,17 @@ if (shouldInjectProvider()) { target: CONTENT_SCRIPT, }); + const mux = new ObjectMultiplex(); + pipeline(metamaskStream, mux, metamaskStream, (error) => { + let warningMsg = `Lost connection to "${METAMASK_PROVIDER}".`; + if (error?.stack) { + warningMsg += `\n${error.stack}`; + } + console.warn(warningMsg); + }); + initializeProvider({ - connectionStream: metamaskStream, + connectionStream: mux.createStream(METAMASK_PROVIDER), logger: log, shouldShimWeb3: true, providerInfo: { @@ -67,4 +90,13 @@ if (shouldInjectProvider()) { rdns: process.env.METAMASK_BUILD_APP_ID, }, }); + + // this is currently equivalent to process.env.MULTICHAIN_API + ///: BEGIN:ONLY_INCLUDE_IF(build-beta,build-flask) + getMultichainClient({ + transport: getDefaultTransport(), + }).then((client) => { + registerSolanaWalletStandard({ client }); + }); + ///: END:ONLY_INCLUDE_IF } diff --git a/app/scripts/lib/AccountIdentitiesPetnamesBridge.test.ts b/app/scripts/lib/AccountIdentitiesPetnamesBridge.test.ts index c17ce27d68aa..16a0a169aa23 100644 --- a/app/scripts/lib/AccountIdentitiesPetnamesBridge.test.ts +++ b/app/scripts/lib/AccountIdentitiesPetnamesBridge.test.ts @@ -204,7 +204,6 @@ describe('AccountIdentitiesPetnamesBridge', () => { }); describe('shouldSyncPetname', () => { - // @ts-expect-error This is missing from the Mocha type definitions it.each([ { origin: NameOrigin.ACCOUNT_IDENTITY, diff --git a/app/scripts/lib/SnapsNameProvider.test.ts b/app/scripts/lib/SnapsNameProvider.test.ts index 25a5f22a3f80..a524f10d544d 100644 --- a/app/scripts/lib/SnapsNameProvider.test.ts +++ b/app/scripts/lib/SnapsNameProvider.test.ts @@ -167,7 +167,7 @@ describe('SnapsNameProvider', () => { for (const snapId of [SNAP_MOCK.id, SNAP_MOCK_2.id]) { expect(handleSnapRequest).toHaveBeenCalledWith({ snapId, - origin: '', + origin: 'metamask', handler: HandlerType.OnNameLookup, request: { jsonrpc: '2.0', diff --git a/app/scripts/lib/SnapsNameProvider.ts b/app/scripts/lib/SnapsNameProvider.ts index 483d6d58e11c..1598b83bea20 100644 --- a/app/scripts/lib/SnapsNameProvider.ts +++ b/app/scripts/lib/SnapsNameProvider.ts @@ -124,7 +124,7 @@ export class SnapsNameProvider implements NameProvider { 'SnapController:handleRequest', { snapId: snap.id, - origin: '', + origin: 'metamask', handler: HandlerType.OnNameLookup, request: { jsonrpc: '2.0', diff --git a/app/scripts/lib/approval/utils.test.ts b/app/scripts/lib/approval/utils.test.ts index fc7840faea31..8ee54593c37e 100644 --- a/app/scripts/lib/approval/utils.test.ts +++ b/app/scripts/lib/approval/utils.test.ts @@ -48,7 +48,6 @@ describe('Approval Utils', () => { ); }); - // @ts-expect-error This function is missing from the Mocha type definitions it.each([ ApprovalType.SnapDialogAlert, ApprovalType.SnapDialogPrompt, @@ -64,7 +63,6 @@ describe('Approval Utils', () => { expect(approvalController.accept).toHaveBeenCalledWith(ID_MOCK, null); }); - // @ts-expect-error This function is missing from the Mocha type definitions it.each([ ApprovalType.SnapDialogConfirmation, SNAP_MANAGE_ACCOUNTS_CONFIRMATION_TYPES.confirmAccountCreation, @@ -81,7 +79,6 @@ describe('Approval Utils', () => { expect(approvalController.accept).toHaveBeenCalledWith(ID_MOCK, false); }); - // @ts-expect-error This function is missing from the Mocha type definitions it.each([ ApprovalType.SnapDialogAlert, ApprovalType.SnapDialogPrompt, diff --git a/app/scripts/lib/createEvmMethodsToNonEvmAccountReqFilterMiddleware.test.ts b/app/scripts/lib/createEvmMethodsToNonEvmAccountReqFilterMiddleware.test.ts index 09893ea05a5e..c52a9878a852 100644 --- a/app/scripts/lib/createEvmMethodsToNonEvmAccountReqFilterMiddleware.test.ts +++ b/app/scripts/lib/createEvmMethodsToNonEvmAccountReqFilterMiddleware.test.ts @@ -5,7 +5,10 @@ import createEvmMethodsToNonEvmAccountReqFilterMiddleware, { } from './createEvmMethodsToNonEvmAccountReqFilterMiddleware'; describe('createEvmMethodsToNonEvmAccountReqFilterMiddleware', () => { - const getMockRequest = (method: string, params: Record) => ({ + const getMockRequest = ( + method: string, + params: Record[] | undefined, + ) => ({ jsonrpc: jsonrpc2, id: 1, method, @@ -13,7 +16,6 @@ describe('createEvmMethodsToNonEvmAccountReqFilterMiddleware', () => { }); const getMockResponse = () => ({ jsonrpc: jsonrpc2, id: 'foo' }); - // @ts-expect-error This function is missing from the Mocha type definitions it.each([ // EVM requests { @@ -285,8 +287,8 @@ describe('createEvmMethodsToNonEvmAccountReqFilterMiddleware', () => { }: { accountType: EthAccountType | BtcAccountType; method: string; - params: Record; - calledNext: number; + params: Record[] | undefined; + calledNext: boolean; }) => { const filterFn = createEvmMethodsToNonEvmAccountReqFilterMiddleware({ messenger: { diff --git a/app/scripts/lib/multichain/address.test.ts b/app/scripts/lib/multichain/address.test.ts index 61dbed67629f..dc211a76d829 100644 --- a/app/scripts/lib/multichain/address.test.ts +++ b/app/scripts/lib/multichain/address.test.ts @@ -4,80 +4,63 @@ import { normalizeSafeAddress, } from './address'; -type TestAddress = { - address: string; - normalizedAddress: string; - checksumAddress: string; -}; - -const ETH_ADDRESSES = [ - // Lower-case address - { - address: '0x6431726eee67570bf6f0cf892ae0a3988f03903f', - normalizedAddress: '0x6431726eee67570bf6f0cf892ae0a3988f03903f', - checksumAddress: '0x6431726EEE67570BF6f0Cf892aE0a3988F03903F', - }, - // Checksum address - { - address: '0x6431726EEE67570BF6f0Cf892aE0a3988F03903F', - normalizedAddress: '0x6431726eee67570bf6f0cf892ae0a3988f03903f', - checksumAddress: '0x6431726EEE67570BF6f0Cf892aE0a3988F03903F', - }, -]; +describe('address', () => { + const TEST_CASES_EVM_ADDRESSES = [ + { + address: '0x6431726eee67570bf6f0cf892ae0a3988f03903f', // Lower-case address + normalizedAddress: '0x6431726eee67570bf6f0cf892ae0a3988f03903f', + checksumAddress: '0x6431726EEE67570BF6f0Cf892aE0a3988F03903F', + }, + { + address: '0x6431726EEE67570BF6f0Cf892aE0a3988F03903F', // Checksum address + normalizedAddress: '0x6431726eee67570bf6f0cf892ae0a3988f03903f', + checksumAddress: '0x6431726EEE67570BF6f0Cf892aE0a3988F03903F', + }, + ]; -const NON_EVM_ADDRESSES = [ - { - address: '0xdeadbeef', - }, - { - address: 'bc1ql49ydapnjafl5t2cp9zqpjwe6pdgmxy98859v2', - }, -]; + const TEST_CASES_NON_EVM_ADDRESSES = [ + '0xdeadbeef', + 'bc1ql49ydapnjafl5t2cp9zqpjwe6pdgmxy98859v2', + ]; -describe('address', () => { describe('isEthAddress', () => { - // @ts-expect-error This is missing from the Mocha type definitions - it.each(ETH_ADDRESSES)( + it.each(TEST_CASES_EVM_ADDRESSES)( 'returns true if address is an ethereum address: $address', - ({ address }: TestAddress) => { + ({ address }) => { expect(isEthAddress(address)).toBe(true); expect(isEthAddress(address.toLowerCase())).toBe(true); }, ); - // @ts-expect-error This is missing from the Mocha type definitions - it.each(NON_EVM_ADDRESSES)( + it.each(TEST_CASES_NON_EVM_ADDRESSES)( 'returns false if address is not an ethereum address: $address', - ({ address }: TestAddress) => { + (address) => { expect(isEthAddress(address)).toBe(false); }, ); }); describe('normalizeAddress', () => { - // @ts-expect-error This is missing from the Mocha type definitions - it.each(ETH_ADDRESSES)( + it.each(TEST_CASES_EVM_ADDRESSES)( 'normalizes address: $address', - ({ address, normalizedAddress }: TestAddress) => { + ({ address, normalizedAddress }) => { expect(normalizeAddress(address)).toBe(normalizedAddress); expect(normalizeAddress(address.toLowerCase())).toBe(normalizedAddress); }, ); - // @ts-expect-error This is missing from the Mocha type definitions - it.each(NON_EVM_ADDRESSES)( + it.each(TEST_CASES_NON_EVM_ADDRESSES)( 'returns the original address if its a non-EVM address', - ({ address }: TestAddress) => { + (address) => { expect(normalizeAddress(address)).toBe(address); }, ); }); describe('normalizeSafeAddress', () => { - // @ts-expect-error This is missing from the Mocha type definitions - it.each(ETH_ADDRESSES)( + it.each(TEST_CASES_EVM_ADDRESSES)( 'normalizes address to its "safe" form: $address to: $checksumAddress', - ({ address, checksumAddress }: TestAddress) => { + ({ address, checksumAddress }) => { expect(normalizeSafeAddress(address)).toBe(checksumAddress); expect(normalizeSafeAddress(address.toLowerCase())).toBe( checksumAddress, @@ -85,10 +68,9 @@ describe('address', () => { }, ); - // @ts-expect-error This is missing from the Mocha type definitions - it.each(NON_EVM_ADDRESSES)( + it.each(TEST_CASES_NON_EVM_ADDRESSES)( 'returns the original address if its a non-EVM address', - ({ address }: TestAddress) => { + (address) => { expect(normalizeSafeAddress(address)).toBe(address); }, ); diff --git a/app/scripts/lib/ppom/ppom-util.test.ts b/app/scripts/lib/ppom/ppom-util.test.ts index 0bb1deb72c86..c30ecc135a63 100644 --- a/app/scripts/lib/ppom/ppom-util.test.ts +++ b/app/scripts/lib/ppom/ppom-util.test.ts @@ -261,7 +261,6 @@ describe('PPOM Utils', () => { ); }); - // @ts-expect-error This is missing from the Mocha type definitions it.each([METHOD_SIGN_TYPED_DATA_V3, METHOD_SIGN_TYPED_DATA_V4])( 'sanitizes request params if method is %s', async (method: string) => { diff --git a/app/scripts/lib/rpc-method-middleware/createUnsupportedMethodMiddleware.test.ts b/app/scripts/lib/rpc-method-middleware/createUnsupportedMethodMiddleware.test.ts index 341eb1b98706..d3c285c9454c 100644 --- a/app/scripts/lib/rpc-method-middleware/createUnsupportedMethodMiddleware.test.ts +++ b/app/scripts/lib/rpc-method-middleware/createUnsupportedMethodMiddleware.test.ts @@ -21,7 +21,6 @@ describe('createUnsupportedMethodMiddleware', () => { expect(endMock).not.toHaveBeenCalled(); }); - // @ts-expect-error This function is missing from the Mocha type definitions it.each([...UNSUPPORTED_RPC_METHODS])( 'ends requests for default unsupported rpc methods when no list is provided: %s', (method: string) => { @@ -40,7 +39,6 @@ describe('createUnsupportedMethodMiddleware', () => { const unsupportedMethods = new Set(['foo', 'bar']); - // @ts-expect-error This function is missing from the Mocha type definitions it.each([...unsupportedMethods])( 'ends requests for methods that are in the provided list of unsupported methods: %s', (method: string) => { diff --git a/app/scripts/lib/rpc-method-middleware/handlers/ethereum-chain-utils.js b/app/scripts/lib/rpc-method-middleware/handlers/ethereum-chain-utils.js index 3c69d83e56f5..fb99677c68d7 100644 --- a/app/scripts/lib/rpc-method-middleware/handlers/ethereum-chain-utils.js +++ b/app/scripts/lib/rpc-method-middleware/handlers/ethereum-chain-utils.js @@ -4,7 +4,7 @@ import { Caip25CaveatType, Caip25EndowmentPermissionName, getPermittedEthChainIds, -} from '@metamask/multichain'; +} from '@metamask/chain-agnostic-permission'; import { isPrefixedFormattedHexString, isSafeChainId, diff --git a/app/scripts/lib/rpc-method-middleware/handlers/ethereum-chain-utils.test.ts b/app/scripts/lib/rpc-method-middleware/handlers/ethereum-chain-utils.test.ts index b1ec4b8dbacf..515b918292f6 100644 --- a/app/scripts/lib/rpc-method-middleware/handlers/ethereum-chain-utils.test.ts +++ b/app/scripts/lib/rpc-method-middleware/handlers/ethereum-chain-utils.test.ts @@ -1,9 +1,9 @@ -import * as Multichain from '@metamask/multichain'; +import * as Multichain from '@metamask/chain-agnostic-permission'; import { errorCodes, rpcErrors } from '@metamask/rpc-errors'; import { Caip25CaveatType, Caip25EndowmentPermissionName, -} from '@metamask/multichain'; +} from '@metamask/chain-agnostic-permission'; import { Hex } from '@metamask/utils'; import * as EthChainUtils from './ethereum-chain-utils'; @@ -253,7 +253,6 @@ describe('Ethereum Chain Utils', () => { }); }); - // @ts-expect-error This function is missing from the Mocha type definitions describe.each([ ['legacy', false], ['multichain', true], diff --git a/app/scripts/lib/rpc-method-middleware/handlers/switch-ethereum-chain.js b/app/scripts/lib/rpc-method-middleware/handlers/switch-ethereum-chain.js index 3bf690e71837..85c6ef8b36a8 100644 --- a/app/scripts/lib/rpc-method-middleware/handlers/switch-ethereum-chain.js +++ b/app/scripts/lib/rpc-method-middleware/handlers/switch-ethereum-chain.js @@ -16,6 +16,7 @@ const switchEthereumChain = { getCaveat: true, getCurrentChainIdForDomain: true, requestPermittedChainsPermissionIncrementalForOrigin: true, + rejectApprovalRequestsForOrigin: true, setTokenNetworkFilter: true, hasApprovalRequestsForOrigin: true, }, @@ -35,6 +36,7 @@ async function switchEthereumChainHandler( getCaveat, getCurrentChainIdForDomain, requestPermittedChainsPermissionIncrementalForOrigin, + rejectApprovalRequestsForOrigin, setTokenNetworkFilter, hasApprovalRequestsForOrigin, }, @@ -81,6 +83,7 @@ async function switchEthereumChainHandler( setActiveNetwork, getCaveat, requestPermittedChainsPermissionIncrementalForOrigin, + rejectApprovalRequestsForOrigin, setTokenNetworkFilter, requestUserApproval, hasApprovalRequestsForOrigin, diff --git a/app/scripts/lib/rpc-method-middleware/handlers/wallet-createSession/handler.test.ts b/app/scripts/lib/rpc-method-middleware/handlers/wallet-createSession/handler.test.ts index 66a4a10b15c5..2f61bdd4f256 100644 --- a/app/scripts/lib/rpc-method-middleware/handlers/wallet-createSession/handler.test.ts +++ b/app/scripts/lib/rpc-method-middleware/handlers/wallet-createSession/handler.test.ts @@ -4,8 +4,10 @@ import { Caip25EndowmentPermissionName, Caip25Authorization, NormalizedScopesObject, -} from '@metamask/multichain'; -import * as Multichain from '@metamask/multichain'; + KnownSessionProperties, +} from '@metamask/chain-agnostic-permission'; +import * as Multichain from '@metamask/chain-agnostic-permission'; +import { MultichainNetwork } from '@metamask/multichain-transactions-controller'; import { Json, JsonRpcRequest, JsonRpcSuccess } from '@metamask/utils'; import * as Util from '../../../util'; import { walletCreateSession } from './handler'; @@ -16,8 +18,8 @@ jest.mock('../../../util', () => ({ })); const MockUtil = jest.mocked(Util); -jest.mock('@metamask/multichain', () => ({ - ...jest.requireActual('@metamask/multichain'), +jest.mock('@metamask/chain-agnostic-permission', () => ({ + ...jest.requireActual('@metamask/chain-agnostic-permission'), validateAndNormalizeScopes: jest.fn(), bucketScopes: jest.fn(), getSessionScopes: jest.fn(), @@ -91,6 +93,8 @@ const createMockedHandler = () => { }, }; const listAccounts = jest.fn().mockReturnValue([]); + const getNonEvmSupportedMethods = jest.fn().mockReturnValue([]); + const isNonEvmScopeSupported = jest.fn().mockReturnValue(false); const response = { jsonrpc: '2.0' as const, id: 0, @@ -98,6 +102,7 @@ const createMockedHandler = () => { sessionScopes: NormalizedScopesObject; sessionProperties?: Record; }>; + const getNonEvmAccountAddresses = jest.fn().mockReturnValue([]); const handler = ( request: JsonRpcRequest & { origin: string }, ) => @@ -107,6 +112,9 @@ const createMockedHandler = () => { metamaskState, sendMetrics, listAccounts, + getNonEvmSupportedMethods, + isNonEvmScopeSupported, + getNonEvmAccountAddresses, }); return { @@ -118,6 +126,9 @@ const createMockedHandler = () => { metamaskState, sendMetrics, listAccounts, + getNonEvmSupportedMethods, + isNonEvmScopeSupported, + getNonEvmAccountAddresses, handler, }; }; @@ -129,7 +140,13 @@ describe('wallet_createSession', () => { normalizedOptionalScopes: {}, }); MockMultichain.bucketScopes.mockReturnValue({ - supportedScopes: {}, + supportedScopes: { + 'eip155:1': { + methods: [], + notifications: [], + accounts: ['eip155:1:0x1', 'eip155:1:0x2'], + }, + }, supportableScopes: {}, unsupportableScopes: {}, }); @@ -193,7 +210,7 @@ describe('wallet_createSession', () => { }); it('filters the required scopesObjects', async () => { - const { handler } = createMockedHandler(); + const { handler, getNonEvmSupportedMethods } = createMockedHandler(); MockMultichain.validateAndNormalizeScopes.mockReturnValue({ normalizedRequiredScopes: { 'eip155:1': { @@ -206,17 +223,23 @@ describe('wallet_createSession', () => { }); await handler(baseRequest); - expect(MockMultichain.getSupportedScopeObjects).toHaveBeenNthCalledWith(1, { - 'eip155:1': { - methods: ['eth_chainId'], - notifications: ['accountsChanged', 'chainChanged'], - accounts: ['eip155:1:0x1', 'eip155:1:0x2'], + expect(MockMultichain.getSupportedScopeObjects).toHaveBeenNthCalledWith( + 1, + { + 'eip155:1': { + methods: ['eth_chainId'], + notifications: ['accountsChanged', 'chainChanged'], + accounts: ['eip155:1:0x1', 'eip155:1:0x2'], + }, }, - }); + { + getNonEvmSupportedMethods, + }, + ); }); it('filters the optional scopesObjects', async () => { - const { handler } = createMockedHandler(); + const { handler, getNonEvmSupportedMethods } = createMockedHandler(); MockMultichain.validateAndNormalizeScopes.mockReturnValue({ normalizedRequiredScopes: {}, normalizedOptionalScopes: { @@ -229,17 +252,24 @@ describe('wallet_createSession', () => { }); await handler(baseRequest); - expect(MockMultichain.getSupportedScopeObjects).toHaveBeenNthCalledWith(2, { - 'eip155:1': { - methods: ['eth_chainId'], - notifications: ['accountsChanged', 'chainChanged'], - accounts: ['eip155:1:0x1', 'eip155:1:0x2'], + expect(MockMultichain.getSupportedScopeObjects).toHaveBeenNthCalledWith( + 2, + { + 'eip155:1': { + methods: ['eth_chainId'], + notifications: ['accountsChanged', 'chainChanged'], + accounts: ['eip155:1:0x1', 'eip155:1:0x2'], + }, }, - }); + { + getNonEvmSupportedMethods, + }, + ); }); it('buckets the required scopes', async () => { - const { handler } = createMockedHandler(); + const { handler, getNonEvmSupportedMethods, isNonEvmScopeSupported } = + createMockedHandler(); MockMultichain.validateAndNormalizeScopes.mockReturnValue({ normalizedRequiredScopes: { 'eip155:1': { @@ -262,18 +292,21 @@ describe('wallet_createSession', () => { }, }, expect.objectContaining({ - isChainIdSupported: expect.any(Function), - isChainIdSupportable: expect.any(Function), + isEvmChainIdSupported: expect.any(Function), + isEvmChainIdSupportable: expect.any(Function), + getNonEvmSupportedMethods, + isNonEvmScopeSupported, }), ); - const isChainIdSupportedBody = - MockMultichain.bucketScopes.mock.calls[0][1].isChainIdSupported.toString(); - expect(isChainIdSupportedBody).toContain('findNetworkClientIdByChainId'); + const isEvmChainIdSupportedBody = + MockMultichain.bucketScopes.mock.calls[0][1].isEvmChainIdSupported.toString(); + expect(isEvmChainIdSupportedBody).toContain('findNetworkClientIdByChainId'); }); it('buckets the optional scopes', async () => { - const { handler } = createMockedHandler(); + const { handler, getNonEvmSupportedMethods, isNonEvmScopeSupported } = + createMockedHandler(); MockMultichain.validateAndNormalizeScopes.mockReturnValue({ normalizedRequiredScopes: {}, normalizedOptionalScopes: { @@ -296,31 +329,102 @@ describe('wallet_createSession', () => { }, }, expect.objectContaining({ - isChainIdSupported: expect.any(Function), - isChainIdSupportable: expect.any(Function), + isEvmChainIdSupported: expect.any(Function), + isEvmChainIdSupportable: expect.any(Function), + getNonEvmSupportedMethods, + isNonEvmScopeSupported, }), ); - const isChainIdSupportedBody = - MockMultichain.bucketScopes.mock.calls[1][1].isChainIdSupported.toString(); - expect(isChainIdSupportedBody).toContain('findNetworkClientIdByChainId'); + const isEvmChainIdSupportedBody = + MockMultichain.bucketScopes.mock.calls[1][1].isEvmChainIdSupported.toString(); + expect(isEvmChainIdSupportedBody).toContain('findNetworkClientIdByChainId'); + }); + + it('throws an error when no scopes are supported', async () => { + const { handler, end } = createMockedHandler(); + MockMultichain.bucketScopes + .mockReturnValueOnce({ + supportedScopes: {}, + supportableScopes: {}, + unsupportableScopes: {}, + }) + .mockReturnValueOnce({ + supportedScopes: {}, + supportableScopes: {}, + unsupportableScopes: {}, + }); + await handler(baseRequest); + expect(end).toHaveBeenCalledWith( + new JsonRpcError(5100, 'Requested scopes are not supported'), + ); }); it('gets a list of evm accounts in the wallet', async () => { const { handler, listAccounts } = createMockedHandler(); + await handler(baseRequest); expect(listAccounts).toHaveBeenCalled(); }); - it('requests approval for account and permitted chains permission based on the supported eth accounts and eth chains from the supported scopes in the request', async () => { - const { handler, listAccounts, requestPermissionsForOrigin } = + it('gets the account addresses for non evm scopes', async () => { + const { handler, listAccounts, getNonEvmAccountAddresses } = createMockedHandler(); listAccounts.mockReturnValue([ { address: '0x1' }, { address: '0x3' }, { address: '0x4' }, ]); + MockMultichain.bucketScopes + .mockReturnValueOnce({ + supportedScopes: {}, + supportableScopes: {}, + unsupportableScopes: {}, + }) + .mockReturnValueOnce({ + supportedScopes: { + [MultichainNetwork.Solana]: { + methods: [], + notifications: [], + accounts: [ + 'solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp:EEivRh9T4GTLEJprEaKQyjSQzW13JRb5D7jSpvPQ8296', + ], + }, + 'solana:deadbeef': { + methods: [], + notifications: [], + accounts: [ + 'solana:deadbeef:EEivRh9T4GTLEJprEaKQyjSQzW13JRb5D7jSpvPQ8296', + ], + }, + }, + supportableScopes: {}, + unsupportableScopes: {}, + }); + getNonEvmAccountAddresses.mockReturnValue([]); + + await handler(baseRequest); + + expect(getNonEvmAccountAddresses).toHaveBeenCalledTimes(2); + expect(getNonEvmAccountAddresses).toHaveBeenCalledWith( + MultichainNetwork.Solana, + ); + expect(getNonEvmAccountAddresses).toHaveBeenCalledWith('solana:deadbeef'); + }); + + it('requests approval for account and permitted chains permission based on the supported accounts and scopes in the request', async () => { + const { + handler, + listAccounts, + requestPermissionsForOrigin, + getNonEvmAccountAddresses, + } = createMockedHandler(); + listAccounts.mockReturnValue([ + { address: '0x1' }, + { address: '0x3' }, + { address: '0x4' }, + ]); MockMultichain.bucketScopes .mockReturnValueOnce({ supportedScopes: { @@ -340,34 +444,55 @@ describe('wallet_createSession', () => { notifications: [], accounts: ['eip155:2:0x1', 'eip155:2:0x3', 'eip155:2:0xdeadbeef'], }, + [MultichainNetwork.Solana]: { + methods: [], + notifications: [], + accounts: [ + 'solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp:EEivRh9T4GTLEJprEaKQyjSQzW13JRb5D7jSpvPQ8296', + 'solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp:notSupported', + ], + }, }, supportableScopes: {}, unsupportableScopes: {}, }); + getNonEvmAccountAddresses.mockReturnValue([ + 'solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp:EEivRh9T4GTLEJprEaKQyjSQzW13JRb5D7jSpvPQ8296', + ]); + await handler(baseRequest); - expect(requestPermissionsForOrigin).toHaveBeenCalledWith({ - [Caip25EndowmentPermissionName]: { - caveats: [ - { - type: Caip25CaveatType, - value: { - requiredScopes: { - 'eip155:1337': { - accounts: ['eip155:1337:0x1', 'eip155:1337:0x3'], + expect(requestPermissionsForOrigin).toHaveBeenCalledWith( + { + [Caip25EndowmentPermissionName]: { + caveats: [ + { + type: Caip25CaveatType, + value: { + requiredScopes: { + 'eip155:1337': { + accounts: ['eip155:1337:0x1', 'eip155:1337:0x3'], + }, }, - }, - optionalScopes: { - 'eip155:100': { - accounts: ['eip155:100:0x1', 'eip155:100:0x3'], + optionalScopes: { + 'eip155:100': { + accounts: ['eip155:100:0x1', 'eip155:100:0x3'], + }, + [MultichainNetwork.Solana]: { + accounts: [ + 'solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp:EEivRh9T4GTLEJprEaKQyjSQzW13JRb5D7jSpvPQ8296', + ], + }, }, + isMultichainOrigin: true, + sessionProperties: {}, }, - isMultichainOrigin: true, }, - }, - ], + ], + }, }, - }); + { metadata: { promptToCreateSolanaAccount: false } }, + ); }); it('throws an error when requesting account permission approval fails', async () => { @@ -384,12 +509,6 @@ describe('wallet_createSession', () => { it('emits the dapp viewed metrics event', async () => { MockUtil.shouldEmitDappViewedEvent.mockReturnValue(true); const { handler, sendMetrics } = createMockedHandler(); - - MockMultichain.bucketScopes.mockReturnValue({ - supportedScopes: {}, - supportableScopes: {}, - unsupportableScopes: {}, - }); await handler(baseRequest); expect(sendMetrics).toHaveBeenCalledWith( @@ -411,7 +530,7 @@ describe('wallet_createSession', () => { ); }); - it('returns the session ID, properties, and session scopes', async () => { + it('returns the known sessionProperties and approved session scopes', async () => { const { handler, response } = createMockedHandler(); MockMultichain.getSessionScopes.mockReturnValue({ 'eip155:5': { @@ -433,10 +552,7 @@ describe('wallet_createSession', () => { await handler(baseRequest); expect(response.result).toStrictEqual({ - sessionProperties: { - expiry: 'date', - foo: 'bar', - }, + sessionProperties: {}, sessionScopes: { 'eip155:5': { methods: ['eth_chainId', 'net_version'], @@ -456,4 +572,393 @@ describe('wallet_createSession', () => { }, }); }); + + it('filters out unknown session properties', async () => { + const { handler, requestPermissionsForOrigin, listAccounts } = + createMockedHandler(); + listAccounts.mockReturnValue([ + { address: '0x1' }, + { address: '0x3' }, + { address: '0x4' }, + ]); + MockMultichain.bucketScopes + .mockReturnValueOnce({ + supportedScopes: { + 'eip155:1337': { + methods: [], + notifications: [], + accounts: ['eip155:1:0x1', 'eip155:1:0x2'], + }, + }, + supportableScopes: {}, + unsupportableScopes: {}, + }) + .mockReturnValueOnce({ + supportedScopes: { + 'eip155:100': { + methods: [], + notifications: [], + accounts: ['eip155:2:0x1', 'eip155:2:0x3', 'eip155:2:0xdeadbeef'], + }, + }, + supportableScopes: {}, + unsupportableScopes: {}, + }); + await handler(baseRequest); + expect(requestPermissionsForOrigin).toHaveBeenCalledWith( + { + [Caip25EndowmentPermissionName]: { + caveats: [ + { + type: Caip25CaveatType, + value: { + requiredScopes: { + 'eip155:1337': { + accounts: ['eip155:1337:0x1', 'eip155:1337:0x3'], + }, + }, + optionalScopes: { + 'eip155:100': { + accounts: ['eip155:100:0x1', 'eip155:100:0x3'], + }, + }, + isMultichainOrigin: true, + sessionProperties: {}, + }, + }, + ], + }, + }, + { metadata: { promptToCreateSolanaAccount: false } }, + ); + }); + + it('preserves known session properties', async () => { + const { handler, response, requestPermissionsForOrigin } = + createMockedHandler(); + requestPermissionsForOrigin.mockReturnValue([ + { + [Caip25EndowmentPermissionName]: { + caveats: [ + { + type: Caip25CaveatType, + value: { + optionalScopes: { + 'eip155:5': { + accounts: ['eip155:5:0x1', 'eip155:5:0x2'], + methods: ['eth_chainId', 'net_version'], + notifications: ['accountsChanged', 'chainChanged'], + }, + }, + sessionProperties: { + [KnownSessionProperties.SolanaAccountChangedNotifications]: + true, + }, + }, + }, + ], + }, + }, + ]); + MockMultichain.getSessionScopes.mockReturnValue({ + 'eip155:5': { + methods: ['eth_chainId', 'net_version'], + notifications: ['accountsChanged', 'chainChanged'], + accounts: ['eip155:5:0x1', 'eip155:5:0x2'], + }, + }); + await handler({ + ...baseRequest, + params: { + ...baseRequest.params, + sessionProperties: { + [KnownSessionProperties.SolanaAccountChangedNotifications]: true, + }, + }, + }); + + expect(response.result).toStrictEqual({ + sessionProperties: { + [KnownSessionProperties.SolanaAccountChangedNotifications]: true, + }, + sessionScopes: { + 'eip155:5': { + accounts: ['eip155:5:0x1', 'eip155:5:0x2'], + methods: ['eth_chainId', 'net_version'], + notifications: ['accountsChanged', 'chainChanged'], + }, + }, + }); + }); + + describe('promptToCreateSolanaAccount', () => { + const baseRequestWithSolanaScope = { + jsonrpc: '2.0' as const, + id: 0, + method: 'wallet_createSession', + origin: 'http://test.com', + params: { + optionalScopes: { + [MultichainNetwork.Solana]: { + methods: [], + notifications: [], + accounts: [], + }, + }, + sessionProperties: { + [KnownSessionProperties.SolanaAccountChangedNotifications]: true, + }, + }, + }; + it('prompts to create a solana account if a solana scope is requested and no solana accounts are currently available', async () => { + const { + handler, + requestPermissionsForOrigin, + getNonEvmAccountAddresses, + } = createMockedHandler(); + getNonEvmAccountAddresses.mockResolvedValue([]); + MockMultichain.validateAndNormalizeScopes.mockReturnValue({ + normalizedRequiredScopes: { + [MultichainNetwork.Solana]: { + methods: [], + notifications: [], + accounts: [], + }, + }, + normalizedOptionalScopes: {}, + }); + + MockMultichain.bucketScopes + .mockReturnValueOnce({ + supportedScopes: {}, + supportableScopes: {}, + unsupportableScopes: {}, + }) + .mockReturnValueOnce({ + supportedScopes: { + 'eip155:1337': { + methods: [], + notifications: [], + accounts: [], + }, + }, + supportableScopes: {}, + unsupportableScopes: {}, + }); + + await handler(baseRequestWithSolanaScope); + + expect(requestPermissionsForOrigin).toHaveBeenCalledWith( + { + [Caip25EndowmentPermissionName]: { + caveats: [ + { + type: Caip25CaveatType, + value: { + requiredScopes: {}, + optionalScopes: { + 'eip155:1337': { + accounts: [], + }, + }, + isMultichainOrigin: true, + sessionProperties: { + [KnownSessionProperties.SolanaAccountChangedNotifications]: + true, + }, + }, + }, + ], + }, + }, + { metadata: { promptToCreateSolanaAccount: true } }, + ); + }); + + it('does not prompt to create a solana account if a solana scope is requested and solana accounts are currently available', async () => { + const { + handler, + requestPermissionsForOrigin, + getNonEvmAccountAddresses, + } = createMockedHandler(); + getNonEvmAccountAddresses.mockResolvedValue([ + 'solana:101:0x1', + 'solana:101:0x2', + ]); + MockMultichain.validateAndNormalizeScopes.mockReturnValue({ + normalizedRequiredScopes: {}, + normalizedOptionalScopes: { + [MultichainNetwork.Solana]: { + methods: [], + notifications: [], + accounts: [], + }, + }, + }); + + MockMultichain.bucketScopes + .mockReturnValueOnce({ + supportedScopes: {}, + supportableScopes: {}, + unsupportableScopes: {}, + }) + .mockReturnValueOnce({ + supportedScopes: { + [MultichainNetwork.Solana]: { + methods: [], + notifications: [], + accounts: [], + }, + }, + supportableScopes: {}, + unsupportableScopes: {}, + }); + + await handler(baseRequestWithSolanaScope); + + expect(requestPermissionsForOrigin).toHaveBeenCalledWith( + { + [Caip25EndowmentPermissionName]: { + caveats: [ + { + type: Caip25CaveatType, + value: { + requiredScopes: {}, + optionalScopes: { + [MultichainNetwork.Solana]: { + accounts: [], + }, + }, + isMultichainOrigin: true, + sessionProperties: { + [KnownSessionProperties.SolanaAccountChangedNotifications]: + true, + }, + }, + }, + ], + }, + }, + { metadata: { promptToCreateSolanaAccount: false } }, + ); + }); + }); + + describe('address case sensitivity', () => { + it('treats EVM addresses as case insensitive but other addresses as case sensitive', async () => { + const { + handler, + listAccounts, + requestPermissionsForOrigin, + getNonEvmAccountAddresses, + } = createMockedHandler(); + + listAccounts.mockReturnValue([ + { address: '0xabc123' }, // Note: lowercase in wallet + ]); + + // Mocking nonEVM account addresses in the wallet + getNonEvmAccountAddresses.mockImplementation((scope) => { + if (scope === MultichainNetwork.Solana) { + return ['solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp:address1']; + } + if (scope === MultichainNetwork.Bitcoin) { + return ['bip122:000000000019d6689c085ae165831e93:address1']; + } + return []; + }); + + // Test both EVM (case-insensitive) and Solana (case-sensitive) and Bitcoin (case-sensitive) behavior + MockMultichain.bucketScopes + .mockReturnValueOnce({ + supportedScopes: { + 'eip155:1': { + methods: [], + notifications: [], + accounts: ['eip155:1:0xABC123'], // Upper case in request + }, + }, + supportableScopes: {}, + unsupportableScopes: {}, + }) + .mockReturnValueOnce({ + supportedScopes: { + [MultichainNetwork.Solana]: { + methods: [], + notifications: [], + accounts: [ + // Solana address in request is different case than what + // getNonEvmAccountAddresses (returns in wallet account address) returns + 'solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp:ADDRESS1', + ], + }, + [MultichainNetwork.Bitcoin]: { + methods: [], + notifications: [], + accounts: ['bip122:000000000019d6689c085ae165831e93:ADDRESS1'], + }, + }, + supportableScopes: {}, + unsupportableScopes: {}, + }); + + await handler({ + jsonrpc: '2.0', + id: 0, + method: 'wallet_createSession', + origin: 'http://test.com', + params: { + requiredScopes: { + eip155: { + methods: ['eth_accounts'], + notifications: [], + accounts: ['eip155:1:0xABC123'], + }, + }, + optionalScopes: { + [MultichainNetwork.Solana]: { + methods: ['getAccounts'], + notifications: [], + accounts: ['solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp:ADDRESS1'], + }, + [MultichainNetwork.Bitcoin]: { + methods: ['getAccounts'], + notifications: [], + accounts: ['bip122:000000000019d6689c085ae165831e93:ADDRESS1'], + }, + }, + }, + }); + + expect(requestPermissionsForOrigin).toHaveBeenCalledWith( + { + [Caip25EndowmentPermissionName]: { + caveats: [ + { + type: Caip25CaveatType, + value: { + requiredScopes: { + 'eip155:1': { + accounts: ['eip155:1:0xABC123'], // Requested EVM address included + }, + }, + optionalScopes: { + [MultichainNetwork.Solana]: { + accounts: [], // Solana address excluded due to case mismatch + }, + [MultichainNetwork.Bitcoin]: { + accounts: [], // Bitcoin address excluded due to case mismatch + }, + }, + isMultichainOrigin: true, + sessionProperties: {}, + }, + }, + ], + }, + }, + { metadata: { promptToCreateSolanaAccount: false } }, + ); + }); + }); }); diff --git a/app/scripts/lib/rpc-method-middleware/handlers/wallet-createSession/handler.ts b/app/scripts/lib/rpc-method-middleware/handlers/wallet-createSession/handler.ts index fd8eac30a8ee..378a393ba200 100644 --- a/app/scripts/lib/rpc-method-middleware/handlers/wallet-createSession/handler.ts +++ b/app/scripts/lib/rpc-method-middleware/handlers/wallet-createSession/handler.ts @@ -3,7 +3,6 @@ import { Caip25CaveatType, Caip25EndowmentPermissionName, getEthAccounts, - setEthAccounts, bucketScopes, validateAndNormalizeScopes, Caip25Authorization, @@ -12,23 +11,29 @@ import { NormalizedScopesObject, getSupportedScopeObjects, Caip25CaveatValue, -} from '@metamask/multichain'; + setPermittedAccounts, +} from '@metamask/chain-agnostic-permission'; import { invalidParams, RequestedPermissions, } from '@metamask/permission-controller'; import { + CaipAccountId, + CaipChainId, Hex, isPlainObject, Json, JsonRpcRequest, JsonRpcSuccess, + KnownCaipNamespace, + parseCaipAccountId, } from '@metamask/utils'; import { NetworkController } from '@metamask/network-controller'; import { JsonRpcEngineEndCallback, JsonRpcEngineNextCallback, } from '@metamask/json-rpc-engine'; +import { MultichainNetwork } from '@metamask/multichain-transactions-controller'; import { MetaMetricsEventCategory, MetaMetricsEventName, @@ -38,6 +43,13 @@ import { import { shouldEmitDappViewedEvent } from '../../../util'; import { MESSAGE_TYPE } from '../../../../../../shared/constants/app'; import { GrantedPermissions } from '../types'; +import { isEqualCaseInsensitive } from '../../../../../../shared/modules/string-utils'; +import { getAllScopesFromScopesObjects } from '../../../../../../shared/lib/multichain/chain-agnostic-permission-utils/caip-chainids'; +import { getCaipAccountIdsFromScopesObjects } from '../../../../../../shared/lib/multichain/chain-agnostic-permission-utils/caip-accounts'; +import { + isKnownSessionPropertyValue, + isNamespaceInScopesObject, +} from '../../../../../../shared/lib/multichain/chain-agnostic-permission-utils/misc-utils'; /** * Handler for the `wallet_createSession` RPC method which is responsible @@ -59,6 +71,9 @@ import { GrantedPermissions } from '../types'; * @param hooks.findNetworkClientIdByChainId - The hook that returns the networkClientId for a chainId. * @param hooks.requestPermissionsForOrigin - The hook that approves and grants requested permissions. * @param hooks.sendMetrics - The hook that tracks an analytics event. + * @param hooks.getNonEvmSupportedMethods - The hook that returns the supported methods for a non EVM scope. + * @param hooks.isNonEvmScopeSupported - The hook that returns true if a non EVM scope is supported. + * @param hooks.getNonEvmAccountAddresses - The hook that returns a list of CaipAccountIds that are supported for a CaipChainId. * @param hooks.metamaskState - The wallet state. * @param hooks.metamaskState.metaMetricsId - The analytics id. * @param hooks.metamaskState.permissionHistory - The permission history object keyed by origin. @@ -77,16 +92,20 @@ async function walletCreateSessionHandler( findNetworkClientIdByChainId: NetworkController['findNetworkClientIdByChainId']; requestPermissionsForOrigin: ( requestedPermissions: RequestedPermissions, + metadata?: Record, ) => Promise<[GrantedPermissions]>; sendMetrics: ( payload: MetaMetricsEventPayload, options?: MetaMetricsEventOptions, ) => void; + getNonEvmSupportedMethods: (scope: CaipChainId) => string[]; + isNonEvmScopeSupported: (scope: CaipChainId) => boolean; metamaskState: { metaMetricsId: string; permissionHistory: Record; accounts: Record; }; + getNonEvmAccountAddresses: (scope: CaipChainId) => CaipAccountId[]; }, ) { const { origin } = req; @@ -99,14 +118,24 @@ async function walletCreateSessionHandler( return end(new JsonRpcError(5302, 'Invalid sessionProperties requested')); } + const filteredSessionProperties = Object.fromEntries( + Object.entries(sessionProperties ?? {}).filter(([key]) => + isKnownSessionPropertyValue(key), + ), + ); + try { const { normalizedRequiredScopes, normalizedOptionalScopes } = validateAndNormalizeScopes(requiredScopes || {}, optionalScopes || {}); const requiredScopesWithSupportedMethodsAndNotifications = - getSupportedScopeObjects(normalizedRequiredScopes); + getSupportedScopeObjects(normalizedRequiredScopes, { + getNonEvmSupportedMethods: hooks.getNonEvmSupportedMethods, + }); const optionalScopesWithSupportedMethodsAndNotifications = - getSupportedScopeObjects(normalizedOptionalScopes); + getSupportedScopeObjects(normalizedOptionalScopes, { + getNonEvmSupportedMethods: hooks.getNonEvmSupportedMethods, + }); const networkClientExistsForChainId = (chainId: Hex) => { try { @@ -117,55 +146,129 @@ async function walletCreateSessionHandler( } }; + // if solana is a requested scope but not supported, we add a promptToCreateSolanaAccount flag to request + const isSolanaRequested = + isNamespaceInScopesObject( + requiredScopesWithSupportedMethodsAndNotifications, + KnownCaipNamespace.Solana, + ) || + isNamespaceInScopesObject( + optionalScopesWithSupportedMethodsAndNotifications, + KnownCaipNamespace.Solana, + ); + + let promptToCreateSolanaAccount = false; + if (isSolanaRequested) { + const supportedSolanaAccounts = await hooks.getNonEvmAccountAddresses( + MultichainNetwork.Solana, + ); + promptToCreateSolanaAccount = supportedSolanaAccounts.length === 0; + } + const { supportedScopes: supportedRequiredScopes } = bucketScopes( requiredScopesWithSupportedMethodsAndNotifications, { - isChainIdSupported: networkClientExistsForChainId, - isChainIdSupportable: () => false, // intended for future usage with eip3085 scopedProperties + isEvmChainIdSupported: networkClientExistsForChainId, + isEvmChainIdSupportable: () => false, // intended for future usage with eip3085 scopedProperties + getNonEvmSupportedMethods: hooks.getNonEvmSupportedMethods, + isNonEvmScopeSupported: hooks.isNonEvmScopeSupported, }, ); const { supportedScopes: supportedOptionalScopes } = bucketScopes( optionalScopesWithSupportedMethodsAndNotifications, { - isChainIdSupported: networkClientExistsForChainId, - isChainIdSupportable: () => false, // intended for future usage with eip3085 scopedProperties + isEvmChainIdSupported: networkClientExistsForChainId, + isEvmChainIdSupportable: () => false, // intended for future usage with eip3085 scopedProperties + getNonEvmSupportedMethods: hooks.getNonEvmSupportedMethods, + isNonEvmScopeSupported: hooks.isNonEvmScopeSupported, }, ); - // Fetch EVM accounts from native wallet keyring - // These addresses are lowercased already + const allRequestedAccountAddresses = getCaipAccountIdsFromScopesObjects([ + supportedRequiredScopes, + supportedOptionalScopes, + ]); + + const allSupportedRequestedCaipChainIds = getAllScopesFromScopesObjects([ + supportedRequiredScopes, + supportedOptionalScopes, + ]); + const existingEvmAddresses = hooks .listAccounts() .map((account) => account.address); - const supportedEthAccounts = getEthAccounts({ - requiredScopes: supportedRequiredScopes, - optionalScopes: supportedOptionalScopes, - }) - .map((address) => address.toLowerCase() as Hex) - .filter((address) => existingEvmAddresses.includes(address)); + + const supportedRequestedAccountAddresses = + allRequestedAccountAddresses.filter( + (requestedAccountAddress: CaipAccountId) => { + const { + address, + chain: { namespace }, + chainId: caipChainId, + } = parseCaipAccountId(requestedAccountAddress); + if (namespace === KnownCaipNamespace.Eip155) { + return existingEvmAddresses.some((existingEvmAddress) => { + return isEqualCaseInsensitive(address, existingEvmAddress); + }); + } + + // If the namespace is not eip155 (EVM) we do a case sensitive check + return hooks + .getNonEvmAccountAddresses(caipChainId) + .some((existingCaipAddress) => { + return requestedAccountAddress === existingCaipAddress; + }); + }, + ); const requestedCaip25CaveatValue = { requiredScopes: getInternalScopesObject(supportedRequiredScopes), optionalScopes: getInternalScopesObject(supportedOptionalScopes), isMultichainOrigin: true, + sessionProperties: filteredSessionProperties, }; - const requestedCaip25CaveatValueWithSupportedEthAccounts = setEthAccounts( - requestedCaip25CaveatValue, - supportedEthAccounts, - ); + const requestedCaip25CaveatValueWithSupportedAccounts = + setPermittedAccounts( + requestedCaip25CaveatValue, + supportedRequestedAccountAddresses, + ); - const [grantedPermissions] = await hooks.requestPermissionsForOrigin({ - [Caip25EndowmentPermissionName]: { - caveats: [ - { - type: Caip25CaveatType, - value: requestedCaip25CaveatValueWithSupportedEthAccounts, - }, - ], + // if `promptToCreateSolanaAccount` is true and there are no other valid scopes requested, + // we add a `wallet` scope to the request in order to get passed the CAIP-25 caveat validator. + // This is very hacky but is necessary because the solana opt-in flow breaks key assumptions + // of the CAIP-25 permission specification - namely that we can have valid requests with no scopes. + if (allSupportedRequestedCaipChainIds.length === 0) { + if (promptToCreateSolanaAccount) { + requestedCaip25CaveatValueWithSupportedAccounts.optionalScopes[ + KnownCaipNamespace.Wallet + ] = { + accounts: [], + }; + } else { + // if solana is not requested and there are no supported scopes, we return an error + return end( + new JsonRpcError(5100, 'Requested scopes are not supported'), + ); + } + } + + const [grantedPermissions] = await hooks.requestPermissionsForOrigin( + { + [Caip25EndowmentPermissionName]: { + caveats: [ + { + type: Caip25CaveatType, + value: requestedCaip25CaveatValueWithSupportedAccounts, + }, + ], + }, }, - }); + { + metadata: { promptToCreateSolanaAccount }, + }, + ); const approvedCaip25Permission = grantedPermissions[Caip25EndowmentPermissionName]; @@ -176,7 +279,12 @@ async function walletCreateSessionHandler( throw rpcErrors.internal(); } - const sessionScopes = getSessionScopes(approvedCaip25CaveatValue); + const sessionScopes = getSessionScopes(approvedCaip25CaveatValue, { + getNonEvmSupportedMethods: hooks.getNonEvmSupportedMethods, + }); + + const { sessionProperties: approvedSessionProperties = {} } = + approvedCaip25CaveatValue; // TODO: Contact analytics team for how they would prefer to track this // first time connection to dapp will lead to no log in the permissionHistory @@ -211,7 +319,7 @@ async function walletCreateSessionHandler( res.result = { sessionScopes, - sessionProperties, + sessionProperties: approvedSessionProperties, }; return end(); } catch (err) { @@ -228,5 +336,8 @@ export const walletCreateSession = { requestPermissionsForOrigin: true, sendMetrics: true, metamaskState: true, + getNonEvmSupportedMethods: true, + isNonEvmScopeSupported: true, + getNonEvmAccountAddresses: true, }, }; diff --git a/app/scripts/lib/rpc-method-middleware/handlers/wallet-getPermissions.test.ts b/app/scripts/lib/rpc-method-middleware/handlers/wallet-getPermissions.test.ts index 2cc8f19fb3ca..dbef1520a114 100644 --- a/app/scripts/lib/rpc-method-middleware/handlers/wallet-getPermissions.test.ts +++ b/app/scripts/lib/rpc-method-middleware/handlers/wallet-getPermissions.test.ts @@ -1,8 +1,8 @@ import { Caip25CaveatType, Caip25EndowmentPermissionName, -} from '@metamask/multichain'; -import * as Multichain from '@metamask/multichain'; +} from '@metamask/chain-agnostic-permission'; +import * as Multichain from '@metamask/chain-agnostic-permission'; import { Json, JsonRpcRequest, PendingJsonRpcResponse } from '@metamask/utils'; import { CaveatTypes, @@ -11,8 +11,8 @@ import { import { PermissionNames } from '../../../controllers/permissions'; import { getPermissionsHandler } from './wallet-getPermissions'; -jest.mock('@metamask/multichain', () => ({ - ...jest.requireActual('@metamask/multichain'), +jest.mock('@metamask/chain-agnostic-permission', () => ({ + ...jest.requireActual('@metamask/chain-agnostic-permission'), getPermittedEthChainIds: jest.fn(), })); const MockMultichain = jest.mocked(Multichain); diff --git a/app/scripts/lib/rpc-method-middleware/handlers/wallet-getPermissions.ts b/app/scripts/lib/rpc-method-middleware/handlers/wallet-getPermissions.ts index 0ff95c327a59..173fdc6fac18 100644 --- a/app/scripts/lib/rpc-method-middleware/handlers/wallet-getPermissions.ts +++ b/app/scripts/lib/rpc-method-middleware/handlers/wallet-getPermissions.ts @@ -9,7 +9,7 @@ import { Caip25CaveatValue, Caip25EndowmentPermissionName, getPermittedEthChainIds, -} from '@metamask/multichain'; +} from '@metamask/chain-agnostic-permission'; import { AsyncJsonRpcEngineNextCallback, JsonRpcEngineEndCallback, diff --git a/app/scripts/lib/rpc-method-middleware/handlers/wallet-requestPermissions.test.ts b/app/scripts/lib/rpc-method-middleware/handlers/wallet-requestPermissions.test.ts index 5556dd840021..f58e1cb4bc96 100644 --- a/app/scripts/lib/rpc-method-middleware/handlers/wallet-requestPermissions.test.ts +++ b/app/scripts/lib/rpc-method-middleware/handlers/wallet-requestPermissions.test.ts @@ -5,7 +5,7 @@ import { import { Caip25CaveatType, Caip25EndowmentPermissionName, -} from '@metamask/multichain'; +} from '@metamask/chain-agnostic-permission'; import { Json, JsonRpcRequest, PendingJsonRpcResponse } from '@metamask/utils'; import { CaveatTypes, diff --git a/app/scripts/lib/rpc-method-middleware/handlers/wallet-requestPermissions.ts b/app/scripts/lib/rpc-method-middleware/handlers/wallet-requestPermissions.ts index 30f6668712ef..0e756c3fc51f 100644 --- a/app/scripts/lib/rpc-method-middleware/handlers/wallet-requestPermissions.ts +++ b/app/scripts/lib/rpc-method-middleware/handlers/wallet-requestPermissions.ts @@ -12,7 +12,7 @@ import { Caip25CaveatValue, Caip25EndowmentPermissionName, getPermittedEthChainIds, -} from '@metamask/multichain'; +} from '@metamask/chain-agnostic-permission'; import { Json, JsonRpcRequest, PendingJsonRpcResponse } from '@metamask/utils'; import { AsyncJsonRpcEngineNextCallback, diff --git a/app/scripts/lib/rpc-method-middleware/handlers/wallet-revokePermissions.test.ts b/app/scripts/lib/rpc-method-middleware/handlers/wallet-revokePermissions.test.ts index fd14fa424a61..b238b05a8dfd 100644 --- a/app/scripts/lib/rpc-method-middleware/handlers/wallet-revokePermissions.test.ts +++ b/app/scripts/lib/rpc-method-middleware/handlers/wallet-revokePermissions.test.ts @@ -1,5 +1,5 @@ import { invalidParams } from '@metamask/permission-controller'; -import { Caip25EndowmentPermissionName } from '@metamask/multichain'; +import { Caip25EndowmentPermissionName } from '@metamask/chain-agnostic-permission'; import { Json, JsonRpcRequest, PendingJsonRpcResponse } from '@metamask/utils'; import { PermissionNames } from '../../../controllers/permissions'; import { RestrictedMethods } from '../../../../../shared/constants/permissions'; @@ -87,7 +87,6 @@ describe('revokePermissionsHandler', () => { ); }); - // @ts-expect-error This is missing from the Mocha type definitions describe.each([ [RestrictedMethods.eth_accounts], [PermissionNames.permittedChains], diff --git a/app/scripts/lib/rpc-method-middleware/handlers/wallet-revokePermissions.ts b/app/scripts/lib/rpc-method-middleware/handlers/wallet-revokePermissions.ts index 8b5e7155fd27..04aa30b731ee 100644 --- a/app/scripts/lib/rpc-method-middleware/handlers/wallet-revokePermissions.ts +++ b/app/scripts/lib/rpc-method-middleware/handlers/wallet-revokePermissions.ts @@ -5,7 +5,7 @@ import { JsonRpcRequest, PendingJsonRpcResponse, } from '@metamask/utils'; -import { Caip25EndowmentPermissionName } from '@metamask/multichain'; +import { Caip25EndowmentPermissionName } from '@metamask/chain-agnostic-permission'; import { AsyncJsonRpcEngineNextCallback, JsonRpcEngineEndCallback, diff --git a/app/scripts/lib/snap-keyring/keyring-snaps-permissions.test.ts b/app/scripts/lib/snap-keyring/keyring-snaps-permissions.test.ts index a04b443759a1..e66739c7b47b 100644 --- a/app/scripts/lib/snap-keyring/keyring-snaps-permissions.test.ts +++ b/app/scripts/lib/snap-keyring/keyring-snaps-permissions.test.ts @@ -32,7 +32,6 @@ describe('keyringSnapPermissionsBuilder', () => { }); describe('Portfolio origin', () => { - // @ts-expect-error This is missing from the Mocha type definitions it.each(PORTFOLIO_ORIGINS)( 'returns the methods that can be called by %s', (origin: string) => { @@ -49,7 +48,6 @@ describe('keyringSnapPermissionsBuilder', () => { }, ); - // @ts-expect-error This is missing from the Mocha type definitions it.each(PORTFOLIO_ORIGINS)( '%s cannot create an account', (origin: string) => { @@ -61,7 +59,6 @@ describe('keyringSnapPermissionsBuilder', () => { }, ); - // @ts-expect-error This is missing from the Mocha type definitions it.each(PORTFOLIO_ORIGINS)('%s can submit a request', (origin: string) => { const permissions = keyringSnapPermissionsBuilder(mockController, origin); expect(permissions()).toContain(KeyringRpcMethod.SubmitRequest); @@ -113,7 +110,6 @@ describe('keyringSnapPermissionsBuilder', () => { expect(permissions()).toStrictEqual([]); }); - // @ts-expect-error This is missing from the Mocha type definitions it.each([ '', 'null', @@ -139,7 +135,6 @@ describe('keyringSnapPermissionsBuilder', () => { }); describe('isProtocolAllowed', () => { - // @ts-expect-error This is missing from the Mocha type definitions it.each([ ['http://some-dapp.com', true], ['https://some-dapp.com', true], diff --git a/app/scripts/lib/snap-keyring/keyring-snaps-permissions.ts b/app/scripts/lib/snap-keyring/keyring-snaps-permissions.ts index f7d9c829a3cc..1566e7b3b6bb 100644 --- a/app/scripts/lib/snap-keyring/keyring-snaps-permissions.ts +++ b/app/scripts/lib/snap-keyring/keyring-snaps-permissions.ts @@ -1,8 +1,8 @@ +import { KeyringRpcMethod } from '@metamask/keyring-api'; import { - SubjectType, SubjectMetadataController, + SubjectType, } from '@metamask/permission-controller'; -import { KeyringRpcMethod } from '@metamask/keyring-api'; /** * The origins of the Portfolio dapp. diff --git a/app/scripts/lib/snap-keyring/snap-keyring.test.ts b/app/scripts/lib/snap-keyring/snap-keyring.test.ts index 4c42846a10d1..6264b841e5d6 100644 --- a/app/scripts/lib/snap-keyring/snap-keyring.test.ts +++ b/app/scripts/lib/snap-keyring/snap-keyring.test.ts @@ -11,6 +11,8 @@ import { MetaMetricsEventCategory, MetaMetricsEventName, } from '../../../../shared/constants/metametrics'; +import { isSnapPreinstalled } from '../../../../shared/lib/snaps/snaps'; +import { getSnapName } from '../../../../shared/lib/accounts/snaps'; import { showAccountCreationDialog, showAccountNameSuggestionDialog, @@ -20,7 +22,6 @@ import { SnapKeyringBuilderAllowActions, SnapKeyringBuilderMessenger, } from './types'; -import { getSnapName, isSnapPreinstalled } from './snaps'; const mockAddRequest = jest.fn(); const mockStartFlow = jest.fn(); @@ -68,9 +69,13 @@ const mockInternalAccount = { }, }; -jest.mock('./snaps', () => ({ - ...jest.requireActual('./snaps'), +jest.mock('../../../../shared/lib/snaps/snaps', () => ({ + ...jest.requireActual('../../../../shared/lib/snaps/snaps'), isSnapPreinstalled: jest.fn(), +})); + +jest.mock('../../../../shared/lib/accounts/snaps', () => ({ + ...jest.requireActual('../../../../shared/lib/accounts/snaps'), getSnapName: jest.fn(), })); diff --git a/app/scripts/lib/snap-keyring/snap-keyring.ts b/app/scripts/lib/snap-keyring/snap-keyring.ts index 3f7b2281c1ae..6506c697ab58 100644 --- a/app/scripts/lib/snap-keyring/snap-keyring.ts +++ b/app/scripts/lib/snap-keyring/snap-keyring.ts @@ -1,4 +1,9 @@ -import { SnapKeyring, SnapKeyringCallbacks } from '@metamask/eth-snap-keyring'; +import { + getDefaultInternalOptions, + SnapKeyring, + SnapKeyringCallbacks, + SnapKeyringInternalOptions, +} from '@metamask/eth-snap-keyring'; import browser from 'webextension-polyfill'; import { SnapId } from '@metamask/snaps-sdk'; import { assertIsValidSnapId } from '@metamask/snaps-utils'; @@ -14,10 +19,11 @@ import { t } from '../../translate'; import { IconName } from '../../../../ui/components/component-library/icon'; import MetaMetricsController from '../../controllers/metametrics-controller'; import { getUniqueAccountName } from '../../../../shared/lib/accounts'; +import { isSnapPreinstalled } from '../../../../shared/lib/snaps/snaps'; +import { getSnapName } from '../../../../shared/lib/accounts/snaps'; import { SnapKeyringBuilderMessenger } from './types'; import { isBlockedUrl } from './utils/isBlockedUrl'; import { showError, showSuccess } from './utils/showResult'; -import { getSnapName, isSnapPreinstalled } from './snaps'; /** * Builder type for the Snap keyring. @@ -274,12 +280,14 @@ class SnapKeyringImpl implements SnapKeyringCallbacks { address, snapId, skipConfirmationDialog, + skipSetSelectedAccountStep, accountName, onceSaved, }: { address: string; snapId: SnapId; skipConfirmationDialog: boolean; + skipSetSelectedAccountStep: boolean; onceSaved: Promise; accountName?: string; }) { @@ -310,11 +318,13 @@ class SnapKeyringImpl implements SnapKeyringCallbacks { // state, so we can safely uses this state to run post-processing. // (e.g. renaming the account, select the account, etc...) - // Set the selected account to the new account - this.#messenger.call( - 'AccountsController:setSelectedAccount', - accountId, - ); + if (!skipSetSelectedAccountStep) { + // Set the selected account to the new account + this.#messenger.call( + 'AccountsController:setSelectedAccount', + accountId, + ); + } if (accountName) { this.#messenger.call( @@ -384,8 +394,11 @@ class SnapKeyringImpl implements SnapKeyringCallbacks { handleUserInput: (accepted: boolean) => Promise, onceSaved: Promise, accountNameSuggestion: string = '', - displayConfirmation: boolean = false, - displayAccountNameSuggestion: boolean = true, + { + displayConfirmation, + displayAccountNameSuggestion, + setSelectedAccount, + }: SnapKeyringInternalOptions = getDefaultInternalOptions(), ) { assertIsValidSnapId(snapId); @@ -397,6 +410,10 @@ class SnapKeyringImpl implements SnapKeyringCallbacks { const skipAccountNameSuggestionDialog = isSnapPreinstalled(snapId) && !displayAccountNameSuggestion; + // Only pre-installed Snaps can skip the account from being selected. + const skipSetSelectedAccountStep = + isSnapPreinstalled(snapId) && !setSelectedAccount; + // First part of the flow, which includes confirmation dialogs (if not skipped). // Once confirmed, we resume the Snap execution. const { accountName } = await this.#addAccountConfirmations({ @@ -415,6 +432,7 @@ class SnapKeyringImpl implements SnapKeyringCallbacks { address, snapId, skipConfirmationDialog, + skipSetSelectedAccountStep, accountName, onceSaved, }); diff --git a/app/scripts/lib/snap-keyring/utils/isBlockedUrl.test.ts b/app/scripts/lib/snap-keyring/utils/isBlockedUrl.test.ts index d45adad18041..4f6d238d7077 100644 --- a/app/scripts/lib/snap-keyring/utils/isBlockedUrl.test.ts +++ b/app/scripts/lib/snap-keyring/utils/isBlockedUrl.test.ts @@ -32,7 +32,6 @@ describe('isBlockedUrl', () => { }, }); - // @ts-expect-error This is missing from the Mocha type definitions it.each([ ['http://metamask.io', false], ['https://metamask.io', false], diff --git a/app/scripts/lib/transaction/__snapshots__/delegation.test.ts.snap b/app/scripts/lib/transaction/__snapshots__/delegation.test.ts.snap new file mode 100644 index 000000000000..691fe2924a32 --- /dev/null +++ b/app/scripts/lib/transaction/__snapshots__/delegation.test.ts.snap @@ -0,0 +1,7 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Delegation Utils encodeRedeemDelegations returns encoded hex if delegation chains and batch execution 1`] = `"0xcef6d2090000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000058000000000000000000000000000000000000000000000000000000000000005c00000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004c0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000026000000000000000000000000012345678901234567890123456789012345678920000000000000000000000001234567890123456789012345678901234567893aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa00000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000007b00000000000000000000000000000000000000000000000000000000000001e0000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000001234567890123456789012345678901234567896000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000021234000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000243210000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002789000000000000000000000000000000000000000000000000000000000000000000000000000000000000012345678901234567890123456789012345678920000000000000000000000001234567890123456789012345678901234567893aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa00000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000007b00000000000000000000000000000000000000000000000000000000000001e0000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000001234567890123456789012345678901234567896000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000212340000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002432100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000027890000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000101000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000001c000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000001234567890123456789012345678901234567894000000000000000000000000000000000000000000000000000000000000012300000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000014123456789012345678901234567890123456789500000000000000000000000000000000000000000000000012345678901234567890123456789012345678940000000000000000000000000000000000000000000000000000000000000123000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000141234567890123456789012345678901234567895000000000000000000000000"`; + +exports[`Delegation Utils encodeRedeemDelegations returns encoded hex if multiple delegation chains and multiple batch executions 1`] = `"0xcef6d20900000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000a800000000000000000000000000000000000000000000000000000000000000ae000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000052000000000000000000000000000000000000000000000000000000000000004c0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000026000000000000000000000000012345678901234567890123456789012345678920000000000000000000000001234567890123456789012345678901234567893aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa00000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000007b00000000000000000000000000000000000000000000000000000000000001e0000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000001234567890123456789012345678901234567896000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000021234000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000243210000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002789000000000000000000000000000000000000000000000000000000000000000000000000000000000000012345678901234567890123456789012345678920000000000000000000000001234567890123456789012345678901234567893aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa00000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000007b00000000000000000000000000000000000000000000000000000000000001e0000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000001234567890123456789012345678901234567896000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000021234000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000243210000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002789000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004c0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000026000000000000000000000000012345678901234567890123456789012345678920000000000000000000000001234567890123456789012345678901234567893aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa00000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000007b00000000000000000000000000000000000000000000000000000000000001e0000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000001234567890123456789012345678901234567896000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000021234000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000243210000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002789000000000000000000000000000000000000000000000000000000000000000000000000000000000000012345678901234567890123456789012345678920000000000000000000000001234567890123456789012345678901234567893aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa00000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000007b00000000000000000000000000000000000000000000000000000000000001e0000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000001234567890123456789012345678901234567896000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000021234000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000243210000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002789000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020100000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000022000000000000000000000000000000000000000000000000000000000000001c000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000123456789012345678901234567890123456789400000000000000000000000000000000000000000000000000000000000001230000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000001412345678901234567890123456789012345678950000000000000000000000000000000000000000000000001234567890123456789012345678901234567894000000000000000000000000000000000000000000000000000000000000012300000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000014123456789012345678901234567890123456789500000000000000000000000000000000000000000000000000000000000000000000000000000000000001c000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000001234567890123456789012345678901234567894000000000000000000000000000000000000000000000000000000000000012300000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000014123456789012345678901234567890123456789500000000000000000000000000000000000000000000000012345678901234567890123456789012345678940000000000000000000000000000000000000000000000000000000000000123000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000141234567890123456789012345678901234567895000000000000000000000000"`; + +exports[`Delegation Utils encodeRedeemDelegations returns encoded hex if single delegation and single execution 1`] = `"0xcef6d20900000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000340000000000000000000000000000000000000000000000000000000000000038000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000028000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000002000000000000000000000000012345678901234567890123456789012345678920000000000000000000000001234567890123456789012345678901234567893aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa00000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000007b00000000000000000000000000000000000000000000000000000000000001e0000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000001234567890123456789012345678901234567896000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000002123400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000024321000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000278900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000002000000000000000000000000012345678901234567890123456789012345678940000000000000000000000000000000000000000000000000000000000000123000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000141234567890123456789012345678901234567895000000000000000000000000"`; diff --git a/app/scripts/lib/transaction/decode/util.ts b/app/scripts/lib/transaction/decode/util.ts index cb5aca019516..61192d0c0df4 100644 --- a/app/scripts/lib/transaction/decode/util.ts +++ b/app/scripts/lib/transaction/decode/util.ts @@ -121,7 +121,7 @@ function normalizeDecodedParamValue(value: any): any { const hexValue = value._hex; if (hexValue) { - return parseInt(hexValue, 16); + return BigInt(hexValue).toString(); } return value; diff --git a/app/scripts/lib/transaction/delegation.test.ts b/app/scripts/lib/transaction/delegation.test.ts new file mode 100644 index 000000000000..190ffecdfa7a --- /dev/null +++ b/app/scripts/lib/transaction/delegation.test.ts @@ -0,0 +1,141 @@ +import { + KeyringControllerSignTypedMessageAction, + SignTypedDataVersion, +} from '@metamask/keyring-controller'; +import { Messenger } from '@metamask/base-controller'; +import { TransactionControllerInitMessenger } from '../../controller-init/messengers/transaction-controller-messenger'; +import { + Delegation, + Execution, + ExecutionMode, + encodeRedeemDelegations, + signDelegation, +} from './delegation'; + +const FROM_MOCK = '0x123456789012345678901234567890123456789a'; +const CHAIN_ID_MOCK = '0x123'; + +const DELEGATION_MOCK: Delegation = { + authority: + '0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', + caveats: [ + { + enforcer: '0x1234567890123456789012345678901234567896', + terms: '0x1234', + args: '0x4321', + }, + ], + delegate: '0x1234567890123456789012345678901234567892', + delegator: '0x1234567890123456789012345678901234567893', + salt: 123, + signature: '0x7890', +}; + +const EXECUTION_MOCK: Execution = { + target: '0x1234567890123456789012345678901234567894', + value: '0x123', + callData: '0x1234567890123456789012345678901234567895', +}; + +describe('Delegation Utils', () => { + let keyringControllerSignTypedMessageMock: jest.MockedFn< + KeyringControllerSignTypedMessageAction['handler'] + >; + + let initMessenger: TransactionControllerInitMessenger; + + beforeEach(() => { + jest.resetAllMocks(); + + keyringControllerSignTypedMessageMock = jest.fn(); + + const baseMessenger = new Messenger< + KeyringControllerSignTypedMessageAction, + never + >(); + + baseMessenger.registerActionHandler( + 'KeyringController:signTypedMessage', + keyringControllerSignTypedMessageMock, + ); + + initMessenger = baseMessenger.getRestricted({ + name: 'Test', + allowedActions: ['KeyringController:signTypedMessage'], + allowedEvents: [], + }); + }); + + describe('signDelegation', () => { + it('calls keyring controller', async () => { + await signDelegation({ + chainId: CHAIN_ID_MOCK, + delegation: DELEGATION_MOCK, + from: FROM_MOCK, + messenger: initMessenger, + }); + + expect(keyringControllerSignTypedMessageMock).toHaveBeenCalledTimes(1); + expect(keyringControllerSignTypedMessageMock).toHaveBeenCalledWith( + { + from: FROM_MOCK, + data: expect.any(Object), + }, + SignTypedDataVersion.V4, + ); + }); + + it('returns hash from keyring controller', async () => { + keyringControllerSignTypedMessageMock.mockResolvedValueOnce( + DELEGATION_MOCK.signature, + ); + + const result = await signDelegation({ + chainId: CHAIN_ID_MOCK, + delegation: DELEGATION_MOCK, + from: FROM_MOCK, + messenger: initMessenger, + }); + + expect(result).toBe(DELEGATION_MOCK.signature); + }); + }); + + describe('encodeRedeemDelegations', () => { + it('returns encoded hex if single delegation and single execution', () => { + expect( + encodeRedeemDelegations( + [[DELEGATION_MOCK]], + [ExecutionMode.BATCH_DEFAULT_MODE], + [[EXECUTION_MOCK]], + ), + ).toMatchSnapshot(); + }); + + it('returns encoded hex if delegation chains and batch execution', () => { + expect( + encodeRedeemDelegations( + [[DELEGATION_MOCK, DELEGATION_MOCK]], + [ExecutionMode.BATCH_DEFAULT_MODE], + [[EXECUTION_MOCK, EXECUTION_MOCK]], + ), + ).toMatchSnapshot(); + }); + + it('returns encoded hex if multiple delegation chains and multiple batch executions', () => { + expect( + encodeRedeemDelegations( + [ + [DELEGATION_MOCK, DELEGATION_MOCK], + [DELEGATION_MOCK, DELEGATION_MOCK], + ], + [ExecutionMode.BATCH_DEFAULT_MODE, ExecutionMode.BATCH_DEFAULT_MODE], + [ + [EXECUTION_MOCK, EXECUTION_MOCK], + [EXECUTION_MOCK, EXECUTION_MOCK], + ], + ), + ).toMatchSnapshot(); + }); + }); +}); diff --git a/app/scripts/lib/transaction/delegation.ts b/app/scripts/lib/transaction/delegation.ts new file mode 100644 index 000000000000..7a6111e19601 --- /dev/null +++ b/app/scripts/lib/transaction/delegation.ts @@ -0,0 +1,195 @@ +import { MessageParamsTypedData } from '@metamask/signature-controller'; +import { Hex, hexToNumber } from '@metamask/utils'; +import { SignTypedDataVersion } from '@metamask/keyring-controller'; +import { Interface, ParamType, defaultAbiCoder } from '@ethersproject/abi'; +import { TransactionControllerInitMessenger } from '../../controller-init/messengers/transaction-controller-messenger'; + +export type Caveat = { + enforcer: Hex; + terms: Hex; + args: Hex; +}; + +export type UnsignedDelegation = { + delegate: Hex; + delegator: Hex; + authority: Hex; + caveats: Caveat[]; + salt: number; +}; + +export type Delegation = UnsignedDelegation & { + signature: Hex; +}; + +export type Execution = { + target: Hex; + value: Hex; + callData: Hex; +}; + +export enum ExecutionMode { + BATCH_DEFAULT_MODE = '0x0100000000000000000000000000000000000000000000000000000000000000', +} + +export const ROOT_AUTHORITY = + '0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'; + +export const ANY_BENEFICIARY = '0x0000000000000000000000000000000000000a11'; + +const PRIMARY_TYPE_DELEGATION = 'Delegation'; +const DOMAIN_NAME = 'DelegationManager'; + +const ABI_TYPES_CAVEAT = [ + { type: 'address', name: 'enforcer' }, + { type: 'bytes', name: 'terms' }, + { type: 'bytes', name: 'args' }, +]; + +const ABI_TYPES_DELEGATION = [ + { type: 'address', name: 'delegate' }, + { type: 'address', name: 'delegator' }, + { type: 'bytes32', name: 'authority' }, + { type: 'tuple[]', name: 'caveats', components: ABI_TYPES_CAVEAT }, + { type: 'uint256', name: 'salt' }, + { type: 'bytes', name: 'signature' }, +]; + +const ABI_TYPES_EXECUTION = [ + { type: 'address', name: 'target' }, + { type: 'uint256', name: 'value' }, + { type: 'bytes', name: 'callData' }, +]; + +const ABI_REDEEM_DELEGATIONS = [ + { + type: 'function', + name: 'redeemDelegations', + inputs: [ + { + name: '_permissionContexts', + type: 'bytes[]', + internalType: 'bytes[]', + }, + { + name: '_modes', + type: 'bytes32[]', + internalType: 'ModeCode[]', + }, + { + name: '_executionCallDatas', + type: 'bytes[]', + internalType: 'bytes[]', + }, + ], + outputs: [], + stateMutability: 'nonpayable', + }, +]; + +const TYPES_EIP_712_DOMAIN = [ + { name: 'name', type: 'string' }, + { name: 'version', type: 'string' }, + { name: 'chainId', type: 'uint256' }, + { name: 'verifyingContract', type: 'address' }, +]; + +const TYPES_DELEGATION = { + EIP712Domain: TYPES_EIP_712_DOMAIN, + Caveat: [ + { name: 'enforcer', type: 'address' }, + { name: 'terms', type: 'bytes' }, + ], + Delegation: [ + { name: 'delegate', type: 'address' }, + { name: 'delegator', type: 'address' }, + { name: 'authority', type: 'bytes32' }, + { name: 'caveats', type: 'Caveat[]' }, + { name: 'salt', type: 'uint256' }, + ], +}; + +export async function signDelegation({ + chainId, + delegation, + from, + messenger, +}: { + chainId: Hex; + delegation: UnsignedDelegation; + from: Hex; + messenger: TransactionControllerInitMessenger; +}): Promise { + const data: MessageParamsTypedData = { + types: TYPES_DELEGATION, + primaryType: PRIMARY_TYPE_DELEGATION, + domain: { + chainId: String(hexToNumber(chainId)), + name: DOMAIN_NAME, + version: '1', + verifyingContract: process.env.DELEGATION_MANAGER_ADDRESS as Hex, + }, + message: { ...delegation, chainId: hexToNumber(chainId) }, + }; + + return (await messenger.call( + 'KeyringController:signTypedMessage', + { + from, + data, + }, + SignTypedDataVersion.V4, + )) as Hex; +} + +export function encodeRedeemDelegations( + delegations: Delegation[][], + modes: ExecutionMode[], + executions: Execution[][], +): Hex { + const redeemDelegationsInterface = new Interface(ABI_REDEEM_DELEGATIONS); + + return redeemDelegationsInterface.encodeFunctionData('redeemDelegations', [ + encodePermissionContexts(delegations), + modes, + encodeExecutionCalldatas(executions), + ]) as Hex; +} + +function encodePermissionContexts(permissionContexts: Delegation[][]) { + const encodedDelegations = permissionContexts.map((delegationChain) => + encodeDelegation(delegationChain), + ); + + return encodedDelegations; +} + +function encodeExecutionCalldatas(executionsBatch: Execution[][]): Hex[] { + return executionsBatch.map(encodeBatchExecution); +} + +function encodeBatchExecution(executions: Execution[]): Hex { + return defaultAbiCoder.encode( + [ + ParamType.from({ + components: ABI_TYPES_EXECUTION, + name: 'executions', + type: 'tuple[]', + }), + ], + [executions], + ) as Hex; +} + +function encodeDelegation(delegations: Delegation[]): Hex { + return defaultAbiCoder.encode( + [ + ParamType.from({ + components: ABI_TYPES_DELEGATION, + name: 'delegations', + type: 'tuple[]', + }), + ], + [delegations], + ) as Hex; +} diff --git a/app/scripts/lib/transaction/eip5792.test.ts b/app/scripts/lib/transaction/eip5792.test.ts index 399456511805..654ab4dbcc72 100644 --- a/app/scripts/lib/transaction/eip5792.test.ts +++ b/app/scripts/lib/transaction/eip5792.test.ts @@ -104,11 +104,17 @@ describe('EIP-5792', () => { Parameters[0]['validateSecurity'] > = jest.fn(); + const getDismissSmartAccountSuggestionEnabledMock: jest.MockedFn< + () => boolean + > = jest.fn(); + let messenger: EIP5792Messenger; const sendCallsHooks = { addTransactionBatch: addTransactionBatchMock, getDisabledAccountUpgradeChains: getDisabledAccountUpgradeChainsMock, + getDismissSmartAccountSuggestionEnabled: + getDismissSmartAccountSuggestionEnabledMock, isAtomicBatchSupported: isAtomicBatchSupportedMock, validateSecurity: validateSecurityMock, }; @@ -414,7 +420,6 @@ describe('EIP-5792', () => { ); }); - // @ts-expect-error This function is missing from the Mocha type definitions it.each([ TransactionStatus.approved, TransactionStatus.signed, @@ -462,6 +467,8 @@ describe('EIP-5792', () => { const capabilities = await getCapabilities( { getDisabledAccountUpgradeChains: getDisabledAccountUpgradeChainsMock, + getDismissSmartAccountSuggestionEnabled: + getDismissSmartAccountSuggestionEnabledMock, isAtomicBatchSupported: isAtomicBatchSupportedMock, }, FROM_MOCK, @@ -490,6 +497,8 @@ describe('EIP-5792', () => { const capabilities = await getCapabilities( { getDisabledAccountUpgradeChains: getDisabledAccountUpgradeChainsMock, + getDismissSmartAccountSuggestionEnabled: + getDismissSmartAccountSuggestionEnabledMock, isAtomicBatchSupported: isAtomicBatchSupportedMock, }, FROM_MOCK, @@ -511,6 +520,8 @@ describe('EIP-5792', () => { const capabilities = await getCapabilities( { getDisabledAccountUpgradeChains: getDisabledAccountUpgradeChainsMock, + getDismissSmartAccountSuggestionEnabled: + getDismissSmartAccountSuggestionEnabledMock, isAtomicBatchSupported: isAtomicBatchSupportedMock, }, FROM_MOCK, @@ -535,6 +546,8 @@ describe('EIP-5792', () => { const capabilities = await getCapabilities( { getDisabledAccountUpgradeChains: getDisabledAccountUpgradeChainsMock, + getDismissSmartAccountSuggestionEnabled: + getDismissSmartAccountSuggestionEnabledMock, isAtomicBatchSupported: isAtomicBatchSupportedMock, }, FROM_MOCK, @@ -557,6 +570,8 @@ describe('EIP-5792', () => { const capabilities = await getCapabilities( { getDisabledAccountUpgradeChains: getDisabledAccountUpgradeChainsMock, + getDismissSmartAccountSuggestionEnabled: + getDismissSmartAccountSuggestionEnabledMock, isAtomicBatchSupported: isAtomicBatchSupportedMock, }, FROM_MOCK, diff --git a/app/scripts/lib/transaction/eip5792.ts b/app/scripts/lib/transaction/eip5792.ts index d5e425bdc251..e0e0c5143827 100644 --- a/app/scripts/lib/transaction/eip5792.ts +++ b/app/scripts/lib/transaction/eip5792.ts @@ -42,6 +42,7 @@ export async function processSendCalls( hooks: { addTransactionBatch: TransactionController['addTransactionBatch']; getDisabledAccountUpgradeChains: () => Hex[]; + getDismissSmartAccountSuggestionEnabled: () => boolean; isAtomicBatchSupported: TransactionController['isAtomicBatchSupported']; validateSecurity: ( securityAlertId: string, @@ -58,6 +59,7 @@ export async function processSendCalls( getDisabledAccountUpgradeChains, isAtomicBatchSupported, validateSecurity: validateSecurityHook, + getDismissSmartAccountSuggestionEnabled, } = hooks; const { calls, from: paramFrom } = params; @@ -75,6 +77,9 @@ export async function processSendCalls( const disabledChains = getDisabledAccountUpgradeChains(); + const dismissSmartAccountSuggestionEnabled = + getDismissSmartAccountSuggestionEnabled(); + const batchSupport = await isAtomicBatchSupported({ address: from, chainIds: [dappChainId], @@ -87,6 +92,7 @@ export async function processSendCalls( from, dappChainId, disabledChains, + dismissSmartAccountSuggestionEnabled, chainBatchSupport, ); @@ -154,12 +160,17 @@ export function getCallsStatus( export async function getCapabilities( hooks: { getDisabledAccountUpgradeChains: () => Hex[]; + getDismissSmartAccountSuggestionEnabled: () => boolean; isAtomicBatchSupported: TransactionController['isAtomicBatchSupported']; }, address: Hex, chainIds: Hex[] | undefined, ) { - const { getDisabledAccountUpgradeChains, isAtomicBatchSupported } = hooks; + const { + getDisabledAccountUpgradeChains, + getDismissSmartAccountSuggestionEnabled, + isAtomicBatchSupported, + } = hooks; const chainIdsNormalized = chainIds?.map( (chainId) => chainId.toLowerCase() as Hex, @@ -178,7 +189,8 @@ export async function getCapabilities( chainBatchSupport; const isUpgradeDisabled = - getDisabledAccountUpgradeChains()?.includes(chainId); + getDisabledAccountUpgradeChains()?.includes(chainId) || + getDismissSmartAccountSuggestionEnabled(); const canUpgrade = !isUpgradeDisabled && upgradeContractAddress && !delegationAddress; @@ -208,12 +220,20 @@ function validateSendCalls( from: Hex, dappChainId: Hex, disabledChains: Hex[], + dismissSmartAccountSuggestionEnabled: boolean, chainBatchSupport: IsAtomicBatchSupportedResultEntry | undefined, ) { validateSendCallsVersion(sendCalls); validateSendCallsChainId(sendCalls, dappChainId, chainBatchSupport); validateCapabilities(sendCalls); - validateUserDisabled(from, disabledChains, dappChainId, chainBatchSupport); + + validateUserDisabled( + from, + disabledChains, + dappChainId, + dismissSmartAccountSuggestionEnabled, + chainBatchSupport, + ); } function validateSendCallsVersion(sendCalls: SendCalls) { @@ -282,6 +302,7 @@ function validateUserDisabled( from: Hex, disabledChains: Hex[], dappChainId: Hex, + dismissSmartAccountSuggestionEnabled: boolean, chainBatchSupport: IsAtomicBatchSupportedResultEntry | undefined, ) { if (chainBatchSupport?.delegationAddress) { @@ -290,7 +311,7 @@ function validateUserDisabled( const isDisabled = disabledChains.includes(dappChainId); - if (isDisabled) { + if (isDisabled || dismissSmartAccountSuggestionEnabled) { throw new JsonRpcError( EIP5792ErrorCode.RejectedUpgrade, `EIP-7702 upgrade rejected for this chain and account - Chain ID: ${dappChainId}, Account: ${from}`, diff --git a/app/scripts/lib/transaction/hooks/delegation-7702-publish.test.ts b/app/scripts/lib/transaction/hooks/delegation-7702-publish.test.ts new file mode 100644 index 000000000000..29a953456e0c --- /dev/null +++ b/app/scripts/lib/transaction/hooks/delegation-7702-publish.test.ts @@ -0,0 +1,266 @@ +import { + GasFeeToken, + TransactionController, + TransactionMeta, +} from '@metamask/transaction-controller'; +import { Messenger } from '@metamask/base-controller'; +import { toHex } from '@metamask/controller-utils'; +import { + KeyringControllerSignEip7702AuthorizationAction, + KeyringControllerSignTypedMessageAction, +} from '@metamask/keyring-controller'; +import { TransactionControllerInitMessenger } from '../../../controller-init/messengers/transaction-controller-messenger'; +import { submitRelayTransaction } from '../transaction-relay'; +import { Delegation7702PublishHook } from './delegation-7702-publish'; + +jest.mock('../transaction-relay'); + +const SIGNED_TX_MOCK = '0x1234'; +const ENFORCE_ADDRESS_MOCK = '0x12345678901234567890123456789012345678a2'; +const DELEGATION_SIGNATURE_MOCK = '0xabcd'; +const TRANSCATION_HASH_MOCK = '0xefab'; + +const AUTHORIZATION_SIGNATURE_MOCK = + '0xf85c827a6994663f3ad617193148711d28f5334ee4ed070166028080a040e292da533253143f134643a03405f1af1de1d305526f44ed27e62061368d4ea051cfb0af34e491aa4d6796dececf95569088322e116c4b2f312bb23f20699269'; + +const UPGRADE_CONTRACT_ADDRESS_MOCK = + '0x12345678901234567890123456789012345678a4'; + +const DELEGATION_MANAGER_ADDRESS_MOCK = + '0x12345678901234567890123456789012345678a0'; + +const TRANSACTION_META_MOCK = { + chainId: '0x1', + txParams: { + from: '0x12345678901234567890123456789012345678ab', + maxFeePerGas: '0x2', + maxPriorityFeePerGas: '0x1', + nonce: '0x3', + to: '0x12345678901234567890123456789012345678a3', + }, +} as unknown as TransactionMeta; + +const GAS_FEE_TOKEN_MOCK: GasFeeToken = { + amount: toHex(1000), + balance: toHex(2345), + decimals: 3, + gas: '0x3', + maxFeePerGas: '0x4', + maxPriorityFeePerGas: '0x5', + rateWei: toHex('1798170000000000000'), + recipient: '0x1234567890123456789012345678901234567890', + symbol: 'TEST', + tokenAddress: '0x1234567890123456789012345678901234567890', +}; + +describe('Delegation 7702 Publish Hook', () => { + const submitRelayTransactionMock = jest.mocked(submitRelayTransaction); + + let messenger: TransactionControllerInitMessenger; + let hookClass: Delegation7702PublishHook; + + const signTypedMessageMock: jest.MockedFn< + KeyringControllerSignTypedMessageAction['handler'] + > = jest.fn(); + + const signEip7702AuthorizationMock: jest.MockedFn< + KeyringControllerSignEip7702AuthorizationAction['handler'] + > = jest.fn(); + + const isAtomicBatchSupportedMock: jest.MockedFn< + TransactionController['isAtomicBatchSupported'] + > = jest.fn(); + + beforeEach(() => { + jest.resetAllMocks(); + + process.env.DELEGATION_MANAGER_ADDRESS = DELEGATION_MANAGER_ADDRESS_MOCK; + process.env.GASLESS_7702_ENFORCER_ADDRESS = ENFORCE_ADDRESS_MOCK; + + const baseMessenger = new Messenger< + | KeyringControllerSignEip7702AuthorizationAction + | KeyringControllerSignTypedMessageAction, + never + >(); + + messenger = baseMessenger.getRestricted({ + name: 'TransactionController', + allowedActions: [ + 'KeyringController:signEip7702Authorization', + 'KeyringController:signTypedMessage', + ], + allowedEvents: [], + }); + + baseMessenger.registerActionHandler( + 'KeyringController:signEip7702Authorization', + signEip7702AuthorizationMock, + ); + + baseMessenger.registerActionHandler( + 'KeyringController:signTypedMessage', + signTypedMessageMock, + ); + + hookClass = new Delegation7702PublishHook({ + isAtomicBatchSupported: isAtomicBatchSupportedMock, + messenger, + }); + + isAtomicBatchSupportedMock.mockResolvedValue([]); + signTypedMessageMock.mockResolvedValue(DELEGATION_SIGNATURE_MOCK); + + submitRelayTransactionMock.mockResolvedValue({ + transactionHash: TRANSCATION_HASH_MOCK, + }); + + signEip7702AuthorizationMock.mockResolvedValue( + AUTHORIZATION_SIGNATURE_MOCK, + ); + }); + + describe('returns empty result if', () => { + it('atomic batch is not supported', async () => { + const result = await hookClass.getHook()( + TRANSACTION_META_MOCK, + SIGNED_TX_MOCK, + ); + + expect(result).toEqual({ + transactionHash: undefined, + }); + }); + + it('no selected gas fee token', async () => { + isAtomicBatchSupportedMock.mockResolvedValueOnce([ + { + chainId: TRANSACTION_META_MOCK.chainId, + delegationAddress: undefined, + isSupported: false, + }, + ]); + + const result = await hookClass.getHook()( + { + ...TRANSACTION_META_MOCK, + gasFeeTokens: [GAS_FEE_TOKEN_MOCK], + }, + SIGNED_TX_MOCK, + ); + + expect(result).toEqual({ + transactionHash: undefined, + }); + }); + + it('no gas fee tokens', async () => { + isAtomicBatchSupportedMock.mockResolvedValueOnce([ + { + chainId: TRANSACTION_META_MOCK.chainId, + delegationAddress: undefined, + isSupported: false, + }, + ]); + + const result = await hookClass.getHook()( + { + ...TRANSACTION_META_MOCK, + selectedGasFeeToken: GAS_FEE_TOKEN_MOCK.tokenAddress, + }, + SIGNED_TX_MOCK, + ); + + expect(result).toEqual({ + transactionHash: undefined, + }); + }); + }); + + it('submits request to transaction relay', async () => { + isAtomicBatchSupportedMock.mockResolvedValueOnce([ + { + chainId: TRANSACTION_META_MOCK.chainId, + delegationAddress: UPGRADE_CONTRACT_ADDRESS_MOCK, + isSupported: true, + upgradeContractAddress: UPGRADE_CONTRACT_ADDRESS_MOCK, + }, + ]); + + await hookClass.getHook()( + { + ...TRANSACTION_META_MOCK, + gasFeeTokens: [GAS_FEE_TOKEN_MOCK], + selectedGasFeeToken: GAS_FEE_TOKEN_MOCK.tokenAddress, + }, + SIGNED_TX_MOCK, + ); + + expect(submitRelayTransactionMock).toHaveBeenCalledTimes(1); + expect(submitRelayTransactionMock).toHaveBeenCalledWith({ + data: expect.any(String), + maxFeePerGas: TRANSACTION_META_MOCK.txParams.maxFeePerGas, + maxPriorityFeePerGas: TRANSACTION_META_MOCK.txParams.maxPriorityFeePerGas, + to: process.env.DELEGATION_MANAGER_ADDRESS, + }); + }); + + it('returns transaction hash from transaction relay', async () => { + isAtomicBatchSupportedMock.mockResolvedValueOnce([ + { + chainId: TRANSACTION_META_MOCK.chainId, + delegationAddress: UPGRADE_CONTRACT_ADDRESS_MOCK, + isSupported: true, + upgradeContractAddress: UPGRADE_CONTRACT_ADDRESS_MOCK, + }, + ]); + + const result = await hookClass.getHook()( + { + ...TRANSACTION_META_MOCK, + gasFeeTokens: [GAS_FEE_TOKEN_MOCK], + selectedGasFeeToken: GAS_FEE_TOKEN_MOCK.tokenAddress, + }, + SIGNED_TX_MOCK, + ); + + expect(result).toStrictEqual({ + transactionHash: TRANSCATION_HASH_MOCK, + }); + }); + + it('includes authorization list if not upgraded', async () => { + isAtomicBatchSupportedMock.mockResolvedValueOnce([ + { + chainId: TRANSACTION_META_MOCK.chainId, + delegationAddress: undefined, + isSupported: false, + upgradeContractAddress: UPGRADE_CONTRACT_ADDRESS_MOCK, + }, + ]); + + await hookClass.getHook()( + { + ...TRANSACTION_META_MOCK, + gasFeeTokens: [GAS_FEE_TOKEN_MOCK], + selectedGasFeeToken: GAS_FEE_TOKEN_MOCK.tokenAddress, + }, + SIGNED_TX_MOCK, + ); + + expect(submitRelayTransactionMock).toHaveBeenCalledTimes(1); + expect(submitRelayTransactionMock).toHaveBeenCalledWith( + expect.objectContaining({ + authorizationList: [ + { + address: UPGRADE_CONTRACT_ADDRESS_MOCK, + chainId: TRANSACTION_META_MOCK.chainId, + nonce: TRANSACTION_META_MOCK.txParams.nonce, + r: expect.any(String), + s: expect.any(String), + yParity: expect.any(String), + }, + ], + }), + ); + }); +}); diff --git a/app/scripts/lib/transaction/hooks/delegation-7702-publish.ts b/app/scripts/lib/transaction/hooks/delegation-7702-publish.ts new file mode 100644 index 000000000000..5ef1f19a666b --- /dev/null +++ b/app/scripts/lib/transaction/hooks/delegation-7702-publish.ts @@ -0,0 +1,309 @@ +import { + AuthorizationList, + GasFeeToken, + IsAtomicBatchSupportedRequest, + IsAtomicBatchSupportedResult, + PublishHook, + PublishHookResult, + TransactionMeta, + TransactionParams, +} from '@metamask/transaction-controller'; +import { Hex, add0x, createProjectLogger, remove0x } from '@metamask/utils'; +import { abiERC20 } from '@metamask/metamask-eth-abis'; +import { Interface } from '@ethersproject/abi'; +import { + ANY_BENEFICIARY, + Caveat, + Delegation, + Execution, + ExecutionMode, + ROOT_AUTHORITY, + UnsignedDelegation, + encodeRedeemDelegations, + signDelegation, +} from '../delegation'; +import { TransactionControllerInitMessenger } from '../../../controller-init/messengers/transaction-controller-messenger'; +import { + RelaySubmitRequest, + submitRelayTransaction, +} from '../transaction-relay'; + +const EMPTY_HEX = '0x'; + +const EMPTY_RESULT = { + transactionHash: undefined, +}; + +const log = createProjectLogger('delegation-7702-publish-hook'); + +export class Delegation7702PublishHook { + #isAtomicBatchSupported: ( + request: IsAtomicBatchSupportedRequest, + ) => Promise; + + #messenger: TransactionControllerInitMessenger; + + constructor({ + isAtomicBatchSupported, + messenger, + }: { + isAtomicBatchSupported: ( + request: IsAtomicBatchSupportedRequest, + ) => Promise; + messenger: TransactionControllerInitMessenger; + }) { + this.#isAtomicBatchSupported = isAtomicBatchSupported; + this.#messenger = messenger; + } + + getHook(): PublishHook { + return this.#hookWrapper.bind(this); + } + + async #hookWrapper( + transactionMeta: TransactionMeta, + _signedTx: string, + ): Promise { + try { + return await this.#hook(transactionMeta, _signedTx); + } catch (error) { + log('Error', error); + throw error; + } + } + + async #hook( + transactionMeta: TransactionMeta, + _signedTx: string, + ): Promise { + const { chainId, gasFeeTokens, selectedGasFeeToken, txParams } = + transactionMeta; + + const { from, maxFeePerGas, maxPriorityFeePerGas } = txParams; + + const atomicBatchSupport = await this.#isAtomicBatchSupported({ + address: from as Hex, + chainIds: [chainId], + }); + + const atomicBatchChainSupport = atomicBatchSupport.find( + (result) => result.chainId.toLowerCase() === chainId.toLowerCase(), + ); + + const isChainSupported = + atomicBatchChainSupport && + (!atomicBatchChainSupport.delegationAddress || + atomicBatchChainSupport.isSupported); + + if (!isChainSupported) { + log('Skipping as EIP-7702 is not supported', { from, chainId }); + return EMPTY_RESULT; + } + + const { delegationAddress, upgradeContractAddress } = + atomicBatchChainSupport; + + if (!selectedGasFeeToken || !gasFeeTokens?.length) { + log('Skipping as no selected gas fee token'); + return EMPTY_RESULT; + } + + const gasFeeToken = gasFeeTokens.find( + (token) => + token.tokenAddress.toLowerCase() === selectedGasFeeToken.toLowerCase(), + ); + + if (!gasFeeToken) { + throw new Error('Selected gas fee token not found'); + } + + const delegation = await this.#buildDelegation( + transactionMeta, + gasFeeToken, + ); + + const executions = this.#buildExecutions(transactionMeta, gasFeeToken); + + const transactionData = encodeRedeemDelegations( + [[delegation]], + [ExecutionMode.BATCH_DEFAULT_MODE], + [executions], + ); + + const relayRequest: RelaySubmitRequest = { + data: transactionData, + maxFeePerGas: maxFeePerGas as Hex, + maxPriorityFeePerGas: maxPriorityFeePerGas as Hex, + to: process.env.DELEGATION_MANAGER_ADDRESS as Hex, + }; + + if (!delegationAddress) { + relayRequest.authorizationList = await this.#buildAuthorizationList( + transactionMeta, + upgradeContractAddress, + ); + } + + log('Relay request', relayRequest); + + const { transactionHash } = await submitRelayTransaction(relayRequest); + + return { + transactionHash, + }; + } + + #buildExecutions( + transactionMeta: TransactionMeta, + gasFeeToken: GasFeeToken, + ): Execution[] { + const { txParams } = transactionMeta; + const { data, to, value } = txParams; + + const userExecution: Execution = { + target: to as Hex, + value: (value as Hex) ?? '0x0', + callData: (data as Hex) ?? EMPTY_HEX, + }; + + const transferExecution: Execution = { + target: gasFeeToken.tokenAddress, + value: '0x0', + callData: this.#buildTokenTransferData( + gasFeeToken.recipient, + gasFeeToken.amount, + ), + }; + + return [userExecution, transferExecution]; + } + + async #buildDelegation( + transactionMeta: TransactionMeta, + gasFeeToken: GasFeeToken, + ): Promise { + const { chainId, txParams } = transactionMeta; + const { from } = txParams; + + const caveats = this.#buildCaveats(txParams, gasFeeToken); + + log('Caveats', caveats); + + const delegation: UnsignedDelegation = { + authority: ROOT_AUTHORITY, + caveats, + delegate: ANY_BENEFICIARY, + delegator: from as Hex, + salt: new Date().getTime(), + }; + + log('Unsigned delegation', delegation); + + const signature = await signDelegation({ + chainId, + delegation, + from: from as Hex, + messenger: this.#messenger, + }); + + log('Delegation signature', signature); + + return { + ...delegation, + signature, + }; + } + + #buildCaveats( + txParams: TransactionParams, + gasFeeToken: GasFeeToken, + ): Caveat[] { + const { amount, recipient, tokenAddress } = gasFeeToken; + const { data, to } = txParams; + const tokenAmountPadded = add0x(remove0x(amount).padStart(64, '0')); + const enforcer = process.env.GASLESS_7702_ENFORCER_ADDRESS as Hex; + + const enforcerTerms = add0x( + ( + [ + tokenAddress, + recipient, + tokenAmountPadded, + to, + data ?? EMPTY_HEX, + ] as Hex[] + ) + .map(remove0x) + .join(''), + ); + + return [ + { + enforcer, + terms: enforcerTerms, + args: EMPTY_HEX, + }, + ]; + } + + async #buildAuthorizationList( + transactionMeta: TransactionMeta, + upgradeContractAddress?: Hex, + ): Promise { + const { chainId, txParams } = transactionMeta; + const { from, nonce } = txParams; + + log('Including authorization as not upgraded'); + + if (!upgradeContractAddress) { + throw new Error('Upgrade contract address not found'); + } + + const authorizationSignature = (await this.#messenger.call( + 'KeyringController:signEip7702Authorization', + { + chainId: parseInt(chainId, 16), + contractAddress: upgradeContractAddress, + from, + nonce: parseInt(nonce as string, 16), + }, + )) as Hex; + + const { r, s, yParity } = this.#decodeAuthorizationSignature( + authorizationSignature, + ); + + log('Authorization signature', { authorizationSignature, r, s, yParity }); + + return [ + { + address: upgradeContractAddress, + chainId, + nonce: nonce as Hex, + r, + s, + yParity, + }, + ]; + } + + #buildTokenTransferData(recipient: Hex, amount: Hex): Hex { + return new Interface(abiERC20).encodeFunctionData('transfer', [ + recipient, + amount, + ]) as Hex; + } + + #decodeAuthorizationSignature(signature: Hex) { + const r = signature.slice(0, 66) as Hex; + const s = `0x${signature.slice(66, 130)}` as Hex; + const v = parseInt(signature.slice(130, 132), 16); + const yParity = v - 27 === 0 ? ('0x' as const) : ('0x1' as const); + + return { + r, + s, + yParity, + }; + } +} diff --git a/app/scripts/lib/transaction/institutional-snap/InstitutionalSnapController.test.ts b/app/scripts/lib/transaction/institutional-snap/InstitutionalSnapController.test.ts new file mode 100644 index 000000000000..56425442fe78 --- /dev/null +++ b/app/scripts/lib/transaction/institutional-snap/InstitutionalSnapController.test.ts @@ -0,0 +1,233 @@ +import { Messenger } from '@metamask/base-controller'; +import { ORIGIN_METAMASK } from '@metamask/controller-utils'; +import { HandlerType } from '@metamask/snaps-utils'; +import { + TransactionStatus, + TransactionEnvelopeType, + TransactionMeta, +} from '@metamask/transaction-controller'; +import InstitutionalWalletSnap from '@metamask/institutional-wallet-snap/dist/preinstalled-snap.json'; +import { + InstitutionalSnapController, + InstitutionalSnapControllerMessenger, + AllowedActions, + InstitutionalSnapControllerPublishHookAction, + InstitutionalSnapControllerBeforeCheckPendingTransactionHookAction, +} from './InstitutionalSnapController'; + +describe('InstitutionalSnapController', () => { + let controller: InstitutionalSnapController; + let messenger: InstitutionalSnapControllerMessenger; + + const mockTransactionMeta: TransactionMeta = { + id: '123', + chainId: '0x1', + txParams: { + from: '0x123', + to: '0x456', + value: '0x1', + data: '0x', + }, + networkClientId: '1', + status: TransactionStatus.unapproved, + time: Date.now(), + }; + + const mockSnapResponse = { + keyringRequest: { + id: '123', + scope: 'scope', + account: '0x123', + request: { + method: 'method', + params: [ + { + chainId: '1', + nonce: '0x1', + maxPriorityFeePerGas: '0x1', + maxFeePerGas: '0x1', + gasLimit: '0x1', + to: '0x456', + value: '0x1', + data: '0x', + accessList: [], + from: '0x123', + type: '0x2', + }, + ], + }, + }, + type: 'type', + fulfilled: true, + rejected: false, + lastUpdated: 123456789, + transaction: { + custodianTransactionId: 'custodian-123', + transactionStatus: { + finished: true, + success: true, + displayText: 'Success', + submitted: true, + reason: '', + signed: true, + }, + from: '0x123', + custodianPublishesTransaction: true, + maxFeePerGas: '0x1', + maxPriorityFeePerGas: '0x1', + gasLimit: '0x1', + nonce: '0x1', + to: '0x456', + transactionHash: '0xhash', + type: '0x2', + }, + result: { + v: '0x1', + r: '0x2', + s: '0x3', + }, + }; + + beforeEach(() => { + const baseMessenger = new Messenger< + | AllowedActions + | InstitutionalSnapControllerPublishHookAction + | InstitutionalSnapControllerBeforeCheckPendingTransactionHookAction, + never + >(); + + messenger = baseMessenger.getRestricted({ + name: 'InstitutionalSnapController', + allowedActions: [ + 'SnapController:handleRequest', + 'AccountsController:getAccountByAddress', + 'TransactionController:updateCustodialTransaction', + ], + allowedEvents: [], + }) as InstitutionalSnapControllerMessenger; + + // Mock messenger calls + messenger.registerActionHandler = jest.fn(); + messenger.call = jest.fn().mockImplementation((method, ..._args) => { + switch (method) { + case 'SnapController:handleRequest': + return mockSnapResponse; + case 'AccountsController:getAccountByAddress': + return { + options: { + custodian: { + deferPublication: true, + }, + }, + }; + case 'TransactionController:updateCustodialTransaction': + return {}; + default: + return {}; + } + }); + + controller = new InstitutionalSnapController({ messenger }); + }); + + describe('constructor', () => { + it('should initialize correctly', () => { + expect(messenger.registerActionHandler).toHaveBeenCalledTimes(3); + expect(messenger.registerActionHandler).toHaveBeenCalledWith( + 'InstitutionalSnapController:getState', + expect.any(Function), + ); + expect(messenger.registerActionHandler).toHaveBeenCalledWith( + 'InstitutionalSnapController:publishHook', + expect.any(Function), + ); + + expect(messenger.registerActionHandler).toHaveBeenCalledWith( + 'InstitutionalSnapController:beforeCheckPendingTransactionHook', + expect.any(Function), + ); + }); + }); + + describe('deferPublicationHook', () => { + it('should handle deferred publication', async () => { + const result = await controller.deferPublicationHook(mockTransactionMeta); + + expect(result).toBe(false); + expect(messenger.call).toHaveBeenCalledWith( + 'SnapController:handleRequest', + expect.objectContaining({ + snapId: InstitutionalWalletSnap.snapId, + origin: ORIGIN_METAMASK, + handler: HandlerType.OnRpcRequest, + request: { + method: 'transactions.getMutableTransactionParameters', + params: expect.any(Object), + }, + }), + ); + + expect(messenger.call).toHaveBeenCalledWith( + 'TransactionController:updateCustodialTransaction', + expect.objectContaining({ + transactionId: mockTransactionMeta.id, + status: TransactionStatus.submitted, + hash: mockSnapResponse.transaction.transactionHash, + nonce: mockSnapResponse.transaction.nonce, + gasLimit: mockSnapResponse.transaction.gasLimit, + maxFeePerGas: mockSnapResponse.transaction.maxFeePerGas, + maxPriorityFeePerGas: + mockSnapResponse.transaction.maxPriorityFeePerGas, + type: mockSnapResponse.transaction.type as TransactionEnvelopeType, + }), + ); + }); + + it('should handle non-deferred publication', async () => { + messenger.call = jest.fn().mockImplementation((method) => { + if (method === 'AccountsController:getAccountByAddress') { + return { + options: { + custodian: { + deferPublication: false, + }, + }, + }; + } + return {}; + }); + + const result = await controller.deferPublicationHook(mockTransactionMeta); + expect(result).toBe(true); + }); + }); + + describe('beforeCheckPendingTransactionHook', () => { + it('should return false for deferred transactions', async () => { + const result = await controller.beforeCheckPendingTransactionHook( + mockTransactionMeta, + ); + expect(result).toBe(false); + }); + + it('should return true for non-deferred transactions', async () => { + messenger.call = jest.fn().mockImplementation((method) => { + if (method === 'AccountsController:getAccountByAddress') { + return { + options: { + custodian: { + deferPublication: false, + }, + }, + }; + } + return {}; + }); + + const result = await controller.beforeCheckPendingTransactionHook( + mockTransactionMeta, + ); + expect(result).toBe(true); + }); + }); +}); diff --git a/app/scripts/lib/transaction/institutional-snap/InstitutionalSnapController.ts b/app/scripts/lib/transaction/institutional-snap/InstitutionalSnapController.ts new file mode 100644 index 000000000000..6724d7230350 --- /dev/null +++ b/app/scripts/lib/transaction/institutional-snap/InstitutionalSnapController.ts @@ -0,0 +1,210 @@ +import { + TransactionControllerUpdateCustodialTransactionAction, + TransactionEnvelopeType, + TransactionMeta, + TransactionStatus, +} from '@metamask/transaction-controller'; +import type { HandleSnapRequest } from '@metamask/snaps-controllers'; +import { HandlerType } from '@metamask/snaps-utils'; +import { BaseController, RestrictedMessenger } from '@metamask/base-controller'; +import { AccountsControllerGetAccountByAddressAction } from '@metamask/accounts-controller'; +import { ORIGIN_METAMASK } from '@metamask/controller-utils'; +import { INSTITUTIONAL_WALLET_SNAP_ID } from '../../../../../shared/lib/accounts/institutional-wallet-snap'; +import { + InstitutionalSnapRequestSearchParameters, + InstitutionalSnapResponse, +} from './institutional-snap-controller.types'; + +const SNAP_ID = INSTITUTIONAL_WALLET_SNAP_ID; + +const controllerName = 'InstitutionalSnapController'; + +type SnapRPCRequest = Parameters[0]; + +export type AllowedActions = + | HandleSnapRequest + | AccountsControllerGetAccountByAddressAction + | TransactionControllerUpdateCustodialTransactionAction; + +export type InstitutionalSnapControllerPublishHookAction = { + type: `${typeof controllerName}:publishHook`; + handler: InstitutionalSnapController['deferPublicationHook']; +}; + +export type InstitutionalSnapControllerBeforeCheckPendingTransactionHookAction = + { + type: `${typeof controllerName}:beforeCheckPendingTransactionHook`; + handler: InstitutionalSnapController['beforeCheckPendingTransactionHook']; + }; + +type Actions = + | AllowedActions + | InstitutionalSnapControllerPublishHookAction + | InstitutionalSnapControllerBeforeCheckPendingTransactionHookAction; + +export type InstitutionalSnapControllerMessenger = RestrictedMessenger< + typeof controllerName, + Actions, + never, + Actions['type'], + never +>; + +type DeferrableTransactionAccount = { + options: { + custodian: { + deferPublication: boolean; + }; + }; +}; + +type InstitutionalSnapControllerControllerState = Record; + +const metadata = {}; + +export class InstitutionalSnapController extends BaseController< + 'InstitutionalSnapController', + InstitutionalSnapControllerControllerState, + InstitutionalSnapControllerMessenger +> { + constructor({ + messenger, + }: { + messenger: InstitutionalSnapControllerMessenger; + }) { + super({ + messenger, + name: controllerName, + state: {}, + metadata, + }); + + this.#registerMessageHandlers(); + } + + async deferPublicationHook( + transactionMeta: TransactionMeta, + ): Promise { + const shouldDefer = await this.#shouldDeferPublication(transactionMeta); + + if (shouldDefer) { + const updatedTransactionParameters = + await this.#getUpdatedTransactionParameters(transactionMeta); + + await this.#updateTransaction( + transactionMeta.id, + updatedTransactionParameters, + ); + return false; + } + + return true; + } + + async beforeCheckPendingTransactionHook( + transactionMeta: TransactionMeta, + ): Promise { + return !(await this.#shouldDeferPublication(transactionMeta)); + } + + #registerMessageHandlers() { + this.messagingSystem.registerActionHandler( + `${controllerName}:publishHook`, + this.deferPublicationHook.bind(this), + ); + + this.messagingSystem.registerActionHandler( + `${controllerName}:beforeCheckPendingTransactionHook`, + this.beforeCheckPendingTransactionHook.bind(this), + ); + } + + async #handleSnapRequest(args: SnapRPCRequest) { + const response = await this.messagingSystem.call( + 'SnapController:handleRequest', + args, + ); + return response as InstitutionalSnapResponse; + } + + async #getUpdatedTransactionParameters(transactionMeta: TransactionMeta) { + const searchParams: InstitutionalSnapRequestSearchParameters = { + from: transactionMeta.txParams.from as string, + to: transactionMeta.txParams.to as string, + value: transactionMeta.txParams.value as string, + data: transactionMeta.txParams.data as string, + chainId: transactionMeta.chainId as string, + }; + + const snapGetMutableTransactionParamsPayload: SnapRPCRequest = { + snapId: SNAP_ID, + origin: ORIGIN_METAMASK, + handler: HandlerType.OnRpcRequest, + request: { + method: 'transactions.getMutableTransactionParameters', + params: searchParams, + }, + }; + + const snapResponse = await this.#handleSnapRequest( + snapGetMutableTransactionParamsPayload, + ); + + const hash = snapResponse.transaction.transactionHash; + + return { + hash, + nonce: snapResponse.transaction.nonce, + gasLimit: snapResponse.transaction.gasLimit, + maxFeePerGas: snapResponse.transaction.maxFeePerGas, + maxPriorityFeePerGas: snapResponse.transaction.maxPriorityFeePerGas, + type: snapResponse.transaction.type as TransactionEnvelopeType, + status: TransactionStatus.submitted, + }; + } + + async #updateTransaction( + transactionId: string, + { + status, + hash, + nonce, + gasLimit, + maxFeePerGas, + maxPriorityFeePerGas, + type, + }: { + status: TransactionStatus; + hash: string; + nonce: string; + gasLimit: string; + maxFeePerGas: string; + maxPriorityFeePerGas: string; + type: TransactionEnvelopeType; + }, + ) { + const response = await this.messagingSystem.call( + 'TransactionController:updateCustodialTransaction', + { + transactionId, + status, + hash, + nonce, + gasLimit, + maxFeePerGas, + maxPriorityFeePerGas, + type, + }, + ); + return response; + } + + async #shouldDeferPublication(transactionMeta: TransactionMeta) { + const account = (await this.messagingSystem.call( + 'AccountsController:getAccountByAddress', + transactionMeta.txParams.from as string, + )) as unknown as DeferrableTransactionAccount; + + return account?.options.custodian?.deferPublication; + } +} diff --git a/app/scripts/lib/transaction/institutional-snap/institutional-snap-controller.types.ts b/app/scripts/lib/transaction/institutional-snap/institutional-snap-controller.types.ts new file mode 100644 index 000000000000..71205a8e5623 --- /dev/null +++ b/app/scripts/lib/transaction/institutional-snap/institutional-snap-controller.types.ts @@ -0,0 +1,64 @@ +// Response from the `transactions.getMutableTransactionParameters` method of the Institutional Snap +export type InstitutionalSnapResponse = { + keyringRequest: { + id: string; + scope: string; + account: string; + request: { + method: string; + params: [ + { + chainId: string; + nonce: string; + maxPriorityFeePerGas: string; + maxFeePerGas: string; + gasLimit: string; + to: string; + value: string; + data: string; + accessList: string[]; + from: string; + type: string; + }, + ]; + }; + }; + type: string; + fulfilled: boolean; + rejected: boolean; + lastUpdated: number; + transaction: { + custodianTransactionId: string; + transactionStatus: { + finished: boolean; + success: boolean; + displayText: string; + submitted: boolean; + reason: string; + signed: boolean; + }; + from: string; + custodianPublishesTransaction: boolean; + maxFeePerGas: string; + maxPriorityFeePerGas: string; + gasLimit: string; + nonce: string; + to: string; + transactionHash: string; + type: string; + }; + result: { + v: string; + r: string; + s: string; + }; +}; + +// Parameters for the `transactions.getMutableTransactionParameters` method of the Institutional Snap +export type InstitutionalSnapRequestSearchParameters = { + from: string; + to: string; + value: string; + data: string; + chainId: string; +}; diff --git a/app/scripts/lib/transaction/metrics.test.ts b/app/scripts/lib/transaction/metrics.test.ts index bcccad1ddf71..d7d9c01acad6 100644 --- a/app/scripts/lib/transaction/metrics.test.ts +++ b/app/scripts/lib/transaction/metrics.test.ts @@ -1261,218 +1261,208 @@ describe('Transaction metrics', () => { }); }); - ( + describe.each([ + ['if added', handleTransactionAdded], + ['if approved', handleTransactionApproved], + ['if dropped', handleTransactionDropped], + ['if failed', handleTransactionFailed], + ['if rejected', handleTransactionRejected], + ['if submitted', handleTransactionSubmitted], [ - ['if added', handleTransactionAdded], - ['if approved', handleTransactionApproved], - ['if dropped', handleTransactionDropped], - ['if failed', handleTransactionFailed], - ['if rejected', handleTransactionRejected], - ['if submitted', handleTransactionSubmitted], - [ - 'if confirmed', - (request: TransactionMetricsRequest, args: TransactionEventPayload) => - handleTransactionConfirmed( - request, - args.transactionMeta as TransactionMetaEventPayload, - ), - ], - ] as [ - string, - ( - request: TransactionMetricsRequest, - args: TransactionEventPayload, - ) => ReturnType, - ][] - ).forEach(([_title, fn]) => - describe(_title, () => { - it('includes batch properties', async () => { - const transactionMeta = { - ...mockTransactionMeta, - delegationAddress: ADDRESS_3_MOCK, - nestedTransactions: [ - { - to: ADDRESS_MOCK, - data: '0x1', - type: TransactionType.contractInteraction, - }, + 'if confirmed', + (request: TransactionMetricsRequest, args: TransactionEventPayload) => + handleTransactionConfirmed( + request, + args.transactionMeta as TransactionMetaEventPayload, + ), + ], + ])('%s', (_title, fn) => { + it('includes batch properties', async () => { + const transactionMeta = { + ...mockTransactionMeta, + delegationAddress: ADDRESS_3_MOCK, + nestedTransactions: [ + { + to: ADDRESS_MOCK, + data: '0x1', + type: TransactionType.contractInteraction, + }, + { + to: ADDRESS_2_MOCK, + data: '0x2', + type: TransactionType.contractInteraction, + }, + ], + txParams: { + ...mockTransactionMeta.txParams, + authorizationList: [ { - to: ADDRESS_2_MOCK, - data: '0x2', - type: TransactionType.contractInteraction, + address: ADDRESS_3_MOCK, }, ], - txParams: { - ...mockTransactionMeta.txParams, - authorizationList: [ - { - address: ADDRESS_3_MOCK, - }, - ], - }, - } as TransactionMeta; - - jest - .mocked(mockTransactionMetricsRequest.getMethodData) - .mockResolvedValueOnce({ - name: METHOD_NAME_MOCK, - }) - .mockResolvedValueOnce({ - name: METHOD_NAME_2_MOCK, - }); - - await fn(mockTransactionMetricsRequest, { - transactionMeta, + }, + } as TransactionMeta; + + jest + .mocked(mockTransactionMetricsRequest.getMethodData) + .mockResolvedValueOnce({ + name: METHOD_NAME_MOCK, + }) + .mockResolvedValueOnce({ + name: METHOD_NAME_2_MOCK, }); - const { properties, sensitiveProperties } = jest.mocked( - mockTransactionMetricsRequest.createEventFragment, - ).mock.calls[0][0]; - - expect(properties).toStrictEqual( - expect.objectContaining({ - api_method: MESSAGE_TYPE.WALLET_SEND_CALLS, - batch_transaction_count: 2, - batch_transaction_method: 'eip7702', - eip7702_upgrade_transaction: true, - transaction_contract_method: [METHOD_NAME_MOCK, METHOD_NAME_2_MOCK], - }), - ); - - expect(sensitiveProperties).toStrictEqual( - expect.objectContaining({ - account_eip7702_upgraded: ADDRESS_3_MOCK, - transaction_contract_address: [ADDRESS_MOCK, ADDRESS_2_MOCK], - }), - ); + await fn(mockTransactionMetricsRequest, { + transactionMeta, }); - it('includes gas_paid_with if selected gas fee token', async () => { - const transactionMeta = { - ...mockTransactionMeta, - gasFeeTokens: [GAS_FEE_TOKEN_MOCK], - selectedGasFeeToken: GAS_FEE_TOKEN_MOCK.tokenAddress, - } as TransactionMeta; + const { properties, sensitiveProperties } = jest.mocked( + mockTransactionMetricsRequest.createEventFragment, + ).mock.calls[0][0]; - await fn(mockTransactionMetricsRequest, { - transactionMeta, - }); + expect(properties).toStrictEqual( + expect.objectContaining({ + api_method: MESSAGE_TYPE.WALLET_SEND_CALLS, + batch_transaction_count: 2, + batch_transaction_method: 'eip7702', + eip7702_upgrade_transaction: true, + transaction_contract_method: [METHOD_NAME_MOCK, METHOD_NAME_2_MOCK], + }), + ); - const { properties } = jest.mocked( - mockTransactionMetricsRequest.createEventFragment, - ).mock.calls[0][0]; + expect(sensitiveProperties).toStrictEqual( + expect.objectContaining({ + account_eip7702_upgraded: ADDRESS_3_MOCK, + transaction_contract_address: [ADDRESS_MOCK, ADDRESS_2_MOCK], + }), + ); + }); - expect(properties).toStrictEqual( - expect.objectContaining({ - gas_paid_with: GAS_FEE_TOKEN_MOCK.symbol, - }), - ); + it('includes gas_paid_with if selected gas fee token', async () => { + const transactionMeta = { + ...mockTransactionMeta, + gasFeeTokens: [GAS_FEE_TOKEN_MOCK], + selectedGasFeeToken: GAS_FEE_TOKEN_MOCK.tokenAddress, + } as TransactionMeta; + + await fn(mockTransactionMetricsRequest, { + transactionMeta, }); - it('includes gas_payment_tokens_available if gas fee tokens', async () => { - const transactionMeta = { - ...mockTransactionMeta, - gasFeeTokens: [ - GAS_FEE_TOKEN_MOCK, - { ...GAS_FEE_TOKEN_MOCK, symbol: 'DAI' }, - ], - } as TransactionMeta; + const { properties } = jest.mocked( + mockTransactionMetricsRequest.createEventFragment, + ).mock.calls[0][0]; - await fn(mockTransactionMetricsRequest, { - transactionMeta, - }); + expect(properties).toStrictEqual( + expect.objectContaining({ + gas_paid_with: GAS_FEE_TOKEN_MOCK.symbol, + }), + ); + }); - const { properties } = jest.mocked( - mockTransactionMetricsRequest.createEventFragment, - ).mock.calls[0][0]; + it('includes gas_payment_tokens_available if gas fee tokens', async () => { + const transactionMeta = { + ...mockTransactionMeta, + gasFeeTokens: [ + GAS_FEE_TOKEN_MOCK, + { ...GAS_FEE_TOKEN_MOCK, symbol: 'DAI' }, + ], + } as TransactionMeta; - expect(properties).toStrictEqual( - expect.objectContaining({ - gas_payment_tokens_available: [GAS_FEE_TOKEN_MOCK.symbol, 'DAI'], - }), - ); + await fn(mockTransactionMetricsRequest, { + transactionMeta, }); - it('includes transasction_type as gas_payment', async () => { - const transactionMeta = { - ...mockTransactionMeta, - batchId: '0x123', - } as TransactionMeta; + const { properties } = jest.mocked( + mockTransactionMetricsRequest.createEventFragment, + ).mock.calls[0][0]; - await fn(mockTransactionMetricsRequest, { - transactionMeta, - }); + expect(properties).toStrictEqual( + expect.objectContaining({ + gas_payment_tokens_available: [GAS_FEE_TOKEN_MOCK.symbol, 'DAI'], + }), + ); + }); - const { properties } = jest.mocked( - mockTransactionMetricsRequest.createEventFragment, - ).mock.calls[0][0]; + it('includes transasction_type as gas_payment', async () => { + const transactionMeta = { + ...mockTransactionMeta, + batchId: '0x123', + } as TransactionMeta; - expect(properties).toStrictEqual( - expect.objectContaining({ - transaction_type: 'gas_payment', - }), - ); + await fn(mockTransactionMetricsRequest, { + transactionMeta, }); - it('includes gas_insufficient_native_asset as true if insufficient native balance', async () => { - const transactionMeta = { - ...mockTransactionMeta, - txParams: { - ...mockTransactionMeta.txParams, - gas: toHex(10), - maxFeePerGas: toHex(5), - value: toHex(3), - }, - } as TransactionMeta; + const { properties } = jest.mocked( + mockTransactionMetricsRequest.createEventFragment, + ).mock.calls[0][0]; - jest - .mocked(mockTransactionMetricsRequest.getAccountBalance) - .mockReturnValueOnce(toHex(52)); + expect(properties).toStrictEqual( + expect.objectContaining({ + transaction_type: 'gas_payment', + }), + ); + }); - await fn(mockTransactionMetricsRequest, { - transactionMeta, - }); + it('includes gas_insufficient_native_asset as true if insufficient native balance', async () => { + const transactionMeta = { + ...mockTransactionMeta, + txParams: { + ...mockTransactionMeta.txParams, + gas: toHex(10), + maxFeePerGas: toHex(5), + value: toHex(3), + }, + } as TransactionMeta; - const { properties } = jest.mocked( - mockTransactionMetricsRequest.createEventFragment, - ).mock.calls[0][0]; + jest + .mocked(mockTransactionMetricsRequest.getAccountBalance) + .mockReturnValueOnce(toHex(52)); - expect(properties).toStrictEqual( - expect.objectContaining({ - gas_insufficient_native_asset: true, - }), - ); + await fn(mockTransactionMetricsRequest, { + transactionMeta, }); - it('includes gas_insufficient_native_asset as false if sufficient native balance', async () => { - const transactionMeta = { - ...mockTransactionMeta, - txParams: { - ...mockTransactionMeta.txParams, - gas: toHex(10), - maxFeePerGas: toHex(5), - value: toHex(3), - }, - } as TransactionMeta; + const { properties } = jest.mocked( + mockTransactionMetricsRequest.createEventFragment, + ).mock.calls[0][0]; - jest - .mocked(mockTransactionMetricsRequest.getAccountBalance) - .mockReturnValueOnce(toHex(53)); + expect(properties).toStrictEqual( + expect.objectContaining({ + gas_insufficient_native_asset: true, + }), + ); + }); - await fn(mockTransactionMetricsRequest, { - transactionMeta, - }); + it('includes gas_insufficient_native_asset as false if sufficient native balance', async () => { + const transactionMeta = { + ...mockTransactionMeta, + txParams: { + ...mockTransactionMeta.txParams, + gas: toHex(10), + maxFeePerGas: toHex(5), + value: toHex(3), + }, + } as TransactionMeta; - const { properties } = jest.mocked( - mockTransactionMetricsRequest.createEventFragment, - ).mock.calls[0][0]; + jest + .mocked(mockTransactionMetricsRequest.getAccountBalance) + .mockReturnValueOnce(toHex(53)); - expect(properties).toStrictEqual( - expect.objectContaining({ - gas_insufficient_native_asset: false, - }), - ); + await fn(mockTransactionMetricsRequest, { + transactionMeta, }); - }), - ); + + const { properties } = jest.mocked( + mockTransactionMetricsRequest.createEventFragment, + ).mock.calls[0][0]; + + expect(properties).toStrictEqual( + expect.objectContaining({ + gas_insufficient_native_asset: false, + }), + ); + }); + }); }); diff --git a/app/scripts/lib/transaction/mmi-hooks.test.ts b/app/scripts/lib/transaction/mmi-hooks.test.ts deleted file mode 100644 index 45d0b83c2341..000000000000 --- a/app/scripts/lib/transaction/mmi-hooks.test.ts +++ /dev/null @@ -1,107 +0,0 @@ -import { TransactionStatus } from '@metamask/transaction-controller'; -import { - afterTransactionSign, - beforeCheckPendingTransaction, - beforeTransactionPublish, - getAdditionalSignArguments, -} from './mmi-hooks'; - -describe('MMI hooks', () => { - const fromMocked = '0xc684832530fcbddae4b4230a47e991ddcec2831d'; - const toMocked = '0xc684832530fcbddae4b4230a47e991ddcec2831d'; - const custodyIdMocked = '123'; - describe('afterTransactionSign', () => { - it('returns false if txMeta has no custodyStatus', () => { - // TODO: Replace `any` with type - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const txMeta = { to: toMocked } as any; - const signedEthTx = {}; - const result = afterTransactionSign(txMeta, signedEthTx, jest.fn()); - expect(result).toBe(true); - }); - - it('returns true if txMeta has custodyStatus', () => { - const txMeta = { - custodyStatus: TransactionStatus.approved, - custodyId: custodyIdMocked, - txParams: { from: fromMocked }, - // TODO: Replace `any` with type - // eslint-disable-next-line @typescript-eslint/no-explicit-any - } as any; - const signedEthTx = { - custodian_transactionId: custodyIdMocked, - transactionStatus: TransactionStatus.signed, - }; - const addTransactionToWatchList = jest.fn(); - const result = afterTransactionSign( - txMeta, - signedEthTx, - addTransactionToWatchList, - ); - expect(result).toBe(false); - expect(txMeta.custodyId).toBe(custodyIdMocked); - expect(txMeta.custodyStatus).toBe(TransactionStatus.signed); - expect(addTransactionToWatchList).toHaveBeenCalledWith( - custodyIdMocked, - fromMocked, - ); - }); - }); - - describe('beforeTransactionPublish', () => { - it('returns true if txMeta has custodyStatus', () => { - // TODO: Replace `any` with type - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const txMeta = { custodyStatus: TransactionStatus.approved } as any; - const result = beforeTransactionPublish(txMeta); - expect(result).toBe(false); - }); - - it('returns false if txMeta has no custodyStatus', () => { - // TODO: Replace `any` with type - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const txMeta = { to: toMocked } as any; - const result = beforeTransactionPublish(txMeta); - expect(result).toBe(true); - }); - }); - - describe('getAdditionalSignArguments', () => { - it('returns an array with txMeta when custodyStatus is truthy', () => { - // TODO: Replace `any` with type - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const txMeta = { custodyStatus: TransactionStatus.approved } as any; - const result = getAdditionalSignArguments(txMeta); - expect(result).toEqual([txMeta]); - }); - - it('returns an empty array when custodyStatus is falsy', () => { - // TODO: Replace `any` with type - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const txMeta = { to: toMocked } as any; - const result = getAdditionalSignArguments(txMeta); - expect(result).toEqual([]); - }); - }); - - describe('beforeCheckPendingTransaction', () => { - it('returns true if txMeta has custodyStatus', () => { - const txMeta = { - custodyStatus: TransactionStatus.approved, - custodyId: 1, - // TODO: Replace `any` with type - // eslint-disable-next-line @typescript-eslint/no-explicit-any - } as any; - const result = beforeCheckPendingTransaction(txMeta); - expect(result).toBe(false); - }); - - it('returns false if txMeta has no custodyStatus', () => { - // TODO: Replace `any` with type - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const txMeta = { to: toMocked } as any; - const result = beforeCheckPendingTransaction(txMeta); - expect(result).toBe(true); - }); - }); -}); diff --git a/app/scripts/lib/transaction/mmi-hooks.ts b/app/scripts/lib/transaction/mmi-hooks.ts deleted file mode 100644 index 1716fe738c04..000000000000 --- a/app/scripts/lib/transaction/mmi-hooks.ts +++ /dev/null @@ -1,65 +0,0 @@ -import { TransactionMeta } from '@metamask/transaction-controller'; - -/** - * Whether or not to skip publishing the transaction. - * - * @param txMeta - The transaction meta. - * @param signedEthTx - Signed Ethereum transaction. - * @param addTransactionToWatchList - */ -export function afterTransactionSign( - txMeta: TransactionMeta, - // TODO: Replace `any` with type - // eslint-disable-next-line @typescript-eslint/no-explicit-any - signedEthTx: any, - addTransactionToWatchList: ( - custodianTransactionId: string | undefined, - from?: string, - bufferType?: string, - isSignedMessage?: boolean, - ) => Promise, -): boolean { - // MMI does not broadcast transactions, as that is the responsibility of the custodian - if (!txMeta?.custodyStatus) { - return true; - } - - txMeta.custodyId = signedEthTx.custodian_transactionId; - txMeta.custodyStatus = signedEthTx.transactionStatus; - - addTransactionToWatchList(txMeta.custodyId, txMeta.txParams.from); - - return false; -} - -/** - * Whether or not should run logic before publishing the transaction. - * - * @param txMeta - The transaction meta. - */ -export function beforeTransactionPublish(txMeta: TransactionMeta): boolean { - // MMI does not broadcast transactions, as that is the responsibility of the custodian - return !txMeta?.custodyStatus; -} - -/** - * Gets additional sign arguments`. - * - * @param txMeta - The transaction meta. - */ -export function getAdditionalSignArguments( - txMeta: TransactionMeta, -): (TransactionMeta | undefined)[] { - return [txMeta.custodyStatus ? txMeta : undefined]; -} - -/** - * Whether or not should run the logic before checking the transaction when checking pending transactions. - * - * @param txMeta - The transaction meta. - */ -export function beforeCheckPendingTransaction( - txMeta: TransactionMeta, -): boolean { - return !txMeta?.custodyId; -} diff --git a/app/scripts/lib/transaction/smart-transactions.ts b/app/scripts/lib/transaction/smart-transactions.ts index 2afd0db930c8..379806dd4965 100644 --- a/app/scripts/lib/transaction/smart-transactions.ts +++ b/app/scripts/lib/transaction/smart-transactions.ts @@ -170,6 +170,7 @@ class SmartTransactionHook { getFeesResponse = await this.#smartTransactionsController.getFees( { ...this.#txParams, chainId: this.#chainId }, undefined, + { networkClientId: this.#transactionMeta.networkClientId }, ); } catch (error) { log.error( diff --git a/app/scripts/lib/transaction/transaction-relay.test.ts b/app/scripts/lib/transaction/transaction-relay.test.ts new file mode 100644 index 000000000000..78fcf1f3106f --- /dev/null +++ b/app/scripts/lib/transaction/transaction-relay.test.ts @@ -0,0 +1,64 @@ +import { + RelaySubmitRequest, + submitRelayTransaction, +} from './transaction-relay'; + +const URL_MOCK = 'test.com/test'; +const TRANSACTION_HASH_MOCK = '0x123'; +const ERROR_STATUS_MOCK = 500; +const ERROR_BODY_MOCK = 'test error'; + +const SUBMIT_REQUEST_MOCK: RelaySubmitRequest = { + data: '0x1', + maxFeePerGas: '0x2', + maxPriorityFeePerGas: '0x3', + to: '0x4', +}; + +describe('Transaction Relay Utils', () => { + let fetchMock: jest.Mock; + + beforeEach(() => { + jest.resetAllMocks(); + + process.env.TRANSACTION_RELAY_API_URL = URL_MOCK; + + fetchMock = jest.spyOn(global, 'fetch').mockReturnValue({ + json: () => Promise.resolve({ transactionHash: TRANSACTION_HASH_MOCK }), + ok: true, + }); + }); + + describe('submitRelayTransaction', () => { + it('submits request to API', async () => { + await submitRelayTransaction(SUBMIT_REQUEST_MOCK); + + expect(fetchMock).toHaveBeenCalledWith( + URL_MOCK, + expect.objectContaining({ + body: JSON.stringify(SUBMIT_REQUEST_MOCK), + }), + ); + }); + + it('returns transaction hash from response if successful', async () => { + const result = await submitRelayTransaction(SUBMIT_REQUEST_MOCK); + + expect(result).toStrictEqual({ + transactionHash: TRANSACTION_HASH_MOCK, + }); + }); + + it('throws if response status it not successful', async () => { + fetchMock.mockReturnValueOnce({ + ok: false, + status: ERROR_STATUS_MOCK, + text: () => Promise.resolve(ERROR_BODY_MOCK), + }); + + await expect(submitRelayTransaction(SUBMIT_REQUEST_MOCK)).rejects.toThrow( + `Transaction relay submit failed with status: ${ERROR_STATUS_MOCK} - ${ERROR_BODY_MOCK}`, + ); + }); + }); +}); diff --git a/app/scripts/lib/transaction/transaction-relay.ts b/app/scripts/lib/transaction/transaction-relay.ts new file mode 100644 index 000000000000..5eabe716b3aa --- /dev/null +++ b/app/scripts/lib/transaction/transaction-relay.ts @@ -0,0 +1,37 @@ +import { AuthorizationList } from '@metamask/transaction-controller'; +import { Hex } from '@metamask/utils'; + +export type RelaySubmitRequest = { + authorizationList?: AuthorizationList; + data: Hex; + maxFeePerGas: Hex; + maxPriorityFeePerGas: Hex; + to: Hex; +}; + +export type RelaySubmitResponse = { + transactionHash: Hex; +}; + +export async function submitRelayTransaction( + request: RelaySubmitRequest, +): Promise { + const baseUrl = process.env.TRANSACTION_RELAY_API_URL as string; + + const response = await fetch(baseUrl, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify(request), + }); + + if (!response.ok) { + const errorBody = await response.text(); + throw new Error( + `Transaction relay submit failed with status: ${response.status} - ${errorBody}`, + ); + } + + return await response.json(); +} diff --git a/app/scripts/lib/tx-verification/tx-verification-middleware.test.ts b/app/scripts/lib/tx-verification/tx-verification-middleware.test.ts index ea0aea6216d0..03b90463a71b 100644 --- a/app/scripts/lib/tx-verification/tx-verification-middleware.test.ts +++ b/app/scripts/lib/tx-verification/tx-verification-middleware.test.ts @@ -53,7 +53,6 @@ describe('tx verification middleware', () => { expect(end).not.toHaveBeenCalled(); }); - // @ts-expect-error Our test types are broken it.each([ ['null', null], ['string', 'foo'], @@ -75,29 +74,29 @@ describe('tx verification middleware', () => { 'non-"0x"-prefixed "chainId"', [{ data: 'data', from: 'from', to: 'to', value: 'value', chainId: '1' }], ], - ])( - 'ignores invalid params: %s', - (_: string, invalidParams: JsonRpcParams) => { - const middleware = createTxVerificationMiddleware( - getMockNetworkController(), - mockTrustedSigners, - ); + ])('ignores invalid params: %s', (_: string, invalidParams) => { + const middleware = createTxVerificationMiddleware( + getMockNetworkController(), + mockTrustedSigners, + ); - const { req, res, next, end } = getMiddlewareParams( - 'eth_sendTransaction', - invalidParams, - ); - middleware(req, res, next, end); + const { req, res, next, end } = getMiddlewareParams( + 'eth_sendTransaction', + invalidParams as JsonRpcParams, + ); + middleware(req, res, next, end); - expect(next).toHaveBeenCalledTimes(1); - expect(end).not.toHaveBeenCalled(); - }, - ); + expect(next).toHaveBeenCalledTimes(1); + expect(end).not.toHaveBeenCalled(); + }); - // @ts-expect-error Our test types are broken - it.each(Object.keys(FIRST_PARTY_CONTRACT_NAMES['MetaMask Bridge']))( + it.each( + Object.keys( + FIRST_PARTY_CONTRACT_NAMES[EXPERIENCES_TYPE.METAMASK_BRIDGE], + ) as Hex[], + )( 'ignores transactions that are not addressed to the bridge contract for chain %s', - (chainId: `0x${string}`) => { + (chainId) => { const middleware = createTxVerificationMiddleware( getMockNetworkController(), mockTrustedSigners, @@ -114,10 +113,9 @@ describe('tx verification middleware', () => { }, ); - // @ts-expect-error Our test types are broken - it.each(['0x11111', '0x111', '0x222222'])( + it.each(['0x11111', '0x111', '0x222222'] as Hex[])( 'ignores transactions that do not have a bridge contract deployed for chain %s', - (chainId: `0x${string}`) => { + (chainId) => { const middleware = createTxVerificationMiddleware( getMockNetworkController(), mockTrustedSigners, diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index 0ecd7babea5f..3d7f52caad5f 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -1,15 +1,10 @@ import EventEmitter from 'events'; import { finished, pipeline } from 'readable-stream'; import { - AssetsContractController, CurrencyRateController, - NftController, - NftDetectionController, TokenDetectionController, TokenListController, - TokenRatesController, TokensController, - CodefiTokenPricesServiceV2, RatesController, fetchMultiExchangeRate, TokenBalancesController, @@ -19,7 +14,15 @@ import { createEngineStream } from '@metamask/json-rpc-middleware-stream'; import { ObservableStore } from '@metamask/obs-store'; import { storeAsStream } from '@metamask/obs-store/dist/asStream'; import { providerAsMiddleware } from '@metamask/eth-json-rpc-middleware'; -import { debounce, throttle, memoize, wrap, pick, cloneDeep } from 'lodash'; +import { + debounce, + throttle, + memoize, + wrap, + pick, + cloneDeep, + uniq, +} from 'lodash'; import { KeyringController, KeyringTypes, @@ -77,6 +80,7 @@ import { import { LoggingController, LogType } from '@metamask/logging-controller'; import { PermissionLogController } from '@metamask/permission-log-controller'; +import { MultichainRouter } from '@metamask/snaps-controllers'; import { createSnapsMethodMiddleware, buildSnapEndowmentSpecifications, @@ -142,12 +146,27 @@ import { isSnapId } from '@metamask/snaps-utils'; import { Interface } from '@ethersproject/abi'; import { abiERC1155, abiERC721 } from '@metamask/metamask-eth-abis'; -import { isEvmAccountType } from '@metamask/keyring-api'; -import { hasProperty, hexToBigInt, toCaipChainId } from '@metamask/utils'; +import { isEvmAccountType, SolAccountType } from '@metamask/keyring-api'; +import { + hasProperty, + hexToBigInt, + toCaipChainId, + parseCaipAccountId, +} from '@metamask/utils'; import { normalize } from '@metamask/eth-sig-util'; import { TRIGGER_TYPES } from '@metamask/notification-services-controller/notification-services'; +import { + multichainMethodCallValidatorMiddleware, + MultichainSubscriptionManager, + MultichainMiddlewareManager, + walletGetSession, + walletRevokeSession, + walletInvokeMethod, + MultichainApiNotifications, +} from '@metamask/multichain-api-middleware'; + import { Caip25CaveatMutators, Caip25CaveatType, @@ -156,13 +175,10 @@ import { getSessionScopes, setPermittedEthChainIds, setEthAccounts, - multichainMethodCallValidatorMiddleware, - MultichainSubscriptionManager, - MultichainMiddlewareManager, - walletGetSession, - walletRevokeSession, - walletInvokeMethod, -} from '@metamask/multichain'; + getPermittedAccountsForScopes, + KnownSessionProperties, +} from '@metamask/chain-agnostic-permission'; + import { methodsRequiringNetworkSwitch, methodsThatCanSwitchNetworkWithoutApproval, @@ -173,7 +189,7 @@ import { import { toChecksumHexAddress } from '../../shared/modules/hexstring-utils'; ///: END:ONLY_INCLUDE_IF -import { AssetType, TokenStandard } from '../../shared/constants/transaction'; +import { TokenStandard } from '../../shared/constants/transaction'; import { GAS_API_BASE_URL, GAS_DEV_API_BASE_URL, @@ -245,8 +261,13 @@ import { getProviderConfig } from '../../shared/modules/selectors/networks'; import { endTrace, trace } from '../../shared/lib/trace'; import { ENVIRONMENT } from '../../development/build/constants'; import fetchWithCache from '../../shared/lib/fetch-with-cache'; +import { MultichainNetworks } from '../../shared/constants/multichain/networks'; import { BRIDGE_API_BASE_URL } from '../../shared/constants/bridge'; import { BridgeStatusAction } from '../../shared/types/bridge-status'; +///: BEGIN:ONLY_INCLUDE_IF(solana) +import { addDiscoveredSolanaAccounts } from '../../shared/lib/accounts'; +import { SOLANA_WALLET_SNAP_ID } from '../../shared/lib/accounts/solana-wallet-snap'; +///: END:ONLY_INCLUDE_IF import { ///: BEGIN:ONLY_INCLUDE_IF(build-mmi) handleMMITransactionUpdate, @@ -320,6 +341,8 @@ import { getRemovedAuthorizations, getChangedAuthorizations, getAuthorizedScopesByOrigin, + getPermittedAccountsForScopesByOrigin, + getOriginsWithSessionProperty, } from './controllers/permissions'; import { MetaMetricsDataDeletionController } from './controllers/metametrics-data-deletion/metametrics-data-deletion'; import { DataDeletionService } from './services/data-deletion-service'; @@ -365,6 +388,7 @@ import { handleBridgeTransactionFailed, handleTransactionFailedTypeBridge, } from './lib/bridge-status/metrics'; +import { InstitutionalSnapControllerInit } from './controller-init/institutional-snap/institutional-snap-controller-init'; import { ///: BEGIN:ONLY_INCLUDE_IF(multichain) MultichainAssetsControllerInit, @@ -374,6 +398,12 @@ import { ///: END:ONLY_INCLUDE_IF MultichainNetworkControllerInit, } from './controller-init/multichain'; +import { + AssetsContractControllerInit, + NftControllerInit, + NftDetectionControllerInit, + TokenRatesControllerInit, +} from './controller-init/assets'; import { TransactionControllerInit } from './controller-init/confirmations/transaction-controller-init'; import { PPOMControllerInit } from './controller-init/confirmations/ppom-controller-init'; import { initControllers } from './controller-init/utils'; @@ -729,25 +759,6 @@ export default class MetamaskController extends EventEmitter { state: initState.TokenListController, }); - const assetsContractControllerMessenger = - this.controllerMessenger.getRestricted({ - name: 'AssetsContractController', - allowedActions: [ - 'NetworkController:getNetworkClientById', - 'NetworkController:getNetworkConfigurationByNetworkClientId', - 'NetworkController:getSelectedNetworkClient', - 'NetworkController:getState', - ], - allowedEvents: [ - 'PreferencesController:stateChange', - 'NetworkController:networkDidChange', - ], - }); - this.assetsContractController = new AssetsContractController({ - messenger: assetsContractControllerMessenger, - chainId: this.#getGlobalChainId(), - }); - const tokensControllerMessenger = this.controllerMessenger.getRestricted({ name: 'TokensController', allowedActions: [ @@ -771,74 +782,6 @@ export default class MetamaskController extends EventEmitter { chainId: this.#getGlobalChainId(), }); - const nftControllerMessenger = this.controllerMessenger.getRestricted({ - name: 'NftController', - allowedEvents: [ - 'PreferencesController:stateChange', - 'NetworkController:networkDidChange', - 'AccountsController:selectedEvmAccountChange', - ], - allowedActions: [ - `${this.approvalController.name}:addRequest`, - `${this.networkController.name}:getNetworkClientById`, - 'AccountsController:getSelectedAccount', - 'AccountsController:getAccount', - 'AssetsContractController:getERC721AssetName', - 'AssetsContractController:getERC721AssetSymbol', - 'AssetsContractController:getERC721TokenURI', - 'AssetsContractController:getERC721OwnerOf', - 'AssetsContractController:getERC1155BalanceOf', - 'AssetsContractController:getERC1155TokenURI', - ], - }); - this.nftController = new NftController({ - state: initState.NftController, - messenger: nftControllerMessenger, - chainId: this.#getGlobalChainId(), - onNftAdded: ({ address, symbol, tokenId, standard, source }) => - this.metaMetricsController.trackEvent({ - event: MetaMetricsEventName.NftAdded, - category: MetaMetricsEventCategory.Wallet, - sensitiveProperties: { - token_contract_address: address, - token_symbol: symbol, - token_id: tokenId, - token_standard: standard, - asset_type: AssetType.NFT, - source, - }, - }), - }); - - const nftDetectionControllerMessenger = - this.controllerMessenger.getRestricted({ - name: 'NftDetectionController', - allowedEvents: [ - 'NetworkController:stateChange', - 'PreferencesController:stateChange', - ], - allowedActions: [ - 'ApprovalController:addRequest', - 'NetworkController:getState', - 'NetworkController:getNetworkClientById', - 'AccountsController:getSelectedAccount', - ], - }); - - this.nftDetectionController = new NftDetectionController({ - messenger: nftDetectionControllerMessenger, - chainId: this.#getGlobalChainId(), - getOpenSeaApiKey: () => this.nftController.openSeaApiKey, - getBalancesInSingleCall: - this.assetsContractController.getBalancesInSingleCall.bind( - this.assetsContractController, - ), - addNft: this.nftController.addNft.bind(this.nftController), - getNftState: () => this.nftController.state, - // added this to track previous value of useNftDetection, should be true on very first initializing of controller[] - disabled: !this.preferencesController.state.useNftDetection, - }); - const metaMetricsControllerMessenger = this.controllerMessenger.getRestricted({ name: 'MetaMetricsController', @@ -1036,31 +979,6 @@ export default class MetamaskController extends EventEmitter { fetchMultiExchangeRate, }); - const tokenRatesMessenger = this.controllerMessenger.getRestricted({ - name: 'TokenRatesController', - allowedActions: [ - 'TokensController:getState', - 'NetworkController:getNetworkClientById', - 'NetworkController:getState', - 'AccountsController:getAccount', - 'AccountsController:getSelectedAccount', - ], - allowedEvents: [ - 'NetworkController:stateChange', - 'AccountsController:selectedEvmAccountChange', - 'PreferencesController:stateChange', - 'TokensController:stateChange', - ], - }); - - // token exchange rate tracker - this.tokenRatesController = new TokenRatesController({ - state: initState.TokenRatesController, - messenger: tokenRatesMessenger, - tokenPricesService: new CodefiTokenPricesServiceV2(), - disabled: !this.preferencesController.state.useCurrencyRateCheck, - }); - this.controllerMessenger.subscribe( 'PreferencesController:stateChange', previousValueComparator((prevState, currState) => { @@ -1254,6 +1172,14 @@ export default class MetamaskController extends EventEmitter { this.networkController.findNetworkClientIdByChainId.bind( this.networkController, ), + isNonEvmScopeSupported: this.controllerMessenger.call.bind( + this.controllerMessenger, + 'MultichainRouter:isSupportedScope', + ), + getNonEvmAccountAddresses: this.controllerMessenger.call.bind( + this.controllerMessenger, + 'MultichainRouter:getSupportedAccounts', + ), }), permissionSpecifications: { ...getPermissionSpecifications(), @@ -1306,6 +1232,32 @@ export default class MetamaskController extends EventEmitter { subjectCacheLimit: 100, }); + // @TODO(snaps): This fixes an issue where `withKeyring` would lock the `KeyringController` mutex. + // That meant that if a snap requested a keyring operation (like requesting entropy) while the `KeyringController` was locked, + // it would cause a deadlock. + // This is a temporary fix until we can refactor how we handle requests to the Snaps Keyring. + const withSnapKeyring = async (operation) => { + const keyring = await this.getSnapKeyring(); + + return operation({ keyring }); + }; + + const multichainRouterMessenger = this.controllerMessenger.getRestricted({ + name: 'MultichainRouter', + allowedActions: [ + `SnapController:getAll`, + `SnapController:handleRequest`, + `${this.permissionController.name}:getPermissions`, + `AccountsController:listMultichainAccounts`, + ], + allowedEvents: [], + }); + + this.multichainRouter = new MultichainRouter({ + messenger: multichainRouterMessenger, + withSnapKeyring, + }); + // account tracker watches balances, nonces, and any code at their address this.accountTrackerController = new AccountTrackerController({ state: { accounts: {} }, @@ -1354,6 +1306,9 @@ export default class MetamaskController extends EventEmitter { if (!prevCompletedOnboarding && currCompletedOnboarding) { const { address } = this.accountsController.getSelectedAccount(); + ///: BEGIN:ONLY_INCLUDE_IF(solana) + await this._addSolanaAccount(); + ///: END:ONLY_INCLUDE_IF await this._addAccountsWithBalance(); this.postOnboardingInitialization(); @@ -1394,10 +1349,8 @@ export default class MetamaskController extends EventEmitter { this.tokenDetectionController = new TokenDetectionController({ messenger: tokenDetectionControllerMessenger, - getBalancesInSingleCall: - this.assetsContractController.getBalancesInSingleCall.bind( - this.assetsContractController, - ), + getBalancesInSingleCall: (...args) => + this.assetsContractController.getBalancesInSingleCall(...args), trackMetaMetricsEvent: this.metaMetricsController.trackEvent.bind( this.metaMetricsController, ), @@ -1901,6 +1854,7 @@ export default class MetamaskController extends EventEmitter { /** @type {import('./controller-init/utils').InitFunctions} */ const controllerInitFunctions = { ExecutionService: ExecutionServiceInit, + InstitutionalSnapController: InstitutionalSnapControllerInit, RateLimitController: RateLimitControllerInit, SnapsRegistry: SnapsRegistryInit, SnapController: SnapControllerInit, @@ -1909,6 +1863,10 @@ export default class MetamaskController extends EventEmitter { CronjobController: CronjobControllerInit, PPOMController: PPOMControllerInit, TransactionController: TransactionControllerInit, + NftController: NftControllerInit, + AssetsContractController: AssetsContractControllerInit, + NftDetectionController: NftDetectionControllerInit, + TokenRatesController: TokenRatesControllerInit, ///: BEGIN:ONLY_INCLUDE_IF(multichain) MultichainAssetsController: MultichainAssetsControllerInit, MultichainAssetsRatesController: MultichainAssetsRatesControllerInit, @@ -1948,6 +1906,9 @@ export default class MetamaskController extends EventEmitter { this.snapsRegistry = controllersByName.SnapsRegistry; this.ppomController = controllersByName.PPOMController; this.txController = controllersByName.TransactionController; + this.nftController = controllersByName.NftController; + this.nftDetectionController = controllersByName.NftDetectionController; + this.assetsContractController = controllersByName.AssetsContractController; ///: BEGIN:ONLY_INCLUDE_IF(multichain) this.multichainAssetsController = controllersByName.MultichainAssetsController; @@ -1958,6 +1919,7 @@ export default class MetamaskController extends EventEmitter { this.multichainAssetsRatesController = controllersByName.MultichainAssetsRatesController; ///: END:ONLY_INCLUDE_IF + this.tokenRatesController = controllersByName.TokenRatesController; this.multichainNetworkController = controllersByName.MultichainNetworkController; this.authenticationController = controllersByName.AuthenticationController; @@ -2104,6 +2066,9 @@ export default class MetamaskController extends EventEmitter { this.preferencesController.getDisabledAccountUpgradeChains.bind( this.preferencesController, ), + getDismissSmartAccountSuggestionEnabled: () => + this.preferencesController.state.preferences + .dismissSmartAccountSuggestionEnabled, isAtomicBatchSupported: this.txController.isAtomicBatchSupported.bind( this.txController, ), @@ -2125,6 +2090,9 @@ export default class MetamaskController extends EventEmitter { this.preferencesController.getDisabledAccountUpgradeChains.bind( this.preferencesController, ), + getDismissSmartAccountSuggestionEnabled: () => + this.preferencesController.state.preferences + .dismissSmartAccountSuggestionEnabled, isAtomicBatchSupported: this.txController.isAtomicBatchSupported.bind( this.txController, ), @@ -2211,6 +2179,7 @@ export default class MetamaskController extends EventEmitter { MultichainTransactionsController: this.multichainTransactionsController, MultichainAssetsRatesController: this.multichainAssetsRatesController, ///: END:ONLY_INCLUDE_IF + TokenRatesController: this.tokenRatesController, MultichainNetworkController: this.multichainNetworkController, NetworkController: this.networkController, KeyringController: this.keyringController, @@ -2729,6 +2698,20 @@ export default class MetamaskController extends EventEmitter { */ setupControllerEventSubscriptions() { let lastSelectedAddress; + let lastSelectedSolanaAccountAddress; + + if (process.env.MULTICHAIN_API) { + // this throws if there is no solana account... perhaps we should handle this better at the controller level + try { + lastSelectedSolanaAccountAddress = + this.accountsController.getSelectedMultichainAccount( + MultichainNetworks.SOLANA, + )?.address; + } catch { + // noop + } + } + this.controllerMessenger.subscribe( 'PreferencesController:stateChange', previousValueComparator(async (prevState, currState) => { @@ -2767,6 +2750,7 @@ export default class MetamaskController extends EventEmitter { // This handles CAIP-25 authorization changes every time relevant permission state // changes, for any reason. if (process.env.MULTICHAIN_API) { + // wallet_sessionChanged and eth_subscription setup/teardown this.controllerMessenger.subscribe( `${this.permissionController.name}:stateChange`, async (currentValue, previousValue) => { @@ -2785,7 +2769,10 @@ export default class MetamaskController extends EventEmitter { origin, authorization, ] of removedAuthorizations.entries()) { - const sessionScopes = getSessionScopes(authorization); + const sessionScopes = getSessionScopes(authorization, { + getNonEvmSupportedMethods: + this.getNonEvmSupportedMethods.bind(this), + }); // if the eth_subscription notification is in the scope and eth_subscribe is in the methods // then remove middleware and unsubscribe Object.entries(sessionScopes).forEach(([scope, scopeObject]) => { @@ -2806,7 +2793,10 @@ export default class MetamaskController extends EventEmitter { origin, authorization, ] of changedAuthorizations.entries()) { - const sessionScopes = getSessionScopes(authorization); + const sessionScopes = getSessionScopes(authorization, { + getNonEvmSupportedMethods: + this.getNonEvmSupportedMethods.bind(this), + }); // if the eth_subscription notification is in the scope and eth_subscribe is in the methods // then get the subscriptionManager going for that scope @@ -2830,12 +2820,142 @@ export default class MetamaskController extends EventEmitter { }); } }); - this._notifyAuthorizationChange(origin, authorization); } }, getAuthorizedScopesByOrigin, ); + + // wallet_notify for solana accountChanged when permission changes + this.controllerMessenger.subscribe( + `${this.permissionController.name}:stateChange`, + async (currentValue, previousValue) => { + const origins = uniq([ + ...previousValue.keys(), + ...currentValue.keys(), + ]); + origins.forEach((origin) => { + const previousCaveatValue = previousValue.get(origin); + const currentCaveatValue = currentValue.get(origin); + + const previousSolanaAccountChangedNotificationsEnabled = Boolean( + previousCaveatValue?.sessionProperties?.[ + KnownSessionProperties.SolanaAccountChangedNotifications + ], + ); + const currentSolanaAccountChangedNotificationsEnabled = Boolean( + currentCaveatValue?.sessionProperties?.[ + KnownSessionProperties.SolanaAccountChangedNotifications + ], + ); + + if ( + !previousSolanaAccountChangedNotificationsEnabled && + !currentSolanaAccountChangedNotificationsEnabled + ) { + return; + } + + const previousSolanaCaipAccountIds = previousCaveatValue + ? getPermittedAccountsForScopes(previousCaveatValue, [ + MultichainNetworks.SOLANA, + MultichainNetworks.SOLANA_DEVNET, + MultichainNetworks.SOLANA_TESTNET, + ]) + : []; + const previousNonUniqueSolanaHexAccountAddresses = + previousSolanaCaipAccountIds.map((caipAccountId) => { + const { address } = parseCaipAccountId(caipAccountId); + return address; + }); + const previousSolanaHexAccountAddresses = uniq( + previousNonUniqueSolanaHexAccountAddresses, + ); + const [previousSelectedSolanaAccountAddress] = + this.sortMultichainAccountsByLastSelected( + previousSolanaHexAccountAddresses, + ); + + const currentSolanaCaipAccountIds = currentCaveatValue + ? getPermittedAccountsForScopes(currentCaveatValue, [ + MultichainNetworks.SOLANA, + MultichainNetworks.SOLANA_DEVNET, + MultichainNetworks.SOLANA_TESTNET, + ]) + : []; + const currentNonUniqueSolanaHexAccountAddresses = + currentSolanaCaipAccountIds.map((caipAccountId) => { + const { address } = parseCaipAccountId(caipAccountId); + return address; + }); + const currentSolanaHexAccountAddresses = uniq( + currentNonUniqueSolanaHexAccountAddresses, + ); + const [currentSelectedSolanaAccountAddress] = + this.sortMultichainAccountsByLastSelected( + currentSolanaHexAccountAddresses, + ); + + if ( + previousSelectedSolanaAccountAddress !== + currentSelectedSolanaAccountAddress + ) { + this._notifySolanaAccountChange( + origin, + currentSelectedSolanaAccountAddress + ? [currentSelectedSolanaAccountAddress] + : [], + ); + } + }); + }, + getAuthorizedScopesByOrigin, + ); + + // wallet_notify for solana accountChanged when selected account changes + this.controllerMessenger.subscribe( + `${this.accountsController.name}:selectedAccountChange`, + async (account) => { + if ( + account.type === SolAccountType.DataAccount && + account.address !== lastSelectedSolanaAccountAddress + ) { + lastSelectedSolanaAccountAddress = account.address; + + const originsWithSolanaAccountChangedNotifications = + getOriginsWithSessionProperty( + this.permissionController.state, + KnownSessionProperties.SolanaAccountChangedNotifications, + ); + + // returns a map of origins to permitted solana accounts + const solanaAccounts = getPermittedAccountsForScopesByOrigin( + this.permissionController.state, + [ + MultichainNetworks.SOLANA, + MultichainNetworks.SOLANA_DEVNET, + MultichainNetworks.SOLANA_TESTNET, + ], + ); + + if (solanaAccounts.size > 0) { + for (const [origin, accounts] of solanaAccounts.entries()) { + const parsedSolanaAddresses = accounts.map((caipAccountId) => { + const { address } = parseCaipAccountId(caipAccountId); + return address; + }); + + if ( + parsedSolanaAddresses.includes(account.address) && + originsWithSolanaAccountChangedNotifications[origin] + ) { + this._notifySolanaAccountChange(origin, [account.address]); + } + } + } + } + }, + ); } this.controllerMessenger.subscribe( @@ -2890,14 +3010,7 @@ export default class MetamaskController extends EventEmitter { this.controllerMessenger.subscribe( 'NetworkController:networkDidChange', async () => { - const filteredChainIds = this.#getAllAddedNetworks().filter( - (networkId) => - this.preferencesController.state.incomingTransactionsPreferences[ - networkId - ], - ); - - if (filteredChainIds.length > 0) { + if (this.preferencesController.state.useExternalServices === true) { this.txController.stopIncomingTransactionPolling(); await this.txController.updateIncomingTransactions(); @@ -3275,6 +3388,7 @@ export default class MetamaskController extends EventEmitter { gasFeeController, metaMetricsController, networkController, + multichainNetworkController, announcementController, onboardingController, permissionController, @@ -3282,7 +3396,6 @@ export default class MetamaskController extends EventEmitter { tokensController, smartTransactionsController, txController, - assetsContractController, backup, approvalController, phishingController, @@ -3402,10 +3515,6 @@ export default class MetamaskController extends EventEmitter { setCurrentLocale: preferencesController.setCurrentLocale.bind( preferencesController, ), - setIncomingTransactionsPreferences: - preferencesController.setIncomingTransactionsPreferences.bind( - preferencesController, - ), setServiceWorkerKeepAlivePreference: preferencesController.setServiceWorkerKeepAlivePreference.bind( preferencesController, @@ -3536,6 +3645,11 @@ export default class MetamaskController extends EventEmitter { ), ///: END:ONLY_INCLUDE_IF + setManageInstitutionalWallets: + preferencesController.setManageInstitutionalWallets.bind( + preferencesController, + ), + // AccountsController setSelectedInternalAccount: (id) => { const account = this.accountsController.getAccount(id); @@ -3558,6 +3672,8 @@ export default class MetamaskController extends EventEmitter { // AssetsContractController getTokenStandardAndDetails: this.getTokenStandardAndDetails.bind(this), getTokenSymbol: this.getTokenSymbol.bind(this), + getTokenStandardAndDetailsByChain: + this.getTokenStandardAndDetailsByChain.bind(this), // NftController addNft: nftController.addNft.bind(nftController), @@ -3675,11 +3791,9 @@ export default class MetamaskController extends EventEmitter { setLocked: this.setLocked.bind(this), createNewVaultAndKeychain: this.createNewVaultAndKeychain.bind(this), createNewVaultAndRestore: this.createNewVaultAndRestore.bind(this), - ///: BEGIN:ONLY_INCLUDE_IF(multi-srp) generateNewMnemonicAndAddToVault: this.generateNewMnemonicAndAddToVault.bind(this), importMnemonicToVault: this.importMnemonicToVault.bind(this), - ///: END:ONLY_INCLUDE_IF exportAccount: this.exportAccount.bind(this), // txController @@ -3763,6 +3877,9 @@ export default class MetamaskController extends EventEmitter { ...getPermissionBackgroundApiMethods({ permissionController, approvalController, + accountsController, + networkController, + multichainNetworkController, }), ///: BEGIN:ONLY_INCLUDE_IF(build-mmi) @@ -4132,10 +4249,8 @@ export default class MetamaskController extends EventEmitter { tokensController.addDetectedTokens.bind(tokensController), addImportedTokens: tokensController.addTokens.bind(tokensController), ignoreTokens: tokensController.ignoreTokens.bind(tokensController), - getBalancesInSingleCall: - assetsContractController.getBalancesInSingleCall.bind( - assetsContractController, - ), + getBalancesInSingleCall: (...args) => + this.assetsContractController.getBalancesInSingleCall(...args), // Authentication Controller performSignIn: authenticationController.performSignIn.bind( @@ -4228,6 +4343,17 @@ export default class MetamaskController extends EventEmitter { ), setName: this.nameController.setName.bind(this.nameController), + ///: BEGIN:ONLY_INCLUDE_IF(keyring-snaps) + // SnapKeyring + createSnapAccount: async (snapId, options, internalOptions) => { + // NOTE: We should probably start using `withKeyring` with `createIfMissing: true` + // in this case. + const keyring = await this.getSnapKeyring(); + + return await keyring.createAccount(snapId, options, internalOptions); + }, + ///: END:ONLY_INCLUDE_IF + ///: BEGIN:ONLY_INCLUDE_IF(multichain) // MultichainBalancesController multichainUpdateBalance: (accountId) => @@ -4284,7 +4410,7 @@ export default class MetamaskController extends EventEmitter { const staticTokenListDetails = STATIC_MAINNET_TOKEN_LIST[address?.toLowerCase()] || {}; - const tokenListDetails = tokenList[address.toLowerCase()] || {}; + const tokenListDetails = tokenList[address?.toLowerCase()] || {}; const userDefinedTokenDetails = tokens.find(({ address: _address }) => isEqualCaseInsensitive(_address, address), @@ -4296,19 +4422,23 @@ export default class MetamaskController extends EventEmitter { ...userDefinedTokenDetails, }; + // boolean to check if the token is an ERC20 const tokenDetailsStandardIsERC20 = isEqualCaseInsensitive(tokenDetails.standard, TokenStandard.ERC20) || tokenDetails.erc20 === true; + // boolean to check if the token is an NFT const noEvidenceThatTokenIsAnNFT = !tokenId && !isEqualCaseInsensitive(tokenDetails.standard, TokenStandard.ERC1155) && !isEqualCaseInsensitive(tokenDetails.standard, TokenStandard.ERC721) && !tokenDetails.erc721; + // boolean to check if the token is an ERC20 like const otherDetailsAreERC20Like = tokenDetails.decimals !== undefined && tokenDetails.symbol; + // boolean to check if the token can be treated as an ERC20 const tokenCanBeTreatedAsAnERC20 = tokenDetailsStandardIsERC20 || (noEvidenceThatTokenIsAnNFT && otherDetailsAreERC20Like); @@ -4388,6 +4518,141 @@ export default class MetamaskController extends EventEmitter { }; } + async getTokenStandardAndDetailsByChain( + address, + userAddress, + tokenId, + chainId, + ) { + const { tokensChainsCache } = this.tokenListController.state; + const tokenList = tokensChainsCache?.[chainId]?.data || {}; + const { tokens } = this.tokensController.state; + + let staticTokenListDetails = {}; + if (chainId === CHAIN_IDS.MAINNET) { + staticTokenListDetails = + STATIC_MAINNET_TOKEN_LIST[address?.toLowerCase()] || {}; + } + + const tokenListDetails = tokenList[address?.toLowerCase()] || {}; + const userDefinedTokenDetails = + tokens.find(({ address: _address }) => + isEqualCaseInsensitive(_address, address), + ) || {}; + const tokenDetails = { + ...staticTokenListDetails, + ...tokenListDetails, + ...userDefinedTokenDetails, + }; + + const tokenDetailsStandardIsERC20 = + isEqualCaseInsensitive(tokenDetails.standard, TokenStandard.ERC20) || + tokenDetails.erc20 === true; + + const noEvidenceThatTokenIsAnNFT = + !tokenId && + !isEqualCaseInsensitive(tokenDetails.standard, TokenStandard.ERC1155) && + !isEqualCaseInsensitive(tokenDetails.standard, TokenStandard.ERC721) && + !tokenDetails.erc721; + + const otherDetailsAreERC20Like = + tokenDetails.decimals !== undefined && tokenDetails.symbol; + + // boolean to check if the token can be treated as an ERC20 + const tokenCanBeTreatedAsAnERC20 = + tokenDetailsStandardIsERC20 || + (noEvidenceThatTokenIsAnNFT && otherDetailsAreERC20Like); + + let details; + if (tokenCanBeTreatedAsAnERC20) { + try { + let balance = 0; + if (this.#getGlobalChainId() === chainId) { + balance = await fetchTokenBalance( + address, + userAddress, + this.provider, + ); + } + + details = { + address, + balance, + standard: TokenStandard.ERC20, + decimals: tokenDetails.decimals, + symbol: tokenDetails.symbol, + }; + } catch (e) { + // If the `fetchTokenBalance` call failed, `details` remains undefined, and we + // fall back to the below `assetsContractController.getTokenStandardAndDetails` call + log.warn(`Failed to get token balance. Error: ${e}`); + } + } + + // `details`` will be undefined if `tokenCanBeTreatedAsAnERC20`` is false, + // or if it is true but the `fetchTokenBalance`` call failed. In either case, we should + // attempt to retrieve details from `assetsContractController.getTokenStandardAndDetails` + if (details === undefined) { + try { + const networkClientId = + this.networkController?.state?.networkConfigurationsByChainId?.[ + chainId + ]?.rpcEndpoints[ + this.networkController?.state?.networkConfigurationsByChainId?.[ + chainId + ]?.defaultRpcEndpointIndex + ]?.networkClientId; + + details = + await this.assetsContractController.getTokenStandardAndDetails( + address, + userAddress, + tokenId, + networkClientId, + ); + } catch (e) { + log.warn(`Failed to get token standard and details. Error: ${e}`); + } + } + + if (details) { + const tokenDetailsStandardIsERC1155 = isEqualCaseInsensitive( + details.standard, + TokenStandard.ERC1155, + ); + + if (tokenDetailsStandardIsERC1155) { + try { + const balance = await fetchERC1155Balance( + address, + userAddress, + tokenId, + this.provider, + ); + + const balanceToUse = balance?._hex + ? parseInt(balance._hex, 16).toString() + : null; + + details = { + ...details, + balance: balanceToUse, + }; + } catch (e) { + // If the `fetchTokenBalance` call failed, `details` remains undefined, and we + // fall back to the below `assetsContractController.getTokenStandardAndDetails` call + log.warn('Failed to get token balance. Error:', e); + } + } + } + + return { + ...details, + decimals: details?.decimals?.toString(10), + balance: details?.balance?.toString(10), + }; + } + async getTokenSymbol(address) { try { const details = @@ -4430,7 +4695,6 @@ export default class MetamaskController extends EventEmitter { * @param {string} mnemonic * @returns {object} new account address */ - ///: BEGIN:ONLY_INCLUDE_IF(multi-srp) async importMnemonicToVault(mnemonic) { const releaseLock = await this.createVaultMutex.acquire(); try { @@ -4467,6 +4731,9 @@ export default class MetamaskController extends EventEmitter { this.accountsController.getAccountByAddress(newAccountAddress); this.accountsController.setSelectedAccount(account.id); + ///: BEGIN:ONLY_INCLUDE_IF(solana) + await this._addSolanaAccount(id); + ///: END:ONLY_INCLUDE_IF await this._addAccountsWithBalance(id); return newAccountAddress; @@ -4505,7 +4772,6 @@ export default class MetamaskController extends EventEmitter { releaseLock(); } } - ///: END:ONLY_INCLUDE_IF /** * Create a new Vault and restore an existent keyring. @@ -4543,6 +4809,9 @@ export default class MetamaskController extends EventEmitter { ); if (completedOnboarding) { + ///: BEGIN:ONLY_INCLUDE_IF(solana) + await this._addSolanaAccount(); + ///: END:ONLY_INCLUDE_IF await this._addAccountsWithBalance(); // This must be set as soon as possible to communicate to the @@ -4568,10 +4837,26 @@ export default class MetamaskController extends EventEmitter { ? { id: keyringId } : { type: KeyringTypes.hd }; - const accounts = await this.keyringController.withKeyring( + const { + accounts, + ///: BEGIN:ONLY_INCLUDE_IF(solana) + entropySource, + ///: END:ONLY_INCLUDE_IF + } = await this.keyringController.withKeyring( keyringSelector, - async ({ keyring }) => { - return await keyring.getAccounts(); + async ({ + keyring, + ///: BEGIN:ONLY_INCLUDE_IF(solana) + metadata, + ///: END:ONLY_INCLUDE_IF + }) => { + const keyringAccounts = await keyring.getAccounts(); + return { + accounts: keyringAccounts, + ///: BEGIN:ONLY_INCLUDE_IF(solana) + entropySource: metadata.id, + ///: END:ONLY_INCLUDE_IF + }; }, ); let address = accounts[accounts.length - 1]; @@ -4612,6 +4897,14 @@ export default class MetamaskController extends EventEmitter { }, ); } + ///: BEGIN:ONLY_INCLUDE_IF(solana) + const keyring = await this.getSnapKeyring(); + await addDiscoveredSolanaAccounts( + this.controllerMessenger, + entropySource, + keyring, + ); + ///: END:ONLY_INCLUDE_IF } catch (e) { log.warn(`Failed to add accounts with balance. Error: ${e}`); } finally { @@ -4621,6 +4914,40 @@ export default class MetamaskController extends EventEmitter { } } + /** + * Adds Solana account to the keyring. + * + * @param {string} keyringId - The ID of the keyring to add the account to. + */ + ///: BEGIN:ONLY_INCLUDE_IF(solana) + async _addSolanaAccount(keyringId) { + const snapId = SOLANA_WALLET_SNAP_ID; + let entropySource = keyringId; + if (!entropySource) { + // Get the entropy source from the first HD keyring + const id = await this.keyringController.withKeyring( + { type: KeyringTypes.hd }, + async ({ metadata }) => { + return metadata.id; + }, + ); + entropySource = id; + } + + const keyring = await this.getSnapKeyring(); + + return await keyring.createAccount( + snapId, + { entropySource }, + { + displayConfirmation: false, + displayAccountNameSuggestion: false, + setSelectedAccount: false, + }, + ); + } + ///: END:ONLY_INCLUDE_IF + /** * Encodes a BIP-39 mnemonic as the indices of words in the English BIP-39 wordlist. * @@ -5114,12 +5441,7 @@ export default class MetamaskController extends EventEmitter { */ async getSeedPhrase(password, _keyringId) { return this._convertEnglishWordlistIndicesToCodepoints( - await this.keyringController.exportSeedPhrase( - password, - ///: BEGIN:ONLY_INCLUDE_IF(multi-srp) - _keyringId, - ///: END:ONLY_INCLUDE_IF - ), + await this.keyringController.exportSeedPhrase(password, _keyringId), ); } @@ -5194,13 +5516,36 @@ export default class MetamaskController extends EventEmitter { * Sorts a list of evm account addresses by most recently selected by using * the lastSelected value for the matching InternalAccount object stored in state. * - * @param {Hex[]} [accounts] - The list of evm accounts addresses to sort. + * @param {Hex[]} [addresses] - The list of evm accounts addresses to sort. * @returns {Hex[]} The sorted evm accounts addresses. */ - sortAccountsByLastSelected(accounts) { + sortEvmAccountsByLastSelected(addresses) { const internalAccounts = this.accountsController.listAccounts(); + return this.sortAddressesWithInternalAccounts(addresses, internalAccounts); + } - return accounts.sort((firstAddress, secondAddress) => { + /** + * Sorts a list of multichain account addresses by most recently selected by using + * the lastSelected value for the matching InternalAccount object stored in state. + * + * @param {string[]} [addresses] - The list of addresses (not full CAIP-10 Account IDs) to sort. + * @returns {string[]} The sorted accounts addresses. + */ + sortMultichainAccountsByLastSelected(addresses) { + const internalAccounts = this.accountsController.listMultichainAccounts(); + return this.sortAddressesWithInternalAccounts(addresses, internalAccounts); + } + + /** + * Sorts a list of addresses by most recently selected by using the lastSelected value for + * the matching InternalAccount object from the list of internalAccounts provided. + * + * @param {string[]} [addresses] - The list of caip accounts addresses to sort. + * @param {InternalAccount[]} [internalAccounts] - The list of InternalAccounts to determine lastSelected from. + * @returns {string[]} The sorted accounts addresses. + */ + sortAddressesWithInternalAccounts(addresses, internalAccounts) { + return addresses.sort((firstAddress, secondAddress) => { const firstAccount = internalAccounts.find( (internalAccount) => internalAccount.address.toLowerCase() === firstAddress.toLowerCase(), @@ -5214,13 +5559,13 @@ export default class MetamaskController extends EventEmitter { if (!firstAccount) { this.captureKeyringTypesWithMissingIdentities( internalAccounts, - accounts, + addresses, ); throw new Error(`Missing identity for address: "${firstAddress}".`); } else if (!secondAccount) { this.captureKeyringTypesWithMissingIdentities( internalAccounts, - accounts, + addresses, ); throw new Error(`Missing identity for address: "${secondAddress}".`); } else if ( @@ -5275,7 +5620,7 @@ export default class MetamaskController extends EventEmitter { } const ethAccounts = getEthAccounts(caveat.value); - return this.sortAccountsByLastSelected(ethAccounts); + return this.sortEvmAccountsByLastSelected(ethAccounts); } /** @@ -5378,6 +5723,7 @@ export default class MetamaskController extends EventEmitter { { requiredScopes: {}, optionalScopes: {}, + sessionProperties: {}, isMultichainOrigin: false, }, [chainId], @@ -5428,6 +5774,7 @@ export default class MetamaskController extends EventEmitter { { requiredScopes: {}, optionalScopes: {}, + sessionProperties: {}, isMultichainOrigin: false, }, [chainId], @@ -5513,6 +5860,7 @@ export default class MetamaskController extends EventEmitter { accounts: [], }, }, + sessionProperties: {}, isMultichainOrigin: false, }; @@ -5537,6 +5885,66 @@ export default class MetamaskController extends EventEmitter { }, }; } + + getNonEvmSupportedMethods(scope) { + return this.controllerMessenger.call( + 'MultichainRouter:getSupportedMethods', + scope, + ); + } + + /** + * For origins with a solana scope permitted, sends a wallet_notify -> metamask_accountChanged + * event to fire for the solana scope with the currently selected solana account if any are + * permitted or empty array otherwise. + * + * @param {string} origin - The origin to notify with the current solana account + */ + notifySolanaAccountChangedForCurrentAccount(origin) { + let caip25Caveat; + try { + caip25Caveat = this.permissionController.getCaveat( + origin, + Caip25EndowmentPermissionName, + Caip25CaveatType, + ); + } catch { + // noop + } + if (!caip25Caveat) { + return; + } + const solanaAccountsChangedNotifications = + caip25Caveat.value.sessionProperties[ + KnownSessionProperties.SolanaAccountChangedNotifications + ]; + + const sessionScopes = getSessionScopes(caip25Caveat.value, { + getNonEvmSupportedMethods: this.getNonEvmSupportedMethods.bind(this), + }); + + const solanaScope = + sessionScopes[MultichainNetworks.SOLANA] || + sessionScopes[MultichainNetworks.SOLANA_DEVNET] || + sessionScopes[MultichainNetworks.SOLANA_TESTNET]; + + if (solanaAccountsChangedNotifications && solanaScope) { + const { accounts } = solanaScope; + const parsedPermittedSolanaAddresses = accounts.map((caipAccountId) => { + const { address } = parseCaipAccountId(caipAccountId); + return address; + }); + + const [accountAddressToEmit] = this.sortMultichainAccountsByLastSelected( + parsedPermittedSolanaAddresses, + ); + + if (accountAddressToEmit) { + this._notifySolanaAccountChange(origin, [accountAddressToEmit]); + } + } + } + // --------------------------------------------------------------------------- // Identity Management (signature operations) @@ -6140,6 +6548,16 @@ export default class MetamaskController extends EventEmitter { engine, }); + // solana account changed notifications + // This delay is needed because it's possible for a dapp to not have listeners + // setup in time right after a connection is established. + // This can be resolved if we amend the caip standards to include a liveliness + // handshake as part of the initial connection. + setTimeout( + () => this.notifySolanaAccountChangedForCurrentAccount(origin), + 500, + ); + pipeline( outStream, dupeReqFilterStream, @@ -6701,10 +7119,11 @@ export default class MetamaskController extends EventEmitter { listAccounts: this.accountsController.listAccounts.bind( this.accountsController, ), - requestPermissionsForOrigin: (requestedPermissions) => + requestPermissionsForOrigin: (requestedPermissions, options = {}) => this.permissionController.requestPermissions( { origin }, requestedPermissions, + options, ), sendMetrics: this.metaMetricsController.trackEvent.bind( this.metaMetricsController, @@ -6721,6 +7140,20 @@ export default class MetamaskController extends EventEmitter { this.permissionController, origin, ), + getNonEvmSupportedMethods: this.getNonEvmSupportedMethods.bind(this), + isNonEvmScopeSupported: this.controllerMessenger.call.bind( + this.controllerMessenger, + 'MultichainRouter:isSupportedScope', + ), + handleNonEvmRequestForOrigin: (params) => + this.controllerMessenger.call('MultichainRouter:handleRequest', { + ...params, + origin, + }), + getNonEvmAccountAddresses: this.controllerMessenger.call.bind( + this.controllerMessenger, + 'MultichainRouter:getSupportedAccounts', + ), }), ); @@ -6856,7 +7289,9 @@ export default class MetamaskController extends EventEmitter { ); // add new notification subscriptions for changed authorizations - const sessionScopes = getSessionScopes(caip25Caveat.value); + const sessionScopes = getSessionScopes(caip25Caveat.value, { + getNonEvmSupportedMethods: this.getNonEvmSupportedMethods.bind(this), + }); // if the eth_subscription notification is in the scope and eth_subscribe is in the methods // then get the subscriptionManager going for that scope @@ -7010,7 +7445,6 @@ export default class MetamaskController extends EventEmitter { */ notifyConnections(origin, payload, apiType) { const connections = this.connections[origin]; - if (connections) { Object.values(connections).forEach((conn) => { if (apiType && conn.apiType !== apiType) { @@ -7382,6 +7816,17 @@ export default class MetamaskController extends EventEmitter { }; } + updateAccountBalanceForTransactionNetwork(transactionMeta) { + const { + networkClientId, + txParams: { from }, + } = transactionMeta; + this.accountTrackerController.updateAccountByAddress({ + from, + networkClientId, + }); + } + toggleExternalServices(useExternal) { this.preferencesController.toggleExternalServices(useExternal); this.tokenListController.updatePreventPollingOnNetworkRestart(!useExternal); @@ -7696,9 +8141,29 @@ export default class MetamaskController extends EventEmitter { this.notifyConnections( origin, { - method: NOTIFICATION_NAMES.sessionChanged, + method: MultichainApiNotifications.sessionChanged, params: { - sessionScopes: getSessionScopes(newAuthorization), + sessionScopes: getSessionScopes(newAuthorization, { + getNonEvmSupportedMethods: + this.getNonEvmSupportedMethods.bind(this), + }), + }, + }, + API_TYPE.CAIP_MULTICHAIN, + ); + } + + async _notifySolanaAccountChange(origin, accountAddressArray) { + this.notifyConnections( + origin, + { + method: MultichainApiNotifications.walletNotify, + params: { + scope: MultichainNetworks.SOLANA, + notification: { + method: NOTIFICATION_NAMES.accountsChanged, + params: accountAddressArray, + }, }, }, API_TYPE.CAIP_MULTICHAIN, @@ -8134,16 +8599,9 @@ export default class MetamaskController extends EventEmitter { } #restartSmartTransactionPoller() { - const filteredChainIds = this.#getAllAddedNetworks().filter( - (networkId) => - this.preferencesController.state.incomingTransactionsPreferences[ - networkId - ], - ); - - if (filteredChainIds.length > 0) { + if (this.preferencesController.state.useExternalServices === true) { this.txController.stopIncomingTransactionPolling(); - this.txController.startIncomingTransactionPolling(filteredChainIds); + this.txController.startIncomingTransactionPolling(); } } @@ -8165,6 +8623,8 @@ export default class MetamaskController extends EventEmitter { getStateUI: this._getMetaMaskState.bind(this), getTransactionMetricsRequest: this.getTransactionMetricsRequest.bind(this), + updateAccountBalanceForTransactionNetwork: + this.updateAccountBalanceForTransactionNetwork.bind(this), offscreenPromise: this.offscreenPromise, persistedState: initState, removeAllConnections: this.removeAllConnections.bind(this), diff --git a/app/scripts/metamask-controller.test.js b/app/scripts/metamask-controller.test.js index 6e038ff300bf..bbf39cf5c1c8 100644 --- a/app/scripts/metamask-controller.test.js +++ b/app/scripts/metamask-controller.test.js @@ -17,6 +17,7 @@ import { BtcAccountType, BtcMethod, EthAccountType, + SolScope, } from '@metamask/keyring-api'; import { Messenger } from '@metamask/base-controller'; import { LoggingController, LogType } from '@metamask/logging-controller'; @@ -34,8 +35,9 @@ import { LedgerKeyring } from '@metamask/eth-ledger-bridge-keyring'; import { Caip25CaveatType, Caip25EndowmentPermissionName, -} from '@metamask/multichain'; +} from '@metamask/chain-agnostic-permission'; import { PermissionDoesNotExistError } from '@metamask/permission-controller'; +import { KeyringInternalSnapClient } from '@metamask/keyring-internal-snap-client'; import { createTestProviderTools } from '../../test/stub/provider'; import { HardwareDeviceNames, @@ -778,6 +780,40 @@ describe('MetaMaskController', () => { allDetectedTokens: { '0x1': { [TEST_ADDRESS_2]: [{}] } }, }); + const mockSnapKeyring = { + createAccount: jest + .fn() + .mockResolvedValue({ address: 'mockedAddress' }), + }; + + const originalGetKeyringsByType = + metamaskController.keyringController.getKeyringsByType; + let snapKeyringCallCount = 0; + jest + .spyOn(metamaskController.keyringController, 'getKeyringsByType') + .mockImplementation((type) => { + if (type === 'Snap Keyring') { + snapKeyringCallCount += 1; + + if (snapKeyringCallCount === 1) { + // First call - use original implementation to let controller initialize snap keyring + return originalGetKeyringsByType.call( + metamaskController.keyringController, + type, + ); + } + // Second call and beyond - return mock + console.log('returning mocked snap keyring!'); + return [mockSnapKeyring]; + } + + // For other types, always use original implementation + return originalGetKeyringsByType.call( + metamaskController.keyringController, + type, + ); + }); + await metamaskController.createNewVaultAndRestore( 'foobar1337', TEST_SEED, @@ -926,7 +962,7 @@ describe('MetaMaskController', () => { }, }); jest - .spyOn(metamaskController, 'sortAccountsByLastSelected') + .spyOn(metamaskController, 'sortEvmAccountsByLastSelected') .mockReturnValue(['not_empty']); expect( @@ -956,12 +992,12 @@ describe('MetaMaskController', () => { }, }); jest - .spyOn(metamaskController, 'sortAccountsByLastSelected') + .spyOn(metamaskController, 'sortEvmAccountsByLastSelected') .mockReturnValue([]); metamaskController.getPermittedAccounts('test.com'); expect( - metamaskController.sortAccountsByLastSelected, + metamaskController.sortEvmAccountsByLastSelected, ).toHaveBeenCalledWith(['0xdead', '0xbeef']); }); @@ -979,7 +1015,7 @@ describe('MetaMaskController', () => { }, }); jest - .spyOn(metamaskController, 'sortAccountsByLastSelected') + .spyOn(metamaskController, 'sortEvmAccountsByLastSelected') .mockReturnValue(['0xbeef', '0xdead']); expect( @@ -1067,6 +1103,7 @@ describe('MetaMaskController', () => { accounts: [], }, }, + sessionProperties: {}, isMultichainOrigin: false, }, }, @@ -1105,6 +1142,7 @@ describe('MetaMaskController', () => { accounts: ['wallet:eip155:foo'], }, }, + sessionProperties: {}, isMultichainOrigin: false, }, }, @@ -1146,6 +1184,7 @@ describe('MetaMaskController', () => { accounts: [], }, }, + sessionProperties: {}, isMultichainOrigin: false, }, }, @@ -1195,6 +1234,7 @@ describe('MetaMaskController', () => { accounts: ['eip155:100:foo'], }, }, + sessionProperties: {}, isMultichainOrigin: false, }, }, @@ -1233,6 +1273,7 @@ describe('MetaMaskController', () => { accounts: ['wallet:eip155:foo'], }, }, + sessionProperties: {}, isMultichainOrigin: false, }, }, @@ -1271,6 +1312,7 @@ describe('MetaMaskController', () => { accounts: [], }, }, + sessionProperties: {}, isMultichainOrigin: false, }, }, @@ -1317,6 +1359,7 @@ describe('MetaMaskController', () => { accounts: ['wallet:eip155:foo'], }, }, + sessionProperties: {}, isMultichainOrigin: false, }, }, @@ -1369,6 +1412,7 @@ describe('MetaMaskController', () => { accounts: ['eip155:5:0xdeadbeef'], }, }, + sessionProperties: {}, isMultichainOrigin: false, }, }, @@ -1417,6 +1461,7 @@ describe('MetaMaskController', () => { accounts: ['wallet:eip155:0xdeadbeef'], }, }, + sessionProperties: {}, isMultichainOrigin: false, }, }, @@ -1457,6 +1502,7 @@ describe('MetaMaskController', () => { accounts: [], }, }, + sessionProperties: {}, isMultichainOrigin: false, }, }, @@ -1506,6 +1552,7 @@ describe('MetaMaskController', () => { value: { requiredScopes: {}, optionalScopes: { 'eip155:1': { accounts: [] } }, + sessionProperties: {}, isMultichainOrigin: false, }, }, @@ -1561,6 +1608,7 @@ describe('MetaMaskController', () => { value: { requiredScopes: {}, optionalScopes: { 'eip155:1': { accounts: [] } }, + sessionProperties: {}, isMultichainOrigin: false, }, }, @@ -1613,7 +1661,7 @@ describe('MetaMaskController', () => { }); }); - describe('#sortAccountsByLastSelected', () => { + describe('#sortEvmAccountsByLastSelected', () => { it('returns the keyring accounts in lastSelected order', () => { jest .spyOn(metamaskController.accountsController, 'listAccounts') @@ -1681,7 +1729,7 @@ describe('MetaMaskController', () => { }); expect( - metamaskController.sortAccountsByLastSelected([ + metamaskController.sortEvmAccountsByLastSelected([ '0x7A2Bd22810088523516737b4Dc238A4bC37c23F2', '0x7152f909e5EB3EF198f17e5Cb087c5Ced88294e3', '0xDe70d2FF1995DC03EF1a3b584e3ae14da020C616', @@ -1736,7 +1784,7 @@ describe('MetaMaskController', () => { }); expect(() => - metamaskController.sortAccountsByLastSelected([ + metamaskController.sortEvmAccountsByLastSelected([ '0x7A2Bd22810088523516737b4Dc238A4bC37c23F2', '0x7152f909e5EB3EF198f17e5Cb087c5Ced88294e3', '0xDe70d2FF1995DC03EF1a3b584e3ae14da020C616', @@ -1794,7 +1842,7 @@ describe('MetaMaskController', () => { }); expect(() => - metamaskController.sortAccountsByLastSelected([ + metamaskController.sortEvmAccountsByLastSelected([ '0x7A2Bd22810088523516737b4Dc238A4bC37c23F2', '0x7152f909e5EB3EF198f17e5Cb087c5Ced88294e3', '0xDe70d2FF1995DC03EF1a3b584e3ae14da020C616', @@ -3576,15 +3624,13 @@ describe('MetaMaskController', () => { }); describe('incoming transactions', () => { - it('starts incoming transaction polling if incomingTransactionsPreferences is enabled for that chainId', async () => { + it('starts incoming transaction polling if useExternalServices is enabled for that chainId', async () => { expect( TransactionController.prototype.startIncomingTransactionPolling, ).not.toHaveBeenCalled(); await simulatePreferencesChange({ - incomingTransactionsPreferences: { - [MAINNET_CHAIN_ID]: true, - }, + useExternalServices: true, }); expect( @@ -3592,15 +3638,13 @@ describe('MetaMaskController', () => { ).toHaveBeenCalledTimes(1); }); - it('stops incoming transaction polling if incomingTransactionsPreferences is disabled for that chainId', async () => { + it('stops incoming transaction polling if useExternalServices is disabled for that chainId', async () => { expect( TransactionController.prototype.stopIncomingTransactionPolling, ).not.toHaveBeenCalled(); await simulatePreferencesChange({ - incomingTransactionsPreferences: { - [MAINNET_CHAIN_ID]: false, - }, + useExternalServices: false, }); expect( @@ -3935,6 +3979,39 @@ describe('MetaMaskController', () => { it('generates a new hd keyring instance with a mnemonic', async () => { const password = 'what-what-what'; jest.spyOn(metamaskController, 'getBalance').mockResolvedValue('0x0'); + const mockSnapKeyring = { + createAccount: jest + .fn() + .mockResolvedValue({ address: 'mockedAddress' }), + }; + + const originalGetKeyringsByType = + metamaskController.keyringController.getKeyringsByType; + let snapKeyringCallCount = 0; + jest + .spyOn(metamaskController.keyringController, 'getKeyringsByType') + .mockImplementation((type) => { + if (type === 'Snap Keyring') { + snapKeyringCallCount += 1; + + if (snapKeyringCallCount === 1) { + // First call - use original implementation to let controller initialize snap keyring + return originalGetKeyringsByType.call( + metamaskController.keyringController, + type, + ); + } + // Second call and beyond - return mock + console.log('returning mocked snap keyring!'); + return [mockSnapKeyring]; + } + + // For other types, always use original implementation + return originalGetKeyringsByType.call( + metamaskController.keyringController, + type, + ); + }); await metamaskController.createNewVaultAndRestore(password, TEST_SEED); @@ -3949,7 +4026,7 @@ describe('MetaMaskController', () => { const newlyAddedKeyringId = metamaskController.keyringController.state.keyringsMetadata[ metamaskController.keyringController.state.keyringsMetadata.length - - 1 + 2 // -1 for the snap keyring, -1 for the newly added keyring ].id; const newSRP = Buffer.from( @@ -3959,7 +4036,10 @@ describe('MetaMaskController', () => { expect( currentKeyrings.filter((kr) => kr.type === 'HD Key Tree'), ).toHaveLength(2); - expect(currentKeyrings).toHaveLength(previousKeyrings.length + 1); + expect( + currentKeyrings.filter((kr) => kr.type === 'Snap Keyring'), + ).toHaveLength(1); + expect(currentKeyrings).toHaveLength(previousKeyrings.length + 2); expect(newSRP).toStrictEqual(TEST_SEED_ALT); }); @@ -3974,6 +4054,76 @@ describe('MetaMaskController', () => { 'This Secret Recovery Phrase has already been imported.', ); }); + + ///: BEGIN:ONLY_INCLUDE_IF(multi-srp) + it('discovers and creates Solana accounts through KeyringInternalSnapClient when importing a mnemonic', async () => { + const password = 'what-what-what'; + jest.spyOn(metamaskController, 'getBalance').mockResolvedValue('0x0'); + + const mockDiscoverAccounts = jest + .fn() + .mockResolvedValueOnce([{ derivationPath: "m/44'/501'/0'/0'" }]) + .mockResolvedValueOnce([{ derivationPath: "m/44'/501'/1'/0'" }]) + .mockResolvedValueOnce([]); // Return empty array on third call to stop the discovery loop + + jest + .spyOn(KeyringInternalSnapClient.prototype, 'discoverAccounts') + .mockImplementation(mockDiscoverAccounts); + + const mockCreateAccount = jest.fn().mockResolvedValue(undefined); + jest + .spyOn(metamaskController, 'getSnapKeyring') + .mockResolvedValue({ createAccount: mockCreateAccount }); + + await metamaskController.createNewVaultAndRestore(password, TEST_SEED); + await metamaskController.importMnemonicToVault(TEST_SEED_ALT); + + // Assert that discoverAccounts was called correctly + // Should be called 3 times (twice with discovered accounts, once with empty array) + expect(mockDiscoverAccounts).toHaveBeenCalledTimes(3); + + // All calls should include the solana scopes + expect(mockDiscoverAccounts.mock.calls[0][0]).toStrictEqual( + expect.arrayContaining([ + SolScope.Mainnet, + SolScope.Testnet, + SolScope.Devnet, + ]), + ); + + // First call should be for index 0 + expect(mockDiscoverAccounts.mock.calls[0][2]).toBe(0); + // Second call should be for index 1 + expect(mockDiscoverAccounts.mock.calls[1][2]).toBe(1); + // Third call should be for index 2 + expect(mockDiscoverAccounts.mock.calls[2][2]).toBe(2); + + // Assert that createAccount was called correctly for each discovered account + expect(mockCreateAccount).toHaveBeenCalledTimes(3); + + // All calls should use the solana snap ID + expect(mockCreateAccount.mock.calls[0][0]).toStrictEqual( + expect.stringContaining('solana-wallet'), + ); + // Second call should use derivation path on index 0 + expect(mockCreateAccount.mock.calls[1][1]).toStrictEqual({ + derivationPath: "m/44'/501'/0'/0'", + entropySource: expect.any(String), + }); + // All calls should use the same internal options + expect(mockCreateAccount.mock.calls[0][2]).toStrictEqual({ + displayConfirmation: false, + displayAccountNameSuggestion: false, + setSelectedAccount: false, + }); + + // Third call should use derivation path on index 1 + expect(mockCreateAccount.mock.calls[2][1]).toStrictEqual({ + derivationPath: "m/44'/501'/1'/0'", + entropySource: expect.any(String), + }); + }); + ///: END:ONLY_INCLUDE_IF }); }); diff --git a/app/scripts/migrations/077-supplements/077-supplement-for-088.ts b/app/scripts/migrations/077-supplements/077-supplement-for-088.ts index 4d430865ab54..f0388d001df8 100644 --- a/app/scripts/migrations/077-supplements/077-supplement-for-088.ts +++ b/app/scripts/migrations/077-supplements/077-supplement-for-088.ts @@ -11,7 +11,7 @@ import { hasProperty, isObject, isStrictHexString } from '@metamask/utils'; * @param state - The persisted MetaMask state, keyed by controller. * @returns Updated versioned MetaMask extension state. */ -export default function transformState077For086( +export default function transformState077For088( state: Record, ): Record { if (hasProperty(state, 'NftController') && isObject(state.NftController)) { diff --git a/app/scripts/migrations/095.test.ts b/app/scripts/migrations/095.test.ts index 988f59b8f5f8..7af6b1502118 100644 --- a/app/scripts/migrations/095.test.ts +++ b/app/scripts/migrations/095.test.ts @@ -156,7 +156,6 @@ describe('migration #95', () => { }); }); - // @ts-expect-error This is missing from the Mocha type definitions it.each([ ['undefined', undefined], ['empty', {}], diff --git a/app/scripts/migrations/121.1.test.ts b/app/scripts/migrations/121.1.test.ts index 1d2d6f9ab70e..5a39b9d519b4 100644 --- a/app/scripts/migrations/121.1.test.ts +++ b/app/scripts/migrations/121.1.test.ts @@ -212,7 +212,6 @@ describe('migration #121.1', () => { }, ]; - // @ts-expect-error 'each' function missing from type definitions, but it does exist it.each(invalidState)( 'captures error when state is invalid due to: $label', async ({ diff --git a/app/scripts/migrations/131.test.ts b/app/scripts/migrations/131.test.ts index ab359ff7283c..7614ef01dfcc 100644 --- a/app/scripts/migrations/131.test.ts +++ b/app/scripts/migrations/131.test.ts @@ -218,7 +218,6 @@ describe(`migration #${version}`, () => { }, ]; - // @ts-expect-error 'each' function missing from type definitions, but it does exist it.each(invalidState)( 'captures error when state is invalid due to: $label', async ({ diff --git a/app/scripts/migrations/133.1.test.ts b/app/scripts/migrations/133.1.test.ts index 4f1979f31a97..48ca469c7cd5 100644 --- a/app/scripts/migrations/133.1.test.ts +++ b/app/scripts/migrations/133.1.test.ts @@ -198,7 +198,6 @@ describe(`migration #${version}`, () => { }, ]; - // @ts-expect-error 'each' function is not recognized by TypeScript types it.each(invalidState)( 'captures error when state is invalid due to: $label', async ({ diff --git a/app/scripts/migrations/139.test.ts b/app/scripts/migrations/139.test.ts index 0505607c7193..bf7cc39db818 100644 --- a/app/scripts/migrations/139.test.ts +++ b/app/scripts/migrations/139.test.ts @@ -495,7 +495,6 @@ describe('migration #139', () => { }); }); - // @ts-expect-error This function is missing from the Mocha type definitions describe.each([ [ 'built-in', diff --git a/app/scripts/migrations/151.test.ts b/app/scripts/migrations/151.test.ts new file mode 100644 index 000000000000..adcf814779a4 --- /dev/null +++ b/app/scripts/migrations/151.test.ts @@ -0,0 +1,54 @@ +import { migrate, version } from './151'; + +const oldVersion = 150; + +describe(`migration #${version}`, () => { + it('updates the version metadata', async () => { + const oldStorage = { + meta: { version: oldVersion }, + data: {}, + }; + const newStorage = await migrate(oldStorage); + expect(newStorage.meta).toStrictEqual({ version }); + }); + + describe(`migration #${version}`, () => { + it('removes the incomingTransactionsPreferences from PreferencesController state', async () => { + const oldStorage = { + meta: { version: oldVersion }, + data: { + PreferencesController: { + incomingTransactionsPreferences: { 0x1: true }, + }, + }, + }; + const expectedData = { + PreferencesController: {}, + }; + const newStorage = await migrate(oldStorage); + + expect(newStorage.data).toStrictEqual(expectedData); + }); + + it('does nothing to other PreferencesController state if incomingTransactionsPreferences is not set', async () => { + const oldStorage = { + meta: { version: oldVersion }, + data: { + PreferencesController: { + existingPreference: true, + }, + }, + }; + + const expectedData = { + PreferencesController: { + existingPreference: true, + }, + }; + + const newStorage = await migrate(oldStorage); + + expect(newStorage.data).toStrictEqual(expectedData); + }); + }); +}); diff --git a/app/scripts/migrations/151.ts b/app/scripts/migrations/151.ts new file mode 100644 index 000000000000..5f6925643166 --- /dev/null +++ b/app/scripts/migrations/151.ts @@ -0,0 +1,37 @@ +import { cloneDeep } from 'lodash'; + +type VersionedData = { + meta: { version: number }; + data: Record; +}; + +export const version = 151; + +/** + * This migration deletes the preference `petnamesEnabled` if the user has + * existing data. + * + * @param originalVersionedData - Versioned MetaMask extension state, exactly + * what we persist to dist. + * @param originalVersionedData.meta - State metadata. + * @param originalVersionedData.meta.version - The current state version. + * @param originalVersionedData.data - The persisted MetaMask state, keyed by + * controller. + * @returns Updated versioned MetaMask extension state. + */ +export async function migrate( + originalVersionedData: VersionedData, +): Promise { + const versionedData = cloneDeep(originalVersionedData); + versionedData.meta.version = version; + transformState(versionedData.data); + return versionedData; +} + +function transformState(state: Record) { + const preferencesControllerState = state?.PreferencesController as + | Record + | undefined; + + delete preferencesControllerState?.incomingTransactionsPreferences; +} diff --git a/app/scripts/migrations/152.1.test.ts b/app/scripts/migrations/152.1.test.ts new file mode 100644 index 000000000000..f89325ea4ee8 --- /dev/null +++ b/app/scripts/migrations/152.1.test.ts @@ -0,0 +1,85 @@ +import { TESTNETS, migrate, version } from './152.1'; + +const mockNetworks = { + 'bip122:000000000019d6689c085ae165831e93': { + chainId: 'bip122:000000000019d6689c085ae165831e93', + name: 'Bitcoin', + nativeCurrency: 'bip122:000000000019d6689c085ae165831e93/slip44:0', + isEvm: false, + }, + 'solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp': { + chainId: 'solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp', + name: 'Solana', + nativeCurrency: 'solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp/slip44:501', + isEvm: false, + }, +}; + +const oldVersion = 152; + +describe(`migration #${version}`, () => { + it('updates the version metadata', async () => { + const oldStorage = { + meta: { version: oldVersion }, + data: {}, + }; + const newStorage = await migrate(oldStorage); + expect(newStorage.meta).toStrictEqual({ version }); + }); + + describe(`migration #${version}`, () => { + it('does nothing if MultichainNetworkController is missing', async () => { + const oldStorage = { + meta: { version: oldVersion }, + data: {}, + }; + const newStorage = await migrate(oldStorage); + expect(newStorage.data).toStrictEqual({}); + }); + + it('does nothing if MultichainNetworkController is not an object', async () => { + const oldStorage = { + meta: { version: oldVersion }, + data: { + MultichainNetworkController: 'invalidData', + }, + }; + const newStorage = await migrate(oldStorage); + expect(newStorage.data).toStrictEqual(oldStorage.data); + }); + + it('does nothing if MultichainNetworkController.multichainNetworkConfigurationsByChainId is not an object', async () => { + const oldStorage = { + meta: { version: oldVersion }, + data: { + MultichainNetworkController: { + multichainNetworkConfigurationsByChainId: 'not an object', + }, + }, + }; + const newStorage = await migrate(oldStorage); + expect(newStorage.data).toStrictEqual(oldStorage.data); + }); + + it('updates the multichainNetworkConfigurationsByChainId to contain test networks', async () => { + const oldStorage = { + meta: { version: oldVersion }, + data: { + MultichainNetworkController: { + multichainNetworkConfigurationsByChainId: mockNetworks, + }, + }, + }; + const expectedData = { + MultichainNetworkController: { + multichainNetworkConfigurationsByChainId: { + ...mockNetworks, + ...TESTNETS, + }, + }, + }; + const newStorage = await migrate(oldStorage); + expect(newStorage.data).toStrictEqual(expectedData); + }); + }); +}); diff --git a/app/scripts/migrations/152.1.ts b/app/scripts/migrations/152.1.ts new file mode 100644 index 000000000000..5abbc33f92f4 --- /dev/null +++ b/app/scripts/migrations/152.1.ts @@ -0,0 +1,78 @@ +import { hasProperty, isObject } from '@metamask/utils'; +import { cloneDeep } from 'lodash'; + +type VersionedData = { + meta: { version: number }; + data: Record; +}; + +export const version = 152.1; + +// Since this is a migration, we don't want to rely on data +// from outside packages that could change. Therefore, we'll +// use literal values. +export const TESTNETS = { + 'bip122:000000000933ea01ad0ee984209779ba': { + chainId: 'bip122:000000000933ea01ad0ee984209779ba', + name: 'Bitcoin Testnet', + nativeCurrency: 'bip122:000000000933ea01ad0ee984209779ba/slip44:0', + isEvm: false, + }, + 'bip122:00000008819873e925422c1ff0f99f7c': { + chainId: 'bip122:00000008819873e925422c1ff0f99f7c', + name: 'Bitcoin Signet', + nativeCurrency: 'bip122:00000008819873e925422c1ff0f99f7c/slip44:0', + isEvm: false, + }, + 'solana:4uhcVJyU9pJkvQyS88uRDiswHXSCkY3z': { + chainId: 'solana:4uhcVJyU9pJkvQyS88uRDiswHXSCkY3z', + name: 'Solana Testnet', + nativeCurrency: 'solana:4uhcVJyU9pJkvQyS88uRDiswHXSCkY3z/slip44:501', + isEvm: false, + }, + 'solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1': { + chainId: 'solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1', + name: 'Solana Devnet', + nativeCurrency: 'solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1/slip44:501', + isEvm: false, + }, +}; + +/** + * This migration adds test network configurations to the MultichainNetworkController. + * Networks added: Bitcoin testnet, Bitcoin Signet, Solana testnet, and Solana devnet. + * + * @param originalVersionedData - Versioned MetaMask extension state, exactly + * what we persist to disk. + * @returns Updated versioned MetaMask extension state. + */ +export async function migrate( + originalVersionedData: VersionedData, +): Promise { + const versionedData = cloneDeep(originalVersionedData); + versionedData.meta.version = version; + transformState(versionedData.data); + return versionedData; +} + +function transformState( + state: Record, +): Record { + if ( + hasProperty(state, 'MultichainNetworkController') && + isObject(state.MultichainNetworkController) && + isObject( + state.MultichainNetworkController + .multichainNetworkConfigurationsByChainId, + ) + ) { + state.MultichainNetworkController.multichainNetworkConfigurationsByChainId = + { + ...state.MultichainNetworkController + .multichainNetworkConfigurationsByChainId, + ...TESTNETS, + }; + } + + return state; +} diff --git a/app/scripts/migrations/152.test.ts b/app/scripts/migrations/152.test.ts new file mode 100644 index 000000000000..4a95313230c9 --- /dev/null +++ b/app/scripts/migrations/152.test.ts @@ -0,0 +1,295 @@ +import { + Caip25EndowmentPermissionName, + KnownSessionProperties, +} from '@metamask/chain-agnostic-permission'; + +import { migrate, version } from './152'; + +const oldVersion = 151; + +describe(`migration #${version}`, () => { + it('updates the version metadata', async () => { + const oldStorage = { + meta: { version: oldVersion }, + data: {}, + }; + const newStorage = await migrate(oldStorage); + expect(newStorage.meta).toStrictEqual({ version }); + }); + + it('does nothing if PermissionController is missing', async () => { + const oldStorage = { + meta: { version: oldVersion }, + data: { + SomeOtherController: {}, + }, + }; + const newStorage = await migrate(oldStorage); + expect(newStorage.data).toStrictEqual(oldStorage.data); + }); + + it('adds sessionProperties to CAIP-25 permissions that do not have it', async () => { + const oldStorage = { + meta: { version: oldVersion }, + data: { + PermissionController: { + subjects: { + 'example.com': { + origin: 'example.com', + permissions: { + [Caip25EndowmentPermissionName]: { + id: '123', + parentCapability: Caip25EndowmentPermissionName, + invoker: 'example.com', + caveats: [ + { + type: 'authorizedScopes', + value: { + requiredScopes: {}, + optionalScopes: { + 'eip155:1': { + accounts: ['eip155:1:0x123'], + }, + }, + isMultichainOrigin: false, + }, + }, + ], + }, + }, + }, + }, + }, + }, + }; + + const expectedData = { + PermissionController: { + subjects: { + 'example.com': { + origin: 'example.com', + permissions: { + [Caip25EndowmentPermissionName]: { + id: '123', + parentCapability: Caip25EndowmentPermissionName, + invoker: 'example.com', + caveats: [ + { + type: 'authorizedScopes', + value: { + requiredScopes: {}, + optionalScopes: { + 'eip155:1': { + accounts: ['eip155:1:0x123'], + }, + }, + isMultichainOrigin: false, + sessionProperties: {}, + }, + }, + ], + }, + }, + }, + }, + }, + }; + + const newStorage = await migrate(oldStorage); + expect(newStorage.data).toStrictEqual(expectedData); + }); + + it('preserves existing sessionProperties in CAIP-25 permissions', async () => { + const existingSessionProperties = { + [KnownSessionProperties.SolanaAccountChangedNotifications]: true, + }; + + const oldStorage = { + meta: { version: oldVersion }, + data: { + PermissionController: { + subjects: { + 'example.com': { + origin: 'example.com', + permissions: { + [Caip25EndowmentPermissionName]: { + id: '123', + parentCapability: Caip25EndowmentPermissionName, + invoker: 'example.com', + caveats: [ + { + type: 'authorizedScopes', + value: { + requiredScopes: {}, + optionalScopes: { + 'eip155:1': { + accounts: ['eip155:1:0x123'], + }, + }, + isMultichainOrigin: false, + sessionProperties: existingSessionProperties, + }, + }, + ], + }, + }, + }, + }, + }, + }, + }; + + const expectedData = { + PermissionController: { + subjects: { + 'example.com': { + origin: 'example.com', + permissions: { + [Caip25EndowmentPermissionName]: { + id: '123', + parentCapability: Caip25EndowmentPermissionName, + invoker: 'example.com', + caveats: [ + { + type: 'authorizedScopes', + value: { + requiredScopes: {}, + optionalScopes: { + 'eip155:1': { + accounts: ['eip155:1:0x123'], + }, + }, + isMultichainOrigin: false, + sessionProperties: existingSessionProperties, + }, + }, + ], + }, + }, + }, + }, + }, + }; + + const newStorage = await migrate(oldStorage); + expect(newStorage.data).toStrictEqual(expectedData); + }); + + it('handles multiple subjects with CAIP-25 permissions', async () => { + const oldStorage = { + meta: { version: oldVersion }, + data: { + PermissionController: { + subjects: { + 'example.com': { + origin: 'example.com', + permissions: { + [Caip25EndowmentPermissionName]: { + caveats: [ + { + type: 'authorizedScopes', + value: { + requiredScopes: {}, + optionalScopes: {}, + isMultichainOrigin: false, + }, + }, + ], + }, + }, + }, + 'other-site.com': { + origin: 'other-site.com', + permissions: { + [Caip25EndowmentPermissionName]: { + caveats: [ + { + type: 'authorizedScopes', + value: { + requiredScopes: {}, + optionalScopes: {}, + isMultichainOrigin: true, + }, + }, + ], + }, + }, + }, + }, + }, + }, + }; + + const expectedData = { + PermissionController: { + subjects: { + 'example.com': { + origin: 'example.com', + permissions: { + [Caip25EndowmentPermissionName]: { + caveats: [ + { + type: 'authorizedScopes', + value: { + requiredScopes: {}, + optionalScopes: {}, + isMultichainOrigin: false, + sessionProperties: {}, + }, + }, + ], + }, + }, + }, + 'other-site.com': { + origin: 'other-site.com', + permissions: { + [Caip25EndowmentPermissionName]: { + caveats: [ + { + type: 'authorizedScopes', + value: { + requiredScopes: {}, + optionalScopes: {}, + isMultichainOrigin: true, + sessionProperties: {}, + }, + }, + ], + }, + }, + }, + }, + }, + }; + + const newStorage = await migrate(oldStorage); + expect(newStorage.data).toStrictEqual(expectedData); + }); + + it('ignores subjects without CAIP-25 permissions', async () => { + const oldStorage = { + meta: { version: oldVersion }, + data: { + PermissionController: { + subjects: { + 'example.com': { + origin: 'example.com', + permissions: { + 'other:permission': { + id: '123', + parentCapability: 'other:permission', + invoker: 'example.com', + caveats: [], + }, + }, + }, + }, + }, + }, + }; + + const newStorage = await migrate(oldStorage); + expect(newStorage.data).toStrictEqual(oldStorage.data); + }); +}); diff --git a/app/scripts/migrations/152.ts b/app/scripts/migrations/152.ts new file mode 100644 index 000000000000..16ce48511a85 --- /dev/null +++ b/app/scripts/migrations/152.ts @@ -0,0 +1,91 @@ +import { cloneDeep } from 'lodash'; +import { hasProperty, isObject } from '@metamask/utils'; + +export const version = 152; + +// inlined from @metamask/chain-agnostic-permission +const Caip25CaveatType = 'authorizedScopes'; +const Caip25EndowmentPermissionName = 'endowment:caip25'; + +type VersionedData = { + meta: { version: number }; + data: Record; +}; +/** + * Add sessionProperties property to CAIP-25 permission caveats + * + * @param originalVersionedData - Versioned MetaMask extension state + * @returns Updated versioned MetaMask extension state + */ +export async function migrate(originalVersionedData: VersionedData) { + const versionedData = cloneDeep(originalVersionedData); + versionedData.meta.version = version; + transformState(versionedData.data); + return versionedData; +} + +/** + * Add sessionProperties property to CAIP-25 permission caveats + * + * @param state - The MetaMask state + * @returns The updated MetaMask state + */ +function transformState(state: VersionedData['data']) { + if (!hasProperty(state, 'PermissionController')) { + return state; + } + + if (!isObject(state.PermissionController)) { + global.sentry?.captureException?.( + new Error( + `Migration ${version}: typeof state.PermissionController is ${typeof state.PermissionController}`, + ), + ); + return state; + } + + const { subjects } = state.PermissionController; + + if (!isObject(subjects)) { + global.sentry?.captureException?.( + new Error( + `Migration ${version}: typeof state.PermissionController.subjects is ${typeof subjects}`, + ), + ); + return state; + } + + for (const subject of Object.values(subjects)) { + if ( + !isObject(subject) || + !hasProperty(subject, 'permissions') || + !isObject(subject.permissions) + ) { + continue; + } + + const { permissions } = subject; + const caip25Permission = permissions[Caip25EndowmentPermissionName]; + + if ( + !isObject(caip25Permission) || + !Array.isArray(caip25Permission.caveats) + ) { + continue; + } + + const caip25Caveat = caip25Permission.caveats.find( + (caveat) => caveat.type === Caip25CaveatType, + ); + + if ( + caip25Caveat && + isObject(caip25Caveat.value) && + !hasProperty(caip25Caveat.value, 'sessionProperties') + ) { + caip25Caveat.value.sessionProperties = {}; + } + } + + return state; +} diff --git a/app/scripts/migrations/index.js b/app/scripts/migrations/index.js index 616cdbe13e5c..7e4b11a5ccc7 100644 --- a/app/scripts/migrations/index.js +++ b/app/scripts/migrations/index.js @@ -177,6 +177,9 @@ const migrations = [ require('./148'), require('./149'), require('./150'), + require('./151'), + require('./152'), + require('./152.1'), ]; export default migrations; diff --git a/app/scripts/snaps/preinstalled-snaps.ts b/app/scripts/snaps/preinstalled-snaps.ts index bfa23aadc960..eb998ce2ee71 100644 --- a/app/scripts/snaps/preinstalled-snaps.ts +++ b/app/scripts/snaps/preinstalled-snaps.ts @@ -12,6 +12,8 @@ import BitcoinWalletSnap from '@metamask/bitcoin-wallet-snap/dist/preinstalled-s import SolanaWalletSnap from '@metamask/solana-wallet-snap/dist/preinstalled-snap.json'; ///: END:ONLY_INCLUDE_IF +import InstitutionalWalletSnap from '@metamask/institutional-wallet-snap/dist/preinstalled-snap.json'; + // The casts here are less than ideal but we expect the SnapController to validate the inputs. const PREINSTALLED_SNAPS = Object.freeze([ MessageSigningSnap as unknown as PreinstalledSnap, @@ -26,6 +28,7 @@ const PREINSTALLED_SNAPS = Object.freeze([ ///: BEGIN:ONLY_INCLUDE_IF(solana) SolanaWalletSnap as unknown as PreinstalledSnap, ///: END:ONLY_INCLUDE_IF + InstitutionalWalletSnap as unknown as PreinstalledSnap, ]); export default PREINSTALLED_SNAPS; diff --git a/attribution.txt b/attribution.txt index 8c23fca324e9..f494e1fa4e6f 100644 --- a/attribution.txt +++ b/attribution.txt @@ -16872,7 +16872,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE ****************************** @metamask/account-watcher -4.1.2 +4.1.3 Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ @@ -17493,6 +17493,58 @@ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +****************************** + +@metamask/chain-agnostic-permission +0.2.0 +MIT License + +Copyright (c) 2025 MetaMask + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + + +****************************** + +@metamask/chain-agnostic-permission +0.3.0 +MIT License + +Copyright (c) 2025 MetaMask + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + + ****************************** @metamask/contract-metadata @@ -17517,7 +17569,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ****************************** @metamask/controller-utils -11.6.0 +11.7.0 MIT License Copyright (c) 2018 MetaMask @@ -17543,7 +17595,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE ****************************** @metamask/design-tokens -5.1.0 +7.0.0 MIT License Copyright (c) 2024 MetaMask @@ -17972,7 +18024,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ****************************** @metamask/eth-json-rpc-infura -10.0.0 +10.1.0 ISC License Copyright (c) 2020 MetaMask @@ -18164,7 +18216,7 @@ THE SOFTWARE. ****************************** @metamask/eth-ledger-bridge-keyring -11.0.0 +11.0.3 ISC License Copyright (c) 2020 MetaMask @@ -18255,7 +18307,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ****************************** @metamask/eth-snap-keyring -12.0.0 +12.1.1 Copyright ConsenSys Software Inc. 2022. All rights reserved. You acknowledge and agree that ConsenSys Software Inc. (ā€œConsenSysā€) (or ConsenSys’s licensors) own all legal right, title and interest in and to the work, software, application, source code, documentation and any other documents in this repository (collectively, the ā€œProgramā€), including any intellectual property rights which subsist in the Program (whether those rights happen to be registered or not, and wherever in the world those rights may exist), whether in source code or any other form. @@ -18641,6 +18693,13 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +****************************** + +@metamask/institutional-wallet-snap +1.3.1 +license: (MIT-0 OR Apache-2.0) +authors: undefined + ****************************** @metamask-institutional/websocket-client @@ -18758,7 +18817,7 @@ If you have any questions, comments or interest in pursuing any other use cases, ****************************** @metamask/keyring-controller -21.0.3 +21.0.4 MIT License Copyright (c) 2018 MetaMask @@ -18781,13 +18840,6 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -****************************** - -@metamask/keyring-internal-api -5.0.0 -license: Custom: https://github.com/MetaMask/accounts -authors: undefined - ****************************** @metamask/keyring-internal-api @@ -18798,21 +18850,14 @@ authors: undefined ****************************** @metamask/keyring-internal-snap-client -4.0.1 +4.0.2 license: Custom: https://github.com/MetaMask/accounts authors: undefined ****************************** @metamask/keyring-snap-client -4.0.1 -license: Custom: https://github.com/MetaMask/accounts -authors: undefined - -****************************** - -@metamask/keyring-utils -2.3.1 +4.1.0 license: Custom: https://github.com/MetaMask/accounts authors: undefined @@ -18951,11 +18996,32 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ****************************** -@metamask/multichain -3.0.0 +@metamask/multichain-api-client +0.2.0 +ISC License + +Copyright (c) 2021 MetaMask + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + +****************************** + +@metamask/multichain-api-middleware +0.1.1 MIT License -Copyright (c) 2024 MetaMask +Copyright (c) 2025 MetaMask Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -18978,7 +19044,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE ****************************** @metamask/multichain-network-controller -0.1.2 +0.3.0 MIT License Copyright (c) 2025 MetaMask @@ -19004,7 +19070,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE ****************************** @metamask/multichain-network-controller -0.3.0 +0.4.0 MIT License Copyright (c) 2025 MetaMask @@ -19105,6 +19171,32 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +****************************** + +@metamask/network-controller +23.1.0 +MIT License + +Copyright (c) 2018 MetaMask + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + + ****************************** @metamask/nonce-tracker @@ -19593,7 +19685,7 @@ authors: undefined ****************************** @metamask/profile-sync-controller -10.1.0 +11.0.1 MIT License Copyright (c) 2024 MetaMask @@ -19616,33 +19708,6 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -****************************** - -@metamask/providers -20.0.0 -MIT License - -Copyright (c) 2020 MetaMask - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - - ****************************** @metamask/providers @@ -19894,7 +19959,7 @@ If you have any questions, comments or interest in pursuing any other use cases, ****************************** @metamask/snaps-controllers -11.1.0 +11.2.2 Copyright ConsenSys Software Inc. 2021. All rights reserved. You acknowledge and agree that ConsenSys Software Inc. (ā€œConsenSysā€) (or ConsenSys’s licensors) own all legal right, title and interest in and to the work, software, application, source code, documentation and any other documents in this repository (collectively, the ā€œProgramā€), including any intellectual property rights which subsist in the Program (whether those rights happen to be registered or not, and wherever in the world those rights may exist), whether in source code or any other form. @@ -19918,7 +19983,7 @@ If you have any questions, comments or interest in pursuing any other use cases, ****************************** @metamask/snaps-execution-environments -7.1.0 +7.2.1 Copyright ConsenSys Software Inc. 2022. All rights reserved. You acknowledge and agree that ConsenSys Software Inc. (ā€œConsenSysā€) (or ConsenSys’s licensors) own all legal right, title and interest in and to the work, software, application, source code, documentation and any other documents in this repository (collectively, the ā€œProgramā€), including any intellectual property rights which subsist in the Program (whether those rights happen to be registered or not, and wherever in the world those rights may exist), whether in source code or any other form. @@ -20151,7 +20216,7 @@ If you have any questions, comments or interest in pursuing any other use cases, ****************************** @metamask/snaps-rpc-methods -12.0.0 +12.1.0 Copyright ConsenSys Software Inc. 2021. All rights reserved. You acknowledge and agree that ConsenSys Software Inc. (ā€œConsenSysā€) (or ConsenSys’s licensors) own all legal right, title and interest in and to the work, software, application, source code, documentation and any other documents in this repository (collectively, the ā€œProgramā€), including any intellectual property rights which subsist in the Program (whether those rights happen to be registered or not, and wherever in the world those rights may exist), whether in source code or any other form. @@ -20175,7 +20240,7 @@ If you have any questions, comments or interest in pursuing any other use cases, ****************************** @metamask/snaps-sdk -6.21.0 +6.22.0 ISC License Copyright (c) 2023 MetaMask @@ -20217,7 +20282,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ****************************** @metamask/snaps-utils -9.1.0 +9.2.0 ISC License Copyright (c) 2022 MetaMask @@ -20238,14 +20303,35 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ****************************** @metamask/solana-wallet-snap -1.15.1 +1.24.0 license: (MIT-0 OR Apache-2.0) authors: undefined +****************************** + +@metamask/solana-wallet-standard +0.1.1 +ISC License + +Copyright (c) 2021 MetaMask + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + ****************************** @metamask/superstruct -3.1.0 +3.2.1 The MIT License Copyright © 2017, [Ian Storm Taylor](https://ianstormtaylor.com) @@ -20267,7 +20353,7 @@ authors: undefined ****************************** @metamask/transaction-controller -52.3.0 +54.0.0 MIT License Copyright (c) 2018 MetaMask @@ -20293,7 +20379,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE ****************************** @metamask/user-operation-controller -24.0.1 +31.0.0 MIT License Copyright (c) 2023 MetaMask @@ -20340,7 +20426,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ****************************** @metamask/utils -11.2.0 +11.4.0 ISC License Copyright (c) 2022 MetaMask @@ -27735,486 +27821,633 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ****************************** -@solana/web3.js -2.0.0 -Copyright (c) 2023 Solana Labs, Inc +@solana/wallet-standard-chains +1.1.1 -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + 1. Definitions. + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. -****************************** + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. -space-separated-tokens -1.1.5 -(The MIT License) + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. -Copyright (c) 2016 Titus Wormer + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -'Software'), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. -THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. -****************************** + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." -sprintf-js -1.1.3 -Copyright (c) 2007-present, Alexandru Mărășteanu -All rights reserved. + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: -* Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. -* Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. -* Neither the name of this software nor the names of its contributors may be - used to endorse or promote products derived from this software without - specific prior written permission. + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: -****************************** + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and -@spruceid/siwe-parser -2.1.0 -license: Apache-2.0 -authors: Spruce Systems Inc. + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and -****************************** + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and -@spruceid/siwe-parser -2.1.2 -license: Apache-2.0 -authors: Spruce Systems Inc. + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. -****************************** + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. -@stablelib/binary -1.0.1 -This software is licensed under the MIT license: + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. -Copyright (C) 2016 Dmitry Chestnykh + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies -of the Software, and to permit persons to whom the Software is furnished to do -so, subject to the following conditions: + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + END OF TERMS AND CONDITIONS -****************************** + APPENDIX: How to apply the Apache License to your work. -@stablelib/int -1.0.1 -This software is licensed under the MIT license: + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. -Copyright (C) 2016 Dmitry Chestnykh + Copyright [yyyy] [name of copyright owner] -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies -of the Software, and to permit persons to whom the Software is furnished to do -so, subject to the following conditions: + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. + http://www.apache.org/licenses/LICENSE-2.0 -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. ****************************** -@stablelib/random -1.0.2 -This software is licensed under the MIT license: - -Copyright (C) 2016 Dmitry Chestnykh +@solana/wallet-standard-features +1.3.0 -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies -of the Software, and to permit persons to whom the Software is furnished to do -so, subject to the following conditions: + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. + 1. Definitions. + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. -****************************** + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. -@stablelib/wipe -1.0.1 -This software is licensed under the MIT license: + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. -Copyright (C) 2016 Dmitry Chestnykh + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies -of the Software, and to permit persons to whom the Software is furnished to do -so, subject to the following conditions: + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. -****************************** + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." -stop-iteration-iterator -1.0.0 -MIT License + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. -Copyright (c) 2023 Jordan Harband + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and -****************************** + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and -stream-browserify -3.0.0 -MIT License + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. -Copyright (c) James Halliday + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -the Software, and to permit persons to whom the Software is furnished to do so, -subject to the following conditions: + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. -****************************** + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. -stream-splicer -2.0.0 -This software is released under the MIT license: + END OF TERMS AND CONDITIONS -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -the Software, and to permit persons to whom the Software is furnished to do so, -subject to the following conditions: + APPENDIX: How to apply the Apache License to your work. -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + Copyright [yyyy] [name of copyright owner] + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at -****************************** + http://www.apache.org/licenses/LICENSE-2.0 -streamx -2.15.1 -The MIT License (MIT) + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. -Copyright (c) 2019 Mathias Buus -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: +****************************** -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. +@solana/web3.js +2.0.0 +Copyright (c) 2023 Solana Labs, Inc -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. -****************************** +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -string_decoder -1.1.1 -Node.js is licensed for use as follows: -""" -Copyright Node.js contributors. All rights reserved. +****************************** -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to -deal in the Software without restriction, including without limitation the -rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -sell copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: +space-separated-tokens +1.1.5 +(The MIT License) -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. +Copyright (c) 2016 Titus Wormer -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -IN THE SOFTWARE. -""" +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: -This license applies to parts of Node.js originating from the -https://github.com/joyent/node repository: +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. -""" -Copyright Joyent, Inc. and other Node contributors. All rights reserved. -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to -deal in the Software without restriction, including without limitation the -rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -sell copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -IN THE SOFTWARE. -""" +****************************** + +sprintf-js +1.1.3 +Copyright (c) 2007-present, Alexandru Mărășteanu +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: +* Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. +* Neither the name of this software nor the names of its contributors may be + used to endorse or promote products derived from this software without + specific prior written permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ****************************** -string_decoder -1.3.0 -Node.js is licensed for use as follows: +@spruceid/siwe-parser +2.1.0 +license: Apache-2.0 +authors: Spruce Systems Inc. -""" -Copyright Node.js contributors. All rights reserved. +****************************** -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to -deal in the Software without restriction, including without limitation the -rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -sell copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: +@spruceid/siwe-parser +2.1.2 +license: Apache-2.0 +authors: Spruce Systems Inc. -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. +****************************** -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -IN THE SOFTWARE. -""" +@stablelib/binary +1.0.1 +This software is licensed under the MIT license: -This license applies to parts of Node.js originating from the -https://github.com/joyent/node repository: +Copyright (C) 2016 Dmitry Chestnykh -""" -Copyright Joyent, Inc. and other Node contributors. All rights reserved. -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to -deal in the Software without restriction, including without limitation the -rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -sell copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -IN THE SOFTWARE. -""" - +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. ****************************** -string-width -4.2.3 -MIT License +@stablelib/int +1.0.1 +This software is licensed under the MIT license: -Copyright (c) Sindre Sorhus (sindresorhus.com) +Copyright (C) 2016 Dmitry Chestnykh -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. ****************************** -strip-ansi -6.0.1 -MIT License +@stablelib/random +1.0.2 +This software is licensed under the MIT license: -Copyright (c) Sindre Sorhus (sindresorhus.com) +Copyright (C) 2016 Dmitry Chestnykh -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. ****************************** -strip-hex-prefix -1.0.0 -The MIT License +@stablelib/wipe +1.0.1 +This software is licensed under the MIT license: -Copyright (c) 2016 Nick Dodson. nickdodson.com +Copyright (C) 2016 Dmitry Chestnykh -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. ****************************** -strnum -1.0.5 +stop-iteration-iterator +1.0.0 MIT License -Copyright (c) 2021 Natural Intelligence +Copyright (c) 2023 Jordan Harband Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -28237,54 +28470,61 @@ SOFTWARE. ****************************** -style-to-object -0.3.0 -The MIT License (MIT) - -Copyright (c) 2017 Menglin "Mark" Xu - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. +stream-browserify +3.0.0 +MIT License -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +Copyright (c) James Halliday +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: -****************************** +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. -supports-color -7.1.0 -MIT License +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -Copyright (c) Sindre Sorhus (sindresorhus.com) -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: +****************************** -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +stream-splicer +2.0.0 +This software is released under the MIT license: -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ****************************** -supports-preserve-symlinks-flag -1.0.0 -MIT License +streamx +2.15.1 +The MIT License (MIT) -Copyright (c) 2022 Inspect JS +Copyright (c) 2019 Mathias Buus Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -28293,242 +28533,284 @@ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. ****************************** -@swc/core -1.4.11 - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ +string_decoder +1.1.1 +Node.js is licensed for use as follows: -TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION +""" +Copyright Node.js contributors. All rights reserved. -1. Definitions. +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to +deal in the Software without restriction, including without limitation the +rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +sell copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +IN THE SOFTWARE. +""" - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. +This license applies to parts of Node.js originating from the +https://github.com/joyent/node repository: - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. +""" +Copyright Joyent, Inc. and other Node contributors. All rights reserved. +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to +deal in the Software without restriction, including without limitation the +rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +sell copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +IN THE SOFTWARE. +""" - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." +****************************** - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. +string_decoder +1.3.0 +Node.js is licensed for use as follows: -2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. +""" +Copyright Node.js contributors. All rights reserved. -3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to +deal in the Software without restriction, including without limitation the +rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +sell copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: -4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +IN THE SOFTWARE. +""" - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and +This license applies to parts of Node.js originating from the +https://github.com/joyent/node repository: - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and +""" +Copyright Joyent, Inc. and other Node contributors. All rights reserved. +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to +deal in the Software without restriction, including without limitation the +rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +sell copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +IN THE SOFTWARE. +""" -5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. -6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. -7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. +****************************** -8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. +string-width +4.2.3 +MIT License -9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. +Copyright (c) Sindre Sorhus (sindresorhus.com) -END OF TERMS AND CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: -APPENDIX: How to apply the Apache License to your work. +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -Copyright [yyyy] [name of copyright owner] -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at +****************************** - http://www.apache.org/licenses/LICENSE-2.0 +strip-ansi +6.0.1 +MIT License + +Copyright (c) Sindre Sorhus (sindresorhus.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. ****************************** -@swc/core-linux-x64-gnu -1.4.11 -license: Apache-2.0 AND MIT -authors: ź°•ė™ģœ¤ +strip-hex-prefix +1.0.0 +The MIT License + +Copyright (c) 2016 Nick Dodson. nickdodson.com + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + ****************************** -@swc/counter -0.1.3 -license: Apache-2.0 -authors: ź°•ė™ģœ¤ +strnum +1.0.5 +MIT License + +Copyright (c) 2021 Natural Intelligence + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + ****************************** -@swc/types -0.1.12 +style-to-object +0.3.0 +The MIT License (MIT) + +Copyright (c) 2017 Menglin "Mark" Xu + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +supports-color +7.1.0 +MIT License + +Copyright (c) Sindre Sorhus (sindresorhus.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +****************************** + +supports-preserve-symlinks-flag +1.0.0 +MIT License + +Copyright (c) 2022 Inspect JS + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +@swc/core +1.4.11 Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ @@ -28733,55 +29015,275 @@ limitations under the License. ****************************** -tar-stream -3.1.7 -The MIT License (MIT) - -Copyright (c) 2014 Mathias Buus - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. +@swc/core-linux-x64-gnu +1.4.11 +license: Apache-2.0 AND MIT +authors: ź°•ė™ģœ¤ ****************************** -through -2.3.8 -Apache License, Version 2.0 +@swc/counter +0.1.3 +license: Apache-2.0 +authors: ź°•ė™ģœ¤ -Copyright (c) 2011 Dominic Tarr +****************************** -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at +@swc/types +0.1.12 + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ - http://www.apache.org/licenses/LICENSE-2.0 +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. +1. Definitions. + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. -****************************** + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. -tiny-invariant -1.3.3 + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +****************************** + +tar-stream +3.1.7 +The MIT License (MIT) + +Copyright (c) 2014 Mathias Buus + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +****************************** + +through +2.3.8 +Apache License, Version 2.0 + +Copyright (c) 2011 Dominic Tarr + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + + +****************************** + +tiny-invariant +1.3.3 MIT License Copyright (c) 2019 Alexander Reardon @@ -31222,6 +31724,630 @@ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +****************************** + +@wallet-standard/base +1.1.0 + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + +****************************** + +@wallet-standard/features +1.1.0 + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + +****************************** + +@wallet-standard/wallet +1.1.0 + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + ****************************** warning diff --git a/builds.yml b/builds.yml index 701e522c1246..5effddba8656 100644 --- a/builds.yml +++ b/builds.yml @@ -18,6 +18,7 @@ buildTypes: features: - build-main - keyring-snaps + - multi-srp # Additional env variables that are specific to this build env: - INFURA_PROD_PROJECT_ID @@ -27,7 +28,7 @@ buildTypes: - ALLOW_LOCAL_SNAPS: false - REQUIRE_SNAPS_ALLOWLIST: true - REJECT_INVALID_SNAPS_PLATFORM_VERSION: true - - IFRAME_EXECUTION_ENVIRONMENT_URL: https://execution.metamask.io/iframe/7.1.0/index.html + - IFRAME_EXECUTION_ENVIRONMENT_URL: https://execution.metamask.io/iframe/7.2.1/index.html - ACCOUNT_SNAPS_DIRECTORY_URL: https://snaps.metamask.io/account-management - EVM_MULTICHAIN_ENABLED: false # Main build uses the default browser manifest @@ -55,9 +56,10 @@ buildTypes: - ALLOW_LOCAL_SNAPS: false - REQUIRE_SNAPS_ALLOWLIST: true - REJECT_INVALID_SNAPS_PLATFORM_VERSION: true - - IFRAME_EXECUTION_ENVIRONMENT_URL: https://execution.metamask.io/iframe/7.1.0/index.html + - IFRAME_EXECUTION_ENVIRONMENT_URL: https://execution.metamask.io/iframe/7.2.1/index.html - ACCOUNT_SNAPS_DIRECTORY_URL: https://snaps.metamask.io/account-management - EVM_MULTICHAIN_ENABLED: false + - MULTICHAIN_API: true # Modifies how the version is displayed. # eg. instead of 10.25.0 -> 10.25.0-beta.2 isPrerelease: true @@ -83,7 +85,7 @@ buildTypes: - ALLOW_LOCAL_SNAPS: true - REQUIRE_SNAPS_ALLOWLIST: false - REJECT_INVALID_SNAPS_PLATFORM_VERSION: false - - IFRAME_EXECUTION_ENVIRONMENT_URL: https://execution.metamask.io/iframe/7.1.0/index.html + - IFRAME_EXECUTION_ENVIRONMENT_URL: https://execution.metamask.io/iframe/7.2.1/index.html - SUPPORT_LINK: https://support.metamask.io/ - SUPPORT_REQUEST_LINK: https://support.metamask.io/ - INFURA_ENV_KEY_REF: INFURA_FLASK_PROJECT_ID @@ -109,7 +111,7 @@ buildTypes: - ALLOW_LOCAL_SNAPS: false - REQUIRE_SNAPS_ALLOWLIST: true - REJECT_INVALID_SNAPS_PLATFORM_VERSION: true - - IFRAME_EXECUTION_ENVIRONMENT_URL: https://execution.metamask.io/iframe/7.1.0/index.html + - IFRAME_EXECUTION_ENVIRONMENT_URL: https://execution.metamask.io/iframe/7.2.1/index.html - MMI_CONFIGURATION_SERVICE_URL: https://configuration.metamask-institutional.io/v2/configuration/default - SUPPORT_LINK: https://support.metamask-institutional.io - SUPPORT_REQUEST_LINK: https://support.metamask-institutional.io @@ -352,3 +354,12 @@ env: # Public key used to verify EIP-7702 contract address signatures set in LaunchDarkly. ### - EIP_7702_PUBLIC_KEY: '0x3c7a1cCCe462e96D186B8ca9a1BCB2010C3dABa3' + + # URL of transaction relay API + - TRANSACTION_RELAY_API_URL: null + + # Address of DelegationManager smart contract + - DELEGATION_MANAGER_ADDRESS: null + + # Address of enforcer used for gasless EIP-7702 transactions + - GASLESS_7702_ENFORCER_ADDRESS: null diff --git a/development/circular-deps.jsonc b/development/circular-deps.jsonc index a2c13191c67e..cacbfc2e603d 100644 --- a/development/circular-deps.jsonc +++ b/development/circular-deps.jsonc @@ -60,34 +60,6 @@ "ui/components/app/metamask-translation/index.js", "ui/components/app/metamask-translation/metamask-translation.js" ], - [ - "ui/components/app/metamask-template-renderer/metamask-template-renderer.js", - "ui/components/app/metamask-template-renderer/safe-component-list.js", - "ui/components/app/snaps/snap-ui-renderer/index.js", - "ui/components/app/snaps/snap-ui-renderer/snap-ui-renderer.js", - "ui/components/multichain/create-named-snap-account/create-named-snap-account.tsx", - "ui/components/multichain/create-named-snap-account/index.js", - "ui/components/multichain/index.js", - "ui/components/multichain/notification-detail-block-explorer-button/index.ts", - "ui/components/multichain/notification-detail-block-explorer-button/notification-detail-block-explorer-button.tsx", - "ui/components/multichain/notification-detail-button/index.ts", - "ui/components/multichain/notification-detail-button/notification-detail-button.tsx", - "ui/pages/notifications/notification-components/index.ts", - "ui/pages/notifications/notification-components/snap/snap.tsx" - ], - [ - "ui/components/app/metamask-template-renderer/metamask-template-renderer.js", - "ui/components/app/metamask-template-renderer/safe-component-list.js", - "ui/components/app/snaps/snap-ui-renderer/index.js", - "ui/components/app/snaps/snap-ui-renderer/snap-ui-renderer.js", - "ui/components/multichain/index.js", - "ui/components/multichain/notification-detail-block-explorer-button/index.ts", - "ui/components/multichain/notification-detail-block-explorer-button/notification-detail-block-explorer-button.tsx", - "ui/components/multichain/notification-detail-button/index.ts", - "ui/components/multichain/notification-detail-button/notification-detail-button.tsx", - "ui/pages/notifications/notification-components/index.ts", - "ui/pages/notifications/notification-components/snap/snap.tsx" - ], [ "ui/components/app/permission-page-container/index.js", "ui/components/app/permission-page-container/permission-page-container.component.js", @@ -258,96 +230,6 @@ "ui/components/multichain/edit-networks-modal/index.js", "ui/components/multichain/index.js" ], - [ - "ui/components/multichain/index.js", - "ui/components/multichain/notification-detail-block-explorer-button/index.ts", - "ui/components/multichain/notification-detail-block-explorer-button/notification-detail-block-explorer-button.tsx", - "ui/components/multichain/notification-detail-button/index.ts", - "ui/components/multichain/notification-detail-button/notification-detail-button.tsx", - "ui/pages/notifications/notification-components/erc1155-sent-received/erc1155-sent-received.tsx", - "ui/pages/notifications/notification-components/index.ts" - ], - [ - "ui/components/multichain/index.js", - "ui/components/multichain/notification-detail-block-explorer-button/index.ts", - "ui/components/multichain/notification-detail-block-explorer-button/notification-detail-block-explorer-button.tsx", - "ui/components/multichain/notification-detail-button/index.ts", - "ui/components/multichain/notification-detail-button/notification-detail-button.tsx", - "ui/pages/notifications/notification-components/erc20-sent-received/erc20-sent-received.tsx", - "ui/pages/notifications/notification-components/index.ts" - ], - [ - "ui/components/multichain/index.js", - "ui/components/multichain/notification-detail-block-explorer-button/index.ts", - "ui/components/multichain/notification-detail-block-explorer-button/notification-detail-block-explorer-button.tsx", - "ui/components/multichain/notification-detail-button/index.ts", - "ui/components/multichain/notification-detail-button/notification-detail-button.tsx", - "ui/pages/notifications/notification-components/erc721-sent-received/erc721-sent-received.tsx", - "ui/pages/notifications/notification-components/index.ts" - ], - [ - "ui/components/multichain/index.js", - "ui/components/multichain/notification-detail-block-explorer-button/index.ts", - "ui/components/multichain/notification-detail-block-explorer-button/notification-detail-block-explorer-button.tsx", - "ui/components/multichain/notification-detail-button/index.ts", - "ui/components/multichain/notification-detail-button/notification-detail-button.tsx", - "ui/pages/notifications/notification-components/eth-sent-received/eth-sent-received.tsx", - "ui/pages/notifications/notification-components/index.ts" - ], - [ - "ui/components/multichain/index.js", - "ui/components/multichain/notification-detail-block-explorer-button/index.ts", - "ui/components/multichain/notification-detail-block-explorer-button/notification-detail-block-explorer-button.tsx", - "ui/components/multichain/notification-detail-button/index.ts", - "ui/components/multichain/notification-detail-button/notification-detail-button.tsx", - "ui/pages/notifications/notification-components/feature-announcement/feature-announcement.tsx", - "ui/pages/notifications/notification-components/index.ts" - ], - [ - "ui/components/multichain/index.js", - "ui/components/multichain/notification-detail-block-explorer-button/index.ts", - "ui/components/multichain/notification-detail-block-explorer-button/notification-detail-block-explorer-button.tsx", - "ui/components/multichain/notification-detail-button/index.ts", - "ui/components/multichain/notification-detail-button/notification-detail-button.tsx", - "ui/pages/notifications/notification-components/index.ts", - "ui/pages/notifications/notification-components/lido-stake-ready-to-be-withdrawn/lido-stake-ready-to-be-withdrawn.tsx" - ], - [ - "ui/components/multichain/index.js", - "ui/components/multichain/notification-detail-block-explorer-button/index.ts", - "ui/components/multichain/notification-detail-block-explorer-button/notification-detail-block-explorer-button.tsx", - "ui/components/multichain/notification-detail-button/index.ts", - "ui/components/multichain/notification-detail-button/notification-detail-button.tsx", - "ui/pages/notifications/notification-components/index.ts", - "ui/pages/notifications/notification-components/lido-withdrawal-requested/lido-withdrawal-requested.tsx" - ], - [ - "ui/components/multichain/index.js", - "ui/components/multichain/notification-detail-block-explorer-button/index.ts", - "ui/components/multichain/notification-detail-block-explorer-button/notification-detail-block-explorer-button.tsx", - "ui/components/multichain/notification-detail-button/index.ts", - "ui/components/multichain/notification-detail-button/notification-detail-button.tsx", - "ui/pages/notifications/notification-components/index.ts", - "ui/pages/notifications/notification-components/snap/snap.tsx" - ], - [ - "ui/components/multichain/index.js", - "ui/components/multichain/notification-detail-block-explorer-button/index.ts", - "ui/components/multichain/notification-detail-block-explorer-button/notification-detail-block-explorer-button.tsx", - "ui/components/multichain/notification-detail-button/index.ts", - "ui/components/multichain/notification-detail-button/notification-detail-button.tsx", - "ui/pages/notifications/notification-components/index.ts", - "ui/pages/notifications/notification-components/stake/stake.tsx" - ], - [ - "ui/components/multichain/index.js", - "ui/components/multichain/notification-detail-block-explorer-button/index.ts", - "ui/components/multichain/notification-detail-block-explorer-button/notification-detail-block-explorer-button.tsx", - "ui/components/multichain/notification-detail-button/index.ts", - "ui/components/multichain/notification-detail-button/notification-detail-button.tsx", - "ui/pages/notifications/notification-components/index.ts", - "ui/pages/notifications/notification-components/swap-completed/swap-completed.tsx" - ], ["ui/ducks/alerts/unconnected-account.js", "ui/store/actions.ts"], [ "ui/ducks/confirm-transaction/confirm-transaction.duck.js", diff --git a/development/metamaskbot-build-announce.ts b/development/metamaskbot-build-announce.ts index 3fbe6a418710..a47d5149f6d6 100644 --- a/development/metamaskbot-build-announce.ts +++ b/development/metamaskbot-build-announce.ts @@ -1,4 +1,3 @@ -import { execFileSync } from 'child_process'; import startCase from 'lodash/startCase'; import { version as VERSION } from '../package.json'; @@ -70,6 +69,9 @@ async function start(): Promise { chrome: `${BUILD_LINK_BASE}/builds/metamask-chrome-${VERSION}.zip`, firefox: `${BUILD_LINK_BASE}/builds-mv2/metamask-firefox-${VERSION}.zip`, }, + 'builds (beta)': { + chrome: `${HOST_URL}/builds-beta/metamask-beta-chrome-${VERSION}-beta.0.zip`, + }, 'builds (flask)': { chrome: `${BUILD_LINK_BASE}/builds-flask/metamask-flask-chrome-${VERSION}-flask.0.zip`, firefox: `${BUILD_LINK_BASE}/builds-flask-mv2/metamask-flask-firefox-${VERSION}-flask.0.zip`, @@ -84,27 +86,6 @@ async function start(): Promise { }, }; - const commitMessage = execFileSync('git', [ - 'show', - '-s', - '--format=%s', - HEAD_COMMIT_HASH, - ]) - .toString() - .trim(); - - const betaVersionRegex = /Version v[0-9]+\.[0-9]+\.[0-9]+-beta\.[0-9]+/u; - const betaMatch = commitMessage.match(betaVersionRegex); - - // only include beta build link if a beta version is detected in the commit message - if (betaMatch) { - const betaVersion = betaMatch[0].split('-beta.')[1]; - console.log(`Beta version ${betaVersion} detected, adding beta build link`); - buildMap['builds (beta)'] = { - chrome: `${HOST_URL}/builds-beta/metamask-beta-chrome-${VERSION}-beta.${betaVersion}.zip`, - }; - } - const buildContentRows = Object.entries(buildMap).map(([label, builds]) => { const buildLinks = Object.entries(builds).map(([platform, url]) => { return `${platform}`; diff --git a/lavamoat/browserify/beta/policy.json b/lavamoat/browserify/beta/policy.json index 16e1e2664228..cba5b9ba435f 100644 --- a/lavamoat/browserify/beta/policy.json +++ b/lavamoat/browserify/beta/policy.json @@ -1191,6 +1191,26 @@ "crypto": true } }, + "@metamask/chain-agnostic-permission": { + "packages": { + "@metamask/chain-agnostic-permission>@metamask/api-specs": true, + "@metamask/controller-utils": true, + "@metamask/permission-controller": true, + "@metamask/rpc-errors": true, + "@metamask/utils": true, + "lodash": true + } + }, + "@metamask/multichain-api-middleware>@metamask/chain-agnostic-permission": { + "packages": { + "@metamask/multichain-api-middleware>@metamask/api-specs": true, + "@metamask/controller-utils": true, + "@metamask/permission-controller": true, + "@metamask/rpc-errors": true, + "@metamask/utils": true, + "lodash": true + } + }, "@metamask/controller-utils": { "globals": { "URL": true, @@ -1266,7 +1286,7 @@ "@metamask/eth-json-rpc-provider": true, "@metamask/json-rpc-engine": true, "@metamask/rpc-errors": true, - "@metamask/network-controller>@metamask/eth-json-rpc-infura>@metamask/utils": true + "@metamask/utils": true } }, "@metamask/eth-json-rpc-middleware": { @@ -1316,7 +1336,8 @@ "document.createElement": true, "document.head.appendChild": true, "fetch": true, - "removeEventListener": true + "removeEventListener": true, + "setTimeout": true }, "packages": { "@metamask/eth-ledger-bridge-keyring>@ethereumjs/rlp": true, @@ -1468,13 +1489,14 @@ "globals": { "URL": true, "console.error": true, - "console.info": true + "console.info": true, + "console.warn": true }, "packages": { "@ethereumjs/tx": true, "@metamask/eth-snap-keyring>@metamask/eth-sig-util": true, "@metamask/keyring-api": true, - "@metamask/eth-snap-keyring>@metamask/keyring-internal-snap-client": true, + "@metamask/keyring-internal-snap-client": true, "@metamask/keyring-api>@metamask/keyring-utils": true, "@metamask/utils>@metamask/superstruct": true, "@metamask/utils": true, @@ -1650,7 +1672,7 @@ "@metamask/keyring-controller>ulid": true } }, - "@metamask/eth-snap-keyring>@metamask/keyring-internal-snap-client": { + "@metamask/keyring-internal-snap-client": { "packages": { "@metamask/keyring-snap-client": true } @@ -1658,7 +1680,7 @@ "@metamask/keyring-snap-client": { "packages": { "@metamask/keyring-api": true, - "@metamask/keyring-snap-client>@metamask/keyring-utils": true, + "@metamask/keyring-api>@metamask/keyring-utils": true, "@metamask/utils>@metamask/superstruct": true, "@metamask/keyring-snap-client>uuid": true } @@ -1673,16 +1695,6 @@ "bitcoin-address-validation": true } }, - "@metamask/keyring-snap-client>@metamask/keyring-utils": { - "globals": { - "URL": true - }, - "packages": { - "@metamask/utils>@metamask/superstruct": true, - "@metamask/utils": true, - "bitcoin-address-validation": true - } - }, "@metamask/logging-controller": { "packages": { "@metamask/base-controller": true, @@ -1713,12 +1725,13 @@ "uuid": true } }, - "@metamask/multichain": { + "@metamask/multichain-api-middleware": { "globals": { "console.error": true }, "packages": { - "@metamask/multichain>@metamask/api-specs": true, + "@metamask/multichain-api-middleware>@metamask/api-specs": true, + "@metamask/multichain-api-middleware>@metamask/chain-agnostic-permission": true, "@metamask/controller-utils": true, "@metamask/eth-json-rpc-filters": true, "@metamask/json-rpc-engine": true, @@ -1727,8 +1740,7 @@ "@metamask/safe-event-emitter": true, "@metamask/utils": true, "@open-rpc/schema-utils-js": true, - "@metamask/multichain>jsonschema": true, - "lodash": true + "@metamask/message-manager>jsonschema": true } }, "@metamask/multichain-network-controller": { @@ -1918,6 +1930,18 @@ "uuid": true } }, + "@metamask/user-operation-controller>@metamask/polling-controller": { + "globals": { + "clearTimeout": true, + "console.error": true, + "setTimeout": true + }, + "packages": { + "@metamask/base-controller": true, + "@metamask/snaps-utils>fast-json-stable-stringify": true, + "uuid": true + } + }, "@metamask/post-message-stream": { "globals": { "MessageEvent.prototype": true, @@ -2081,7 +2105,7 @@ "@metamask/utils": true, "browserify>buffer": true, "webpack>events": true, - "@metamask/multichain>jsonschema": true, + "@metamask/message-manager>jsonschema": true, "uuid": true } }, @@ -2216,6 +2240,7 @@ "@metamask/snaps-utils>cron-parser": true, "@metamask/snaps-utils>fast-json-stable-stringify": true, "@metamask/snaps-utils>fast-xml-parser": true, + "luxon": true, "@metamask/snaps-utils>marked": true, "@metamask/snaps-utils>rfdc": true, "semver": true, @@ -2369,7 +2394,7 @@ "@metamask/controller-utils": true, "@metamask/controller-utils>@metamask/eth-query": true, "@metamask/gas-fee-controller": true, - "@metamask/polling-controller": true, + "@metamask/user-operation-controller>@metamask/polling-controller": true, "@metamask/rpc-errors": true, "@metamask/utils>@metamask/superstruct": true, "@metamask/transaction-controller": true, @@ -2440,21 +2465,6 @@ "semver": true } }, - "@metamask/network-controller>@metamask/eth-json-rpc-infura>@metamask/utils": { - "globals": { - "TextDecoder": true, - "TextEncoder": true - }, - "packages": { - "@metamask/utils>@metamask/superstruct": true, - "@noble/hashes": true, - "@metamask/utils>@scure/base": true, - "browserify>buffer": true, - "nock>debug": true, - "@metamask/utils>pony-cause": true, - "semver": true - } - }, "@metamask/network-controller>@metamask/eth-json-rpc-middleware>@metamask/utils": { "globals": { "TextDecoder": true, @@ -4393,7 +4403,7 @@ "define": true } }, - "@metamask/multichain>jsonschema": { + "@metamask/message-manager>jsonschema": { "packages": { "browserify>url": true } diff --git a/lavamoat/browserify/flask/policy.json b/lavamoat/browserify/flask/policy.json index 16e1e2664228..cba5b9ba435f 100644 --- a/lavamoat/browserify/flask/policy.json +++ b/lavamoat/browserify/flask/policy.json @@ -1191,6 +1191,26 @@ "crypto": true } }, + "@metamask/chain-agnostic-permission": { + "packages": { + "@metamask/chain-agnostic-permission>@metamask/api-specs": true, + "@metamask/controller-utils": true, + "@metamask/permission-controller": true, + "@metamask/rpc-errors": true, + "@metamask/utils": true, + "lodash": true + } + }, + "@metamask/multichain-api-middleware>@metamask/chain-agnostic-permission": { + "packages": { + "@metamask/multichain-api-middleware>@metamask/api-specs": true, + "@metamask/controller-utils": true, + "@metamask/permission-controller": true, + "@metamask/rpc-errors": true, + "@metamask/utils": true, + "lodash": true + } + }, "@metamask/controller-utils": { "globals": { "URL": true, @@ -1266,7 +1286,7 @@ "@metamask/eth-json-rpc-provider": true, "@metamask/json-rpc-engine": true, "@metamask/rpc-errors": true, - "@metamask/network-controller>@metamask/eth-json-rpc-infura>@metamask/utils": true + "@metamask/utils": true } }, "@metamask/eth-json-rpc-middleware": { @@ -1316,7 +1336,8 @@ "document.createElement": true, "document.head.appendChild": true, "fetch": true, - "removeEventListener": true + "removeEventListener": true, + "setTimeout": true }, "packages": { "@metamask/eth-ledger-bridge-keyring>@ethereumjs/rlp": true, @@ -1468,13 +1489,14 @@ "globals": { "URL": true, "console.error": true, - "console.info": true + "console.info": true, + "console.warn": true }, "packages": { "@ethereumjs/tx": true, "@metamask/eth-snap-keyring>@metamask/eth-sig-util": true, "@metamask/keyring-api": true, - "@metamask/eth-snap-keyring>@metamask/keyring-internal-snap-client": true, + "@metamask/keyring-internal-snap-client": true, "@metamask/keyring-api>@metamask/keyring-utils": true, "@metamask/utils>@metamask/superstruct": true, "@metamask/utils": true, @@ -1650,7 +1672,7 @@ "@metamask/keyring-controller>ulid": true } }, - "@metamask/eth-snap-keyring>@metamask/keyring-internal-snap-client": { + "@metamask/keyring-internal-snap-client": { "packages": { "@metamask/keyring-snap-client": true } @@ -1658,7 +1680,7 @@ "@metamask/keyring-snap-client": { "packages": { "@metamask/keyring-api": true, - "@metamask/keyring-snap-client>@metamask/keyring-utils": true, + "@metamask/keyring-api>@metamask/keyring-utils": true, "@metamask/utils>@metamask/superstruct": true, "@metamask/keyring-snap-client>uuid": true } @@ -1673,16 +1695,6 @@ "bitcoin-address-validation": true } }, - "@metamask/keyring-snap-client>@metamask/keyring-utils": { - "globals": { - "URL": true - }, - "packages": { - "@metamask/utils>@metamask/superstruct": true, - "@metamask/utils": true, - "bitcoin-address-validation": true - } - }, "@metamask/logging-controller": { "packages": { "@metamask/base-controller": true, @@ -1713,12 +1725,13 @@ "uuid": true } }, - "@metamask/multichain": { + "@metamask/multichain-api-middleware": { "globals": { "console.error": true }, "packages": { - "@metamask/multichain>@metamask/api-specs": true, + "@metamask/multichain-api-middleware>@metamask/api-specs": true, + "@metamask/multichain-api-middleware>@metamask/chain-agnostic-permission": true, "@metamask/controller-utils": true, "@metamask/eth-json-rpc-filters": true, "@metamask/json-rpc-engine": true, @@ -1727,8 +1740,7 @@ "@metamask/safe-event-emitter": true, "@metamask/utils": true, "@open-rpc/schema-utils-js": true, - "@metamask/multichain>jsonschema": true, - "lodash": true + "@metamask/message-manager>jsonschema": true } }, "@metamask/multichain-network-controller": { @@ -1918,6 +1930,18 @@ "uuid": true } }, + "@metamask/user-operation-controller>@metamask/polling-controller": { + "globals": { + "clearTimeout": true, + "console.error": true, + "setTimeout": true + }, + "packages": { + "@metamask/base-controller": true, + "@metamask/snaps-utils>fast-json-stable-stringify": true, + "uuid": true + } + }, "@metamask/post-message-stream": { "globals": { "MessageEvent.prototype": true, @@ -2081,7 +2105,7 @@ "@metamask/utils": true, "browserify>buffer": true, "webpack>events": true, - "@metamask/multichain>jsonschema": true, + "@metamask/message-manager>jsonschema": true, "uuid": true } }, @@ -2216,6 +2240,7 @@ "@metamask/snaps-utils>cron-parser": true, "@metamask/snaps-utils>fast-json-stable-stringify": true, "@metamask/snaps-utils>fast-xml-parser": true, + "luxon": true, "@metamask/snaps-utils>marked": true, "@metamask/snaps-utils>rfdc": true, "semver": true, @@ -2369,7 +2394,7 @@ "@metamask/controller-utils": true, "@metamask/controller-utils>@metamask/eth-query": true, "@metamask/gas-fee-controller": true, - "@metamask/polling-controller": true, + "@metamask/user-operation-controller>@metamask/polling-controller": true, "@metamask/rpc-errors": true, "@metamask/utils>@metamask/superstruct": true, "@metamask/transaction-controller": true, @@ -2440,21 +2465,6 @@ "semver": true } }, - "@metamask/network-controller>@metamask/eth-json-rpc-infura>@metamask/utils": { - "globals": { - "TextDecoder": true, - "TextEncoder": true - }, - "packages": { - "@metamask/utils>@metamask/superstruct": true, - "@noble/hashes": true, - "@metamask/utils>@scure/base": true, - "browserify>buffer": true, - "nock>debug": true, - "@metamask/utils>pony-cause": true, - "semver": true - } - }, "@metamask/network-controller>@metamask/eth-json-rpc-middleware>@metamask/utils": { "globals": { "TextDecoder": true, @@ -4393,7 +4403,7 @@ "define": true } }, - "@metamask/multichain>jsonschema": { + "@metamask/message-manager>jsonschema": { "packages": { "browserify>url": true } diff --git a/lavamoat/browserify/main/policy.json b/lavamoat/browserify/main/policy.json index 16e1e2664228..cba5b9ba435f 100644 --- a/lavamoat/browserify/main/policy.json +++ b/lavamoat/browserify/main/policy.json @@ -1191,6 +1191,26 @@ "crypto": true } }, + "@metamask/chain-agnostic-permission": { + "packages": { + "@metamask/chain-agnostic-permission>@metamask/api-specs": true, + "@metamask/controller-utils": true, + "@metamask/permission-controller": true, + "@metamask/rpc-errors": true, + "@metamask/utils": true, + "lodash": true + } + }, + "@metamask/multichain-api-middleware>@metamask/chain-agnostic-permission": { + "packages": { + "@metamask/multichain-api-middleware>@metamask/api-specs": true, + "@metamask/controller-utils": true, + "@metamask/permission-controller": true, + "@metamask/rpc-errors": true, + "@metamask/utils": true, + "lodash": true + } + }, "@metamask/controller-utils": { "globals": { "URL": true, @@ -1266,7 +1286,7 @@ "@metamask/eth-json-rpc-provider": true, "@metamask/json-rpc-engine": true, "@metamask/rpc-errors": true, - "@metamask/network-controller>@metamask/eth-json-rpc-infura>@metamask/utils": true + "@metamask/utils": true } }, "@metamask/eth-json-rpc-middleware": { @@ -1316,7 +1336,8 @@ "document.createElement": true, "document.head.appendChild": true, "fetch": true, - "removeEventListener": true + "removeEventListener": true, + "setTimeout": true }, "packages": { "@metamask/eth-ledger-bridge-keyring>@ethereumjs/rlp": true, @@ -1468,13 +1489,14 @@ "globals": { "URL": true, "console.error": true, - "console.info": true + "console.info": true, + "console.warn": true }, "packages": { "@ethereumjs/tx": true, "@metamask/eth-snap-keyring>@metamask/eth-sig-util": true, "@metamask/keyring-api": true, - "@metamask/eth-snap-keyring>@metamask/keyring-internal-snap-client": true, + "@metamask/keyring-internal-snap-client": true, "@metamask/keyring-api>@metamask/keyring-utils": true, "@metamask/utils>@metamask/superstruct": true, "@metamask/utils": true, @@ -1650,7 +1672,7 @@ "@metamask/keyring-controller>ulid": true } }, - "@metamask/eth-snap-keyring>@metamask/keyring-internal-snap-client": { + "@metamask/keyring-internal-snap-client": { "packages": { "@metamask/keyring-snap-client": true } @@ -1658,7 +1680,7 @@ "@metamask/keyring-snap-client": { "packages": { "@metamask/keyring-api": true, - "@metamask/keyring-snap-client>@metamask/keyring-utils": true, + "@metamask/keyring-api>@metamask/keyring-utils": true, "@metamask/utils>@metamask/superstruct": true, "@metamask/keyring-snap-client>uuid": true } @@ -1673,16 +1695,6 @@ "bitcoin-address-validation": true } }, - "@metamask/keyring-snap-client>@metamask/keyring-utils": { - "globals": { - "URL": true - }, - "packages": { - "@metamask/utils>@metamask/superstruct": true, - "@metamask/utils": true, - "bitcoin-address-validation": true - } - }, "@metamask/logging-controller": { "packages": { "@metamask/base-controller": true, @@ -1713,12 +1725,13 @@ "uuid": true } }, - "@metamask/multichain": { + "@metamask/multichain-api-middleware": { "globals": { "console.error": true }, "packages": { - "@metamask/multichain>@metamask/api-specs": true, + "@metamask/multichain-api-middleware>@metamask/api-specs": true, + "@metamask/multichain-api-middleware>@metamask/chain-agnostic-permission": true, "@metamask/controller-utils": true, "@metamask/eth-json-rpc-filters": true, "@metamask/json-rpc-engine": true, @@ -1727,8 +1740,7 @@ "@metamask/safe-event-emitter": true, "@metamask/utils": true, "@open-rpc/schema-utils-js": true, - "@metamask/multichain>jsonschema": true, - "lodash": true + "@metamask/message-manager>jsonschema": true } }, "@metamask/multichain-network-controller": { @@ -1918,6 +1930,18 @@ "uuid": true } }, + "@metamask/user-operation-controller>@metamask/polling-controller": { + "globals": { + "clearTimeout": true, + "console.error": true, + "setTimeout": true + }, + "packages": { + "@metamask/base-controller": true, + "@metamask/snaps-utils>fast-json-stable-stringify": true, + "uuid": true + } + }, "@metamask/post-message-stream": { "globals": { "MessageEvent.prototype": true, @@ -2081,7 +2105,7 @@ "@metamask/utils": true, "browserify>buffer": true, "webpack>events": true, - "@metamask/multichain>jsonschema": true, + "@metamask/message-manager>jsonschema": true, "uuid": true } }, @@ -2216,6 +2240,7 @@ "@metamask/snaps-utils>cron-parser": true, "@metamask/snaps-utils>fast-json-stable-stringify": true, "@metamask/snaps-utils>fast-xml-parser": true, + "luxon": true, "@metamask/snaps-utils>marked": true, "@metamask/snaps-utils>rfdc": true, "semver": true, @@ -2369,7 +2394,7 @@ "@metamask/controller-utils": true, "@metamask/controller-utils>@metamask/eth-query": true, "@metamask/gas-fee-controller": true, - "@metamask/polling-controller": true, + "@metamask/user-operation-controller>@metamask/polling-controller": true, "@metamask/rpc-errors": true, "@metamask/utils>@metamask/superstruct": true, "@metamask/transaction-controller": true, @@ -2440,21 +2465,6 @@ "semver": true } }, - "@metamask/network-controller>@metamask/eth-json-rpc-infura>@metamask/utils": { - "globals": { - "TextDecoder": true, - "TextEncoder": true - }, - "packages": { - "@metamask/utils>@metamask/superstruct": true, - "@noble/hashes": true, - "@metamask/utils>@scure/base": true, - "browserify>buffer": true, - "nock>debug": true, - "@metamask/utils>pony-cause": true, - "semver": true - } - }, "@metamask/network-controller>@metamask/eth-json-rpc-middleware>@metamask/utils": { "globals": { "TextDecoder": true, @@ -4393,7 +4403,7 @@ "define": true } }, - "@metamask/multichain>jsonschema": { + "@metamask/message-manager>jsonschema": { "packages": { "browserify>url": true } diff --git a/lavamoat/browserify/mmi/policy.json b/lavamoat/browserify/mmi/policy.json index c3a6a72aa2ec..7772266cab6b 100644 --- a/lavamoat/browserify/mmi/policy.json +++ b/lavamoat/browserify/mmi/policy.json @@ -1322,6 +1322,26 @@ "crypto": true } }, + "@metamask/chain-agnostic-permission": { + "packages": { + "@metamask/chain-agnostic-permission>@metamask/api-specs": true, + "@metamask/controller-utils": true, + "@metamask/permission-controller": true, + "@metamask/rpc-errors": true, + "@metamask/utils": true, + "lodash": true + } + }, + "@metamask/multichain-api-middleware>@metamask/chain-agnostic-permission": { + "packages": { + "@metamask/multichain-api-middleware>@metamask/api-specs": true, + "@metamask/controller-utils": true, + "@metamask/permission-controller": true, + "@metamask/rpc-errors": true, + "@metamask/utils": true, + "lodash": true + } + }, "@metamask/controller-utils": { "globals": { "URL": true, @@ -1397,7 +1417,7 @@ "@metamask/eth-json-rpc-provider": true, "@metamask/json-rpc-engine": true, "@metamask/rpc-errors": true, - "@metamask/network-controller>@metamask/eth-json-rpc-infura>@metamask/utils": true + "@metamask/utils": true } }, "@metamask/eth-json-rpc-middleware": { @@ -1447,7 +1467,8 @@ "document.createElement": true, "document.head.appendChild": true, "fetch": true, - "removeEventListener": true + "removeEventListener": true, + "setTimeout": true }, "packages": { "@metamask/eth-ledger-bridge-keyring>@ethereumjs/rlp": true, @@ -1599,13 +1620,14 @@ "globals": { "URL": true, "console.error": true, - "console.info": true + "console.info": true, + "console.warn": true }, "packages": { "@ethereumjs/tx": true, "@metamask/eth-snap-keyring>@metamask/eth-sig-util": true, "@metamask/keyring-api": true, - "@metamask/eth-snap-keyring>@metamask/keyring-internal-snap-client": true, + "@metamask/keyring-internal-snap-client": true, "@metamask/keyring-api>@metamask/keyring-utils": true, "@metamask/utils>@metamask/superstruct": true, "@metamask/utils": true, @@ -1781,7 +1803,7 @@ "@metamask/keyring-controller>ulid": true } }, - "@metamask/eth-snap-keyring>@metamask/keyring-internal-snap-client": { + "@metamask/keyring-internal-snap-client": { "packages": { "@metamask/keyring-snap-client": true } @@ -1789,7 +1811,7 @@ "@metamask/keyring-snap-client": { "packages": { "@metamask/keyring-api": true, - "@metamask/keyring-snap-client>@metamask/keyring-utils": true, + "@metamask/keyring-api>@metamask/keyring-utils": true, "@metamask/utils>@metamask/superstruct": true, "@metamask/keyring-snap-client>uuid": true } @@ -1804,16 +1826,6 @@ "bitcoin-address-validation": true } }, - "@metamask/keyring-snap-client>@metamask/keyring-utils": { - "globals": { - "URL": true - }, - "packages": { - "@metamask/utils>@metamask/superstruct": true, - "@metamask/utils": true, - "bitcoin-address-validation": true - } - }, "@metamask/logging-controller": { "packages": { "@metamask/base-controller": true, @@ -1844,12 +1856,13 @@ "uuid": true } }, - "@metamask/multichain": { + "@metamask/multichain-api-middleware": { "globals": { "console.error": true }, "packages": { - "@metamask/multichain>@metamask/api-specs": true, + "@metamask/multichain-api-middleware>@metamask/api-specs": true, + "@metamask/multichain-api-middleware>@metamask/chain-agnostic-permission": true, "@metamask/controller-utils": true, "@metamask/eth-json-rpc-filters": true, "@metamask/json-rpc-engine": true, @@ -1858,8 +1871,7 @@ "@metamask/safe-event-emitter": true, "@metamask/utils": true, "@open-rpc/schema-utils-js": true, - "@metamask/multichain>jsonschema": true, - "lodash": true + "@metamask/message-manager>jsonschema": true } }, "@metamask/multichain-network-controller": { @@ -2049,6 +2061,18 @@ "uuid": true } }, + "@metamask/user-operation-controller>@metamask/polling-controller": { + "globals": { + "clearTimeout": true, + "console.error": true, + "setTimeout": true + }, + "packages": { + "@metamask/base-controller": true, + "@metamask/snaps-utils>fast-json-stable-stringify": true, + "uuid": true + } + }, "@metamask/post-message-stream": { "globals": { "MessageEvent.prototype": true, @@ -2212,7 +2236,7 @@ "@metamask/utils": true, "browserify>buffer": true, "webpack>events": true, - "@metamask/multichain>jsonschema": true, + "@metamask/message-manager>jsonschema": true, "uuid": true } }, @@ -2347,6 +2371,7 @@ "@metamask/snaps-utils>cron-parser": true, "@metamask/snaps-utils>fast-json-stable-stringify": true, "@metamask/snaps-utils>fast-xml-parser": true, + "luxon": true, "@metamask/snaps-utils>marked": true, "@metamask/snaps-utils>rfdc": true, "semver": true, @@ -2500,7 +2525,7 @@ "@metamask/controller-utils": true, "@metamask/controller-utils>@metamask/eth-query": true, "@metamask/gas-fee-controller": true, - "@metamask/polling-controller": true, + "@metamask/user-operation-controller>@metamask/polling-controller": true, "@metamask/rpc-errors": true, "@metamask/utils>@metamask/superstruct": true, "@metamask/transaction-controller": true, @@ -2571,21 +2596,6 @@ "semver": true } }, - "@metamask/network-controller>@metamask/eth-json-rpc-infura>@metamask/utils": { - "globals": { - "TextDecoder": true, - "TextEncoder": true - }, - "packages": { - "@metamask/utils>@metamask/superstruct": true, - "@noble/hashes": true, - "@metamask/utils>@scure/base": true, - "browserify>buffer": true, - "nock>debug": true, - "@metamask/utils>pony-cause": true, - "semver": true - } - }, "@metamask/network-controller>@metamask/eth-json-rpc-middleware>@metamask/utils": { "globals": { "TextDecoder": true, @@ -4524,7 +4534,7 @@ "define": true } }, - "@metamask/multichain>jsonschema": { + "@metamask/message-manager>jsonschema": { "packages": { "browserify>url": true } diff --git a/package.json b/package.json index 8f82e7c08e49..4efed994ec6c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "metamask-crx", - "version": "12.16.2", + "version": "12.17.0", "private": true, "repository": { "type": "git", @@ -36,7 +36,7 @@ "build:test:flask:mv2": "ENABLE_MV3=false yarn build:test:flask", "build:test:mmi": "yarn build:test --build-type mmi", "build:test:mv2": "ENABLE_MV3=false BLOCKAID_FILE_CDN=static.cx.metamask.io/api/v1/confirmations/ppom yarn build:test", - "build:test:webpack": "BLOCKAID_FILE_CDN=static.cx.metamask.io/api/v1/confirmations/ppom yarn env:e2e webpack --test --browser=chrome --no-cache --lockdown --sentry --snow", + "build:test:webpack": "BLOCKAID_FILE_CDN=static.cx.metamask.io/api/v1/confirmations/ppom yarn env:e2e webpack --test --browser=chrome --browser=firefox --no-cache --lockdown --sentry --snow", "test": "yarn lint && yarn test:unit", "dapp": "node development/static-server.js node_modules/@metamask/test-dapp/dist --port 8080", "dapp-multichain": "node development/static-server.js node_modules/@metamask/test-dapp-multichain/build --port 8080", @@ -187,7 +187,7 @@ "semver@7.3.7": "^7.5.4", "semver@7.3.8": "^7.5.4", "lavamoat-core@npm:^16.2.2": "patch:lavamoat-core@npm%3A16.2.2#~/.yarn/patches/lavamoat-core-npm-16.2.2-e361ff1f8a.patch", - "@metamask/snaps-sdk": "^6.21.0", + "@metamask/snaps-sdk": "^6.22.0", "@swc/types@0.1.5": "^0.1.6", "@babel/core": "patch:@babel/core@npm%3A7.25.9#~/.yarn/patches/@babel-core-npm-7.25.9-4ae3bff7f3.patch", "@babel/runtime": "patch:@babel/runtime@npm%3A7.25.9#~/.yarn/patches/@babel-runtime-npm-7.25.9-fe8c62510a.patch", @@ -254,7 +254,7 @@ "@metamask-institutional/transaction-update": "^0.2.6", "@metamask-institutional/types": "^1.2.0", "@metamask/abi-utils": "^2.0.2", - "@metamask/account-watcher": "^4.1.2", + "@metamask/account-watcher": "^4.1.3", "@metamask/accounts-controller": "^26.0.0", "@metamask/address-book-controller": "^6.0.3", "@metamask/announcement-controller": "^7.0.3", @@ -264,34 +264,38 @@ "@metamask/bitcoin-wallet-snap": "^0.9.0", "@metamask/bridge-controller": "^11.0.0", "@metamask/browser-passworder": "^4.3.0", + "@metamask/chain-agnostic-permission": "^0.3.0", "@metamask/contract-metadata": "^2.5.0", "@metamask/controller-utils": "^11.4.0", - "@metamask/design-tokens": "^5.1.0", + "@metamask/design-tokens": "^7.0.0", "@metamask/ens-controller": "^15.0.2", "@metamask/ens-resolver-snap": "^0.1.2", "@metamask/eth-json-rpc-filters": "^9.0.0", "@metamask/eth-json-rpc-middleware": "^17.0.0", - "@metamask/eth-ledger-bridge-keyring": "^11.0.0", + "@metamask/eth-ledger-bridge-keyring": "^11.0.3", "@metamask/eth-sig-util": "^7.0.1", - "@metamask/eth-snap-keyring": "^12.0.0", + "@metamask/eth-snap-keyring": "^12.1.1", "@metamask/eth-token-tracker": "^10.0.2", "@metamask/eth-trezor-keyring": "^8.0.0", "@metamask/etherscan-link": "^3.0.0", "@metamask/gas-fee-controller": "^22.0.3", + "@metamask/institutional-wallet-snap": "1.3.1", "@metamask/jazzicon": "^2.0.0", "@metamask/json-rpc-engine": "^10.0.0", "@metamask/json-rpc-middleware-stream": "^8.0.4", - "@metamask/keyring-api": "^17.2.1", - "@metamask/keyring-controller": "^21.0.3", - "@metamask/keyring-internal-api": "^6.0.0", - "@metamask/keyring-snap-client": "^4.0.1", + "@metamask/keyring-api": "^17.5.0", + "@metamask/keyring-controller": "^21.0.4", + "@metamask/keyring-internal-api": "^6.0.1", + "@metamask/keyring-internal-snap-client": "^4.0.1", + "@metamask/keyring-snap-client": "^4.1.0", "@metamask/logging-controller": "^6.0.4", "@metamask/logo": "^4.0.0", "@metamask/message-manager": "^12.0.1", "@metamask/message-signing-snap": "^0.6.0", "@metamask/metamask-eth-abis": "^3.1.1", - "@metamask/multichain": "^3.0.0", - "@metamask/multichain-network-controller": "^0.1.0", + "@metamask/multichain-api-client": "^0.2.0", + "@metamask/multichain-api-middleware": "^0.1.1", + "@metamask/multichain-network-controller": "^0.4.0", "@metamask/multichain-transactions-controller": "^0.7.2", "@metamask/name-controller": "^8.0.3", "@metamask/network-controller": "patch:@metamask/network-controller@npm%3A22.1.1#~/.yarn/patches/@metamask-network-controller-npm-22.1.1-09b6510f1e.patch", @@ -305,8 +309,8 @@ "@metamask/post-message-stream": "^9.0.0", "@metamask/ppom-validator": "0.36.0", "@metamask/preinstalled-example-snap": "^0.3.0", - "@metamask/profile-sync-controller": "^10.1.0", - "@metamask/providers": "^20.0.0", + "@metamask/profile-sync-controller": "^11.0.1", + "@metamask/providers": "^21.0.0", "@metamask/queued-request-controller": "^7.0.1", "@metamask/rate-limit-controller": "^6.0.3", "@metamask/remote-feature-flag-controller": "^1.6.0", @@ -316,14 +320,15 @@ "@metamask/selected-network-controller": "^19.0.0", "@metamask/signature-controller": "patch:@metamask/signature-controller@npm%3A26.0.0#~/.yarn/patches/@metamask-signature-controller-npm-26.0.0-ecbc8b6cda.patch", "@metamask/smart-transactions-controller": "^16.3.1", - "@metamask/snaps-controllers": "^11.1.0", - "@metamask/snaps-execution-environments": "^7.1.0", - "@metamask/snaps-rpc-methods": "^12.0.0", - "@metamask/snaps-sdk": "^6.21.0", - "@metamask/snaps-utils": "^9.1.0", - "@metamask/solana-wallet-snap": "^1.15.1", - "@metamask/transaction-controller": "patch:@metamask/transaction-controller@npm%3A52.3.0#~/.yarn/patches/@metamask-transaction-controller-npm-52.3.0-56fc57fbe6.patch", - "@metamask/user-operation-controller": "^24.0.1", + "@metamask/snaps-controllers": "^11.2.2", + "@metamask/snaps-execution-environments": "^7.2.1", + "@metamask/snaps-rpc-methods": "^12.1.0", + "@metamask/snaps-sdk": "^6.22.0", + "@metamask/snaps-utils": "^9.2.0", + "@metamask/solana-wallet-snap": "^1.24.0", + "@metamask/solana-wallet-standard": "^0.1.1", + "@metamask/transaction-controller": "patch:@metamask/transaction-controller@npm%3A54.0.0#~/.yarn/patches/@metamask-transaction-controller-npm-54.0.0-ccc4668363.patch", + "@metamask/user-operation-controller": "^31.0.0", "@metamask/utils": "^11.1.0", "@ngraveio/bc-ur": "^1.1.13", "@noble/hashes": "^1.3.3", @@ -427,8 +432,8 @@ "@lavamoat/allow-scripts": "^3.3.1", "@lavamoat/lavadome-core": "0.0.20", "@lavamoat/lavapack": "^7.0.5", - "@lydell/node-pty": "^1.0.1", - "@metamask/api-specs": "^0.11.0", + "@lydell/node-pty": "^1.1.0", + "@metamask/api-specs": "^0.13.0", "@metamask/auto-changelog": "^2.1.0", "@metamask/build-utils": "^3.0.0", "@metamask/eslint-config": "^9.0.0", diff --git a/privacy-snapshot.json b/privacy-snapshot.json index 0bb27ab20a5b..6e853aa76080 100644 --- a/privacy-snapshot.json +++ b/privacy-snapshot.json @@ -6,7 +6,9 @@ "api.lens.dev", "api.segment.io", "api.simplehash.com", + "api.testnet.solana.com", "api.web3modal.com", + "api.web3modal.org", "app.ens.domains", "arbitrum-mainnet.infura.io", "authentication.api.cx.metamask.io", @@ -84,6 +86,5 @@ "unresponsive-rpc.url", "user-storage.api.cx.metamask.io", "verify.walletconnect.com", - "www.4byte.directory", - "api.web3modal.org" + "www.4byte.directory" ] diff --git a/shared/constants/bridge.ts b/shared/constants/bridge.ts index 7bdc87a758e2..fb817cf68710 100644 --- a/shared/constants/bridge.ts +++ b/shared/constants/bridge.ts @@ -52,24 +52,24 @@ export const NETWORK_TO_SHORT_NETWORK_NAME_MAP: Record< string > = { [CHAIN_IDS.MAINNET]: 'Ethereum', + [toEvmCaipChainId(CHAIN_IDS.MAINNET)]: 'Ethereum', [CHAIN_IDS.LINEA_MAINNET]: 'Linea', - [CHAIN_IDS.POLYGON]: NETWORK_TO_NAME_MAP[CHAIN_IDS.POLYGON], - [CHAIN_IDS.AVALANCHE]: 'Avalanche', - [CHAIN_IDS.BSC]: NETWORK_TO_NAME_MAP[CHAIN_IDS.BSC], - [CHAIN_IDS.ARBITRUM]: NETWORK_TO_NAME_MAP[CHAIN_IDS.ARBITRUM], - [CHAIN_IDS.OPTIMISM]: NETWORK_TO_NAME_MAP[CHAIN_IDS.OPTIMISM], - [CHAIN_IDS.ZKSYNC_ERA]: 'ZkSync Era', - [CHAIN_IDS.BASE]: 'Base', - [toEvmCaipChainId(CHAIN_IDS.BASE)]: 'Base', [toEvmCaipChainId(CHAIN_IDS.LINEA_MAINNET)]: 'Linea', + [CHAIN_IDS.POLYGON]: NETWORK_TO_NAME_MAP[CHAIN_IDS.POLYGON], [toEvmCaipChainId(CHAIN_IDS.POLYGON)]: NETWORK_TO_NAME_MAP[CHAIN_IDS.POLYGON], + [CHAIN_IDS.AVALANCHE]: 'Avalanche', [toEvmCaipChainId(CHAIN_IDS.AVALANCHE)]: 'Avalanche', + [CHAIN_IDS.BSC]: NETWORK_TO_NAME_MAP[CHAIN_IDS.BSC], [toEvmCaipChainId(CHAIN_IDS.BSC)]: NETWORK_TO_NAME_MAP[CHAIN_IDS.BSC], + [CHAIN_IDS.ARBITRUM]: NETWORK_TO_NAME_MAP[CHAIN_IDS.ARBITRUM], [toEvmCaipChainId(CHAIN_IDS.ARBITRUM)]: NETWORK_TO_NAME_MAP[CHAIN_IDS.ARBITRUM], + [CHAIN_IDS.OPTIMISM]: NETWORK_TO_NAME_MAP[CHAIN_IDS.OPTIMISM], [toEvmCaipChainId(CHAIN_IDS.OPTIMISM)]: NETWORK_TO_NAME_MAP[CHAIN_IDS.OPTIMISM], + [CHAIN_IDS.ZKSYNC_ERA]: 'ZkSync Era', [toEvmCaipChainId(CHAIN_IDS.ZKSYNC_ERA)]: 'ZkSync Era', + [CHAIN_IDS.BASE]: 'Base', [toEvmCaipChainId(CHAIN_IDS.BASE)]: 'Base', ///: BEGIN:ONLY_INCLUDE_IF(solana-swaps) [MultichainNetworks.SOLANA]: 'Solana', diff --git a/shared/constants/multichain/assets.ts b/shared/constants/multichain/assets.ts index 58e0869ff045..00e8b9095058 100644 --- a/shared/constants/multichain/assets.ts +++ b/shared/constants/multichain/assets.ts @@ -1,4 +1,4 @@ -import { CaipAssetType } from '@metamask/keyring-api'; +import { CaipAssetType, CaipChainId } from '@metamask/keyring-api'; import { MultichainNetworks } from './networks'; export const MULTICHAIN_NATIVE_CURRENCY_TO_CAIP19 = { @@ -20,7 +20,7 @@ export enum MultichainNativeAssets { * Each network is mapped to an array containing its native asset for consistency. */ export const MULTICHAIN_NETWORK_TO_ASSET_TYPES: Record< - MultichainNetworks, + CaipChainId, CaipAssetType[] > = { [MultichainNetworks.SOLANA]: [MultichainNativeAssets.SOLANA], @@ -30,4 +30,4 @@ export const MULTICHAIN_NETWORK_TO_ASSET_TYPES: Record< [MultichainNetworks.BITCOIN_TESTNET]: [ MultichainNativeAssets.BITCOIN_TESTNET, ], -}; +} as const; diff --git a/shared/constants/multichain/networks.ts b/shared/constants/multichain/networks.ts index ee1b7c0907da..349f39e28333 100644 --- a/shared/constants/multichain/networks.ts +++ b/shared/constants/multichain/networks.ts @@ -1,5 +1,10 @@ import { CaipChainId } from '@metamask/utils'; -import { BtcAccountType, SolAccountType } from '@metamask/keyring-api'; +import { + BtcAccountType, + SolAccountType, + BtcScope, + SolScope, +} from '@metamask/keyring-api'; import { isBtcMainnetAddress, isBtcTestnetAddress, @@ -34,14 +39,27 @@ export type MultichainProviderConfig = ProviderConfigWithImageUrl & { export type MultichainNetworkIds = `${MultichainNetworks}`; export enum MultichainNetworks { - BITCOIN = 'bip122:000000000019d6689c085ae165831e93', - BITCOIN_TESTNET = 'bip122:000000000933ea01ad0ee984209779ba', + BITCOIN = BtcScope.Mainnet, + BITCOIN_TESTNET = BtcScope.Testnet, + BITCOIN_SIGNET = BtcScope.Signet, - SOLANA = 'solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp', - SOLANA_DEVNET = 'solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1', - SOLANA_TESTNET = 'solana:4uhcVJyU9pJkvQyS88uRDiswHXSCkY3z', + SOLANA = SolScope.Mainnet, + SOLANA_DEVNET = SolScope.Devnet, + SOLANA_TESTNET = SolScope.Testnet, } +// TODO: This data should be provided by the snap +export const MULTICHAIN_NETWORK_TO_ACCOUNT_TYPE_NAME: Record< + CaipChainId, + string +> = { + [BtcScope.Mainnet]: 'Bitcoin', + [BtcScope.Testnet]: 'Bitcoin testnet', + [SolScope.Mainnet]: 'Solana', + [SolScope.Testnet]: 'Solana', + [SolScope.Devnet]: 'Solana', +} as const; + export const MULTICHAIN_ACCOUNT_TYPE_TO_MAINNET = { [BtcAccountType.P2wpkh]: MultichainNetworks.BITCOIN, [SolAccountType.DataAccount]: MultichainNetworks.SOLANA, @@ -49,16 +67,20 @@ export const MULTICHAIN_ACCOUNT_TYPE_TO_MAINNET = { export const MULTICHAIN_NETWORK_TO_NICKNAME: Record = { [MultichainNetworks.BITCOIN]: 'Bitcoin', - [MultichainNetworks.BITCOIN_TESTNET]: 'Bitcoin (testnet)', + [MultichainNetworks.BITCOIN_TESTNET]: 'Bitcoin Testnet', + [MultichainNetworks.BITCOIN_SIGNET]: 'Bitcoin Signet', [MultichainNetworks.SOLANA]: 'Solana', - [MultichainNetworks.SOLANA_DEVNET]: 'Solana (devnet)', - [MultichainNetworks.SOLANA_TESTNET]: 'Solana (testnet)', -}; + [MultichainNetworks.SOLANA_DEVNET]: 'Solana Devnet', + [MultichainNetworks.SOLANA_TESTNET]: 'Solana Testnet', +} as const; +// TODO: This data should be provided by the snap export const BITCOIN_TOKEN_IMAGE_URL = './images/bitcoin-logo.svg'; export const BITCOIN_TESTNET_TOKEN_IMAGE_URL = './images/bitcoin-testnet-logo.svg'; export const SOLANA_TOKEN_IMAGE_URL = './images/solana-logo.svg'; +export const SOLANA_TESTNET_IMAGE_URL = './images/solana-testnet-logo.svg'; +export const SOLANA_DEVNET_IMAGE_URL = './images/solana-devnet-logo.svg'; export const BITCOIN_BLOCK_EXPLORER_URL = 'https://mempool.space'; export const SOLANA_BLOCK_EXPLORER_URL = 'https://solscan.io'; @@ -99,8 +121,15 @@ export const MULTICHAIN_TOKEN_IMAGE_MAP: Record = { [MultichainNetworks.BITCOIN]: BITCOIN_TOKEN_IMAGE_URL, [MultichainNetworks.BITCOIN_TESTNET]: BITCOIN_TESTNET_TOKEN_IMAGE_URL, [MultichainNetworks.SOLANA]: SOLANA_TOKEN_IMAGE_URL, + [MultichainNetworks.SOLANA_DEVNET]: SOLANA_DEVNET_IMAGE_URL, + [MultichainNetworks.SOLANA_TESTNET]: SOLANA_TESTNET_IMAGE_URL, } as const; +/** + * @deprecated MULTICHAIN_PROVIDER_CONFIGS is deprecated and will be removed in the future. + * Use the data from @metamask/multichain-network-controller. + * Useful selectors in selectors/multichain/networks.ts. + */ export const MULTICHAIN_PROVIDER_CONFIGS: Record< CaipChainId, MultichainProviderConfig diff --git a/shared/constants/network.ts b/shared/constants/network.ts index c6442e60f3ff..13201d7e42ae 100644 --- a/shared/constants/network.ts +++ b/shared/constants/network.ts @@ -4,7 +4,8 @@ import type { } from '@metamask/network-controller'; import { RpcEndpointType } from '@metamask/network-controller'; import { capitalize, pick } from 'lodash'; -import { Hex } from '@metamask/utils'; +import { Hex, hexToNumber } from '@metamask/utils'; +import { MultichainNetworks } from './multichain/networks'; /** * A type representing built-in network types, used as an identifier. @@ -181,7 +182,9 @@ export const CHAIN_IDS = { MODE_SEPOLIA: '0x397', MODE: '0x868b', MEGAETH_TESTNET: '0x18c6', + XRPLEVM_TESTNET: '0x161c28', LENS: '0xe8', + PLUME: '0x18232', } as const; export const CHAINLIST_CHAIN_IDS_MAP = { @@ -252,6 +255,7 @@ export const CHAINLIST_CHAIN_IDS_MAP = { MODE: '0x868b', SHAPE_SEPOLIA: '0x2b03', SHAPE: '0x168', + XRPLEVM_TESTNET: '0x161c28', } as const; // To add a deprecation warning to a network, add it to the array @@ -307,11 +311,14 @@ export const LISK_SEPOLIA_DISPLAY_NAME = 'Lisk Sepolia'; export const INK_SEPOLIA_DISPLAY_NAME = 'Ink Sepolia'; export const INK_DISPLAY_NAME = 'Ink Mainnet'; export const SONEIUM_DISPLAY_NAME = 'Soneium Mainnet'; +export const SONEIUM_TESTNET_DISPLAY_NAME = 'Soneium Minato Testnet'; export const MODE_SEPOLIA_DISPLAY_NAME = 'Mode Sepolia'; export const MODE_DISPLAY_NAME = 'Mode Mainnet'; export const SHAPE_SEPOLIA_DISPLAY_NAME = 'Shape Sepolia'; export const SHAPE_DISPLAY_NAME = 'Shape'; +export const XRPLEVM_TESTNET_DISPLAY_NAME = 'XRPL EVM Testnet'; export const LENS_DISPLAY_NAME = 'Lens'; +export const PLUME_DISPLAY_NAME = 'Plume'; export const infuraProjectId = process.env.INFURA_PROJECT_ID; export const getRpcUrl = ({ @@ -369,6 +376,7 @@ export const CURRENCY_SYMBOLS = { MOONRIVER: 'MOVR', ONE: 'ONE', LENS: 'GHO', + PLUME: 'PLUME', } as const; // Non-EVM currency symbols @@ -444,6 +452,7 @@ const CHAINLIST_CURRENCY_SYMBOLS_MAP = { MODE: 'ETH', SHAPE: 'ETH', SHAPE_SEPOLIA: 'ETH', + XRPLEVM_TESTNET: 'XRP', } as const; export const CHAINLIST_CURRENCY_SYMBOLS_MAP_NETWORK_COLLISION = { @@ -540,8 +549,13 @@ export const SHAPE_SEPOLIA_IMAGE_URL = './images/shape-sepolia.svg'; export const SHAPE_IMAGE_URL = './images/shape.svg'; export const UNICHAIN_IMAGE_URL = './images/unichain.svg'; export const MEGAETH_TESTNET_IMAGE_URL = './images/MegaETH-logo-testnet.png'; +export const SOLANA_IMAGE_URL = './images/solana-logo.svg'; +export const XRPLEVM_TESTNET_IMAGE_URL = './images/xrplevm-testnet.svg'; +export const XRP_TOKEN_IMAGE_URL = './images/xrp-logo.svg'; export const LENS_IMAGE_URL = './images/lens.png'; export const LENS_NATIVE_TOKEN_IMAGE_URL = './images/lens-native.svg'; +export const PLUME_IMAGE_URL = './images/plume.svg'; +export const PLUME_NATIVE_TOKEN_IMAGE_URL = './images/plume-native.svg'; export const INFURA_PROVIDER_TYPES = [ NETWORK_TYPES.MAINNET, @@ -557,6 +571,10 @@ export const TEST_CHAINS: Hex[] = [ CHAIN_IDS.MEGAETH_TESTNET, ]; +export const CAIP_FORMATTED_EVM_TEST_CHAINS = TEST_CHAINS.map( + (chainId) => `eip155:${hexToNumber(chainId)}`, +); + export const MAINNET_CHAINS = [ { chainId: CHAIN_IDS.MAINNET, rpcUrl: MAINNET_RPC_URL }, { chainId: CHAIN_IDS.LINEA_MAINNET, rpcUrl: LINEA_MAINNET_RPC_URL }, @@ -664,6 +682,7 @@ export const NETWORK_TO_NAME_MAP = { [CHAIN_IDS.LISK_SEPOLIA]: LISK_SEPOLIA_DISPLAY_NAME, [CHAIN_IDS.MEGAETH_TESTNET]: MEGAETH_TESTNET_DISPLAY_NAME, [CHAIN_IDS.LENS]: LENS_DISPLAY_NAME, + [CHAIN_IDS.PLUME]: PLUME_DISPLAY_NAME, } as const; export const CHAIN_ID_TO_CURRENCY_SYMBOL_MAP = { @@ -795,6 +814,7 @@ export const CHAIN_ID_TO_CURRENCY_SYMBOL_MAP = { [CHAINLIST_CHAIN_IDS_MAP.MEGAETH_TESTNET]: TEST_NETWORK_TICKER_MAP[NETWORK_TYPES.MEGAETH_TESTNET], [CHAIN_IDS.LENS]: CURRENCY_SYMBOLS.LENS, + [CHAIN_IDS.PLUME]: CURRENCY_SYMBOLS.PLUME, } as const; /** @@ -836,7 +856,7 @@ export const CHAIN_ID_TO_RPC_URL_MAP = { [CHAIN_IDS.MEGAETH_TESTNET]: MEGAETH_TESTNET_RPC_URL, } as const; -export const CHAIN_ID_TO_NETWORK_IMAGE_URL_MAP: Record = { +export const CHAIN_ID_TO_NETWORK_IMAGE_URL_MAP: Record = { [CHAIN_IDS.MAINNET]: ETH_TOKEN_IMAGE_URL, [CHAIN_IDS.LINEA_GOERLI]: LINEA_GOERLI_TOKEN_IMAGE_URL, [CHAIN_IDS.LINEA_SEPOLIA]: LINEA_SEPOLIA_TOKEN_IMAGE_URL, @@ -929,7 +949,10 @@ export const CHAIN_ID_TO_NETWORK_IMAGE_URL_MAP: Record = { [CHAINLIST_CHAIN_IDS_MAP.SHAPE_SEPOLIA]: SHAPE_SEPOLIA_IMAGE_URL, [CHAINLIST_CHAIN_IDS_MAP.UNICHAIN]: UNICHAIN_IMAGE_URL, [CHAINLIST_CHAIN_IDS_MAP.UNICHAIN_SEPOLIA]: UNICHAIN_IMAGE_URL, + [MultichainNetworks.SOLANA]: SOLANA_IMAGE_URL, + [CHAINLIST_CHAIN_IDS_MAP.XRPLEVM_TESTNET]: XRPLEVM_TESTNET_IMAGE_URL, [CHAIN_IDS.LENS]: LENS_IMAGE_URL, + [CHAIN_IDS.PLUME]: PLUME_IMAGE_URL, } as const; export const CHAIN_ID_TO_ETHERS_NETWORK_NAME_MAP = { @@ -981,7 +1004,9 @@ export const CHAIN_ID_TOKEN_IMAGE_MAP = { [CHAINLIST_CHAIN_IDS_MAP.SHAPE_SEPOLIA]: TEST_ETH_TOKEN_IMAGE_URL, [CHAINLIST_CHAIN_IDS_MAP.UNICHAIN]: ETH_TOKEN_IMAGE_URL, [CHAINLIST_CHAIN_IDS_MAP.UNICHAIN_SEPOLIA]: ETH_TOKEN_IMAGE_URL, + [CHAINLIST_CHAIN_IDS_MAP.XRPLEVM_TESTNET]: XRP_TOKEN_IMAGE_URL, [CHAIN_IDS.LENS]: LENS_NATIVE_TOKEN_IMAGE_URL, + [CHAIN_IDS.PLUME]: PLUME_NATIVE_TOKEN_IMAGE_URL, } as const; /** diff --git a/shared/constants/swaps.ts b/shared/constants/swaps.ts index acf47b949349..1babd0067b67 100644 --- a/shared/constants/swaps.ts +++ b/shared/constants/swaps.ts @@ -322,6 +322,7 @@ export enum TokenBucketPriority { export enum Slippage { default = 2, high = 3, + stable = 0.5, } const ETH_USDC_TOKEN_OBJECT = { @@ -435,3 +436,64 @@ export const SWAPS_CHAINID_COMMON_TOKEN_PAIR = { [MultichainNetworks.SOLANA]: SOLANA_USDC_TOKEN_OBJECT, ///: END:ONLY_INCLUDE_IF }; + +export const STABLE_PAIRS: Record = { + [CURRENCY_SYMBOLS.USDC]: true, + [CURRENCY_SYMBOLS.USDT]: true, +}; + +export function isStablePair( + sourceSymbol: string, + destinationSymbol: string, +): boolean { + return STABLE_PAIRS[sourceSymbol] && STABLE_PAIRS[destinationSymbol]; +} + +/** + * A map of chain IDs to sets of known stablecoin contract addresses with deep liquidity. + * Used to determine if a pair qualifies for lower default slippage to avoid frontrunning. + * Just using USDC and USDT for now, but can add more as needed. + */ +export const StablecoinsByChainId: Partial>> = { + [CHAIN_IDS.MAINNET]: new Set([ + '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48', // USDC + '0xdac17f958d2ee523a2206206994597c13d831ec7', // USDT + ]), + [CHAIN_IDS.LINEA_MAINNET]: new Set([ + '0x176211869cA2b568f2A7D4EE941E073a821EE1ff', // USDC + '0xA219439258ca9da29E9Cc4cE5596924745e12B93', // USDT + ]), + [CHAIN_IDS.POLYGON]: new Set([ + '0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359', // USDC + '0x2791bca1f2de4661ed88a30c99a7a9449aa84174', // USDC.e + '0xc2132d05d31c914a87c6611c10748aeb04b58e8f', // USDT + ]), + [CHAIN_IDS.ARBITRUM]: new Set([ + '0xaf88d065e77c8cC2239327C5EDb3A432268e5831', // USDC + '0xFF970A61A04b1cA14834A43f5dE4533eBDDB5CC8', // USDC.e + '0xFd086bC7CD5C481DCC9C85ebE478A1C0b69FCbb9', // USDT + ]), + [CHAIN_IDS.BASE]: new Set([ + '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913', // USDC + ]), + [CHAIN_IDS.OPTIMISM]: new Set([ + '0x0b2C639c533813f4Aa9D7837CAf62653d097Ff85', // USDC + '0x7F5c764cBc14f9669B88837ca1490cCa17c31607', // USDC.e + '0x94b008aA00579c1307B0EF2c499aD98a8ce58e58', // USDT + ]), + [CHAIN_IDS.BSC]: new Set([ + '0x8ac76a51cc950d9822d68b83fe1ad97b32cd580d', // USDC + '0x55d398326f99059ff775485246999027b3197955', // USDT + ]), + [CHAIN_IDS.AVALANCHE]: new Set([ + '0xb97ef9ef8734c71904d8002f8b6bc66dd9c48a6e', // USDC + '0xa7d7079b0fead91f3e65f86e8915cb59c1a4c664', // USDC.e + '0x9702230a8ea53601f5cd2dc00fdbc13d4df4a8c7', // USDT + '0xc7198437980c041c805a1edcba50c1ce5db95118', // USDT.e + ]), + [CHAIN_IDS.ZKSYNC_ERA]: new Set([ + '0x1d17CBcF0D6D143135aE902365D2E5e2A16538D4', // USDC + '0x3355df6D4c9C3035724Fd0e3914dE96A5a83aaf4', // USDC.e + '0x493257fD37EDB34451f62EDf8D2a0C418852bA4C', // USDT + ]), +}; diff --git a/shared/lib/accounts/accounts.ts b/shared/lib/accounts/accounts.ts index a6385a44f5a8..894d6d860ba4 100644 --- a/shared/lib/accounts/accounts.ts +++ b/shared/lib/accounts/accounts.ts @@ -1,4 +1,13 @@ import { InternalAccount } from '@metamask/keyring-internal-api'; +///: BEGIN:ONLY_INCLUDE_IF(solana) +import { SolScope } from '@metamask/keyring-api'; +import { + KeyringInternalSnapClient, + KeyringInternalSnapClientMessenger, +} from '@metamask/keyring-internal-snap-client'; +import { SnapKeyring } from '@metamask/eth-snap-keyring'; +import { SOLANA_WALLET_SNAP_ID } from './solana-wallet-snap'; +///: END:ONLY_INCLUDE_IF /** * Get the next available account name based on the suggestion and the list of @@ -25,3 +34,47 @@ export function getUniqueAccountName( return candidateName; } + +///: BEGIN:ONLY_INCLUDE_IF(solana) +export async function addDiscoveredSolanaAccounts( + controllerMessenger: KeyringInternalSnapClientMessenger, + entropySource: string, + snapKeyring: SnapKeyring, +) { + const snapId = SOLANA_WALLET_SNAP_ID; + const scopes = [SolScope.Mainnet, SolScope.Testnet, SolScope.Devnet]; + const client = new KeyringInternalSnapClient({ + messenger: controllerMessenger, + snapId, + }); + + for (let index = 0; ; index++) { + const discovered = await client.discoverAccounts( + scopes, + entropySource, + index, + ); + + // We stop discovering accounts if none got discovered for that index. + if (discovered.length === 0) { + break; + } + + await Promise.allSettled( + discovered.map(async (discoveredAccount) => { + const options = { + derivationPath: discoveredAccount.derivationPath, + entropySource, + }; + + // TODO: Use `withKeyring` instead of using the keyring directly. + await snapKeyring.createAccount(snapId, options, { + displayConfirmation: false, + displayAccountNameSuggestion: false, + setSelectedAccount: false, + }); + }), + ); + } +} +///: END:ONLY_INCLUDE_IF diff --git a/shared/lib/accounts/index.ts b/shared/lib/accounts/index.ts index 5fcdc110a743..96fd0c377b7b 100644 --- a/shared/lib/accounts/index.ts +++ b/shared/lib/accounts/index.ts @@ -1,4 +1,5 @@ export * from './accounts'; export * from './bitcoin-wallet-snap'; +export * from './institutional-wallet-snap'; export * from './snaps'; export * from './solana-wallet-snap'; diff --git a/shared/lib/accounts/institutional-wallet-snap.ts b/shared/lib/accounts/institutional-wallet-snap.ts new file mode 100644 index 000000000000..9d560647d60a --- /dev/null +++ b/shared/lib/accounts/institutional-wallet-snap.ts @@ -0,0 +1,8 @@ +import { SnapId } from '@metamask/snaps-sdk'; +import InstitutionalWalletSnap from '@metamask/institutional-wallet-snap/dist/preinstalled-snap.json'; + +export const INSTITUTIONAL_WALLET_SNAP_ID: SnapId = + InstitutionalWalletSnap.snapId as SnapId; + +export const INSTITUTIONAL_WALLET_NAME: string = + InstitutionalWalletSnap.manifest.proposedName; diff --git a/shared/lib/accounts/snaps.ts b/shared/lib/accounts/snaps.ts index e1b46e26a395..dd6a0ba442f1 100644 --- a/shared/lib/accounts/snaps.ts +++ b/shared/lib/accounts/snaps.ts @@ -1,6 +1,12 @@ import { SnapId } from '@metamask/snaps-sdk'; -import { BITCOIN_WALLET_SNAP_ID } from './bitcoin-wallet-snap'; +import { + stripSnapPrefix, + getLocalizedSnapManifest, +} from '@metamask/snaps-utils'; +// eslint-disable-next-line import/no-restricted-paths +import { SnapKeyringBuilderMessenger } from '../../../app/scripts/lib/snap-keyring/types'; import { SOLANA_WALLET_SNAP_ID } from './solana-wallet-snap'; +import { BITCOIN_WALLET_SNAP_ID } from './bitcoin-wallet-snap'; /** * A constant array that contains the IDs of whitelisted multichain @@ -21,3 +27,33 @@ const WHITELISTED_SNAPS = [BITCOIN_WALLET_SNAP_ID, SOLANA_WALLET_SNAP_ID]; export function isMultichainWalletSnap(id: SnapId): boolean { return WHITELISTED_SNAPS.includes(id); } + +/** + * Get the localized Snap name or some fallback name otherwise. + * + * @param snapId - Snap ID. + * @param messenger - Snap keyring messenger. + * @returns The Snap name. + */ +export function getSnapName( + snapId: SnapId, + messenger: SnapKeyringBuilderMessenger, +) { + const { currentLocale } = messenger.call('PreferencesController:getState'); + const snap = messenger.call('SnapController:get', snapId); + + if (!snap) { + return stripSnapPrefix(snapId); + } + + if (snap.localizationFiles) { + const localizedManifest = getLocalizedSnapManifest( + snap.manifest, + currentLocale, + snap.localizationFiles, + ); + return localizedManifest.proposedName; + } + + return snap.manifest.proposedName; +} diff --git a/shared/lib/asset-utils.test.ts b/shared/lib/asset-utils.test.ts index 24f7fcaf3b6c..d0369244abc4 100644 --- a/shared/lib/asset-utils.test.ts +++ b/shared/lib/asset-utils.test.ts @@ -7,6 +7,7 @@ import { import { toEvmCaipChainId } from '@metamask/multichain-network-controller'; import { MultichainNetwork } from '@metamask/multichain-transactions-controller'; import { toHex } from '@metamask/controller-utils'; +import { getNativeAssetForChainId } from '@metamask/bridge-controller'; import { MINUTE } from '../constants/time'; import { MultichainNetworks } from '../constants/multichain/networks'; import fetchWithCache from './fetch-with-cache'; @@ -21,6 +22,10 @@ describe('asset-utils', () => { const TOKEN_API_V3_BASE_URL = 'https://tokens.api.cx.metamask.io/v3'; describe('toAssetId', () => { + beforeEach(() => { + jest.clearAllMocks(); + }); + it('should return the same asset ID if input is already a CAIP asset type', () => { const caipAssetId = CaipAssetTypeStruct.create('eip155:1/erc20:0x123'); const chainId = 'eip155:1' as CaipChainId; @@ -29,12 +34,49 @@ describe('asset-utils', () => { expect(result).toBe(caipAssetId); }); + it('should return native asset ID for native EVM address', () => { + const nativeAddress = '0x0000000000000000000000000000000000000000'; + const chainId = 'eip155:1' as CaipChainId; + + const result = toAssetId(nativeAddress, chainId); + expect(result).toBe(getNativeAssetForChainId(chainId).assetId); + expect(CaipAssetTypeStruct.validate(result)).toStrictEqual([ + undefined, + result, + ]); + }); + + it('should return native asset ID for null EVM address', () => { + const nativeAddress = null; + const chainId = 'eip155:1' as CaipChainId; + + const result = toAssetId(nativeAddress as never, chainId); + expect(result).toBe(getNativeAssetForChainId(chainId).assetId); + expect(CaipAssetTypeStruct.validate(result)).toStrictEqual([ + undefined, + result, + ]); + }); + + it('should return undefined if getNativeAssetForChainId throws an error', () => { + const nativeAddress = '0x0000000000000000000000000000000000000000'; + const chainId = 'eip155:1231' as CaipChainId; + + expect(() => toAssetId(nativeAddress, chainId)).toThrow( + 'No XChain Swaps native asset found for chainId: eip155:1231', + ); + }); + it('should create Solana token asset ID correctly', () => { const address = 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v'; const chainId = MultichainNetwork.Solana as CaipChainId; const result = toAssetId(address, chainId); expect(result).toBe(`${MultichainNetwork.Solana}/token:${address}`); + expect(CaipAssetTypeStruct.validate(result)).toStrictEqual([ + undefined, + result, + ]); }); it('should create EVM token asset ID correctly', () => { @@ -43,6 +85,10 @@ describe('asset-utils', () => { const result = toAssetId(address, chainId); expect(result).toBe(`eip155:1/erc20:${address}`); + expect(CaipAssetTypeStruct.validate(result)).toStrictEqual([ + undefined, + result, + ]); }); it('should return undefined for non-hex address on EVM chains', () => { @@ -59,6 +105,10 @@ describe('asset-utils', () => { const result = toAssetId(address, chainId); expect(result).toBe(`eip155:137/erc20:${address}`); + expect(CaipAssetTypeStruct.validate(result)).toStrictEqual([ + undefined, + result, + ]); }); it('should handle checksummed addresses', () => { @@ -67,6 +117,10 @@ describe('asset-utils', () => { const result = toAssetId(address, chainId); expect(result).toBe(`eip155:1/erc20:${address}`); + expect(CaipAssetTypeStruct.validate(result)).toStrictEqual([ + undefined, + result, + ]); }); }); diff --git a/shared/lib/asset-utils.ts b/shared/lib/asset-utils.ts index 1623e497f617..455e0c27534b 100644 --- a/shared/lib/asset-utils.ts +++ b/shared/lib/asset-utils.ts @@ -13,6 +13,10 @@ import { import { toEvmCaipChainId } from '@metamask/multichain-network-controller'; import { MultichainNetwork } from '@metamask/multichain-transactions-controller'; import { toHex } from '@metamask/controller-utils'; +import { + getNativeAssetForChainId, + isNativeAddress, +} from '@metamask/bridge-controller'; import { MINUTE } from '../constants/time'; import { decimalToPrefixedHex } from '../modules/conversion.utils'; import fetchWithCache from './fetch-with-cache'; @@ -26,7 +30,11 @@ export const toAssetId = ( ): CaipAssetType | undefined => { if (isCaipAssetType(address)) { return address; - } else if (chainId === MultichainNetwork.Solana) { + } + if (isNativeAddress(address)) { + return getNativeAssetForChainId(chainId)?.assetId as CaipAssetType; + } + if (chainId === MultichainNetwork.Solana) { return CaipAssetTypeStruct.create(`${chainId}/token:${address}`); } // EVM assets diff --git a/shared/lib/bridge-status/utils.ts b/shared/lib/bridge-status/utils.ts index 849d20f971c6..50e93a1a7c8f 100644 --- a/shared/lib/bridge-status/utils.ts +++ b/shared/lib/bridge-status/utils.ts @@ -1,4 +1,5 @@ import type { QuoteMetadata, QuoteResponse } from '@metamask/bridge-controller'; +import { TransactionStatus } from '@metamask/transaction-controller'; import { QuoteMetadataSerialized, StatusRequest, @@ -73,6 +74,66 @@ export const serializeQuoteMetadata = ( }; }; +/** + * Internal type defining the relevant parts of a transaction object + * needed for bridge status utility functions. + */ +type BridgeTransaction = { + isBridgeTx: boolean; + bridgeInfo?: { + status?: string; + destTxHash?: string; + }; +}; + +export function isBridgeComplete(transaction: BridgeTransaction): boolean { + return Boolean( + transaction.isBridgeTx && + transaction.bridgeInfo && + (transaction.bridgeInfo.status === StatusTypes.COMPLETE || + transaction.bridgeInfo.status === 'COMPLETE') && + typeof transaction.bridgeInfo.destTxHash === 'string' && + transaction.bridgeInfo.destTxHash.length > 0, + ); +} + +export function isBridgeFailed( + transaction: BridgeTransaction, + baseStatusKey: string, +): boolean { + const bridgeFailed = Boolean( + transaction.isBridgeTx && + transaction.bridgeInfo && + (transaction.bridgeInfo.status === StatusTypes.FAILED || + transaction.bridgeInfo.status === 'FAILED'), + ); + const baseFailed = baseStatusKey === TransactionStatus.failed; + + return bridgeFailed || baseFailed; +} + +export function getBridgeStatusKey( + transaction: BridgeTransaction, + baseStatusKey: string, +): string { + if (!transaction.isBridgeTx || !transaction.bridgeInfo) { + return baseStatusKey; + } + + if (isBridgeFailed(transaction, baseStatusKey)) { + return TransactionStatus.failed; + } + + if ( + isBridgeComplete(transaction) && + baseStatusKey === TransactionStatus.confirmed + ) { + return TransactionStatus.confirmed; + } + + return TransactionStatus.submitted; +} + export const getInitialHistoryItem = ({ quoteResponse, bridgeTxMetaId, @@ -109,8 +170,6 @@ export const getInitialHistoryItem = ({ targetContractAddress, account, status: { - // We always have a PENDING status when we start polling for a tx, don't need the Bridge API for that - // Also we know the bare minimum fields for status at this point in time status: StatusTypes.PENDING, srcChain: { chainId: statusRequest.srcChainId, diff --git a/shared/lib/four-byte.test.ts b/shared/lib/four-byte.test.ts index 2909bc169279..5613f8a8da1b 100644 --- a/shared/lib/four-byte.test.ts +++ b/shared/lib/four-byte.test.ts @@ -28,15 +28,13 @@ describe('Four Byte', () => { expect(result).toStrictEqual('someOtherFunction(address,uint256)'); }); - // @ts-expect-error This is missing from the Mocha type definitions it.each([undefined, null, '', '0x', '0X'])( 'returns undefined if four byte prefix is %s', - async (prefix: string) => { - expect(await getMethodFrom4Byte(prefix)).toBeUndefined(); + async (prefix) => { + expect(await getMethodFrom4Byte(prefix as string)).toBeUndefined(); }, ); - // @ts-expect-error This is missing from the Mocha type definitions it.each([ ['with hex prefix', '0x1234567'], ['without hex prefix', '1234567'], @@ -47,7 +45,6 @@ describe('Four Byte', () => { }, ); - // @ts-expect-error This is missing from the Mocha type definitions it.each([ ['undefined', { results: undefined }], ['object', { results: {} }], diff --git a/shared/lib/multichain/accounts.test.ts b/shared/lib/multichain/accounts.test.ts index 10b41425d5b0..9e8f15499070 100644 --- a/shared/lib/multichain/accounts.test.ts +++ b/shared/lib/multichain/accounts.test.ts @@ -27,7 +27,6 @@ const SOL_ADDRESSES = [ describe('multichain', () => { describe('isBtcMainnetAddress', () => { - // @ts-expect-error This is missing from the Mocha type definitions it.each(BTC_MAINNET_ADDRESSES)( 'returns true if address is compatible with BTC mainnet: %s', (address: string) => { @@ -35,7 +34,6 @@ describe('multichain', () => { }, ); - // @ts-expect-error This is missing from the Mocha type definitions it.each([...BTC_TESTNET_ADDRESSES, ...ETH_ADDRESSES, ...SOL_ADDRESSES])( 'returns false if address is not compatible with BTC mainnet: %s', (address: string) => { @@ -45,7 +43,6 @@ describe('multichain', () => { }); describe('isBtcTestnetAddress', () => { - // @ts-expect-error This is missing from the Mocha type definitions it.each(BTC_TESTNET_ADDRESSES)( 'returns true if address is compatible with BTC testnet: %s', (address: string) => { @@ -53,7 +50,6 @@ describe('multichain', () => { }, ); - // @ts-expect-error This is missing from the Mocha type definitions it.each([...BTC_MAINNET_ADDRESSES, ...ETH_ADDRESSES, ...SOL_ADDRESSES])( 'returns false if address is compatible with BTC testnet: %s', (address: string) => { @@ -63,7 +59,6 @@ describe('multichain', () => { }); describe('isSolanaAddress', () => { - // @ts-expect-error This is missing from the Mocha type definitions it.each(SOL_ADDRESSES)( 'returns true if address is a valid Solana address: %s', (address: string) => { @@ -77,7 +72,6 @@ describe('multichain', () => { }); describe('getChainTypeFromAddress', () => { - // @ts-expect-error This is missing from the Mocha type definitions it.each([...BTC_MAINNET_ADDRESSES, ...BTC_TESTNET_ADDRESSES])( 'returns KnownCaipNamespace.Bitcoin for bitcoin address: %s', (address: string) => { @@ -87,7 +81,6 @@ describe('multichain', () => { }, ); - // @ts-expect-error This is missing from the Mocha type definitions it.each(ETH_ADDRESSES)( 'returns KnownCaipNamespace.Ethereum for ethereum address: %s', (address: string) => { @@ -97,7 +90,6 @@ describe('multichain', () => { }, ); - // @ts-expect-error This is missing from the Mocha type definitions it.each(SOL_ADDRESSES)( 'returns KnownCaipNamespace.Solana for non-supported address: %s', (address: string) => { diff --git a/shared/lib/multichain/chain-agnostic-permission-utils/caip-accounts.ts b/shared/lib/multichain/chain-agnostic-permission-utils/caip-accounts.ts new file mode 100644 index 000000000000..e82f015aba41 --- /dev/null +++ b/shared/lib/multichain/chain-agnostic-permission-utils/caip-accounts.ts @@ -0,0 +1,87 @@ +import { + Caip25CaveatValue, + InternalScopesObject, + parseScopeString, +} from '@metamask/chain-agnostic-permission'; +import type { InternalAccount } from '@metamask/keyring-internal-api'; +import { CaipAccountId, parseCaipAccountId } from '@metamask/utils'; + +/** + * Gets all accounts from an array of scopes objects + * This extracts all account IDs from both required and optional scopes + * and returns a unique set. + * + * @param scopesObjects - The scopes objects to extract accounts from + * @returns Array of unique account IDs + */ +export function getCaipAccountIdsFromScopesObjects( + scopesObjects: InternalScopesObject[], +): CaipAccountId[] { + const allAccounts = new Set(); + + for (const scopeObject of scopesObjects) { + for (const { accounts } of Object.values(scopeObject)) { + for (const account of accounts) { + allAccounts.add(account); + } + } + } + + return Array.from(allAccounts); +} + +/** + * Gets all permitted accounts from a CAIP-25 caveat + * This extracts all account IDs from both required and optional scopes + * and returns a unique set. + * + * @param caip25CaveatValue - The CAIP-25 caveat value to extract accounts from + * @returns Array of unique account IDs + */ +export function getCaipAccountIdsFromCaip25CaveatValue( + caip25CaveatValue: Caip25CaveatValue, +): CaipAccountId[] { + return getCaipAccountIdsFromScopesObjects([ + caip25CaveatValue.requiredScopes, + caip25CaveatValue.optionalScopes, + ]); +} + +/** + * Checks if an internal account is connected to any of the permitted accounts + * based on scope matching + * + * @param internalAccount - The internal account to check against permitted accounts + * @param permittedAccounts - Array of CAIP-10 account IDs that are permitted + * @returns True if the account is connected to any permitted account + */ +export function isInternalAccountInPermittedAccountIds( + internalAccount: InternalAccount, + permittedAccounts: CaipAccountId[], +): boolean { + if (!internalAccount || !permittedAccounts.length) { + return false; + } + + const parsedInteralAccountScopes = internalAccount.scopes.map((scope) => { + return parseScopeString(scope); + }); + + return permittedAccounts.some((account) => { + const parsedPermittedAccount = parseCaipAccountId(account); + + return parsedInteralAccountScopes.some(({ namespace, reference }) => { + if ( + namespace !== parsedPermittedAccount.chain.namespace || + internalAccount.address !== parsedPermittedAccount.address + ) { + return false; + } + + return ( + reference === '0' || + reference === parsedPermittedAccount.chain.reference + ); + }); + }); +} diff --git a/shared/lib/multichain/chain-agnostic-permission-utils/caip-chainids.ts b/shared/lib/multichain/chain-agnostic-permission-utils/caip-chainids.ts new file mode 100644 index 000000000000..85c2e82e9526 --- /dev/null +++ b/shared/lib/multichain/chain-agnostic-permission-utils/caip-chainids.ts @@ -0,0 +1,102 @@ +import { + Caip25CaveatType, + Caip25CaveatValue, + InternalScopesObject, + InternalScopeString, + parseScopeString, +} from '@metamask/chain-agnostic-permission'; +import { + CaipChainId, + CaipNamespace, + KnownCaipNamespace, +} from '@metamask/utils'; + +/** + * Gets all scopes from a CAIP-25 caveat value + * + * @param scopesObjects - The scopes objects to get the scopes from. + * @returns An array of InternalScopeStrings. + */ +export function getAllScopesFromScopesObjects( + scopesObjects: InternalScopesObject[], +): InternalScopeString[] { + const scopeSet = new Set(); + + for (const scopeObject of scopesObjects) { + for (const key of Object.keys(scopeObject)) { + scopeSet.add(key as InternalScopeString); + } + } + + return Array.from(scopeSet); +} + +/** + * Gets all scopes (chain IDs) from a CAIP-25 caveat + * This extracts all scopes from both required and optional scopes + * and returns a unique set. + * + * @param caip25CaveatValue - The CAIP-25 caveat value to extract scopes from + * @returns Array of unique scope strings (chain IDs) + */ +export function getAllScopesFromCaip25CaveatValue( + caip25CaveatValue: Caip25CaveatValue, +): CaipChainId[] { + return getAllScopesFromScopesObjects([ + caip25CaveatValue.requiredScopes, + caip25CaveatValue.optionalScopes, + ]) as CaipChainId[]; +} + +/** + * Gets all non-wallet namespaces from a CAIP-25 caveat value + * This extracts all namespaces from both required and optional scopes + * and returns a unique set. + * + * @param caip25CaveatValue - The CAIP-25 caveat value to extract namespaces from + * @returns Array of unique namespace strings + */ +export function getAllNonWalletNamespacesFromCaip25CaveatValue( + caip25CaveatValue: Caip25CaveatValue, +): CaipNamespace[] { + const allScopes = getAllScopesFromCaip25CaveatValue(caip25CaveatValue); + const namespaceSet = new Set(); + + for (const scope of allScopes) { + const { namespace, reference } = parseScopeString(scope); + if (namespace === KnownCaipNamespace.Wallet) { + if (reference) { + namespaceSet.add(reference); + } + } else if (namespace) { + namespaceSet.add(namespace); + } + } + + return Array.from(namespaceSet); +} + +/** + * Gets all scopes (chain IDs) from a CAIP-25 permission + * This extracts all scopes from both required and optional scopes + * and returns a unique set. + * + * @param caip25Permission - The CAIP-25 permission object + * @param caip25Permission.caveats - The caveats of the CAIP-25 permission + * @returns Array of unique scope strings (chain IDs) + */ +export function getAllScopesFromPermission(caip25Permission: { + caveats: { + type: string; + value: Caip25CaveatValue; + }[]; +}): CaipChainId[] { + const caip25Caveat = caip25Permission.caveats.find( + (caveat) => caveat.type === Caip25CaveatType, + ); + if (!caip25Caveat) { + return []; + } + + return getAllScopesFromCaip25CaveatValue(caip25Caveat.value); +} diff --git a/shared/lib/multichain/chain-agnostic-permission-utils/misc-utils.ts b/shared/lib/multichain/chain-agnostic-permission-utils/misc-utils.ts new file mode 100644 index 000000000000..4d8a1bccd343 --- /dev/null +++ b/shared/lib/multichain/chain-agnostic-permission-utils/misc-utils.ts @@ -0,0 +1,67 @@ +import type { + NormalizedScopesObject, + Caip25CaveatValue, +} from '@metamask/chain-agnostic-permission'; +import { + Caip25CaveatType, + KnownSessionProperties, + parseScopeString, +} from '@metamask/chain-agnostic-permission'; +import type { CaipNamespace } from '@metamask/utils'; + +// @metamask/chain-agnostic-permission -> scopes/constants.ts +/** + * Checks if a given value is a known session property. + * + * @param value - The value to check. + * @returns `true` if the value is a known session property, otherwise `false`. + */ +export function isKnownSessionPropertyValue( + value: string, +): value is KnownSessionProperties { + return Object.values(KnownSessionProperties).includes( + value as KnownSessionProperties, + ); +} + +// @metamask/chain-agnostic-permission -> scopes/authorization.ts +/** + * Checks if a given CAIP namespace is present in a NormalizedScopesObject. + * + * @param scopesObject - The NormalizedScopesObject to check. + * @param caipNamespace - The CAIP namespace to check for. + * @returns true if the CAIP namespace is present in the NormalizedScopesObject, false otherwise. + */ +export function isNamespaceInScopesObject( + scopesObject: NormalizedScopesObject, + caipNamespace: CaipNamespace, +) { + return Object.keys(scopesObject).some((scope) => { + const { namespace } = parseScopeString(scope); + return namespace === caipNamespace; + }); +} + +// @metamask/chain-agnostic-permission -> caip25Permission.ts +/** + * Helper to get the CAIP-25 caveat from a permission + * + * @param caip25Permission - The CAIP-25 permission object + * @param caip25Permission.caveats - The caveats of the CAIP-25 permission + * @returns The CAIP-25 caveat or undefined if not found + */ +export function getCaip25CaveatFromPermission(caip25Permission: { + caveats: { + type: string; + value: Caip25CaveatValue | undefined; + }[]; +}): + | { + type: string; + value: Caip25CaveatValue | undefined; + } + | undefined { + return caip25Permission?.caveats?.find( + (caveat) => caveat.type === Caip25CaveatType, + ); +} diff --git a/shared/lib/snaps/snaps.ts b/shared/lib/snaps/snaps.ts new file mode 100644 index 000000000000..347d85adb75c --- /dev/null +++ b/shared/lib/snaps/snaps.ts @@ -0,0 +1,21 @@ +import { SnapId } from '@metamask/snaps-sdk'; + +export const PREINSTALLED_SNAPS = [ + 'npm:@metamask/message-signing-snap', + 'npm:@metamask/ens-resolver-snap', + 'npm:@metamask/institutional-wallet-snap', + 'npm:@metamask/account-watcher', + 'npm:@metamask/preinstalled-example-snap', + 'npm:@metamask/bitcoin-wallet-snap', + 'npm:@metamask/solana-wallet-snap', +]; + +/** + * Check if a Snap is a preinstalled Snap. + * + * @param snapId - Snap ID to verify. + * @returns True if Snap is a preinstalled Snap, false otherwise. + */ +export function isSnapPreinstalled(snapId: SnapId) { + return PREINSTALLED_SNAPS.some((snap) => snap === snapId); +} diff --git a/shared/lib/transaction-controller-utils.test.js b/shared/lib/transaction-controller-utils.test.js index 7cc7bc75b22f..df47ef7bb2e7 100644 --- a/shared/lib/transaction-controller-utils.test.js +++ b/shared/lib/transaction-controller-utils.test.js @@ -19,7 +19,6 @@ describe('transaction controller utils', () => { }); describe('calcTokenAmount()', () => { - // @ts-expect-error This is missing from the Mocha type definitions it.each([ // number values [0, 5, '0'], diff --git a/shared/lib/ui-utils.js b/shared/lib/ui-utils.js index a1fcf17d159c..0d718723ef86 100644 --- a/shared/lib/ui-utils.js +++ b/shared/lib/ui-utils.js @@ -22,3 +22,6 @@ export const TRANSACTION_SIMULATIONS_LEARN_MORE_LINK = export const GAS_FEES_LEARN_MORE_URL = 'https://community.metamask.io/t/what-is-gas-why-do-transactions-take-so-long/3172'; + +export const SMART_ACCOUNT_INFO_LINK = + 'https://support.metamask.io/configure/accounts/what-is-a-smart-account'; diff --git a/shared/modules/network.utils.test.ts b/shared/modules/network.utils.test.ts index 239269f0c770..463a556ef60c 100644 --- a/shared/modules/network.utils.test.ts +++ b/shared/modules/network.utils.test.ts @@ -166,7 +166,7 @@ describe('network utils', () => { const networks: Record = { [SolScope.Mainnet]: { chainId: SolScope.Mainnet, - name: 'Solana Mainnet', + name: 'Solana', nativeCurrency: `${SolScope.Mainnet}/slip44:501`, isEvm: false, }, @@ -188,7 +188,7 @@ describe('network utils', () => { }, [BtcScope.Mainnet]: { chainId: BtcScope.Mainnet, - name: 'Bitcoin Mainnet', + name: 'Bitcoin', nativeCurrency: `${BtcScope.Mainnet}/slip44:0`, isEvm: false, }, @@ -202,13 +202,13 @@ describe('network utils', () => { expect(sortNetworks(networks, sortedChainIds)).toStrictEqual([ { chainId: SolScope.Mainnet, - name: 'Solana Mainnet', + name: 'Solana', nativeCurrency: `${SolScope.Mainnet}/slip44:501`, isEvm: false, }, { chainId: BtcScope.Mainnet, - name: 'Bitcoin Mainnet', + name: 'Bitcoin', nativeCurrency: `${BtcScope.Mainnet}/slip44:0`, isEvm: false, }, diff --git a/shared/modules/selectors/feature-flags.test.ts b/shared/modules/selectors/feature-flags.test.ts new file mode 100644 index 000000000000..955b7f2d3e2f --- /dev/null +++ b/shared/modules/selectors/feature-flags.test.ts @@ -0,0 +1,180 @@ +import { RpcEndpointType } from '@metamask/network-controller'; +import { CHAIN_IDS } from '../../constants/network'; +// Import the module to spy on +import * as featureFlags from '../feature-flags'; +import { + getFeatureFlagsByChainId, + type SwapsFeatureFlags, +} from './feature-flags'; +import { ProviderConfigState } from './networks'; + +type MockState = ProviderConfigState & { + metamask: { + networkConfigurationsByChainId: Record< + string, + { + chainId: string; + rpcEndpoints: { + networkClientId: string; + type: RpcEndpointType; + url: string; + }[]; + blockExplorerUrls: string[]; + defaultBlockExplorerUrlIndex: number; + name: string; + nativeCurrency: string; + defaultRpcEndpointIndex: number; + } + >; + selectedNetworkClientId: string; + networksMetadata: { + [clientId: string]: { status: string }; + }; + swapsState: { + swapsFeatureFlags: SwapsFeatureFlags; + }; + }; +}; + +describe('Feature Flags Selectors', () => { + const createMockState = (chainId = CHAIN_IDS.MAINNET): MockState => { + // Use a simpler approach - explicit type cast for test purposes + return { + metamask: { + // Network state for provider config + networkConfigurationsByChainId: { + [chainId]: { + chainId, + rpcEndpoints: [ + { + networkClientId: 'test-client-id', + type: RpcEndpointType.Custom, + url: 'https://example.com', + }, + ], + blockExplorerUrls: ['https://example.com'], + defaultBlockExplorerUrlIndex: 0, + name: 'Test Network', + nativeCurrency: 'ETH', + defaultRpcEndpointIndex: 0, + }, + }, + selectedNetworkClientId: 'test-client-id', + networksMetadata: { + 'test-client-id': { status: 'available' }, + }, + // Swaps feature flags + swapsState: { + swapsFeatureFlags: { + ethereum: { + extensionActive: true, + mobileActive: false, + smartTransactions: { + expectedDeadline: 45, + maxDeadline: 150, + extensionReturnTxHashAsap: false, + }, + }, + bsc: { + extensionActive: true, + mobileActive: false, + smartTransactions: { + expectedDeadline: 60, + maxDeadline: 180, + extensionReturnTxHashAsap: true, + }, + }, + smartTransactions: { + mobileActive: true, + extensionActive: true, + extensionReturnTxHashAsap: false, + }, + } as SwapsFeatureFlags, + }, + }, + }; + }; + + describe('getFeatureFlagsByChainId', () => { + beforeEach(() => { + jest + .spyOn(featureFlags, 'getNetworkNameByChainId') + .mockImplementation((chainId: string) => { + switch (chainId) { + case CHAIN_IDS.MAINNET: + return 'ethereum'; + case CHAIN_IDS.BSC: + return 'bsc'; + case CHAIN_IDS.POLYGON: + return 'polygon'; + default: + return ''; + } + }); + }); + + afterEach(() => { + jest.restoreAllMocks(); + }); + + it('returns correct feature flags for current chain ID in state', () => { + const state = createMockState(CHAIN_IDS.MAINNET); + const result = getFeatureFlagsByChainId(state); + + expect(result).toStrictEqual({ + smartTransactions: { + mobileActive: true, + extensionActive: true, + expectedDeadline: 45, + maxDeadline: 150, + extensionReturnTxHashAsap: false, + }, + }); + }); + + it('returns null if chainId is not supported', () => { + // Instead of using SEPOLIA, create a state with a custom network + // and mock getNetworkNameByChainId to return empty string + const state = createMockState(CHAIN_IDS.MAINNET); + + // Mock the implementation for this specific test + jest + .spyOn(featureFlags, 'getNetworkNameByChainId') + .mockReturnValueOnce(''); + + const result = getFeatureFlagsByChainId(state); + expect(result).toBeNull(); + }); + + it('prioritizes provided chainId parameter over state chainId', () => { + // State has Ethereum network, but we're providing BSC chainId + const state = createMockState(CHAIN_IDS.MAINNET); + const result = getFeatureFlagsByChainId(state, CHAIN_IDS.BSC); + + expect(result).toStrictEqual({ + smartTransactions: { + extensionActive: true, + mobileActive: true, + expectedDeadline: 60, + maxDeadline: 180, + extensionReturnTxHashAsap: true, + }, + }); + }); + + it('falls back to state chainId if provided chainId is falsy', () => { + const state = createMockState(CHAIN_IDS.MAINNET); + const result = getFeatureFlagsByChainId(state, ''); + + expect(result).toStrictEqual({ + smartTransactions: { + extensionActive: true, + mobileActive: true, + expectedDeadline: 45, + maxDeadline: 150, + extensionReturnTxHashAsap: false, + }, + }); + }); + }); +}); diff --git a/shared/modules/selectors/feature-flags.ts b/shared/modules/selectors/feature-flags.ts index 34358e2e0e9f..b317c0790534 100644 --- a/shared/modules/selectors/feature-flags.ts +++ b/shared/modules/selectors/feature-flags.ts @@ -1,29 +1,43 @@ import { getNetworkNameByChainId } from '../feature-flags'; import { ProviderConfigState, getCurrentChainId } from './networks'; +type NetworkFeatureFlag = { + extensionActive: boolean; + mobileActive: boolean; + smartTransactions?: { + mobileActive?: boolean; + extensionActive?: boolean; + expectedDeadline?: number; + maxDeadline?: number; + extensionReturnTxHashAsap?: boolean; + }; +}; + +type SmartTransactionsFeatureFlag = { + mobileActive: boolean; + extensionActive: boolean; + extensionReturnTxHashAsap: boolean; +}; + +export type SwapsFeatureFlags = { + [networkName: string]: NetworkFeatureFlag; + smartTransactions: SmartTransactionsFeatureFlag; +}; + type FeatureFlagsMetaMaskState = { metamask: { swapsState: { - swapsFeatureFlags: { - [key: string]: { - extensionActive: boolean; - mobileActive: boolean; - smartTransactions: { - expectedDeadline?: number; - maxDeadline?: number; - extensionReturnTxHashAsap?: boolean; - }; - }; - }; + swapsFeatureFlags: SwapsFeatureFlags; }; }; }; export function getFeatureFlagsByChainId( state: ProviderConfigState & FeatureFlagsMetaMaskState, + chainId?: string, ) { - const chainId = getCurrentChainId(state); - const networkName = getNetworkNameByChainId(chainId); + const effectiveChainId = chainId || getCurrentChainId(state); + const networkName = getNetworkNameByChainId(effectiveChainId); const featureFlags = state.metamask.swapsState?.swapsFeatureFlags; if (!featureFlags?.[networkName]) { return null; diff --git a/shared/modules/selectors/index.test.ts b/shared/modules/selectors/index.test.ts index 40ed2e22d0e4..7540066b8869 100644 --- a/shared/modules/selectors/index.test.ts +++ b/shared/modules/selectors/index.test.ts @@ -4,9 +4,10 @@ import { it as jestIt } from '@jest/globals'; import { createSwapsMockStore } from '../../../test/jest'; import { CHAIN_IDS } from '../../constants/network'; import { mockNetworkState } from '../../../test/stub/networks'; +import * as envModule from '../environment'; import { getSmartTransactionsOptInStatusForMetrics, - getCurrentChainSupportsSmartTransactions, + getChainSupportsSmartTransactions, getSmartTransactionsEnabled, getIsSmartTransaction, getSmartTransactionsPreferenceEnabled, @@ -122,12 +123,12 @@ describe('Selectors', () => { }); }); - describe('getCurrentChainSupportsSmartTransactions', () => { + describe('getChainSupportsSmartTransactions', () => { jestIt( 'should return true if the chain ID is allowed for smart transactions', () => { const state = createMockState(); - const result = getCurrentChainSupportsSmartTransactions(state); + const result = getChainSupportsSmartTransactions(state); expect(result).toBe(true); }, ); @@ -143,10 +144,36 @@ describe('Selectors', () => { ...mockNetworkState({ chainId: CHAIN_IDS.POLYGON }), }, }; - const result = getCurrentChainSupportsSmartTransactions(newState); + const result = getChainSupportsSmartTransactions(newState); expect(result).toBe(false); }, ); + + jestIt( + 'should prioritize provided chainId parameter over state chainId', + () => { + const state = createMockState(); // Has allowed chain ID + // Should be false for non-allowed chain ID regardless of state + expect( + getChainSupportsSmartTransactions(state, CHAIN_IDS.POLYGON), + ).toBe(false); + + const nonSupportedState = { + ...state, + metamask: { + ...state.metamask, + ...mockNetworkState({ chainId: CHAIN_IDS.POLYGON }), + }, + }; + // Should be true for allowed chain ID regardless of state + expect( + getChainSupportsSmartTransactions( + nonSupportedState, + CHAIN_IDS.MAINNET, + ), + ).toBe(true); + }, + ); }); describe('getSmartTransactionsEnabled', () => { @@ -303,6 +330,130 @@ describe('Selectors', () => { '36eb02e0-7925-47f0-859f-076608f09b69'; expect(getSmartTransactionsEnabled(state)).toBe(false); }); + + jestIt('prioritizes provided chainId parameter over state chainId', () => { + const state = createSwapsMockStore(); // Ethereum network (supported) + + // Should be false for Polygon chainId regardless of state + expect(getSmartTransactionsEnabled(state, CHAIN_IDS.POLYGON)).toBe(false); + + // Should be true for BSC chainId (supported) regardless of state + const polygonState = { + ...state, + metamask: { + ...state.metamask, + ...mockNetworkState( + { chainId: CHAIN_IDS.POLYGON }, + { + chainId: CHAIN_IDS.BSC, + rpcUrl: 'https://bsc-dataseed.binance.org/', + }, + ), + }, + }; + expect(getSmartTransactionsEnabled(polygonState, CHAIN_IDS.BSC)).toBe( + true, + ); + }); + + // RPC URL checking tests + jestIt('permits Infura URLs in production for RPC URL checks', () => { + jest.spyOn(envModule, 'isProduction').mockReturnValue(true); + + const state = createSwapsMockStore(); + const newState = { + ...state, + metamask: { + ...state.metamask, + ...mockNetworkState({ + chainId: CHAIN_IDS.MAINNET, + rpcUrl: 'https://mainnet.infura.io/v3/some-project-id', + }), + }, + }; + + expect(getSmartTransactionsEnabled(newState)).toBe(true); + }); + + jestIt('permits Binance URLs in production for RPC URL checks', () => { + jest.spyOn(envModule, 'isProduction').mockReturnValue(true); + + const state = createSwapsMockStore(); + const newState = { + ...state, + metamask: { + ...state.metamask, + ...mockNetworkState({ + chainId: CHAIN_IDS.BSC, + rpcUrl: 'https://bsc-dataseed.binance.org/', + }), + }, + }; + + expect(getSmartTransactionsEnabled(newState)).toBe(true); + }); + + jestIt('rejects other URLs in production for RPC URL checks', () => { + jest.spyOn(envModule, 'isProduction').mockReturnValue(true); + + const state = createSwapsMockStore(); + const newState = { + ...state, + metamask: { + ...state.metamask, + ...mockNetworkState({ + chainId: CHAIN_IDS.BSC, + rpcUrl: 'https://bsc-dataseed1.defibit.io/', + }), + }, + }; + + expect(getSmartTransactionsEnabled(newState)).toBe(false); + }); + + jestIt('allows any URL in non-production for RPC URL checks', () => { + jest.spyOn(envModule, 'isProduction').mockReturnValue(false); + + const state = createSwapsMockStore(); + const newState = { + ...state, + metamask: { + ...state.metamask, + ...mockNetworkState({ + chainId: CHAIN_IDS.BSC, + rpcUrl: 'https://some-random-rpc.example.com', + }), + }, + }; + + expect(getSmartTransactionsEnabled(newState)).toBe(true); + }); + + jestIt( + 'prioritizes provided chainId parameter over state chainId for RPC URL checks', + () => { + jest.spyOn(envModule, 'isProduction').mockReturnValue(false); + + // Set up a state with a chain ID that should be skipped, but a non-acceptable RPC URL + const state = createSwapsMockStore(); + const stateWithCustomRpc = { + ...state, + metamask: { + ...state.metamask, + ...mockNetworkState({ + chainId: CHAIN_IDS.MAINNET, + rpcUrl: 'https://some-random-rpc.example.com', + }), + }, + }; + + // When we pass CHAIN_IDS.BSC which is in the skip list, it should work + // regardless of the RPC URL in the state + expect( + getSmartTransactionsEnabled(stateWithCustomRpc, CHAIN_IDS.BSC), + ).toBe(true); + }, + ); }); describe('getIsSmartTransaction', () => { @@ -360,5 +511,32 @@ describe('Selectors', () => { const result = getIsSmartTransaction(newState); expect(result).toBe(false); }); + + jestIt('prioritizes provided chainId parameter over state chainId', () => { + const state = createMockState(); // Has enabled smart transactions + + // Should be false for non-supported chain ID despite state supporting it + expect(getIsSmartTransaction(state, CHAIN_IDS.POLYGON)).toBe(false); + + // Create a state with Polygon (non-supported) chain ID + const nonSupportedState = { + ...state, + metamask: { + ...state.metamask, + ...mockNetworkState( + { chainId: CHAIN_IDS.POLYGON }, + { + chainId: CHAIN_IDS.MAINNET, + rpcUrl: 'https://mainnet.infura.io/v3/', + }, + ), + }, + }; + + // Should be true for supported chain ID despite state not supporting it + expect(getIsSmartTransaction(nonSupportedState, CHAIN_IDS.MAINNET)).toBe( + true, + ); + }); }); }); diff --git a/shared/modules/selectors/networks.ts b/shared/modules/selectors/networks.ts index bc8d05b5164d..b1aa21484973 100644 --- a/shared/modules/selectors/networks.ts +++ b/shared/modules/selectors/networks.ts @@ -1,10 +1,13 @@ +import { type MultichainNetworkConfiguration as InternalMultichainNetworkConfiguration } from '@metamask/multichain-network-controller'; import { RpcEndpointType, - type NetworkConfiguration, type NetworkState as InternalNetworkState, + type NetworkConfiguration as InternalNetworkConfiguration, } from '@metamask/network-controller'; import { createSelector } from 'reselect'; +import { AccountsControllerState } from '@metamask/accounts-controller'; import { NetworkStatus } from '../../constants/network'; +import { hexToDecimal } from '../conversion.utils'; import { createDeepEqualSelector } from './util'; export type NetworkState = { @@ -13,7 +16,7 @@ export type NetworkState = { export type NetworkConfigurationsState = { metamask: { - networkConfigurations: Record; + networkConfigurations: Record; }; }; @@ -32,6 +35,19 @@ export type NetworksMetadataState = { export type ProviderConfigState = NetworkConfigurationsByChainIdState & SelectedNetworkClientIdState; +export type MultichainNetworkConfigurationsByChainIdState = { + metamask: { + multichainNetworkConfigurationsByChainId: Record< + string, + InternalMultichainNetworkConfiguration + >; + networkConfigurationsByChainId: Record< + string, + InternalNetworkConfiguration + >; + }; +}; + export const getNetworkConfigurationsByChainId = createDeepEqualSelector( (state: NetworkConfigurationsByChainIdState) => state.metamask.networkConfigurationsByChainId, @@ -44,6 +60,92 @@ export function getSelectedNetworkClientId( return state.metamask.selectedNetworkClientId; } +/** + * Combines and returns network configurations for all chains (EVM and not) by caip chain id. + * + * @param params - The parameters object. + * @param params.multichainNetworkConfigurationsByChainId - network configurations by caip chain id from the MultichainNetworkController state. + * @param params.networkConfigurationsByChainId - network configurations by hex chain id from the NetworkController state. + * @param params.internalAccounts - InternalAccounts object from the AccountController state. + * @returns A consolidated object containing all available network configurations by caip chain id. + */ +export const getNetworkConfigurationsByCaipChainId = ({ + multichainNetworkConfigurationsByChainId, + networkConfigurationsByChainId, + internalAccounts, +}: { + multichainNetworkConfigurationsByChainId: Record< + string, + InternalMultichainNetworkConfiguration + >; + networkConfigurationsByChainId: Record; + internalAccounts: AccountsControllerState['internalAccounts']; +}) => { + const caipFormattedEvmNetworkConfigurations: Record< + string, + InternalNetworkConfiguration | InternalMultichainNetworkConfiguration + > = {}; + + Object.entries(networkConfigurationsByChainId).forEach( + ([chainId, network]) => { + const caipChainId = `eip155:${hexToDecimal(chainId)}`; + caipFormattedEvmNetworkConfigurations[caipChainId] = network; + }, + ); + + // For now we need to filter out networkConfigurations/scopes without accounts because + // the `endowment:caip25` caveat validator will throw if there are no supported accounts for the given scope + // due to how the `MultichainRouter.isSupportedScope()` method is implemented + Object.entries(multichainNetworkConfigurationsByChainId).forEach( + ([caipChainId, networkConfig]) => { + const matchesAccount = Object.values(internalAccounts.accounts).some( + (account) => { + const matchesScope = account.scopes.some((scope) => { + return scope === caipChainId; + }); + + const isSnapEnabled = account.metadata.snap?.enabled; + + return matchesScope && isSnapEnabled; + }, + ); + + if (matchesAccount) { + caipFormattedEvmNetworkConfigurations[caipChainId] = networkConfig; + } + }, + ); + + return caipFormattedEvmNetworkConfigurations; +}; + +/** + * Combines and returns network configurations for all chains (EVM and not). + * + * @param state - Redux state. + * @returns A consolidated object containing all available network configurations. + */ +export const getAllNetworkConfigurationsByCaipChainId = createSelector( + (state: MultichainNetworkConfigurationsByChainIdState) => + state.metamask.networkConfigurationsByChainId, + (state: MultichainNetworkConfigurationsByChainIdState) => + state.metamask.multichainNetworkConfigurationsByChainId, + (state: { + metamask: { internalAccounts: AccountsControllerState['internalAccounts'] }; + }) => state.metamask.internalAccounts, + ( + networkConfigurationsByChainId, + multichainNetworkConfigurationsByChainId, + internalAccounts, + ) => { + return getNetworkConfigurationsByCaipChainId({ + networkConfigurationsByChainId, + multichainNetworkConfigurationsByChainId, + internalAccounts, + }); + }, +); + /** * Get the provider configuration for the current selected network. * @@ -87,7 +189,7 @@ export const getProviderConfig = createSelector( export function getNetworkConfigurations( state: NetworkConfigurationsState, -): Record { +): Record { return state.metamask.networkConfigurations; } @@ -119,3 +221,14 @@ export function getCurrentChainId(state: ProviderConfigState) { const { chainId } = getProviderConfig(state); return chainId; } + +export const getIsAllNetworksFilterEnabled = createSelector( + getNetworkConfigurationsByChainId, + (allNetworks) => { + const allOpts: Record = {}; + Object.keys(allNetworks || {}).forEach((chain) => { + allOpts[chain] = true; + }); + return allOpts; + }, +); diff --git a/shared/modules/selectors/smart-transactions.ts b/shared/modules/selectors/smart-transactions.ts index 3ed3fed587c0..e1351984baaf 100644 --- a/shared/modules/selectors/smart-transactions.ts +++ b/shared/modules/selectors/smart-transactions.ts @@ -4,9 +4,9 @@ import { SKIP_STX_RPC_URL_CHECK_CHAIN_IDS, } from '../../constants/smartTransactions'; import { - getCurrentNetwork, accountSupportsSmartTx, getPreferences, + selectDefaultRpcEndpointByChainId, // TODO: Remove restricted import // eslint-disable-next-line import/no-restricted-paths } from '../../../ui/selectors/selectors'; // TODO: Migrate shared selectors to this file. @@ -129,44 +129,57 @@ export const getSmartTransactionsPreferenceEnabled = createSelector( }, ); -export const getCurrentChainSupportsSmartTransactions = ( +export const getChainSupportsSmartTransactions = ( state: NetworkState, + chainId?: string, ): boolean => { - const chainId = getCurrentChainId(state); - return getAllowedSmartTransactionsChainIds().includes(chainId); + const effectiveChainId = chainId || getCurrentChainId(state); + return getAllowedSmartTransactionsChainIds().includes(effectiveChainId); }; -const getIsAllowedRpcUrlForSmartTransactions = (state: NetworkState) => { - const chainId = getCurrentChainId(state); +const getIsAllowedRpcUrlForSmartTransactions = ( + state: NetworkState, + chainId?: string, +) => { + const effectiveChainId = chainId || getCurrentChainId(state); // Allow in non-production or if chain ID is on skip list. - if (!isProduction() || SKIP_STX_RPC_URL_CHECK_CHAIN_IDS.includes(chainId)) { + if ( + !isProduction() || + SKIP_STX_RPC_URL_CHECK_CHAIN_IDS.includes(effectiveChainId) + ) { return true; } - const rpcUrl = getCurrentNetwork(state)?.rpcUrl; - if (!rpcUrl) { - return false; - } - const { hostname } = new URL(rpcUrl); - if (!hostname) { - return false; - } - return hostname.endsWith('.infura.io') || hostname.endsWith('.binance.org'); + + // Get the default RPC endpoint directly for this chain ID + const defaultRpcEndpoint = selectDefaultRpcEndpointByChainId( + state, + effectiveChainId, + ); + const rpcUrl = defaultRpcEndpoint?.url; + const hostname = rpcUrl && new URL(rpcUrl).hostname; + + return ( + hostname?.endsWith('.infura.io') || + hostname?.endsWith('.binance.org') || + false + ); }; export const getSmartTransactionsEnabled = ( state: SmartTransactionsMetaMaskState & NetworkState, + chainId?: string, ): boolean => { const supportedAccount = accountSupportsSmartTx(state); // @ts-expect-error Smart transaction selector types does not match controller state - const featureFlagsByChainId = getFeatureFlagsByChainId(state); + const featureFlagsByChainId = getFeatureFlagsByChainId(state, chainId); // TODO: Create a new proxy service only for MM feature flags. const smartTransactionsFeatureFlagEnabled = featureFlagsByChainId?.smartTransactions?.extensionActive; const smartTransactionsLiveness = state.metamask.smartTransactionsState?.liveness; return Boolean( - getCurrentChainSupportsSmartTransactions(state) && - getIsAllowedRpcUrlForSmartTransactions(state) && + getChainSupportsSmartTransactions(state, chainId) && + getIsAllowedRpcUrlForSmartTransactions(state, chainId) && supportedAccount && smartTransactionsFeatureFlagEnabled && smartTransactionsLiveness, @@ -175,10 +188,11 @@ export const getSmartTransactionsEnabled = ( export const getIsSmartTransaction = ( state: SmartTransactionsMetaMaskState & NetworkState, + chainId?: string, ): boolean => { const smartTransactionsPreferenceEnabled = getSmartTransactionsPreferenceEnabled(state); - const smartTransactionsEnabled = getSmartTransactionsEnabled(state); + const smartTransactionsEnabled = getSmartTransactionsEnabled(state, chainId); return Boolean( smartTransactionsPreferenceEnabled && smartTransactionsEnabled, ); diff --git a/shared/notifications/index.ts b/shared/notifications/index.ts index 5325c62cc025..b6e7e4714484 100644 --- a/shared/notifications/index.ts +++ b/shared/notifications/index.ts @@ -26,7 +26,10 @@ export type ModalHeaderProps = { image?: NotificationImage; }; export type ModalBodyProps = { title: string }; -export type ModalFooterProps = { onAction: () => void; onCancel: () => void }; +export type ModalFooterProps = { + onAction: () => void | Promise; + onCancel: () => void | Promise; +}; export type TranslatedUINotification = { id: number; diff --git a/test/data/bridge/mock-bridge-store.ts b/test/data/bridge/mock-bridge-store.ts new file mode 100644 index 000000000000..5efac938af4a --- /dev/null +++ b/test/data/bridge/mock-bridge-store.ts @@ -0,0 +1,115 @@ +import { + BRIDGE_PREFERRED_GAS_ESTIMATE, + getDefaultBridgeControllerState, + formatChainIdToCaip, +} from '@metamask/bridge-controller'; +import { DEFAULT_BRIDGE_STATUS_STATE } from '../../../app/scripts/controllers/bridge-status/constants'; +import { CHAIN_IDS } from '../../../shared/constants/network'; +import { BridgeAppState } from '../../../ui/ducks/bridge/selectors'; +import { createSwapsMockStore } from '../../jest/mock-store'; +import { mockNetworkState } from '../../stub/networks'; +import { mockTokenData } from './mock-token-data'; + +export const createBridgeMockStore = ({ + featureFlagOverrides = {}, + bridgeSliceOverrides = {}, + bridgeStateOverrides = {}, + bridgeStatusStateOverrides = {}, + metamaskStateOverrides = {}, +}: { + // featureFlagOverrides?: Partial; + // bridgeSliceOverrides?: Partial; + // bridgeStateOverrides?: Partial; + // bridgeStatusStateOverrides?: Partial; + // metamaskStateOverrides?: Partial; + // TODO replace these with correct types + // eslint-disable-next-line @typescript-eslint/no-explicit-any + featureFlagOverrides?: Record; + // eslint-disable-next-line @typescript-eslint/no-explicit-any + bridgeSliceOverrides?: Record; + // eslint-disable-next-line @typescript-eslint/no-explicit-any + bridgeStateOverrides?: Record; + // eslint-disable-next-line @typescript-eslint/no-explicit-any + bridgeStatusStateOverrides?: Record; + // eslint-disable-next-line @typescript-eslint/no-explicit-any + metamaskStateOverrides?: Record; +} = {}) => { + const swapsStore = createSwapsMockStore(); + return { + ...swapsStore, + // For initial state of dest asset picker + swaps: { + ...swapsStore.swaps, + topAssets: [], + }, + bridge: { + toChainId: null, + sortOrder: 'cost_ascending', + ...bridgeSliceOverrides, + }, + localeMessages: { currentLocale: 'es_419' }, + metamask: { + ...swapsStore.metamask, + ...mockNetworkState( + { chainId: CHAIN_IDS.MAINNET }, + { chainId: CHAIN_IDS.LINEA_MAINNET }, + ), + completedOnboarding: true, + gasFeeEstimates: { + estimatedBaseFee: '0.00010456', + [BRIDGE_PREFERRED_GAS_ESTIMATE]: { + suggestedMaxFeePerGas: '0.00018456', + suggestedMaxPriorityFeePerGas: '0.0001', + }, + }, + currencyRates: { + ETH: { conversionRate: 2524.25 }, + usd: { conversionRate: 1 }, + }, + marketData: { + '0x1': { + '0x1f9840a85d5af5bf1d1762f925bdaddc4201f984': { + currency: 'usd', + price: 2.3, + }, + }, + }, + slides: [], + ...mockTokenData, + ...metamaskStateOverrides, + ...{ + ...getDefaultBridgeControllerState(), + bridgeFeatureFlags: { + ...featureFlagOverrides, + extensionConfig: { + support: false, + ...featureFlagOverrides?.extensionConfig, + chains: { + [formatChainIdToCaip('0x1')]: { + isActiveSrc: true, + isActiveDest: false, + }, + ...Object.fromEntries( + Object.entries( + featureFlagOverrides?.extensionConfig?.chains ?? {}, + ).map(([chainId, config]) => [ + formatChainIdToCaip(chainId), + config, + ]), + ), + }, + }, + }, + }, + ...bridgeStateOverrides, + bridgeStatusState: { + ...DEFAULT_BRIDGE_STATUS_STATE, + ...bridgeStatusStateOverrides, + }, + }, + send: { + swapsBlockedTokens: [], + }, + // TODO fix types + } as unknown as BridgeAppState; +}; diff --git a/test/data/confirmations/batch-transaction.ts b/test/data/confirmations/batch-transaction.ts new file mode 100644 index 000000000000..2776d004c9d0 --- /dev/null +++ b/test/data/confirmations/batch-transaction.ts @@ -0,0 +1,311 @@ +import { TransactionType } from '@metamask/transaction-controller'; + +export const upgradeAccountConfirmation = { + batchId: '0x6046131032d748a6bfac42fd5117479f', + chainId: '0xaa36a7', + id: 'aa0ff2b0-150f-11f0-9325-8f0b8505bc4f', + nestedTransactions: [ + { + to: '0x0c54FcCd2e384b4BB6f2E405Bf5Cbc15a017AaFb', + data: '0x654365436543', + value: '0x3B9ACA00', + type: TransactionType.simpleSend, + }, + { + to: '0xbc2114a988e9CEf5bA63548D432024f34B487048', + data: '0x789078907890', + value: '0x1DCD6500', + type: TransactionType.simpleSend, + }, + ], + networkClientId: 'sepolia', + securityAlertResponse: { + block: 8082431, + result_type: 'Benign', + reason: '', + description: '', + features: [], + source: 'api', + securityAlertId: '31cda7d5-9657-4567-b364-d6918f0933a0', + }, + status: 'unapproved', + time: 1744181747035, + txParams: { + from: '0x8a0bbcd42cf79e7cee834e7808eb2fef1cebdb87', + authorizationList: [ + { address: '0x63c0c19a282a1B52b07dD5a65b58948A07DAE32B' }, + ], + data: '0xe9ae5c530100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000001c000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000c54fccd2e384b4bb6f2e405bf5cbc15a017aafb000000000000000000000000000000000000000000000000000000003b9aca00000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000066543654365430000000000000000000000000000000000000000000000000000000000000000000000000000bc2114a988e9cef5ba63548d432024f34b487048000000000000000000000000000000000000000000000000000000001dcd6500000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000067890789078900000000000000000000000000000000000000000000000000000', + gas: '0x1a209', + to: '0x8a0bbcd42cf79e7cee834e7808eb2fef1cebdb87', + value: '0x0', + maxFeePerGas: '0x21b65659b', + maxPriorityFeePerGas: '0x59682f00', + type: '0x4', + }, + type: 'batch', + userEditedGasLimit: false, + verifiedOnBlockchain: false, + gasLimitNoBuffer: '0x116b1', + originalGasEstimate: '0x1a209', + defaultGasEstimates: { + gas: '0x1a209', + maxFeePerGas: '0x21b65659b', + maxPriorityFeePerGas: '0x59682f00', + estimateType: 'medium', + }, + userFeeLevel: 'medium', + sendFlowHistory: [], + history: [ + { + batchId: '0x6046131032d748a6bfac42fd5117479f', + chainId: '0xaa36a7', + id: 'aa0ff2b0-150f-11f0-9325-8f0b8505bc4f', + nestedTransactions: [ + { + to: '0x0c54FcCd2e384b4BB6f2E405Bf5Cbc15a017AaFb', + data: '0x654365436543', + value: '0x3B9ACA00', + type: 'simpleSend', + }, + { + to: '0xbc2114a988e9CEf5bA63548D432024f34B487048', + data: '0x789078907890', + value: '0x1DCD6500', + type: 'simpleSend', + }, + ], + networkClientId: 'sepolia', + securityAlertResponse: { + securityAlertId: '31cda7d5-9657-4567-b364-d6918f0933a0', + }, + status: 'unapproved', + time: 1744181747035, + txParams: { + from: '0x8a0bbcd42cf79e7cee834e7808eb2fef1cebdb87', + authorizationList: [ + { address: '0x63c0c19a282a1B52b07dD5a65b58948A07DAE32B' }, + ], + data: '0xe9ae5c530100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000001c000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000c54fccd2e384b4bb6f2e405bf5cbc15a017aafb000000000000000000000000000000000000000000000000000000003b9aca00000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000066543654365430000000000000000000000000000000000000000000000000000000000000000000000000000bc2114a988e9cef5ba63548d432024f34b487048000000000000000000000000000000000000000000000000000000001dcd6500000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000067890789078900000000000000000000000000000000000000000000000000000', + to: '0x8a0bbcd42cf79e7cee834e7808eb2fef1cebdb87', + type: '0x4', + value: '0x0', + gas: '0x1a209', + maxFeePerGas: '0x21b65659b', + maxPriorityFeePerGas: '0x59682f00', + }, + type: 'batch', + userEditedGasLimit: false, + verifiedOnBlockchain: false, + gasLimitNoBuffer: '0x116b1', + originalGasEstimate: '0x1a209', + defaultGasEstimates: { + gas: '0x1a209', + maxFeePerGas: '0x21b65659b', + maxPriorityFeePerGas: '0x59682f00', + estimateType: 'medium', + }, + userFeeLevel: 'medium', + sendFlowHistory: [], + }, + [ + { + op: 'add', + path: '/securityAlertResponse/result_type', + value: 'loading', + note: 'TransactionController:updatesecurityAlertResponse - securityAlertResponse updated', + timestamp: 1744181748371, + }, + { + op: 'add', + path: '/securityAlertResponse/reason', + value: 'validation_in_progress', + }, + ], + [ + { + op: 'add', + path: '/gasFeeEstimates', + value: { + type: 'fee-market', + low: { + maxFeePerGas: '0x188ee0ee4', + maxPriorityFeePerGas: '0x3b9aca00', + }, + medium: { + maxFeePerGas: '0x21b65659b', + maxPriorityFeePerGas: '0x59682f00', + }, + high: { + maxFeePerGas: '0x2addcbc51', + maxPriorityFeePerGas: '0x77359400', + }, + }, + note: 'TransactionController#updateSimulationData - Update simulation data', + timestamp: 1744181748673, + }, + { op: 'add', path: '/gasFeeEstimatesLoaded', value: true }, + { op: 'add', path: '/gasFeeTokens', value: [] }, + { + op: 'add', + path: '/simulationData', + value: { + nativeBalanceChange: { + previousBalance: '0x109f1f975d02012', + newBalance: '0x109f1f91c67f112', + difference: '0x59682f00', + isDecrease: true, + }, + tokenBalanceChanges: [], + }, + }, + ], + [ + { + op: 'replace', + path: '/securityAlertResponse/reason', + value: '', + note: 'TransactionController:updatesecurityAlertResponse - securityAlertResponse updated', + timestamp: 1744181749212, + }, + { + op: 'replace', + path: '/securityAlertResponse/result_type', + value: 'Benign', + }, + { op: 'add', path: '/securityAlertResponse/block', value: 8082431 }, + { op: 'add', path: '/securityAlertResponse/description', value: '' }, + { op: 'add', path: '/securityAlertResponse/features', value: [] }, + { op: 'add', path: '/securityAlertResponse/source', value: 'api' }, + ], + ], + gasFeeEstimates: { + type: 'fee-market', + low: { maxFeePerGas: '0x188ee0ee4', maxPriorityFeePerGas: '0x3b9aca00' }, + medium: { maxFeePerGas: '0x21b65659b', maxPriorityFeePerGas: '0x59682f00' }, + high: { maxFeePerGas: '0x2addcbc51', maxPriorityFeePerGas: '0x77359400' }, + }, + gasFeeEstimatesLoaded: true, + gasFeeTokens: [], + simulationData: { + nativeBalanceChange: { + previousBalance: '0x109f1f975d02012', + newBalance: '0x109f1f91c67f112', + difference: '0x59682f00', + isDecrease: true, + }, + tokenBalanceChanges: [], + }, +}; + +export const RevokeDelegation = { + actionId: 1743757606797.6257, + chainId: '0xaa36a7', + delegationAddress: '0xcd8d6c5554e209fbb0dec797c6293cf7eae13454', + id: '22c82900-1134-11f0-a4de-3b789e5a89ad', + networkClientId: 'sepolia', + origin: 'metamask', + status: 'unapproved', + time: 1743757606800, + txParams: { + from: '0x8a0bbcd42cf79e7cee834e7808eb2fef1cebdb87', + authorizationList: [ + { address: '0x0000000000000000000000000000000000000000' }, + ], + gas: '0x11017', + to: '0x8a0bbcd42cf79e7cee834e7808eb2fef1cebdb87', + value: '0x0', + maxFeePerGas: '0xd0017b51', + maxPriorityFeePerGas: '0x59682f00', + type: '0x4', + }, + type: TransactionType.revokeDelegation, + userEditedGasLimit: false, + verifiedOnBlockchain: false, + gasLimitNoBuffer: '0xb565', + originalGasEstimate: '0x11017', + defaultGasEstimates: { + gas: '0x11017', + maxFeePerGas: '0xd0017b51', + maxPriorityFeePerGas: '0x59682f00', + estimateType: 'medium', + }, + userFeeLevel: 'medium', + sendFlowHistory: [], + history: [ + { + actionId: 1743757606797.6257, + chainId: '0xaa36a7', + delegationAddress: '0xcd8d6c5554e209fbb0dec797c6293cf7eae13454', + id: '22c82900-1134-11f0-a4de-3b789e5a89ad', + networkClientId: 'sepolia', + origin: 'metamask', + status: 'unapproved', + time: 1743757606800, + txParams: { + from: '0x8a0bbcd42cf79e7cee834e7808eb2fef1cebdb87', + authorizationList: [ + { address: '0x0000000000000000000000000000000000000000' }, + ], + to: '0x8a0bbcd42cf79e7cee834e7808eb2fef1cebdb87', + type: '0x4', + value: '0x0', + gas: '0x11017', + maxFeePerGas: '0xd0017b51', + maxPriorityFeePerGas: '0x59682f00', + }, + type: 'revokeDelegation', + userEditedGasLimit: false, + verifiedOnBlockchain: false, + gasLimitNoBuffer: '0xb565', + originalGasEstimate: '0x11017', + defaultGasEstimates: { + gas: '0x11017', + maxFeePerGas: '0xd0017b51', + maxPriorityFeePerGas: '0x59682f00', + estimateType: 'medium', + }, + userFeeLevel: 'medium', + sendFlowHistory: [], + }, + [ + { + op: 'add', + path: '/gasFeeEstimates', + value: { + type: 'fee-market', + low: { + maxFeePerGas: '0x9374a3b7', + maxPriorityFeePerGas: '0x3b9aca00', + }, + medium: { + maxFeePerGas: '0xd0017b51', + maxPriorityFeePerGas: '0x59682f00', + }, + high: { + maxFeePerGas: '0x10c8e52eb', + maxPriorityFeePerGas: '0x77359400', + }, + }, + note: 'TransactionController#updateSimulationData - Update simulation data', + timestamp: 1743757609512, + }, + { op: 'add', path: '/gasFeeEstimatesLoaded', value: true }, + { op: 'add', path: '/gasFeeTokens', value: [] }, + { + op: 'add', + path: '/simulationData', + value: { tokenBalanceChanges: [] }, + }, + ], + ], + gasFeeEstimates: { + type: 'fee-market', + low: { maxFeePerGas: '0x9374a3b7', maxPriorityFeePerGas: '0x3b9aca00' }, + medium: { maxFeePerGas: '0xd0017b51', maxPriorityFeePerGas: '0x59682f00' }, + high: { maxFeePerGas: '0x10c8e52eb', maxPriorityFeePerGas: '0x77359400' }, + }, + gasFeeEstimatesLoaded: true, + gasFeeTokens: [], + simulationData: { tokenBalanceChanges: [] }, +}; diff --git a/test/data/confirmations/helper.ts b/test/data/confirmations/helper.ts index 334034262760..8bac11a7653f 100644 --- a/test/data/confirmations/helper.ts +++ b/test/data/confirmations/helper.ts @@ -129,11 +129,12 @@ export const getMockConfirmState = (args: RootState = { metamask: {} }) => ({ export const getMockConfirmStateForTransaction = ( transaction: Confirmation, - args: RootState = { metamask: {} }, + args: RootState = { appState: {}, metamask: {} }, ) => getMockConfirmState( merge( { + appState: args.appState, metamask: { ...args.metamask, pendingApprovals: { diff --git a/test/data/mock-send-state.json b/test/data/mock-send-state.json index a36d69b595a3..bdf038a91fec 100644 --- a/test/data/mock-send-state.json +++ b/test/data/mock-send-state.json @@ -308,13 +308,13 @@ "multichainNetworkConfigurationsByChainId": { "bip122:000000000019d6689c085ae165831e93": { "chainId": "bip122:000000000019d6689c085ae165831e93", - "name": "Bitcoin Mainnet", + "name": "Bitcoin", "nativeCurrency": "bip122:000000000019d6689c085ae165831e93/slip44:0", "isEvm": false }, "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp": { "chainId": "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp", - "name": "Solana Mainnet", + "name": "Solana", "nativeCurrency": "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp/slip44:501", "isEvm": false } diff --git a/test/data/mock-state.json b/test/data/mock-state.json index bd65d3a1474f..29ebe154ae02 100644 --- a/test/data/mock-state.json +++ b/test/data/mock-state.json @@ -431,6 +431,7 @@ "unconnectedAccount": true }, "featureFlags": {}, + "remoteFeatureFlags": {}, "networkConfigurationsByChainId": { "0x1": { "chainId": "0x1", @@ -681,13 +682,13 @@ "multichainNetworkConfigurationsByChainId": { "bip122:000000000019d6689c085ae165831e93": { "chainId": "bip122:000000000019d6689c085ae165831e93", - "name": "Bitcoin Mainnet", + "name": "Bitcoin", "nativeCurrency": "bip122:000000000019d6689c085ae165831e93/slip44:0", "isEvm": false }, "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp": { "chainId": "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp", - "name": "Solana Mainnet", + "name": "Solana", "nativeCurrency": "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp/slip44:501", "isEvm": false } @@ -732,14 +733,6 @@ } } }, - "incomingTransactionsPreferences": { - "0x1": true, - "0xe708": false, - "0xfa": true, - "0x5": false, - "0xaa36a7": true, - "0xe704": true - }, "selectedAddress": "0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc", "accounts": { "0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc": { diff --git a/test/e2e/api-specs/helpers.ts b/test/e2e/api-specs/helpers.ts index 7febfdafaa05..003a15237336 100644 --- a/test/e2e/api-specs/helpers.ts +++ b/test/e2e/api-specs/helpers.ts @@ -1,7 +1,7 @@ import { v4 as uuid } from 'uuid'; import { ErrorObject } from '@open-rpc/meta-schema'; import { Json, JsonRpcFailure, JsonRpcResponse } from '@metamask/utils'; -import { InternalScopeString } from '@metamask/multichain'; +import { InternalScopeString } from '@metamask/chain-agnostic-permission'; import { Driver } from '../webdriver/driver'; // eslint-disable-next-line @typescript-eslint/no-shadow, @typescript-eslint/no-explicit-any diff --git a/test/e2e/constants.ts b/test/e2e/constants.ts index 624260076c96..36de7ebb366f 100644 --- a/test/e2e/constants.ts +++ b/test/e2e/constants.ts @@ -1,8 +1,8 @@ -/** Address of the first account generated by the default Ganache mnemonic. */ -export const GANACHE_ACCOUNT = '0xe18035bf8712672935fdb4e5e431b1a0183d2dfc'; +/** Address of the first account generated by the default local node mnemonic. */ +export const LOCAL_NODE_ACCOUNT = '0xe18035bf8712672935fdb4e5e431b1a0183d2dfc'; -/** Private key for the Ganache account. */ -export const GANACHE_PRIVATE_KEY = +/** Private key for the local node default account. */ +export const LOCAL_NODE_PRIVATE_KEY = '0x4cfd3e90fc78b0f86bf7524722150bb8da9c60cd532564d7ff43f5716514f553'; /** Address of the account derived from the default onboarding fixture. */ @@ -25,7 +25,7 @@ export const ERC_4337_ACCOUNT_SNAP_URL = /* Salt used to generate the 4337 account. */ export const ERC_4337_ACCOUNT_SALT = '0x1'; -/* Address of the SimpleAccountFactory smart contract deployed to Ganache. */ +/* Address of the SimpleAccountFactory smart contract deployed to the local node. */ export const SIMPLE_ACCOUNT_FACTORY = '0x4aFf835038b16dccDb1670103C4877A8F93E5219'; @@ -33,11 +33,11 @@ export const SIMPLE_ACCOUNT_FACTORY = export const TEST_SNAPS_SIMPLE_KEYRING_WEBSITE_URL = 'https://metamask.github.io/snap-simple-keyring/1.1.6/'; -/* Address of the VerifyingPaymaster smart contract deployed to Ganache. */ +/* Address of the VerifyingPaymaster smart contract deployed to the local node. */ export const VERIFYING_PAYMASTER = '0xbdbDEc38ed168331b1F7004cc9e5392A2272C1D7'; -/* Default ganache ETH balance in decimal when first login */ -export const DEFAULT_GANACHE_ETH_BALANCE_DEC = '25'; +/* Default local node ETH balance in decimal when first login */ +export const DEFAULT_LOCAL_NODE_ETH_BALANCE_DEC = '25'; /* Dapp host addresses and URL*/ export const DAPP_HOST_ADDRESS = '127.0.0.1:8080'; diff --git a/test/e2e/fixture-builder.js b/test/e2e/fixture-builder.js index f145664346ac..ea1b3c9725d4 100644 --- a/test/e2e/fixture-builder.js +++ b/test/e2e/fixture-builder.js @@ -115,9 +115,6 @@ function onboardingFixture() { [ETHERSCAN_SUPPORTED_CHAIN_IDS.MOONRIVER]: true, [ETHERSCAN_SUPPORTED_CHAIN_IDS.GNOSIS]: true, }, - showTestNetworks: false, - smartTransactionsOptInStatus: true, - tokenNetworkFilter: {}, }, QueuedRequestController: { queuedRequestCount: 0, @@ -237,6 +234,12 @@ class FixtureBuilder { }); } + withUseBasicFunctionalityEnabled() { + return this.withPreferencesController({ + useExternalServices: true, + }); + } + withGasFeeController(data) { merge(this.fixture.data.GasFeeController, data); return this; @@ -339,21 +342,21 @@ class FixtureBuilder { }); } - withNetworkControllerDoubleGanache() { - const ganacheNetworks = mockNetworkStateOld({ + withNetworkControllerDoubleNode() { + const secondNode = mockNetworkStateOld({ id: '76e9cd59-d8e2-47e7-b369-9c205ccb602c', rpcUrl: 'http://localhost:8546', chainId: '0x53a', ticker: 'ETH', nickname: 'Localhost 8546', }); - delete ganacheNetworks.selectedNetworkClientId; - return this.withNetworkController(ganacheNetworks); + delete secondNode.selectedNetworkClientId; + return this.withNetworkController(secondNode); } - withNetworkControllerTripleGanache() { - this.withNetworkControllerDoubleGanache(); - const thirdGanache = mockNetworkStateOld({ + withNetworkControllerTripleNode() { + this.withNetworkControllerDoubleNode(); + const thirdNode = mockNetworkStateOld({ rpcUrl: 'http://localhost:7777', chainId: '0x3e8', ticker: 'ETH', @@ -361,8 +364,8 @@ class FixtureBuilder { blockExplorerUrl: undefined, }); - delete thirdGanache.selectedNetworkClientId; - merge(this.fixture.data.NetworkController, thirdGanache); + delete thirdNode.selectedNetworkClientId; + merge(this.fixture.data.NetworkController, thirdNode); return this; } @@ -1639,14 +1642,6 @@ class FixtureBuilder { }); } - withIncomingTransactionsPreferences(incomingTransactionsPreferences) { - return this.withPreferencesController({ - featureFlags: { - showIncomingTransactions: incomingTransactionsPreferences, - }, - }); - } - withIncomingTransactionsCache(cache) { return this.withTransactionController({ lastFetchedBlockNumbers: cache }); } diff --git a/test/e2e/flask/multi-srp/common-multi-srp.ts b/test/e2e/flask/multi-srp/common-multi-srp.ts index f6b287a319be..4490226a47e0 100644 --- a/test/e2e/flask/multi-srp/common-multi-srp.ts +++ b/test/e2e/flask/multi-srp/common-multi-srp.ts @@ -29,6 +29,7 @@ export async function withMultiSrp( const accountListPage = new AccountListPage(driver); await accountListPage.check_pageIsLoaded(); await accountListPage.startImportSecretPhrase(srpToUse); + await homePage.check_newSrpAddedToastIsDisplayed(); await test(driver); }, ); diff --git a/test/e2e/flask/multichain-api/testHelpers.ts b/test/e2e/flask/multichain-api/testHelpers.ts index 1c314090b0bc..05ef816e9a5c 100644 --- a/test/e2e/flask/multichain-api/testHelpers.ts +++ b/test/e2e/flask/multichain-api/testHelpers.ts @@ -1,6 +1,9 @@ import * as path from 'path'; import { By } from 'selenium-webdriver'; -import { KnownRpcMethods, KnownNotifications } from '@metamask/multichain'; +import { + KnownRpcMethods, + KnownNotifications, +} from '@metamask/chain-agnostic-permission'; import { convertETHToHexGwei, multipleGanacheOptions, @@ -9,7 +12,7 @@ import { WINDOW_TITLES, } from '../../helpers'; import { Driver } from '../../webdriver/driver'; -import { DEFAULT_GANACHE_ETH_BALANCE_DEC } from '../../constants'; +import { DEFAULT_LOCAL_NODE_ETH_BALANCE_DEC } from '../../constants'; export type FixtureCallbackArgs = { driver: Driver; extensionId: string }; @@ -33,7 +36,7 @@ export const DEFAULT_MULTICHAIN_TEST_DAPP_FIXTURE_OPTIONS = { type: 'ganache', options: { secretKey: PRIVATE_KEY, - balance: convertETHToHexGwei(DEFAULT_GANACHE_ETH_BALANCE_DEC), + balance: convertETHToHexGwei(DEFAULT_LOCAL_NODE_ETH_BALANCE_DEC), accounts: multipleGanacheOptions.accounts, }, }, diff --git a/test/e2e/flask/multichain-api/wallet_createSession.spec.ts b/test/e2e/flask/multichain-api/wallet_createSession.spec.ts index 5ff3c70d1619..5ea3b308897c 100644 --- a/test/e2e/flask/multichain-api/wallet_createSession.spec.ts +++ b/test/e2e/flask/multichain-api/wallet_createSession.spec.ts @@ -21,7 +21,7 @@ import { } from './testHelpers'; describeBrowserOnly(Browser.CHROME, 'Multichain API', function () { - describe('Connect wallet to the multichain dapp via `externally_connectable`, call `wallet_createSession` with requested EVM scope that does NOT match one of the user’s enabled networks', function () { + describe('Connect wallet to the multichain dapp via `externally_connectable`, call `wallet_createSession` with requested EVM scope that does NOT match one of the users enabled networks', function () { it("the specified EVM scopes that do not match the user's configured networks should be treated as if they were not requested", async function () { await withFixtures( { @@ -44,8 +44,13 @@ describeBrowserOnly(Browser.CHROME, 'Multichain API', function () { ...scopesToIgnore, ]); - await driver.clickElement({ text: 'Connect', tag: 'button' }); - + await driver.clickElementAndWaitForWindowToClose({ + text: 'Connect', + tag: 'button', + }); + await driver.switchToWindowWithTitle( + WINDOW_TITLES.MultichainTestDApp, + ); const getSessionResult = await testDapp.getSession(); for (const scope of scopesToIgnore) { @@ -59,13 +64,13 @@ describeBrowserOnly(Browser.CHROME, 'Multichain API', function () { }); }); - describe('Call `wallet_createSession` with EVM scopes that match the user’s enabled networks, and eip155 scoped accounts', function () { + describe("Call `wallet_createSession` with EVM scopes that match the user's enabled networks, and eip155 scoped accounts", function () { it('should ignore requested accounts that do not match accounts in the wallet and and pre-select matching requested accounts in the permission confirmation screen', async function () { await withFixtures( { title: this.test?.fullTitle(), fixtures: new FixtureBuilder() - .withNetworkControllerTripleGanache() + .withNetworkControllerTripleNode() .withTrezorAccount() .build(), ...DEFAULT_MULTICHAIN_TEST_DAPP_FIXTURE_OPTIONS, @@ -90,7 +95,13 @@ describeBrowserOnly(Browser.CHROME, 'Multichain API', function () { [SECOND_ACCOUNT_IN_WALLET, ACCOUNT_NOT_IN_WALLET], ); - await driver.clickElement({ text: 'Connect', tag: 'button' }); + await driver.clickElementAndWaitForWindowToClose({ + text: 'Connect', + tag: 'button', + }); + await driver.switchToWindowWithTitle( + WINDOW_TITLES.MultichainTestDApp, + ); const getSessionResult = await testDapp.getSession(); /** @@ -148,7 +159,11 @@ describeBrowserOnly(Browser.CHROME, 'Multichain API', function () { ); for (const item of networkListItems) { - const network = await item.getText(); + const networkNameDiv = await item.findElement( + By.css('div[data-testid]'), + ); + const network = await networkNameDiv.getAttribute('data-testid'); + const checkbox = await item.findElement( By.css('input[type="checkbox"]'), ); @@ -173,13 +188,13 @@ describeBrowserOnly(Browser.CHROME, 'Multichain API', function () { }); describe('Call `wallet_createSession`', function () { - describe('With requested EVM scope that match the user’s enabled networks, edit selection in wallet UI', function () { + describe("With requested EVM scope that match the user's enabled networks, edit selection in wallet UI", function () { it('should change result according to changed network & accounts', async function () { await withFixtures( { title: this.test?.fullTitle(), fixtures: new FixtureBuilder() - .withNetworkControllerTripleGanache() + .withNetworkControllerTripleNode() .withPreferencesControllerAdditionalAccountIdentities() .build(), ...DEFAULT_MULTICHAIN_TEST_DAPP_FIXTURE_OPTIONS, @@ -202,7 +217,13 @@ describeBrowserOnly(Browser.CHROME, 'Multichain API', function () { await permissionsTab.click(); await updateNetworkCheckboxes(driver, ['Localhost 8545']); - await driver.clickElement({ text: 'Connect', tag: 'button' }); + await driver.clickElementAndWaitForWindowToClose({ + text: 'Connect', + tag: 'button', + }); + await driver.switchToWindowWithTitle( + WINDOW_TITLES.MultichainTestDApp, + ); const getSessionResult = await testDapp.getSession(); @@ -267,7 +288,7 @@ describeBrowserOnly(Browser.CHROME, 'Multichain API', function () { { title: this.test?.fullTitle(), fixtures: new FixtureBuilder() - .withNetworkControllerTripleGanache() + .withNetworkControllerTripleNode() .withPreferencesControllerAdditionalAccountIdentities() .build(), ...DEFAULT_MULTICHAIN_TEST_DAPP_FIXTURE_OPTIONS, @@ -282,7 +303,10 @@ describeBrowserOnly(Browser.CHROME, 'Multichain API', function () { await addAccountInWalletAndAuthorize(driver); - await driver.clickElement({ text: 'Connect', tag: 'button' }); + await driver.clickElementAndWaitForWindowToClose({ + text: 'Connect', + tag: 'button', + }); await driver.switchToWindowWithTitle( WINDOW_TITLES.MultichainTestDApp, ); @@ -355,7 +379,7 @@ describeBrowserOnly(Browser.CHROME, 'Multichain API', function () { { title: this.test?.fullTitle(), fixtures: new FixtureBuilder() - .withNetworkControllerTripleGanache() + .withNetworkControllerTripleNode() .withPermissionControllerConnectedToMultichainTestDappWithTwoAccounts( { scopes: OLD_SCOPES, @@ -392,7 +416,13 @@ describeBrowserOnly(Browser.CHROME, 'Multichain API', function () { await driver.clickElement(`input[name="${scope}"]`), ); await testDapp.initCreateSessionScopes(NEW_SCOPES, [TREZOR_ACCOUNT]); - await driver.clickElement({ text: 'Connect', tag: 'button' }); + await driver.clickElementAndWaitForWindowToClose({ + text: 'Connect', + tag: 'button', + }); + await driver.switchToWindowWithTitle( + WINDOW_TITLES.MultichainTestDApp, + ); await driver.delay(largeDelayMs); const newgetSessionResult = await testDapp.getSession(); diff --git a/test/e2e/flask/multichain-api/wallet_invokeMethod.spec.ts b/test/e2e/flask/multichain-api/wallet_invokeMethod.spec.ts index 30f8c7fdb8b5..fef21e0b4f2f 100644 --- a/test/e2e/flask/multichain-api/wallet_invokeMethod.spec.ts +++ b/test/e2e/flask/multichain-api/wallet_invokeMethod.spec.ts @@ -10,7 +10,7 @@ import { withFixtures, } from '../../helpers'; import FixtureBuilder from '../../fixture-builder'; -import { DEFAULT_GANACHE_ETH_BALANCE_DEC } from '../../constants'; +import { DEFAULT_LOCAL_NODE_ETH_BALANCE_DEC } from '../../constants'; import TestDappMultichain from '../../page-objects/pages/test-dapp-multichain'; import { DEFAULT_MULTICHAIN_TEST_DAPP_FIXTURE_OPTIONS, @@ -24,7 +24,7 @@ describeBrowserOnly(Browser.CHROME, 'Multichain API', function () { const GANACHE_SCOPES = ['eip155:1337', 'eip155:1338', 'eip155:1000']; const ACCOUNTS = [ACCOUNT_1, ACCOUNT_2]; const DEFAULT_INITIAL_BALANCE_HEX = convertETHToHexGwei( - DEFAULT_GANACHE_ETH_BALANCE_DEC, + DEFAULT_LOCAL_NODE_ETH_BALANCE_DEC, ); describe('Calling `wallet_invokeMethod` on the same dapp across three different connected chains', function () { @@ -34,7 +34,7 @@ describeBrowserOnly(Browser.CHROME, 'Multichain API', function () { { title: this.test?.fullTitle(), fixtures: new FixtureBuilder() - .withNetworkControllerTripleGanache() + .withNetworkControllerTripleNode() .build(), ...DEFAULT_MULTICHAIN_TEST_DAPP_FIXTURE_OPTIONS, }, @@ -98,7 +98,7 @@ describeBrowserOnly(Browser.CHROME, 'Multichain API', function () { { title: this.test?.fullTitle(), fixtures: new FixtureBuilder() - .withNetworkControllerTripleGanache() + .withNetworkControllerTripleNode() .build(), ...DEFAULT_MULTICHAIN_TEST_DAPP_FIXTURE_OPTIONS, }, @@ -164,7 +164,7 @@ describeBrowserOnly(Browser.CHROME, 'Multichain API', function () { { title: this.test?.fullTitle(), fixtures: new FixtureBuilder() - .withNetworkControllerTripleGanache() + .withNetworkControllerTripleNode() .build(), ...DEFAULT_MULTICHAIN_TEST_DAPP_FIXTURE_OPTIONS, }, diff --git a/test/e2e/flask/multichain-api/wallet_revokeSession.spec.ts b/test/e2e/flask/multichain-api/wallet_revokeSession.spec.ts index 5d1cf2f1f51b..cc32568ad17a 100644 --- a/test/e2e/flask/multichain-api/wallet_revokeSession.spec.ts +++ b/test/e2e/flask/multichain-api/wallet_revokeSession.spec.ts @@ -29,7 +29,7 @@ describeBrowserOnly( { title: this.test?.fullTitle(), fixtures: new FixtureBuilder() - .withNetworkControllerTripleGanache() + .withNetworkControllerTripleNode() .build(), ...DEFAULT_MULTICHAIN_TEST_DAPP_FIXTURE_OPTIONS, }, @@ -77,7 +77,7 @@ describeBrowserOnly( { title: this.test?.fullTitle(), fixtures: new FixtureBuilder() - .withNetworkControllerTripleGanache() + .withNetworkControllerTripleNode() .build(), ...DEFAULT_MULTICHAIN_TEST_DAPP_FIXTURE_OPTIONS, }, diff --git a/test/e2e/flask/multichain-api/wallet_sessionChanged.spec.ts b/test/e2e/flask/multichain-api/wallet_sessionChanged.spec.ts index 1d266b0fb2f9..935921efc10e 100644 --- a/test/e2e/flask/multichain-api/wallet_sessionChanged.spec.ts +++ b/test/e2e/flask/multichain-api/wallet_sessionChanged.spec.ts @@ -34,7 +34,7 @@ describeBrowserOnly( { title: this.test?.fullTitle(), fixtures: new FixtureBuilder() - .withNetworkControllerTripleGanache() + .withNetworkControllerTripleNode() .build(), ...DEFAULT_MULTICHAIN_TEST_DAPP_FIXTURE_OPTIONS, }, diff --git a/test/e2e/flask/solana/check-balance.spec.ts b/test/e2e/flask/solana/check-balance.spec.ts index 3ae44d7e30bb..7a33f104d1d3 100644 --- a/test/e2e/flask/solana/check-balance.spec.ts +++ b/test/e2e/flask/solana/check-balance.spec.ts @@ -39,7 +39,7 @@ describe('Check balance', function (this: Suite) { }, async (driver) => { const homePage = new NonEvmHomepage(driver); - await homePage.check_getBalance('$9,921.00', 'USD'); + await homePage.check_getBalance('$5,643.50', 'USD'); }, ); }); diff --git a/test/e2e/flask/solana/common-solana.ts b/test/e2e/flask/solana/common-solana.ts index de04ea998189..959611c2a9a7 100644 --- a/test/e2e/flask/solana/common-solana.ts +++ b/test/e2e/flask/solana/common-solana.ts @@ -1,4 +1,4 @@ -import { Mockttp } from 'mockttp'; +import { Mockttp, MockedEndpoint } from 'mockttp'; import { withFixtures } from '../../helpers'; import { Driver } from '../../webdriver/driver'; import HeaderNavbar from '../../page-objects/pages/header-navbar'; @@ -26,7 +26,9 @@ export const METAMASK_PHISHING_DETECTION_API = /^https:\/\/phishing-detection\.api\.cx\.metamask\.io\/$/u; export const METAMASK_CLIENT_SIDE_DETECTION_REGEX = /^https:\/\/client-side-detection\.api\.cx\.metamask\.io\/$/u; - +export const ACCOUNTS_API = + /^https:\/\/accounts\.api\.cx\.metamask\.io\/v1\/accounts\/0x5cfe73b6021e818b776b421b1c4db2474086a7e1\/$/u; +export const SOLANA_TOKEN_PROGRAM = 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA'; export enum SendFlowPlaceHolders { AMOUNT = 'Enter amount to send', RECIPIENT = 'Enter receiving address', @@ -56,6 +58,29 @@ export const commonSolanaTxConfirmedDetailsFixture = { '3AcYfpsSaFYogY4Y4YN77MkhDgVBEgUe1vuEeqKnCMm5udTrFCyw9w17mNM8DUnHnQD2VHRFeipMUb27Q3iqMQJr', }; +export async function mockAccountsApi(mockServer: Mockttp) { + const response = { + pageInfo: { + count: 0, + cursor: null, + hasNextPage: false + }, + data: [], + unprocessedNetworks: [] +}; + return await mockServer + .forGet(ACCOUNTS_API) + .withQuery({ + networks: '0x1,0x89,0x38,0xe708,0x2105,0xa,0xa4b1,0x82750', + }) + .thenCallback(() => { + return { + statusCode: 200, + json: response + }; + }); +} + export async function mockClientSideDetectionApi(mockServer: Mockttp) { return await mockServer .forPost(METAMASK_CLIENT_SIDE_DETECTION_REGEX) @@ -92,12 +117,48 @@ export async function mockPriceApiSpotPrice(mockServer: Mockttp) { statusCode: 200, json: { 'solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp/slip44:501': { - usd: 198.42, + id: "solana", + price: 112.87, + marketCap: 58245152246, + allTimeHigh: 293.31, + allTimeLow: 0.500801, + totalVolume: 6991628445, + high1d: 119.85, + low1d: 105.87, + circulatingSupply: 515615042.5147497, + dilutedMarketCap: 67566552200, + marketCapPercentChange1d: 6.43259, + priceChange1d: 6.91, + pricePercentChange1h: -0.10747351712871725, + pricePercentChange1d: 6.517062579985171, + pricePercentChange7d: -1.2651850097746231, + pricePercentChange14d: -17.42211401987578, + pricePercentChange30d: -7.317068682545842, + pricePercentChange200d: -22.09390252653303, + pricePercentChange1y: -31.856951873653344 }, 'solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp/token:2zMMhcVQEXDtdE6vsFS7S7D5oUodfJHE8vd1gnBouauv': { - usd: 0.01157283, - }, + id: "usd-coin", + price: 0.9999, + marketCap: 59878237545, + allTimeHigh: 1.17, + allTimeLow: 0.877647, + totalVolume: 15910794136, + high1d: 1.001, + low1d: 0.999781, + circulatingSupply: 59884477611.62816, + dilutedMarketCap: 59993084685, + marketCapPercentChange1d: -0.54935, + priceChange1d: -0.00000967395266227, + pricePercentChange1h: -0.0036230127807169886, + pricePercentChange1d: -0.0009674830537401128, + pricePercentChange7d: -0.0040353282511238105, + pricePercentChange14d: 0.008577550625780632, + pricePercentChange30d: 0.004483705121822349, + pricePercentChange200d: 0.029482859180996183, + pricePercentChange1y: -0.11068819291624574 + }, }, }; return await mockServer.forGet(SOLANA_SPOT_PRICE_API).thenCallback(() => { @@ -442,6 +503,33 @@ export async function mockStaticMetamaskTokenIconDevnet(mockServer: Mockttp) { }); } +export async function mockTokenApiMainnetTest(mockServer: Mockttp) { + console.log('mockTokenApi'); + const response = { + statusCode: 200, + json: [ + { + decimals: 9, + assetId: 'solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp/slip44:501', + name: 'Solana', + symbol: 'SOL', + }, + { + decimals: 6, + assetId: + 'solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp/token:2RBko3xoz56aH69isQMUpzZd9NYHahhwC23A5F3Spkin', + name: 'PUMPKIN', + symbol: 'PKIN', + }, + ], + }; + return await mockServer + .forGet(SOLANA_TOKEN_API) + .thenCallback(() => { + return response; + }); +} + export async function mockTokenApiMainnet(mockServer: Mockttp) { console.log('mockTokenApi'); const response = { @@ -467,6 +555,60 @@ export async function mockTokenApiMainnet(mockServer: Mockttp) { }); } +export async function mockTokenApiMainnet2(mockServer: Mockttp) { + console.log('mockTokenApi'); + const response = { + statusCode: 200, + json: [ + { + decimals: 9, + assetId: "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp/slip44:501", + name: "Solana", + symbol: "SOL" + }, + { + decimals: 9, + assetId: "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1/slip44:501", + name: "Solana", + symbol: "SOL" + } + ] + }; + return await mockServer + .forGet(SOLANA_TOKEN_API) + .withQuery({ + assetIds: + 'solana%5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp%2Fslip44%3A501%2Csolana%3AEtWTRABZaYq6iMfeYKouRu166VU2xqa1%2Fslip44%3A501', + }) + .thenCallback(() => { + return response; + }); +} + +export async function mockTokenApiDevnet2(mockServer: Mockttp) { + console.log('mockTokenApi'); + const response = { + statusCode: 200, + json: [ + { + decimals: 9, + assetId: 'solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1/slip44:501', + name: 'Solana', + symbol: 'SOL', + }, + ], + }; + return await mockServer + .forGet(SOLANA_TOKEN_API) + .withQuery({ + assetIds: + 'solana%3AEtWTRABZaYq6iMfeYKouRu166VU2xqa1%2Fslip44%3A501', + }) + .thenCallback(() => { + return response; + }); +} + export async function mockTokenApiDevnet(mockServer: Mockttp) { console.log('mockTokenApi'); const response = { @@ -568,6 +710,50 @@ export async function mockSolanaBalanceQuoteDevnet( }); } +export async function simulateSolanaTransactionFailed( + mockServer: Mockttp, +) { + const response = { + statusCode: 200, + json: { + result: { + "jsonrpc": "2.0", + "result": { + "context": { + "slot": 12345678 + }, + "value": { + "err": { + "InstructionError": [ + 1, + { + "Custom": 1 + } + ] + }, + "logs": [ + "Program 11111111111111111111111111111111 invoke [1]", + "Program 11111111111111111111111111111111 failed: custom program error: 0x1" + ], + "accounts": null, + "unitsConsumed": 200000 + } + }, + "id": 1 + } + }, + }; + + return await mockServer + .forPost(SOLANA_URL_REGEX_MAINNET) + .withJsonBodyIncluding({ + method: 'simulateTransaction', + }) + .thenCallback(() => { + return response; + }); +} + export async function simulateSolanaTransaction( mockServer: Mockttp, isNative: boolean = true, @@ -1214,41 +1400,685 @@ export async function mockGetFailedTransaction(mockServer: Mockttp) { return response; }); } -export async function mockGetSuccessTransaction(mockServer: Mockttp) { +export async function mockGetFailedTransactionDevnet(mockServer: Mockttp) { + console.log('mockGetFailedTransaction'); const response = { statusCode: 200, json: { result: { - blockTime: 1739973211, + blockTime: 1739988764, meta: { - computeUnitsConsumed: 150, - err: null, - fee: 5000, - innerInstructions: [], - loadedAddresses: { - readonly: [], - writable: [], + computeUnitsConsumed: 227081, + err: { + InstructionError: [6, 'ProgramFailedToComplete'], }, - logMessages: [ - 'Program 11111111111111111111111111111111 invoke [1]', - 'Program 11111111111111111111111111111111 success', + fee: 5003, + innerInstructions: [ + { + index: 6, + instructions: [ + { + accounts: [ + 24, 32, 25, 26, 1, 2, 30, 28, 27, 32, 0, 29, 29, 33, 32, 4, + 5, 6, + ], + data: 'PgQWtn8oziwv4wjywURrfSUpN2afyjR5h', + programIdIndex: 32, + stackHeight: 2, + }, + { + accounts: [1, 28, 26, 0], + data: 'geX9xF4vG8SRn', + programIdIndex: 29, + stackHeight: 3, + }, + { + accounts: [25, 30, 2, 24], + data: 'iQbm5aGXcxE2q', + programIdIndex: 29, + stackHeight: 3, + }, + { + accounts: [33], + data: 'yCGxBopjnVNQkNP5usq1Poz4fRguySgsQmFH4UH3WnybnnKLMv4E31ZgcviiVVBcdfGH9CKN1QJU2sGMDjSL2BMngeWNEuZYV2pntb9tQCA4bAj2h9auc55vN4spYstjhyVHhbVVEdMguD2c8hS718SW5Cs3cL7wcVJgN4R6B7f172DL8guGbHgggrWHtkb31aqgVV', + programIdIndex: 32, + stackHeight: 3, + }, + { + accounts: [14], + data: 'QMqFu4fYGGeUEysFnenhAvBobXTzswhLdvQq6s8axxcbKUPRksm2543pJNNNHVd1VJ58FCg7NVh9cMuPYiMKNyfUpUXSDci9arMkqVwgC1zp8zDJwW7pyDP9b5cYa5qw53EeE5G8kdfjFeQwWaSmPrybVSiwipxHWP5ipHGTNnrUbod', + programIdIndex: 13, + stackHeight: 2, + }, + { + accounts: [ + 15, 32, 16, 17, 2, 3, 31, 30, 18, 32, 0, 29, 29, 33, 32, 19, + ], + data: 'PgQWtn8ozixD9F2rzgmrRy83iHAQSKhno', + programIdIndex: 32, + stackHeight: 2, + }, + { + accounts: [2, 30, 17, 0], + data: 'iQbm5aGXcxE2q', + programIdIndex: 29, + stackHeight: 3, + }, + { + accounts: [16, 31, 3, 15], + data: 'jEX4PcL3MYVoN', + programIdIndex: 29, + stackHeight: 3, + }, + { + accounts: [33], + data: 'yCGxBopjnVNQkNP5usq1PnieAT94qLJpXa7U5hQkqcasRRm8PypkFAXYpuQGWQAoTxcq1bAZrnBrU784NtdfP6EpvkxuNJ6oaWAnRT6a87P3VcuyXHTeeYtN78WZ5Y2YgyezMPkdTThHhms9dCo3rFchirvKRkbTvZhaXbMvMrzz7gRZP5DStrrEAbjHtp8cdKyWFZ', + programIdIndex: 32, + stackHeight: 3, + }, + { + accounts: [14], + data: 'QMqFu4fYGGeUEysFnenhAvBobXTzswhLdvQq6s8axxcbKUPRksm2543pJNNNHVd1VJwXfcUWQEHusMZ55Vd8C9CLFM5Wg9RwxshnjoSxBQonfjBTF9DYwGyEnAnKT6FoERcF8QDWA2psNoVS9PWDLncAJNG4bgXBc2NQoBSm5mxV2xP', + programIdIndex: 13, + stackHeight: 2, + }, + { + accounts: [ + 20, 32, 21, 22, 3, 1, 31, 28, 23, 32, 0, 29, 29, 33, 32, 7, + 8, 9, + ], + data: 'PgQWtn8ozixMA7i75HkXhsJ6xryM1VG3H', + programIdIndex: 32, + stackHeight: 2, + }, + { + accounts: [3, 31, 21, 0], + data: 'jEX4PcL3MYVoN', + programIdIndex: 29, + stackHeight: 3, + }, + { + accounts: [22, 28, 1, 20], + data: 'gzSGobBbETi3r', + programIdIndex: 29, + stackHeight: 3, + }, + { + accounts: [33], + data: 'yCGxBopjnVNQkNP5usq1Pov6GJuCoryx81NaK44ZYA3PaVLCYuN6xV4Ew7eNzQ39FF8zgnQFCeARbJ7AVTLD5XgiEbMqMQnBmYA3JfmpmA83yXNWT2Jk71eyjkv2HnM9s2kgNbHGjkx8DrNaQBjKrx89Rnze2qCpDZjRvnn2mmHR8fAV826kLzY7ifBRLNXnQVfQij', + programIdIndex: 32, + stackHeight: 3, + }, + { + accounts: [14], + data: 'QMqFu4fYGGeUEysFnenhAvBobXTzswhLdvQq6s8axxcbKUPRksm2543pJNNNHVd1VKMQxCUWZtjhztwssiahZW5QRwrQ9AZP1GpjxfNbrheNNgSZSoWNdzCeXo4HbeAxfB9UkFNT26YXZmkQbpve8ATHJynLE2hp2zzz9fhqgqevi9M', + programIdIndex: 13, + stackHeight: 2, + }, + ], + }, ], - postBalances: [6995200, 525845878579, 1], - postTokenBalances: [], - preBalances: [14078760, 525838800019, 1], - preTokenBalances: [], - rewards: [], - status: { - Ok: null, - }, - }, - slot: 321700491, - transaction: { - message: { - accountKeys: [ - 'HH9ZzgQvSVmznKcRfwHuEphuxk7zU5f92CkXFDQfVJcq', - 'AL9Z5JgZdeCKnaYg6jduy9PQGzo3moo7vZYVSTJwnSEq', - '11111111111111111111111111111111', + loadedAddresses: { + readonly: [ + 'So11111111111111111111111111111111111111112', + 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA', + '6p6xgHyF7AeE6TZkSmFsko444wqoP15icUSqi2jfGiPN', + '9McvH6w97oewLmPxqQEoHUAv3u5iYMyQ9AeZZhguYf1T', + 'LBUZKhRxPF3XUpBCjp4YzTKgLccjZhTSDM9YuVaPwxo', + 'D1ZN9Wj1fRSUQfCjhvnu1hqDMT7hzjzBBpi12nVniYD6', + ], + writable: [ + '29reKMpP4V3czq4nCyHcT1xtaLbajXoMdULge8spA4jF', + 'EDY2fMWABHRNkaWy9LkfoQumJLN1y3RJY4UYnupt1FE4', + 'B3PDScDob59VGqQ5uk7V3ykRwermmAms6kaEJh6TQXFM', + 'Ff7oak29LVz2AFt93TSxU5npcBYS4T35CEsBH2XtgPM1', + '45AwfA9GQ1Vt5bFowhJPX9sSGHqVELpEEhPZ1cWh2eC2', + 'CW65UBkNMFDYGy2jZBenxihs9Gqh6y6opTDzS8txxyAK', + '6UabcCKafVh29VZknaMQduf8SXiamaXxDUiZty2gfw5B', + 'G2LeRmQbTUFrLXhWJPPUpSx28eVkd7iHg1GyGC6MNAFJ', + 'FicnHXkPCPjuctuxLZH23BjzcN4Zsa5CNHtpXf64CdZS', + 'D6RL6sWrs6khn7AfEyS6dsqqiiqAh4hXC83JtcmEUf6D', + '3MNsvVWUNVM67aGMKMzBgcMKhvc9HsNdwz2RaKHwwEv4', + '2x3UPXgacTTQp45bvx7UbXuHjrwa4J9jfAE8HB2YdjgU', + 'B44GzRdUq48vBUbppeWxV51PtC7P25U6YA3GDuMqpGdW', + ], + }, + logMessages: [ + 'Program ComputeBudget111111111111111111111111111111 invoke [1]', + 'Program ComputeBudget111111111111111111111111111111 success', + 'Program ComputeBudget111111111111111111111111111111 invoke [1]', + 'Program ComputeBudget111111111111111111111111111111 success', + 'Program ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL invoke [1]', + 'Program log: CreateIdempotent', + 'Program ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL consumed 4339 of 226781 compute units', + 'Program ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL success', + 'Program ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL invoke [1]', + 'Program log: CreateIdempotent', + 'Program ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL consumed 4338 of 222442 compute units', + 'Program ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL success', + 'Program ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL invoke [1]', + 'Program log: CreateIdempotent', + 'Program ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL consumed 4338 of 218104 compute units', + 'Program ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL success', + 'Program ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL invoke [1]', + 'Program log: CreateIdempotent', + 'Program ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL consumed 4339 of 213766 compute units', + 'Program ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL success', + 'Program JUPSjgjMFjU4453KMgxhqVmzep6W352bQpE4RsNqXAx invoke [1]', + 'Program LBUZKhRxPF3XUpBCjp4YzTKgLccjZhTSDM9YuVaPwxo invoke [2]', + 'Program log: Instruction: Swap', + 'Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA invoke [3]', + 'Program log: Instruction: TransferChecked', + 'Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA consumed 6238 of 160377 compute units', + 'Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA success', + 'Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA invoke [3]', + 'Program log: Instruction: TransferChecked', + 'Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA consumed 6147 of 150705 compute units', + 'Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA success', + 'Program LBUZKhRxPF3XUpBCjp4YzTKgLccjZhTSDM9YuVaPwxo invoke [3]', + 'Program LBUZKhRxPF3XUpBCjp4YzTKgLccjZhTSDM9YuVaPwxo consumed 2134 of 141124 compute units', + 'Program LBUZKhRxPF3XUpBCjp4YzTKgLccjZhTSDM9YuVaPwxo success', + 'Program LBUZKhRxPF3XUpBCjp4YzTKgLccjZhTSDM9YuVaPwxo consumed 63909 of 201331 compute units', + 'Program LBUZKhRxPF3XUpBCjp4YzTKgLccjZhTSDM9YuVaPwxo success', + 'Program JUPSjgjMFjU4453KMgxhqVmzep6W352bQpE4RsNqXAx invoke [2]', + 'Program JUPSjgjMFjU4453KMgxhqVmzep6W352bQpE4RsNqXAx consumed 182 of 135690 compute units', + 'Program JUPSjgjMFjU4453KMgxhqVmzep6W352bQpE4RsNqXAx success', + 'Program LBUZKhRxPF3XUpBCjp4YzTKgLccjZhTSDM9YuVaPwxo invoke [2]', + 'Program log: Instruction: Swap', + 'Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA invoke [3]', + 'Program log: Instruction: TransferChecked', + 'Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA consumed 6147 of 90588 compute units', + 'Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA success', + 'Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA invoke [3]', + 'Program log: Instruction: TransferChecked', + 'Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA consumed 6173 of 81007 compute units', + 'Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA success', + 'Program LBUZKhRxPF3XUpBCjp4YzTKgLccjZhTSDM9YuVaPwxo invoke [3]', + 'Program LBUZKhRxPF3XUpBCjp4YzTKgLccjZhTSDM9YuVaPwxo consumed 2134 of 71400 compute units', + 'Program LBUZKhRxPF3XUpBCjp4YzTKgLccjZhTSDM9YuVaPwxo success', + 'Program LBUZKhRxPF3XUpBCjp4YzTKgLccjZhTSDM9YuVaPwxo consumed 62873 of 130639 compute units', + 'Program LBUZKhRxPF3XUpBCjp4YzTKgLccjZhTSDM9YuVaPwxo success', + 'Program JUPSjgjMFjU4453KMgxhqVmzep6W352bQpE4RsNqXAx invoke [2]', + 'Program JUPSjgjMFjU4453KMgxhqVmzep6W352bQpE4RsNqXAx consumed 182 of 66034 compute units', + 'Program JUPSjgjMFjU4453KMgxhqVmzep6W352bQpE4RsNqXAx success', + 'Program LBUZKhRxPF3XUpBCjp4YzTKgLccjZhTSDM9YuVaPwxo invoke [2]', + 'Program log: Instruction: Swap', + 'Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA invoke [3]', + 'Program log: Instruction: TransferChecked', + 'Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA consumed 6173 of 24780 compute units', + 'Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA success', + 'Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA invoke [3]', + 'Program log: Instruction: TransferChecked', + 'Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA consumed 6238 of 15174 compute units', + 'Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA success', + 'Program LBUZKhRxPF3XUpBCjp4YzTKgLccjZhTSDM9YuVaPwxo invoke [3]', + 'Program LBUZKhRxPF3XUpBCjp4YzTKgLccjZhTSDM9YuVaPwxo consumed 2134 of 5505 compute units', + 'Program LBUZKhRxPF3XUpBCjp4YzTKgLccjZhTSDM9YuVaPwxo success', + 'Program LBUZKhRxPF3XUpBCjp4YzTKgLccjZhTSDM9YuVaPwxo consumed 58872 of 60675 compute units', + 'Program LBUZKhRxPF3XUpBCjp4YzTKgLccjZhTSDM9YuVaPwxo success', + 'Program JUPSjgjMFjU4453KMgxhqVmzep6W352bQpE4RsNqXAx invoke [2]', + 'Program JUPSjgjMFjU4453KMgxhqVmzep6W352bQpE4RsNqXAx consumed 71 of 71 compute units', + 'Program JUPSjgjMFjU4453KMgxhqVmzep6W352bQpE4RsNqXAx failed: exceeded CUs meter at BPF instruction', + 'Program JUPSjgjMFjU4453KMgxhqVmzep6W352bQpE4RsNqXAx consumed 209427 of 209427 compute units', + 'Program JUPSjgjMFjU4453KMgxhqVmzep6W352bQpE4RsNqXAx failed: Program failed to complete', + ], + postBalances: [ + 2214757471, 24524198861, 2039280, 2039280, 71437440, 71437440, + 71437440, 71437440, 71437440, 71437440, 1, 731913600, 1, 1141440, 0, + 7182720, 2039280, 2039280, 23385600, 71437440, 7282720, 2039280, + 296172641647, 23385600, 7182721, 2039280, 45847462984, 23385600, + 959143176713, 934087680, 1335629455120, 27971524604, 1141440, + 4000000, + ], + postTokenBalances: [ + { + accountIndex: 1, + mint: 'So11111111111111111111111111111111111111112', + owner: 's3zTLVvDbrBzbQ36sr2Z4xrzpRHFv3noWChbNi6vcjr', + programId: 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA', + uiTokenAmount: { + amount: '24522159581', + decimals: 9, + uiAmount: 24.522159581, + uiAmountString: '24.522159581', + }, + }, + { + accountIndex: 2, + mint: '6p6xgHyF7AeE6TZkSmFsko444wqoP15icUSqi2jfGiPN', + owner: 's3zTLVvDbrBzbQ36sr2Z4xrzpRHFv3noWChbNi6vcjr', + programId: 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA', + uiTokenAmount: { + amount: '0', + decimals: 6, + uiAmount: null, + uiAmountString: '0', + }, + }, + { + accountIndex: 3, + mint: '9McvH6w97oewLmPxqQEoHUAv3u5iYMyQ9AeZZhguYf1T', + owner: 's3zTLVvDbrBzbQ36sr2Z4xrzpRHFv3noWChbNi6vcjr', + programId: 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA', + uiTokenAmount: { + amount: '0', + decimals: 9, + uiAmount: null, + uiAmountString: '0', + }, + }, + { + accountIndex: 16, + mint: '9McvH6w97oewLmPxqQEoHUAv3u5iYMyQ9AeZZhguYf1T', + owner: '29reKMpP4V3czq4nCyHcT1xtaLbajXoMdULge8spA4jF', + programId: 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA', + uiTokenAmount: { + amount: '2636762152', + decimals: 9, + uiAmount: 2.636762152, + uiAmountString: '2.636762152', + }, + }, + { + accountIndex: 17, + mint: '6p6xgHyF7AeE6TZkSmFsko444wqoP15icUSqi2jfGiPN', + owner: '29reKMpP4V3czq4nCyHcT1xtaLbajXoMdULge8spA4jF', + programId: 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA', + uiTokenAmount: { + amount: '7264154', + decimals: 6, + uiAmount: 7.264154, + uiAmountString: '7.264154', + }, + }, + { + accountIndex: 21, + mint: '9McvH6w97oewLmPxqQEoHUAv3u5iYMyQ9AeZZhguYf1T', + owner: 'CW65UBkNMFDYGy2jZBenxihs9Gqh6y6opTDzS8txxyAK', + programId: 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA', + uiTokenAmount: { + amount: '8191355381419', + decimals: 9, + uiAmount: 8191.355381419, + uiAmountString: '8191.355381419', + }, + }, + { + accountIndex: 22, + mint: 'So11111111111111111111111111111111111111112', + owner: 'CW65UBkNMFDYGy2jZBenxihs9Gqh6y6opTDzS8txxyAK', + programId: 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA', + uiTokenAmount: { + amount: '296170602367', + decimals: 9, + uiAmount: 296.170602367, + uiAmountString: '296.170602367', + }, + }, + { + accountIndex: 25, + mint: '6p6xgHyF7AeE6TZkSmFsko444wqoP15icUSqi2jfGiPN', + owner: 'D6RL6sWrs6khn7AfEyS6dsqqiiqAh4hXC83JtcmEUf6D', + programId: 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA', + uiTokenAmount: { + amount: '884477775', + decimals: 6, + uiAmount: 884.477775, + uiAmountString: '884.477775', + }, + }, + { + accountIndex: 26, + mint: 'So11111111111111111111111111111111111111112', + owner: 'D6RL6sWrs6khn7AfEyS6dsqqiiqAh4hXC83JtcmEUf6D', + programId: 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA', + uiTokenAmount: { + amount: '45845423703', + decimals: 9, + uiAmount: 45.845423703, + uiAmountString: '45.845423703', + }, + }, + ], + preBalances: [ + 2214762474, 24524198861, 2039280, 2039280, 71437440, 71437440, + 71437440, 71437440, 71437440, 71437440, 1, 731913600, 1, 1141440, 0, + 7182720, 2039280, 2039280, 23385600, 71437440, 7282720, 2039280, + 296172641647, 23385600, 7182721, 2039280, 45847462984, 23385600, + 959143176713, 934087680, 1335629455120, 27971524604, 1141440, + 4000000, + ], + preTokenBalances: [ + { + accountIndex: 1, + mint: 'So11111111111111111111111111111111111111112', + owner: 's3zTLVvDbrBzbQ36sr2Z4xrzpRHFv3noWChbNi6vcjr', + programId: 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA', + uiTokenAmount: { + amount: '24522159581', + decimals: 9, + uiAmount: 24.522159581, + uiAmountString: '24.522159581', + }, + }, + { + accountIndex: 2, + mint: '6p6xgHyF7AeE6TZkSmFsko444wqoP15icUSqi2jfGiPN', + owner: 's3zTLVvDbrBzbQ36sr2Z4xrzpRHFv3noWChbNi6vcjr', + programId: 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA', + uiTokenAmount: { + amount: '0', + decimals: 6, + uiAmount: null, + uiAmountString: '0', + }, + }, + { + accountIndex: 3, + mint: '9McvH6w97oewLmPxqQEoHUAv3u5iYMyQ9AeZZhguYf1T', + owner: 's3zTLVvDbrBzbQ36sr2Z4xrzpRHFv3noWChbNi6vcjr', + programId: 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA', + uiTokenAmount: { + amount: '0', + decimals: 9, + uiAmount: null, + uiAmountString: '0', + }, + }, + { + accountIndex: 16, + mint: '9McvH6w97oewLmPxqQEoHUAv3u5iYMyQ9AeZZhguYf1T', + owner: '29reKMpP4V3czq4nCyHcT1xtaLbajXoMdULge8spA4jF', + programId: 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA', + uiTokenAmount: { + amount: '2636762152', + decimals: 9, + uiAmount: 2.636762152, + uiAmountString: '2.636762152', + }, + }, + { + accountIndex: 17, + mint: '6p6xgHyF7AeE6TZkSmFsko444wqoP15icUSqi2jfGiPN', + owner: '29reKMpP4V3czq4nCyHcT1xtaLbajXoMdULge8spA4jF', + programId: 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA', + uiTokenAmount: { + amount: '7264154', + decimals: 6, + uiAmount: 7.264154, + uiAmountString: '7.264154', + }, + }, + { + accountIndex: 21, + mint: '9McvH6w97oewLmPxqQEoHUAv3u5iYMyQ9AeZZhguYf1T', + owner: 'CW65UBkNMFDYGy2jZBenxihs9Gqh6y6opTDzS8txxyAK', + programId: 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA', + uiTokenAmount: { + amount: '8191355381419', + decimals: 9, + uiAmount: 8191.355381419, + uiAmountString: '8191.355381419', + }, + }, + { + accountIndex: 22, + mint: 'So11111111111111111111111111111111111111112', + owner: 'CW65UBkNMFDYGy2jZBenxihs9Gqh6y6opTDzS8txxyAK', + programId: 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA', + uiTokenAmount: { + amount: '296170602367', + decimals: 9, + uiAmount: 296.170602367, + uiAmountString: '296.170602367', + }, + }, + { + accountIndex: 25, + mint: '6p6xgHyF7AeE6TZkSmFsko444wqoP15icUSqi2jfGiPN', + owner: 'D6RL6sWrs6khn7AfEyS6dsqqiiqAh4hXC83JtcmEUf6D', + programId: 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA', + uiTokenAmount: { + amount: '884477775', + decimals: 6, + uiAmount: 884.477775, + uiAmountString: '884.477775', + }, + }, + { + accountIndex: 26, + mint: 'So11111111111111111111111111111111111111112', + owner: 'D6RL6sWrs6khn7AfEyS6dsqqiiqAh4hXC83JtcmEUf6D', + programId: 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA', + uiTokenAmount: { + amount: '45845423703', + decimals: 9, + uiAmount: 45.845423703, + uiAmountString: '45.845423703', + }, + }, + ], + rewards: [], + status: { + Err: { + InstructionError: [6, 'ProgramFailedToComplete'], + }, + }, + }, + slot: 321739724, + transaction: { + message: { + accountKeys: [ + 's3zTLVvDbrBzbQ36sr2Z4xrzpRHFv3noWChbNi6vcjr', + '6sBssU2T4xhaw95q1i48pjSDTwDC45u3eTZAkK5CKNYQ', + 'AskK3y8NKwhczpG72ZKAwuPAqUQWr51frfabf8gXv4YV', + 'C2m8gz92gHGS32o38LXrMa9NheNb1pxsWadjEqY6jdpn', + '42ECGwTnCe22gmzVQw5AD4vmEJp42u2HiFBP6XnC7SSi', + '5nBajSNFtR62AFLYqaU4TYwnDWBduPTUAvFY3tqJ3MCd', + '2TvN137JoQgwjWtuaAp6fwLyhVDNt9PHoaHRgEXgcDw8', + 'GwTbrnsugAQrLa3xbZrknyGiTUD9vjfoZW78oFAnQVVg', + 'DC2ZjAA1z85HfDGcurc1tppH5nETCUGMgvG1Nr9QKduz', + '7no6QTSVJoHm286jnESCP26a7UR4QuZ8rQdZhQQEFVN4', + 'ComputeBudget111111111111111111111111111111', + 'ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL', + '11111111111111111111111111111111', + 'JUPSjgjMFjU4453KMgxhqVmzep6W352bQpE4RsNqXAx', + '8J2QTzGjsgb49at66wyA48o7s2zZeRtxfASsBDe2TnEd', + ], + addressTableLookups: [ + { + accountKey: '4ynUVUKW68eEy7WKP7TmwbnR7tmnws8Cqk91u7VU7kfr', + readonlyIndexes: [30, 8, 224, 223, 4, 9], + writableIndexes: [226, 220, 221, 217, 216], + }, + { + accountKey: 'APBx2HjiMVeVoMxVuihdhUzHMY9VjxezgbWSX6VBtENA', + readonlyIndexes: [], + writableIndexes: [207, 208, 122, 125], + }, + { + accountKey: '9YbkrJysYz7rPQKCWTbZwUsqjZ8epZWLPLskP7BxNgsk', + readonlyIndexes: [], + writableIndexes: [64, 60, 66, 61], + }, + ], + header: { + numReadonlySignedAccounts: 0, + numReadonlyUnsignedAccounts: 5, + numRequiredSignatures: 1, + }, + instructions: [ + { + accounts: [], + data: 'EL6XMh', + programIdIndex: 10, + stackHeight: null, + }, + { + accounts: [], + data: '3FTyfrdhjHgT', + programIdIndex: 10, + stackHeight: null, + }, + { + accounts: [0, 1, 0, 28, 12, 29], + data: '2', + programIdIndex: 11, + stackHeight: null, + }, + { + accounts: [0, 2, 0, 30, 12, 29], + data: '2', + programIdIndex: 11, + stackHeight: null, + }, + { + accounts: [0, 3, 0, 31, 12, 29], + data: '2', + programIdIndex: 11, + stackHeight: null, + }, + { + accounts: [0, 1, 0, 28, 12, 29], + data: '2', + programIdIndex: 11, + stackHeight: null, + }, + { + accounts: [ + 29, 0, 1, 3, 13, 31, 13, 14, 13, 32, 24, 32, 25, 26, 1, 2, 30, + 28, 27, 32, 0, 29, 29, 33, 32, 4, 5, 6, 13, 32, 15, 32, 16, + 17, 2, 3, 31, 30, 18, 32, 0, 29, 29, 33, 32, 19, 13, 32, 20, + 32, 21, 22, 3, 1, 31, 28, 23, 32, 0, 29, 29, 33, 32, 7, 8, 9, + 13, + ], + data: 'HsoVKDsbqEUoMD4o3nR6TWLiK5ryockP5BuBzCGoAjojtKJB5bq5Zt3BjGb', + programIdIndex: 13, + stackHeight: null, + }, + ], + recentBlockhash: '4xhayLciiYjWXSzM41tzwUcjufCdxbgouLuCJqXiySAW', + }, + signatures: [ + '3AcYfpsSaFYogY4Y4YN77MkhDgVBEgUe1vuEeqKnCMm5udTrFCyw9w17mNM8DUnHnQD2VHRFeipMUb27Q3iqMQJr', + ], + }, + version: 0, + }, + }, + }; + + return await mockServer + .forPost(SOLANA_URL_REGEX_DEVNET) + .withBodyIncluding('getTransaction') + .thenCallback(() => { + return response; + }); +} +export async function mockGetSuccessTransaction(mockServer: Mockttp) { + const response = { + statusCode: 200, + json: { + result: { + blockTime: 1739973211, + meta: { + computeUnitsConsumed: 150, + err: null, + fee: 5000, + innerInstructions: [], + loadedAddresses: { + readonly: [], + writable: [], + }, + logMessages: [ + 'Program 11111111111111111111111111111111 invoke [1]', + 'Program 11111111111111111111111111111111 success', + ], + postBalances: [6995200, 525845878579, 1], + postTokenBalances: [], + preBalances: [14078760, 525838800019, 1], + preTokenBalances: [], + rewards: [], + status: { + Ok: null, + }, + }, + slot: 321700491, + transaction: { + message: { + accountKeys: [ + 'HH9ZzgQvSVmznKcRfwHuEphuxk7zU5f92CkXFDQfVJcq', + 'AL9Z5JgZdeCKnaYg6jduy9PQGzo3moo7vZYVSTJwnSEq', + '11111111111111111111111111111111', + ], + addressTableLookups: [], + header: { + numReadonlySignedAccounts: 0, + numReadonlyUnsignedAccounts: 1, + numRequiredSignatures: 1, + }, + instructions: [ + { + accounts: [0, 1], + data: '3Bxs4TcxCSkLAdy9', + programIdIndex: 2, + stackHeight: null, + }, + ], + recentBlockhash: 'BV3s6CSZXUiNkFvdzQjpD6jB3ZSNqhnbpRQ1acu2DG5L', + }, + signatures: [ + '3AcYfpsSaFYogY4Y4YN77MkhDgVBEgUe1vuEeqKnCMm5udTrFCyw9w17mNM8DUnHnQD2VHRFeipMUb27Q3iqMQJr', + ], + }, + version: 0, + }, + }, + }; + + return await mockServer + .forPost(SOLANA_URL_REGEX_MAINNET) + .withBodyIncluding('getTransaction') + .thenCallback(() => { + return response; + }); +} + +export async function mockGetSuccessTransactionDevnet(mockServer: Mockttp) { + const response = { + statusCode: 200, + json: { + result: { + blockTime: 1739973211, + meta: { + computeUnitsConsumed: 150, + err: null, + fee: 5000, + innerInstructions: [], + loadedAddresses: { + readonly: [], + writable: [], + }, + logMessages: [ + 'Program 11111111111111111111111111111111 invoke [1]', + 'Program 11111111111111111111111111111111 success', + ], + postBalances: [6995200, 525845878579, 1], + postTokenBalances: [], + preBalances: [14078760, 525838800019, 1], + preTokenBalances: [], + rewards: [], + status: { + Ok: null, + }, + }, + slot: 321700491, + transaction: { + message: { + accountKeys: [ + 'HH9ZzgQvSVmznKcRfwHuEphuxk7zU5f92CkXFDQfVJcq', + 'AL9Z5JgZdeCKnaYg6jduy9PQGzo3moo7vZYVSTJwnSEq', + '11111111111111111111111111111111', ], addressTableLookups: [], header: { @@ -1276,7 +2106,7 @@ export async function mockGetSuccessTransaction(mockServer: Mockttp) { }; return await mockServer - .forPost(SOLANA_URL_REGEX_MAINNET) + .forPost(SOLANA_URL_REGEX_DEVNET) .withBodyIncluding('getTransaction') .thenCallback(() => { return response; @@ -1309,6 +2139,32 @@ export async function mockGetLatestBlockhash(mockServer: Mockttp) { return response; }); } +export async function mockGetLatestBlockhashDevnet(mockServer: Mockttp) { + const response = { + statusCode: 200, + json: { + result: { + context: { + apiVersion: '2.0.18', + slot: 308460925, + }, + value: { + blockhash: '6E9FiVcuvavWyKTfYC7N9ezJWkNgJVQsroDTHvqApncg', + lastValidBlockHeight: 341034515, + }, + }, + id: 1337, + }, + }; + return await mockServer + .forPost(SOLANA_URL_REGEX_DEVNET) + .withJsonBodyIncluding({ + method: 'getLatestBlockhash', + }) + .thenCallback(() => { + return response; + }); +} export async function mockGetFailedSignaturesForAddress(mockServer: Mockttp) { return await mockServer .forPost(SOLANA_URL_REGEX_MAINNET) @@ -1334,6 +2190,31 @@ export async function mockGetFailedSignaturesForAddress(mockServer: Mockttp) { }; }); } +export async function mockGetFailedSignaturesForAddressDevnet(mockServer: Mockttp) { + return await mockServer + .forPost(SOLANA_URL_REGEX_DEVNET) + .withBodyIncluding('getSignaturesForAddress') + .thenCallback(() => { + return { + statusCode: 200, + json: { + result: [ + { + blockTime: 1739973211, + confirmationStatus: 'finalized', + err: { + InstructionError: [0, 'CustomError'], + }, + memo: null, + signature: + '3AcYfpsSaFYogY4Y4YN77MkhDgVBEgUe1vuEeqKnCMm5udTrFCyw9w17mNM8DUnHnQD2VHRFeipMUb27Q3iqMQJr', + slot: 321700491, + }, + ], + }, + }; + }); +} export async function mockGetSuccessSignaturesForAddress(mockServer: Mockttp) { return await mockServer .forPost(SOLANA_URL_REGEX_MAINNET) @@ -1358,6 +2239,69 @@ export async function mockGetSuccessSignaturesForAddress(mockServer: Mockttp) { }); } +export async function mockGetSuccessSignaturesForAddressDevnet(mockServer: Mockttp) { + return await mockServer + .forPost(SOLANA_URL_REGEX_DEVNET) + .withBodyIncluding('getSignaturesForAddress') + .thenCallback(() => { + return { + statusCode: 200, + json: { + result: [ + { + blockTime: 1739973211, + confirmationStatus: 'finalized', + err: null, + memo: null, + signature: + '3AcYfpsSaFYogY4Y4YN77MkhDgVBEgUe1vuEeqKnCMm5udTrFCyw9w17mNM8DUnHnQD2VHRFeipMUb27Q3iqMQJr', + slot: 321700491, + }, + ], + }, + }; + }); +} + +export async function mockSendSolanaFailedTransaction(mockServer: Mockttp) { + const response = { + statusCode: 200, + json: { + jsonrpc: "2.0", + error: { + code: -32002, + message: "Transaction simulation failed: Error processing Instruction 0: custom program error: 0x1", + data: { + accounts: null, + err: { + InstructionError: [ + 0, + { + Custom: 1 + } + ] + }, + logs: [ + "Program 11111111111111111111111111111111 invoke [1]", + "Program 11111111111111111111111111111111 failed: custom program error: 0x1" + ], + unitsConsumed: 200000, + returnData: null + } + }, + id: 1 + }, + }; + return await mockServer + .forPost(SOLANA_URL_REGEX_MAINNET) + .withJsonBodyIncluding({ + method: 'sendTransaction', + }) + .thenCallback(() => { + return response; + }); +} + export async function mockSendSolanaTransaction(mockServer: Mockttp) { const response = { statusCode: 200, @@ -1377,6 +2321,25 @@ export async function mockSendSolanaTransaction(mockServer: Mockttp) { }); } +export async function mockSendSolanaTransactionDevnet(mockServer: Mockttp) { + const response = { + statusCode: 200, + json: { + result: + '3nqGKH1ef8WkTgKXZ8q3xKsvjktWmHHhJpZMSdbB6hBqy5dA7aLVSAUjw5okezZjKMHiNg2MF5HAqtpmsesQtnpj', + id: 1337, + }, + }; + return await mockServer + .forPost(SOLANA_URL_REGEX_DEVNET) + .withJsonBodyIncluding({ + method: 'sendTransaction', + }) + .thenCallback(() => { + return response; + }); +} + /* export async function mockGetTokenAccountsByOwner(mockServer: Mockttp) { return await mockServer @@ -1446,9 +2409,88 @@ export async function mockGetFeeForMessage(mockServer: Mockttp) { }); } -export async function mockGetTokenAccountsByOwner(mockServer: Mockttp) { +export async function mockGetFeeForMessageDevnet(mockServer: Mockttp) { + const response = { + statusCode: 200, + json: { + result: { context: { slot: 5068 }, value: 5000 }, + id: 1337, + }, + }; + return await mockServer + .forPost(SOLANA_URL_REGEX_DEVNET) + .withJsonBodyIncluding({ + method: 'getFeeForMessage', + }) + .thenCallback(() => { + return response; + }); +} + +export async function mockGetTokenAccountsByOwner(mockServer: Mockttp, programId: string) { return await mockServer .forPost(SOLANA_URL_REGEX_MAINNET) + .withJsonBodyIncluding({ + method: 'getTokenAccountsByOwner', + params: [ + '4tE76eixEgyJDrdykdWJR1XBkzUk4cLMvqjR2xVJUxer', + { + programId: programId, + }, + { + encoding: 'jsonParsed', + commitment: 'confirmed', + }, + ], + }) + .thenCallback(() => { + return { + statusCode: 200, + json: { + result: { + context: { + slot: 137568828, + }, + value: [ + { + account: { + data: { + parsed: { + info: { + isNative: false, + mint: '2RBko3xoz56aH69isQMUpzZd9NYHahhwC23A5F3Spkin', + owner: '14BLn1WLBf3coaPj1fZ5ZqJKQArEjJHvw7rvSktGv2b5', + state: 'initialized', + tokenAmount: { + amount: '6000000', + decimals: 6, + uiAmount: 6, + uiAmountString: '6', + }, + }, + type: 'account', + }, + program: 'spl-token', + space: 165, + }, + executable: false, + lamports: 2039280, + owner: 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA', + rentEpoch: 18446744073709552000, + space: 165, + }, + pubkey: 'EzG33TbDzHVaWBqgQgHhtQSY6tcAVsWub6hBRepcsDt4', + }, + ], + }, + }, + }; + }); +} + +export async function mockGetTokenAccountsByOwnerDevnet(mockServer: Mockttp) { + return await mockServer + .forPost(SOLANA_URL_REGEX_DEVNET) .withJsonBodyIncluding({ method: 'getTokenAccountsByOwner', }) @@ -1496,6 +2538,7 @@ export async function mockGetTokenAccountsByOwner(mockServer: Mockttp) { }; }); } + export async function mockGetAccountInfo(mockServer: Mockttp) { console.log('mockGetAccountInfo'); const response = { @@ -1599,6 +2642,64 @@ export async function mockGetTokenAccountInfo(mockServer: Mockttp) { }); } +export async function mockGetTokenAccountInfoDevnet(mockServer: Mockttp) { + console.log('mockGetTokenAccountInfo'); + const response = { + statusCode: 200, + json: { + result: { + context: { + apiVersion: '2.0.21', + slot: 317161313, + }, + value: { + data: { + parsed: { + info: { + isNative: false, + mint: '2RBko3xoz56aH69isQMUpzZd9NYHahhwC23A5F3Spkin', + owner: '3xTPAZxmpwd8GrNEKApaTw6VH4jqJ31WFXUvQzgwhR7c', + state: 'initialized', + tokenAmount: { + amount: '3610951', + decimals: 6, + uiAmount: 3.610951, + uiAmountString: '3.610951', + }, + }, + type: 'account', + }, + program: 'spl-token', + space: 165, + }, + executable: false, + lamports: 2039280, + owner: 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA', + rentEpoch: 18446744073709552000, + space: 165, + }, + }, + }, + }; + return await mockServer + .forPost(SOLANA_URL_REGEX_DEVNET) + .withJsonBodyIncluding({ + method: 'getAccountInfo', + }) + .withJsonBodyIncluding({ + params: [ + '4Dt7hvLAzSXGvxvpqFU7cRdQXXhU3orACV6ujY4KPv9D', + { + encoding: 'jsonParsed', + commitment: 'confirmed', + }, + ], + }) + .thenCallback(() => { + return response; + }); +} + export async function withSolanaAccountSnap( { title, @@ -1611,6 +2712,8 @@ export async function withSolanaAccountSnap( mockGetTransactionSuccess, mockGetTransactionFailed, mockZeroBalance, + simulateFailedTransaction, + sendFailedTransaction, }: { title?: string; showNativeTokenAsMainBalance?: boolean; @@ -1622,6 +2725,8 @@ export async function withSolanaAccountSnap( mockGetTransactionSuccess?: boolean; mockGetTransactionFailed?: boolean; mockZeroBalance?: boolean; + simulateFailedTransaction?: boolean; + sendFailedTransaction?: boolean; }, test: (driver: Driver, mockServer: Mockttp) => Promise, ) { @@ -1637,49 +2742,59 @@ export async function withSolanaAccountSnap( title, dapp: true, testSpecificMock: async (mockServer: Mockttp) => { - const mockList = []; + const mockList: MockedEndpoint[] = []; if (mockGetTransactionSuccess && !mockGetTransactionFailed) { mockList.push(await mockGetSuccessSignaturesForAddress(mockServer)); mockList.push(await mockGetSuccessTransaction(mockServer)); + mockList.push(await mockGetSuccessSignaturesForAddressDevnet(mockServer)); + mockList.push(await mockGetSuccessTransactionDevnet(mockServer)); } if (mockGetTransactionFailed && !mockGetTransactionSuccess) { mockList.push(await mockGetFailedSignaturesForAddress(mockServer)); mockList.push(await mockGetFailedTransaction(mockServer)); + mockList.push(await mockGetFailedSignaturesForAddressDevnet(mockServer)); + mockList.push(await mockGetFailedTransactionDevnet(mockServer)); } if (!mockGetTransactionSuccess && !mockGetTransactionFailed) { // success tx by default mockList.push(await mockGetSuccessSignaturesForAddress(mockServer)); mockList.push(await mockGetSuccessTransaction(mockServer)); + mockList.push(await mockGetSuccessSignaturesForAddressDevnet(mockServer)); + mockList.push(await mockGetSuccessTransactionDevnet(mockServer)); } if (mockCalls) { - mockList.push([ + mockList.push(...[ await mockSolanaBalanceQuote(mockServer), - // await mockGetTransaction(mockServer), - await mockGetTokenAccountsByOwner(mockServer), - // await mockGetSuccessSignaturesForAddress(mockServer), + await mockSolanaBalanceQuoteDevnet(mockServer), + await mockGetTokenAccountsByOwner(mockServer, SOLANA_TOKEN_PROGRAM), + await mockGetTokenAccountsByOwnerDevnet(mockServer), await mockMultiCoinPrice(mockServer), await mockGetLatestBlockhash(mockServer), + await mockGetLatestBlockhashDevnet(mockServer), await mockGetFeeForMessage(mockServer), + await mockGetFeeForMessageDevnet(mockServer), await mockPriceApiSpotPrice(mockServer), await mockPriceApiExchangeRates(mockServer), await mockClientSideDetectionApi(mockServer), await mockPhishingDetectionApi(mockServer), await mockGetTokenAccountInfo(mockServer), await mockGetAccountInfo(mockServer), - await mockTokenApiMainnet(mockServer), - await mockTokenApiDevnet(mockServer), - await mockSolanaBalanceQuoteDevnet(mockServer), + await mockTokenApiMainnetTest(mockServer), + await mockAccountsApi(mockServer), ]); } if (mockZeroBalance) { mockList.push(await mockSolanaBalanceQuote(mockServer, true)); + mockList.push(await mockSolanaBalanceQuoteDevnet(mockServer, true)); } - if (mockSendTransaction) { + if (mockSendTransaction || simulateTransaction) { + mockList.push(await simulateSolanaTransaction(mockServer)); mockList.push(await mockSendSolanaTransaction(mockServer)); - } - if (simulateTransaction) { - mockList.push(await simulateSolanaTransaction(mockServer, isNative)); + mockList.push(await mockSendSolanaTransactionDevnet(mockServer)); + } else if (sendFailedTransaction) { + mockList.push(await simulateSolanaTransaction(mockServer)); + mockList.push(await mockSendSolanaFailedTransaction(mockServer)); } return mockList; }, @@ -1690,8 +2805,8 @@ export async function withSolanaAccountSnap( }, async ({ driver, mockServer }: { driver: Driver; mockServer: Mockttp }) => { await loginWithoutBalanceValidation(driver); - const headerComponen = new HeaderNavbar(driver); - await headerComponen.openAccountMenu(); + const headerComponent = new HeaderNavbar(driver); + await headerComponent.openAccountMenu(); const accountListPage = new AccountListPage(driver); if (!importAccount) { await accountListPage.addAccount({ @@ -1699,6 +2814,7 @@ export async function withSolanaAccountSnap( accountName: 'Solana 1', }); } + await headerComponent.check_accountLabel('Solana 1'); await test(driver, mockServer); }, ); diff --git a/test/e2e/flask/solana/send-flow.spec.ts b/test/e2e/flask/solana/send-flow.spec.ts index a14890f17536..06764f7e7c2c 100644 --- a/test/e2e/flask/solana/send-flow.spec.ts +++ b/test/e2e/flask/solana/send-flow.spec.ts @@ -112,7 +112,7 @@ describe('Send full flow of USD', function (this: Suite) { const confirmSolanaPage = new ConfirmSolanaTxPage(driver); await sendSolanaPage.clickOnContinue(); assert.equal( - await confirmSolanaPage.checkAmountDisplayed('0.0504'), + await confirmSolanaPage.checkAmountDisplayed('0.0886'), true, 'Check amount displayed is wrong', ); @@ -149,7 +149,7 @@ describe('Send full flow of USD', function (this: Suite) { await confirmSolanaPage.clickOnSend(); const sentTxPage = new SolanaTxresultPage(driver); assert.equal( - await sentTxPage.check_TransactionStatusText('0.0504', true), + await sentTxPage.check_TransactionStatusText('0.0886', true), true, 'Transaction amount is not correct', ); @@ -319,14 +319,14 @@ describe('Send full flow of SOL', function (this: Suite) { }); describe('Send flow', function (this: Suite) { it('and Transaction fails', async function () { - this.timeout(120000); // there is a bug open for this big timeout https://consensyssoftware.atlassian.net/browse/SOL-90 + this.timeout(120000); await withSolanaAccountSnap( { title: this.test?.fullTitle(), showNativeTokenAsMainBalance: true, mockCalls: true, mockSendTransaction: false, - simulateTransaction: true, + sendFailedTransaction: true, }, async (driver) => { const homePage = new NonEvmHomepage(driver); diff --git a/test/e2e/flask/solana/send-spl-token.spec.ts b/test/e2e/flask/solana/send-spl-token.spec.ts index ce346d8b0dce..62022f18a5f6 100644 --- a/test/e2e/flask/solana/send-spl-token.spec.ts +++ b/test/e2e/flask/solana/send-spl-token.spec.ts @@ -143,7 +143,7 @@ describe('Send flow', function (this: Suite) { showNativeTokenAsMainBalance: true, mockCalls: true, mockSendTransaction: false, - simulateTransaction: true, + sendFailedTransaction: true, }, async (driver) => { const homePage = new NonEvmHomepage(driver); diff --git a/test/e2e/flask/solana/solana-networks.spec.ts b/test/e2e/flask/solana/solana-networks.spec.ts index 5f79d8cae753..5cc82913430f 100644 --- a/test/e2e/flask/solana/solana-networks.spec.ts +++ b/test/e2e/flask/solana/solana-networks.spec.ts @@ -12,7 +12,7 @@ describe('Solana network', function (this: Suite) { const headerNavbar = new HeaderNavbar(driver); await headerNavbar.check_pageIsLoaded(); await headerNavbar.check_accountLabel('Solana 1'); - await headerNavbar.check_currentSelectedNetwork('Solana Mainnet'); + await headerNavbar.check_currentSelectedNetwork('Solana'); await headerNavbar.check_ifNetworkPickerClickable(true); await headerNavbar.openAccountMenu(); const accountMenu = new AccountListPage(driver); @@ -35,7 +35,7 @@ describe('Solana network', function (this: Suite) { await switchToNetworkFlow(driver, 'Linea Mainnet'); // Switch back to Solana Mainnet - await switchToNetworkFlow(driver, 'Solana Mainnet'); + await switchToNetworkFlow(driver, 'Solana'); // Linea, still as the selected network in the network-controller // but not in the UI, should be removed from the network-controller diff --git a/test/e2e/flask/solana/switching-network-accounts.spec.ts b/test/e2e/flask/solana/switching-network-accounts.spec.ts index f43e0b0f47df..65d890f0c01a 100644 --- a/test/e2e/flask/solana/switching-network-accounts.spec.ts +++ b/test/e2e/flask/solana/switching-network-accounts.spec.ts @@ -14,7 +14,7 @@ describe('Switching between account from different networks', function (this: Su await headerNavbar.check_pageIsLoaded(); await headerNavbar.check_accountLabel('Solana 1'); await headerNavbar.check_ifNetworkPickerClickable(true); - await headerNavbar.check_currentSelectedNetwork('Solana Mainnet'); + await headerNavbar.check_currentSelectedNetwork('Solana'); await headerNavbar.openAccountMenu(); const accountListPage = new AccountListPage(driver); await accountListPage.selectAccount('Account 1'); @@ -40,7 +40,7 @@ describe('Switching between account from different networks', function (this: Su accountName: 'Solana Account 2', }); await headerNavbar.check_ifNetworkPickerClickable(true); - await headerNavbar.check_currentSelectedNetwork('Solana Mainnet'); + await headerNavbar.check_currentSelectedNetwork('Solana'); await headerNavbar.check_accountLabel('Solana Account 2'); }, ); @@ -54,8 +54,8 @@ describe('Switching between account from different networks', function (this: Su await headerNavbar.clickSwitchNetworkDropDown(); const selectNetworkDialog = new SelectNetwork(driver); await selectNetworkDialog.check_pageIsLoaded(); - await selectNetworkDialog.selectNetworkName('Solana Mainnet'); - await headerNavbar.check_currentSelectedNetwork('Solana Mainnet'); + await selectNetworkDialog.selectNetworkName('Solana'); + await headerNavbar.check_currentSelectedNetwork('Solana'); await headerNavbar.openAccountMenu(); const accountListPage = new AccountListPage(driver); await accountListPage.addAccount({ diff --git a/test/e2e/flask/user-operations.spec.ts b/test/e2e/flask/user-operations.spec.ts index e7f78c501ffe..ee0a1675ba7b 100644 --- a/test/e2e/flask/user-operations.spec.ts +++ b/test/e2e/flask/user-operations.spec.ts @@ -9,14 +9,14 @@ import { } from '../helpers'; import FixtureBuilder from '../fixture-builder'; import { + BUNDLER_URL, ENTRYPOINT, + ERC_4337_ACCOUNT, + ERC_4337_ACCOUNT_SALT, ERC_4337_ACCOUNT_SNAP_URL, - BUNDLER_URL, + LOCAL_NODE_ACCOUNT, + LOCAL_NODE_PRIVATE_KEY, SIMPLE_ACCOUNT_FACTORY, - GANACHE_PRIVATE_KEY, - ERC_4337_ACCOUNT_SALT, - ERC_4337_ACCOUNT, - GANACHE_ACCOUNT, VERIFYING_PAYMASTER, } from '../constants'; import { buildQuote, reviewQuote } from '../tests/swaps/shared'; @@ -240,7 +240,7 @@ async function withAccountSnap( await createSnapAccount( driver, - GANACHE_PRIVATE_KEY, + LOCAL_NODE_PRIVATE_KEY, ERC_4337_ACCOUNT_SALT, ); @@ -262,7 +262,7 @@ describe('User Operations', function () { await withAccountSnap({ title: this.test?.fullTitle() }, async (driver) => { await createDappTransaction(driver, { from: ERC_4337_ACCOUNT, - to: GANACHE_ACCOUNT, + to: LOCAL_NODE_ACCOUNT, value: convertETHToHexGwei(1), maxFeePerGas: '0x0', maxPriorityFeePerGas: '0x0', @@ -276,7 +276,7 @@ describe('User Operations', function () { await withAccountSnap( { title: this.test?.fullTitle() }, async (driver, bundlerServer) => { - await sendTransaction(driver, GANACHE_ACCOUNT, 1, true); + await sendTransaction(driver, LOCAL_NODE_ACCOUNT, 1, true); await openConfirmedTransaction(driver); await expectTransactionDetailsMatchReceipt(driver, bundlerServer); @@ -314,7 +314,7 @@ describe('User Operations', function () { async (driver, bundlerServer) => { await createDappTransaction(driver, { from: ERC_4337_ACCOUNT, - to: GANACHE_ACCOUNT, + to: LOCAL_NODE_ACCOUNT, value: convertETHToHexGwei(1), maxFeePerGas: '0x0', maxPriorityFeePerGas: '0x0', diff --git a/test/e2e/helpers.js b/test/e2e/helpers.js index 8f4b36d49230..5e887d626888 100644 --- a/test/e2e/helpers.js +++ b/test/e2e/helpers.js @@ -19,8 +19,8 @@ const { Bundler } = require('./bundler'); const { SMART_CONTRACTS } = require('./seeder/smart-contracts'); const { setManifestFlags } = require('./set-manifest-flags'); const { + DEFAULT_LOCAL_NODE_ETH_BALANCE_DEC, ERC_4337_ACCOUNT, - DEFAULT_GANACHE_ETH_BALANCE_DEC, } = require('./constants'); const { getServerMochaToBackground, @@ -441,6 +441,7 @@ const WINDOW_TITLES = Object.freeze({ ServiceWorkerSettings: 'Inspect with Chrome Developer Tools', SnapSimpleKeyringDapp: 'SSK - Simple Snap Keyring', TestDApp: 'E2E Test Dapp', + TestDappSendIndividualRequest: 'E2E Test Dapp - Send Individual Request', MultichainTestDApp: 'Multichain Test Dapp', TestSnaps: 'Test Snaps', ERC4337Snap: 'Account Abstraction Snap', @@ -551,11 +552,11 @@ const multipleGanacheOptions = { accounts: [ { secretKey: PRIVATE_KEY, - balance: convertETHToHexGwei(DEFAULT_GANACHE_ETH_BALANCE_DEC), + balance: convertETHToHexGwei(DEFAULT_LOCAL_NODE_ETH_BALANCE_DEC), }, { secretKey: PRIVATE_KEY_TWO, - balance: convertETHToHexGwei(DEFAULT_GANACHE_ETH_BALANCE_DEC), + balance: convertETHToHexGwei(DEFAULT_LOCAL_NODE_ETH_BALANCE_DEC), }, ], }; @@ -571,6 +572,7 @@ const editGasFeeForm = async (driver, gasLimit, gasPrice) => { }; const openActionMenuAndStartSendFlow = async (driver) => { + console.log('Opening action menu and starting send flow'); await driver.clickElement('[data-testid="eth-overview-send"]'); }; diff --git a/test/e2e/json-rpc/switchEthereumChain.spec.js b/test/e2e/json-rpc/switchEthereumChain.spec.js index 8a1b2a3b3298..9920a41ba7e2 100644 --- a/test/e2e/json-rpc/switchEthereumChain.spec.js +++ b/test/e2e/json-rpc/switchEthereumChain.spec.js @@ -16,7 +16,7 @@ describe('Switch Ethereum Chain for two dapps', function () { { dapp: true, fixtures: new FixtureBuilder() - .withNetworkControllerDoubleGanache() + .withNetworkControllerDoubleNode() .build(), dappOptions: { numberOfDapps: 2 }, localNodeOptions: [ @@ -91,7 +91,7 @@ describe('Switch Ethereum Chain for two dapps', function () { { dapp: true, fixtures: new FixtureBuilder() - .withNetworkControllerDoubleGanache() + .withNetworkControllerDoubleNode() .withPreferencesControllerSmartTransactionsOptedOut() .build(), dappOptions: { numberOfDapps: 2 }, @@ -220,7 +220,7 @@ describe('Switch Ethereum Chain for two dapps', function () { { dapp: true, fixtures: new FixtureBuilder() - .withNetworkControllerDoubleGanache() + .withNetworkControllerDoubleNode() .build(), dappOptions: { numberOfDapps: 2 }, localNodeOptions: [ @@ -352,4 +352,171 @@ describe('Switch Ethereum Chain for two dapps', function () { }, ); }); + + describe('There are pending confirmation in the old network', function () { + it('show alerts on permission network if user does not have permission on new network', async function () { + await withFixtures( + { + dapp: true, + fixtures: new FixtureBuilder() + .withNetworkControllerDoubleNode() + .withPermissionControllerConnectedToTestDappWithChains(['0x539']) + .build(), + dappOptions: { numberOfDapps: 2 }, + localNodeOptions: [ + { + type: 'anvil', + }, + { + type: 'anvil', + options: { + blockTime: 2, + vmErrorsOnRPCResponse: false, + mnemonic: + 'phrase upgrade clock rough situate wedding elder clever doctor stamp excess tent', + port: 8546, + chainId: 1338, + }, + }, + ], + title: this.test.fullTitle(), + }, + async ({ driver }) => { + if (process.env.EVM_MULTICHAIN_ENABLED === 'true') { + await unlockWallet(driver); + + await openDapp(driver); + + await driver.clickElement('#personalSign'); + + // switchEthereumChain request + const switchEthereumChainRequest = JSON.stringify({ + jsonrpc: '2.0', + method: 'wallet_switchEthereumChain', + params: [{ chainId: '0x53a' }], + }); + + // Initiate switchEthereumChain on the Dapp + await driver.executeScript( + `window.ethereum.request(${switchEthereumChainRequest})`, + ); + + await driver.switchToWindowWithTitle(WINDOW_TITLES.Dialog); + + await driver.clickElement( + '[data-testid="confirm-nav__next-confirmation"]', + ); + + // User reviews pending alerts + await driver.clickElement({ text: 'Confirm', tag: 'button' }); + await driver.clickElement( + '[data-testid="alert-modal-action-showPendingConfirmation"]', + ); + + // user confirms permissions + await driver.clickElement( + '[data-testid="confirm-nav__next-confirmation"]', + ); + await driver.clickElement({ text: 'Confirm', tag: 'button' }); + await driver.clickElement('[data-testid="alert-modal-button"]'); + + await driver.switchToWindowWithTitle(WINDOW_TITLES.TestDApp); + + // Wait for chain id element to change, there's a page reload. + await driver.waitForSelector({ + css: '#chainId', + text: '0x53a', + }); + } + }, + ); + }); + + it('show alerts on switch network page if user does has permission on new network', async function () { + await withFixtures( + { + dapp: true, + fixtures: new FixtureBuilder() + .withNetworkControllerDoubleNode() + .withPermissionControllerConnectedToTestDappWithChains([ + '0x539', + '0x53a', + ]) + .build(), + dappOptions: { numberOfDapps: 2 }, + localNodeOptions: [ + { + type: 'anvil', + }, + { + type: 'anvil', + options: { + blockTime: 2, + vmErrorsOnRPCResponse: false, + mnemonic: + 'phrase upgrade clock rough situate wedding elder clever doctor stamp excess tent', + port: 8546, + chainId: 1338, + }, + }, + ], + title: this.test.fullTitle(), + }, + async ({ driver }) => { + if (process.env.EVM_MULTICHAIN_ENABLED === 'true') { + await unlockWallet(driver); + + await openDapp(driver); + + await driver.clickElement('#personalSign'); + + // switchEthereumChain request + const switchEthereumChainRequest = JSON.stringify({ + jsonrpc: '2.0', + method: 'wallet_switchEthereumChain', + params: [{ chainId: '0x53a' }], + }); + + // Initiate switchEthereumChain on the Dapp + await driver.executeScript( + `window.ethereum.request(${switchEthereumChainRequest})`, + ); + + await driver.switchToWindowWithTitle(WINDOW_TITLES.Dialog); + + await driver.clickElement( + '[data-testid="confirm-nav__next-confirmation"]', + ); + + // User reviews pending alerts + await driver.clickElement({ + text: 'Switch network', + tag: 'button', + }); + await driver.clickElement( + '[data-testid="alert-modal-action-showPendingConfirmation"]', + ); + + // user confirms permissions + await driver.clickElement( + '[data-testid="confirm-nav__next-confirmation"]', + ); + await driver.clickElement({ + text: 'Switch network', + tag: 'button', + }); + await driver.clickElement('[data-testid="alert-modal-button"]'); + + await driver.switchToWindowWithTitle(WINDOW_TITLES.TestDApp); + + // Wait for chain id element to change, there's a page reload. + await driver.waitForSelector({ + css: '#chainId', + text: '0x53a', + }); + } + }, + ); + }); + }); }); diff --git a/test/e2e/json-rpc/wallet_addEthereumChain.spec.ts b/test/e2e/json-rpc/wallet_addEthereumChain.spec.ts index 6a0b64e1388b..5cf1b0af0d4b 100644 --- a/test/e2e/json-rpc/wallet_addEthereumChain.spec.ts +++ b/test/e2e/json-rpc/wallet_addEthereumChain.spec.ts @@ -103,7 +103,7 @@ describe('Add Ethereum Chain', function () { { dapp: true, fixtures: new FixtureBuilder() - .withNetworkControllerDoubleGanache() + .withNetworkControllerDoubleNode() .build(), localNodeOptions: [ { @@ -166,7 +166,7 @@ describe('Add Ethereum Chain', function () { { dapp: true, fixtures: new FixtureBuilder() - .withNetworkControllerDoubleGanache() + .withNetworkControllerDoubleNode() .build(), localNodeOptions: [ { @@ -281,7 +281,7 @@ describe('Add Ethereum Chain', function () { { dapp: true, fixtures: new FixtureBuilder() - .withNetworkControllerDoubleGanache() + .withNetworkControllerDoubleNode() .build(), title: this.test?.fullTitle(), }, @@ -336,7 +336,7 @@ describe('Add Ethereum Chain', function () { { dapp: true, fixtures: new FixtureBuilder() - .withNetworkControllerDoubleGanache() + .withNetworkControllerDoubleNode() .withPermissionControllerConnectedToTestDappWithChains([ '0x539', '0x53a', @@ -408,7 +408,7 @@ describe('Add Ethereum Chain', function () { { dapp: true, fixtures: new FixtureBuilder() - .withNetworkControllerDoubleGanache() + .withNetworkControllerDoubleNode() .withPermissionControllerConnectedToTestDappWithChains([ '0x539', '0x53a', @@ -470,6 +470,7 @@ describe('Add Ethereum Chain', function () { ); }); }); + describe('the dapp is already permitted to use the chain being added, and the dapp is on the same chain as the chain being added, but the rpcEndpoint being proposed does not match any existing rpcEndpoints for the chain', () => { it('prompts to add the rpc endpoint to the chain networkConfiguration and set it as the default', async function () { await withFixtures( @@ -530,4 +531,95 @@ describe('Add Ethereum Chain', function () { ); }); }); + + describe('There are pending confirmation in the old network', () => { + it('alert user about pending confirmations', async function () { + await withFixtures( + { + dapp: true, + fixtures: new FixtureBuilder() + .withNetworkControllerDoubleNode() + .withPermissionControllerConnectedToTestDappWithChains(['0x539']) + .build(), + localNodeOptions: [ + { + type: 'anvil', + }, + { + type: 'anvil', + options: { + port: 8546, + chainId: 1338, + }, + }, + ], + title: this.test?.fullTitle(), + }, + async ({ driver }: { driver: Driver }) => { + if (process.env.EVM_MULTICHAIN_ENABLED === 'true') { + await unlockWallet(driver); + await openDapp(driver); + + await driver.clickElement('#personalSign'); + + const beforePermittedChains = await getPermittedChains(driver); + assert.deepEqual(beforePermittedChains, ['0x539']); + + // should start on 1337 + await driver.findElement({ css: '#chainId', text: '0x539' }); + + const switchEthereumChainRequest = JSON.stringify({ + jsonrpc: '2.0', + method: 'wallet_addEthereumChain', + params: [ + { + chainId: '0x53a', + chainName: 'Localhost 8546 alternative', + nativeCurrency: { + name: '', + symbol: 'ETH', + decimals: 18, + }, + // this does not match what already exists in the NetworkController + rpcUrls: ['http://127.0.0.1:8546'], + blockExplorerUrls: [], + }, + ], + }); + + await driver.executeScript( + `window.ethereum.request(${switchEthereumChainRequest})`, + ); + + await driver.switchToWindowWithTitle(WINDOW_TITLES.Dialog); + + await driver.clickElement( + '[data-testid="confirm-nav__next-confirmation"]', + ); + + // User reviews pending alerts + await driver.clickElement({ text: 'Approve', tag: 'button' }); + await driver.clickElement( + '[data-testid="alert-modal-action-showPendingConfirmation"]', + ); + + // user confirms add network confirmation + await driver.clickElement( + '[data-testid="confirm-nav__next-confirmation"]', + ); + await driver.clickElement({ text: 'Approve', tag: 'button' }); + await driver.clickElement('[data-testid="alert-modal-button"]'); + + await driver.switchToWindowWithTitle(WINDOW_TITLES.TestDApp); + + const afterPermittedChains = await getPermittedChains(driver); + assert.deepEqual(afterPermittedChains, ['0x539', '0x53a']); + + // should end on 1338 + await driver.findElement({ css: '#chainId', text: '0x53a' }); + } + }, + ); + }); + }); }); diff --git a/test/e2e/json-rpc/wallet_revokePermissions.spec.ts b/test/e2e/json-rpc/wallet_revokePermissions.spec.ts index 1f7758db3fc8..21b32153abdf 100644 --- a/test/e2e/json-rpc/wallet_revokePermissions.spec.ts +++ b/test/e2e/json-rpc/wallet_revokePermissions.spec.ts @@ -180,4 +180,55 @@ describe('Revoke Dapp Permissions', function () { }, ); }); + + describe('There are pending confirmation in the old network', function () { + it.only('rejects the pending confirmations as permissions are revoked for the network', async function () { + await withFixtures( + { + dapp: true, + fixtures: new FixtureBuilder() + .withPermissionControllerConnectedToTestDappWithChains(['0x539']) + .build(), + title: this.test?.fullTitle(), + }, + async ({ driver }) => { + if (process.env.EVM_MULTICHAIN_ENABLED === 'true') { + await loginWithBalanceValidation(driver); + const testDapp = new TestDapp(driver); + await testDapp.openTestDappPage(); + await driver.clickElement('#personalSign'); + + const revokePermissionsRequest = JSON.stringify({ + jsonrpc: '2.0', + method: 'wallet_revokePermissions', + params: [ + { + eth_accounts: {}, + }, + ], + }); + + const revokePermissionsResult = await driver.executeScript( + `return window.ethereum.request(${revokePermissionsRequest})`, + ); + assert.deepEqual(revokePermissionsResult, null); + + await driver.waitUntilXWindowHandles(2); + + const afterGetPermissionsRequest = JSON.stringify({ + jsonrpc: '2.0', + method: 'wallet_getPermissions', + }); + const afterGetPermissionsResult = await driver.executeScript( + `return window.ethereum.request(${afterGetPermissionsRequest})`, + ); + const afterGetPermissionsNames = afterGetPermissionsResult.map( + (permission: PermissionConstraint) => permission.parentCapability, + ); + assert.deepEqual(afterGetPermissionsNames, []); + } + }, + ); + }); + }); }); diff --git a/test/e2e/mock-e2e-allowlist.js b/test/e2e/mock-e2e-allowlist.js index 51faa317849c..cd38b23f2096 100644 --- a/test/e2e/mock-e2e-allowlist.js +++ b/test/e2e/mock-e2e-allowlist.js @@ -1,23 +1,6 @@ // Please do not add any more items to this list. // This list is temporary and the goal is to reduce it to 0, meaning all requests are mocked in our e2e tests. const ALLOWLISTED_URLS = [ - 'https://account.api.cx.metamask.io/networks/1/tokens', - 'https://account.api.cx.metamask.io/networks/10/tokens', - 'https://account.api.cx.metamask.io/networks/100/tokens', - 'https://account.api.cx.metamask.io/networks/1101/tokens', - 'https://account.api.cx.metamask.io/networks/1284/tokens', - 'https://account.api.cx.metamask.io/networks/1285/tokens', - 'https://account.api.cx.metamask.io/networks/1313161554/tokens', - 'https://account.api.cx.metamask.io/networks/137/tokens', - 'https://account.api.cx.metamask.io/networks/25/tokens', - 'https://account.api.cx.metamask.io/networks/250/tokens', - 'https://account.api.cx.metamask.io/networks/324/tokens', - 'https://account.api.cx.metamask.io/networks/42161/tokens', - 'https://account.api.cx.metamask.io/networks/42220/tokens', - 'https://account.api.cx.metamask.io/networks/43114/tokens', - 'https://account.api.cx.metamask.io/networks/56/tokens', - 'https://account.api.cx.metamask.io/networks/59144/tokens', - 'https://account.api.cx.metamask.io/networks/8453/tokens', 'https://accounts.google.com/ListAccounts?gpsia=1&source=ChromiumBrowser&json=standard', 'https://acl.execution.metamask.io/latest/registry.json', 'https://acl.execution.metamask.io/latest/signature.json', @@ -29,7 +12,6 @@ const ALLOWLISTED_URLS = [ 'https://authentication.api.cx.metamask.io/siwe/verify', 'https://bafkreifvhjdf6ve4jfv6qytqtux5nd4nwnelioeiqx5x2ez5yrgrzk7ypi.ipfs.dweb.link/', 'https://bafybeidxfmwycgzcp4v2togflpqh2gnibuexjy4m4qqwxp7nh3jx5zlh4y.ipfs.dweb.link/1.json', - 'https://bridge.api.cx.metamask.io/getAllFeatureFlags', 'https://bridge.api.cx.metamask.io/getTokens?chainId=1', 'https://cdn.contentful.com/spaces/jdkgyfmyd9sw/environments/master/entries?content_type=productAnnouncement&order=-sys.createdAt&fields.clients=portfolio', 'https://cdn.segment.com/analytics-next/bundles/ajs-destination.bundle.ed53a26b6edc80c65d73.js', @@ -40,14 +22,12 @@ const ALLOWLISTED_URLS = [ 'https://cdn.segment.com/v1/projects/MHae0tTVRqyHDim9qQ9ablSZpvm3Tvzc/settings', 'https://cdnjs.cloudflare.com/ajax/libs/mdbootstrap/4.14.1/css/mdb.min.css', 'https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.4.1/css/bootstrap.min.css', - 'https://chainid.network/chains.json', 'https://client-config.api.cx.metamask.io/v1/flags?client=extension&distribution=flask&environment=dev', - 'https://client-side-detection.api.cx.metamask.io/v1/request-blocklist', 'https://d6tizftlrpuof.cloudfront.net/themes/production/consensys-button-8ad6c4bb549247e0276dd160e2d8e00d.png', 'https://doesntexist.test/customRPC', 'https://etherscan.io/favicon.ico', - 'https://execution.metamask.io/iframe/7.1.0/index.html', - 'https://execution.metamask.io/iframe/7.1.0/bundle.js', + 'https://execution.metamask.io/iframe/7.2.1/index.html', + 'https://execution.metamask.io/iframe/7.2.1/bundle.js', 'https://gas.api.cx.metamask.io/networks/1/gasPrices', 'https://gas.api.cx.metamask.io/networks/1/suggestedGasFees', 'https://gas.api.cx.metamask.io/networks/1337/suggestedGasFees', @@ -112,12 +92,6 @@ const ALLOWLISTED_URLS = [ 'https://nft.api.cx.metamask.io/collections?chainId=0x539&contract=0x5fbdb2315678afecb367f032d93f642f64180aa3', 'https://nft.api.cx.metamask.io/users/0x5cfe73b6021e818b776b421b1c4db2474086a7e1/tokens?chainIds=1&limit=50&includeTopBid=true&continuation=', 'https://o1377931.ingest.sentry.io/api/6689755/envelope/?sentry_key=be397d53390141cda058e18f3749c8e4&sentry_version=7&sentry_client=sentry.javascript.react%2F7.102.1', - 'https://on-ramp-content.api.cx.metamask.io/regions/networks?context=extension', - 'https://on-ramp.api.cx.metamask.io/eligibility/mm-card?id=', - 'https://on-ramp.api.cx.metamask.io/eligibility/mm-card?id=0x01a92b9df8ce522a8f98161a97378bfdb2cce64f2d4293657e7eefe818d9ffbc', - 'https://on-ramp.api.cx.metamask.io/eligibility/mm-card?id=0xb1b1aa3036452bf32c1159266d1886279e4890ba907ed275e39fbc56906a8be2', - 'https://on-ramp.api.cx.metamask.io/eligibility/mm-card?id=7ea301c0-6a98-11ef-a19e-f3acaa606eca', - 'https://on-ramp.api.cx.metamask.io/eligibility/mm-card?id=8af26790-6a98-11ef-bee7-5553e37c0097', 'https://raw.githubusercontent.com/MetaMask/eth-phishing-detect/master/src/config.json', 'https://responsive-rpc.test/', 'https://security-alerts.api.cx.metamask.io/validate/0x1', @@ -127,16 +101,6 @@ const ALLOWLISTED_URLS = [ 'https://signature-insights.api.cx.metamask.io/v1/signature?chainId=0x539', 'https://sourcify.dev/server/files/any/1337/0x', 'https://staking.api.cx.metamask.io/v1/pooled-staking/eligibility?addresses=', - 'https://static.cx.metamask.io/api/v1/tokenIcons/1337/0x0000000000000000000000000000000000000000.png', - 'https://static.cx.metamask.io/api/v1/tokenIcons/1/0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2.png', - 'https://static.cx.metamask.io/api/v1/tokenIcons/1/0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48.png', - 'https://static.cx.metamask.io/api/v1/tokenIcons/1337/0x581c3c1a2a4ebde2a0df29b5cf4c116e42945947.png', - 'https://static.cx.metamask.io/api/v1/tokenIcons/1337/0x6b175474e89094c44da98b954eedeac495271d0f.png', - 'https://static.cx.metamask.io/api/v1/tokenIcons/1337/0x86002be4cdd922de1ccb831582bf99284b99ac12.png', - 'https://static.cx.metamask.io/api/v1/tokenIcons/1337/0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48.png', - 'https://static.cx.metamask.io/api/v1/tokenIcons/1337/0xc6bdb96e29c38dc43f014eed44de4106a6a8eb5f.png', - 'https://static.cx.metamask.io/api/v1/tokenIcons/56/0x0d8775f648430679a709e98d2b0cb6250d2887ef.png', - 'https://static.cx.metamask.io/api/v1/tokenIcons/56/0x6b175474e89094c44da98b954eedeac495271d0f.png', 'https://swap.api.cx.metamask.io/networks/1', 'https://swap.api.cx.metamask.io/networks/1/trades?destinationToken=0x6b175474e89094c44da98b954eedeac495271d0f&sourceToken=0x0000000000000000000000000000000000000000&sourceAmount=1000000000000000&slippage=2&timeout=10000&walletAddress=0x5cfe73b6021e818b776b421b1c4db2474086a7e1', 'https://swap.api.cx.metamask.io/networks/1/trades?destinationToken=0x6b175474e89094c44da98b954eedeac495271d0f&sourceToken=0x0000000000000000000000000000000000000000&sourceAmount=2000000000000000000&slippage=2&timeout=10000&walletAddress=0x5cfe73b6021e818b776b421b1c4db2474086a7e1', @@ -153,15 +117,6 @@ const ALLOWLISTED_URLS = [ 'https://verify.walletconnect.com/e6360eaee594162688065f1c70c863b7', 'https://w.usabilla.com/ade130c1096e.js?lv=1', 'https://websites.cdn.getfeedback.com/embed/aaeNy60jTL/gf.js', - 'https://www.4byte.directory/api/v1/signatures/?hex_signature=0x', - 'https://www.4byte.directory/api/v1/signatures/?hex_signature=0x048226a0', - 'https://www.4byte.directory/api/v1/signatures/?hex_signature=0x095ea7b3', - 'https://www.4byte.directory/api/v1/signatures/?hex_signature=0x23b872dd', - 'https://www.4byte.directory/api/v1/signatures/?hex_signature=0x2e1a7d4d', - 'https://www.4byte.directory/api/v1/signatures/?hex_signature=0x39509351', - 'https://www.4byte.directory/api/v1/signatures/?hex_signature=0x5f575529', - 'https://www.4byte.directory/api/v1/signatures/?hex_signature=0x60806040', - 'https://www.4byte.directory/api/v1/signatures/?hex_signature=0xd0e30db0', ]; const ALLOWLISTED_HOSTS = [ diff --git a/test/e2e/mock-e2e.js b/test/e2e/mock-e2e.js index ce513fd22ec7..b1aebbfc972c 100644 --- a/test/e2e/mock-e2e.js +++ b/test/e2e/mock-e2e.js @@ -35,8 +35,17 @@ const CDN_STALE_DIFF_RES_HEADERS_PATH = const CDN_STALE_RES_HEADERS_PATH = 'test/e2e/mock-cdn/cdn-stale-res-headers.json'; +const ACCOUNTS_API_TOKENS_PATH = + 'test/e2e/mock-response-data/accounts-api-tokens.json'; const AGGREGATOR_METADATA_PATH = 'test/e2e/mock-response-data/aggregator-metadata.json'; +const BRIDGE_GET_ALL_FEATURE_FLAGS_PATH = + 'test/e2e/mock-response-data/bridge-get-all-feature-flags.json'; +const CHAIN_ID_NETWORKS_PATH = + 'test/e2e/mock-response-data/chain-id-network-chains.json'; +const CLIENT_SIDE_DETECTION_BLOCKLIST_PATH = + 'test/e2e/mock-response-data/client-side-detection-blocklist.json'; +const ON_RAMP_CONTENT_PATH = 'test/e2e/mock-response-data/on-ramp-content.json'; const TOKEN_BLOCKLIST_PATH = 'test/e2e/mock-response-data/token-blocklist.json'; const blocklistedHosts = [ @@ -829,6 +838,104 @@ async function setupMocking( }; }); + // On Ramp Content + const ON_RAMP_CONTENT = fs.readFileSync(ON_RAMP_CONTENT_PATH); + await server + .forGet('https://on-ramp-content.api.cx.metamask.io/regions/networks') + .thenCallback(() => { + return { + statusCode: 200, + json: JSON.parse(ON_RAMP_CONTENT), + }; + }); + + // Chains Metadata + const CHAIN_ID_NETWORKS = fs.readFileSync(CHAIN_ID_NETWORKS_PATH); + await server + .forGet('https://chainid.network/chains.json') + .thenCallback(() => { + return { + statusCode: 200, + json: JSON.parse(CHAIN_ID_NETWORKS), + }; + }); + + // Accounts API: supported networks + await server + .forGet('https://accounts.api.cx.metamask.io/v1/supportedNetworks') + .thenCallback(() => { + return { + statusCode: 200, + json: { + fullSupport: [1, 137, 56, 59144, 8453, 10, 42161, 534352], + partialSupport: { + balances: [42220, 43114], + }, + }, + }; + }); + + // Accounts API: tokens + const ACCOUNTS_API_TOKENS = fs.readFileSync(ACCOUNTS_API_TOKENS_PATH); + await server + .forGet('https://account.api.cx.metamask.io/networks') + .thenCallback(() => { + return { + statusCode: 200, + json: JSON.parse(ACCOUNTS_API_TOKENS), + }; + }); + + // Bridge Feature Flags + const BRIDGE_GET_ALL_FEATURE_FLAGS = fs.readFileSync( + BRIDGE_GET_ALL_FEATURE_FLAGS_PATH, + ); + await server + .forGet('https://bridge.api.cx.metamask.io/getAllFeatureFlags') + .thenCallback(() => { + return { + statusCode: 200, + json: JSON.parse(BRIDGE_GET_ALL_FEATURE_FLAGS), + }; + }); + + // Client Side Detecition: Request Blocklist + const CLIENT_SIDE_DETECTION_BLOCKLIST = fs.readFileSync( + CLIENT_SIDE_DETECTION_BLOCKLIST_PATH, + ); + await server + .forGet( + 'https://client-side-detection.api.cx.metamask.io/v1/request-blocklist', + ) + .thenCallback(() => { + return { + statusCode: 200, + json: JSON.parse(CLIENT_SIDE_DETECTION_BLOCKLIST), + }; + }); + + // On Ramp: Eligibility MetaMask Card + await server + .forGet('https://on-ramp.api.cx.metamask.io/eligibility/mm-card') + .thenCallback(() => { + return { + statusCode: 200, + body: true, + headers: { + 'Content-Type': 'text/html; charset=utf-8', + }, + }; + }); + + // Token Icons + await server + .forGet('https://static.cx.metamask.io/api/v1/tokenIcons') + .thenCallback(() => { + return { + statusCode: 200, + }; + }); + /** * Returns an array of alphanumerically sorted hostnames that were requested * during the current test suite. diff --git a/test/e2e/mock-response-data/accounts-api-tokens.json b/test/e2e/mock-response-data/accounts-api-tokens.json new file mode 100644 index 000000000000..b556502c5b29 --- /dev/null +++ b/test/e2e/mock-response-data/accounts-api-tokens.json @@ -0,0 +1,13 @@ +[ + { + "name": "Ethereum", + "symbol": "ETH", + "decimals": 18, + "address": "0x0000000000000000000000000000000000000000", + "iconUrl": "https://token.api.cx.metamask.io/assets/nativeCurrencyLogos/ethereum.svg", + "occurrences": 100, + "sources": [], + "chainId": 1, + "coingeckoId": "ethereum" + } +] diff --git a/test/e2e/mock-response-data/bridge-get-all-feature-flags.json b/test/e2e/mock-response-data/bridge-get-all-feature-flags.json new file mode 100644 index 000000000000..29f1cdd6b245 --- /dev/null +++ b/test/e2e/mock-response-data/bridge-get-all-feature-flags.json @@ -0,0 +1,413 @@ +{ + "$flagsState": { + "aggregator-allowlist": { "variation": 0, "version": 16 }, + "approval-gas-multiplier": { "variation": 1, "version": 25 }, + "blocked-wallets": { "variation": 1, "version": 7 }, + "bridge-allowlist": { "variation": 8, "version": 47 }, + "bridge-gas-multiplier": { "variation": 4, "version": 36 }, + "bridge-self-serve-config": { "variation": 2, "version": 9 }, + "bridge-slippage-override": { "variation": 0, "version": 2 }, + "bridge-token-blacklist": { "variation": 1, "version": 3 }, + "dest-network-allowlist": { "variation": 7, "version": 27 }, + "dev-addresses": { "variation": 0, "version": 18 }, + "exchange-allowlist": { "variation": 6, "version": 20 }, + "extension-config": { "variation": 2, "version": 12 }, + "extension-support": { "variation": 1, "version": 2 }, + "fee-rate": { "variation": 0, "version": 13 }, + "fee-tokens": { "variation": 3, "version": 16 }, + "metabridge-contract-version": { "variation": 1, "version": 3 }, + "mobile-config": { "variation": 1, "version": 3 }, + "quote-timeout-ms": { "variation": 3, "version": 10 }, + "selected-simulator": { "variation": 7, "version": 42 }, + "socket-api-url-update": { "variation": 1, "version": 2 }, + "src-network-allowlist": { "variation": 8, "version": 32 } + }, + "$valid": true, + "aggregator-allowlist": ["lifi", "socket", "squid"], + "approval-gas-multiplier": { + "1": 1, + "10": 1.1, + "56": 1.1, + "137": 1, + "324": 1, + "8453": 1, + "42161": 1.1, + "43114": 1, + "59144": 1 + }, + "blocked-wallets": ["0x106311b0651fd123d02B4c999CCA810712bb347B"], + "bridge-allowlist": [ + "hop", + "polygon", + "celer", + "celercircle", + "connext", + "axelar", + "across", + "stargate", + "mayan", + "mayanWH", + "mayanMCTP", + "relay" + ], + "bridge-gas-multiplier": { + "1": 1.1, + "10": 1.1, + "56": 1.1, + "137": 1.1, + "324": 10, + "8453": 1.1, + "42161": 1.1, + "43114": 1.1, + "59144": 1.1 + }, + "bridge-self-serve-config": { + "1": { "tests": 5 }, + "10": { "tests": 5 }, + "56": { "tests": 5 }, + "137": { "tests": 5 }, + "324": { "tests": 5 }, + "8453": { "tests": 5 }, + "42161": { "tests": 5 }, + "43114": { "tests": 5 }, + "59144": { "tests": 5 } + }, + "bridge-slippage-override": {}, + "bridge-token-blacklist": { + "8453": ["0x8544fe9d190fd7ec52860abbf45088e81ee24a8c"] + }, + "dest-network-allowlist": [ + 1, 10, 56, 137, 324, 8453, 42161, 43114, 59144, 1151111081099710 + ], + "dev-addresses": [ + "0xaf1f673eec5b26f99fc42a9863f180822e2e8bec", + "0xd374df405d07d1a7dc77b5f1fe4aec9adf79591d", + "0x0a985a957b490f4d05bef05bc7ec556dd8535946" + ], + "exchange-allowlist": { + "1": [ + "pangolin", + "curve_v2", + "pancakeswap_v3", + "uniswap_v3", + "kyberswap", + "quickswap_v3", + "paraswap", + "hashflow", + "openocean", + "0x", + "1inch", + "airswap" + ], + "10": [ + "pangolin", + "curve_v2", + "pancakeswap_v3", + "uniswap_v3", + "kyberswap", + "quickswap_v3", + "hashflow", + "openocean", + "0x", + "1inch" + ], + "56": [ + "pangolin", + "curve_v2", + "pancakeswap_v3", + "uniswap_v3", + "kyberswap", + "quickswap_v3", + "paraswap", + "hashflow", + "0x", + "1inch", + "airswap" + ], + "137": [ + "pangolin", + "curve_v2", + "pancakeswap_v3", + "uniswap_v3", + "kyberswap", + "quickswap_v3", + "paraswap", + "hashflow", + "openocean", + "0x", + "1inch", + "airswap" + ], + "324": [ + "pangolin", + "curve_v2", + "pancakeswap_v3", + "uniswap_v3", + "kyberswap", + "quickswap_v3", + "paraswap", + "hashflow", + "openocean", + "0x", + "1inch", + "airswap" + ], + "8453": [ + "pangolin", + "curve_v2", + "pancakeswap_v3", + "uniswap_v3", + "kyberswap", + "quickswap_v3", + "paraswap", + "hashflow", + "openocean", + "0x", + "1inch", + "airswap" + ], + "42161": [ + "pangolin", + "curve_v2", + "pancakeswap_v3", + "uniswap_v3", + "kyberswap", + "quickswap_v3", + "hashflow", + "openocean", + "0x", + "1inch", + "airswap", + "camelot_v3" + ], + "43114": [ + "pangolin", + "curve_v2", + "pancakeswap_v3", + "uniswap_v3", + "kyberswap", + "quickswap_v3", + "paraswap", + "hashflow", + "openocean", + "0x", + "1inch", + "airswap" + ], + "59144": [ + "pangolin", + "curve_v2", + "pancakeswap_v3", + "uniswap_v3", + "kyberswap", + "quickswap_v3", + "paraswap", + "hashflow", + "openocean", + "0x", + "1inch", + "airswap" + ], + "1151111081099710": ["jupiter"] + }, + "extension-config": { + "maxRefreshCount": 5, + "refreshRate": 30000, + "support": true, + "chains": { + "1": { "isActiveDest": true, "isActiveSrc": true }, + "10": { "isActiveSrc": true, "isActiveDest": true }, + "56": { "isActiveDest": true, "isActiveSrc": true }, + "137": { "isActiveDest": true, "isActiveSrc": true }, + "324": { "isActiveDest": true, "isActiveSrc": true }, + "8453": { "isActiveDest": true, "isActiveSrc": true }, + "42161": { "isActiveDest": true, "isActiveSrc": true }, + "43114": { "isActiveDest": true, "isActiveSrc": true }, + "59144": { "isActiveDest": true, "isActiveSrc": true }, + "1151111081099710": { + "topAssets": [ + "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", + "6p6xgHyF7AeE6TZkSmFsko444wqoP15icUSqi2jfGiPN", + "JUPyiwrYJFskUPiHa7hkeR8VUtAeFoSYbKedZNsDvCN", + "7vfCXTUXx5WJV5JADk17DUJ4ksgau7utNKj4b963voxsDx8F8k8k3uYw1PDC", + "3iQL8BFS2vE7mww4ehAqQHAsbmRNCrPxizWAT2Zfyr9y", + "9zNQRsGLjNKwCUU5Gq5LR8beUCPzQMVMqKAi3SSZh54u", + "DezXAZ8z7PnrnRJjz3wXBoRgixCa6xjnB7YaB1pPB263", + "rndrizKT3MK1iimdxRdWabcF7Zg7AR5T4nud4EkHBof", + "21AErpiB8uSb94oQKRcwuHqyHF93njAxBSbdUrpupump" + ], + "isActiveDest": true, + "isActiveSrc": true, + "refreshRate": 10000 + } + } + }, + "extension-support": false, + "fee-rate": "875", + "fee-tokens": { + "1": [ + "0x0000000000000000000000000000000000000000", + "0x2260fac5e5542a773aa44fbcfedf7c193bc2c599", + "0xdC035D45d973E3EC169d2276DDab16f1e407384F", + "0x6b175474e89094c44da98b954eedeac495271d0f", + "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", + "0x056Fd409E1d7A124BD7017459dFEa2F387b6d5Cd", + "0x1f9840a85d5af5bf1d1762f925bdaddc4201f984", + "0x9f8f72aa9304c8b593d555f12ef6589cc3a579a2", + "0x7Fc66500c84A76Ad7e9c93437bFc5Ac33E2DDaE9", + "0xc00e94cb662c3520282e6f5717214004a7f26888", + "0xc011a73ee8576fb46f5e1c5751ca3b9fe0af2a6f", + "0x6b3595068778dd592e39a122f4f5a5cf09c90fe2", + "0xe41d2489571d322189246dafa5ebde1f4699f498", + "0xD533a949740bb3306d119CC777fa900bA034cd52", + "0x0bc529c00c6401aef6d220be8c6ea1667f6ad93e", + "0xba100000625a3754423978a60c9317c58a424e3D", + "0x514910771af9ca656af840dff83e8264ecf986ca", + "0x7D1AfA7B718fb893dB30A3aBc0Cfc608AaCfeBB0", + "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", + "0xeb4c2781e4eba804ce9a9803c67d0893436bb27d", + "0x5d3a536e4d6dbd6114cc1ead35777bab948e3643", + "0x0000000000085d4780B73119b644AE5ecd22b376", + "0x4Fabb145d64652a948d72533023f6E7A623C7C53", + "0x8e870d67f660d95d5be530380d0ec0bd388289e1", + "0xd46ba6d942050d489dbd938a2c909a5d5039a161", + "0x5f98805A4E8be255a32880FDeC7F6728C6568bA0", + "0xaaaebe6fe48e54f431b0c390cfaf0b017d09d42d", + "0x1f573d6fb3f13d689ff844b4ce37794d79a7ff1c", + "0x111111111117dc0aa78b770fa6a738034120c302", + "0x408e41876cccdc0f92210600ef50372656052a38", + "0x4e15361fd6b4bb609fa63c81a2be19d873717870", + "0x2ba592f78db6436527729929aaf6c908497cb200", + "0x0f5d2fb29fb7d3cfee444a200298f468908cc942", + "0xc944e90c64b2c07662a292be6244bdf05cda44a7", + "0x0d8775f648430679a709e98d2b0cb6250d2887ef", + "0xd26114cd6ee289accf82350c8d8487fedb8a0c07", + "0x50d1c9771902476076ecfc8b2a83ad6b9355a4c9", + "0x2b591e99afe9f32eaa6214f7b7629768c40eeb39", + "0x4a220e6096b25eadb88358cb44068a3248254675", + "0x467bccd9d29f223bce8043b84e8c8b282827790f", + "0x4691937a7508860f876c9c0a2a617e7d9e945d4b", + "0x1494ca1f11d487c2bbe4543e90080aeba4ba3c2b", + "0xbb0e17ef65f82ab018d8edd776e8dd940327b28b", + "0x1985365e9f78359a9B6AD760e32412f4a445E862", + "0xCC8Fa225D80b9c7D42F96e9570156c65D6cAAa25", + "0x5a98fcbea516cf06857215779fd812ca3bef1b32", + "0xdac17f958d2ee523a2206206994597c13d831ec7", + "0xae78736cd615f374d3085123a210448e74fc6393", + "0xae7ab96520de3a18e5e111b5eaab095312d7fe84", + "0x7f39c581f595b53c5cb19bd0b3f8da6c935e2ca0" + ], + "10": [ + "0x4200000000000000000000000000000000000006", + "0x68f180fcCe6836688e9084f035309E29Bf0A2095", + "0x7F5c764cBc14f9669B88837ca1490cCa17c31607", + "0xDA10009cBd5D07dd0CeCc66161FC93D7c9000da1", + "0x8c6f28f2F1A3C87F0f938b96d27520d9751ec8d9", + "0x4200000000000000000000000000000000000042", + "0x94b008aA00579c1307B0EF2c499aD98a8ce58e58", + "0x0000000000000000000000000000000000000000", + "0x9bcef72be871e61ed4fbbc7630889bee758eb81d", + "0x68f180fcce6836688e9084f035309e29bf0a2095", + "0x0b2C639c533813f4Aa9D7837CAf62653d097Ff85" + ], + "56": [ + "0x2170ed0880ac9a755fd29b2688956bd959f933f8", + "0x8ac76a51cc950d9822d68b83fe1ad97b32cd580d", + "0x1af3f329e8be154074d8769d1ffa4ee058b1dbc3", + "0x0000000000000000000000000000000000000000", + "0xbb4cdb9cbd36b01bd1cbaebf2de08d9173bc095c", + "0xe9e7cea3dedca5984780bafc599bd69add087d56", + "0x55d398326f99059ff775485246999027b3197955", + "0x0e09fabb73bd3ade0a17ecc321fd13a19e81ce82", + "0xcc42724c6683b7e57334c4e856f4c9965ed682bd", + "0x1ce0c2827e2ef14d5c4f29a091d735a204794041", + "0x7130d2a12b9bcbfae4f2634d864a1ee1ce3ead9c" + ], + "137": [ + "0x7ceb23fd6bc0add59e62ac25578270cff1b9f619", + "0x1bfd67037b42cf73acf2047067bd4f2c47d9bfd6", + "0x2791bca1f2de4661ed88a30c99a7a9449aa84174", + "0x8f3cf7ad23cd3cadbd9735aff958023239c6a063", + "0x0000000000000000000000000000000000001010", + "0x0000000000000000000000000000000000000000", + "0x0d500b1d8e8ef31e21c99d1db9a6444d3adf1270", + "0xc2132d05d31c914a87c6611c10748aeb04b58e8f", + "0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359" + ], + "324": [ + "0x0000000000000000000000000000000000000000", + "0x000000000000000000000000000000000000800A", + "0x5AEa5775959fBC2557Cc8789bC1bf90A239D9a91", + "0xBBeB516fb02a01611cBBE0453Fe3c580D7281011", + "0x3355df6D4c9C3035724Fd0e3914dE96A5a83aaf4", + "0x493257fD37EDB34451f62EDf8D2a0C418852bA4C", + "0x32fd44bb869620c0ef993754c8a00be67c464806", + "0x4bef76b6b7f2823c6c1f4fcfeacd85c24548ad7e", + "0x1d17CBcF0D6D143135aE902365D2E5e2A16538D4" + ], + "8453": [ + "0x0000000000000000000000000000000000000000", + "0x50c5725949a6f0c72e6c4a641f24049a917db0cb", + "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913", + "0xd9aaec86b65d86f6a7b5b1b0c42ffa531710b6ca" + ], + "42161": [ + "0x82aF49447D8a07e3bd95BD0d56f35241523fBab1", + "0x2f2a2543B76A4166549F7aaB2e75Bef0aefC5B0f", + "0xaf88d065e77c8cC2239327C5EDb3A432268e5831", + "0xDA10009cBd5D07dd0CeCc66161FC93D7c9000da1", + "0xFd086bC7CD5C481DCC9C85ebE478A1C0b69FCbb9", + "0x0000000000000000000000000000000000000000", + "0x912CE59144191C1204E64559FE8253a0e49E6548", + "0xff970a61a04b1ca14834a43f5de4533ebddb5cc8", + "0xec70dcb4a1efa46b8f2d97c310c9c4790ba5ffa8", + "0x82af49447d8a07e3bd95bd0d56f35241523fbab1", + "0x2f2a2543b76a4166549f7aab2e75bef0aefc5b0f" + ], + "43114": [ + "0x49d5c2bdffac6ce2bfdb6640f4f80f226bc10bab", + "0x50b7545627a5162f82a992c33b87adc75187b218", + "0xb97ef9ef8734c71904d8002f8b6bc66dd9c48a6e", + "0xa7d7079b0fead91f3e65f86e8915cb59c1a4c664", + "0xd586e7f844cea2f87f50152665bcbc2c279d8d70", + "0xba7deebbfc5fa1100fb055a87773e1e99cd3507a", + "0x0000000000000000000000000000000000000000", + "0xb31f66aa3c1e785363f0875a1b74e27b85fd66c7", + "0x19860ccb0a68fd4213ab9d8266f7bbf05a8dde98", + "0xc7198437980c041c805a1edcba50c1ce5db95118", + "0x9702230a8ea53601f5cd2dc00fdbc13d4df4a8c7" + ], + "59144": [ + "0x0000000000000000000000000000000000000000", + "0x3aAB2285ddcDdaD8edf438C1bAB47e1a9D05a9b4", + "0xA219439258ca9da29E9Cc4cE5596924745e12B93", + "0x4AF15ec2A0BD43Db75dd04E62FAA3B8EF36b00d5", + "0x176211869cA2b568f2A7D4EE941E073a821EE1ff", + "0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f" + ] + }, + "hostname": "bridge-api-777b55555c-bs6cb", + "metabridge-contract-version": "v2", + "mobile-config": { + "chains": {}, + "maxRefreshCount": 1, + "refreshRate": 3000000, + "support": false + }, + "quote-timeout-ms": 15000, + "selected-simulator": { + "1": "txLifecycle", + "10": "txLifecycle", + "56": "txLifecycle", + "137": "txLifecycle", + "324": "defaults", + "8453": "txLifecycle", + "42161": "txLifecycle", + "43114": "txLifecycle", + "59144": "txLifecycle" + }, + "socket-api-url-update": false, + "src-network-allowlist": [ + 1, 10, 56, 137, 324, 8453, 42161, 43114, 59144, 1151111081099710 + ] +} diff --git a/test/e2e/mock-response-data/chain-id-network-chains.json b/test/e2e/mock-response-data/chain-id-network-chains.json new file mode 100644 index 000000000000..a7616175ead2 --- /dev/null +++ b/test/e2e/mock-response-data/chain-id-network-chains.json @@ -0,0 +1,211 @@ +[ + { + "name": "Ethereum Mainnet", + "chain": "ETH", + "icon": "ethereum", + "rpc": [ + "https://mainnet.infura.io/v3/${INFURA_API_KEY}", + "wss://mainnet.infura.io/ws/v3/${INFURA_API_KEY}", + "https://api.mycryptoapi.com/eth", + "https://cloudflare-eth.com", + "https://ethereum-rpc.publicnode.com", + "wss://ethereum-rpc.publicnode.com", + "https://mainnet.gateway.tenderly.co", + "wss://mainnet.gateway.tenderly.co", + "https://rpc.blocknative.com/boost", + "https://rpc.flashbots.net", + "https://rpc.flashbots.net/fast", + "https://rpc.mevblocker.io", + "https://rpc.mevblocker.io/fast", + "https://rpc.mevblocker.io/noreverts", + "https://rpc.mevblocker.io/fullprivacy", + "https://eth.drpc.org", + "wss://eth.drpc.org", + "https://api.securerpc.com/v1" + ], + "features": [{ "name": "EIP155" }, { "name": "EIP1559" }], + "faucets": [], + "nativeCurrency": { "name": "Ether", "symbol": "ETH", "decimals": 18 }, + "infoURL": "https://ethereum.org", + "shortName": "eth", + "chainId": 1, + "networkId": 1, + "slip44": 60, + "ens": { "registry": "0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e" }, + "explorers": [ + { + "name": "etherscan", + "url": "https://etherscan.io", + "standard": "EIP3091" + }, + { + "name": "blockscout", + "url": "https://eth.blockscout.com", + "icon": "blockscout", + "standard": "EIP3091" + }, + { + "name": "dexguru", + "url": "https://ethereum.dex.guru", + "icon": "dexguru", + "standard": "EIP3091" + }, + { + "name": "Routescan", + "url": "https://ethereum.routescan.io", + "standard": "EIP3091" + } + ] + }, + { + "name": "Orderly Mainnet", + "chain": "ETH", + "rpc": ["https://rpc.orderly.network"], + "faucets": [], + "nativeCurrency": { "name": "Ether", "symbol": "ETH", "decimals": 18 }, + "infoURL": "https://orderly.network/", + "shortName": "orderly", + "chainId": 291, + "networkId": 291, + "icon": "orderly", + "explorers": [ + { + "name": "orderlyscout", + "url": "https://explorer.orderly.network", + "icon": "blockscout", + "standard": "EIP3091" + } + ] + }, + { + "name": "PrimusChain mainnet", + "chain": "PC", + "rpc": ["https://ethnode.primusmoney.com/mainnet"], + "faucets": [], + "nativeCurrency": { + "name": "Primus Ether", + "symbol": "PETH", + "decimals": 18 + }, + "infoURL": "https://primusmoney.com", + "shortName": "primuschain", + "chainId": 78, + "networkId": 78 + }, + { + "name": "Camino C-Chain", + "chain": "CAM", + "rpc": ["https://api.camino.network/ext/bc/C/rpc"], + "faucets": [], + "nativeCurrency": { "name": "Camino", "symbol": "CAM", "decimals": 18 }, + "infoURL": "https://camino.network/", + "shortName": "Camino", + "chainId": 500, + "networkId": 1000, + "icon": "camino", + "explorers": [ + { + "name": "blockexplorer", + "url": "https://suite.camino.network/explorer", + "standard": "none" + } + ] + }, + { + "name": "Elysium Testnet", + "title": "An L1, carbon-neutral, tree-planting, metaverse dedicated blockchain created by VulcanForged", + "chain": "Atlantis", + "rpc": ["https://rpc.atlantischain.network"], + "faucets": ["https://faucet.atlantischain.network"], + "nativeCurrency": { "name": "ELY", "symbol": "ELY", "decimals": 18 }, + "infoURL": "https://elysiumchain.tech", + "shortName": "ATL", + "chainId": 1338, + "networkId": 1338, + "explorers": [ + { + "name": "Atlantis explorer", + "url": "https://blockscout.atlantischain.network", + "standard": "EIP3091" + } + ] + }, + { + "name": "Geth Testnet", + "title": "Go Ethereum (Geth) Private Testnet", + "chain": "ETH", + "rpc": ["http://127.0.0.1:8545"], + "faucets": [], + "nativeCurrency": { + "name": "Geth Testnet Ether", + "symbol": "ETH", + "decimals": 18 + }, + "infoURL": "https://geth.ethereum.org", + "shortName": "geth", + "chainId": 1337, + "networkId": 1337, + "slip44": 1 + }, + { + "name": "Linea Sepolia", + "title": "Linea Sepolia Testnet", + "chain": "ETH", + "rpc": [ + "https://rpc.sepolia.linea.build", + "wss://rpc.sepolia.linea.build", + "https://linea-sepolia.infura.io/v3/${INFURA_API_KEY}", + "wss://linea-sepolia.infura.io/ws/v3/${INFURA_API_KEY}", + "https://linea-sepolia-rpc.publicnode.com", + "wss://linea-sepolia-rpc.publicnode.com" + ], + "faucets": [], + "nativeCurrency": { + "name": "Linea Ether", + "symbol": "ETH", + "decimals": 18 + }, + "infoURL": "https://linea.build", + "shortName": "linea-sepolia", + "chainId": 59141, + "networkId": 59141, + "slip44": 1, + "icon": "linea", + "parent": { + "type": "L2", + "chain": "eip155-11155111", + "bridges": [{ "url": "https://bridge.linea.build/" }] + }, + "explorers": [ + { + "name": "Etherscan", + "url": "https://sepolia.lineascan.build", + "standard": "EIP3091", + "icon": "linea" + }, + { + "name": "Blockscout", + "url": "https://explorer.sepolia.linea.build", + "standard": "EIP3091", + "icon": "linea" + } + ], + "status": "active" + }, + { + "name": "MegaETH Testnet", + "chain": "ETH", + "nativeCurrency": { + "name": "MegaETH Testnet Ether", + "symbol": "ETH", + "decimals": 18 + }, + "rpc": ["https://carrot.megaeth.com/rpc", "wss://carrot.megaeth.com/ws"], + "faucets": [], + "infoURL": "https://testnet.megaeth.com", + "shortName": "megatest", + "chainId": 6342, + "networkId": 6342, + "slip44": 1 + } +] diff --git a/test/e2e/mock-response-data/client-side-detection-blocklist.json b/test/e2e/mock-response-data/client-side-detection-blocklist.json new file mode 100644 index 000000000000..ff2459da6939 --- /dev/null +++ b/test/e2e/mock-response-data/client-side-detection-blocklist.json @@ -0,0 +1,7 @@ +{ + "lastFetchedAt": 1743579433, + "recentlyAdded": [ + "c0e2feb0871e55372e310484bf02b54001e23cf8e2f655e3d4ecaf903a408314" + ], + "recentlyRemoved": [] +} diff --git a/test/e2e/mock-response-data/on-ramp-content.json b/test/e2e/mock-response-data/on-ramp-content.json new file mode 100644 index 000000000000..aeba574ac637 --- /dev/null +++ b/test/e2e/mock-response-data/on-ramp-content.json @@ -0,0 +1,172 @@ +{ + "networks": [ + { + "active": true, + "chainId": "42161", + "chainName": "Arbitrum Mainnet", + "shortName": "Arbitrum", + "isEvm": true, + "nativeTokenSupported": true + }, + { + "active": true, + "chainId": "1313161554", + "chainName": "Aurora Mainnet", + "shortName": "Aurora", + "isEvm": true, + "nativeTokenSupported": false + }, + { + "active": true, + "chainId": "43114", + "chainName": "Avalanche C-Chain Mainnet", + "shortName": "Avalanche C-Chain", + "isEvm": true, + "nativeTokenSupported": true + }, + { + "active": true, + "chainId": "8453", + "chainName": "Base Mainnet", + "shortName": "Base", + "isEvm": true, + "nativeTokenSupported": true + }, + { + "active": true, + "chainId": "80094", + "chainName": "Berachain Mainnet", + "shortName": "Berachain", + "isEvm": true, + "nativeTokenSupported": true + }, + { + "active": true, + "chainId": "bip122:000000000019d6689c085ae165831e93", + "chainName": "Bitcoin", + "shortName": "Bitcoin", + "nativeTokenSupported": true, + "isEvm": false + }, + { + "active": true, + "chainId": "56", + "chainName": "BNB Chain Mainnet", + "shortName": "BNB Chain", + "isEvm": true, + "nativeTokenSupported": true + }, + { + "active": true, + "chainId": "42220", + "chainName": "Celo Mainnet", + "shortName": "Celo", + "isEvm": true, + "nativeTokenSupported": false + }, + { + "active": true, + "chainId": "25", + "chainName": "Cronos Mainnet", + "shortName": "Cronos", + "isEvm": true, + "nativeTokenSupported": true + }, + { + "active": true, + "chainId": "1", + "chainName": "Ethereum Mainnet", + "shortName": "Ethereum", + "isEvm": true, + "nativeTokenSupported": true + }, + { + "active": true, + "chainId": "250", + "chainName": "Fantom Mainnet", + "shortName": "Fantom", + "isEvm": true, + "nativeTokenSupported": true + }, + { + "active": true, + "chainId": "100", + "chainName": "Gnosis Mainnet", + "shortName": "Gnosis", + "isEvm": true, + "nativeTokenSupported": true + }, + { + "active": true, + "chainId": "1666600000", + "chainName": "Harmony Mainnet (Shard 0)", + "shortName": "Harmony (Shard 0)", + "isEvm": true, + "nativeTokenSupported": true + }, + { + "active": true, + "chainId": "59144", + "chainName": "Linea", + "shortName": "Linea", + "isEvm": true, + "nativeTokenSupported": true + }, + { + "active": true, + "chainId": "1284", + "chainName": "Moonbeam Mainnet", + "shortName": "Moonbeam", + "isEvm": true, + "nativeTokenSupported": true + }, + { + "active": true, + "chainId": "1285", + "chainName": "Moonriver Mainnet", + "shortName": "Moonriver", + "isEvm": true, + "nativeTokenSupported": true + }, + { + "active": true, + "chainId": "10", + "chainName": "Optimism Mainnet", + "shortName": "Optimism", + "isEvm": true, + "nativeTokenSupported": true + }, + { + "active": true, + "chainId": "137", + "chainName": "Polygon Mainnet", + "shortName": "Polygon", + "isEvm": true, + "nativeTokenSupported": true + }, + { + "active": true, + "chainId": "1101", + "chainName": "Polygon zkEVM", + "shortName": "Polygon zkEVM", + "isEvm": true, + "nativeTokenSupported": true + }, + { + "active": true, + "chainId": "146", + "chainName": "Sonic", + "shortName": "Sonic", + "isEvm": true, + "nativeTokenSupported": true + }, + { + "active": true, + "chainId": "324", + "chainName": "zkSync Era Mainnet", + "shortName": "zkSync Era", + "isEvm": true, + "nativeTokenSupported": true + } + ] +} diff --git a/test/e2e/page-objects/flows/encrypt-decrypt.flow.ts b/test/e2e/page-objects/flows/encrypt-decrypt.flow.ts new file mode 100644 index 000000000000..01cde22cfec9 --- /dev/null +++ b/test/e2e/page-objects/flows/encrypt-decrypt.flow.ts @@ -0,0 +1,52 @@ +import { Driver } from '../../webdriver/driver'; +import { WINDOW_TITLES } from '../../helpers'; +import { DEFAULT_LOCAL_NODE_ETH_BALANCE_DEC } from '../../constants'; +import DecryptMessageConfirmation from '../pages/confirmations/redesign/decrypt-message-confirmation'; +import GetEncryptionKeyConfirmation from '../pages/confirmations/redesign/get-encryption-key-confirmation'; +import TestDapp from '../pages/test-dapp'; + +/** + * Get encryption key in test dapp and verify the result. + * + * @param driver - The driver instance. + * @param encryptionKey - The expected encryption key to display. + * @param balanceValue - The balance value to check, default is DEFAULT_LOCAL_NODE_ETH_BALANCE_DEC. + */ +export async function getEncryptionKeyInDapp(driver: Driver, encryptionKey: string, balanceValue: string = DEFAULT_LOCAL_NODE_ETH_BALANCE_DEC + ' ETH') { + const testDapp = new TestDapp(driver); + await testDapp.clickGetEncryptionKeyButton(); + await driver.switchToWindowWithTitle(WINDOW_TITLES.Dialog); + + const getEncryptionKeyConfirmation = new GetEncryptionKeyConfirmation(driver); + await getEncryptionKeyConfirmation.check_pageIsLoaded(); + // Check account balance is converted properly + await getEncryptionKeyConfirmation.check_accountBalance(balanceValue); + + await getEncryptionKeyConfirmation.clickToConfirmProvideEncryptionKey(); + await driver.switchToWindowWithTitle(WINDOW_TITLES.TestDApp); + await testDapp.check_getEncryptionKeyResult(encryptionKey); +} + +/** + * Decrypt message in test dapp and verify the result. + * + * @param driver - The driver instance. + * @param message - The message to decrypt. + * @param balanceValue - The balance value to check, default is DEFAULT_LOCAL_NODE_ETH_BALANCE_DEC. + */ +export async function decryptMessageAndVerifyResult(driver: Driver, message: string, balanceValue: string = DEFAULT_LOCAL_NODE_ETH_BALANCE_DEC + ' ETH') { + console.log('Decrypt message in test dapp and verify the result'); + const testDapp = new TestDapp(driver); + await testDapp.clickDecryptButton(); + await driver.switchToWindowWithTitle(WINDOW_TITLES.Dialog); + const decryptMessageConfirmation = new DecryptMessageConfirmation(driver); + await decryptMessageConfirmation.check_pageIsLoaded(); + + // Check account balance is converted properly + await decryptMessageConfirmation.check_accountBalance(balanceValue); + + // Click decrypt message button and verify the result + await decryptMessageConfirmation.clickDecryptMessageButton(); + await decryptMessageConfirmation.check_decryptedMessage(message); + await decryptMessageConfirmation.clickToConfirmDecryptMessage(); +} diff --git a/test/e2e/page-objects/flows/transaction.ts b/test/e2e/page-objects/flows/transaction.ts index ad6e67b60267..a598c349f210 100644 --- a/test/e2e/page-objects/flows/transaction.ts +++ b/test/e2e/page-objects/flows/transaction.ts @@ -3,7 +3,7 @@ import { DEFAULT_FIXTURE_ACCOUNT } from '../../constants'; import { Driver } from '../../webdriver/driver'; import HomePage from '../pages/home/homepage'; import SendTokenPage from '../pages/send/send-token-page'; -import TestDapp from '../pages/test-dapp'; +import TestDappIndividualRequest from '../pages/test-dapp-individual-request'; export const createInternalTransaction = async (driver: Driver) => { // Firefox has incorrect balance if send flow started too quickly. @@ -44,9 +44,9 @@ export const createDappTransaction = async ( driver: Driver, override?: Partial, ) => { - const testDapp = new TestDapp(driver); + const testDappIndividualRequest = new TestDappIndividualRequest(driver); - await testDapp.request('eth_sendTransaction', [ + await testDappIndividualRequest.request('eth_sendTransaction', [ { data: '0x', from: DEFAULT_FIXTURE_ACCOUNT, diff --git a/test/e2e/page-objects/pages/account-list-page.ts b/test/e2e/page-objects/pages/account-list-page.ts index 13d1b3b01735..a30d88a290ac 100644 --- a/test/e2e/page-objects/pages/account-list-page.ts +++ b/test/e2e/page-objects/pages/account-list-page.ts @@ -145,7 +145,7 @@ class AccountListPage { tag: 'h4', }; - private readonly importSrpInput = '#import-multi-srp__srp-word-0'; + private readonly importSrpInput = '#import-srp__multi-srp__srp-word-0'; private readonly importSrpConfirmButton = { text: 'Import wallet', @@ -335,7 +335,7 @@ class AccountListPage { const srpName = `Secret Recovery Phrase ${srpIndex.toString()}`; // First, we first click here to go to the SRP List. await this.driver.clickElement({ - text: 'Secret Recovery Phrase 1', + text: 'Secret Recovery Phrase 2', }); // Then, we select the SRP that we want to add the account to. await this.driver.clickElement({ @@ -777,6 +777,10 @@ class AccountListPage { } const srps = await this.driver.findElements('.select-srp__container'); const selectedSrp = srps[srpIndex - 1]; + const showAccountsButton = await this.driver.waitForSelector( + `[data-testid="srp-list-show-accounts-${srpIndex - 1}"]`, + ); + await showAccountsButton.click(); await this.driver.findNestedElement(selectedSrp, { text: accountName, diff --git a/test/e2e/page-objects/pages/confirmations/redesign/batch-confirmation.ts b/test/e2e/page-objects/pages/confirmations/redesign/batch-confirmation.ts new file mode 100644 index 000000000000..c8c3f83e525b --- /dev/null +++ b/test/e2e/page-objects/pages/confirmations/redesign/batch-confirmation.ts @@ -0,0 +1,48 @@ +import { Driver } from '../../../../webdriver/driver'; +import TransactionConfirmation from './transaction-confirmation'; + +export default class Eip7702AndSendCalls extends TransactionConfirmation { + constructor(driver: Driver) { + super(driver); + + this.driver = driver; + } + + protected driver: Driver; + + private readonly batchTxList = '[data-testid="batch-txs=]'; + + private readonly confirmUpgradeButton = 'Use smart account'; + + private readonly interactingWith = + '[data-testid="transaction-details-section"]'; + + private readonly txType = '[data-testid="tx-type"]'; + + async check_batchTxListIsPresent(): Promise { + await this.driver.isElementPresent(this.batchTxList); + } + + async check_expectedInteractingWithIsDisplayed( + account: string, + ): Promise { + await this.driver.isElementPresent({ + css: this.interactingWith, + text: account, + }); + } + + async check_expectedTxTypeIsDisplayed(txType: string): Promise { + await this.driver.isElementPresent({ + css: this.txType, + text: txType, + }); + } + + async tickSplashUpgradeButton(): Promise { + await this.driver.clickElement({ + text: this.confirmUpgradeButton, + tag: 'button', + }); + } +} diff --git a/test/e2e/page-objects/pages/confirmations/redesign/decrypt-message-confirmation.ts b/test/e2e/page-objects/pages/confirmations/redesign/decrypt-message-confirmation.ts new file mode 100644 index 000000000000..7e24342e737a --- /dev/null +++ b/test/e2e/page-objects/pages/confirmations/redesign/decrypt-message-confirmation.ts @@ -0,0 +1,78 @@ +import { Driver } from '../../../../webdriver/driver'; + +class DecryptMessageConfirmation { + driver: Driver; + + private readonly accountBalanceValue = '.request-decrypt-message__balance-value'; + + private readonly confirmDecryptMessageButton = { text: 'Decrypt', tag: 'button' }; + + private readonly decryptedMessage = '.request-decrypt-message__message-text'; + + private readonly decryptMessageButton = { text: 'Decrypt message', tag: 'div' }; + + private readonly decryptMessageConfirmationTitle = { + text: 'Decrypt request', + css: '.request-decrypt-message__header__text', + } + + constructor(driver: Driver) { + this.driver = driver; + } + + async check_pageIsLoaded(): Promise { + try { + await this.driver.waitForMultipleSelectors([ + this.decryptMessageConfirmationTitle, + this.decryptMessageButton, + ]); + } catch (e) { + console.log( + `Timeout while waiting for decrypt message confirmation page to be loaded`, + e, + ); + throw e; + } + console.log(`Decrypt message confirmation page is loaded`); + } + + async clickDecryptMessageButton(): Promise { + console.log('Click decrypt message button on decrypt message confirmation page'); + await this.driver.clickElement(this.decryptMessageButton); + } + + async clickToConfirmDecryptMessage(): Promise { + console.log('Click to confirm decrypt message on decrypt message confirmation page'); + await this.driver.clickElement( + this.confirmDecryptMessageButton, + ); + } + + /** + * Check the account balance value in decrypt message confirmation page. + * + * @param balanceValue - The balance value to check. + */ + async check_accountBalance(balanceValue: string): Promise { + console.log('Check account balance on decrypt message confirmation screen: ', balanceValue); + await this.driver.waitForSelector({ + css: this.accountBalanceValue, + text: balanceValue, + }); + } + + /** + * Check the decrypted message on decrypt message confirmation page. + * + * @param message - The decrypted message to check. + */ + async check_decryptedMessage(message: string): Promise { + console.log('Check decrypted message on decrypt message confirmation page'); + await this.driver.waitForSelector({ + css: this.decryptedMessage, + text: message, + }); + } +} + +export default DecryptMessageConfirmation; diff --git a/test/e2e/page-objects/pages/confirmations/redesign/get-encryption-key-confirmation.ts b/test/e2e/page-objects/pages/confirmations/redesign/get-encryption-key-confirmation.ts new file mode 100644 index 000000000000..8453e1b018fd --- /dev/null +++ b/test/e2e/page-objects/pages/confirmations/redesign/get-encryption-key-confirmation.ts @@ -0,0 +1,59 @@ +import { Driver } from '../../../../webdriver/driver'; + +class GetEncryptionKeyConfirmation { + driver: Driver; + + private readonly accountBalanceValue = '.request-encryption-public-key__balance-value'; + + private readonly getEncryptionKeyConfirmationTitle = { + text: 'Request encryption public key', + css: '.request-encryption-public-key__header__text', + } + + private readonly provideEncryptionKeyButton = { + text: 'Provide', + tag: 'button', + }; + + constructor(driver: Driver) { + this.driver = driver; + } + + async check_pageIsLoaded(): Promise { + try { + await this.driver.waitForMultipleSelectors([ + this.getEncryptionKeyConfirmationTitle, + this.provideEncryptionKeyButton, + ]); + } catch (e) { + console.log( + `Timeout while waiting for get encryption key confirmation page to be loaded`, + e, + ); + throw e; + } + console.log(`Get encryption key confirmation page is loaded`); + } + + async clickToConfirmProvideEncryptionKey(): Promise { + console.log('Click to confirm provide encryption key on get encryption key confirmation page'); + await this.driver.clickElementAndWaitForWindowToClose( + this.provideEncryptionKeyButton, + ); + } + + /** + * Check the account balance value in get encryption key confirmation page. + * + * @param balanceValue - The balance value to check. + */ + async check_accountBalance(balanceValue: string): Promise { + console.log('Check account balance on get encryption key confirmation screen: ', balanceValue); + await this.driver.waitForSelector({ + css: this.accountBalanceValue, + text: balanceValue, + }); + } +} + +export default GetEncryptionKeyConfirmation; diff --git a/test/e2e/page-objects/pages/confirmations/redesign/personal-sign-confirmation.ts b/test/e2e/page-objects/pages/confirmations/redesign/personal-sign-confirmation.ts index e2d55a46e1cc..6e74c75c2c32 100644 --- a/test/e2e/page-objects/pages/confirmations/redesign/personal-sign-confirmation.ts +++ b/test/e2e/page-objects/pages/confirmations/redesign/personal-sign-confirmation.ts @@ -14,10 +14,25 @@ export default class PersonalSignConfirmation extends Confirmation { private messageSelector = { text: 'Example `personal_sign` message' }; + private signinConfirmationTitle = { + text: 'Sign-in request', + css: 'h2', + }; + private siweMessage = { text: 'I accept the MetaMask Terms of Service: https://community.metamask.io/tos', }; + private signinMessageTitle = { + text: 'A site wants you to sign in to prove you own this account.', + css: 'p', + }; + + private signinMessageUrl = { + text: 'https://127.0.0.1:8080', + css: 'p', + }; + async verifyOrigin() { const origin = await this.driver.findElement(this.originSelector); assert.ok(origin, 'Origin element is missing or incorrect'); @@ -28,7 +43,13 @@ export default class PersonalSignConfirmation extends Confirmation { assert.ok(await message); } - async verifySiweMessage() { - this.driver.findElement(this.siweMessage); + async check_siweMessage() { + console.log('Verify sign in with ethereum message on confirmation screen'); + await this.driver.waitForMultipleSelectors([ + this.signinConfirmationTitle, + this.signinMessageTitle, + this.siweMessage, + this.signinMessageUrl, + ]); } } diff --git a/test/e2e/page-objects/pages/dialog/snap-install.ts b/test/e2e/page-objects/pages/dialog/snap-install.ts index 15f12ce381f9..358e4647f7e5 100644 --- a/test/e2e/page-objects/pages/dialog/snap-install.ts +++ b/test/e2e/page-objects/pages/dialog/snap-install.ts @@ -27,11 +27,6 @@ class SnapInstall { tag: 'span', }; - private readonly transactionType = { - css: 'p', - text: 'ERC-20', - }; - constructor(driver: Driver) { this.driver = driver; } @@ -111,16 +106,6 @@ class SnapInstall { await this.driver.clickElement(this.connectButton); } - async check_transactionInsightsTitle() { - console.log('Checking transaction insights title'); - await this.driver.waitForSelector(this.insightTitle); - } - - async check_transactionInsightsType() { - console.log('Checking transaction insights type'); - await this.driver.waitForSelector(this.transactionType); - } - async check_messageResultSpan( spanSelectorId: string, expectedMessage: string, diff --git a/test/e2e/page-objects/pages/dialog/snap-txinsight.ts b/test/e2e/page-objects/pages/dialog/snap-txinsight.ts new file mode 100644 index 000000000000..22a04cae6c8a --- /dev/null +++ b/test/e2e/page-objects/pages/dialog/snap-txinsight.ts @@ -0,0 +1,58 @@ +import { Driver } from '../../../webdriver/driver'; +import { veryLargeDelayMs } from '../../../helpers'; + +class SnapTxInsights { + private driver: Driver; + + private readonly insightTitle = { + text: 'Insights Example Snap', + tag: 'span', + }; + + private readonly transactionType = '.snap-ui-renderer__text'; + + private readonly transactionAddress = '[data-testid="snap-ui-address"]'; + + constructor(driver: Driver) { + this.driver = driver; + } + + async check_pageIsLoaded(): Promise { + try { + await this.driver.waitForMultipleSelectors([ + this.insightTitle, + this.transactionAddress, + ]); + } catch (e) { + console.log( + 'Timeout while waiting for Snap txInsight section to be loaded under transaction confirmation dialog', + e, + ); + throw e; + } + console.log('Snap txInsight section is loaded under transaction confirmation dialog'); + } + + async check_transactionInsightsTitle() { + console.log('Checking transaction insights title'); + await this.driver.waitForSelector(this.insightTitle); + } + + async check_transactionInsightsType(transactionType: string) { + console.log('Checking transaction insights type'); + await this.driver.waitForSelector({ + css: this.transactionType, + text: transactionType, + }); + } + + async check_transactionAddress(address: string) { + console.log('Checking transaction address'); + await this.driver.waitForSelector({ + css: this.transactionAddress, + text: address, + }); + } +} + +export default SnapTxInsights; diff --git a/test/e2e/page-objects/pages/home/activity-list.ts b/test/e2e/page-objects/pages/home/activity-list.ts index dddb62a2ac00..e6684bef0d1d 100644 --- a/test/e2e/page-objects/pages/home/activity-list.ts +++ b/test/e2e/page-objects/pages/home/activity-list.ts @@ -279,7 +279,7 @@ class ActivityListPage { } async click_confirmTransactionReplacement() { - await this.driver.clickElement(this.confirmTransactionReplacementButton); + await this.driver.clickElementAndWaitToDisappear(this.confirmTransactionReplacementButton); } async check_waitForTransactionStatus(status: 'confirmed' | 'cancelled') { diff --git a/test/e2e/page-objects/pages/home/asset-list.ts b/test/e2e/page-objects/pages/home/asset-list.ts index f9beafbd6a9e..25179716f52d 100644 --- a/test/e2e/page-objects/pages/home/asset-list.ts +++ b/test/e2e/page-objects/pages/home/asset-list.ts @@ -88,10 +88,17 @@ class AssetListPage { private readonly tokenOptionsButton = '[data-testid="import-token-button"]'; + private tokenImportSelectNetwork(chainId: string): string { + return `[data-testid="select-network-item-${chainId}"]`; + } + private tokenPercentage(address: string): string { return `[data-testid="token-increase-decrease-percentage-${address}"]`; } + private readonly tokenChainDropdown = + '[data-testid="test-import-tokens-drop-down-custom-import"]'; + private readonly tokenSearchInput = 'input[placeholder="Search tokens"]'; private readonly tokenSymbolInput = @@ -205,13 +212,19 @@ class AssetListPage { ); } - async importCustomToken(tokenAddress: string, symbol: string): Promise { + async importCustomTokenByChain( + tokenAddress: string, + symbol: string, + chainId: string, + ): Promise { console.log(`Creating custom token ${symbol} on homepage`); await this.driver.clickElement(this.tokenOptionsButton); await this.driver.clickElement(this.importTokensButton); await this.driver.waitForSelector(this.importTokenModalTitle); await this.driver.clickElement(this.customTokenModalOption); await this.driver.waitForSelector(this.modalWarningBanner); + await this.driver.clickElement(this.tokenChainDropdown); + await this.driver.clickElement(this.tokenImportSelectNetwork(chainId)); await this.driver.fill(this.tokenAddressInput, tokenAddress); await this.driver.fill(this.tokenSymbolInput, symbol); await this.driver.clickElement(this.importTokensNextButton); diff --git a/test/e2e/page-objects/pages/home/homepage.ts b/test/e2e/page-objects/pages/home/homepage.ts index bd833f6bc287..c4e32a3be7c6 100644 --- a/test/e2e/page-objects/pages/home/homepage.ts +++ b/test/e2e/page-objects/pages/home/homepage.ts @@ -306,6 +306,14 @@ class HomePage { } await this.check_expectedBalanceIsDisplayed(expectedBalance); } + + async check_newSrpAddedToastIsDisplayed( + srpNumber: number = 2, + ): Promise { + await this.driver.waitForSelector({ + text: `Secret Recovery Phrase ${srpNumber} imported`, + }); + } } export default HomePage; diff --git a/test/e2e/page-objects/pages/home/nft-list.ts b/test/e2e/page-objects/pages/home/nft-list.ts index cbfb151447db..e7948021da16 100644 --- a/test/e2e/page-objects/pages/home/nft-list.ts +++ b/test/e2e/page-objects/pages/home/nft-list.ts @@ -26,6 +26,11 @@ class NftListPage { tag: 'h6', }; + private readonly successRemoveNftMessage = { + text: 'NFT was successfully removed!', + tag: 'h6', + }; + constructor(driver: Driver) { this.driver = driver; } @@ -94,6 +99,13 @@ class NftListPage { ); await this.driver.waitForSelector(this.successImportNftMessage); } + + async check_successRemoveNftMessageIsDisplayed(): Promise { + console.log( + 'Check that success removed NFT message is displayed on homepage', + ); + await this.driver.waitForSelector(this.successRemoveNftMessage); + } } export default NftListPage; diff --git a/test/e2e/page-objects/pages/nft-details-page.ts b/test/e2e/page-objects/pages/nft-details-page.ts index 2671248085bc..05510a7bc6ce 100644 --- a/test/e2e/page-objects/pages/nft-details-page.ts +++ b/test/e2e/page-objects/pages/nft-details-page.ts @@ -3,29 +3,27 @@ import { Driver } from '../../webdriver/driver'; class NFTDetailsPage { private driver: Driver; - private readonly nftSendButton = '[data-testid="nft-send-button"]'; + private readonly nftBackButton = '[data-testid="nft__back"]'; - private readonly nftItemButtom = '[data-testid="nft-item"]'; + private readonly nftDetailsAddress = '.nft-details__addressButton'; - private readonly nftOptionsButton = '[data-testid="nft-options__button"]'; + private readonly nftDetailsDescription = + '[data-testid="nft-details__description"]'; - private readonly nftBackButton = '[data-testid="nft__back"]'; + private readonly nftDetailsName = '[data-testid="nft-details__name"]'; - constructor(driver: Driver) { - this.driver = driver; - } + private readonly nftImageContainer = '.nft-item__container'; - async clickNFTSendButton() { - await this.driver.clickElement(this.nftSendButton); - } + private readonly nftOptionsButton = '[data-testid="nft-options__button"]'; - async clickNFTItemButton() { - await this.driver.clickElement(this.nftItemButtom); - } + private readonly nftRemoveButton = '[data-testid="nft-item-remove__button"]'; - async check_nftFullImageIsDisplayed() { - console.log('Check if NFT full image is displayed on NFT details page'); - await this.driver.waitForSelector('[data-testid="nft-item"]'); + private readonly nftSendButton = '[data-testid="nft-send-button"]'; + + private readonly nftItemButtom = '[data-testid="nft-item"]'; + + constructor(driver: Driver) { + this.driver = driver; } async check_pageIsLoaded(): Promise { @@ -41,6 +39,62 @@ class NFTDetailsPage { } console.log('NFT details page is loaded'); } + + async clickNFTSendButton() { + await this.driver.clickElement(this.nftSendButton); + } + + async clickNFTItemButton() { + await this.driver.clickElement(this.nftItemButtom); + } + + async removeNFT() { + console.log('Click to remove NFT on NFT details page'); + await this.driver.clickElement(this.nftOptionsButton); + await this.driver.clickElement(this.nftRemoveButton); + } + + async check_nftDescriptionIsDisplayed(description: string) { + console.log( + 'Check if NFT description is displayed on NFT details page', + description, + ); + await this.driver.waitForSelector({ + css: this.nftDetailsDescription, + text: description, + }); + } + + async check_nftDetailsAddressIsDisplayed(address: string) { + console.log( + 'Check if NFT address is displayed on NFT details page', + address, + ); + await this.driver.waitForSelector({ + css: this.nftDetailsAddress, + text: address, + }); + } + + async check_nftImageContainerIsDisplayed() { + console.log( + 'Check if NFT image container is displayed on NFT details page', + ); + await this.driver.waitForSelector(this.nftImageContainer); + } + + async check_nftNameIsDisplayed(name: string) { + console.log('Check if NFT name is displayed on NFT details page', name); + await this.driver.waitForSelector({ + css: this.nftDetailsName, + text: name, + }); + } + + async check_nftFullImageIsDisplayed() { + console.log('Check if NFT full image is displayed on NFT details page'); + await this.driver.waitForSelector('[data-testid="nft-item"]'); + } } export default NFTDetailsPage; diff --git a/test/e2e/page-objects/pages/permission/permission-list-page.ts b/test/e2e/page-objects/pages/permission/permission-list-page.ts index 10f214fd8da6..52788522f17b 100644 --- a/test/e2e/page-objects/pages/permission/permission-list-page.ts +++ b/test/e2e/page-objects/pages/permission/permission-list-page.ts @@ -7,6 +7,8 @@ import { Driver } from '../../../webdriver/driver'; class PermissionListPage { private driver: Driver; + private readonly connectionListItem = '[data-testid="connection-list-item"]'; + private readonly permissionsPage = '[data-testid="permissions-page"]'; constructor(driver: Driver) { @@ -45,6 +47,26 @@ class PermissionListPage { console.log('Check if account is connected to site', site); await this.driver.waitForSelector({ text: site, tag: 'p' }); } + + /** + * Check the number of connected sites + * + * @param expectedNumberOfConnectedSites - The expected number of connected sites, default to 1 + */ + async check_numberOfConnectedSites( + expectedNumberOfConnectedSites: number = 1, + ): Promise { + console.log( + `Verify the number of connected sites is: ${expectedNumberOfConnectedSites}`, + ); + await this.driver.waitForSelector(this.connectionListItem); + await this.driver.wait(async () => { + const connectedSites = await this.driver.findElements( + this.connectionListItem, + ); + return connectedSites.length === expectedNumberOfConnectedSites; + }); + } } export default PermissionListPage; diff --git a/test/e2e/page-objects/pages/swap/swap-page.ts b/test/e2e/page-objects/pages/swap/swap-page.ts index 4937d7082f76..88f3fc4ea4c1 100644 --- a/test/e2e/page-objects/pages/swap/swap-page.ts +++ b/test/e2e/page-objects/pages/swap/swap-page.ts @@ -19,6 +19,8 @@ class SwapPage { text: 'Close', }; + private readonly transactionHeader = '[data-testid="awaiting-swap-header"]'; + constructor(driver: Driver) { this.driver = driver; } @@ -54,11 +56,34 @@ class SwapPage { }); } + async swapProcessingMessageCheck(message: string): Promise { + await this.driver.wait(async () => { + const confirmedTxs = await this.driver.findElements({ + css: this.transactionHeader, + text: message, + }); + return confirmedTxs.length === 1; + }, 10000); + } + async submitSwap(): Promise { console.log('Submit Swap'); await this.driver.clickElement(this.swapButton); + await this.driver.delay(1500); + // console.log('Processing Swap'); + // await this.swapProcessingMessageCheck('Processing'); + console.log('Swap Transaction complete'); + await this.swapProcessingMessageCheck('Transaction complete'); await this.driver.clickElement(this.closeButton); } + + async dismissManualTokenWarning(): Promise { + console.log('Dismiss manual token warning'); + await this.driver.clickElement({ + text: 'Continue swapping', + tag: 'button', + }); + } } export default SwapPage; diff --git a/test/e2e/page-objects/pages/test-dapp-individual-request.ts b/test/e2e/page-objects/pages/test-dapp-individual-request.ts new file mode 100644 index 000000000000..4fc064fb074a --- /dev/null +++ b/test/e2e/page-objects/pages/test-dapp-individual-request.ts @@ -0,0 +1,57 @@ +import { Driver } from '../../webdriver/driver'; +import { DAPP_URL } from '../../constants' + +class TestDappIndividualRequest { + private readonly driver: Driver; + + private readonly result = 'main'; + + constructor(driver: Driver) { + this.driver = driver; + } + + /** + * Verify the result of the request. + * + * @param expectedResult - The expected result from the individual request. + */ + async checkExpectedResult(expectedResult: string) { + console.log('Verify the result from the individual request.'); + await this.driver.waitForSelector({ + tag: this.result, + text: expectedResult, + }); + } + + /** + * Open the test dapp individual request page. + * + * @param options - The options for opening the test dapp page. + * @param options.contractAddress - The contract address to open the dapp with. Defaults to null. + * @param options.url - The URL of the dapp. Defaults to DAPP_URL. + * @returns A promise that resolves when the new page is opened. + */ + async openTestDappIndividualPage({ + contractAddress = null, + url = DAPP_URL, + }: { + contractAddress?: string | null; + url?: string; + } = {}): Promise { + const dappUrl = contractAddress + ? `${url}/?contract=${contractAddress}` + : url; + await this.driver.openNewPage(dappUrl); + } + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + async request(method: string, params: any[]) { + await this.openTestDappIndividualPage({ + url: `${DAPP_URL}/request?method=${method}¶ms=${JSON.stringify( + params, + )}`, + }); + } +} + +export default TestDappIndividualRequest; diff --git a/test/e2e/page-objects/pages/test-dapp-multichain.ts b/test/e2e/page-objects/pages/test-dapp-multichain.ts index ce02bd63aa91..9d327fc2743e 100644 --- a/test/e2e/page-objects/pages/test-dapp-multichain.ts +++ b/test/e2e/page-objects/pages/test-dapp-multichain.ts @@ -1,4 +1,4 @@ -import { NormalizedScopeObject } from '@metamask/multichain'; +import { NormalizedScopeObject } from '@metamask/chain-agnostic-permission'; import { largeDelayMs, WINDOW_TITLES } from '../../helpers'; import { Driver } from '../../webdriver/driver'; diff --git a/test/e2e/page-objects/pages/test-dapp.ts b/test/e2e/page-objects/pages/test-dapp.ts index 4676000e5d73..4ea3b89fdd8b 100644 --- a/test/e2e/page-objects/pages/test-dapp.ts +++ b/test/e2e/page-objects/pages/test-dapp.ts @@ -1,10 +1,8 @@ import { strict as assert } from 'assert'; +import { DAPP_URL } from '../../constants' import { WINDOW_TITLES } from '../../helpers'; import { Driver } from '../../webdriver/driver'; -const DAPP_HOST_ADDRESS = '127.0.0.1:8080'; -const DAPP_URL = `http://${DAPP_HOST_ADDRESS}`; - class TestDapp { private readonly driver: Driver; @@ -44,10 +42,20 @@ class TestDapp { private readonly createTokenButton = { text: 'Create Token', tag: 'button' }; + private readonly decryptButton = '#decryptButton'; + + private readonly decryptedMessage = '#cleartextDisplay'; + private readonly depositPiggyBankContractButton = '#depositButton'; private readonly eip747ContractAddressInput = '#eip747ContractAddress'; + private readonly encryptButton = '#encryptButton'; + + private readonly encryptedMessage = '#ciphertextDisplay'; + + private readonly encryptMessageInput = '#encryptMessageInput'; + private readonly erc1155MintButton = '#batchMintButton'; private readonly erc1155RevokeSetApprovalForAllButton = @@ -76,6 +84,20 @@ class TestDapp { private readonly erc721TransferFromButton = '#transferFromButton'; + private readonly ethSubscribeResponse = '[data-testid="eth-subscribe-response"]'; + + private readonly getAccountsButton = '#getAccounts'; + + private readonly getAccountsResult = '#getAccountsResult'; + + private readonly getEncryptionKeyButton = '#getEncryptionKeyButton'; + + private readonly getEncryptionKeyResult = '#encryptionKeyDisplay'; + + private readonly getPermissionsButton = '#getPermissions'; + + private readonly getPermissionsResult = '#permissionsResult'; + private readonly localhostNetworkMessage = { css: '#chainId', text: '0x539' }; private readonly mmlogo = '#mm-logo'; @@ -95,6 +117,8 @@ class TestDapp { private readonly sign721PermitButton = '#sign721Permit'; + private readonly sendCallsButton = '#eip5792SendCallsButton'; + private sign721PermitResult = '#sign721PermitResult'; private sign721PermitResultR = '#sign721PermitResultR'; @@ -211,6 +235,41 @@ class TestDapp { } } + /** + * Verify the decrypted message on test dapp. + * + * @param message - The decrypted message to verify. + */ + async check_decryptedMessage(message: string) { + console.log('Verify decrypted message on test dapp'); + await this.driver.waitForSelector({ + css: this.decryptedMessage, + text: message, + }); + } + + /** + * Verifies the eth_subscribe response. + * + * @param shouldBePresent - Whether the eth_subscribe response should be present, defaults to true. + * @param guardTime - Time to wait to check if the eth_subscribe response is present, defaults to 1000ms. + */ + async check_ethSubscribeResponse( + shouldBePresent: boolean = true, + guardTime: number = 1000, + ) { + if (shouldBePresent) { + console.log('Verify eth_subscribe response is displayed'); + await this.driver.waitForSelector(this.ethSubscribeResponse); + } else { + console.log('Verify eth_subscribe response is not displayed'); + await this.driver.assertElementNotPresent( + this.ethSubscribeResponse, + { waitAtLeastGuard: guardTime }, + ); + } + } + /** * Verify the failed personal sign signature. * @@ -281,6 +340,51 @@ class TestDapp { }); } + /** + * Verify get connected accounts result. + * + * @param expectedResult - The expected account address. + */ + async check_getAccountsResult(expectedResult: string) { + console.log( + 'Verify get connected accounts result contains:', + expectedResult, + ); + await this.driver.clickElement(this.getAccountsButton); + await this.driver.waitForSelector({ + css: this.getAccountsResult, + text: expectedResult, + }); + } + + /** + * Verify the get encryption key result. + * + * @param encryptionKey - The encryption key to display. + */ + async check_getEncryptionKeyResult(encryptionKey: string) { + console.log('Verify get encryption key result on test dapp: ', encryptionKey); + await this.driver.waitForSelector({ + css: this.getEncryptionKeyResult, + text: encryptionKey, + }); + } + + /** + * Verify get permissions result. + * + * @param expectedPermission - The expected displayed permission. + */ + async check_getPermissionsResult(expectedPermission: string) { + console.log('Verify get permissions result contains:', expectedPermission); + await this.driver.waitForElementToStopMoving(this.getPermissionsButton); + await this.driver.clickElement(this.getPermissionsButton); + await this.driver.waitForSelector({ + css: this.getPermissionsResult, + text: expectedPermission, + }); + } + async check_pageIsLoaded(): Promise { try { await this.driver.waitForSelector(this.mmlogo); @@ -517,6 +621,10 @@ class TestDapp { await this.driver.clickElement(this.approveTokensButton); } + async clickDecryptButton() { + await this.driver.clickElement(this.decryptButton); + } + async clickApproveTokensWithoutGas() { await this.driver.clickElement(this.approveTokensButtonWithoutGas); } @@ -565,6 +673,10 @@ class TestDapp { await this.driver.clickElement(this.erc721TransferFromButton); } + async clickGetEncryptionKeyButton() { + await this.driver.clickElement(this.getEncryptionKeyButton); + } + async clickPermit() { await this.driver.clickElement(this.signPermitButton); } @@ -573,6 +685,10 @@ class TestDapp { await this.driver.clickElement(this.personalSignButton); } + async clickSendCalls() { + await this.driver.clickElement(this.sendCallsButton); + } + async clickSignTypedData() { await this.driver.clickElement(this.signTypedDataButton); } @@ -687,6 +803,21 @@ class TestDapp { await this.check_connectedAccounts(publicAddress, false); } + /** + * Encrypt a message on test dapp. + * + * @param message - The message to encrypt. + */ + async encryptMessage(message: string) { + console.log(`Encrypt message ${message} in test dapp`); + await this.driver.fill(this.encryptMessageInput, message); + await this.driver.clickElement(this.encryptButton); + await this.driver.waitForSelector({ + css: this.encryptedMessage, + text: '0x', + }); + } + async fillERC1155TokenAmount(amount: string) { await this.driver.pasteIntoField(this.erc1155TokenAmountInput, amount); } @@ -821,15 +952,6 @@ class TestDapp { this.confirmSignatureButtonRedesign, ); } - - // eslint-disable-next-line @typescript-eslint/no-explicit-any - async request(method: string, params: any[]) { - await this.openTestDappPage({ - url: `${DAPP_URL}/request?method=${method}¶ms=${JSON.stringify( - params, - )}`, - }); - } } export default TestDapp; diff --git a/test/e2e/run-api-specs-multichain.ts b/test/e2e/run-api-specs-multichain.ts index 21bad51b54dc..2f5d883d9fa5 100644 --- a/test/e2e/run-api-specs-multichain.ts +++ b/test/e2e/run-api-specs-multichain.ts @@ -10,7 +10,7 @@ import { MethodObject, OpenrpcDocument } from '@open-rpc/meta-schema'; import JsonSchemaFakerRule from '@open-rpc/test-coverage/build/rules/json-schema-faker-rule'; import ExamplesRule from '@open-rpc/test-coverage/build/rules/examples-rule'; import { Call, IOptions } from '@open-rpc/test-coverage/build/coverage'; -import { InternalScopeString } from '@metamask/multichain'; +import { InternalScopeString } from '@metamask/chain-agnostic-permission'; import { Mockttp } from 'mockttp'; import { Driver, PAGES } from './webdriver/driver'; @@ -151,9 +151,11 @@ async function main() { skip: [], only: ['wallet_getSession', 'wallet_revokeSession'], }), - new MultichainAuthorizationConfirmation({ - driver, - }), + // Temporarily disabled as the wallet/wallet:eip155 behavior is broken + // but this shouldn't block Solana integration + // new MultichainAuthorizationConfirmation({ + // driver, + // }), new MultichainAuthorizationConfirmationErrors({ driver, }), diff --git a/test/e2e/seeder/anvil.ts b/test/e2e/seeder/anvil.ts index 38f283d179f1..6074a3ea5f5b 100644 --- a/test/e2e/seeder/anvil.ts +++ b/test/e2e/seeder/anvil.ts @@ -22,6 +22,8 @@ type Hardfork = | 'Shanghai' | 'Latest'; +type Hex = `0x${string}`; + const defaultOptions = { balance: 25, chainId: 1337, @@ -102,7 +104,7 @@ export class Anvil { return accounts; } - async getBalance(address: `0x${string}` | null = null): Promise { + async getBalance(address: Hex | null = null): Promise { const provider = this.getProvider(); if (!provider) { @@ -119,7 +121,7 @@ export class Anvil { } const balance = await publicClient.getBalance({ - address: accountToUse as `0x${string}`, + address: accountToUse as Hex, }); const balanceFormatted = Number(balance) / 10 ** 18; @@ -128,6 +130,21 @@ export class Anvil { return balanceRounded; } + async getCode(address: Hex): Promise { + const provider = this.getProvider(); + + if (!provider) { + console.log('No provider found'); + return; + } + const { publicClient } = provider; + + const bytecode = await publicClient.getCode({ + address, + }); + return bytecode; + } + async getFiatBalance(): Promise { const balance = await this.getBalance(); const currencyConversionRate = 1700.0; @@ -137,7 +154,7 @@ export class Anvil { } async setAccountBalance( - address: `0x${string}`, + address: Hex, balance: string, ): Promise { const provider = this.getProvider(); diff --git a/test/e2e/seeder/ganache-seeder.js b/test/e2e/seeder/ganache-seeder.js index ebec4d5a8dcd..92679d582e51 100644 --- a/test/e2e/seeder/ganache-seeder.js +++ b/test/e2e/seeder/ganache-seeder.js @@ -1,7 +1,7 @@ const { Web3Provider } = require('@ethersproject/providers'); const { ContractFactory, Contract } = require('@ethersproject/contracts'); -const { ENTRYPOINT, GANACHE_ACCOUNT } = require('../constants'); +const { ENTRYPOINT, LOCAL_NODE_ACCOUNT } = require('../constants'); const { SMART_CONTRACTS, contractConfiguration } = require('./smart-contracts'); const ContractAddressRegistry = require('./contract-address-registry'); @@ -42,7 +42,7 @@ class GanacheSeeder { } else if (contractName === SMART_CONTRACTS.SIMPLE_ACCOUNT_FACTORY) { contract = await contractFactory.deploy(ENTRYPOINT); } else if (contractName === SMART_CONTRACTS.VERIFYING_PAYMASTER) { - contract = await contractFactory.deploy(ENTRYPOINT, GANACHE_ACCOUNT); + contract = await contractFactory.deploy(ENTRYPOINT, LOCAL_NODE_ACCOUNT); } else { contract = await contractFactory.deploy(); } diff --git a/test/e2e/seeder/ganache.ts b/test/e2e/seeder/ganache.ts index 957d07fc65bd..20f4385a8172 100644 --- a/test/e2e/seeder/ganache.ts +++ b/test/e2e/seeder/ganache.ts @@ -1,6 +1,6 @@ import { Server, server } from 'ganache'; import { BigNumber } from 'bignumber.js'; -import { DEFAULT_GANACHE_ETH_BALANCE_DEC } from '../constants'; +import { DEFAULT_LOCAL_NODE_ETH_BALANCE_DEC } from '../constants'; const PRIVATE_KEY = '0x7C9529A67102755B7E6102D6D950AC5D5863C98713805CEC576B945B15B71EAC'; @@ -38,7 +38,7 @@ export class Ganache { { secretKey: PRIVATE_KEY, balance: convertETHToHexGwei( - Number(DEFAULT_GANACHE_ETH_BALANCE_DEC), + Number(DEFAULT_LOCAL_NODE_ETH_BALANCE_DEC), ), }, ], diff --git a/test/e2e/seeder/network-states/eip7702-state/withDelegatorContracts.json b/test/e2e/seeder/network-states/eip7702-state/withDelegatorContracts.json new file mode 100644 index 000000000000..5370652be73f --- /dev/null +++ b/test/e2e/seeder/network-states/eip7702-state/withDelegatorContracts.json @@ -0,0 +1,680 @@ +{ + "accounts": { + "0x0000000000000000000000000000000000000000": { + "nonce": 0, + "balance": "0xea8131", + "code": "0x", + "storage": {} + }, + "0x14dc79964da2c08b23698b3d3cc7ca32193d9955": { + "nonce": 0, + "balance": "0x21e19e0c9bab2400000", + "code": "0x", + "storage": {} + }, + "0x15d34aaf54267db7d7c367839aaf71a00a2c6a65": { + "nonce": 0, + "balance": "0x21e19e0c9bab2400000", + "code": "0x", + "storage": {} + }, + "0x23618e81e3f5cdf7f54c3d65f7fbc0abf5b21e8f": { + "nonce": 0, + "balance": "0x21e19e0c9bab2400000", + "code": "0x", + "storage": {} + }, + "0x2e983a1ba5e8b38aaaec4b440b9ddcfbf72e15d1": { + "nonce": 2, + "balance": "0x0", + "code": "0x60806040526004361061010c5760003560e01c806370a0823111610095578063b760faf911610064578063b760faf9146103b5578063bb9fe6bf146103d1578063c23a5cea146103e8578063dbed18e014610411578063fc7e286d1461043a5761011c565b806370a08231146102fd578063765e827f1461033a578063850aaf62146103635780639b249f691461038c5761011c565b80631b2e01b8116100dc5780631b2e01b8146101e0578063205c28781461021d57806322cdde4c1461024657806335567e1a146102835780635287ce12146102c05761011c565b806242dc531461012157806301ffc9a71461015e5780630396cb601461019b5780630bd28e3b146101b75761011c565b3661011c5761011a3361047b565b005b600080fd5b34801561012d57600080fd5b5061014860048036038101906101439190613db0565b6104db565b6040516101559190613e51565b60405180910390f35b34801561016a57600080fd5b5061018560048036038101906101809190613ec4565b6106c1565b6040516101929190613f0c565b60405180910390f35b6101b560048036038101906101b09190613f63565b6108b7565b005b3480156101c357600080fd5b506101de60048036038101906101d99190613fe0565b610c13565b005b3480156101ec57600080fd5b506102076004803603810190610202919061400d565b610cb0565b6040516102149190613e51565b60405180910390f35b34801561022957600080fd5b50610244600480360381019061023f919061408b565b610cd5565b005b34801561025257600080fd5b5061026d600480360381019061026891906140f0565b610e78565b60405161027a9190614148565b60405180910390f35b34801561028f57600080fd5b506102aa60048036038101906102a5919061400d565b610eb4565b6040516102b79190613e51565b60405180910390f35b3480156102cc57600080fd5b506102e760048036038101906102e29190614163565b610f63565b6040516102f4919061426f565b60405180910390f35b34801561030957600080fd5b50610324600480360381019061031f9190614163565b611076565b6040516103319190613e51565b60405180910390f35b34801561034657600080fd5b50610361600480360381019061035c91906142e0565b6110c1565b005b34801561036f57600080fd5b5061038a60048036038101906103859190614340565b611255565b005b34801561039857600080fd5b506103b360048036038101906103ae91906143a0565b611303565b005b6103cf60048036038101906103ca9190614163565b61047b565b005b3480156103dd57600080fd5b506103e66113c9565b005b3480156103f457600080fd5b5061040f600480360381019061040a91906143ed565b611579565b005b34801561041d57600080fd5b5061043860048036038101906104339190614470565b611879565b005b34801561044657600080fd5b50610461600480360381019061045c9190614163565b611d90565b6040516104729594939291906144fd565b60405180910390f35b60006104878234611e0f565b90508173ffffffffffffffffffffffffffffffffffffffff167f2da466a7b24304f47e87fa2e1e5a81b9831ce54fec19055ce277ca2f39ba42c4826040516104cf9190613e51565b60405180910390a25050565b6000805a90503073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161461054f576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610546906145ad565b60405180910390fd5b6000856000015190506000816060015190506127108260a001518201016040603f5a02816105805761057f6145cd565b5b0410156105b1577fdeaddead0000000000000000000000000000000000000000000000000000000060005260206000fd5b600080895111156106555760006105cf846000015160008c86611e7a565b9050806106535760006105e3610800611e93565b905060008151111561064d57846000015173ffffffffffffffffffffffffffffffffffffffff168a602001517f1c4fada7374c0a9ee8841fc38afe82932dc0f8e69012e927f061a8bae611a20187602001518460405161064492919061467b565b60405180910390a35b60019250505b505b600088608001515a86030190506106b2828a8a8a8080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f8201169050808301925050505050505084611ec3565b95505050505050949350505050565b60007f3e84f021000000000000000000000000000000000000000000000000000000007fcf28ef97000000000000000000000000000000000000000000000000000000007f915074d80000000000000000000000000000000000000000000000000000000018187bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614806107d057507f915074d8000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b8061083857507fcf28ef97000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b806108a057507f3e84f021000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b806108b057506108af82612164565b5b9050919050565b60008060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020905060008263ffffffff1611610942576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610939906146f7565b60405180910390fd5b80600101600f9054906101000a900463ffffffff1663ffffffff168263ffffffff1610156109a5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161099c90614763565b60405180910390fd5b6000348260010160019054906101000a90046dffffffffffffffffffffffffffff166dffffffffffffffffffffffffffff166109e191906147b2565b905060008111610a26576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610a1d90614832565b60405180910390fd5b6dffffffffffffffffffffffffffff8016811115610a79576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610a709061489e565b60405180910390fd5b6040518060a0016040528083600001548152602001600115158152602001826dffffffffffffffffffffffffffff1681526020018463ffffffff168152602001600065ffffffffffff168152506000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000820151816000015560208201518160010160006101000a81548160ff02191690831515021790555060408201518160010160016101000a8154816dffffffffffffffffffffffffffff02191690836dffffffffffffffffffffffffffff160217905550606082015181600101600f6101000a81548163ffffffff021916908363ffffffff16021790555060808201518160010160136101000a81548165ffffffffffff021916908365ffffffffffff1602179055509050503373ffffffffffffffffffffffffffffffffffffffff167fa5ae833d0bb1dcd632d98a8b70973e8516812898e19bf27b70071ebc8dc52c018285604051610c069291906148f9565b60405180910390a2505050565b600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008277ffffffffffffffffffffffffffffffffffffffffffffffff1677ffffffffffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000815480929190610ca890614922565b919050555050565b6001602052816000526040600020602052806000526040600020600091509150505481565b60008060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002090508060000154821115610d5e576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610d55906149b6565b60405180910390fd5b818160000154610d6e91906149d6565b81600001819055503373ffffffffffffffffffffffffffffffffffffffff167fd1c19fbcd4551a5edfb66d43d2e337c04837afda3482b42bdf569a8fccdae5fb8484604051610dbe929190614a5f565b60405180910390a260008373ffffffffffffffffffffffffffffffffffffffff1683604051610dec90614ab9565b60006040518083038185875af1925050503d8060008114610e29576040519150601f19603f3d011682016040523d82523d6000602084013e610e2e565b606091505b5050905080610e72576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610e6990614b1a565b60405180910390fd5b50505050565b6000610e83826121ce565b3046604051602001610e9793929190614b49565b604051602081830303815290604052805190602001209050919050565b600060408277ffffffffffffffffffffffffffffffffffffffffffffffff16901b600160008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008477ffffffffffffffffffffffffffffffffffffffffffffffff1677ffffffffffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205417905092915050565b610f6b613853565b6000808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206040518060a0016040529081600082015481526020016001820160009054906101000a900460ff161515151581526020016001820160019054906101000a90046dffffffffffffffffffffffffffff166dffffffffffffffffffffffffffff166dffffffffffffffffffffffffffff16815260200160018201600f9054906101000a900463ffffffff1663ffffffff1663ffffffff1681526020016001820160139054906101000a900465ffffffffffff1665ffffffffffff1665ffffffffffff16815250509050919050565b60008060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600001549050919050565b6110c96121e7565b600083839050905060008167ffffffffffffffff8111156110ed576110ec6139cf565b5b60405190808252806020026020018201604052801561112657816020015b6111136138a2565b81526020019060019003908161110b5790505b50905060005b828110156111a657600082828151811061114957611148614b80565b5b60200260200101519050600080611185848a8a8781811061116d5761116c614b80565b5b905060200281019061117f9190614bbe565b8561222b565b915091506111968483836000612421565b505050808060010191505061112c565b5060007fbb47ee3e183a558b1a2ff0874b079f3fc5478b7454eacf2bfc5af2ff5878f97260405160405180910390a160005b8381101561123a57611229818888848181106111f7576111f6614b80565b5b90506020028101906112099190614bbe565b85848151811061121c5761121b614b80565b5b60200260200101516125b4565b8201915080806001019150506111d8565b506112458482612955565b505050611250612a75565b505050565b6000808473ffffffffffffffffffffffffffffffffffffffff16848460405161127f929190614c0c565b600060405180830381855af49150503d80600081146112ba576040519150601f19603f3d011682016040523d82523d6000602084013e6112bf565b606091505b509150915081816040517f994105540000000000000000000000000000000000000000000000000000000081526004016112fa929190614c25565b60405180910390fd5b600061130d612a7f565b73ffffffffffffffffffffffffffffffffffffffff1663570e1a3684846040518363ffffffff1660e01b8152600401611347929190614c82565b6020604051808303816000875af1158015611366573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061138a9190614cbb565b9050806040517f6ca7b8060000000000000000000000000000000000000000000000000000000081526004016113c09190614ce8565b60405180910390fd5b60008060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000209050600081600101600f9054906101000a900463ffffffff1663ffffffff1603611468576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161145f90614d4f565b60405180910390fd5b8060010160009054906101000a900460ff166114b9576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016114b090614dbb565b60405180910390fd5b600081600101600f9054906101000a900463ffffffff1663ffffffff16426114e19190614ddb565b9050808260010160136101000a81548165ffffffffffff021916908365ffffffffffff16021790555060008260010160006101000a81548160ff0219169083151502179055503373ffffffffffffffffffffffffffffffffffffffff167ffa9b3c14cc825c412c9ed81b3ba365a5b459439403f18829e572ed53a4180f0a8260405161156d9190614e46565b60405180910390a25050565b60008060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020905060008160010160019054906101000a90046dffffffffffffffffffffffffffff166dffffffffffffffffffffffffffff16905060008111611631576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161162890614ead565b60405180910390fd5b60008260010160139054906101000a900465ffffffffffff1665ffffffffffff1611611692576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161168990614f19565b60405180910390fd5b428260010160139054906101000a900465ffffffffffff1665ffffffffffff1611156116f3576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016116ea90614f85565b60405180910390fd5b600082600101600f6101000a81548163ffffffff021916908363ffffffff16021790555060008260010160136101000a81548165ffffffffffff021916908365ffffffffffff16021790555060008260010160016101000a8154816dffffffffffffffffffffffffffff02191690836dffffffffffffffffffffffffffff1602179055503373ffffffffffffffffffffffffffffffffffffffff167fb7c918e0e249f999e965cafeb6c664271b3f4317d296461500e71da39f0cbda384836040516117bf929190614a5f565b60405180910390a260008373ffffffffffffffffffffffffffffffffffffffff16826040516117ed90614ab9565b60006040518083038185875af1925050503d806000811461182a576040519150601f19603f3d011682016040523d82523d6000602084013e61182f565b606091505b5050905080611873576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161186a90614ff1565b60405180910390fd5b50505050565b6118816121e7565b60008383905090506000805b82811015611a6857368686838181106118a9576118a8614b80565b5b90506020028101906118bb9190615011565b90503660008280600001906118d09190615039565b9150915060008360200160208101906118e991906150da565b9050600173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff160361195a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161195190615153565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614611a46578073ffffffffffffffffffffffffffffffffffffffff16632dd8113384848780604001906119bc9190615173565b6040518563ffffffff1660e01b81526004016119db94939291906154ec565b60006040518083038186803b1580156119f357600080fd5b505afa925050508015611a04575060015b611a4557806040517f86a9f750000000000000000000000000000000000000000000000000000000008152600401611a3c9190614ce8565b60405180910390fd5b5b8282905086611a5591906147b2565b955050505050808060010191505061188d565b5060008167ffffffffffffffff811115611a8557611a846139cf565b5b604051908082528060200260200182016040528015611abe57816020015b611aab6138a2565b815260200190600190039081611aa35790505b5090506000805b84811015611bc85736888883818110611ae157611ae0614b80565b5b9050602002810190611af39190615011565b9050366000828060000190611b089190615039565b915091506000836020016020810190611b2191906150da565b9050600083839050905060005b81811015611bb5576000898981518110611b4b57611b4a614b80565b5b60200260200101519050600080611b878b898987818110611b6f57611b6e614b80565b5b9050602002810190611b819190614bbe565b8561222b565b91509150611b9784838389612421565b8a80611ba290614922565b9b50505050508080600101915050611b2e565b5050505050508080600101915050611ac5565b507fbb47ee3e183a558b1a2ff0874b079f3fc5478b7454eacf2bfc5af2ff5878f97260405160405180910390a1600080915060005b85811015611d2f5736898983818110611c1957611c18614b80565b5b9050602002810190611c2b9190615011565b9050806020016020810190611c4091906150da565b73ffffffffffffffffffffffffffffffffffffffff167f575ff3acadd5ab348fe1855e217e0f3678f8d767d7494c9f9fefbee2e17cca4d60405160405180910390a2366000828060000190611c959190615039565b91509150600082829050905060005b81811015611d1d57611cf588858584818110611cc357611cc2614b80565b5b9050602002810190611cd59190614bbe565b8b8b81518110611ce857611ce7614b80565b5b60200260200101516125b4565b87611d0091906147b2565b96508780611d0d90614922565b9850508080600101915050611ca4565b50505050508080600101915050611bfd565b50600073ffffffffffffffffffffffffffffffffffffffff167f575ff3acadd5ab348fe1855e217e0f3678f8d767d7494c9f9fefbee2e17cca4d60405160405180910390a2611d7e8682612955565b5050505050611d8b612a75565b505050565b60006020528060005260406000206000915090508060000154908060010160009054906101000a900460ff16908060010160019054906101000a90046dffffffffffffffffffffffffffff169080600101600f9054906101000a900463ffffffff16908060010160139054906101000a900465ffffffffffff16905085565b6000806000808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002090506000838260000154611e6491906147b2565b9050808260000181905550809250505092915050565b6000806000845160208601878987f19050949350505050565b60603d82811115611ea2578290505b604051602082018101604052818152816000602083013e8092505050919050565b6000805a9050600080866000015190506000611ede82612aa7565b905060008260e001519050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603611f295782600001519350612029565b809350600088511115612028578187029550600280811115611f4e57611f4d615527565b5b8a6002811115611f6157611f60615527565b5b14612027578073ffffffffffffffffffffffffffffffffffffffff16637c627b218460a001518c8b8a876040518663ffffffff1660e01b8152600401611faa949392919061559e565b600060405180830381600088803b158015611fc457600080fd5b5087f193505050508015611fd6575060015b612026576000611fe7610800611e93565b9050806040517fad7954bc00000000000000000000000000000000000000000000000000000000815260040161201d91906155ea565b60405180910390fd5b5b5b5b5a85038701965060008360a00151846060015101905060008a60800151890390508082111561207a576000818303905060006064600a83028161206f5761206e6145cd565b5b049050808b019a5050505b505081870295506000896040015190508681101561210a576002808111156120a5576120a4615527565b5b8b60028111156120b8576120b7615527565b5b036120db578096506120c98a612ae3565b6120d68a6000898b612b49565b612105565b7fdeadaa510000000000000000000000000000000000000000000000000000000060005260206000fd5b612156565b6000878203905061211b8682611e0f565b50600080600281111561213157612130615527565b5b8d600281111561214457612143615527565b5b1490506121538c828b8d612b49565b50505b505050505050949350505050565b60007f01ffc9a7000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916149050919050565b60006121d982612bd7565b805190602001209050919050565b6002805403612222576040517f3ee5aeb500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60028081905550565b60008060005a90506000846000015190506122468682612c9b565b61224f86610e78565b85602001818152505060008160400151905060008261012001518361010001518460a0015185608001518660600151868860c0015117171717171790506effffffffffffffffffffffffffffff80168111156122e0576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016122d790615658565b60405180910390fd5b60006122eb84612e57565b90506122fa8a8a8a8487612e89565b965061230e846000015185602001516130c6565b61234f57896040517f220266b600000000000000000000000000000000000000000000000000000000815260040161234691906156c4565b60405180910390fd5b825a8603111561239657896040517f220266b600000000000000000000000000000000000000000000000000000000815260040161238d919061573e565b60405180910390fd5b6060600073ffffffffffffffffffffffffffffffffffffffff168560e0015173ffffffffffffffffffffffffffffffffffffffff16146123e5576123dc8b8b8b85613184565b80985081925050505b818960400181815250506123f881613371565b8960600181815250508960a001355a870301896080018181525050505050505050935093915050565b60008061242d8561337b565b915091508173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16146124a157856040517f220266b600000000000000000000000000000000000000000000000000000000815260040161249891906157b8565b60405180910390fd5b80156124e457856040517f220266b60000000000000000000000000000000000000000000000000000000081526004016124db9190615832565b60405180910390fd5b60006124ef8561337b565b8093508192505050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161461256857866040517f220266b600000000000000000000000000000000000000000000000000000000815260040161255f91906158ac565b60405180910390fd5b81156125ab57866040517f220266b60000000000000000000000000000000000000000000000000000000081526004016125a2919061594c565b60405180910390fd5b50505050505050565b6000805a905060006125c984606001516133d4565b905060008060405190503660008880606001906125e69190615173565b91509150606060008260038111156125fd57843591505b50638dd7712f60e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916817bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916036127245760008b8b60200151604051602401612663929190615aa4565b604051602081830303815290604052638dd7712f60e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff838183161783525050505090503073ffffffffffffffffffffffffffffffffffffffff166242dc53828d8b6040516024016126da93929190615c0d565b604051602081830303815290604052915060e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff838183161783525050505092505061279b565b3073ffffffffffffffffffffffffffffffffffffffff166242dc5385858d8b6040516024016127569493929190615c54565b604051602081830303815290604052915060e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff838183161783525050505091505b602060008351602085016000305af1955060005198508460405250505050508061294b5760003d806020036127d65760206000803e60005191505b507fdeaddead00000000000000000000000000000000000000000000000000000000810361283b57876040517f220266b60000000000000000000000000000000000000000000000000000000081526004016128329190615ce9565b60405180910390fd5b7fdeadaa510000000000000000000000000000000000000000000000000000000081036128aa57600086608001515a8661287591906149d6565b61287f91906147b2565b905060008760400151905061289388612ae3565b6128a08860008385612b49565b8096505050612949565b85600001516000015173ffffffffffffffffffffffffffffffffffffffff1686602001517ff62676f440ff169a3a9afdbf812e89e7f95975ee8e5c31214ffdef631c5f4792886000015160200151612903610800611e93565b60405161291192919061467b565b60405180910390a3600086608001515a8661292c91906149d6565b61293691906147b2565b90506129456002888684611ec3565b9550505b505b5050509392505050565b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16036129c4576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016129bb90615d63565b60405180910390fd5b60008273ffffffffffffffffffffffffffffffffffffffff16826040516129ea90614ab9565b60006040518083038185875af1925050503d8060008114612a27576040519150601f19603f3d011682016040523d82523d6000602084013e612a2c565b606091505b5050905080612a70576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612a6790615dcf565b60405180910390fd5b505050565b6001600281905550565b60007f000000000000000000000000dd8a726a079a85effe3183ecfbe0de8ac36b1e65905090565b600080826101000151905060008361012001519050808203612acd578192505050612ade565b612ad9824883016133de565b925050505b919050565b80600001516000015173ffffffffffffffffffffffffffffffffffffffff1681602001517f67b4fa9642f42120bf031f3051d1824b0fe25627945b27b8a6a65d5761d5482e836000015160200151604051612b3e9190613e51565b60405180910390a350565b836000015160e0015173ffffffffffffffffffffffffffffffffffffffff1684600001516000015173ffffffffffffffffffffffffffffffffffffffff1685602001517f49628fd1471006c1482da88028e9ce4dbb080b815c9b0344d39e5a8e6ec1419f876000015160200151878787604051612bc99493929190615def565b60405180910390a450505050565b60606000612be4836133f7565b90506000836020013590506000612c09858060400190612c049190615173565b613407565b90506000612c25868060600190612c209190615173565b613407565b905060008660800135905060008760a00135905060008860c0013590506000612c5c8a8060e00190612c579190615173565b613407565b90508787878787878787604051602001612c7d989796959493929190615e34565b60405160208183030381529060405298505050505050505050919050565b816000016020810190612cae9190614163565b816000019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250508160200135816020018181525050612d00826080013561341e565b8260400183606001828152508281525050508160a001358160c0018181525050612d2d8260c0013561341e565b8261012001836101000182815250828152505050366000838060e00190612d549190615173565b915091506000828290501115612e01576034828290501015612dab576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612da290615efe565b60405180910390fd5b612db5828261345c565b8560e001866080018760a00183815250838152508373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815250505050612e51565b60008360e0019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff1681525050600083608001818152505060008360a00181815250505b50505050565b6000808260c001518360a001518460800151856060015186604001510101010190508261010001518102915050919050565b60008084600001519050600081600001519050612eb68887898060400190612eb19190615173565b6134fe565b60008260e00151905060008073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603612f17576000612eff84611076565b9050878111612f1057808803612f13565b60005b9150505b8273ffffffffffffffffffffffffffffffffffffffff166319822f7c878b8b60200151856040518563ffffffff1660e01b8152600401612f5993929190615f1e565b60206040518083038160008887f193505050508015612f9657506040513d601f19601f82011682018060405250810190612f939190615f71565b60015b612fe35789612fa6610800611e93565b6040517f65c8fd4d000000000000000000000000000000000000000000000000000000008152600401612fda929190615fea565b60405180910390fd5b80955050600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16036130b95760008060008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000209050600081600001549050808911156130ab578b6040517f220266b60000000000000000000000000000000000000000000000000000000081526004016130a29190616079565b60405180910390fd5b888103826000018190555050505b5050505095945050505050565b600080604083901c905060008390508067ffffffffffffffff16600160008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008477ffffffffffffffffffffffffffffffffffffffffffffffff1677ffffffffffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600081548092919061317590614922565b91905055149250505092915050565b60606000805a905060008560000151905060008160e00151905060008060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002090506000816000015490508781101561322e578a6040517f220266b600000000000000000000000000000000000000000000000000000000815260040161322591906160f3565b60405180910390fd5b87810382600001819055506000846080015190508373ffffffffffffffffffffffffffffffffffffffff166352b7512c828d8d602001518d6040518563ffffffff1660e01b815260040161328493929190615f1e565b60006040518083038160008887f1935050505080156132c657506040513d6000823e3d601f19601f820116820180604052508101906132c39190616191565b60015b613313578b6132d6610800611e93565b6040517f65c8fd4d00000000000000000000000000000000000000000000000000000000815260040161330a929190616239565b60405180910390fd5b8199508098505050805a87031115613362578b6040517f220266b600000000000000000000000000000000000000000000000000000000815260040161335991906162ee565b60405180910390fd5b50505050505094509492505050565b6000819050919050565b6000806000830361339257600080915091506133cf565b600061339d846137cf565b9050806040015165ffffffffffff164211806133c45750806020015165ffffffffffff1642105b915080600001519250505b915091565b6060819050919050565b60008183106133ed57816133ef565b825b905092915050565b6000808235905080915050919050565b600060405182808583378082209250505092915050565b6000808260801c8360001c816fffffffffffffffffffffffffffffffff169150806fffffffffffffffffffffffffffffffff16905091509150915091565b6000806000848460009060149261347593929190616326565b9061348091906163a5565b60601c858560149060249261349793929190616326565b906134a29190616430565b60801c86866024906034926134b993929190616326565b906134c49190616430565b60801c816fffffffffffffffffffffffffffffffff169150806fffffffffffffffffffffffffffffffff1690509250925092509250925092565b600082829050146137c9576000836000015160000151905060008173ffffffffffffffffffffffffffffffffffffffff163b1461357257846040517f220266b600000000000000000000000000000000000000000000000000000000815260040161356991906164db565b60405180910390fd5b600061357c612a7f565b73ffffffffffffffffffffffffffffffffffffffff1663570e1a3686600001516040015186866040518463ffffffff1660e01b81526004016135bf929190614c82565b60206040518083038160008887f11580156135de573d6000803e3d6000fd5b50505050506040513d601f19601f820116820180604052508101906136039190614cbb565b9050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff160361367657856040517f220266b600000000000000000000000000000000000000000000000000000000815260040161366d9190616555565b60405180910390fd5b8173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16146136e657856040517f220266b60000000000000000000000000000000000000000000000000000000081526004016136dd91906165cf565b60405180910390fd5b60008173ffffffffffffffffffffffffffffffffffffffff163b0361374257856040517f220266b60000000000000000000000000000000000000000000000000000000081526004016137399190616649565b60405180910390fd5b6000848460009060149261375893929190616326565b9061376391906163a5565b60601c90508273ffffffffffffffffffffffffffffffffffffffff1686602001517fd51a9c61267aa6196961883ecf5ff2da6619c37dac0fa92122513fb32c032d2d83896000015160e001516040516137bd929190616677565b60405180910390a35050505b50505050565b6137d76138da565b6000829050600060a084901c905060008165ffffffffffff16036137ff5765ffffffffffff90505b600060d085901c905060405180606001604052808473ffffffffffffffffffffffffffffffffffffffff1681526020018265ffffffffffff1681526020018365ffffffffffff168152509350505050919050565b6040518060a001604052806000815260200160001515815260200160006dffffffffffffffffffffffffffff168152602001600063ffffffff168152602001600065ffffffffffff1681525090565b6040518060a001604052806138b5613921565b8152602001600080191681526020016000815260200160008152602001600081525090565b6040518060600160405280600073ffffffffffffffffffffffffffffffffffffffff168152602001600065ffffffffffff168152602001600065ffffffffffff1681525090565b604051806101400160405280600073ffffffffffffffffffffffffffffffffffffffff168152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600073ffffffffffffffffffffffffffffffffffffffff16815260200160008152602001600081525090565b6000604051905090565b600080fd5b600080fd5b600080fd5b600080fd5b6000601f19601f8301169050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b613a07826139be565b810181811067ffffffffffffffff82111715613a2657613a256139cf565b5b80604052505050565b6000613a396139a0565b9050613a4582826139fe565b919050565b600067ffffffffffffffff821115613a6557613a646139cf565b5b613a6e826139be565b9050602081019050919050565b82818337600083830152505050565b6000613a9d613a9884613a4a565b613a2f565b905082815260208101848484011115613ab957613ab86139b9565b5b613ac4848285613a7b565b509392505050565b600082601f830112613ae157613ae06139b4565b5b8135613af1848260208601613a8a565b91505092915050565b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000613b2a82613aff565b9050919050565b613b3a81613b1f565b8114613b4557600080fd5b50565b600081359050613b5781613b31565b92915050565b6000819050919050565b613b7081613b5d565b8114613b7b57600080fd5b50565b600081359050613b8d81613b67565b92915050565b60006101408284031215613baa57613ba9613afa565b5b613bb5610140613a2f565b90506000613bc584828501613b48565b6000830152506020613bd984828501613b7e565b6020830152506040613bed84828501613b7e565b6040830152506060613c0184828501613b7e565b6060830152506080613c1584828501613b7e565b60808301525060a0613c2984828501613b7e565b60a08301525060c0613c3d84828501613b7e565b60c08301525060e0613c5184828501613b48565b60e083015250610100613c6684828501613b7e565b61010083015250610120613c7c84828501613b7e565b6101208301525092915050565b6000819050919050565b613c9c81613c89565b8114613ca757600080fd5b50565b600081359050613cb981613c93565b92915050565b60006101c08284031215613cd657613cd5613afa565b5b613ce060a0613a2f565b90506000613cf084828501613b93565b600083015250610140613d0584828501613caa565b602083015250610160613d1a84828501613b7e565b604083015250610180613d2f84828501613b7e565b6060830152506101a0613d4484828501613b7e565b60808301525092915050565b600080fd5b600080fd5b60008083601f840112613d7057613d6f6139b4565b5b8235905067ffffffffffffffff811115613d8d57613d8c613d50565b5b602083019150836001820283011115613da957613da8613d55565b5b9250929050565b6000806000806102008587031215613dcb57613dca6139aa565b5b600085013567ffffffffffffffff811115613de957613de86139af565b5b613df587828801613acc565b9450506020613e0687828801613cbf565b9350506101e085013567ffffffffffffffff811115613e2857613e276139af565b5b613e3487828801613d5a565b925092505092959194509250565b613e4b81613b5d565b82525050565b6000602082019050613e666000830184613e42565b92915050565b60007fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b613ea181613e6c565b8114613eac57600080fd5b50565b600081359050613ebe81613e98565b92915050565b600060208284031215613eda57613ed96139aa565b5b6000613ee884828501613eaf565b91505092915050565b60008115159050919050565b613f0681613ef1565b82525050565b6000602082019050613f216000830184613efd565b92915050565b600063ffffffff82169050919050565b613f4081613f27565b8114613f4b57600080fd5b50565b600081359050613f5d81613f37565b92915050565b600060208284031215613f7957613f786139aa565b5b6000613f8784828501613f4e565b91505092915050565b600077ffffffffffffffffffffffffffffffffffffffffffffffff82169050919050565b613fbd81613f90565b8114613fc857600080fd5b50565b600081359050613fda81613fb4565b92915050565b600060208284031215613ff657613ff56139aa565b5b600061400484828501613fcb565b91505092915050565b60008060408385031215614024576140236139aa565b5b600061403285828601613b48565b925050602061404385828601613fcb565b9150509250929050565b600061405882613aff565b9050919050565b6140688161404d565b811461407357600080fd5b50565b6000813590506140858161405f565b92915050565b600080604083850312156140a2576140a16139aa565b5b60006140b085828601614076565b92505060206140c185828601613b7e565b9150509250929050565b600080fd5b600061012082840312156140e7576140e66140cb565b5b81905092915050565b600060208284031215614106576141056139aa565b5b600082013567ffffffffffffffff811115614124576141236139af565b5b614130848285016140d0565b91505092915050565b61414281613c89565b82525050565b600060208201905061415d6000830184614139565b92915050565b600060208284031215614179576141786139aa565b5b600061418784828501613b48565b91505092915050565b61419981613b5d565b82525050565b6141a881613ef1565b82525050565b60006dffffffffffffffffffffffffffff82169050919050565b6141d1816141ae565b82525050565b6141e081613f27565b82525050565b600065ffffffffffff82169050919050565b614201816141e6565b82525050565b60a08201600082015161421d6000850182614190565b506020820151614230602085018261419f565b50604082015161424360408501826141c8565b50606082015161425660608501826141d7565b50608082015161426960808501826141f8565b50505050565b600060a0820190506142846000830184614207565b92915050565b60008083601f8401126142a05761429f6139b4565b5b8235905067ffffffffffffffff8111156142bd576142bc613d50565b5b6020830191508360208202830111156142d9576142d8613d55565b5b9250929050565b6000806000604084860312156142f9576142f86139aa565b5b600084013567ffffffffffffffff811115614317576143166139af565b5b6143238682870161428a565b9350935050602061433686828701614076565b9150509250925092565b600080600060408486031215614359576143586139aa565b5b600061436786828701613b48565b935050602084013567ffffffffffffffff811115614388576143876139af565b5b61439486828701613d5a565b92509250509250925092565b600080602083850312156143b7576143b66139aa565b5b600083013567ffffffffffffffff8111156143d5576143d46139af565b5b6143e185828601613d5a565b92509250509250929050565b600060208284031215614403576144026139aa565b5b600061441184828501614076565b91505092915050565b60008083601f8401126144305761442f6139b4565b5b8235905067ffffffffffffffff81111561444d5761444c613d50565b5b60208301915083602082028301111561446957614468613d55565b5b9250929050565b600080600060408486031215614489576144886139aa565b5b600084013567ffffffffffffffff8111156144a7576144a66139af565b5b6144b38682870161441a565b935093505060206144c686828701614076565b9150509250925092565b6144d9816141ae565b82525050565b6144e881613f27565b82525050565b6144f7816141e6565b82525050565b600060a0820190506145126000830188613e42565b61451f6020830187613efd565b61452c60408301866144d0565b61453960608301856144df565b61454660808301846144ee565b9695505050505050565b600082825260208201905092915050565b7f4141393220696e7465726e616c2063616c6c206f6e6c79000000000000000000600082015250565b6000614597601783614550565b91506145a282614561565b602082019050919050565b600060208201905081810360008301526145c68161458a565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b600081519050919050565b600082825260208201905092915050565b60005b8381101561463657808201518184015260208101905061461b565b60008484015250505050565b600061464d826145fc565b6146578185614607565b9350614667818560208601614618565b614670816139be565b840191505092915050565b60006040820190506146906000830185613e42565b81810360208301526146a28184614642565b90509392505050565b7f6d757374207370656369667920756e7374616b652064656c6179000000000000600082015250565b60006146e1601a83614550565b91506146ec826146ab565b602082019050919050565b60006020820190508181036000830152614710816146d4565b9050919050565b7f63616e6e6f7420646563726561736520756e7374616b652074696d6500000000600082015250565b600061474d601c83614550565b915061475882614717565b602082019050919050565b6000602082019050818103600083015261477c81614740565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60006147bd82613b5d565b91506147c883613b5d565b92508282019050808211156147e0576147df614783565b5b92915050565b7f6e6f207374616b65207370656369666965640000000000000000000000000000600082015250565b600061481c601283614550565b9150614827826147e6565b602082019050919050565b6000602082019050818103600083015261484b8161480f565b9050919050565b7f7374616b65206f766572666c6f77000000000000000000000000000000000000600082015250565b6000614888600e83614550565b915061489382614852565b602082019050919050565b600060208201905081810360008301526148b78161487b565b9050919050565b6000819050919050565b60006148e36148de6148d984613f27565b6148be565b613b5d565b9050919050565b6148f3816148c8565b82525050565b600060408201905061490e6000830185613e42565b61491b60208301846148ea565b9392505050565b600061492d82613b5d565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361495f5761495e614783565b5b600182019050919050565b7f576974686472617720616d6f756e7420746f6f206c6172676500000000000000600082015250565b60006149a0601983614550565b91506149ab8261496a565b602082019050919050565b600060208201905081810360008301526149cf81614993565b9050919050565b60006149e182613b5d565b91506149ec83613b5d565b9250828203905081811115614a0457614a03614783565b5b92915050565b6000614a25614a20614a1b84613aff565b6148be565b613aff565b9050919050565b6000614a3782614a0a565b9050919050565b6000614a4982614a2c565b9050919050565b614a5981614a3e565b82525050565b6000604082019050614a746000830185614a50565b614a816020830184613e42565b9392505050565b600081905092915050565b50565b6000614aa3600083614a88565b9150614aae82614a93565b600082019050919050565b6000614ac482614a96565b9150819050919050565b7f6661696c656420746f2077697468647261770000000000000000000000000000600082015250565b6000614b04601283614550565b9150614b0f82614ace565b602082019050919050565b60006020820190508181036000830152614b3381614af7565b9050919050565b614b4381613b1f565b82525050565b6000606082019050614b5e6000830186614139565b614b6b6020830185614b3a565b614b786040830184613e42565b949350505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600080fd5b600080fd5b600080fd5b60008235600161012003833603038112614bdb57614bda614baf565b5b80830191505092915050565b6000614bf38385614a88565b9350614c00838584613a7b565b82840190509392505050565b6000614c19828486614be7565b91508190509392505050565b6000604082019050614c3a6000830185613efd565b8181036020830152614c4c8184614642565b90509392505050565b6000614c618385614607565b9350614c6e838584613a7b565b614c77836139be565b840190509392505050565b60006020820190508181036000830152614c9d818486614c55565b90509392505050565b600081519050614cb581613b31565b92915050565b600060208284031215614cd157614cd06139aa565b5b6000614cdf84828501614ca6565b91505092915050565b6000602082019050614cfd6000830184614b3a565b92915050565b7f6e6f74207374616b656400000000000000000000000000000000000000000000600082015250565b6000614d39600a83614550565b9150614d4482614d03565b602082019050919050565b60006020820190508181036000830152614d6881614d2c565b9050919050565b7f616c726561647920756e7374616b696e67000000000000000000000000000000600082015250565b6000614da5601183614550565b9150614db082614d6f565b602082019050919050565b60006020820190508181036000830152614dd481614d98565b9050919050565b6000614de6826141e6565b9150614df1836141e6565b9250828201905065ffffffffffff811115614e0f57614e0e614783565b5b92915050565b6000614e30614e2b614e26846141e6565b6148be565b613b5d565b9050919050565b614e4081614e15565b82525050565b6000602082019050614e5b6000830184614e37565b92915050565b7f4e6f207374616b6520746f207769746864726177000000000000000000000000600082015250565b6000614e97601483614550565b9150614ea282614e61565b602082019050919050565b60006020820190508181036000830152614ec681614e8a565b9050919050565b7f6d7573742063616c6c20756e6c6f636b5374616b652829206669727374000000600082015250565b6000614f03601d83614550565b9150614f0e82614ecd565b602082019050919050565b60006020820190508181036000830152614f3281614ef6565b9050919050565b7f5374616b65207769746864726177616c206973206e6f74206475650000000000600082015250565b6000614f6f601b83614550565b9150614f7a82614f39565b602082019050919050565b60006020820190508181036000830152614f9e81614f62565b9050919050565b7f6661696c656420746f207769746864726177207374616b650000000000000000600082015250565b6000614fdb601883614550565b9150614fe682614fa5565b602082019050919050565b6000602082019050818103600083015261500a81614fce565b9050919050565b60008235600160600383360303811261502d5761502c614baf565b5b80830191505092915050565b6000808335600160200384360303811261505657615055614baf565b5b80840192508235915067ffffffffffffffff82111561507857615077614bb4565b5b60208301925060208202360383131561509457615093614bb9565b5b509250929050565b60006150a782613b1f565b9050919050565b6150b78161509c565b81146150c257600080fd5b50565b6000813590506150d4816150ae565b92915050565b6000602082840312156150f0576150ef6139aa565b5b60006150fe848285016150c5565b91505092915050565b7f4141393620696e76616c69642061676772656761746f72000000000000000000600082015250565b600061513d601783614550565b915061514882615107565b602082019050919050565b6000602082019050818103600083015261516c81615130565b9050919050565b600080833560016020038436030381126151905761518f614baf565b5b80840192508235915067ffffffffffffffff8211156151b2576151b1614bb4565b5b6020830192506001820236038313156151ce576151cd614bb9565b5b509250929050565b600082825260208201905092915050565b6000819050919050565b60006152006020840184613b48565b905092915050565b61521181613b1f565b82525050565b60006152266020840184613b7e565b905092915050565b600080fd5b600080fd5b600080fd5b6000808335600160200384360303811261525a57615259615238565b5b83810192508235915060208301925067ffffffffffffffff8211156152825761528161522e565b5b60018202360383131561529857615297615233565b5b509250929050565b600082825260208201905092915050565b60006152bd83856152a0565b93506152ca838584613a7b565b6152d3836139be565b840190509392505050565b60006152ed6020840184613caa565b905092915050565b6152fe81613c89565b82525050565b6000610120830161531860008401846151f1565b6153256000860182615208565b506153336020840184615217565b6153406020860182614190565b5061534e604084018461523d565b85830360408701526153618382846152b1565b92505050615372606084018461523d565b85830360608701526153858382846152b1565b9250505061539660808401846152de565b6153a360808601826152f5565b506153b160a0840184615217565b6153be60a0860182614190565b506153cc60c08401846152de565b6153d960c08601826152f5565b506153e760e084018461523d565b85830360e08701526153fa8382846152b1565b9250505061540c61010084018461523d565b8583036101008701526154208382846152b1565b925050508091505092915050565b600061543a8383615304565b905092915050565b6000823560016101200383360303811261545f5761545e615238565b5b82810191505092915050565b6000602082019050919050565b600061548483856151d6565b935083602084028501615496846151e7565b8060005b878110156154da5784840389526154b18284615442565b6154bb858261542e565b94506154c68361546b565b925060208a0199505060018101905061549a565b50829750879450505050509392505050565b60006040820190508181036000830152615507818688615478565b9050818103602083015261551c818486614c55565b905095945050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b6003811061556757615566615527565b5b50565b600081905061557882615556565b919050565b60006155888261556a565b9050919050565b6155988161557d565b82525050565b60006080820190506155b3600083018761558f565b81810360208301526155c58186614642565b90506155d46040830185613e42565b6155e16060830184613e42565b95945050505050565b600060208201905081810360008301526156048184614642565b905092915050565b7f41413934206761732076616c756573206f766572666c6f770000000000000000600082015250565b6000615642601883614550565b915061564d8261560c565b602082019050919050565b6000602082019050818103600083015261567181615635565b9050919050565b7f4141323520696e76616c6964206163636f756e74206e6f6e6365000000000000600082015250565b60006156ae601a83614550565b91506156b982615678565b602082019050919050565b60006040820190506156d96000830184613e42565b81810360208301526156ea816156a1565b905092915050565b7f41413236206f76657220766572696669636174696f6e4761734c696d69740000600082015250565b6000615728601e83614550565b9150615733826156f2565b602082019050919050565b60006040820190506157536000830184613e42565b81810360208301526157648161571b565b905092915050565b7f41413234207369676e6174757265206572726f72000000000000000000000000600082015250565b60006157a2601483614550565b91506157ad8261576c565b602082019050919050565b60006040820190506157cd6000830184613e42565b81810360208301526157de81615795565b905092915050565b7f414132322065787069726564206f72206e6f7420647565000000000000000000600082015250565b600061581c601783614550565b9150615827826157e6565b602082019050919050565b60006040820190506158476000830184613e42565b81810360208301526158588161580f565b905092915050565b7f41413334207369676e6174757265206572726f72000000000000000000000000600082015250565b6000615896601483614550565b91506158a182615860565b602082019050919050565b60006040820190506158c16000830184613e42565b81810360208301526158d281615889565b905092915050565b7f41413332207061796d61737465722065787069726564206f72206e6f7420647560008201527f6500000000000000000000000000000000000000000000000000000000000000602082015250565b6000615936602183614550565b9150615941826158da565b604082019050919050565b60006040820190506159616000830184613e42565b818103602083015261597281615929565b905092915050565b6000610120830161598e60008401846151f1565b61599b6000860182615208565b506159a96020840184615217565b6159b66020860182614190565b506159c4604084018461523d565b85830360408701526159d78382846152b1565b925050506159e8606084018461523d565b85830360608701526159fb8382846152b1565b92505050615a0c60808401846152de565b615a1960808601826152f5565b50615a2760a0840184615217565b615a3460a0860182614190565b50615a4260c08401846152de565b615a4f60c08601826152f5565b50615a5d60e084018461523d565b85830360e0870152615a708382846152b1565b92505050615a8261010084018461523d565b858303610100870152615a968382846152b1565b925050508091505092915050565b60006040820190508181036000830152615abe818561597a565b9050615acd6020830184614139565b9392505050565b61014082016000820151615aeb6000850182615208565b506020820151615afe6020850182614190565b506040820151615b116040850182614190565b506060820151615b246060850182614190565b506080820151615b376080850182614190565b5060a0820151615b4a60a0850182614190565b5060c0820151615b5d60c0850182614190565b5060e0820151615b7060e0850182615208565b50610100820151615b85610100850182614190565b50610120820151615b9a610120850182614190565b50505050565b6101c082016000820151615bb76000850182615ad4565b506020820151615bcb6101408501826152f5565b506040820151615bdf610160850182614190565b506060820151615bf3610180850182614190565b506080820151615c076101a0850182614190565b50505050565b6000610200820190508181036000830152615c288186614642565b9050615c376020830185615ba0565b8181036101e0830152615c4a8184614642565b9050949350505050565b6000610200820190508181036000830152615c70818688614c55565b9050615c7f6020830185615ba0565b8181036101e0830152615c928184614642565b905095945050505050565b7f41413935206f7574206f66206761730000000000000000000000000000000000600082015250565b6000615cd3600f83614550565b9150615cde82615c9d565b602082019050919050565b6000604082019050615cfe6000830184613e42565b8181036020830152615d0f81615cc6565b905092915050565b7f4141393020696e76616c69642062656e65666963696172790000000000000000600082015250565b6000615d4d601883614550565b9150615d5882615d17565b602082019050919050565b60006020820190508181036000830152615d7c81615d40565b9050919050565b7f41413931206661696c65642073656e6420746f2062656e656669636961727900600082015250565b6000615db9601f83614550565b9150615dc482615d83565b602082019050919050565b60006020820190508181036000830152615de881615dac565b9050919050565b6000608082019050615e046000830187613e42565b615e116020830186613efd565b615e1e6040830185613e42565b615e2b6060830184613e42565b95945050505050565b600061010082019050615e4a600083018b614b3a565b615e57602083018a613e42565b615e646040830189614139565b615e716060830188614139565b615e7e6080830187614139565b615e8b60a0830186613e42565b615e9860c0830185614139565b615ea560e0830184614139565b9998505050505050505050565b7f4141393320696e76616c6964207061796d6173746572416e6444617461000000600082015250565b6000615ee8601d83614550565b9150615ef382615eb2565b602082019050919050565b60006020820190508181036000830152615f1781615edb565b9050919050565b60006060820190508181036000830152615f38818661597a565b9050615f476020830185614139565b615f546040830184613e42565b949350505050565b600081519050615f6b81613b67565b92915050565b600060208284031215615f8757615f866139aa565b5b6000615f9584828501615f5c565b91505092915050565b7f4141323320726576657274656400000000000000000000000000000000000000600082015250565b6000615fd4600d83614550565b9150615fdf82615f9e565b602082019050919050565b6000606082019050615fff6000830185613e42565b818103602083015261601081615fc7565b905081810360408301526160248184614642565b90509392505050565b7f41413231206469646e2774207061792070726566756e64000000000000000000600082015250565b6000616063601783614550565b915061606e8261602d565b602082019050919050565b600060408201905061608e6000830184613e42565b818103602083015261609f81616056565b905092915050565b7f41413331207061796d6173746572206465706f73697420746f6f206c6f770000600082015250565b60006160dd601e83614550565b91506160e8826160a7565b602082019050919050565b60006040820190506161086000830184613e42565b8181036020830152616119816160d0565b905092915050565b600061613461612f84613a4a565b613a2f565b9050828152602081018484840111156161505761614f6139b9565b5b61615b848285614618565b509392505050565b600082601f830112616178576161776139b4565b5b8151616188848260208601616121565b91505092915050565b600080604083850312156161a8576161a76139aa565b5b600083015167ffffffffffffffff8111156161c6576161c56139af565b5b6161d285828601616163565b92505060206161e385828601615f5c565b9150509250929050565b7f4141333320726576657274656400000000000000000000000000000000000000600082015250565b6000616223600d83614550565b915061622e826161ed565b602082019050919050565b600060608201905061624e6000830185613e42565b818103602083015261625f81616216565b905081810360408301526162738184614642565b90509392505050565b7f41413336206f766572207061796d6173746572566572696669636174696f6e4760008201527f61734c696d697400000000000000000000000000000000000000000000000000602082015250565b60006162d8602783614550565b91506162e38261627c565b604082019050919050565b60006040820190506163036000830184613e42565b8181036020830152616314816162cb565b905092915050565b600080fd5b600080fd5b6000808585111561633a5761633961631c565b5b8386111561634b5761634a616321565b5b6001850283019150848603905094509492505050565b600082905092915050565b60007fffffffffffffffffffffffffffffffffffffffff00000000000000000000000082169050919050565b600082821b905092915050565b60006163b18383616361565b826163bc813561636c565b925060148210156163fc576163f77fffffffffffffffffffffffffffffffffffffffff00000000000000000000000083601403600802616398565b831692505b505092915050565b60007fffffffffffffffffffffffffffffffff0000000000000000000000000000000082169050919050565b600061643c8383616361565b826164478135616404565b92506010821015616487576164827fffffffffffffffffffffffffffffffff0000000000000000000000000000000083601003600802616398565b831692505b505092915050565b7f414131302073656e64657220616c726561647920636f6e737472756374656400600082015250565b60006164c5601f83614550565b91506164d08261648f565b602082019050919050565b60006040820190506164f06000830184613e42565b8181036020830152616501816164b8565b905092915050565b7f4141313320696e6974436f6465206661696c6564206f72204f4f470000000000600082015250565b600061653f601b83614550565b915061654a82616509565b602082019050919050565b600060408201905061656a6000830184613e42565b818103602083015261657b81616532565b905092915050565b7f4141313420696e6974436f6465206d7573742072657475726e2073656e646572600082015250565b60006165b9602083614550565b91506165c482616583565b602082019050919050565b60006040820190506165e46000830184613e42565b81810360208301526165f5816165ac565b905092915050565b7f4141313520696e6974436f6465206d757374206372656174652073656e646572600082015250565b6000616633602083614550565b915061663e826165fd565b602082019050919050565b600060408201905061665e6000830184613e42565b818103602083015261666f81616626565b905092915050565b600060408201905061668c6000830185614b3a565b6166996020830184614b3a565b939250505056fea2646970667358221220f6e7d5acc3b3ce47e8c4e79583caee84134eab4d0c55f3973f51a15d53351cdb64736f6c63430008170033", + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000002": "0x0000000000000000000000000000000000000000000000000000000000000001" + } + }, + "0x3c44cdddb6a900fa2b585dd299e03d12fa4293bc": { + "nonce": 4, + "balance": "0x21e19afb5cca6f85381", + "code": "0x", + "storage": {} + }, + "0x4e59b44847b379578588920ca78fbf26c0b4956c": { + "nonce": 0, + "balance": "0x0", + "code": "0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe03601600081602082378035828234f58015156039578182fd5b8082525050506014600cf3", + "storage": {} + }, + "0x663f3ad617193148711d28f5334ee4ed07016602": { + "nonce": 1, + "balance": "0x0", + "code": "0x608060405234801561001057600080fd5b506004361061012c5760003560e01c806383ebb771116100ad578063acb8cc4911610071578063acb8cc49146102c9578063cef6d209146102e7578063e30c397814610303578063f2fde38b14610321578063ffa1ad741461033d5761012c565b806383ebb771146102415780638456cb591461025f57806384b0196e146102695780638da5cb5b1461028d578063a3f4df7e146102ab5761012c565b806358909ebc116100f457806358909ebc146101c15780635c975abb146101df57806366134607146101fd578063715018a61461022d57806379ba5097146102375761012c565b80631b13cac2146101315780632d40d0521461014f5780633ed010151461017f5780633f4ba83a1461019b57806349934047146101a5575b600080fd5b61013961035b565b6040516101469190612b0a565b60405180910390f35b61016960048036038101906101649190612b65565b610382565b6040516101769190612bad565b60405180910390f35b61019960048036038101906101949190612bec565b6103a2565b005b6101a3610539565b005b6101bf60048036038101906101ba9190612bec565b61054b565b005b6101c96106e2565b6040516101d69190612c76565b60405180910390f35b6101e76106e8565b6040516101f49190612bad565b60405180910390f35b61021760048036038101906102129190612bec565b6106ff565b6040516102249190612b0a565b60405180910390f35b61023561071a565b005b61023f61072e565b005b6102496107bd565b6040516102569190612b0a565b60405180910390f35b6102676107cc565b005b6102716107de565b6040516102849796959493929190612e33565b60405180910390f35b610295610888565b6040516102a29190612c76565b60405180910390f35b6102b36108b1565b6040516102c09190612eb7565b60405180910390f35b6102d16108ea565b6040516102de9190612eb7565b60405180910390f35b61030160048036038101906102fc9190612f94565b610923565b005b61030b611e9f565b6040516103189190612c76565b60405180910390f35b61033b60048036038101906103369190613074565b611ec9565b005b610345611f76565b6040516103529190612eb7565b60405180910390f35b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60001b81565b60046020528060005260406000206000915054906101000a900460ff1681565b8060200160208101906103b59190613074565b3373ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161461041a576040517fb9f0f17100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000610425836106ff565b90506004600082815260200190815260200160002060009054906101000a900460ff1661047e576040517ff2a5f75a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006004600083815260200190815260200160002060006101000a81548160ff0219169083151502179055508260000160208101906104bd9190613074565b73ffffffffffffffffffffffffffffffffffffffff168360200160208101906104e69190613074565b73ffffffffffffffffffffffffffffffffffffffff16827f3feadce88fc1b49db633a56fd5307ed6ee18734df83bcc4011daa720c9cd95f18660405161052c9190613461565b60405180910390a4505050565b610541611faf565b610549612036565b565b80602001602081019061055e9190613074565b3373ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16146105c3576040517fb9f0f17100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006105ce836106ff565b90506004600082815260200190815260200160002060009054906101000a900460ff1615610627576040517e5ecddb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60016004600083815260200190815260200160002060006101000a81548160ff0219169083151502179055508260000160208101906106669190613074565b73ffffffffffffffffffffffffffffffffffffffff1683602001602081019061068f9190613074565b73ffffffffffffffffffffffffffffffffffffffff16827fea589ba9473ee1fe77d352c7ed919747715a5d22931b972de9b02a907c66d5dd866040516106d59190613461565b60405180910390a4505050565b610a1181565b6000600160149054906101000a900460ff16905090565b60006107138261070e90613803565b612099565b9050919050565b610722611faf565b61072c6000612114565b565b6000610738612145565b90508073ffffffffffffffffffffffffffffffffffffffff16610759611e9f565b73ffffffffffffffffffffffffffffffffffffffff16146107b157806040517f118cdaa70000000000000000000000000000000000000000000000000000000081526004016107a89190612c76565b60405180910390fd5b6107ba81612114565b50565b60006107c761214d565b905090565b6107d4611faf565b6107dc612204565b565b6000606080600080600060606107f2612266565b6107fa6122a1565b46306000801b600067ffffffffffffffff81111561081b5761081a613488565b5b6040519080825280602002602001820160405280156108495781602001602082028036833780820191505090505b507f0f00000000000000000000000000000000000000000000000000000000000000959493929190965096509650965096509650965090919293949596565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b6040518060400160405280601181526020017f44656c65676174696f6e4d616e6167657200000000000000000000000000000081525081565b6040518060400160405280600181526020017f310000000000000000000000000000000000000000000000000000000000000081525081565b61092b6122dc565b600086869050905082829050811415806109485750848490508114155b1561097f576040517f1bcaf69f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008167ffffffffffffffff81111561099b5761099a613488565b5b6040519080825280602002602001820160405280156109ce57816020015b60608152602001906001900390816109b95790505b50905060008267ffffffffffffffff8111156109ed576109ec613488565b5b604051908082528060200260200182016040528015610a2057816020015b6060815260200190600190039081610a0b5790505b50905060005b838110156111b65760008a8a83818110610a4357610a42613816565b5b9050602002810190610a559190613854565b810190610a629190613998565b90506000815103610b4d57600067ffffffffffffffff811115610a8857610a87613488565b5b604051908082528060200260200182016040528015610ac157816020015b610aae612a8c565b815260200190600190039081610aa65790505b50848381518110610ad557610ad4613816565b5b6020026020010181905250600067ffffffffffffffff811115610afb57610afa613488565b5b604051908082528060200260200182016040528015610b295781602001602082028036833780820191505090505b50838381518110610b3d57610b3c613816565b5b60200260200101819052506111aa565b80848381518110610b6157610b60613816565b5b60200260200101819052506000815167ffffffffffffffff811115610b8957610b88613488565b5b604051908082528060200260200182016040528015610bb75781602001602082028036833780820191505090505b50905080848481518110610bce57610bcd613816565b5b60200260200101819052503373ffffffffffffffffffffffffffffffffffffffff1682600081518110610c0457610c03613816565b5b60200260200101516000015173ffffffffffffffffffffffffffffffffffffffff1614158015610c815750610a1173ffffffffffffffffffffffffffffffffffffffff1682600081518110610c5c57610c5b613816565b5b60200260200101516000015173ffffffffffffffffffffffffffffffffffffffff1614155b15610cb8576040517fb586360400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b8251811015610f1d576000838281518110610cd957610cd8613816565b5b60200260200101519050610cec81612099565b838381518110610cff57610cfe613816565b5b6020026020010181815250506000816020015173ffffffffffffffffffffffffffffffffffffffff163b03610dd9576000610d68610d5e610d3e6107bd565b868681518110610d5157610d50613816565b5b602002602001015161231d565b8360a0015161235e565b9050816020015173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614610dd3576040517f3db6791c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50610f11565b6000610e06610de66107bd565b858581518110610df957610df8613816565b5b602002602001015161231d565b90506000826020015173ffffffffffffffffffffffffffffffffffffffff16631626ba7e838560a001516040518363ffffffff1660e01b8152600401610e4d929190613a36565b602060405180830381865afa158015610e6a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e8e9190613abe565b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19169050631626ba7e60e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19168114610f0e576040517f155ff42700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50505b50806001019050610cbb565b5060005b82518110156111a75760046000838381518110610f4157610f40613816565b5b6020026020010151815260200190815260200160002060009054906101000a900460ff1615610f9c576040517f05baa05200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60018351610faa9190613b1a565b81146111215781600182610fbe9190613b4e565b81518110610fcf57610fce613816565b5b6020026020010151838281518110610fea57610fe9613816565b5b6020026020010151604001511461102d576040517fded4370e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008360018361103d9190613b4e565b8151811061104e5761104d613816565b5b6020026020010151600001519050610a1173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16141580156110e457508073ffffffffffffffffffffffffffffffffffffffff168483815181106110bf576110be613816565b5b60200260200101516020015173ffffffffffffffffffffffffffffffffffffffff1614155b1561111b576040517fb586360400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5061119c565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60001b83828151811061115857611157613816565b5b6020026020010151604001511461119b576040517fded4370e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5b806001019050610f21565b50505b50806001019050610a26565b5060005b838110156113fb5760008382815181106111d7576111d6613816565b5b60200260200101515111156113f05760005b8382815181106111fc576111fb613816565b5b6020026020010151518110156113ee57600084838151811061122157611220613816565b5b6020026020010151828151811061123b5761123a613816565b5b602002602001015160600151905060005b81518110156113e157600082828151811061126a57611269613816565b5b60200260200101516000015190508073ffffffffffffffffffffffffffffffffffffffff1663414c3e338484815181106112a7576112a6613816565b5b6020026020010151602001518585815181106112c6576112c5613816565b5b6020026020010151604001518f8f8a8181106112e5576112e4613816565b5b905060200201358e8e8b8181106112ff576112fe613816565b5b90506020028101906113119190613854565b8c8c8151811061132457611323613816565b5b60200260200101518b8151811061133e5761133d613816565b5b60200260200101518e8d8151811061135957611358613816565b5b60200260200101518c8151811061137357611372613816565b5b602002602001015160200151336040518963ffffffff1660e01b81526004016113a3989796959493929190613bd0565b600060405180830381600087803b1580156113bd57600080fd5b505af11580156113d1573d6000803e3d6000fd5b505050505080600101905061124c565b50508060010190506111e9565b505b8060010190506111ba565b5060005b83811015611a8c57600083828151811061141c5761141b613816565b5b602002602001015151036114f1573373ffffffffffffffffffffffffffffffffffffffff1663d691c96489898481811061145957611458613816565b5b9050602002013588888581811061147357611472613816565b5b90506020028101906114859190613854565b6040518463ffffffff1660e01b81526004016114a393929190613c56565b6000604051808303816000875af11580156114c2573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f820116820180604052508101906114eb9190613dd9565b50611a81565b60005b83828151811061150757611506613816565b5b6020026020010151518110156116f957600084838151811061152c5761152b613816565b5b6020026020010151828151811061154657611545613816565b5b602002602001015160600151905060005b81518110156116ec57600082828151811061157557611574613816565b5b60200260200101516000015190508073ffffffffffffffffffffffffffffffffffffffff1663a145832a8484815181106115b2576115b1613816565b5b6020026020010151602001518585815181106115d1576115d0613816565b5b6020026020010151604001518f8f8a8181106115f0576115ef613816565b5b905060200201358e8e8b81811061160a57611609613816565b5b905060200281019061161c9190613854565b8c8c8151811061162f5761162e613816565b5b60200260200101518b8151811061164957611648613816565b5b60200260200101518e8d8151811061166457611663613816565b5b60200260200101518c8151811061167e5761167d613816565b5b602002602001015160200151336040518963ffffffff1660e01b81526004016116ae989796959493929190613bd0565b600060405180830381600087803b1580156116c857600080fd5b505af11580156116dc573d6000803e3d6000fd5b5050505050806001019050611557565b50508060010190506114f4565b5082818151811061170d5761170c613816565b5b6020026020010151600184838151811061172a57611729613816565b5b60200260200101515161173d9190613b1a565b8151811061174e5761174d613816565b5b60200260200101516020015173ffffffffffffffffffffffffffffffffffffffff1663d691c96489898481811061178857611787613816565b5b905060200201358888858181106117a2576117a1613816565b5b90506020028101906117b49190613854565b6040518463ffffffff1660e01b81526004016117d293929190613c56565b6000604051808303816000875af11580156117f1573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f8201168201806040525081019061181a9190613dd9565b5060008382815181106118305761182f613816565b5b60200260200101515190505b6000811115611a7f57600084838151811061185a57611859613816565b5b602002602001015160018361186f9190613b1a565b815181106118805761187f613816565b5b60200260200101516060015190506000815190505b6000811115611a6c576000826001836118ae9190613b1a565b815181106118bf576118be613816565b5b60200260200101516000015190508073ffffffffffffffffffffffffffffffffffffffff1663d3eddcc5846001856118f79190613b1a565b8151811061190857611907613816565b5b602002602001015160200151856001866119229190613b1a565b8151811061193357611932613816565b5b6020026020010151604001518f8f8a81811061195257611951613816565b5b905060200201358e8e8b81811061196c5761196b613816565b5b905060200281019061197e9190613854565b8c8c8151811061199157611990613816565b5b602002602001015160018c6119a69190613b1a565b815181106119b7576119b6613816565b5b60200260200101518e8d815181106119d2576119d1613816565b5b602002602001015160018d6119e79190613b1a565b815181106119f8576119f7613816565b5b602002602001015160200151336040518963ffffffff1660e01b8152600401611a28989796959493929190613bd0565b600060405180830381600087803b158015611a4257600080fd5b505af1158015611a56573d6000803e3d6000fd5b505050505080611a6590613e22565b9050611895565b505080611a7890613e22565b905061183c565b505b8060010190506113ff565b5060005b83811015611d2d576000838281518110611aad57611aac613816565b5b6020026020010151511115611d22576000838281518110611ad157611ad0613816565b5b60200260200101515190505b6000811115611d20576000848381518110611afb57611afa613816565b5b6020026020010151600183611b109190613b1a565b81518110611b2157611b20613816565b5b60200260200101516060015190506000815190505b6000811115611d0d57600082600183611b4f9190613b1a565b81518110611b6057611b5f613816565b5b60200260200101516000015190508073ffffffffffffffffffffffffffffffffffffffff1663ed46336784600185611b989190613b1a565b81518110611ba957611ba8613816565b5b60200260200101516020015185600186611bc39190613b1a565b81518110611bd457611bd3613816565b5b6020026020010151604001518f8f8a818110611bf357611bf2613816565b5b905060200201358e8e8b818110611c0d57611c0c613816565b5b9050602002810190611c1f9190613854565b8c8c81518110611c3257611c31613816565b5b602002602001015160018c611c479190613b1a565b81518110611c5857611c57613816565b5b60200260200101518e8d81518110611c7357611c72613816565b5b602002602001015160018d611c889190613b1a565b81518110611c9957611c98613816565b5b602002602001015160200151336040518963ffffffff1660e01b8152600401611cc9989796959493929190613bd0565b600060405180830381600087803b158015611ce357600080fd5b505af1158015611cf7573d6000803e3d6000fd5b505050505080611d0690613e22565b9050611b36565b505080611d1990613e22565b9050611add565b505b806001019050611a90565b5060005b83811015611e93576000838281518110611d4e57611d4d613816565b5b6020026020010151511115611e885760005b838281518110611d7357611d72613816565b5b602002602001015151811015611e86573373ffffffffffffffffffffffffffffffffffffffff16848381518110611dad57611dac613816565b5b60200260200101516001868581518110611dca57611dc9613816565b5b602002602001015151611ddd9190613b1a565b81518110611dee57611ded613816565b5b60200260200101516020015173ffffffffffffffffffffffffffffffffffffffff167f40dadaa36c6c2e3d7317e24757451ffb2d603d875f0ad5e92c5dd156573b1873868581518110611e4457611e43613816565b5b60200260200101518481518110611e5e57611e5d613816565b5b6020026020010151604051611e73919061401c565b60405180910390a3806001019050611d60565b505b806001019050611d31565b50505050505050505050565b6000600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b611ed1611faf565b80600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508073ffffffffffffffffffffffffffffffffffffffff16611f31610888565b73ffffffffffffffffffffffffffffffffffffffff167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b6040518060400160405280600581526020017f312e332e3000000000000000000000000000000000000000000000000000000081525081565b611fb7612145565b73ffffffffffffffffffffffffffffffffffffffff16611fd5610888565b73ffffffffffffffffffffffffffffffffffffffff161461203457611ff8612145565b6040517f118cdaa700000000000000000000000000000000000000000000000000000000815260040161202b9190612c76565b60405180910390fd5b565b61203e61238a565b6000600160146101000a81548160ff0219169083151502179055507f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa612082612145565b60405161208f9190612c76565b60405180910390a1565b6000807f88c1d2ecf185adf710588203a5f263f0ff61be0d33da39792cde19ba9aa4331e8360000151846020015185604001516120d987606001516123ca565b87608001516040516020016120f39695949392919061403e565b60405160208183030381529060405290508080519060200120915050919050565b600160006101000a81549073ffffffffffffffffffffffffffffffffffffffff0219169055612142816124a2565b50565b600033905090565b60007f000000000000000000000000663f3ad617193148711d28f5334ee4ed0701660273ffffffffffffffffffffffffffffffffffffffff163073ffffffffffffffffffffffffffffffffffffffff161480156121c957507f000000000000000000000000000000000000000000000000000000000000053946145b156121f6577f8cdadf61c3a91a26e93fd395df1ff97693afe59cddc459306faa96608f5933d99050612201565b6121fe612566565b90505b90565b61220c6122dc565b60018060146101000a81548160ff0219169083151502179055507f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a25861224f612145565b60405161225c9190612c76565b60405180910390a1565b606061229c60027f44656c65676174696f6e4d616e616765720000000000000000000000000000116125fc90919063ffffffff16565b905090565b60606122d760037f31000000000000000000000000000000000000000000000000000000000000016125fc90919063ffffffff16565b905090565b6122e46106e8565b1561231b576040517fd93c066500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b565b60006040517f190100000000000000000000000000000000000000000000000000000000000081528360028201528260228201526042812091505092915050565b60008060008061236e86866126ac565b92509250925061237e8282612708565b82935050505092915050565b6123926106e8565b6123c8576040517f8dfc202b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b565b600080825167ffffffffffffffff8111156123e8576123e7613488565b5b6040519080825280602002602001820160405280156124165781602001602082028036833780820191505090505b50905060005b83518110156124725761244884828151811061243b5761243a613816565b5b602002602001015161286c565b82828151811061245b5761245a613816565b5b60200260200101818152505080600101905061241c565b50806040516020016124849190614157565b60405160208183030381529060405280519060200120915050919050565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050816000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a35050565b60007f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f7f604240e1ed005b9ba256cb7011059bf4ae645812b834bbcb5b22c93e2d1185cc7fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc646306040516020016125e195949392919061416e565b60405160208183030381529060405280519060200120905090565b606060ff60001b831461261957612612836128d4565b90506126a6565b818054612625906141f0565b80601f0160208091040260200160405190810160405280929190818152602001828054612651906141f0565b801561269e5780601f106126735761010080835404028352916020019161269e565b820191906000526020600020905b81548152906001019060200180831161268157829003601f168201915b505050505090505b92915050565b600080600060418451036126f15760008060006020870151925060408701519150606087015160001a90506126e388828585612948565b955095509550505050612701565b60006002855160001b9250925092505b9250925092565b6000600381111561271c5761271b614221565b5b82600381111561272f5761272e614221565b5b0315612868576001600381111561274957612748614221565b5b82600381111561275c5761275b614221565b5b03612793576040517ff645eedf00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600260038111156127a7576127a6614221565b5b8260038111156127ba576127b9614221565b5b036127ff578060001c6040517ffce698f70000000000000000000000000000000000000000000000000000000081526004016127f69190614250565b60405180910390fd5b60038081111561281257612811614221565b5b82600381111561282557612824614221565b5b0361286757806040517fd78bce0c00000000000000000000000000000000000000000000000000000000815260040161285e9190612b0a565b60405180910390fd5b5b5050565b6000807f80ad7e1b04ee6d994a125f4714ca0720908bd80ed16063ec8aee4b88e9253e2d83600001518460200151805190602001206040516020016128b39392919061426b565b60405160208183030381529060405290508080519060200120915050919050565b606060006128e183612a3c565b90506000602067ffffffffffffffff811115612900576128ff613488565b5b6040519080825280601f01601f1916602001820160405280156129325781602001600182028036833780820191505090505b5090508181528360208201528092505050919050565b60008060007f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08460001c1115612988576000600385925092509250612a32565b6000600188888888604051600081526020016040526040516129ad94939291906142be565b6020604051602081039080840390855afa1580156129cf573d6000803e3d6000fd5b505050602060405103519050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603612a2357600060016000801b93509350935050612a32565b8060008060001b935093509350505b9450945094915050565b60008060ff8360001c169050601f811115612a83576040517fb3512b0c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80915050919050565b6040518060c00160405280600073ffffffffffffffffffffffffffffffffffffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff168152602001600080191681526020016060815260200160008152602001606081525090565b6000819050919050565b612b0481612af1565b82525050565b6000602082019050612b1f6000830184612afb565b92915050565b6000604051905090565b600080fd5b600080fd5b612b4281612af1565b8114612b4d57600080fd5b50565b600081359050612b5f81612b39565b92915050565b600060208284031215612b7b57612b7a612b2f565b5b6000612b8984828501612b50565b91505092915050565b60008115159050919050565b612ba781612b92565b82525050565b6000602082019050612bc26000830184612b9e565b92915050565b600080fd5b600060c08284031215612be357612be2612bc8565b5b81905092915050565b600060208284031215612c0257612c01612b2f565b5b600082013567ffffffffffffffff811115612c2057612c1f612b34565b5b612c2c84828501612bcd565b91505092915050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000612c6082612c35565b9050919050565b612c7081612c55565b82525050565b6000602082019050612c8b6000830184612c67565b92915050565b60007fff0000000000000000000000000000000000000000000000000000000000000082169050919050565b612cc681612c91565b82525050565b600081519050919050565b600082825260208201905092915050565b60005b83811015612d06578082015181840152602081019050612ceb565b60008484015250505050565b6000601f19601f8301169050919050565b6000612d2e82612ccc565b612d388185612cd7565b9350612d48818560208601612ce8565b612d5181612d12565b840191505092915050565b6000819050919050565b612d6f81612d5c565b82525050565b600081519050919050565b600082825260208201905092915050565b6000819050602082019050919050565b612daa81612d5c565b82525050565b6000612dbc8383612da1565b60208301905092915050565b6000602082019050919050565b6000612de082612d75565b612dea8185612d80565b9350612df583612d91565b8060005b83811015612e26578151612e0d8882612db0565b9750612e1883612dc8565b925050600181019050612df9565b5085935050505092915050565b600060e082019050612e48600083018a612cbd565b8181036020830152612e5a8189612d23565b90508181036040830152612e6e8188612d23565b9050612e7d6060830187612d66565b612e8a6080830186612c67565b612e9760a0830185612afb565b81810360c0830152612ea98184612dd5565b905098975050505050505050565b60006020820190508181036000830152612ed18184612d23565b905092915050565b600080fd5b600080fd5b600080fd5b60008083601f840112612efe57612efd612ed9565b5b8235905067ffffffffffffffff811115612f1b57612f1a612ede565b5b602083019150836020820283011115612f3757612f36612ee3565b5b9250929050565b60008083601f840112612f5457612f53612ed9565b5b8235905067ffffffffffffffff811115612f7157612f70612ede565b5b602083019150836020820283011115612f8d57612f8c612ee3565b5b9250929050565b60008060008060008060608789031215612fb157612fb0612b2f565b5b600087013567ffffffffffffffff811115612fcf57612fce612b34565b5b612fdb89828a01612ee8565b9650965050602087013567ffffffffffffffff811115612ffe57612ffd612b34565b5b61300a89828a01612f3e565b9450945050604087013567ffffffffffffffff81111561302d5761302c612b34565b5b61303989828a01612ee8565b92509250509295509295509295565b61305181612c55565b811461305c57600080fd5b50565b60008135905061306e81613048565b92915050565b60006020828403121561308a57613089612b2f565b5b60006130988482850161305f565b91505092915050565b60006130b0602084018461305f565b905092915050565b6130c181612c55565b82525050565b60006130d66020840184612b50565b905092915050565b6130e781612af1565b82525050565b600080fd5b600080fd5b600080fd5b60008083356001602003843603038112613119576131186130f7565b5b83810192508235915060208301925067ffffffffffffffff821115613141576131406130ed565b5b602082023603831315613157576131566130f2565b5b509250929050565b600082825260208201905092915050565b6000819050919050565b60008083356001602003843603038112613197576131966130f7565b5b83810192508235915060208301925067ffffffffffffffff8211156131bf576131be6130ed565b5b6001820236038313156131d5576131d46130f2565b5b509250929050565b600082825260208201905092915050565b82818337600083830152505050565b600061320983856131dd565b93506132168385846131ee565b61321f83612d12565b840190509392505050565b60006060830161323d60008401846130a1565b61324a60008601826130b8565b50613258602084018461317a565b858303602087015261326b8382846131fd565b9250505061327c604084018461317a565b858303604087015261328f8382846131fd565b925050508091505092915050565b60006132a9838361322a565b905092915050565b6000823560016060038336030381126132cd576132cc6130f7565b5b82810191505092915050565b6000602082019050919050565b60006132f2838561315f565b93508360208402850161330484613170565b8060005b8781101561334857848403895261331f82846132b1565b613329858261329d565b9450613334836132d9565b925060208a01995050600181019050613308565b50829750879450505050509392505050565b61336381612d5c565b811461336e57600080fd5b50565b6000813590506133808161335a565b92915050565b60006133956020840184613371565b905092915050565b600060c083016133b060008401846130a1565b6133bd60008601826130b8565b506133cb60208401846130a1565b6133d860208601826130b8565b506133e660408401846130c7565b6133f360408601826130de565b5061340160608401846130fc565b85830360608701526134148382846132e6565b925050506134256080840184613386565b6134326080860182612da1565b5061344060a084018461317a565b85830360a08701526134538382846131fd565b925050508091505092915050565b6000602082019050818103600083015261347b818461339d565b905092915050565b600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6134c082612d12565b810181811067ffffffffffffffff821117156134df576134de613488565b5b80604052505050565b60006134f2612b25565b90506134fe82826134b7565b919050565b600080fd5b600067ffffffffffffffff82111561352357613522613488565b5b602082029050602081019050919050565b600080fd5b600067ffffffffffffffff82111561355457613553613488565b5b61355d82612d12565b9050602081019050919050565b600061357d61357884613539565b6134e8565b90508281526020810184848401111561359957613598613534565b5b6135a48482856131ee565b509392505050565b600082601f8301126135c1576135c0612ed9565b5b81356135d184826020860161356a565b91505092915050565b6000606082840312156135f0576135ef613483565b5b6135fa60606134e8565b9050600061360a8482850161305f565b600083015250602082013567ffffffffffffffff81111561362e5761362d613503565b5b61363a848285016135ac565b602083015250604082013567ffffffffffffffff81111561365e5761365d613503565b5b61366a848285016135ac565b60408301525092915050565b600061368961368484613508565b6134e8565b905080838252602082019050602084028301858111156136ac576136ab612ee3565b5b835b818110156136f357803567ffffffffffffffff8111156136d1576136d0612ed9565b5b8086016136de89826135da565b855260208501945050506020810190506136ae565b5050509392505050565b600082601f83011261371257613711612ed9565b5b8135613722848260208601613676565b91505092915050565b600060c0828403121561374157613740613483565b5b61374b60c06134e8565b9050600061375b8482850161305f565b600083015250602061376f8482850161305f565b602083015250604061378384828501612b50565b604083015250606082013567ffffffffffffffff8111156137a7576137a6613503565b5b6137b3848285016136fd565b60608301525060806137c784828501613371565b60808301525060a082013567ffffffffffffffff8111156137eb576137ea613503565b5b6137f7848285016135ac565b60a08301525092915050565b600061380f368361372b565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600080fd5b600080fd5b600080fd5b6000808335600160200384360303811261387157613870613845565b5b80840192508235915067ffffffffffffffff8211156138935761389261384a565b5b6020830192506001820236038313156138af576138ae61384f565b5b509250929050565b600067ffffffffffffffff8211156138d2576138d1613488565b5b602082029050602081019050919050565b60006138f66138f1846138b7565b6134e8565b9050808382526020820190506020840283018581111561391957613918612ee3565b5b835b8181101561396057803567ffffffffffffffff81111561393e5761393d612ed9565b5b80860161394b898261372b565b8552602085019450505060208101905061391b565b5050509392505050565b600082601f83011261397f5761397e612ed9565b5b813561398f8482602086016138e3565b91505092915050565b6000602082840312156139ae576139ad612b2f565b5b600082013567ffffffffffffffff8111156139cc576139cb612b34565b5b6139d88482850161396a565b91505092915050565b600081519050919050565b600082825260208201905092915050565b6000613a08826139e1565b613a1281856139ec565b9350613a22818560208601612ce8565b613a2b81612d12565b840191505092915050565b6000604082019050613a4b6000830185612afb565b8181036020830152613a5d81846139fd565b90509392505050565b60007fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b613a9b81613a66565b8114613aa657600080fd5b50565b600081519050613ab881613a92565b92915050565b600060208284031215613ad457613ad3612b2f565b5b6000613ae284828501613aa9565b91505092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000613b2582612d5c565b9150613b3083612d5c565b9250828203905081811115613b4857613b47613aeb565b5b92915050565b6000613b5982612d5c565b9150613b6483612d5c565b9250828201905080821115613b7c57613b7b613aeb565b5b92915050565b6000613b8d82612af1565b9050919050565b613b9d81613b82565b82525050565b6000613baf83856139ec565b9350613bbc8385846131ee565b613bc583612d12565b840190509392505050565b600060e0820190508181036000830152613bea818b6139fd565b90508181036020830152613bfe818a6139fd565b9050613c0d6040830189613b94565b8181036060830152613c20818789613ba3565b9050613c2f6080830186612afb565b613c3c60a0830185612c67565b613c4960c0830184612c67565b9998505050505050505050565b6000604082019050613c6b6000830186613b94565b8181036020830152613c7e818486613ba3565b9050949350505050565b600067ffffffffffffffff821115613ca357613ca2613488565b5b602082029050602081019050919050565b6000613cc7613cc284613539565b6134e8565b905082815260208101848484011115613ce357613ce2613534565b5b613cee848285612ce8565b509392505050565b600082601f830112613d0b57613d0a612ed9565b5b8151613d1b848260208601613cb4565b91505092915050565b6000613d37613d3284613c88565b6134e8565b90508083825260208201905060208402830185811115613d5a57613d59612ee3565b5b835b81811015613da157805167ffffffffffffffff811115613d7f57613d7e612ed9565b5b808601613d8c8982613cf6565b85526020850194505050602081019050613d5c565b5050509392505050565b600082601f830112613dc057613dbf612ed9565b5b8151613dd0848260208601613d24565b91505092915050565b600060208284031215613def57613dee612b2f565b5b600082015167ffffffffffffffff811115613e0d57613e0c612b34565b5b613e1984828501613dab565b91505092915050565b6000613e2d82612d5c565b915060008203613e4057613e3f613aeb565b5b600182039050919050565b600081519050919050565b6000819050602082019050919050565b6000613e71826139e1565b613e7b81856131dd565b9350613e8b818560208601612ce8565b613e9481612d12565b840191505092915050565b6000606083016000830151613eb760008601826130b8565b5060208301518482036020860152613ecf8282613e66565b91505060408301518482036040860152613ee98282613e66565b9150508091505092915050565b6000613f028383613e9f565b905092915050565b6000602082019050919050565b6000613f2282613e4b565b613f2c818561315f565b935083602082028501613f3e85613e56565b8060005b85811015613f7a5784840389528151613f5b8582613ef6565b9450613f6683613f0a565b925060208a01995050600181019050613f42565b50829750879550505050505092915050565b600060c083016000830151613fa460008601826130b8565b506020830151613fb760208601826130b8565b506040830151613fca60408601826130de565b5060608301518482036060860152613fe28282613f17565b9150506080830151613ff76080860182612da1565b5060a083015184820360a086015261400f8282613e66565b9150508091505092915050565b600060208201905081810360008301526140368184613f8c565b905092915050565b600060c0820190506140536000830189612afb565b6140606020830188612c67565b61406d6040830187612c67565b61407a6060830186612afb565b6140876080830185612afb565b61409460a0830184612d66565b979650505050505050565b600081519050919050565b600081905092915050565b6000819050602082019050919050565b6140ce81612af1565b82525050565b60006140e083836140c5565b60208301905092915050565b6000602082019050919050565b60006141048261409f565b61410e81856140aa565b9350614119836140b5565b8060005b8381101561414a57815161413188826140d4565b975061413c836140ec565b92505060018101905061411d565b5085935050505092915050565b600061416382846140f9565b915081905092915050565b600060a0820190506141836000830188612afb565b6141906020830187612afb565b61419d6040830186612afb565b6141aa6060830185612d66565b6141b76080830184612c67565b9695505050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b6000600282049050600182168061420857607f821691505b60208210810361421b5761421a6141c1565b5b50919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b60006020820190506142656000830184612d66565b92915050565b60006060820190506142806000830186612afb565b61428d6020830185612c67565b61429a6040830184612afb565b949350505050565b600060ff82169050919050565b6142b8816142a2565b82525050565b60006080820190506142d36000830187612afb565b6142e060208301866142af565b6142ed6040830185612afb565b6142fa6060830184612afb565b9594505050505056fea26469706673582212205871db72351a516eb48063d38edefa8dca6451c54af96066cc36b7a433d5af5b64736f6c63430008170033", + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000000": "0x00000000000000000000000070997970c51812dc3a010c7d01b50e0d17dc79c8", + "0x0000000000000000000000000000000000000000000000000000000000000001": "0x0000000000000000000000000000000000000000000000000000000000000000" + } + }, + "0x70997970c51812dc3a010c7d01b50e0d17dc79c8": { + "nonce": 0, + "balance": "0x21e19e0c9bab2400000", + "code": "0x", + "storage": {} + }, + "0x8438ad1c834623cff278ab6829a248e37c2d7e3f": { + "nonce": 1, + "balance": "0x0", + "code": "0x6080604052600436106101c65760003560e01c806384b0196e116100f7578063d03c791411610095578063ea4d3c9b11610064578063ea4d3c9b1461066b578063ed8101b514610696578063f23a6e61146106d3578063ffa1ad7414610710576101cd565b8063d03c7914146105b7578063d087d288146105f4578063d691c9641461061f578063e9ae5c531461064f576101cd565b8063b0d691fe116100d1578063b0d691fe146104fb578063bc197c8114610526578063c399ec8814610563578063cef6d2091461058e576101cd565b806384b0196e14610474578063a3f4df7e146104a5578063acb8cc49146104d0576101cd565b80633ed01015116101645780634a58db191161013e5780634a58db19146103fa5780635c1c6dcd146104045780637f07bfdc1461042057806383ebb77114610449576101cd565b80633ed010151461036b578063445140b81461039457806349934047146103d1576101cd565b80631626ba7e116101a05780631626ba7e1461028957806319822f7c146102c65780632b3afd99146103035780633e1b08121461032e576101cd565b806301ffc9a7146101d257806306394d671461020f578063150b7a021461024c576101cd565b366101cd57005b600080fd5b3480156101de57600080fd5b506101f960048036038101906101f49190612f07565b61073b565b6040516102069190612f4f565b60405180910390f35b34801561021b57600080fd5b5061023660048036038101906102319190612f8f565b610a32565b6040516102439190612ff1565b60405180910390f35b34801561025857600080fd5b50610273600480360381019061026e91906131e6565b610a54565b6040516102809190613278565b60405180910390f35b34801561029557600080fd5b506102b060048036038101906102ab919061331f565b610aed565b6040516102bd9190613278565b60405180910390f35b3480156102d257600080fd5b506102ed60048036038101906102e8919061337f565b610b88565b6040516102fa91906133fd565b60405180910390f35b34801561030f57600080fd5b50610318610cb8565b6040516103259190612ff1565b60405180910390f35b34801561033a57600080fd5b5061035560048036038101906103509190613468565b610cdc565b60405161036291906133fd565b60405180910390f35b34801561037757600080fd5b50610392600480360381019061038d91906134b4565b610d81565b005b3480156103a057600080fd5b506103bb60048036038101906103b691906134fd565b610ece565b6040516103c89190612f4f565b60405180910390f35b3480156103dd57600080fd5b506103f860048036038101906103f391906134b4565b610f71565b005b6104026110be565b005b61041e60048036038101906104199190613549565b6111d1565b005b34801561042c57600080fd5b50610447600480360381019061044291906135d0565b6112c4565b005b34801561045557600080fd5b5061045e611414565b60405161046b9190612ff1565b60405180910390f35b34801561048057600080fd5b50610489611423565b60405161049c9796959493929190613797565b60405180910390f35b3480156104b157600080fd5b506104ba6114cd565b6040516104c7919061381b565b60405180910390f35b3480156104dc57600080fd5b506104e5611506565b6040516104f2919061381b565b60405180910390f35b34801561050757600080fd5b5061051061153f565b60405161051d919061389c565b60405180910390f35b34801561053257600080fd5b5061054d6004803603810190610548919061397a565b611563565b60405161055a9190613278565b60405180910390f35b34801561056f57600080fd5b506105786115fd565b60405161058591906133fd565b60405180910390f35b34801561059a57600080fd5b506105b560048036038101906105b09190613af5565b61169e565b005b3480156105c357600080fd5b506105de60048036038101906105d99190613bd5565b6117fa565b6040516105eb9190612f4f565b60405180910390f35b34801561060057600080fd5b506106096118ab565b60405161061691906133fd565b60405180910390f35b61063960048036038101906106349190613c02565b61194f565b6040516106469190613d79565b60405180910390f35b61066960048036038101906106649190613c02565b611c8b565b005b34801561067757600080fd5b50610680611fe0565b60405161068d9190613dbc565b60405180910390f35b3480156106a257600080fd5b506106bd60048036038101906106b89190612f8f565b612004565b6040516106ca9190612ff1565b60405180910390f35b3480156106df57600080fd5b506106fa60048036038101906106f59190613dd7565b612117565b6040516107079190613278565b60405180910390f35b34801561071c57600080fd5b506107256121b1565b604051610732919061381b565b60405180910390f35b60007f0000000000000000000000008438ad1c834623cff278ab6829a248e37c2d7e3f73ffffffffffffffffffffffffffffffffffffffff163073ffffffffffffffffffffffffffffffffffffffff16036107c2576040517f9f03a02600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7fd691c964000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916148061088b57507f150b7a02000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b806108f357507f4e2312e0000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b8061095b57507f01ffc9a7000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b806109c357507f1626ba7e000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b80610a2b57507f39922547000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b9050919050565b6000610a4d610a3f6121ea565b610a4884612004565b6122a1565b9050919050565b60007f0000000000000000000000008438ad1c834623cff278ab6829a248e37c2d7e3f73ffffffffffffffffffffffffffffffffffffffff163073ffffffffffffffffffffffffffffffffffffffff1603610adb576040517f9f03a02600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b63150b7a0260e01b9050949350505050565b60007f0000000000000000000000008438ad1c834623cff278ab6829a248e37c2d7e3f73ffffffffffffffffffffffffffffffffffffffff163073ffffffffffffffffffffffffffffffffffffffff1603610b74576040517f9f03a02600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610b7f8484846122e2565b90509392505050565b60007f0000000000000000000000002e983a1ba5e8b38aaaec4b440b9ddcfbf72e15d173ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610c0f576040517fd663742a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f0000000000000000000000008438ad1c834623cff278ab6829a248e37c2d7e3f73ffffffffffffffffffffffffffffffffffffffff163073ffffffffffffffffffffffffffffffffffffffff1603610c94576040517f9f03a02600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610ca684610ca186610a32565b612385565b9050610cb182612406565b9392505050565b7fbc37962d8bd1d319c95199bdfda6d3f92baa8903a61b32d5f4ec1f4b36a3bc1881565b60007f0000000000000000000000002e983a1ba5e8b38aaaec4b440b9ddcfbf72e15d173ffffffffffffffffffffffffffffffffffffffff166335567e1a30846040518363ffffffff1660e01b8152600401610d39929190613e7d565b602060405180830381865afa158015610d56573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d7a9190613ebb565b9050919050565b7f0000000000000000000000002e983a1ba5e8b38aaaec4b440b9ddcfbf72e15d173ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614158015610e0957503073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614155b15610e40576040517f0796d94500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f000000000000000000000000663f3ad617193148711d28f5334ee4ed0701660273ffffffffffffffffffffffffffffffffffffffff16633ed01015826040518263ffffffff1660e01b8152600401610e99919061425c565b600060405180830381600087803b158015610eb357600080fd5b505af1158015610ec7573d6000803e3d6000fd5b5050505050565b60007f000000000000000000000000663f3ad617193148711d28f5334ee4ed0701660273ffffffffffffffffffffffffffffffffffffffff16632d40d052836040518263ffffffff1660e01b8152600401610f299190612ff1565b602060405180830381865afa158015610f46573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f6a91906142aa565b9050919050565b7f0000000000000000000000002e983a1ba5e8b38aaaec4b440b9ddcfbf72e15d173ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614158015610ff957503073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614155b15611030576040517f0796d94500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f000000000000000000000000663f3ad617193148711d28f5334ee4ed0701660273ffffffffffffffffffffffffffffffffffffffff166349934047826040518263ffffffff1660e01b8152600401611089919061425c565b600060405180830381600087803b1580156110a357600080fd5b505af11580156110b7573d6000803e3d6000fd5b5050505050565b7f0000000000000000000000008438ad1c834623cff278ab6829a248e37c2d7e3f73ffffffffffffffffffffffffffffffffffffffff163073ffffffffffffffffffffffffffffffffffffffff1603611143576040517f9f03a02600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f0000000000000000000000002e983a1ba5e8b38aaaec4b440b9ddcfbf72e15d173ffffffffffffffffffffffffffffffffffffffff1663b760faf934306040518363ffffffff1660e01b815260040161119d91906142d7565b6000604051808303818588803b1580156111b657600080fd5b505af11580156111ca573d6000803e3d6000fd5b5050505050565b7f0000000000000000000000002e983a1ba5e8b38aaaec4b440b9ddcfbf72e15d173ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161415801561125957503073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614155b15611290576040517f0796d94500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6112c08160000160208101906112a691906142f2565b82602001358380604001906112bb919061432e565b6124f2565b5050565b7f0000000000000000000000002e983a1ba5e8b38aaaec4b440b9ddcfbf72e15d173ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161415801561134c57503073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614155b15611383576040517f0796d94500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f0000000000000000000000002e983a1ba5e8b38aaaec4b440b9ddcfbf72e15d173ffffffffffffffffffffffffffffffffffffffff1663205c287883836040518363ffffffff1660e01b81526004016113de9291906143a0565b600060405180830381600087803b1580156113f857600080fd5b505af115801561140c573d6000803e3d6000fd5b505050505050565b600061141e6121ea565b905090565b60006060806000806000606061143761252e565b61143f612569565b46306000801b600067ffffffffffffffff8111156114605761145f6130bb565b5b60405190808252806020026020018201604052801561148e5781602001602082028036833780820191505090505b507f0f00000000000000000000000000000000000000000000000000000000000000959493929190965096509650965096509650965090919293949596565b6040518060400160405280601981526020017f4549503737303253746174656c65737344656c654761746f720000000000000081525081565b6040518060400160405280600181526020017f310000000000000000000000000000000000000000000000000000000000000081525081565b7f0000000000000000000000002e983a1ba5e8b38aaaec4b440b9ddcfbf72e15d181565b60007f0000000000000000000000008438ad1c834623cff278ab6829a248e37c2d7e3f73ffffffffffffffffffffffffffffffffffffffff163073ffffffffffffffffffffffffffffffffffffffff16036115ea576040517f9f03a02600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b63bc197c8160e01b905095945050505050565b60007f0000000000000000000000002e983a1ba5e8b38aaaec4b440b9ddcfbf72e15d173ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b815260040161165891906142d7565b602060405180830381865afa158015611675573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116999190613ebb565b905090565b7f0000000000000000000000002e983a1ba5e8b38aaaec4b440b9ddcfbf72e15d173ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161415801561172657503073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614155b1561175d576040517f0796d94500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f000000000000000000000000663f3ad617193148711d28f5334ee4ed0701660273ffffffffffffffffffffffffffffffffffffffff1663cef6d2098787878787876040518763ffffffff1660e01b81526004016117c096959493929190614541565b600060405180830381600087803b1580156117da57600080fd5b505af11580156117ee573d6000803e3d6000fd5b50505050505050505050565b600080600080600061180b866125a4565b935093509350935061182184600060f81b6125c6565b80611836575061183584600160f81b6125c6565b5b8015611861575061184b83600060f81b612617565b80611860575061185f83600160f81b612617565b5b5b8015611877575061187682600060e01b612668565b5b80156118a05750600060501b69ffffffffffffffffffff19168169ffffffffffffffffffff1916145b945050505050919050565b60007f0000000000000000000000002e983a1ba5e8b38aaaec4b440b9ddcfbf72e15d173ffffffffffffffffffffffffffffffffffffffff166335567e1a3060006040518363ffffffff1660e01b81526004016119099291906145ce565b602060405180830381865afa158015611926573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061194a9190613ebb565b905090565b60607f000000000000000000000000663f3ad617193148711d28f5334ee4ed0701660273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146119d6576040517f1a4b3a0400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000806119e2866125a4565b5050915091506119f682600160f81b6125c6565b15611a9957366000611a0887876126b3565b91509150611a1a83600060f81b612617565b15611a3057611a2982826126cc565b9450611a92565b611a3e83600160f81b612617565b15611a5457611a4d82826127bd565b9450611a91565b826040517f1187dc06000000000000000000000000000000000000000000000000000000008152600401611a889190614618565b60405180910390fd5b5b5050611c82565b611aa782600060f81b6125c6565b15611c4457600080366000611abc898961290e565b9350935093509350600167ffffffffffffffff811115611adf57611ade6130bb565b5b604051908082528060200260200182016040528015611b1257816020015b6060815260200190600190039081611afd5790505b5096506000611b2586600060f81b612617565b15611b5a57611b36858585856124f2565b88600081518110611b4a57611b49614633565b5b6020026020010181905250611c3a565b611b6886600160f81b612617565b15611bfc57611b798585858561297c565b89600081518110611b8d57611b8c614633565b5b60200260200101819052819250505080611bf7577fe723f28f104e46b47fd3531f3608374ac226bcf3ddda334a23a266453e0efdb7600089600081518110611bd857611bd7614633565b5b6020026020010151604051611bee9291906146dd565b60405180910390a15b611c39565b856040517f1187dc06000000000000000000000000000000000000000000000000000000008152600401611c309190614618565b60405180910390fd5b5b5050505050611c81565b816040517fb96fcfe4000000000000000000000000000000000000000000000000000000008152600401611c78919061471c565b60405180910390fd5b5b50509392505050565b7f0000000000000000000000002e983a1ba5e8b38aaaec4b440b9ddcfbf72e15d173ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614158015611d1357503073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614155b15611d4a576040517f0796d94500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600080611d56856125a4565b505091509150611d6a82600160f81b6125c6565b15611e0b57366000611d7c86866126b3565b91509150611d8e83600060f81b612617565b15611da357611d9d82826126cc565b50611e04565b611db183600160f81b612617565b15611dc657611dc082826127bd565b50611e03565b826040517f1187dc06000000000000000000000000000000000000000000000000000000008152600401611dfa9190614618565b60405180910390fd5b5b5050611fd9565b611e1982600060f81b6125c6565b15611f9b57600080366000611e2e888861290e565b9350935093509350611e4485600060f81b612617565b15611e5b57611e55848484846124f2565b50611f92565b611e6985600160f81b612617565b15611f54576000600167ffffffffffffffff811115611e8b57611e8a6130bb565b5b604051908082528060200260200182016040528015611ebe57816020015b6060815260200190600190039081611ea95790505b5090506000611ecf8686868661297c565b83600081518110611ee357611ee2614633565b5b60200260200101819052819250505080611f4d577fe723f28f104e46b47fd3531f3608374ac226bcf3ddda334a23a266453e0efdb7600083600081518110611f2e57611f2d614633565b5b6020026020010151604051611f449291906146dd565b60405180910390a15b5050611f91565b846040517f1187dc06000000000000000000000000000000000000000000000000000000008152600401611f889190614618565b60405180910390fd5b5b50505050611fd8565b816040517fb96fcfe4000000000000000000000000000000000000000000000000000000008152600401611fcf919061471c565b60405180910390fd5b5b5050505050565b7f000000000000000000000000663f3ad617193148711d28f5334ee4ed0701660281565b60007fbc37962d8bd1d319c95199bdfda6d3f92baa8903a61b32d5f4ec1f4b36a3bc1882600001602081019061203a91906142f2565b836020013584806040019061204f919061432e565b60405161205d929190614767565b6040518091039020858060600190612075919061432e565b604051612083929190614767565b604051809103902086608001358760a001358860c00135898060e001906120aa919061432e565b6040516120b8929190614767565b60405180910390207f0000000000000000000000002e983a1ba5e8b38aaaec4b440b9ddcfbf72e15d16040516020016120fa9a99989796959493929190614780565b604051602081830303815290604052805190602001209050919050565b60007f0000000000000000000000008438ad1c834623cff278ab6829a248e37c2d7e3f73ffffffffffffffffffffffffffffffffffffffff163073ffffffffffffffffffffffffffffffffffffffff160361219e576040517f9f03a02600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b63f23a6e6160e01b905095945050505050565b6040518060400160405280600581526020017f312e332e3000000000000000000000000000000000000000000000000000000081525081565b60007f0000000000000000000000008438ad1c834623cff278ab6829a248e37c2d7e3f73ffffffffffffffffffffffffffffffffffffffff163073ffffffffffffffffffffffffffffffffffffffff1614801561226657507f000000000000000000000000000000000000000000000000000000000000053946145b15612293577f6e94388684165b3a90707922416b4045e752f62b048c387b3db54648f016a2d8905061229e565b61229b6129b1565b90505b90565b60006040517f190100000000000000000000000000000000000000000000000000000000000081528360028201528260228201526042812091505092915050565b60003073ffffffffffffffffffffffffffffffffffffffff166123498585858080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f82011690508083019250505050505050612a47565b73ffffffffffffffffffffffffffffffffffffffff160361237357631626ba7e60e01b905061237e565b63ffffffff60e01b90505b9392505050565b6000806123a2838580610100019061239d919061432e565b6122e2565b9050631626ba7e60e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916817bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916036123fa576000915050612400565b60019150505b92915050565b600081146124ef5760003373ffffffffffffffffffffffffffffffffffffffff16827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9060405161245690614842565b600060405180830381858888f193505050503d8060008114612494576040519150601f19603f3d011682016040523d82523d6000602084013e612499565b606091505b505090503373ffffffffffffffffffffffffffffffffffffffff167fa427c7d47f24d01b170779a7600b1d4c0d7cdbabaa0f19c4f0e6182053ffc93183836040516124e5929190614857565b60405180910390a2505b50565b6060604051905081838237600038838387895af1612513573d6000823e3d81fd5b3d8152602081013d6000823e3d810160405250949350505050565b606061256460007f4549503737303253746174656c65737344656c654761746f7200000000000019612a7390919063ffffffff16565b905090565b606061259f60017f3100000000000000000000000000000000000000000000000000000000000001612a7390919063ffffffff16565b905090565b6000806000808493508460081b92508460301b91508460501b90509193509193565b6000817effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916837effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614905092915050565b6000817effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916837effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614905092915050565b6000817bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916837bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614905092915050565b3660008335840160208101925080359150509250929050565b606060008383905090508067ffffffffffffffff8111156126f0576126ef6130bb565b5b60405190808252806020026020018201604052801561272357816020015b606081526020019060019003908161270e5790505b50915060005b818110156127b5573685858381811061274557612744614633565b5b90506020028101906127579190614880565b905061278981600001602081019061276f91906142f2565b8260200135838060400190612784919061432e565b6124f2565b84838151811061279c5761279b614633565b5b6020026020010181905250508080600101915050612729565b505092915050565b606060008383905090508067ffffffffffffffff8111156127e1576127e06130bb565b5b60405190808252806020026020018201604052801561281457816020015b60608152602001906001900390816127ff5790505b50915060005b81811015612906573685858381811061283657612835614633565b5b90506020028101906128489190614880565b9050600061287c82600001602081019061286291906142f2565b8360200135848060400190612877919061432e565b61297c565b86858151811061288f5761288e614633565b5b602002602001018190528192505050806128f7577fe723f28f104e46b47fd3531f3608374ac226bcf3ddda334a23a266453e0efdb7838685815181106128d8576128d7614633565b5b60200260200101516040516128ee9291906148a8565b60405180910390a15b5050808060010191505061281a565b505092915050565b6000803660008585600090601492612928939291906148e2565b906129339190614961565b60601c9350858560149060349261294c939291906148e2565b9061295791906149c0565b60001c92508585603490809261296f939291906148e2565b9150915092959194509250565b600060606040519050828482376000388483888a5af11591503d8152602081013d6000823e3d81016040525094509492505050565b60007f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f7f87e2b3436f0f6d8494dfcb826d860322ea231814dba9eb086540f62b8561c57b7fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc64630604051602001612a2c959493929190614a1f565b60405160208183030381529060405280519060200120905090565b600080600080612a578686612b23565b925092509250612a678282612b7f565b82935050505092915050565b606060ff60001b8314612a9057612a8983612ce3565b9050612b1d565b818054612a9c90614aa1565b80601f0160208091040260200160405190810160405280929190818152602001828054612ac890614aa1565b8015612b155780601f10612aea57610100808354040283529160200191612b15565b820191906000526020600020905b815481529060010190602001808311612af857829003601f168201915b505050505090505b92915050565b60008060006041845103612b685760008060006020870151925060408701519150606087015160001a9050612b5a88828585612d57565b955095509550505050612b78565b60006002855160001b9250925092505b9250925092565b60006003811115612b9357612b92614ad2565b5b826003811115612ba657612ba5614ad2565b5b0315612cdf5760016003811115612bc057612bbf614ad2565b5b826003811115612bd357612bd2614ad2565b5b03612c0a576040517ff645eedf00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60026003811115612c1e57612c1d614ad2565b5b826003811115612c3157612c30614ad2565b5b03612c76578060001c6040517ffce698f7000000000000000000000000000000000000000000000000000000008152600401612c6d91906133fd565b60405180910390fd5b600380811115612c8957612c88614ad2565b5b826003811115612c9c57612c9b614ad2565b5b03612cde57806040517fd78bce0c000000000000000000000000000000000000000000000000000000008152600401612cd59190612ff1565b60405180910390fd5b5b5050565b60606000612cf083612e4b565b90506000602067ffffffffffffffff811115612d0f57612d0e6130bb565b5b6040519080825280601f01601f191660200182016040528015612d415781602001600182028036833780820191505090505b5090508181528360208201528092505050919050565b60008060007f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08460001c1115612d97576000600385925092509250612e41565b600060018888888860405160008152602001604052604051612dbc9493929190614b1d565b6020604051602081039080840390855afa158015612dde573d6000803e3d6000fd5b505050602060405103519050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603612e3257600060016000801b93509350935050612e41565b8060008060001b935093509350505b9450945094915050565b60008060ff8360001c169050601f811115612e92576040517fb3512b0c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80915050919050565b6000604051905090565b600080fd5b600080fd5b60007fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b612ee481612eaf565b8114612eef57600080fd5b50565b600081359050612f0181612edb565b92915050565b600060208284031215612f1d57612f1c612ea5565b5b6000612f2b84828501612ef2565b91505092915050565b60008115159050919050565b612f4981612f34565b82525050565b6000602082019050612f646000830184612f40565b92915050565b600080fd5b60006101208284031215612f8657612f85612f6a565b5b81905092915050565b600060208284031215612fa557612fa4612ea5565b5b600082013567ffffffffffffffff811115612fc357612fc2612eaa565b5b612fcf84828501612f6f565b91505092915050565b6000819050919050565b612feb81612fd8565b82525050565b60006020820190506130066000830184612fe2565b92915050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b60006130378261300c565b9050919050565b6130478161302c565b811461305257600080fd5b50565b6000813590506130648161303e565b92915050565b6000819050919050565b61307d8161306a565b811461308857600080fd5b50565b60008135905061309a81613074565b92915050565b600080fd5b600080fd5b6000601f19601f8301169050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6130f3826130aa565b810181811067ffffffffffffffff82111715613112576131116130bb565b5b80604052505050565b6000613125612e9b565b905061313182826130ea565b919050565b600067ffffffffffffffff821115613151576131506130bb565b5b61315a826130aa565b9050602081019050919050565b82818337600083830152505050565b600061318961318484613136565b61311b565b9050828152602081018484840111156131a5576131a46130a5565b5b6131b0848285613167565b509392505050565b600082601f8301126131cd576131cc6130a0565b5b81356131dd848260208601613176565b91505092915050565b60008060008060808587031215613200576131ff612ea5565b5b600061320e87828801613055565b945050602061321f87828801613055565b93505060406132308782880161308b565b925050606085013567ffffffffffffffff81111561325157613250612eaa565b5b61325d878288016131b8565b91505092959194509250565b61327281612eaf565b82525050565b600060208201905061328d6000830184613269565b92915050565b61329c81612fd8565b81146132a757600080fd5b50565b6000813590506132b981613293565b92915050565b600080fd5b600080fd5b60008083601f8401126132df576132de6130a0565b5b8235905067ffffffffffffffff8111156132fc576132fb6132bf565b5b602083019150836001820283011115613318576133176132c4565b5b9250929050565b60008060006040848603121561333857613337612ea5565b5b6000613346868287016132aa565b935050602084013567ffffffffffffffff81111561336757613366612eaa565b5b613373868287016132c9565b92509250509250925092565b60008060006060848603121561339857613397612ea5565b5b600084013567ffffffffffffffff8111156133b6576133b5612eaa565b5b6133c286828701612f6f565b93505060206133d3868287016132aa565b92505060406133e48682870161308b565b9150509250925092565b6133f78161306a565b82525050565b600060208201905061341260008301846133ee565b92915050565b600077ffffffffffffffffffffffffffffffffffffffffffffffff82169050919050565b61344581613418565b811461345057600080fd5b50565b6000813590506134628161343c565b92915050565b60006020828403121561347e5761347d612ea5565b5b600061348c84828501613453565b91505092915050565b600060c082840312156134ab576134aa612f6a565b5b81905092915050565b6000602082840312156134ca576134c9612ea5565b5b600082013567ffffffffffffffff8111156134e8576134e7612eaa565b5b6134f484828501613495565b91505092915050565b60006020828403121561351357613512612ea5565b5b6000613521848285016132aa565b91505092915050565b6000606082840312156135405761353f612f6a565b5b81905092915050565b60006020828403121561355f5761355e612ea5565b5b600082013567ffffffffffffffff81111561357d5761357c612eaa565b5b6135898482850161352a565b91505092915050565b600061359d8261300c565b9050919050565b6135ad81613592565b81146135b857600080fd5b50565b6000813590506135ca816135a4565b92915050565b600080604083850312156135e7576135e6612ea5565b5b60006135f5858286016135bb565b92505060206136068582860161308b565b9150509250929050565b60007fff0000000000000000000000000000000000000000000000000000000000000082169050919050565b61364581613610565b82525050565b600081519050919050565b600082825260208201905092915050565b60005b8381101561368557808201518184015260208101905061366a565b60008484015250505050565b600061369c8261364b565b6136a68185613656565b93506136b6818560208601613667565b6136bf816130aa565b840191505092915050565b6136d38161302c565b82525050565b600081519050919050565b600082825260208201905092915050565b6000819050602082019050919050565b61370e8161306a565b82525050565b60006137208383613705565b60208301905092915050565b6000602082019050919050565b6000613744826136d9565b61374e81856136e4565b9350613759836136f5565b8060005b8381101561378a5781516137718882613714565b975061377c8361372c565b92505060018101905061375d565b5085935050505092915050565b600060e0820190506137ac600083018a61363c565b81810360208301526137be8189613691565b905081810360408301526137d28188613691565b90506137e160608301876133ee565b6137ee60808301866136ca565b6137fb60a0830185612fe2565b81810360c083015261380d8184613739565b905098975050505050505050565b600060208201905081810360008301526138358184613691565b905092915050565b6000819050919050565b600061386261385d6138588461300c565b61383d565b61300c565b9050919050565b600061387482613847565b9050919050565b600061388682613869565b9050919050565b6138968161387b565b82525050565b60006020820190506138b1600083018461388d565b92915050565b600067ffffffffffffffff8211156138d2576138d16130bb565b5b602082029050602081019050919050565b60006138f66138f1846138b7565b61311b565b90508083825260208201905060208402830185811115613919576139186132c4565b5b835b81811015613942578061392e888261308b565b84526020840193505060208101905061391b565b5050509392505050565b600082601f830112613961576139606130a0565b5b81356139718482602086016138e3565b91505092915050565b600080600080600060a0868803121561399657613995612ea5565b5b60006139a488828901613055565b95505060206139b588828901613055565b945050604086013567ffffffffffffffff8111156139d6576139d5612eaa565b5b6139e28882890161394c565b935050606086013567ffffffffffffffff811115613a0357613a02612eaa565b5b613a0f8882890161394c565b925050608086013567ffffffffffffffff811115613a3057613a2f612eaa565b5b613a3c888289016131b8565b9150509295509295909350565b60008083601f840112613a5f57613a5e6130a0565b5b8235905067ffffffffffffffff811115613a7c57613a7b6132bf565b5b602083019150836020820283011115613a9857613a976132c4565b5b9250929050565b60008083601f840112613ab557613ab46130a0565b5b8235905067ffffffffffffffff811115613ad257613ad16132bf565b5b602083019150836020820283011115613aee57613aed6132c4565b5b9250929050565b60008060008060008060608789031215613b1257613b11612ea5565b5b600087013567ffffffffffffffff811115613b3057613b2f612eaa565b5b613b3c89828a01613a49565b9650965050602087013567ffffffffffffffff811115613b5f57613b5e612eaa565b5b613b6b89828a01613a9f565b9450945050604087013567ffffffffffffffff811115613b8e57613b8d612eaa565b5b613b9a89828a01613a49565b92509250509295509295509295565b613bb281612fd8565b8114613bbd57600080fd5b50565b600081359050613bcf81613ba9565b92915050565b600060208284031215613beb57613bea612ea5565b5b6000613bf984828501613bc0565b91505092915050565b600080600060408486031215613c1b57613c1a612ea5565b5b6000613c2986828701613bc0565b935050602084013567ffffffffffffffff811115613c4a57613c49612eaa565b5b613c56868287016132c9565b92509250509250925092565b600081519050919050565b600082825260208201905092915050565b6000819050602082019050919050565b600081519050919050565b600082825260208201905092915050565b6000613cb582613c8e565b613cbf8185613c99565b9350613ccf818560208601613667565b613cd8816130aa565b840191505092915050565b6000613cef8383613caa565b905092915050565b6000602082019050919050565b6000613d0f82613c62565b613d198185613c6d565b935083602082028501613d2b85613c7e565b8060005b85811015613d675784840389528151613d488582613ce3565b9450613d5383613cf7565b925060208a01995050600181019050613d2f565b50829750879550505050505092915050565b60006020820190508181036000830152613d938184613d04565b905092915050565b6000613da682613869565b9050919050565b613db681613d9b565b82525050565b6000602082019050613dd16000830184613dad565b92915050565b600080600080600060a08688031215613df357613df2612ea5565b5b6000613e0188828901613055565b9550506020613e1288828901613055565b9450506040613e238882890161308b565b9350506060613e348882890161308b565b925050608086013567ffffffffffffffff811115613e5557613e54612eaa565b5b613e61888289016131b8565b9150509295509295909350565b613e7781613418565b82525050565b6000604082019050613e9260008301856136ca565b613e9f6020830184613e6e565b9392505050565b600081519050613eb581613074565b92915050565b600060208284031215613ed157613ed0612ea5565b5b6000613edf84828501613ea6565b91505092915050565b6000613ef76020840184613055565b905092915050565b613f088161302c565b82525050565b6000613f1d60208401846132aa565b905092915050565b613f2e81612fd8565b82525050565b600080fd5b600080fd5b600080fd5b60008083356001602003843603038112613f6057613f5f613f3e565b5b83810192508235915060208301925067ffffffffffffffff821115613f8857613f87613f34565b5b602082023603831315613f9e57613f9d613f39565b5b509250929050565b600082825260208201905092915050565b6000819050919050565b60008083356001602003843603038112613fde57613fdd613f3e565b5b83810192508235915060208301925067ffffffffffffffff82111561400657614005613f34565b5b60018202360383131561401c5761401b613f39565b5b509250929050565b60006140308385613c99565b935061403d838584613167565b614046836130aa565b840190509392505050565b6000606083016140646000840184613ee8565b6140716000860182613eff565b5061407f6020840184613fc1565b8583036020870152614092838284614024565b925050506140a36040840184613fc1565b85830360408701526140b6838284614024565b925050508091505092915050565b60006140d08383614051565b905092915050565b6000823560016060038336030381126140f4576140f3613f3e565b5b82810191505092915050565b6000602082019050919050565b60006141198385613fa6565b93508360208402850161412b84613fb7565b8060005b8781101561416f57848403895261414682846140d8565b61415085826140c4565b945061415b83614100565b925060208a0199505060018101905061412f565b50829750879450505050509392505050565b6000614190602084018461308b565b905092915050565b600060c083016141ab6000840184613ee8565b6141b86000860182613eff565b506141c66020840184613ee8565b6141d36020860182613eff565b506141e16040840184613f0e565b6141ee6040860182613f25565b506141fc6060840184613f43565b858303606087015261420f83828461410d565b925050506142206080840184614181565b61422d6080860182613705565b5061423b60a0840184613fc1565b85830360a087015261424e838284614024565b925050508091505092915050565b600060208201905081810360008301526142768184614198565b905092915050565b61428781612f34565b811461429257600080fd5b50565b6000815190506142a48161427e565b92915050565b6000602082840312156142c0576142bf612ea5565b5b60006142ce84828501614295565b91505092915050565b60006020820190506142ec60008301846136ca565b92915050565b60006020828403121561430857614307612ea5565b5b600061431684828501613055565b91505092915050565b600080fd5b600080fd5b600080fd5b6000808335600160200384360303811261434b5761434a61431f565b5b80840192508235915067ffffffffffffffff82111561436d5761436c614324565b5b60208301925060018202360383131561438957614388614329565b5b509250929050565b61439a81613592565b82525050565b60006040820190506143b56000830185614391565b6143c260208301846133ee565b9392505050565b6000819050919050565b60006143e0848484614024565b90509392505050565b6000602082019050919050565b60006144028385613c6d565b935083602084028501614414846143c9565b8060005b8781101561445a57848403895261442f8284613fc1565b61443a8682846143d3565b9550614445846143e9565b935060208b019a505050600181019050614418565b50829750879450505050509392505050565b600082825260208201905092915050565b6000819050919050565b600061449282612fd8565b9050919050565b6144a281614487565b82525050565b60006144b48383614499565b60208301905092915050565b60006144cf6020840184613bc0565b905092915050565b6000602082019050919050565b60006144f0838561446c565b93506144fb8261447d565b8060005b858110156145345761451182846144c0565b61451b88826144a8565b9750614526836144d7565b9250506001810190506144ff565b5085925050509392505050565b6000606082019050818103600083015261455c81888a6143f6565b905081810360208301526145718186886144e4565b905081810360408301526145868184866143f6565b9050979650505050505050565b6000819050919050565b60006145b86145b36145ae84614593565b61383d565b613418565b9050919050565b6145c88161459d565b82525050565b60006040820190506145e360008301856136ca565b6145f060208301846145bf565b9392505050565b600061460282613610565b9050919050565b614612816145f7565b82525050565b600060208201905061462d6000830184614609565b92915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600061467d61467861467384614593565b61383d565b61306a565b9050919050565b61468d81614662565b82525050565b600082825260208201905092915050565b60006146af82613c8e565b6146b98185614693565b93506146c9818560208601613667565b6146d2816130aa565b840191505092915050565b60006040820190506146f26000830185614684565b818103602083015261470481846146a4565b90509392505050565b614716816145f7565b82525050565b6000602082019050614731600083018461470d565b92915050565b600081905092915050565b600061474e8385614737565b935061475b838584613167565b82840190509392505050565b6000614774828486614742565b91508190509392505050565b600061014082019050614796600083018d612fe2565b6147a3602083018c6136ca565b6147b0604083018b6133ee565b6147bd606083018a612fe2565b6147ca6080830189612fe2565b6147d760a0830188612fe2565b6147e460c08301876133ee565b6147f160e0830186612fe2565b6147ff610100830185612fe2565b61480d61012083018461388d565b9b9a5050505050505050505050565b50565b600061482c600083614737565b91506148378261481c565b600082019050919050565b600061484d8261481f565b9150819050919050565b600060408201905061486c60008301856133ee565b6148796020830184612f40565b9392505050565b60008235600160600383360303811261489c5761489b61431f565b5b80830191505092915050565b60006040820190506148bd60008301856133ee565b81810360208301526148cf81846146a4565b90509392505050565b600080fd5b600080fd5b600080858511156148f6576148f56148d8565b5b83861115614907576149066148dd565b5b6001850283019150848603905094509492505050565b600082905092915050565b60007fffffffffffffffffffffffffffffffffffffffff00000000000000000000000082169050919050565b600082821b905092915050565b600061496d838361491d565b826149788135614928565b925060148210156149b8576149b37fffffffffffffffffffffffffffffffffffffffff00000000000000000000000083601403600802614954565b831692505b505092915050565b60006149cc838361491d565b826149d78135612fd8565b92506020821015614a1757614a127fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff83602003600802614954565b831692505b505092915050565b600060a082019050614a346000830188612fe2565b614a416020830187612fe2565b614a4e6040830186612fe2565b614a5b60608301856133ee565b614a6860808301846136ca565b9695505050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b60006002820490506001821680614ab957607f821691505b602082108103614acc57614acb614a72565b5b50919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b600060ff82169050919050565b614b1781614b01565b82525050565b6000608082019050614b326000830187612fe2565b614b3f6020830186614b0e565b614b4c6040830185612fe2565b614b596060830184612fe2565b9594505050505056fea2646970667358221220844c650b3d2c0aceaf7c108a1ec343abb8963e1bdf5c88d4f28ea4bbdce3ff1a64736f6c63430008170033", + "storage": {} + }, + "0x90f79bf6eb2c4f870365e785982e1f101e93b906": { + "nonce": 0, + "balance": "0x21e19e0c9bab2400000", + "code": "0x", + "storage": {} + }, + "0x976ea74026e726554db657fa54763abd0c3a0aa9": { + "nonce": 0, + "balance": "0x21e19e0c9bab2400000", + "code": "0x", + "storage": {} + }, + "0x9965507d1a55bcc2695c58ba16fb37d819b0a4dc": { + "nonce": 0, + "balance": "0x21e19e0c9bab2400000", + "code": "0x", + "storage": {} + }, + "0xa0ee7a142d267c1f36714e4a8f75612f20a79720": { + "nonce": 0, + "balance": "0x21e19e0c9bab2400000", + "code": "0x", + "storage": {} + }, + "0xbc9129dc0487fc2e169941c75aabc539f208fb01": { + "nonce": 1, + "balance": "0x0", + "code": "0x608060405234801561001057600080fd5b50600436106100625760003560e01c8063414c3e3314610067578063a145832a14610083578063b99deb0e1461009f578063b9cf5249146100cf578063d3eddcc5146100ff578063ed4633671461011b575b600080fd5b610081600480360381019061007c9190610c7a565b610137565b005b61009d60048036038101906100989190610c7a565b610143565b005b6100b960048036038101906100b49190610d7d565b6107c3565b6040516100c69190610ef8565b60405180910390f35b6100e960048036038101906100e49190610f1a565b6109ac565b6040516100f69190610f75565b60405180910390f35b61011960048036038101906101149190610c7a565b6109db565b005b61013560048036038101906101309190610c7a565b6109e7565b005b50505050505050505050565b8561015a610150826109f3565b600160f81b6109fd565b610199576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161019090610fed565b60405180910390fd5b8660006101a582610a4e565b50509150506101b881600060f81b610a70565b6101f7576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016101ee9061107f565b60405180910390fd5b506000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600086815260200190815260200160002060009054906101000a900460ff1615610295576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161028c90611111565b60405180910390fd5b60016000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600087815260200190815260200160002060006101000a81548160ff02191690831515021790555036600061030a8989610ac1565b9150915060028282905014610354576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161034b906111a3565b60405180910390fd5b60006103608f8f6107c3565b9050806060015173ffffffffffffffffffffffffffffffffffffffff1683836000818110610391576103906111c3565b5b90506020028101906103a39190611201565b60000160208101906103b59190611229565b73ffffffffffffffffffffffffffffffffffffffff1614158061040257506000838360008181106103e9576103e86111c3565b5b90506020028101906103fb9190611201565b6020013514155b80610462575080608001518051906020012083836000818110610428576104276111c3565b5b905060200281019061043a9190611201565b80604001906104499190611256565b6040516104579291906112f8565b604051809103902014155b156104a2576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610499906113a9565b60405180910390fd5b806000015173ffffffffffffffffffffffffffffffffffffffff16838360018181106104d1576104d06111c3565b5b90506020028101906104e39190611201565b60000160208101906104f59190611229565b73ffffffffffffffffffffffffffffffffffffffff161415806105425750600083836001818110610529576105286111c3565b5b905060200281019061053b9190611201565b6020013514155b80610584575060448383600181811061055e5761055d6111c3565b5b90506020028101906105709190611201565b806040019061057f9190611256565b905014155b80610625575063a9059cbb60e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916838360018181106105c5576105c46111c3565b5b90506020028101906105d79190611201565b80604001906105e69190611256565b6000906004926105f8939291906113d3565b906106039190611452565b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614155b806106b45750806020015173ffffffffffffffffffffffffffffffffffffffff168383600181811061065a576106596111c3565b5b905060200281019061066c9190611201565b806040019061067b9190611256565b60049060249261068d939291906113d3565b9061069891906114b1565b60001c73ffffffffffffffffffffffffffffffffffffffff1614155b8061071757508060400151838360018181106106d3576106d26111c3565b5b90506020028101906106e59190611201565b80604001906106f49190611256565b602490604492610706939291906113d3565b9061071191906114b1565b60001c14155b15610757576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161074e906115a8565b60405180910390fd5b8673ffffffffffffffffffffffffffffffffffffffff16883373ffffffffffffffffffffffffffffffffffffffff167f76f83a16f9924b51c0c3ad67a44af3e517fbdec68ffa3729776df2ac0f03144060405160405180910390a4505050505050505050505050505050565b6107cb610ada565b605c838390501015610812576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108099061163a565b60405180910390fd5b8282600090601492610826939291906113d3565b906108319190611686565b60601c816000019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff1681525050828260149060289261087f939291906113d3565b9061088a9190611686565b60601c816020019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff168152505082826028906048926108d8939291906113d3565b906108e391906114b1565b60001c8160400181815250508282604890605c92610903939291906113d3565b9061090e9190611686565b60601c816060019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250508282605c90809261095b939291906113d3565b8080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f82011690508083019250505050505050816080018190525092915050565b60006020528160005260406000206020528060005260406000206000915091509054906101000a900460ff1681565b50505050505050505050565b50505050505050505050565b6000819050919050565b6000817effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916837effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614905092915050565b6000806000808493508460081b92508460301b91508460501b90509193509193565b6000817effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916837effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614905092915050565b3660008335840160208101925080359150509250929050565b6040518060a00160405280600073ffffffffffffffffffffffffffffffffffffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff16815260200160008152602001600073ffffffffffffffffffffffffffffffffffffffff168152602001606081525090565b600080fd5b600080fd5b600080fd5b600080fd5b600080fd5b60008083601f840112610b7a57610b79610b55565b5b8235905067ffffffffffffffff811115610b9757610b96610b5a565b5b602083019150836001820283011115610bb357610bb2610b5f565b5b9250929050565b6000819050919050565b610bcd81610bba565b8114610bd857600080fd5b50565b600081359050610bea81610bc4565b92915050565b610bf981610bba565b8114610c0457600080fd5b50565b600081359050610c1681610bf0565b92915050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000610c4782610c1c565b9050919050565b610c5781610c3c565b8114610c6257600080fd5b50565b600081359050610c7481610c4e565b92915050565b60008060008060008060008060008060e08b8d031215610c9d57610c9c610b4b565b5b60008b013567ffffffffffffffff811115610cbb57610cba610b50565b5b610cc78d828e01610b64565b9a509a505060208b013567ffffffffffffffff811115610cea57610ce9610b50565b5b610cf68d828e01610b64565b98509850506040610d098d828e01610bdb565b96505060608b013567ffffffffffffffff811115610d2a57610d29610b50565b5b610d368d828e01610b64565b95509550506080610d498d828e01610c07565b93505060a0610d5a8d828e01610c65565b92505060c0610d6b8d828e01610c65565b9150509295989b9194979a5092959850565b60008060208385031215610d9457610d93610b4b565b5b600083013567ffffffffffffffff811115610db257610db1610b50565b5b610dbe85828601610b64565b92509250509250929050565b610dd381610c3c565b82525050565b6000819050919050565b610dec81610dd9565b82525050565b600081519050919050565b600082825260208201905092915050565b60005b83811015610e2c578082015181840152602081019050610e11565b60008484015250505050565b6000601f19601f8301169050919050565b6000610e5482610df2565b610e5e8185610dfd565b9350610e6e818560208601610e0e565b610e7781610e38565b840191505092915050565b600060a083016000830151610e9a6000860182610dca565b506020830151610ead6020860182610dca565b506040830151610ec06040860182610de3565b506060830151610ed36060860182610dca565b5060808301518482036080860152610eeb8282610e49565b9150508091505092915050565b60006020820190508181036000830152610f128184610e82565b905092915050565b60008060408385031215610f3157610f30610b4b565b5b6000610f3f85828601610c65565b9250506020610f5085828601610c07565b9150509250929050565b60008115159050919050565b610f6f81610f5a565b82525050565b6000602082019050610f8a6000830184610f66565b92915050565b600082825260208201905092915050565b7f436176656174456e666f726365723a696e76616c69642d63616c6c2d74797065600082015250565b6000610fd7602083610f90565b9150610fe282610fa1565b602082019050919050565b6000602082019050818103600083015261100681610fca565b9050919050565b7f436176656174456e666f726365723a696e76616c69642d657865637574696f6e60008201527f2d74797065000000000000000000000000000000000000000000000000000000602082015250565b6000611069602583610f90565b91506110748261100d565b604082019050919050565b600060208201905081810360008301526110988161105c565b9050919050565b7f5370656369666963416374696f6e45524332305472616e73666572426174636860008201527f456e666f726365723a64656c65676174696f6e2d616c72656164792d75736564602082015250565b60006110fb604083610f90565b91506111068261109f565b604082019050919050565b6000602082019050818103600083015261112a816110ee565b9050919050565b7f5370656369666963416374696f6e45524332305472616e73666572426174636860008201527f456e666f726365723a696e76616c69642d62617463682d73697a650000000000602082015250565b600061118d603b83610f90565b915061119882611131565b604082019050919050565b600060208201905081810360008301526111bc81611180565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600080fd5b600080fd5b600080fd5b60008235600160600383360303811261121d5761121c6111f2565b5b80830191505092915050565b60006020828403121561123f5761123e610b4b565b5b600061124d84828501610c65565b91505092915050565b60008083356001602003843603038112611273576112726111f2565b5b80840192508235915067ffffffffffffffff821115611295576112946111f7565b5b6020830192506001820236038313156112b1576112b06111fc565b5b509250929050565b600081905092915050565b82818337600083830152505050565b60006112df83856112b9565b93506112ec8385846112c4565b82840190509392505050565b60006113058284866112d3565b91508190509392505050565b7f5370656369666963416374696f6e45524332305472616e73666572426174636860008201527f456e666f726365723a696e76616c69642d66697273742d7472616e736163746960208201527f6f6e000000000000000000000000000000000000000000000000000000000000604082015250565b6000611393604283610f90565b915061139e82611311565b606082019050919050565b600060208201905081810360008301526113c281611386565b9050919050565b600080fd5b600080fd5b600080858511156113e7576113e66113c9565b5b838611156113f8576113f76113ce565b5b6001850283019150848603905094509492505050565b600082905092915050565b60007fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b600082821b905092915050565b600061145e838361140e565b826114698135611419565b925060048210156114a9576114a47fffffffff0000000000000000000000000000000000000000000000000000000083600403600802611445565b831692505b505092915050565b60006114bd838361140e565b826114c88135610bba565b92506020821015611508576115037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff83602003600802611445565b831692505b505092915050565b7f5370656369666963416374696f6e45524332305472616e73666572426174636860008201527f456e666f726365723a696e76616c69642d7365636f6e642d7472616e7361637460208201527f696f6e0000000000000000000000000000000000000000000000000000000000604082015250565b6000611592604383610f90565b915061159d82611510565b606082019050919050565b600060208201905081810360008301526115c181611585565b9050919050565b7f5370656369666963416374696f6e45524332305472616e73666572426174636860008201527f456e666f726365723a696e76616c69642d7465726d732d6c656e677468000000602082015250565b6000611624603d83610f90565b915061162f826115c8565b604082019050919050565b6000602082019050818103600083015261165381611617565b9050919050565b60007fffffffffffffffffffffffffffffffffffffffff00000000000000000000000082169050919050565b6000611692838361140e565b8261169d813561165a565b925060148210156116dd576116d87fffffffffffffffffffffffffffffffffffffffff00000000000000000000000083601403600802611445565b831692505b50509291505056fea2646970667358221220bb45176bdb8ed7fb317c32e3295e9c2c5ef7b7344ac16b795cd46aff956325b064736f6c63430008170033", + "storage": {} + }, + "0xdd8a726a079a85effe3183ecfbe0de8ac36b1e65": { + "nonce": 1, + "balance": "0x0", + "code": "0x608060405234801561001057600080fd5b506004361061002b5760003560e01c8063570e1a3614610030575b600080fd5b61004a6004803603810190610045919061017b565b610060565b6040516100579190610209565b60405180910390f35b60008083836000906014926100779392919061022e565b9061008291906102ad565b60601c905060008484601490809261009c9392919061022e565b8080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f8201169050808301925050505050505090506000602060008351602085016000875af1905060005193508061010357600093505b50505092915050565b600080fd5b600080fd5b600080fd5b600080fd5b600080fd5b60008083601f84011261013b5761013a610116565b5b8235905067ffffffffffffffff8111156101585761015761011b565b5b60208301915083600182028301111561017457610173610120565b5b9250929050565b600080602083850312156101925761019161010c565b5b600083013567ffffffffffffffff8111156101b0576101af610111565b5b6101bc85828601610125565b92509250509250929050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b60006101f3826101c8565b9050919050565b610203816101e8565b82525050565b600060208201905061021e60008301846101fa565b92915050565b600080fd5b600080fd5b6000808585111561024257610241610224565b5b8386111561025357610252610229565b5b6001850283019150848603905094509492505050565b600082905092915050565b60007fffffffffffffffffffffffffffffffffffffffff00000000000000000000000082169050919050565b600082821b905092915050565b60006102b98383610269565b826102c48135610274565b92506014821015610304576102ff7fffffffffffffffffffffffffffffffffffffffff000000000000000000000000836014036008026102a0565b831692505b50509291505056fea264697066735822122050dbb7b87383c3f370ab6e7c31231f1967684cb78ec9da388509e2ca89e70f0a64736f6c63430008170033", + "storage": {} + }, + "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266": { + "nonce": 0, + "balance": "0x21e19e0c9bab2400000", + "code": "0x", + "storage": {} + } + }, + "best_block_number": "0x4", + "block": { + "number": "0x4", + "coinbase": "0x0000000000000000000000000000000000000000", + "timestamp": "0x67e150f4", + "gas_limit": "0x1c9c380", + "basefee": "0x2d81f0ba", + "difficulty": "0x0", + "prevrandao": "0x76d5ccfe10566cec19b4cb071969bfb3b3f7ae18b8f5e23d9c3056505c8128a2", + "blob_excess_gas_and_price": { "excess_blob_gas": 0, "blob_gasprice": 1 } + }, + "blocks": [ + { + "header": { + "parentHash": "0xf1b02a58253c31b071b2fa814de80eb512d7d1f550385dc85a953186a7d4e44f", + "sha3Uncles": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", + "miner": "0x0000000000000000000000000000000000000000", + "stateRoot": "0x2af8ef3eed5f5fa744846f73af00ee5d89468e6e42f679fd0f92c908745a34c4", + "transactionsRoot": "0xfcbe9327b55e744fda8755eabd1cb654f7114919e3aca9ab859409164fe7a2b5", + "receiptsRoot": "0x94eb585707aefdad426a934d48f1d7f8335aec8038d4533e2ec067f2a8d0c365", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "difficulty": "0x0", + "number": "0x2", + "gasLimit": "0x1c9c380", + "gasUsed": "0x5acf3c", + "timestamp": "0x67e150f4", + "extraData": "0x", + "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "nonce": "0x0000000000000000", + "baseFeePerGas": "0x360f235f", + "withdrawalsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "blobGasUsed": "0x0", + "excessBlobGas": "0x0", + "parentBeaconBlockRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", + "requestsHash": "0xe3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + }, + "transactions": [ + { + "transaction": { + "EIP1559": { + "chainId": "0x539", + "nonce": "0x1", + "gas": "0x5acf3c", + "maxFeePerGas": "0x77359401", + "maxPriorityFeePerGas": "0x1", + "to": null, + "value": "0x0", + "accessList": [], + "input": "0x60a060405260405162000012906200007e565b604051809103906000f0801580156200002f573d6000803e3d6000fd5b5073ffffffffffffffffffffffffffffffffffffffff1660809073ffffffffffffffffffffffffffffffffffffffff168152503480156200006f57600080fd5b5060016002819055506200008c565b610362806200677e83390190565b6080516166d6620000a86000396000612a8301526166d66000f3fe60806040526004361061010c5760003560e01c806370a0823111610095578063b760faf911610064578063b760faf9146103b5578063bb9fe6bf146103d1578063c23a5cea146103e8578063dbed18e014610411578063fc7e286d1461043a5761011c565b806370a08231146102fd578063765e827f1461033a578063850aaf62146103635780639b249f691461038c5761011c565b80631b2e01b8116100dc5780631b2e01b8146101e0578063205c28781461021d57806322cdde4c1461024657806335567e1a146102835780635287ce12146102c05761011c565b806242dc531461012157806301ffc9a71461015e5780630396cb601461019b5780630bd28e3b146101b75761011c565b3661011c5761011a3361047b565b005b600080fd5b34801561012d57600080fd5b5061014860048036038101906101439190613db0565b6104db565b6040516101559190613e51565b60405180910390f35b34801561016a57600080fd5b5061018560048036038101906101809190613ec4565b6106c1565b6040516101929190613f0c565b60405180910390f35b6101b560048036038101906101b09190613f63565b6108b7565b005b3480156101c357600080fd5b506101de60048036038101906101d99190613fe0565b610c13565b005b3480156101ec57600080fd5b506102076004803603810190610202919061400d565b610cb0565b6040516102149190613e51565b60405180910390f35b34801561022957600080fd5b50610244600480360381019061023f919061408b565b610cd5565b005b34801561025257600080fd5b5061026d600480360381019061026891906140f0565b610e78565b60405161027a9190614148565b60405180910390f35b34801561028f57600080fd5b506102aa60048036038101906102a5919061400d565b610eb4565b6040516102b79190613e51565b60405180910390f35b3480156102cc57600080fd5b506102e760048036038101906102e29190614163565b610f63565b6040516102f4919061426f565b60405180910390f35b34801561030957600080fd5b50610324600480360381019061031f9190614163565b611076565b6040516103319190613e51565b60405180910390f35b34801561034657600080fd5b50610361600480360381019061035c91906142e0565b6110c1565b005b34801561036f57600080fd5b5061038a60048036038101906103859190614340565b611255565b005b34801561039857600080fd5b506103b360048036038101906103ae91906143a0565b611303565b005b6103cf60048036038101906103ca9190614163565b61047b565b005b3480156103dd57600080fd5b506103e66113c9565b005b3480156103f457600080fd5b5061040f600480360381019061040a91906143ed565b611579565b005b34801561041d57600080fd5b5061043860048036038101906104339190614470565b611879565b005b34801561044657600080fd5b50610461600480360381019061045c9190614163565b611d90565b6040516104729594939291906144fd565b60405180910390f35b60006104878234611e0f565b90508173ffffffffffffffffffffffffffffffffffffffff167f2da466a7b24304f47e87fa2e1e5a81b9831ce54fec19055ce277ca2f39ba42c4826040516104cf9190613e51565b60405180910390a25050565b6000805a90503073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161461054f576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610546906145ad565b60405180910390fd5b6000856000015190506000816060015190506127108260a001518201016040603f5a02816105805761057f6145cd565b5b0410156105b1577fdeaddead0000000000000000000000000000000000000000000000000000000060005260206000fd5b600080895111156106555760006105cf846000015160008c86611e7a565b9050806106535760006105e3610800611e93565b905060008151111561064d57846000015173ffffffffffffffffffffffffffffffffffffffff168a602001517f1c4fada7374c0a9ee8841fc38afe82932dc0f8e69012e927f061a8bae611a20187602001518460405161064492919061467b565b60405180910390a35b60019250505b505b600088608001515a86030190506106b2828a8a8a8080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f8201169050808301925050505050505084611ec3565b95505050505050949350505050565b60007f3e84f021000000000000000000000000000000000000000000000000000000007fcf28ef97000000000000000000000000000000000000000000000000000000007f915074d80000000000000000000000000000000000000000000000000000000018187bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614806107d057507f915074d8000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b8061083857507fcf28ef97000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b806108a057507f3e84f021000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b806108b057506108af82612164565b5b9050919050565b60008060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020905060008263ffffffff1611610942576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610939906146f7565b60405180910390fd5b80600101600f9054906101000a900463ffffffff1663ffffffff168263ffffffff1610156109a5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161099c90614763565b60405180910390fd5b6000348260010160019054906101000a90046dffffffffffffffffffffffffffff166dffffffffffffffffffffffffffff166109e191906147b2565b905060008111610a26576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610a1d90614832565b60405180910390fd5b6dffffffffffffffffffffffffffff8016811115610a79576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610a709061489e565b60405180910390fd5b6040518060a0016040528083600001548152602001600115158152602001826dffffffffffffffffffffffffffff1681526020018463ffffffff168152602001600065ffffffffffff168152506000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000820151816000015560208201518160010160006101000a81548160ff02191690831515021790555060408201518160010160016101000a8154816dffffffffffffffffffffffffffff02191690836dffffffffffffffffffffffffffff160217905550606082015181600101600f6101000a81548163ffffffff021916908363ffffffff16021790555060808201518160010160136101000a81548165ffffffffffff021916908365ffffffffffff1602179055509050503373ffffffffffffffffffffffffffffffffffffffff167fa5ae833d0bb1dcd632d98a8b70973e8516812898e19bf27b70071ebc8dc52c018285604051610c069291906148f9565b60405180910390a2505050565b600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008277ffffffffffffffffffffffffffffffffffffffffffffffff1677ffffffffffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000815480929190610ca890614922565b919050555050565b6001602052816000526040600020602052806000526040600020600091509150505481565b60008060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002090508060000154821115610d5e576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610d55906149b6565b60405180910390fd5b818160000154610d6e91906149d6565b81600001819055503373ffffffffffffffffffffffffffffffffffffffff167fd1c19fbcd4551a5edfb66d43d2e337c04837afda3482b42bdf569a8fccdae5fb8484604051610dbe929190614a5f565b60405180910390a260008373ffffffffffffffffffffffffffffffffffffffff1683604051610dec90614ab9565b60006040518083038185875af1925050503d8060008114610e29576040519150601f19603f3d011682016040523d82523d6000602084013e610e2e565b606091505b5050905080610e72576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610e6990614b1a565b60405180910390fd5b50505050565b6000610e83826121ce565b3046604051602001610e9793929190614b49565b604051602081830303815290604052805190602001209050919050565b600060408277ffffffffffffffffffffffffffffffffffffffffffffffff16901b600160008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008477ffffffffffffffffffffffffffffffffffffffffffffffff1677ffffffffffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205417905092915050565b610f6b613853565b6000808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206040518060a0016040529081600082015481526020016001820160009054906101000a900460ff161515151581526020016001820160019054906101000a90046dffffffffffffffffffffffffffff166dffffffffffffffffffffffffffff166dffffffffffffffffffffffffffff16815260200160018201600f9054906101000a900463ffffffff1663ffffffff1663ffffffff1681526020016001820160139054906101000a900465ffffffffffff1665ffffffffffff1665ffffffffffff16815250509050919050565b60008060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600001549050919050565b6110c96121e7565b600083839050905060008167ffffffffffffffff8111156110ed576110ec6139cf565b5b60405190808252806020026020018201604052801561112657816020015b6111136138a2565b81526020019060019003908161110b5790505b50905060005b828110156111a657600082828151811061114957611148614b80565b5b60200260200101519050600080611185848a8a8781811061116d5761116c614b80565b5b905060200281019061117f9190614bbe565b8561222b565b915091506111968483836000612421565b505050808060010191505061112c565b5060007fbb47ee3e183a558b1a2ff0874b079f3fc5478b7454eacf2bfc5af2ff5878f97260405160405180910390a160005b8381101561123a57611229818888848181106111f7576111f6614b80565b5b90506020028101906112099190614bbe565b85848151811061121c5761121b614b80565b5b60200260200101516125b4565b8201915080806001019150506111d8565b506112458482612955565b505050611250612a75565b505050565b6000808473ffffffffffffffffffffffffffffffffffffffff16848460405161127f929190614c0c565b600060405180830381855af49150503d80600081146112ba576040519150601f19603f3d011682016040523d82523d6000602084013e6112bf565b606091505b509150915081816040517f994105540000000000000000000000000000000000000000000000000000000081526004016112fa929190614c25565b60405180910390fd5b600061130d612a7f565b73ffffffffffffffffffffffffffffffffffffffff1663570e1a3684846040518363ffffffff1660e01b8152600401611347929190614c82565b6020604051808303816000875af1158015611366573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061138a9190614cbb565b9050806040517f6ca7b8060000000000000000000000000000000000000000000000000000000081526004016113c09190614ce8565b60405180910390fd5b60008060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000209050600081600101600f9054906101000a900463ffffffff1663ffffffff1603611468576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161145f90614d4f565b60405180910390fd5b8060010160009054906101000a900460ff166114b9576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016114b090614dbb565b60405180910390fd5b600081600101600f9054906101000a900463ffffffff1663ffffffff16426114e19190614ddb565b9050808260010160136101000a81548165ffffffffffff021916908365ffffffffffff16021790555060008260010160006101000a81548160ff0219169083151502179055503373ffffffffffffffffffffffffffffffffffffffff167ffa9b3c14cc825c412c9ed81b3ba365a5b459439403f18829e572ed53a4180f0a8260405161156d9190614e46565b60405180910390a25050565b60008060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020905060008160010160019054906101000a90046dffffffffffffffffffffffffffff166dffffffffffffffffffffffffffff16905060008111611631576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161162890614ead565b60405180910390fd5b60008260010160139054906101000a900465ffffffffffff1665ffffffffffff1611611692576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161168990614f19565b60405180910390fd5b428260010160139054906101000a900465ffffffffffff1665ffffffffffff1611156116f3576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016116ea90614f85565b60405180910390fd5b600082600101600f6101000a81548163ffffffff021916908363ffffffff16021790555060008260010160136101000a81548165ffffffffffff021916908365ffffffffffff16021790555060008260010160016101000a8154816dffffffffffffffffffffffffffff02191690836dffffffffffffffffffffffffffff1602179055503373ffffffffffffffffffffffffffffffffffffffff167fb7c918e0e249f999e965cafeb6c664271b3f4317d296461500e71da39f0cbda384836040516117bf929190614a5f565b60405180910390a260008373ffffffffffffffffffffffffffffffffffffffff16826040516117ed90614ab9565b60006040518083038185875af1925050503d806000811461182a576040519150601f19603f3d011682016040523d82523d6000602084013e61182f565b606091505b5050905080611873576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161186a90614ff1565b60405180910390fd5b50505050565b6118816121e7565b60008383905090506000805b82811015611a6857368686838181106118a9576118a8614b80565b5b90506020028101906118bb9190615011565b90503660008280600001906118d09190615039565b9150915060008360200160208101906118e991906150da565b9050600173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff160361195a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161195190615153565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614611a46578073ffffffffffffffffffffffffffffffffffffffff16632dd8113384848780604001906119bc9190615173565b6040518563ffffffff1660e01b81526004016119db94939291906154ec565b60006040518083038186803b1580156119f357600080fd5b505afa925050508015611a04575060015b611a4557806040517f86a9f750000000000000000000000000000000000000000000000000000000008152600401611a3c9190614ce8565b60405180910390fd5b5b8282905086611a5591906147b2565b955050505050808060010191505061188d565b5060008167ffffffffffffffff811115611a8557611a846139cf565b5b604051908082528060200260200182016040528015611abe57816020015b611aab6138a2565b815260200190600190039081611aa35790505b5090506000805b84811015611bc85736888883818110611ae157611ae0614b80565b5b9050602002810190611af39190615011565b9050366000828060000190611b089190615039565b915091506000836020016020810190611b2191906150da565b9050600083839050905060005b81811015611bb5576000898981518110611b4b57611b4a614b80565b5b60200260200101519050600080611b878b898987818110611b6f57611b6e614b80565b5b9050602002810190611b819190614bbe565b8561222b565b91509150611b9784838389612421565b8a80611ba290614922565b9b50505050508080600101915050611b2e565b5050505050508080600101915050611ac5565b507fbb47ee3e183a558b1a2ff0874b079f3fc5478b7454eacf2bfc5af2ff5878f97260405160405180910390a1600080915060005b85811015611d2f5736898983818110611c1957611c18614b80565b5b9050602002810190611c2b9190615011565b9050806020016020810190611c4091906150da565b73ffffffffffffffffffffffffffffffffffffffff167f575ff3acadd5ab348fe1855e217e0f3678f8d767d7494c9f9fefbee2e17cca4d60405160405180910390a2366000828060000190611c959190615039565b91509150600082829050905060005b81811015611d1d57611cf588858584818110611cc357611cc2614b80565b5b9050602002810190611cd59190614bbe565b8b8b81518110611ce857611ce7614b80565b5b60200260200101516125b4565b87611d0091906147b2565b96508780611d0d90614922565b9850508080600101915050611ca4565b50505050508080600101915050611bfd565b50600073ffffffffffffffffffffffffffffffffffffffff167f575ff3acadd5ab348fe1855e217e0f3678f8d767d7494c9f9fefbee2e17cca4d60405160405180910390a2611d7e8682612955565b5050505050611d8b612a75565b505050565b60006020528060005260406000206000915090508060000154908060010160009054906101000a900460ff16908060010160019054906101000a90046dffffffffffffffffffffffffffff169080600101600f9054906101000a900463ffffffff16908060010160139054906101000a900465ffffffffffff16905085565b6000806000808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002090506000838260000154611e6491906147b2565b9050808260000181905550809250505092915050565b6000806000845160208601878987f19050949350505050565b60603d82811115611ea2578290505b604051602082018101604052818152816000602083013e8092505050919050565b6000805a9050600080866000015190506000611ede82612aa7565b905060008260e001519050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603611f295782600001519350612029565b809350600088511115612028578187029550600280811115611f4e57611f4d615527565b5b8a6002811115611f6157611f60615527565b5b14612027578073ffffffffffffffffffffffffffffffffffffffff16637c627b218460a001518c8b8a876040518663ffffffff1660e01b8152600401611faa949392919061559e565b600060405180830381600088803b158015611fc457600080fd5b5087f193505050508015611fd6575060015b612026576000611fe7610800611e93565b9050806040517fad7954bc00000000000000000000000000000000000000000000000000000000815260040161201d91906155ea565b60405180910390fd5b5b5b5b5a85038701965060008360a00151846060015101905060008a60800151890390508082111561207a576000818303905060006064600a83028161206f5761206e6145cd565b5b049050808b019a5050505b505081870295506000896040015190508681101561210a576002808111156120a5576120a4615527565b5b8b60028111156120b8576120b7615527565b5b036120db578096506120c98a612ae3565b6120d68a6000898b612b49565b612105565b7fdeadaa510000000000000000000000000000000000000000000000000000000060005260206000fd5b612156565b6000878203905061211b8682611e0f565b50600080600281111561213157612130615527565b5b8d600281111561214457612143615527565b5b1490506121538c828b8d612b49565b50505b505050505050949350505050565b60007f01ffc9a7000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916149050919050565b60006121d982612bd7565b805190602001209050919050565b6002805403612222576040517f3ee5aeb500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60028081905550565b60008060005a90506000846000015190506122468682612c9b565b61224f86610e78565b85602001818152505060008160400151905060008261012001518361010001518460a0015185608001518660600151868860c0015117171717171790506effffffffffffffffffffffffffffff80168111156122e0576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016122d790615658565b60405180910390fd5b60006122eb84612e57565b90506122fa8a8a8a8487612e89565b965061230e846000015185602001516130c6565b61234f57896040517f220266b600000000000000000000000000000000000000000000000000000000815260040161234691906156c4565b60405180910390fd5b825a8603111561239657896040517f220266b600000000000000000000000000000000000000000000000000000000815260040161238d919061573e565b60405180910390fd5b6060600073ffffffffffffffffffffffffffffffffffffffff168560e0015173ffffffffffffffffffffffffffffffffffffffff16146123e5576123dc8b8b8b85613184565b80985081925050505b818960400181815250506123f881613371565b8960600181815250508960a001355a870301896080018181525050505050505050935093915050565b60008061242d8561337b565b915091508173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16146124a157856040517f220266b600000000000000000000000000000000000000000000000000000000815260040161249891906157b8565b60405180910390fd5b80156124e457856040517f220266b60000000000000000000000000000000000000000000000000000000081526004016124db9190615832565b60405180910390fd5b60006124ef8561337b565b8093508192505050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161461256857866040517f220266b600000000000000000000000000000000000000000000000000000000815260040161255f91906158ac565b60405180910390fd5b81156125ab57866040517f220266b60000000000000000000000000000000000000000000000000000000081526004016125a2919061594c565b60405180910390fd5b50505050505050565b6000805a905060006125c984606001516133d4565b905060008060405190503660008880606001906125e69190615173565b91509150606060008260038111156125fd57843591505b50638dd7712f60e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916817bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916036127245760008b8b60200151604051602401612663929190615aa4565b604051602081830303815290604052638dd7712f60e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff838183161783525050505090503073ffffffffffffffffffffffffffffffffffffffff166242dc53828d8b6040516024016126da93929190615c0d565b604051602081830303815290604052915060e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff838183161783525050505092505061279b565b3073ffffffffffffffffffffffffffffffffffffffff166242dc5385858d8b6040516024016127569493929190615c54565b604051602081830303815290604052915060e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff838183161783525050505091505b602060008351602085016000305af1955060005198508460405250505050508061294b5760003d806020036127d65760206000803e60005191505b507fdeaddead00000000000000000000000000000000000000000000000000000000810361283b57876040517f220266b60000000000000000000000000000000000000000000000000000000081526004016128329190615ce9565b60405180910390fd5b7fdeadaa510000000000000000000000000000000000000000000000000000000081036128aa57600086608001515a8661287591906149d6565b61287f91906147b2565b905060008760400151905061289388612ae3565b6128a08860008385612b49565b8096505050612949565b85600001516000015173ffffffffffffffffffffffffffffffffffffffff1686602001517ff62676f440ff169a3a9afdbf812e89e7f95975ee8e5c31214ffdef631c5f4792886000015160200151612903610800611e93565b60405161291192919061467b565b60405180910390a3600086608001515a8661292c91906149d6565b61293691906147b2565b90506129456002888684611ec3565b9550505b505b5050509392505050565b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16036129c4576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016129bb90615d63565b60405180910390fd5b60008273ffffffffffffffffffffffffffffffffffffffff16826040516129ea90614ab9565b60006040518083038185875af1925050503d8060008114612a27576040519150601f19603f3d011682016040523d82523d6000602084013e612a2c565b606091505b5050905080612a70576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612a6790615dcf565b60405180910390fd5b505050565b6001600281905550565b60007f0000000000000000000000000000000000000000000000000000000000000000905090565b600080826101000151905060008361012001519050808203612acd578192505050612ade565b612ad9824883016133de565b925050505b919050565b80600001516000015173ffffffffffffffffffffffffffffffffffffffff1681602001517f67b4fa9642f42120bf031f3051d1824b0fe25627945b27b8a6a65d5761d5482e836000015160200151604051612b3e9190613e51565b60405180910390a350565b836000015160e0015173ffffffffffffffffffffffffffffffffffffffff1684600001516000015173ffffffffffffffffffffffffffffffffffffffff1685602001517f49628fd1471006c1482da88028e9ce4dbb080b815c9b0344d39e5a8e6ec1419f876000015160200151878787604051612bc99493929190615def565b60405180910390a450505050565b60606000612be4836133f7565b90506000836020013590506000612c09858060400190612c049190615173565b613407565b90506000612c25868060600190612c209190615173565b613407565b905060008660800135905060008760a00135905060008860c0013590506000612c5c8a8060e00190612c579190615173565b613407565b90508787878787878787604051602001612c7d989796959493929190615e34565b60405160208183030381529060405298505050505050505050919050565b816000016020810190612cae9190614163565b816000019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250508160200135816020018181525050612d00826080013561341e565b8260400183606001828152508281525050508160a001358160c0018181525050612d2d8260c0013561341e565b8261012001836101000182815250828152505050366000838060e00190612d549190615173565b915091506000828290501115612e01576034828290501015612dab576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612da290615efe565b60405180910390fd5b612db5828261345c565b8560e001866080018760a00183815250838152508373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815250505050612e51565b60008360e0019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff1681525050600083608001818152505060008360a00181815250505b50505050565b6000808260c001518360a001518460800151856060015186604001510101010190508261010001518102915050919050565b60008084600001519050600081600001519050612eb68887898060400190612eb19190615173565b6134fe565b60008260e00151905060008073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603612f17576000612eff84611076565b9050878111612f1057808803612f13565b60005b9150505b8273ffffffffffffffffffffffffffffffffffffffff166319822f7c878b8b60200151856040518563ffffffff1660e01b8152600401612f5993929190615f1e565b60206040518083038160008887f193505050508015612f9657506040513d601f19601f82011682018060405250810190612f939190615f71565b60015b612fe35789612fa6610800611e93565b6040517f65c8fd4d000000000000000000000000000000000000000000000000000000008152600401612fda929190615fea565b60405180910390fd5b80955050600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16036130b95760008060008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000209050600081600001549050808911156130ab578b6040517f220266b60000000000000000000000000000000000000000000000000000000081526004016130a29190616079565b60405180910390fd5b888103826000018190555050505b5050505095945050505050565b600080604083901c905060008390508067ffffffffffffffff16600160008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008477ffffffffffffffffffffffffffffffffffffffffffffffff1677ffffffffffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600081548092919061317590614922565b91905055149250505092915050565b60606000805a905060008560000151905060008160e00151905060008060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002090506000816000015490508781101561322e578a6040517f220266b600000000000000000000000000000000000000000000000000000000815260040161322591906160f3565b60405180910390fd5b87810382600001819055506000846080015190508373ffffffffffffffffffffffffffffffffffffffff166352b7512c828d8d602001518d6040518563ffffffff1660e01b815260040161328493929190615f1e565b60006040518083038160008887f1935050505080156132c657506040513d6000823e3d601f19601f820116820180604052508101906132c39190616191565b60015b613313578b6132d6610800611e93565b6040517f65c8fd4d00000000000000000000000000000000000000000000000000000000815260040161330a929190616239565b60405180910390fd5b8199508098505050805a87031115613362578b6040517f220266b600000000000000000000000000000000000000000000000000000000815260040161335991906162ee565b60405180910390fd5b50505050505094509492505050565b6000819050919050565b6000806000830361339257600080915091506133cf565b600061339d846137cf565b9050806040015165ffffffffffff164211806133c45750806020015165ffffffffffff1642105b915080600001519250505b915091565b6060819050919050565b60008183106133ed57816133ef565b825b905092915050565b6000808235905080915050919050565b600060405182808583378082209250505092915050565b6000808260801c8360001c816fffffffffffffffffffffffffffffffff169150806fffffffffffffffffffffffffffffffff16905091509150915091565b6000806000848460009060149261347593929190616326565b9061348091906163a5565b60601c858560149060249261349793929190616326565b906134a29190616430565b60801c86866024906034926134b993929190616326565b906134c49190616430565b60801c816fffffffffffffffffffffffffffffffff169150806fffffffffffffffffffffffffffffffff1690509250925092509250925092565b600082829050146137c9576000836000015160000151905060008173ffffffffffffffffffffffffffffffffffffffff163b1461357257846040517f220266b600000000000000000000000000000000000000000000000000000000815260040161356991906164db565b60405180910390fd5b600061357c612a7f565b73ffffffffffffffffffffffffffffffffffffffff1663570e1a3686600001516040015186866040518463ffffffff1660e01b81526004016135bf929190614c82565b60206040518083038160008887f11580156135de573d6000803e3d6000fd5b50505050506040513d601f19601f820116820180604052508101906136039190614cbb565b9050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff160361367657856040517f220266b600000000000000000000000000000000000000000000000000000000815260040161366d9190616555565b60405180910390fd5b8173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16146136e657856040517f220266b60000000000000000000000000000000000000000000000000000000081526004016136dd91906165cf565b60405180910390fd5b60008173ffffffffffffffffffffffffffffffffffffffff163b0361374257856040517f220266b60000000000000000000000000000000000000000000000000000000081526004016137399190616649565b60405180910390fd5b6000848460009060149261375893929190616326565b9061376391906163a5565b60601c90508273ffffffffffffffffffffffffffffffffffffffff1686602001517fd51a9c61267aa6196961883ecf5ff2da6619c37dac0fa92122513fb32c032d2d83896000015160e001516040516137bd929190616677565b60405180910390a35050505b50505050565b6137d76138da565b6000829050600060a084901c905060008165ffffffffffff16036137ff5765ffffffffffff90505b600060d085901c905060405180606001604052808473ffffffffffffffffffffffffffffffffffffffff1681526020018265ffffffffffff1681526020018365ffffffffffff168152509350505050919050565b6040518060a001604052806000815260200160001515815260200160006dffffffffffffffffffffffffffff168152602001600063ffffffff168152602001600065ffffffffffff1681525090565b6040518060a001604052806138b5613921565b8152602001600080191681526020016000815260200160008152602001600081525090565b6040518060600160405280600073ffffffffffffffffffffffffffffffffffffffff168152602001600065ffffffffffff168152602001600065ffffffffffff1681525090565b604051806101400160405280600073ffffffffffffffffffffffffffffffffffffffff168152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600073ffffffffffffffffffffffffffffffffffffffff16815260200160008152602001600081525090565b6000604051905090565b600080fd5b600080fd5b600080fd5b600080fd5b6000601f19601f8301169050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b613a07826139be565b810181811067ffffffffffffffff82111715613a2657613a256139cf565b5b80604052505050565b6000613a396139a0565b9050613a4582826139fe565b919050565b600067ffffffffffffffff821115613a6557613a646139cf565b5b613a6e826139be565b9050602081019050919050565b82818337600083830152505050565b6000613a9d613a9884613a4a565b613a2f565b905082815260208101848484011115613ab957613ab86139b9565b5b613ac4848285613a7b565b509392505050565b600082601f830112613ae157613ae06139b4565b5b8135613af1848260208601613a8a565b91505092915050565b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000613b2a82613aff565b9050919050565b613b3a81613b1f565b8114613b4557600080fd5b50565b600081359050613b5781613b31565b92915050565b6000819050919050565b613b7081613b5d565b8114613b7b57600080fd5b50565b600081359050613b8d81613b67565b92915050565b60006101408284031215613baa57613ba9613afa565b5b613bb5610140613a2f565b90506000613bc584828501613b48565b6000830152506020613bd984828501613b7e565b6020830152506040613bed84828501613b7e565b6040830152506060613c0184828501613b7e565b6060830152506080613c1584828501613b7e565b60808301525060a0613c2984828501613b7e565b60a08301525060c0613c3d84828501613b7e565b60c08301525060e0613c5184828501613b48565b60e083015250610100613c6684828501613b7e565b61010083015250610120613c7c84828501613b7e565b6101208301525092915050565b6000819050919050565b613c9c81613c89565b8114613ca757600080fd5b50565b600081359050613cb981613c93565b92915050565b60006101c08284031215613cd657613cd5613afa565b5b613ce060a0613a2f565b90506000613cf084828501613b93565b600083015250610140613d0584828501613caa565b602083015250610160613d1a84828501613b7e565b604083015250610180613d2f84828501613b7e565b6060830152506101a0613d4484828501613b7e565b60808301525092915050565b600080fd5b600080fd5b60008083601f840112613d7057613d6f6139b4565b5b8235905067ffffffffffffffff811115613d8d57613d8c613d50565b5b602083019150836001820283011115613da957613da8613d55565b5b9250929050565b6000806000806102008587031215613dcb57613dca6139aa565b5b600085013567ffffffffffffffff811115613de957613de86139af565b5b613df587828801613acc565b9450506020613e0687828801613cbf565b9350506101e085013567ffffffffffffffff811115613e2857613e276139af565b5b613e3487828801613d5a565b925092505092959194509250565b613e4b81613b5d565b82525050565b6000602082019050613e666000830184613e42565b92915050565b60007fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b613ea181613e6c565b8114613eac57600080fd5b50565b600081359050613ebe81613e98565b92915050565b600060208284031215613eda57613ed96139aa565b5b6000613ee884828501613eaf565b91505092915050565b60008115159050919050565b613f0681613ef1565b82525050565b6000602082019050613f216000830184613efd565b92915050565b600063ffffffff82169050919050565b613f4081613f27565b8114613f4b57600080fd5b50565b600081359050613f5d81613f37565b92915050565b600060208284031215613f7957613f786139aa565b5b6000613f8784828501613f4e565b91505092915050565b600077ffffffffffffffffffffffffffffffffffffffffffffffff82169050919050565b613fbd81613f90565b8114613fc857600080fd5b50565b600081359050613fda81613fb4565b92915050565b600060208284031215613ff657613ff56139aa565b5b600061400484828501613fcb565b91505092915050565b60008060408385031215614024576140236139aa565b5b600061403285828601613b48565b925050602061404385828601613fcb565b9150509250929050565b600061405882613aff565b9050919050565b6140688161404d565b811461407357600080fd5b50565b6000813590506140858161405f565b92915050565b600080604083850312156140a2576140a16139aa565b5b60006140b085828601614076565b92505060206140c185828601613b7e565b9150509250929050565b600080fd5b600061012082840312156140e7576140e66140cb565b5b81905092915050565b600060208284031215614106576141056139aa565b5b600082013567ffffffffffffffff811115614124576141236139af565b5b614130848285016140d0565b91505092915050565b61414281613c89565b82525050565b600060208201905061415d6000830184614139565b92915050565b600060208284031215614179576141786139aa565b5b600061418784828501613b48565b91505092915050565b61419981613b5d565b82525050565b6141a881613ef1565b82525050565b60006dffffffffffffffffffffffffffff82169050919050565b6141d1816141ae565b82525050565b6141e081613f27565b82525050565b600065ffffffffffff82169050919050565b614201816141e6565b82525050565b60a08201600082015161421d6000850182614190565b506020820151614230602085018261419f565b50604082015161424360408501826141c8565b50606082015161425660608501826141d7565b50608082015161426960808501826141f8565b50505050565b600060a0820190506142846000830184614207565b92915050565b60008083601f8401126142a05761429f6139b4565b5b8235905067ffffffffffffffff8111156142bd576142bc613d50565b5b6020830191508360208202830111156142d9576142d8613d55565b5b9250929050565b6000806000604084860312156142f9576142f86139aa565b5b600084013567ffffffffffffffff811115614317576143166139af565b5b6143238682870161428a565b9350935050602061433686828701614076565b9150509250925092565b600080600060408486031215614359576143586139aa565b5b600061436786828701613b48565b935050602084013567ffffffffffffffff811115614388576143876139af565b5b61439486828701613d5a565b92509250509250925092565b600080602083850312156143b7576143b66139aa565b5b600083013567ffffffffffffffff8111156143d5576143d46139af565b5b6143e185828601613d5a565b92509250509250929050565b600060208284031215614403576144026139aa565b5b600061441184828501614076565b91505092915050565b60008083601f8401126144305761442f6139b4565b5b8235905067ffffffffffffffff81111561444d5761444c613d50565b5b60208301915083602082028301111561446957614468613d55565b5b9250929050565b600080600060408486031215614489576144886139aa565b5b600084013567ffffffffffffffff8111156144a7576144a66139af565b5b6144b38682870161441a565b935093505060206144c686828701614076565b9150509250925092565b6144d9816141ae565b82525050565b6144e881613f27565b82525050565b6144f7816141e6565b82525050565b600060a0820190506145126000830188613e42565b61451f6020830187613efd565b61452c60408301866144d0565b61453960608301856144df565b61454660808301846144ee565b9695505050505050565b600082825260208201905092915050565b7f4141393220696e7465726e616c2063616c6c206f6e6c79000000000000000000600082015250565b6000614597601783614550565b91506145a282614561565b602082019050919050565b600060208201905081810360008301526145c68161458a565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b600081519050919050565b600082825260208201905092915050565b60005b8381101561463657808201518184015260208101905061461b565b60008484015250505050565b600061464d826145fc565b6146578185614607565b9350614667818560208601614618565b614670816139be565b840191505092915050565b60006040820190506146906000830185613e42565b81810360208301526146a28184614642565b90509392505050565b7f6d757374207370656369667920756e7374616b652064656c6179000000000000600082015250565b60006146e1601a83614550565b91506146ec826146ab565b602082019050919050565b60006020820190508181036000830152614710816146d4565b9050919050565b7f63616e6e6f7420646563726561736520756e7374616b652074696d6500000000600082015250565b600061474d601c83614550565b915061475882614717565b602082019050919050565b6000602082019050818103600083015261477c81614740565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60006147bd82613b5d565b91506147c883613b5d565b92508282019050808211156147e0576147df614783565b5b92915050565b7f6e6f207374616b65207370656369666965640000000000000000000000000000600082015250565b600061481c601283614550565b9150614827826147e6565b602082019050919050565b6000602082019050818103600083015261484b8161480f565b9050919050565b7f7374616b65206f766572666c6f77000000000000000000000000000000000000600082015250565b6000614888600e83614550565b915061489382614852565b602082019050919050565b600060208201905081810360008301526148b78161487b565b9050919050565b6000819050919050565b60006148e36148de6148d984613f27565b6148be565b613b5d565b9050919050565b6148f3816148c8565b82525050565b600060408201905061490e6000830185613e42565b61491b60208301846148ea565b9392505050565b600061492d82613b5d565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361495f5761495e614783565b5b600182019050919050565b7f576974686472617720616d6f756e7420746f6f206c6172676500000000000000600082015250565b60006149a0601983614550565b91506149ab8261496a565b602082019050919050565b600060208201905081810360008301526149cf81614993565b9050919050565b60006149e182613b5d565b91506149ec83613b5d565b9250828203905081811115614a0457614a03614783565b5b92915050565b6000614a25614a20614a1b84613aff565b6148be565b613aff565b9050919050565b6000614a3782614a0a565b9050919050565b6000614a4982614a2c565b9050919050565b614a5981614a3e565b82525050565b6000604082019050614a746000830185614a50565b614a816020830184613e42565b9392505050565b600081905092915050565b50565b6000614aa3600083614a88565b9150614aae82614a93565b600082019050919050565b6000614ac482614a96565b9150819050919050565b7f6661696c656420746f2077697468647261770000000000000000000000000000600082015250565b6000614b04601283614550565b9150614b0f82614ace565b602082019050919050565b60006020820190508181036000830152614b3381614af7565b9050919050565b614b4381613b1f565b82525050565b6000606082019050614b5e6000830186614139565b614b6b6020830185614b3a565b614b786040830184613e42565b949350505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600080fd5b600080fd5b600080fd5b60008235600161012003833603038112614bdb57614bda614baf565b5b80830191505092915050565b6000614bf38385614a88565b9350614c00838584613a7b565b82840190509392505050565b6000614c19828486614be7565b91508190509392505050565b6000604082019050614c3a6000830185613efd565b8181036020830152614c4c8184614642565b90509392505050565b6000614c618385614607565b9350614c6e838584613a7b565b614c77836139be565b840190509392505050565b60006020820190508181036000830152614c9d818486614c55565b90509392505050565b600081519050614cb581613b31565b92915050565b600060208284031215614cd157614cd06139aa565b5b6000614cdf84828501614ca6565b91505092915050565b6000602082019050614cfd6000830184614b3a565b92915050565b7f6e6f74207374616b656400000000000000000000000000000000000000000000600082015250565b6000614d39600a83614550565b9150614d4482614d03565b602082019050919050565b60006020820190508181036000830152614d6881614d2c565b9050919050565b7f616c726561647920756e7374616b696e67000000000000000000000000000000600082015250565b6000614da5601183614550565b9150614db082614d6f565b602082019050919050565b60006020820190508181036000830152614dd481614d98565b9050919050565b6000614de6826141e6565b9150614df1836141e6565b9250828201905065ffffffffffff811115614e0f57614e0e614783565b5b92915050565b6000614e30614e2b614e26846141e6565b6148be565b613b5d565b9050919050565b614e4081614e15565b82525050565b6000602082019050614e5b6000830184614e37565b92915050565b7f4e6f207374616b6520746f207769746864726177000000000000000000000000600082015250565b6000614e97601483614550565b9150614ea282614e61565b602082019050919050565b60006020820190508181036000830152614ec681614e8a565b9050919050565b7f6d7573742063616c6c20756e6c6f636b5374616b652829206669727374000000600082015250565b6000614f03601d83614550565b9150614f0e82614ecd565b602082019050919050565b60006020820190508181036000830152614f3281614ef6565b9050919050565b7f5374616b65207769746864726177616c206973206e6f74206475650000000000600082015250565b6000614f6f601b83614550565b9150614f7a82614f39565b602082019050919050565b60006020820190508181036000830152614f9e81614f62565b9050919050565b7f6661696c656420746f207769746864726177207374616b650000000000000000600082015250565b6000614fdb601883614550565b9150614fe682614fa5565b602082019050919050565b6000602082019050818103600083015261500a81614fce565b9050919050565b60008235600160600383360303811261502d5761502c614baf565b5b80830191505092915050565b6000808335600160200384360303811261505657615055614baf565b5b80840192508235915067ffffffffffffffff82111561507857615077614bb4565b5b60208301925060208202360383131561509457615093614bb9565b5b509250929050565b60006150a782613b1f565b9050919050565b6150b78161509c565b81146150c257600080fd5b50565b6000813590506150d4816150ae565b92915050565b6000602082840312156150f0576150ef6139aa565b5b60006150fe848285016150c5565b91505092915050565b7f4141393620696e76616c69642061676772656761746f72000000000000000000600082015250565b600061513d601783614550565b915061514882615107565b602082019050919050565b6000602082019050818103600083015261516c81615130565b9050919050565b600080833560016020038436030381126151905761518f614baf565b5b80840192508235915067ffffffffffffffff8211156151b2576151b1614bb4565b5b6020830192506001820236038313156151ce576151cd614bb9565b5b509250929050565b600082825260208201905092915050565b6000819050919050565b60006152006020840184613b48565b905092915050565b61521181613b1f565b82525050565b60006152266020840184613b7e565b905092915050565b600080fd5b600080fd5b600080fd5b6000808335600160200384360303811261525a57615259615238565b5b83810192508235915060208301925067ffffffffffffffff8211156152825761528161522e565b5b60018202360383131561529857615297615233565b5b509250929050565b600082825260208201905092915050565b60006152bd83856152a0565b93506152ca838584613a7b565b6152d3836139be565b840190509392505050565b60006152ed6020840184613caa565b905092915050565b6152fe81613c89565b82525050565b6000610120830161531860008401846151f1565b6153256000860182615208565b506153336020840184615217565b6153406020860182614190565b5061534e604084018461523d565b85830360408701526153618382846152b1565b92505050615372606084018461523d565b85830360608701526153858382846152b1565b9250505061539660808401846152de565b6153a360808601826152f5565b506153b160a0840184615217565b6153be60a0860182614190565b506153cc60c08401846152de565b6153d960c08601826152f5565b506153e760e084018461523d565b85830360e08701526153fa8382846152b1565b9250505061540c61010084018461523d565b8583036101008701526154208382846152b1565b925050508091505092915050565b600061543a8383615304565b905092915050565b6000823560016101200383360303811261545f5761545e615238565b5b82810191505092915050565b6000602082019050919050565b600061548483856151d6565b935083602084028501615496846151e7565b8060005b878110156154da5784840389526154b18284615442565b6154bb858261542e565b94506154c68361546b565b925060208a0199505060018101905061549a565b50829750879450505050509392505050565b60006040820190508181036000830152615507818688615478565b9050818103602083015261551c818486614c55565b905095945050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b6003811061556757615566615527565b5b50565b600081905061557882615556565b919050565b60006155888261556a565b9050919050565b6155988161557d565b82525050565b60006080820190506155b3600083018761558f565b81810360208301526155c58186614642565b90506155d46040830185613e42565b6155e16060830184613e42565b95945050505050565b600060208201905081810360008301526156048184614642565b905092915050565b7f41413934206761732076616c756573206f766572666c6f770000000000000000600082015250565b6000615642601883614550565b915061564d8261560c565b602082019050919050565b6000602082019050818103600083015261567181615635565b9050919050565b7f4141323520696e76616c6964206163636f756e74206e6f6e6365000000000000600082015250565b60006156ae601a83614550565b91506156b982615678565b602082019050919050565b60006040820190506156d96000830184613e42565b81810360208301526156ea816156a1565b905092915050565b7f41413236206f76657220766572696669636174696f6e4761734c696d69740000600082015250565b6000615728601e83614550565b9150615733826156f2565b602082019050919050565b60006040820190506157536000830184613e42565b81810360208301526157648161571b565b905092915050565b7f41413234207369676e6174757265206572726f72000000000000000000000000600082015250565b60006157a2601483614550565b91506157ad8261576c565b602082019050919050565b60006040820190506157cd6000830184613e42565b81810360208301526157de81615795565b905092915050565b7f414132322065787069726564206f72206e6f7420647565000000000000000000600082015250565b600061581c601783614550565b9150615827826157e6565b602082019050919050565b60006040820190506158476000830184613e42565b81810360208301526158588161580f565b905092915050565b7f41413334207369676e6174757265206572726f72000000000000000000000000600082015250565b6000615896601483614550565b91506158a182615860565b602082019050919050565b60006040820190506158c16000830184613e42565b81810360208301526158d281615889565b905092915050565b7f41413332207061796d61737465722065787069726564206f72206e6f7420647560008201527f6500000000000000000000000000000000000000000000000000000000000000602082015250565b6000615936602183614550565b9150615941826158da565b604082019050919050565b60006040820190506159616000830184613e42565b818103602083015261597281615929565b905092915050565b6000610120830161598e60008401846151f1565b61599b6000860182615208565b506159a96020840184615217565b6159b66020860182614190565b506159c4604084018461523d565b85830360408701526159d78382846152b1565b925050506159e8606084018461523d565b85830360608701526159fb8382846152b1565b92505050615a0c60808401846152de565b615a1960808601826152f5565b50615a2760a0840184615217565b615a3460a0860182614190565b50615a4260c08401846152de565b615a4f60c08601826152f5565b50615a5d60e084018461523d565b85830360e0870152615a708382846152b1565b92505050615a8261010084018461523d565b858303610100870152615a968382846152b1565b925050508091505092915050565b60006040820190508181036000830152615abe818561597a565b9050615acd6020830184614139565b9392505050565b61014082016000820151615aeb6000850182615208565b506020820151615afe6020850182614190565b506040820151615b116040850182614190565b506060820151615b246060850182614190565b506080820151615b376080850182614190565b5060a0820151615b4a60a0850182614190565b5060c0820151615b5d60c0850182614190565b5060e0820151615b7060e0850182615208565b50610100820151615b85610100850182614190565b50610120820151615b9a610120850182614190565b50505050565b6101c082016000820151615bb76000850182615ad4565b506020820151615bcb6101408501826152f5565b506040820151615bdf610160850182614190565b506060820151615bf3610180850182614190565b506080820151615c076101a0850182614190565b50505050565b6000610200820190508181036000830152615c288186614642565b9050615c376020830185615ba0565b8181036101e0830152615c4a8184614642565b9050949350505050565b6000610200820190508181036000830152615c70818688614c55565b9050615c7f6020830185615ba0565b8181036101e0830152615c928184614642565b905095945050505050565b7f41413935206f7574206f66206761730000000000000000000000000000000000600082015250565b6000615cd3600f83614550565b9150615cde82615c9d565b602082019050919050565b6000604082019050615cfe6000830184613e42565b8181036020830152615d0f81615cc6565b905092915050565b7f4141393020696e76616c69642062656e65666963696172790000000000000000600082015250565b6000615d4d601883614550565b9150615d5882615d17565b602082019050919050565b60006020820190508181036000830152615d7c81615d40565b9050919050565b7f41413931206661696c65642073656e6420746f2062656e656669636961727900600082015250565b6000615db9601f83614550565b9150615dc482615d83565b602082019050919050565b60006020820190508181036000830152615de881615dac565b9050919050565b6000608082019050615e046000830187613e42565b615e116020830186613efd565b615e1e6040830185613e42565b615e2b6060830184613e42565b95945050505050565b600061010082019050615e4a600083018b614b3a565b615e57602083018a613e42565b615e646040830189614139565b615e716060830188614139565b615e7e6080830187614139565b615e8b60a0830186613e42565b615e9860c0830185614139565b615ea560e0830184614139565b9998505050505050505050565b7f4141393320696e76616c6964207061796d6173746572416e6444617461000000600082015250565b6000615ee8601d83614550565b9150615ef382615eb2565b602082019050919050565b60006020820190508181036000830152615f1781615edb565b9050919050565b60006060820190508181036000830152615f38818661597a565b9050615f476020830185614139565b615f546040830184613e42565b949350505050565b600081519050615f6b81613b67565b92915050565b600060208284031215615f8757615f866139aa565b5b6000615f9584828501615f5c565b91505092915050565b7f4141323320726576657274656400000000000000000000000000000000000000600082015250565b6000615fd4600d83614550565b9150615fdf82615f9e565b602082019050919050565b6000606082019050615fff6000830185613e42565b818103602083015261601081615fc7565b905081810360408301526160248184614642565b90509392505050565b7f41413231206469646e2774207061792070726566756e64000000000000000000600082015250565b6000616063601783614550565b915061606e8261602d565b602082019050919050565b600060408201905061608e6000830184613e42565b818103602083015261609f81616056565b905092915050565b7f41413331207061796d6173746572206465706f73697420746f6f206c6f770000600082015250565b60006160dd601e83614550565b91506160e8826160a7565b602082019050919050565b60006040820190506161086000830184613e42565b8181036020830152616119816160d0565b905092915050565b600061613461612f84613a4a565b613a2f565b9050828152602081018484840111156161505761614f6139b9565b5b61615b848285614618565b509392505050565b600082601f830112616178576161776139b4565b5b8151616188848260208601616121565b91505092915050565b600080604083850312156161a8576161a76139aa565b5b600083015167ffffffffffffffff8111156161c6576161c56139af565b5b6161d285828601616163565b92505060206161e385828601615f5c565b9150509250929050565b7f4141333320726576657274656400000000000000000000000000000000000000600082015250565b6000616223600d83614550565b915061622e826161ed565b602082019050919050565b600060608201905061624e6000830185613e42565b818103602083015261625f81616216565b905081810360408301526162738184614642565b90509392505050565b7f41413336206f766572207061796d6173746572566572696669636174696f6e4760008201527f61734c696d697400000000000000000000000000000000000000000000000000602082015250565b60006162d8602783614550565b91506162e38261627c565b604082019050919050565b60006040820190506163036000830184613e42565b8181036020830152616314816162cb565b905092915050565b600080fd5b600080fd5b6000808585111561633a5761633961631c565b5b8386111561634b5761634a616321565b5b6001850283019150848603905094509492505050565b600082905092915050565b60007fffffffffffffffffffffffffffffffffffffffff00000000000000000000000082169050919050565b600082821b905092915050565b60006163b18383616361565b826163bc813561636c565b925060148210156163fc576163f77fffffffffffffffffffffffffffffffffffffffff00000000000000000000000083601403600802616398565b831692505b505092915050565b60007fffffffffffffffffffffffffffffffff0000000000000000000000000000000082169050919050565b600061643c8383616361565b826164478135616404565b92506010821015616487576164827fffffffffffffffffffffffffffffffff0000000000000000000000000000000083601003600802616398565b831692505b505092915050565b7f414131302073656e64657220616c726561647920636f6e737472756374656400600082015250565b60006164c5601f83614550565b91506164d08261648f565b602082019050919050565b60006040820190506164f06000830184613e42565b8181036020830152616501816164b8565b905092915050565b7f4141313320696e6974436f6465206661696c6564206f72204f4f470000000000600082015250565b600061653f601b83614550565b915061654a82616509565b602082019050919050565b600060408201905061656a6000830184613e42565b818103602083015261657b81616532565b905092915050565b7f4141313420696e6974436f6465206d7573742072657475726e2073656e646572600082015250565b60006165b9602083614550565b91506165c482616583565b602082019050919050565b60006040820190506165e46000830184613e42565b81810360208301526165f5816165ac565b905092915050565b7f4141313520696e6974436f6465206d757374206372656174652073656e646572600082015250565b6000616633602083614550565b915061663e826165fd565b602082019050919050565b600060408201905061665e6000830184613e42565b818103602083015261666f81616626565b905092915050565b600060408201905061668c6000830185614b3a565b6166996020830184614b3a565b939250505056fea2646970667358221220f6e7d5acc3b3ce47e8c4e79583caee84134eab4d0c55f3973f51a15d53351cdb64736f6c63430008170033608060405234801561001057600080fd5b50610342806100206000396000f3fe608060405234801561001057600080fd5b506004361061002b5760003560e01c8063570e1a3614610030575b600080fd5b61004a6004803603810190610045919061017b565b610060565b6040516100579190610209565b60405180910390f35b60008083836000906014926100779392919061022e565b9061008291906102ad565b60601c905060008484601490809261009c9392919061022e565b8080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f8201169050808301925050505050505090506000602060008351602085016000875af1905060005193508061010357600093505b50505092915050565b600080fd5b600080fd5b600080fd5b600080fd5b600080fd5b60008083601f84011261013b5761013a610116565b5b8235905067ffffffffffffffff8111156101585761015761011b565b5b60208301915083600182028301111561017457610173610120565b5b9250929050565b600080602083850312156101925761019161010c565b5b600083013567ffffffffffffffff8111156101b0576101af610111565b5b6101bc85828601610125565b92509250509250929050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b60006101f3826101c8565b9050919050565b610203816101e8565b82525050565b600060208201905061021e60008301846101fa565b92915050565b600080fd5b600080fd5b6000808585111561024257610241610224565b5b8386111561025357610252610229565b5b6001850283019150848603905094509492505050565b600082905092915050565b60007fffffffffffffffffffffffffffffffffffffffff00000000000000000000000082169050919050565b600082821b905092915050565b60006102b98383610269565b826102c48135610274565b92506014821015610304576102ff7fffffffffffffffffffffffffffffffffffffffff000000000000000000000000836014036008026102a0565b831692505b50509291505056fea264697066735822122050dbb7b87383c3f370ab6e7c31231f1967684cb78ec9da388509e2ca89e70f0a64736f6c63430008170033", + "r": "0x7ea6dafd6ca367c7adaabb4cdf92306ef034b3586a5ffbfb8c4cea202ee02371", + "s": "0x6d2ed0062c1c05afbabdd20bbdbbce52284753731b7fb4804228829d8619f260", + "yParity": "0x0", + "v": "0x0", + "hash": "0x8143bef9c4369a296fdd4e985467bc7f2e9d4ed6331e97988201a7e5c18e6618" + } + }, + "impersonated_sender": null + } + ], + "ommers": [] + }, + { + "header": { + "parentHash": "0x9cdb8aaba60547e8d92dd5cf406c32291e80a74b7048714f22b8ac06b6ca4e22", + "sha3Uncles": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", + "miner": "0x0000000000000000000000000000000000000000", + "stateRoot": "0xc280da9a57775a7520add6aa66798d3cbe010b671cfb721b58ee73547a67445d", + "transactionsRoot": "0x1a16b4c3506cf1df7de734a4e29b56e675b704d3fb81d7f6ce280fffda12b334", + "receiptsRoot": "0x13f38bfac4f328a7b8287f747295102524cbba6fcb7508ac5f41cf7a89540707", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "difficulty": "0x0", + "number": "0x4", + "gasLimit": "0x1c9c380", + "gasUsed": "0x143b63", + "timestamp": "0x67e150f4", + "extraData": "0x", + "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "nonce": "0x0000000000000000", + "baseFeePerGas": "0x2d81f0ba", + "withdrawalsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "blobGasUsed": "0x0", + "excessBlobGas": "0x0", + "parentBeaconBlockRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", + "requestsHash": "0xe3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + }, + "transactions": [ + { + "transaction": { + "EIP1559": { + "chainId": "0x539", + "nonce": "0x3", + "gas": "0x143b63", + "maxFeePerGas": "0x63f72bc9", + "maxPriorityFeePerGas": "0x1", + "to": null, + "value": "0x0", + "accessList": [], + "input": "0x608060405234801561001057600080fd5b5061171b806100206000396000f3fe608060405234801561001057600080fd5b50600436106100625760003560e01c8063414c3e3314610067578063a145832a14610083578063b99deb0e1461009f578063b9cf5249146100cf578063d3eddcc5146100ff578063ed4633671461011b575b600080fd5b610081600480360381019061007c9190610c7a565b610137565b005b61009d60048036038101906100989190610c7a565b610143565b005b6100b960048036038101906100b49190610d7d565b6107c3565b6040516100c69190610ef8565b60405180910390f35b6100e960048036038101906100e49190610f1a565b6109ac565b6040516100f69190610f75565b60405180910390f35b61011960048036038101906101149190610c7a565b6109db565b005b61013560048036038101906101309190610c7a565b6109e7565b005b50505050505050505050565b8561015a610150826109f3565b600160f81b6109fd565b610199576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161019090610fed565b60405180910390fd5b8660006101a582610a4e565b50509150506101b881600060f81b610a70565b6101f7576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016101ee9061107f565b60405180910390fd5b506000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600086815260200190815260200160002060009054906101000a900460ff1615610295576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161028c90611111565b60405180910390fd5b60016000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600087815260200190815260200160002060006101000a81548160ff02191690831515021790555036600061030a8989610ac1565b9150915060028282905014610354576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161034b906111a3565b60405180910390fd5b60006103608f8f6107c3565b9050806060015173ffffffffffffffffffffffffffffffffffffffff1683836000818110610391576103906111c3565b5b90506020028101906103a39190611201565b60000160208101906103b59190611229565b73ffffffffffffffffffffffffffffffffffffffff1614158061040257506000838360008181106103e9576103e86111c3565b5b90506020028101906103fb9190611201565b6020013514155b80610462575080608001518051906020012083836000818110610428576104276111c3565b5b905060200281019061043a9190611201565b80604001906104499190611256565b6040516104579291906112f8565b604051809103902014155b156104a2576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610499906113a9565b60405180910390fd5b806000015173ffffffffffffffffffffffffffffffffffffffff16838360018181106104d1576104d06111c3565b5b90506020028101906104e39190611201565b60000160208101906104f59190611229565b73ffffffffffffffffffffffffffffffffffffffff161415806105425750600083836001818110610529576105286111c3565b5b905060200281019061053b9190611201565b6020013514155b80610584575060448383600181811061055e5761055d6111c3565b5b90506020028101906105709190611201565b806040019061057f9190611256565b905014155b80610625575063a9059cbb60e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916838360018181106105c5576105c46111c3565b5b90506020028101906105d79190611201565b80604001906105e69190611256565b6000906004926105f8939291906113d3565b906106039190611452565b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614155b806106b45750806020015173ffffffffffffffffffffffffffffffffffffffff168383600181811061065a576106596111c3565b5b905060200281019061066c9190611201565b806040019061067b9190611256565b60049060249261068d939291906113d3565b9061069891906114b1565b60001c73ffffffffffffffffffffffffffffffffffffffff1614155b8061071757508060400151838360018181106106d3576106d26111c3565b5b90506020028101906106e59190611201565b80604001906106f49190611256565b602490604492610706939291906113d3565b9061071191906114b1565b60001c14155b15610757576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161074e906115a8565b60405180910390fd5b8673ffffffffffffffffffffffffffffffffffffffff16883373ffffffffffffffffffffffffffffffffffffffff167f76f83a16f9924b51c0c3ad67a44af3e517fbdec68ffa3729776df2ac0f03144060405160405180910390a4505050505050505050505050505050565b6107cb610ada565b605c838390501015610812576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108099061163a565b60405180910390fd5b8282600090601492610826939291906113d3565b906108319190611686565b60601c816000019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff1681525050828260149060289261087f939291906113d3565b9061088a9190611686565b60601c816020019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff168152505082826028906048926108d8939291906113d3565b906108e391906114b1565b60001c8160400181815250508282604890605c92610903939291906113d3565b9061090e9190611686565b60601c816060019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250508282605c90809261095b939291906113d3565b8080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f82011690508083019250505050505050816080018190525092915050565b60006020528160005260406000206020528060005260406000206000915091509054906101000a900460ff1681565b50505050505050505050565b50505050505050505050565b6000819050919050565b6000817effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916837effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614905092915050565b6000806000808493508460081b92508460301b91508460501b90509193509193565b6000817effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916837effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614905092915050565b3660008335840160208101925080359150509250929050565b6040518060a00160405280600073ffffffffffffffffffffffffffffffffffffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff16815260200160008152602001600073ffffffffffffffffffffffffffffffffffffffff168152602001606081525090565b600080fd5b600080fd5b600080fd5b600080fd5b600080fd5b60008083601f840112610b7a57610b79610b55565b5b8235905067ffffffffffffffff811115610b9757610b96610b5a565b5b602083019150836001820283011115610bb357610bb2610b5f565b5b9250929050565b6000819050919050565b610bcd81610bba565b8114610bd857600080fd5b50565b600081359050610bea81610bc4565b92915050565b610bf981610bba565b8114610c0457600080fd5b50565b600081359050610c1681610bf0565b92915050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000610c4782610c1c565b9050919050565b610c5781610c3c565b8114610c6257600080fd5b50565b600081359050610c7481610c4e565b92915050565b60008060008060008060008060008060e08b8d031215610c9d57610c9c610b4b565b5b60008b013567ffffffffffffffff811115610cbb57610cba610b50565b5b610cc78d828e01610b64565b9a509a505060208b013567ffffffffffffffff811115610cea57610ce9610b50565b5b610cf68d828e01610b64565b98509850506040610d098d828e01610bdb565b96505060608b013567ffffffffffffffff811115610d2a57610d29610b50565b5b610d368d828e01610b64565b95509550506080610d498d828e01610c07565b93505060a0610d5a8d828e01610c65565b92505060c0610d6b8d828e01610c65565b9150509295989b9194979a5092959850565b60008060208385031215610d9457610d93610b4b565b5b600083013567ffffffffffffffff811115610db257610db1610b50565b5b610dbe85828601610b64565b92509250509250929050565b610dd381610c3c565b82525050565b6000819050919050565b610dec81610dd9565b82525050565b600081519050919050565b600082825260208201905092915050565b60005b83811015610e2c578082015181840152602081019050610e11565b60008484015250505050565b6000601f19601f8301169050919050565b6000610e5482610df2565b610e5e8185610dfd565b9350610e6e818560208601610e0e565b610e7781610e38565b840191505092915050565b600060a083016000830151610e9a6000860182610dca565b506020830151610ead6020860182610dca565b506040830151610ec06040860182610de3565b506060830151610ed36060860182610dca565b5060808301518482036080860152610eeb8282610e49565b9150508091505092915050565b60006020820190508181036000830152610f128184610e82565b905092915050565b60008060408385031215610f3157610f30610b4b565b5b6000610f3f85828601610c65565b9250506020610f5085828601610c07565b9150509250929050565b60008115159050919050565b610f6f81610f5a565b82525050565b6000602082019050610f8a6000830184610f66565b92915050565b600082825260208201905092915050565b7f436176656174456e666f726365723a696e76616c69642d63616c6c2d74797065600082015250565b6000610fd7602083610f90565b9150610fe282610fa1565b602082019050919050565b6000602082019050818103600083015261100681610fca565b9050919050565b7f436176656174456e666f726365723a696e76616c69642d657865637574696f6e60008201527f2d74797065000000000000000000000000000000000000000000000000000000602082015250565b6000611069602583610f90565b91506110748261100d565b604082019050919050565b600060208201905081810360008301526110988161105c565b9050919050565b7f5370656369666963416374696f6e45524332305472616e73666572426174636860008201527f456e666f726365723a64656c65676174696f6e2d616c72656164792d75736564602082015250565b60006110fb604083610f90565b91506111068261109f565b604082019050919050565b6000602082019050818103600083015261112a816110ee565b9050919050565b7f5370656369666963416374696f6e45524332305472616e73666572426174636860008201527f456e666f726365723a696e76616c69642d62617463682d73697a650000000000602082015250565b600061118d603b83610f90565b915061119882611131565b604082019050919050565b600060208201905081810360008301526111bc81611180565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600080fd5b600080fd5b600080fd5b60008235600160600383360303811261121d5761121c6111f2565b5b80830191505092915050565b60006020828403121561123f5761123e610b4b565b5b600061124d84828501610c65565b91505092915050565b60008083356001602003843603038112611273576112726111f2565b5b80840192508235915067ffffffffffffffff821115611295576112946111f7565b5b6020830192506001820236038313156112b1576112b06111fc565b5b509250929050565b600081905092915050565b82818337600083830152505050565b60006112df83856112b9565b93506112ec8385846112c4565b82840190509392505050565b60006113058284866112d3565b91508190509392505050565b7f5370656369666963416374696f6e45524332305472616e73666572426174636860008201527f456e666f726365723a696e76616c69642d66697273742d7472616e736163746960208201527f6f6e000000000000000000000000000000000000000000000000000000000000604082015250565b6000611393604283610f90565b915061139e82611311565b606082019050919050565b600060208201905081810360008301526113c281611386565b9050919050565b600080fd5b600080fd5b600080858511156113e7576113e66113c9565b5b838611156113f8576113f76113ce565b5b6001850283019150848603905094509492505050565b600082905092915050565b60007fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b600082821b905092915050565b600061145e838361140e565b826114698135611419565b925060048210156114a9576114a47fffffffff0000000000000000000000000000000000000000000000000000000083600403600802611445565b831692505b505092915050565b60006114bd838361140e565b826114c88135610bba565b92506020821015611508576115037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff83602003600802611445565b831692505b505092915050565b7f5370656369666963416374696f6e45524332305472616e73666572426174636860008201527f456e666f726365723a696e76616c69642d7365636f6e642d7472616e7361637460208201527f696f6e0000000000000000000000000000000000000000000000000000000000604082015250565b6000611592604383610f90565b915061159d82611510565b606082019050919050565b600060208201905081810360008301526115c181611585565b9050919050565b7f5370656369666963416374696f6e45524332305472616e73666572426174636860008201527f456e666f726365723a696e76616c69642d7465726d732d6c656e677468000000602082015250565b6000611624603d83610f90565b915061162f826115c8565b604082019050919050565b6000602082019050818103600083015261165381611617565b9050919050565b60007fffffffffffffffffffffffffffffffffffffffff00000000000000000000000082169050919050565b6000611692838361140e565b8261169d813561165a565b925060148210156116dd576116d87fffffffffffffffffffffffffffffffffffffffff00000000000000000000000083601403600802611445565b831692505b50509291505056fea2646970667358221220bb45176bdb8ed7fb317c32e3295e9c2c5ef7b7344ac16b795cd46aff956325b064736f6c63430008170033", + "r": "0x596a664b572840e1c0ac93b09360eaefecfdc3ab8ec9a9eb74d60ac2a7a06e27", + "s": "0x6dd71e9e5742e0768dd93fb8aa3a539458b47287db7184eb3bb1be4853ed5245", + "yParity": "0x0", + "v": "0x0", + "hash": "0x92574096d598401cbf9b37ff4cd468c6e1eaeb0cc13d2e7327588e8be6c5af9b" + } + }, + "impersonated_sender": null + } + ], + "ommers": [] + }, + { + "header": { + "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "sha3Uncles": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", + "miner": "0x0000000000000000000000000000000000000000", + "stateRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", + "transactionsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "receiptsRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "difficulty": "0x0", + "number": "0x0", + "gasLimit": "0x1c9c380", + "gasUsed": "0x0", + "timestamp": "0x67e150f2", + "extraData": "0x", + "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "nonce": "0x0000000000000000", + "baseFeePerGas": "0x3b9aca00", + "withdrawalsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "blobGasUsed": "0x0", + "excessBlobGas": "0x0", + "parentBeaconBlockRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", + "requestsHash": "0xe3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + }, + "transactions": [], + "ommers": [] + }, + { + "header": { + "parentHash": "0x906d63b887e2dde832fec45ebb4edd648448e17419da605efdd9defc478a8885", + "sha3Uncles": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", + "miner": "0x0000000000000000000000000000000000000000", + "stateRoot": "0x6333628307855195b2922493cda443d4eef64096acdcd7056e3f5cd1303aa9ba", + "transactionsRoot": "0xc459790258527ecd6cede276c2389c2d2e994551ce925cfcfc34929363668b30", + "receiptsRoot": "0x4dc1112d55f9a2b30600151f692fb7fb913cb5f5ce4b4c3d738371b068ed2ec1", + "logsBloom": "0x00000000000000000000002000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000810000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000800000000000000000000000000008000000000000000000000000800000001400000000000000000020000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040", + "difficulty": "0x0", + "number": "0x3", + "gasLimit": "0x1c9c380", + "gasUsed": "0x40f07f", + "timestamp": "0x67e150f4", + "extraData": "0x", + "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "nonce": "0x0000000000000000", + "baseFeePerGas": "0x31fb95e4", + "withdrawalsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "blobGasUsed": "0x0", + "excessBlobGas": "0x0", + "parentBeaconBlockRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", + "requestsHash": "0xe3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + }, + "transactions": [ + { + "transaction": { + "EIP1559": { + "chainId": "0x539", + "nonce": "0x2", + "gas": "0x40f07f", + "maxFeePerGas": "0x6c1e46bf", + "maxPriorityFeePerGas": "0x1", + "to": null, + "value": "0x0", + "accessList": [], + "input": "0x6101c06040523073ffffffffffffffffffffffffffffffffffffffff166101609073ffffffffffffffffffffffffffffffffffffffff168152503480156200004657600080fd5b50604051620057443803806200574483398181016040528101906200006c9190620004f1565b81816040518060400160405280601981526020017f4549503737303253746174656c65737344656c654761746f72000000000000008152506040518060400160405280600181526020017f31000000000000000000000000000000000000000000000000000000000000008152508181620000f26000836200030260201b90919060201c565b6101208181525050620001106001826200030260201b90919060201c565b6101408181525050818051906020012060e08181525050808051906020012061010081815250504660a081815250506200014f6200035a60201b60201c565b608081815250503073ffffffffffffffffffffffffffffffffffffffff1660c08173ffffffffffffffffffffffffffffffffffffffff16815250505050601f82511115620001c9576040517f6b66bce400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b601f8151111562000206576040517f9203c9d000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8373ffffffffffffffffffffffffffffffffffffffff166101808173ffffffffffffffffffffffffffffffffffffffff16815250508273ffffffffffffffffffffffffffffffffffffffff166101a08173ffffffffffffffffffffffffffffffffffffffff16815250508373ffffffffffffffffffffffffffffffffffffffff167fb2e8eb88b584ae71ef4e854c10847f4d39bd93e52599f147bfb4dcc8de52014d60405160405180910390a28273ffffffffffffffffffffffffffffffffffffffff167fee8699dc0e27105da2653bdba54be0edcaadc3e33890a3ad705517ffe9bf0a9960405160405180910390a250505050505062000a88565b600060208351101562000328576200032083620003b760201b60201c565b905062000354565b826200033a836200042460201b60201c565b60000190816200034b9190620007b2565b5060ff60001b90505b92915050565b60007f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f60e0516101005146306040516020016200039c959493929190620008d6565b60405160208183030381529060405280519060200120905090565b600080829050601f815111156200040757826040517f305a27a9000000000000000000000000000000000000000000000000000000008152600401620003fe9190620009c2565b60405180910390fd5b805181620004159062000a18565b60001c1760001b915050919050565b6000819050919050565b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000620004608262000433565b9050919050565b6000620004748262000453565b9050919050565b620004868162000467565b81146200049257600080fd5b50565b600081519050620004a6816200047b565b92915050565b6000620004b98262000453565b9050919050565b620004cb81620004ac565b8114620004d757600080fd5b50565b600081519050620004eb81620004c0565b92915050565b600080604083850312156200050b576200050a6200042e565b5b60006200051b8582860162000495565b92505060206200052e85828601620004da565b9150509250929050565b600081519050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b60006002820490506001821680620005ba57607f821691505b602082108103620005d057620005cf62000572565b5b50919050565b60008190508160005260206000209050919050565b60006020601f8301049050919050565b600082821b905092915050565b6000600883026200063a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82620005fb565b620006468683620005fb565b95508019841693508086168417925050509392505050565b6000819050919050565b6000819050919050565b6000620006936200068d62000687846200065e565b62000668565b6200065e565b9050919050565b6000819050919050565b620006af8362000672565b620006c7620006be826200069a565b84845462000608565b825550505050565b600090565b620006de620006cf565b620006eb818484620006a4565b505050565b5b81811015620007135762000707600082620006d4565b600181019050620006f1565b5050565b601f82111562000762576200072c81620005d6565b6200073784620005eb565b8101602085101562000747578190505b6200075f6200075685620005eb565b830182620006f0565b50505b505050565b600082821c905092915050565b6000620007876000198460080262000767565b1980831691505092915050565b6000620007a2838362000774565b9150826002028217905092915050565b620007bd8262000538565b67ffffffffffffffff811115620007d957620007d862000543565b5b620007e58254620005a1565b620007f282828562000717565b600060209050601f8311600181146200082a576000841562000815578287015190505b62000821858262000794565b86555062000891565b601f1984166200083a86620005d6565b60005b8281101562000864578489015182556001820191506020850194506020810190506200083d565b8683101562000884578489015162000880601f89168262000774565b8355505b6001600288020188555050505b505050505050565b6000819050919050565b620008ae8162000899565b82525050565b620008bf816200065e565b82525050565b620008d08162000453565b82525050565b600060a082019050620008ed6000830188620008a3565b620008fc6020830187620008a3565b6200090b6040830186620008a3565b6200091a6060830185620008b4565b620009296080830184620008c5565b9695505050505050565b600082825260208201905092915050565b60005b838110156200096457808201518184015260208101905062000947565b60008484015250505050565b6000601f19601f8301169050919050565b60006200098e8262000538565b6200099a818562000933565b9350620009ac81856020860162000944565b620009b78162000970565b840191505092915050565b60006020820190508181036000830152620009de818462000981565b905092915050565b600081519050919050565b6000819050602082019050919050565b600062000a0f825162000899565b80915050919050565b600062000a2582620009e6565b8262000a3184620009f1565b905062000a3e8162000a01565b9250602082101562000a815762000a7c7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff83602003600802620005fb565b831692505b5050919050565b60805160a05160c05160e05161010051610120516101405161016051610180516101a051614b9862000bac60003960008181610b8c01528181610ce001528181610d8301528181610f7301528181611145015281816111d3015281816112c6015281816113850152818161154101528181611601015281816116a0015281816118af01528181611c8d01526120c2015260008181610e4201528181610ed2015281816110320152818161175f015281816119530152611fe201526000818161073f01528181610a5801528181610af101528181610c11015281816110c001528181611567015261211b0152600061257201526000612537015260006129f7015260006129d6015260006121ee015260006122440152600061226d0152614b986000f3fe6080604052600436106101c65760003560e01c806384b0196e116100f7578063d03c791411610095578063ea4d3c9b11610064578063ea4d3c9b1461066b578063ed8101b514610696578063f23a6e61146106d3578063ffa1ad7414610710576101cd565b8063d03c7914146105b7578063d087d288146105f4578063d691c9641461061f578063e9ae5c531461064f576101cd565b8063b0d691fe116100d1578063b0d691fe146104fb578063bc197c8114610526578063c399ec8814610563578063cef6d2091461058e576101cd565b806384b0196e14610474578063a3f4df7e146104a5578063acb8cc49146104d0576101cd565b80633ed01015116101645780634a58db191161013e5780634a58db19146103fa5780635c1c6dcd146104045780637f07bfdc1461042057806383ebb77114610449576101cd565b80633ed010151461036b578063445140b81461039457806349934047146103d1576101cd565b80631626ba7e116101a05780631626ba7e1461028957806319822f7c146102c65780632b3afd99146103035780633e1b08121461032e576101cd565b806301ffc9a7146101d257806306394d671461020f578063150b7a021461024c576101cd565b366101cd57005b600080fd5b3480156101de57600080fd5b506101f960048036038101906101f49190612f07565b61073b565b6040516102069190612f4f565b60405180910390f35b34801561021b57600080fd5b5061023660048036038101906102319190612f8f565b610a32565b6040516102439190612ff1565b60405180910390f35b34801561025857600080fd5b50610273600480360381019061026e91906131e6565b610a54565b6040516102809190613278565b60405180910390f35b34801561029557600080fd5b506102b060048036038101906102ab919061331f565b610aed565b6040516102bd9190613278565b60405180910390f35b3480156102d257600080fd5b506102ed60048036038101906102e8919061337f565b610b88565b6040516102fa91906133fd565b60405180910390f35b34801561030f57600080fd5b50610318610cb8565b6040516103259190612ff1565b60405180910390f35b34801561033a57600080fd5b5061035560048036038101906103509190613468565b610cdc565b60405161036291906133fd565b60405180910390f35b34801561037757600080fd5b50610392600480360381019061038d91906134b4565b610d81565b005b3480156103a057600080fd5b506103bb60048036038101906103b691906134fd565b610ece565b6040516103c89190612f4f565b60405180910390f35b3480156103dd57600080fd5b506103f860048036038101906103f391906134b4565b610f71565b005b6104026110be565b005b61041e60048036038101906104199190613549565b6111d1565b005b34801561042c57600080fd5b50610447600480360381019061044291906135d0565b6112c4565b005b34801561045557600080fd5b5061045e611414565b60405161046b9190612ff1565b60405180910390f35b34801561048057600080fd5b50610489611423565b60405161049c9796959493929190613797565b60405180910390f35b3480156104b157600080fd5b506104ba6114cd565b6040516104c7919061381b565b60405180910390f35b3480156104dc57600080fd5b506104e5611506565b6040516104f2919061381b565b60405180910390f35b34801561050757600080fd5b5061051061153f565b60405161051d919061389c565b60405180910390f35b34801561053257600080fd5b5061054d6004803603810190610548919061397a565b611563565b60405161055a9190613278565b60405180910390f35b34801561056f57600080fd5b506105786115fd565b60405161058591906133fd565b60405180910390f35b34801561059a57600080fd5b506105b560048036038101906105b09190613af5565b61169e565b005b3480156105c357600080fd5b506105de60048036038101906105d99190613bd5565b6117fa565b6040516105eb9190612f4f565b60405180910390f35b34801561060057600080fd5b506106096118ab565b60405161061691906133fd565b60405180910390f35b61063960048036038101906106349190613c02565b61194f565b6040516106469190613d79565b60405180910390f35b61066960048036038101906106649190613c02565b611c8b565b005b34801561067757600080fd5b50610680611fe0565b60405161068d9190613dbc565b60405180910390f35b3480156106a257600080fd5b506106bd60048036038101906106b89190612f8f565b612004565b6040516106ca9190612ff1565b60405180910390f35b3480156106df57600080fd5b506106fa60048036038101906106f59190613dd7565b612117565b6040516107079190613278565b60405180910390f35b34801561071c57600080fd5b506107256121b1565b604051610732919061381b565b60405180910390f35b60007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff163073ffffffffffffffffffffffffffffffffffffffff16036107c2576040517f9f03a02600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7fd691c964000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916148061088b57507f150b7a02000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b806108f357507f4e2312e0000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b8061095b57507f01ffc9a7000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b806109c357507f1626ba7e000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b80610a2b57507f39922547000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b9050919050565b6000610a4d610a3f6121ea565b610a4884612004565b6122a1565b9050919050565b60007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff163073ffffffffffffffffffffffffffffffffffffffff1603610adb576040517f9f03a02600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b63150b7a0260e01b9050949350505050565b60007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff163073ffffffffffffffffffffffffffffffffffffffff1603610b74576040517f9f03a02600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610b7f8484846122e2565b90509392505050565b60007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610c0f576040517fd663742a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff163073ffffffffffffffffffffffffffffffffffffffff1603610c94576040517f9f03a02600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610ca684610ca186610a32565b612385565b9050610cb182612406565b9392505050565b7fbc37962d8bd1d319c95199bdfda6d3f92baa8903a61b32d5f4ec1f4b36a3bc1881565b60007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff166335567e1a30846040518363ffffffff1660e01b8152600401610d39929190613e7d565b602060405180830381865afa158015610d56573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d7a9190613ebb565b9050919050565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614158015610e0957503073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614155b15610e40576040517f0796d94500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16633ed01015826040518263ffffffff1660e01b8152600401610e99919061425c565b600060405180830381600087803b158015610eb357600080fd5b505af1158015610ec7573d6000803e3d6000fd5b5050505050565b60007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16632d40d052836040518263ffffffff1660e01b8152600401610f299190612ff1565b602060405180830381865afa158015610f46573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f6a91906142aa565b9050919050565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614158015610ff957503073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614155b15611030576040517f0796d94500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff166349934047826040518263ffffffff1660e01b8152600401611089919061425c565b600060405180830381600087803b1580156110a357600080fd5b505af11580156110b7573d6000803e3d6000fd5b5050505050565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff163073ffffffffffffffffffffffffffffffffffffffff1603611143576040517f9f03a02600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663b760faf934306040518363ffffffff1660e01b815260040161119d91906142d7565b6000604051808303818588803b1580156111b657600080fd5b505af11580156111ca573d6000803e3d6000fd5b5050505050565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161415801561125957503073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614155b15611290576040517f0796d94500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6112c08160000160208101906112a691906142f2565b82602001358380604001906112bb919061432e565b6124f2565b5050565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161415801561134c57503073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614155b15611383576040517f0796d94500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663205c287883836040518363ffffffff1660e01b81526004016113de9291906143a0565b600060405180830381600087803b1580156113f857600080fd5b505af115801561140c573d6000803e3d6000fd5b505050505050565b600061141e6121ea565b905090565b60006060806000806000606061143761252e565b61143f612569565b46306000801b600067ffffffffffffffff8111156114605761145f6130bb565b5b60405190808252806020026020018201604052801561148e5781602001602082028036833780820191505090505b507f0f00000000000000000000000000000000000000000000000000000000000000959493929190965096509650965096509650965090919293949596565b6040518060400160405280601981526020017f4549503737303253746174656c65737344656c654761746f720000000000000081525081565b6040518060400160405280600181526020017f310000000000000000000000000000000000000000000000000000000000000081525081565b7f000000000000000000000000000000000000000000000000000000000000000081565b60007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff163073ffffffffffffffffffffffffffffffffffffffff16036115ea576040517f9f03a02600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b63bc197c8160e01b905095945050505050565b60007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b815260040161165891906142d7565b602060405180830381865afa158015611675573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116999190613ebb565b905090565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161415801561172657503073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614155b1561175d576040517f0796d94500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663cef6d2098787878787876040518763ffffffff1660e01b81526004016117c096959493929190614541565b600060405180830381600087803b1580156117da57600080fd5b505af11580156117ee573d6000803e3d6000fd5b50505050505050505050565b600080600080600061180b866125a4565b935093509350935061182184600060f81b6125c6565b80611836575061183584600160f81b6125c6565b5b8015611861575061184b83600060f81b612617565b80611860575061185f83600160f81b612617565b5b5b8015611877575061187682600060e01b612668565b5b80156118a05750600060501b69ffffffffffffffffffff19168169ffffffffffffffffffff1916145b945050505050919050565b60007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff166335567e1a3060006040518363ffffffff1660e01b81526004016119099291906145ce565b602060405180830381865afa158015611926573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061194a9190613ebb565b905090565b60607f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146119d6576040517f1a4b3a0400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000806119e2866125a4565b5050915091506119f682600160f81b6125c6565b15611a9957366000611a0887876126b3565b91509150611a1a83600060f81b612617565b15611a3057611a2982826126cc565b9450611a92565b611a3e83600160f81b612617565b15611a5457611a4d82826127bd565b9450611a91565b826040517f1187dc06000000000000000000000000000000000000000000000000000000008152600401611a889190614618565b60405180910390fd5b5b5050611c82565b611aa782600060f81b6125c6565b15611c4457600080366000611abc898961290e565b9350935093509350600167ffffffffffffffff811115611adf57611ade6130bb565b5b604051908082528060200260200182016040528015611b1257816020015b6060815260200190600190039081611afd5790505b5096506000611b2586600060f81b612617565b15611b5a57611b36858585856124f2565b88600081518110611b4a57611b49614633565b5b6020026020010181905250611c3a565b611b6886600160f81b612617565b15611bfc57611b798585858561297c565b89600081518110611b8d57611b8c614633565b5b60200260200101819052819250505080611bf7577fe723f28f104e46b47fd3531f3608374ac226bcf3ddda334a23a266453e0efdb7600089600081518110611bd857611bd7614633565b5b6020026020010151604051611bee9291906146dd565b60405180910390a15b611c39565b856040517f1187dc06000000000000000000000000000000000000000000000000000000008152600401611c309190614618565b60405180910390fd5b5b5050505050611c81565b816040517fb96fcfe4000000000000000000000000000000000000000000000000000000008152600401611c78919061471c565b60405180910390fd5b5b50509392505050565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614158015611d1357503073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614155b15611d4a576040517f0796d94500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600080611d56856125a4565b505091509150611d6a82600160f81b6125c6565b15611e0b57366000611d7c86866126b3565b91509150611d8e83600060f81b612617565b15611da357611d9d82826126cc565b50611e04565b611db183600160f81b612617565b15611dc657611dc082826127bd565b50611e03565b826040517f1187dc06000000000000000000000000000000000000000000000000000000008152600401611dfa9190614618565b60405180910390fd5b5b5050611fd9565b611e1982600060f81b6125c6565b15611f9b57600080366000611e2e888861290e565b9350935093509350611e4485600060f81b612617565b15611e5b57611e55848484846124f2565b50611f92565b611e6985600160f81b612617565b15611f54576000600167ffffffffffffffff811115611e8b57611e8a6130bb565b5b604051908082528060200260200182016040528015611ebe57816020015b6060815260200190600190039081611ea95790505b5090506000611ecf8686868661297c565b83600081518110611ee357611ee2614633565b5b60200260200101819052819250505080611f4d577fe723f28f104e46b47fd3531f3608374ac226bcf3ddda334a23a266453e0efdb7600083600081518110611f2e57611f2d614633565b5b6020026020010151604051611f449291906146dd565b60405180910390a15b5050611f91565b846040517f1187dc06000000000000000000000000000000000000000000000000000000008152600401611f889190614618565b60405180910390fd5b5b50505050611fd8565b816040517fb96fcfe4000000000000000000000000000000000000000000000000000000008152600401611fcf919061471c565b60405180910390fd5b5b5050505050565b7f000000000000000000000000000000000000000000000000000000000000000081565b60007fbc37962d8bd1d319c95199bdfda6d3f92baa8903a61b32d5f4ec1f4b36a3bc1882600001602081019061203a91906142f2565b836020013584806040019061204f919061432e565b60405161205d929190614767565b6040518091039020858060600190612075919061432e565b604051612083929190614767565b604051809103902086608001358760a001358860c00135898060e001906120aa919061432e565b6040516120b8929190614767565b60405180910390207f00000000000000000000000000000000000000000000000000000000000000006040516020016120fa9a99989796959493929190614780565b604051602081830303815290604052805190602001209050919050565b60007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff163073ffffffffffffffffffffffffffffffffffffffff160361219e576040517f9f03a02600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b63f23a6e6160e01b905095945050505050565b6040518060400160405280600581526020017f312e332e3000000000000000000000000000000000000000000000000000000081525081565b60007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff163073ffffffffffffffffffffffffffffffffffffffff1614801561226657507f000000000000000000000000000000000000000000000000000000000000000046145b15612293577f0000000000000000000000000000000000000000000000000000000000000000905061229e565b61229b6129b1565b90505b90565b60006040517f190100000000000000000000000000000000000000000000000000000000000081528360028201528260228201526042812091505092915050565b60003073ffffffffffffffffffffffffffffffffffffffff166123498585858080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f82011690508083019250505050505050612a47565b73ffffffffffffffffffffffffffffffffffffffff160361237357631626ba7e60e01b905061237e565b63ffffffff60e01b90505b9392505050565b6000806123a2838580610100019061239d919061432e565b6122e2565b9050631626ba7e60e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916817bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916036123fa576000915050612400565b60019150505b92915050565b600081146124ef5760003373ffffffffffffffffffffffffffffffffffffffff16827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9060405161245690614842565b600060405180830381858888f193505050503d8060008114612494576040519150601f19603f3d011682016040523d82523d6000602084013e612499565b606091505b505090503373ffffffffffffffffffffffffffffffffffffffff167fa427c7d47f24d01b170779a7600b1d4c0d7cdbabaa0f19c4f0e6182053ffc93183836040516124e5929190614857565b60405180910390a2505b50565b6060604051905081838237600038838387895af1612513573d6000823e3d81fd5b3d8152602081013d6000823e3d810160405250949350505050565b606061256460007f0000000000000000000000000000000000000000000000000000000000000000612a7390919063ffffffff16565b905090565b606061259f60017f0000000000000000000000000000000000000000000000000000000000000000612a7390919063ffffffff16565b905090565b6000806000808493508460081b92508460301b91508460501b90509193509193565b6000817effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916837effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614905092915050565b6000817effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916837effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614905092915050565b6000817bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916837bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614905092915050565b3660008335840160208101925080359150509250929050565b606060008383905090508067ffffffffffffffff8111156126f0576126ef6130bb565b5b60405190808252806020026020018201604052801561272357816020015b606081526020019060019003908161270e5790505b50915060005b818110156127b5573685858381811061274557612744614633565b5b90506020028101906127579190614880565b905061278981600001602081019061276f91906142f2565b8260200135838060400190612784919061432e565b6124f2565b84838151811061279c5761279b614633565b5b6020026020010181905250508080600101915050612729565b505092915050565b606060008383905090508067ffffffffffffffff8111156127e1576127e06130bb565b5b60405190808252806020026020018201604052801561281457816020015b60608152602001906001900390816127ff5790505b50915060005b81811015612906573685858381811061283657612835614633565b5b90506020028101906128489190614880565b9050600061287c82600001602081019061286291906142f2565b8360200135848060400190612877919061432e565b61297c565b86858151811061288f5761288e614633565b5b602002602001018190528192505050806128f7577fe723f28f104e46b47fd3531f3608374ac226bcf3ddda334a23a266453e0efdb7838685815181106128d8576128d7614633565b5b60200260200101516040516128ee9291906148a8565b60405180910390a15b5050808060010191505061281a565b505092915050565b6000803660008585600090601492612928939291906148e2565b906129339190614961565b60601c9350858560149060349261294c939291906148e2565b9061295791906149c0565b60001c92508585603490809261296f939291906148e2565b9150915092959194509250565b600060606040519050828482376000388483888a5af11591503d8152602081013d6000823e3d81016040525094509492505050565b60007f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f7f00000000000000000000000000000000000000000000000000000000000000007f00000000000000000000000000000000000000000000000000000000000000004630604051602001612a2c959493929190614a1f565b60405160208183030381529060405280519060200120905090565b600080600080612a578686612b23565b925092509250612a678282612b7f565b82935050505092915050565b606060ff60001b8314612a9057612a8983612ce3565b9050612b1d565b818054612a9c90614aa1565b80601f0160208091040260200160405190810160405280929190818152602001828054612ac890614aa1565b8015612b155780601f10612aea57610100808354040283529160200191612b15565b820191906000526020600020905b815481529060010190602001808311612af857829003601f168201915b505050505090505b92915050565b60008060006041845103612b685760008060006020870151925060408701519150606087015160001a9050612b5a88828585612d57565b955095509550505050612b78565b60006002855160001b9250925092505b9250925092565b60006003811115612b9357612b92614ad2565b5b826003811115612ba657612ba5614ad2565b5b0315612cdf5760016003811115612bc057612bbf614ad2565b5b826003811115612bd357612bd2614ad2565b5b03612c0a576040517ff645eedf00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60026003811115612c1e57612c1d614ad2565b5b826003811115612c3157612c30614ad2565b5b03612c76578060001c6040517ffce698f7000000000000000000000000000000000000000000000000000000008152600401612c6d91906133fd565b60405180910390fd5b600380811115612c8957612c88614ad2565b5b826003811115612c9c57612c9b614ad2565b5b03612cde57806040517fd78bce0c000000000000000000000000000000000000000000000000000000008152600401612cd59190612ff1565b60405180910390fd5b5b5050565b60606000612cf083612e4b565b90506000602067ffffffffffffffff811115612d0f57612d0e6130bb565b5b6040519080825280601f01601f191660200182016040528015612d415781602001600182028036833780820191505090505b5090508181528360208201528092505050919050565b60008060007f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08460001c1115612d97576000600385925092509250612e41565b600060018888888860405160008152602001604052604051612dbc9493929190614b1d565b6020604051602081039080840390855afa158015612dde573d6000803e3d6000fd5b505050602060405103519050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603612e3257600060016000801b93509350935050612e41565b8060008060001b935093509350505b9450945094915050565b60008060ff8360001c169050601f811115612e92576040517fb3512b0c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80915050919050565b6000604051905090565b600080fd5b600080fd5b60007fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b612ee481612eaf565b8114612eef57600080fd5b50565b600081359050612f0181612edb565b92915050565b600060208284031215612f1d57612f1c612ea5565b5b6000612f2b84828501612ef2565b91505092915050565b60008115159050919050565b612f4981612f34565b82525050565b6000602082019050612f646000830184612f40565b92915050565b600080fd5b60006101208284031215612f8657612f85612f6a565b5b81905092915050565b600060208284031215612fa557612fa4612ea5565b5b600082013567ffffffffffffffff811115612fc357612fc2612eaa565b5b612fcf84828501612f6f565b91505092915050565b6000819050919050565b612feb81612fd8565b82525050565b60006020820190506130066000830184612fe2565b92915050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b60006130378261300c565b9050919050565b6130478161302c565b811461305257600080fd5b50565b6000813590506130648161303e565b92915050565b6000819050919050565b61307d8161306a565b811461308857600080fd5b50565b60008135905061309a81613074565b92915050565b600080fd5b600080fd5b6000601f19601f8301169050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6130f3826130aa565b810181811067ffffffffffffffff82111715613112576131116130bb565b5b80604052505050565b6000613125612e9b565b905061313182826130ea565b919050565b600067ffffffffffffffff821115613151576131506130bb565b5b61315a826130aa565b9050602081019050919050565b82818337600083830152505050565b600061318961318484613136565b61311b565b9050828152602081018484840111156131a5576131a46130a5565b5b6131b0848285613167565b509392505050565b600082601f8301126131cd576131cc6130a0565b5b81356131dd848260208601613176565b91505092915050565b60008060008060808587031215613200576131ff612ea5565b5b600061320e87828801613055565b945050602061321f87828801613055565b93505060406132308782880161308b565b925050606085013567ffffffffffffffff81111561325157613250612eaa565b5b61325d878288016131b8565b91505092959194509250565b61327281612eaf565b82525050565b600060208201905061328d6000830184613269565b92915050565b61329c81612fd8565b81146132a757600080fd5b50565b6000813590506132b981613293565b92915050565b600080fd5b600080fd5b60008083601f8401126132df576132de6130a0565b5b8235905067ffffffffffffffff8111156132fc576132fb6132bf565b5b602083019150836001820283011115613318576133176132c4565b5b9250929050565b60008060006040848603121561333857613337612ea5565b5b6000613346868287016132aa565b935050602084013567ffffffffffffffff81111561336757613366612eaa565b5b613373868287016132c9565b92509250509250925092565b60008060006060848603121561339857613397612ea5565b5b600084013567ffffffffffffffff8111156133b6576133b5612eaa565b5b6133c286828701612f6f565b93505060206133d3868287016132aa565b92505060406133e48682870161308b565b9150509250925092565b6133f78161306a565b82525050565b600060208201905061341260008301846133ee565b92915050565b600077ffffffffffffffffffffffffffffffffffffffffffffffff82169050919050565b61344581613418565b811461345057600080fd5b50565b6000813590506134628161343c565b92915050565b60006020828403121561347e5761347d612ea5565b5b600061348c84828501613453565b91505092915050565b600060c082840312156134ab576134aa612f6a565b5b81905092915050565b6000602082840312156134ca576134c9612ea5565b5b600082013567ffffffffffffffff8111156134e8576134e7612eaa565b5b6134f484828501613495565b91505092915050565b60006020828403121561351357613512612ea5565b5b6000613521848285016132aa565b91505092915050565b6000606082840312156135405761353f612f6a565b5b81905092915050565b60006020828403121561355f5761355e612ea5565b5b600082013567ffffffffffffffff81111561357d5761357c612eaa565b5b6135898482850161352a565b91505092915050565b600061359d8261300c565b9050919050565b6135ad81613592565b81146135b857600080fd5b50565b6000813590506135ca816135a4565b92915050565b600080604083850312156135e7576135e6612ea5565b5b60006135f5858286016135bb565b92505060206136068582860161308b565b9150509250929050565b60007fff0000000000000000000000000000000000000000000000000000000000000082169050919050565b61364581613610565b82525050565b600081519050919050565b600082825260208201905092915050565b60005b8381101561368557808201518184015260208101905061366a565b60008484015250505050565b600061369c8261364b565b6136a68185613656565b93506136b6818560208601613667565b6136bf816130aa565b840191505092915050565b6136d38161302c565b82525050565b600081519050919050565b600082825260208201905092915050565b6000819050602082019050919050565b61370e8161306a565b82525050565b60006137208383613705565b60208301905092915050565b6000602082019050919050565b6000613744826136d9565b61374e81856136e4565b9350613759836136f5565b8060005b8381101561378a5781516137718882613714565b975061377c8361372c565b92505060018101905061375d565b5085935050505092915050565b600060e0820190506137ac600083018a61363c565b81810360208301526137be8189613691565b905081810360408301526137d28188613691565b90506137e160608301876133ee565b6137ee60808301866136ca565b6137fb60a0830185612fe2565b81810360c083015261380d8184613739565b905098975050505050505050565b600060208201905081810360008301526138358184613691565b905092915050565b6000819050919050565b600061386261385d6138588461300c565b61383d565b61300c565b9050919050565b600061387482613847565b9050919050565b600061388682613869565b9050919050565b6138968161387b565b82525050565b60006020820190506138b1600083018461388d565b92915050565b600067ffffffffffffffff8211156138d2576138d16130bb565b5b602082029050602081019050919050565b60006138f66138f1846138b7565b61311b565b90508083825260208201905060208402830185811115613919576139186132c4565b5b835b81811015613942578061392e888261308b565b84526020840193505060208101905061391b565b5050509392505050565b600082601f830112613961576139606130a0565b5b81356139718482602086016138e3565b91505092915050565b600080600080600060a0868803121561399657613995612ea5565b5b60006139a488828901613055565b95505060206139b588828901613055565b945050604086013567ffffffffffffffff8111156139d6576139d5612eaa565b5b6139e28882890161394c565b935050606086013567ffffffffffffffff811115613a0357613a02612eaa565b5b613a0f8882890161394c565b925050608086013567ffffffffffffffff811115613a3057613a2f612eaa565b5b613a3c888289016131b8565b9150509295509295909350565b60008083601f840112613a5f57613a5e6130a0565b5b8235905067ffffffffffffffff811115613a7c57613a7b6132bf565b5b602083019150836020820283011115613a9857613a976132c4565b5b9250929050565b60008083601f840112613ab557613ab46130a0565b5b8235905067ffffffffffffffff811115613ad257613ad16132bf565b5b602083019150836020820283011115613aee57613aed6132c4565b5b9250929050565b60008060008060008060608789031215613b1257613b11612ea5565b5b600087013567ffffffffffffffff811115613b3057613b2f612eaa565b5b613b3c89828a01613a49565b9650965050602087013567ffffffffffffffff811115613b5f57613b5e612eaa565b5b613b6b89828a01613a9f565b9450945050604087013567ffffffffffffffff811115613b8e57613b8d612eaa565b5b613b9a89828a01613a49565b92509250509295509295509295565b613bb281612fd8565b8114613bbd57600080fd5b50565b600081359050613bcf81613ba9565b92915050565b600060208284031215613beb57613bea612ea5565b5b6000613bf984828501613bc0565b91505092915050565b600080600060408486031215613c1b57613c1a612ea5565b5b6000613c2986828701613bc0565b935050602084013567ffffffffffffffff811115613c4a57613c49612eaa565b5b613c56868287016132c9565b92509250509250925092565b600081519050919050565b600082825260208201905092915050565b6000819050602082019050919050565b600081519050919050565b600082825260208201905092915050565b6000613cb582613c8e565b613cbf8185613c99565b9350613ccf818560208601613667565b613cd8816130aa565b840191505092915050565b6000613cef8383613caa565b905092915050565b6000602082019050919050565b6000613d0f82613c62565b613d198185613c6d565b935083602082028501613d2b85613c7e565b8060005b85811015613d675784840389528151613d488582613ce3565b9450613d5383613cf7565b925060208a01995050600181019050613d2f565b50829750879550505050505092915050565b60006020820190508181036000830152613d938184613d04565b905092915050565b6000613da682613869565b9050919050565b613db681613d9b565b82525050565b6000602082019050613dd16000830184613dad565b92915050565b600080600080600060a08688031215613df357613df2612ea5565b5b6000613e0188828901613055565b9550506020613e1288828901613055565b9450506040613e238882890161308b565b9350506060613e348882890161308b565b925050608086013567ffffffffffffffff811115613e5557613e54612eaa565b5b613e61888289016131b8565b9150509295509295909350565b613e7781613418565b82525050565b6000604082019050613e9260008301856136ca565b613e9f6020830184613e6e565b9392505050565b600081519050613eb581613074565b92915050565b600060208284031215613ed157613ed0612ea5565b5b6000613edf84828501613ea6565b91505092915050565b6000613ef76020840184613055565b905092915050565b613f088161302c565b82525050565b6000613f1d60208401846132aa565b905092915050565b613f2e81612fd8565b82525050565b600080fd5b600080fd5b600080fd5b60008083356001602003843603038112613f6057613f5f613f3e565b5b83810192508235915060208301925067ffffffffffffffff821115613f8857613f87613f34565b5b602082023603831315613f9e57613f9d613f39565b5b509250929050565b600082825260208201905092915050565b6000819050919050565b60008083356001602003843603038112613fde57613fdd613f3e565b5b83810192508235915060208301925067ffffffffffffffff82111561400657614005613f34565b5b60018202360383131561401c5761401b613f39565b5b509250929050565b60006140308385613c99565b935061403d838584613167565b614046836130aa565b840190509392505050565b6000606083016140646000840184613ee8565b6140716000860182613eff565b5061407f6020840184613fc1565b8583036020870152614092838284614024565b925050506140a36040840184613fc1565b85830360408701526140b6838284614024565b925050508091505092915050565b60006140d08383614051565b905092915050565b6000823560016060038336030381126140f4576140f3613f3e565b5b82810191505092915050565b6000602082019050919050565b60006141198385613fa6565b93508360208402850161412b84613fb7565b8060005b8781101561416f57848403895261414682846140d8565b61415085826140c4565b945061415b83614100565b925060208a0199505060018101905061412f565b50829750879450505050509392505050565b6000614190602084018461308b565b905092915050565b600060c083016141ab6000840184613ee8565b6141b86000860182613eff565b506141c66020840184613ee8565b6141d36020860182613eff565b506141e16040840184613f0e565b6141ee6040860182613f25565b506141fc6060840184613f43565b858303606087015261420f83828461410d565b925050506142206080840184614181565b61422d6080860182613705565b5061423b60a0840184613fc1565b85830360a087015261424e838284614024565b925050508091505092915050565b600060208201905081810360008301526142768184614198565b905092915050565b61428781612f34565b811461429257600080fd5b50565b6000815190506142a48161427e565b92915050565b6000602082840312156142c0576142bf612ea5565b5b60006142ce84828501614295565b91505092915050565b60006020820190506142ec60008301846136ca565b92915050565b60006020828403121561430857614307612ea5565b5b600061431684828501613055565b91505092915050565b600080fd5b600080fd5b600080fd5b6000808335600160200384360303811261434b5761434a61431f565b5b80840192508235915067ffffffffffffffff82111561436d5761436c614324565b5b60208301925060018202360383131561438957614388614329565b5b509250929050565b61439a81613592565b82525050565b60006040820190506143b56000830185614391565b6143c260208301846133ee565b9392505050565b6000819050919050565b60006143e0848484614024565b90509392505050565b6000602082019050919050565b60006144028385613c6d565b935083602084028501614414846143c9565b8060005b8781101561445a57848403895261442f8284613fc1565b61443a8682846143d3565b9550614445846143e9565b935060208b019a505050600181019050614418565b50829750879450505050509392505050565b600082825260208201905092915050565b6000819050919050565b600061449282612fd8565b9050919050565b6144a281614487565b82525050565b60006144b48383614499565b60208301905092915050565b60006144cf6020840184613bc0565b905092915050565b6000602082019050919050565b60006144f0838561446c565b93506144fb8261447d565b8060005b858110156145345761451182846144c0565b61451b88826144a8565b9750614526836144d7565b9250506001810190506144ff565b5085925050509392505050565b6000606082019050818103600083015261455c81888a6143f6565b905081810360208301526145718186886144e4565b905081810360408301526145868184866143f6565b9050979650505050505050565b6000819050919050565b60006145b86145b36145ae84614593565b61383d565b613418565b9050919050565b6145c88161459d565b82525050565b60006040820190506145e360008301856136ca565b6145f060208301846145bf565b9392505050565b600061460282613610565b9050919050565b614612816145f7565b82525050565b600060208201905061462d6000830184614609565b92915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600061467d61467861467384614593565b61383d565b61306a565b9050919050565b61468d81614662565b82525050565b600082825260208201905092915050565b60006146af82613c8e565b6146b98185614693565b93506146c9818560208601613667565b6146d2816130aa565b840191505092915050565b60006040820190506146f26000830185614684565b818103602083015261470481846146a4565b90509392505050565b614716816145f7565b82525050565b6000602082019050614731600083018461470d565b92915050565b600081905092915050565b600061474e8385614737565b935061475b838584613167565b82840190509392505050565b6000614774828486614742565b91508190509392505050565b600061014082019050614796600083018d612fe2565b6147a3602083018c6136ca565b6147b0604083018b6133ee565b6147bd606083018a612fe2565b6147ca6080830189612fe2565b6147d760a0830188612fe2565b6147e460c08301876133ee565b6147f160e0830186612fe2565b6147ff610100830185612fe2565b61480d61012083018461388d565b9b9a5050505050505050505050565b50565b600061482c600083614737565b91506148378261481c565b600082019050919050565b600061484d8261481f565b9150819050919050565b600060408201905061486c60008301856133ee565b6148796020830184612f40565b9392505050565b60008235600160600383360303811261489c5761489b61431f565b5b80830191505092915050565b60006040820190506148bd60008301856133ee565b81810360208301526148cf81846146a4565b90509392505050565b600080fd5b600080fd5b600080858511156148f6576148f56148d8565b5b83861115614907576149066148dd565b5b6001850283019150848603905094509492505050565b600082905092915050565b60007fffffffffffffffffffffffffffffffffffffffff00000000000000000000000082169050919050565b600082821b905092915050565b600061496d838361491d565b826149788135614928565b925060148210156149b8576149b37fffffffffffffffffffffffffffffffffffffffff00000000000000000000000083601403600802614954565b831692505b505092915050565b60006149cc838361491d565b826149d78135612fd8565b92506020821015614a1757614a127fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff83602003600802614954565b831692505b505092915050565b600060a082019050614a346000830188612fe2565b614a416020830187612fe2565b614a4e6040830186612fe2565b614a5b60608301856133ee565b614a6860808301846136ca565b9695505050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b60006002820490506001821680614ab957607f821691505b602082108103614acc57614acb614a72565b5b50919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b600060ff82169050919050565b614b1781614b01565b82525050565b6000608082019050614b326000830187612fe2565b614b3f6020830186614b0e565b614b4c6040830185612fe2565b614b596060830184612fe2565b9594505050505056fea2646970667358221220844c650b3d2c0aceaf7c108a1ec343abb8963e1bdf5c88d4f28ea4bbdce3ff1a64736f6c63430008170033000000000000000000000000663f3ad617193148711d28f5334ee4ed070166020000000000000000000000002e983a1ba5e8b38aaaec4b440b9ddcfbf72e15d1", + "r": "0xd8d0863b2634643fd12c349262baa59411a37040cf2d4facb043d2987054d1bb", + "s": "0x58fd29e6f7e10206ad7d43963e8d31450bac6e3538b9dcd0bc032e0b79ebdaee", + "yParity": "0x0", + "v": "0x0", + "hash": "0xdbc70e14bbeac0578540243bda21bd2ea8e38bbad034323f32866d1cf0c0e5a2" + } + }, + "impersonated_sender": null + } + ], + "ommers": [] + }, + { + "header": { + "parentHash": "0x44e32f9912f9c4d2377161f3f997ec0771cf8ac9532c71728b0bdbb103d7cedd", + "sha3Uncles": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", + "miner": "0x0000000000000000000000000000000000000000", + "stateRoot": "0x9c753e1effdc8ccf3d5e93cfc062463499fbae76aff231273d59f59b217a28a0", + "transactionsRoot": "0xc51ef9921af2dca51491904fa952c2bb91ee1c8a35cef654ea4aa3470e45a161", + "receiptsRoot": "0xdc4e7499fa0f8ce7eae9982723c1076831cb0dadc52cd5b7b5a4b46816b879c0", + "logsBloom": "0x00000000000000000002000000000000000000004000000000800000004000000000000000000000000000000000000000000000000000000000001000000020000000000000000000000000000000000001000000000020000000000000000000000800020000000000000000000800000000000000000000000000000000400000000000000000000000000000000000080000000000000001000000000000000000000000000800000000000000000000000000000000000000000000000000000000008040001000000000000000000000000000000000000200000020000000000000000000000000000000000001000000000000000000000000000000", + "difficulty": "0x0", + "number": "0x1", + "gasLimit": "0x1c9c380", + "gasUsed": "0x3a8613", + "timestamp": "0x67e150f3", + "extraData": "0x", + "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "nonce": "0x0000000000000000", + "baseFeePerGas": "0x3b9aca00", + "withdrawalsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "blobGasUsed": "0x0", + "excessBlobGas": "0x0", + "parentBeaconBlockRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", + "requestsHash": "0xe3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + }, + "transactions": [ + { + "transaction": { + "EIP1559": { + "chainId": "0x539", + "nonce": "0x0", + "gas": "0x3a8613", + "maxFeePerGas": "0x77359401", + "maxPriorityFeePerGas": "0x1", + "to": null, + "value": "0x0", + "accessList": [], + "input": "0x6101606040523480156200001257600080fd5b5060405162004f4b38038062004f4b8339818101604052810190620000389190620005cd565b6040518060400160405280601181526020017f44656c65676174696f6e4d616e616765720000000000000000000000000000008152506040518060400160405280600181526020017f310000000000000000000000000000000000000000000000000000000000000081525082600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16036200011a5760006040517f1e4fbdf700000000000000000000000000000000000000000000000000000000815260040162000111919062000610565b60405180910390fd5b6200012b81620002d260201b60201c565b506000600160146101000a81548160ff0219169083151502179055506200015d6002836200030b60201b90919060201c565b61012081815250506200017b6003826200030b60201b90919060201c565b6101408181525050818051906020012060e08181525050808051906020012061010081815250504660a08181525050620001ba6200036360201b60201c565b608081815250503073ffffffffffffffffffffffffffffffffffffffff1660c08173ffffffffffffffffffffffffffffffffffffffff16815250505050600062000209620003c060201b60201c565b90503073ffffffffffffffffffffffffffffffffffffffff16817f04a46d9007577c7ff1e513b900545162ec25d25991ae3dc60cf26ec01a84806d6040518060400160405280601181526020017f44656c65676174696f6e4d616e616765720000000000000000000000000000008152506040518060400160405280600181526020017f310000000000000000000000000000000000000000000000000000000000000081525046604051620002c293929190620006e2565b60405180910390a3505062000bb7565b600160006101000a81549073ffffffffffffffffffffffffffffffffffffffff021916905562000308816200042860201b60201c565b50565b600060208351101562000331576200032983620004ec60201b60201c565b90506200035d565b8262000343836200055960201b60201c565b600001908162000354919062000992565b5060ff60001b90505b92915050565b60007f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f60e051610100514630604051602001620003a595949392919062000a94565b60405160208183030381529060405280519060200120905090565b600060c05173ffffffffffffffffffffffffffffffffffffffff163073ffffffffffffffffffffffffffffffffffffffff1614801562000401575060a05146145b156200041257608051905062000425565b620004226200036360201b60201c565b90505b90565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050816000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a35050565b600080829050601f815111156200053c57826040517f305a27a900000000000000000000000000000000000000000000000000000000815260040162000533919062000af1565b60405180910390fd5b8051816200054a9062000b47565b60001c1760001b915050919050565b6000819050919050565b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000620005958262000568565b9050919050565b620005a78162000588565b8114620005b357600080fd5b50565b600081519050620005c7816200059c565b92915050565b600060208284031215620005e657620005e562000563565b5b6000620005f684828501620005b6565b91505092915050565b6200060a8162000588565b82525050565b6000602082019050620006276000830184620005ff565b92915050565b600081519050919050565b600082825260208201905092915050565b60005b83811015620006695780820151818401526020810190506200064c565b60008484015250505050565b6000601f19601f8301169050919050565b600062000693826200062d565b6200069f818562000638565b9350620006b181856020860162000649565b620006bc8162000675565b840191505092915050565b6000819050919050565b620006dc81620006c7565b82525050565b60006060820190508181036000830152620006fe818662000686565b9050818103602083015262000714818562000686565b9050620007256040830184620006d1565b949350505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b60006002820490506001821680620007a457607f821691505b602082108103620007ba57620007b96200075c565b5b50919050565b60008190508160005260206000209050919050565b60006020601f8301049050919050565b600082821b905092915050565b600060088302620008247fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82620007e5565b620008308683620007e5565b95508019841693508086168417925050509392505050565b6000819050919050565b6000620008736200086d6200086784620006c7565b62000848565b620006c7565b9050919050565b6000819050919050565b6200088f8362000852565b620008a76200089e826200087a565b848454620007f2565b825550505050565b600090565b620008be620008af565b620008cb81848462000884565b505050565b5b81811015620008f357620008e7600082620008b4565b600181019050620008d1565b5050565b601f82111562000942576200090c81620007c0565b6200091784620007d5565b8101602085101562000927578190505b6200093f6200093685620007d5565b830182620008d0565b50505b505050565b600082821c905092915050565b6000620009676000198460080262000947565b1980831691505092915050565b600062000982838362000954565b9150826002028217905092915050565b6200099d826200062d565b67ffffffffffffffff811115620009b957620009b86200072d565b5b620009c582546200078b565b620009d2828285620008f7565b600060209050601f83116001811462000a0a5760008415620009f5578287015190505b62000a01858262000974565b86555062000a71565b601f19841662000a1a86620007c0565b60005b8281101562000a445784890151825560018201915060208501945060208101905062000a1d565b8683101562000a64578489015162000a60601f89168262000954565b8355505b6001600288020188555050505b505050505050565b6000819050919050565b62000a8e8162000a79565b82525050565b600060a08201905062000aab600083018862000a83565b62000aba602083018762000a83565b62000ac9604083018662000a83565b62000ad86060830185620006d1565b62000ae76080830184620005ff565b9695505050505050565b6000602082019050818103600083015262000b0d818462000686565b905092915050565b600081519050919050565b6000819050602082019050919050565b600062000b3e825162000a79565b80915050919050565b600062000b548262000b15565b8262000b608462000b20565b905062000b6d8162000b30565b9250602082101562000bb05762000bab7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff83602003600802620007e5565b831692505b5050919050565b60805160a05160c05160e05161010051610120516101405161433962000c1260003960006122aa0152600061226f015260006125ac0152600061258b01526000612151015260006121a7015260006121d001526143396000f3fe608060405234801561001057600080fd5b506004361061012c5760003560e01c806383ebb771116100ad578063acb8cc4911610071578063acb8cc49146102c9578063cef6d209146102e7578063e30c397814610303578063f2fde38b14610321578063ffa1ad741461033d5761012c565b806383ebb771146102415780638456cb591461025f57806384b0196e146102695780638da5cb5b1461028d578063a3f4df7e146102ab5761012c565b806358909ebc116100f457806358909ebc146101c15780635c975abb146101df57806366134607146101fd578063715018a61461022d57806379ba5097146102375761012c565b80631b13cac2146101315780632d40d0521461014f5780633ed010151461017f5780633f4ba83a1461019b57806349934047146101a5575b600080fd5b61013961035b565b6040516101469190612b0a565b60405180910390f35b61016960048036038101906101649190612b65565b610382565b6040516101769190612bad565b60405180910390f35b61019960048036038101906101949190612bec565b6103a2565b005b6101a3610539565b005b6101bf60048036038101906101ba9190612bec565b61054b565b005b6101c96106e2565b6040516101d69190612c76565b60405180910390f35b6101e76106e8565b6040516101f49190612bad565b60405180910390f35b61021760048036038101906102129190612bec565b6106ff565b6040516102249190612b0a565b60405180910390f35b61023561071a565b005b61023f61072e565b005b6102496107bd565b6040516102569190612b0a565b60405180910390f35b6102676107cc565b005b6102716107de565b6040516102849796959493929190612e33565b60405180910390f35b610295610888565b6040516102a29190612c76565b60405180910390f35b6102b36108b1565b6040516102c09190612eb7565b60405180910390f35b6102d16108ea565b6040516102de9190612eb7565b60405180910390f35b61030160048036038101906102fc9190612f94565b610923565b005b61030b611e9f565b6040516103189190612c76565b60405180910390f35b61033b60048036038101906103369190613074565b611ec9565b005b610345611f76565b6040516103529190612eb7565b60405180910390f35b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60001b81565b60046020528060005260406000206000915054906101000a900460ff1681565b8060200160208101906103b59190613074565b3373ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161461041a576040517fb9f0f17100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000610425836106ff565b90506004600082815260200190815260200160002060009054906101000a900460ff1661047e576040517ff2a5f75a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006004600083815260200190815260200160002060006101000a81548160ff0219169083151502179055508260000160208101906104bd9190613074565b73ffffffffffffffffffffffffffffffffffffffff168360200160208101906104e69190613074565b73ffffffffffffffffffffffffffffffffffffffff16827f3feadce88fc1b49db633a56fd5307ed6ee18734df83bcc4011daa720c9cd95f18660405161052c9190613461565b60405180910390a4505050565b610541611faf565b610549612036565b565b80602001602081019061055e9190613074565b3373ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16146105c3576040517fb9f0f17100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006105ce836106ff565b90506004600082815260200190815260200160002060009054906101000a900460ff1615610627576040517e5ecddb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60016004600083815260200190815260200160002060006101000a81548160ff0219169083151502179055508260000160208101906106669190613074565b73ffffffffffffffffffffffffffffffffffffffff1683602001602081019061068f9190613074565b73ffffffffffffffffffffffffffffffffffffffff16827fea589ba9473ee1fe77d352c7ed919747715a5d22931b972de9b02a907c66d5dd866040516106d59190613461565b60405180910390a4505050565b610a1181565b6000600160149054906101000a900460ff16905090565b60006107138261070e90613803565b612099565b9050919050565b610722611faf565b61072c6000612114565b565b6000610738612145565b90508073ffffffffffffffffffffffffffffffffffffffff16610759611e9f565b73ffffffffffffffffffffffffffffffffffffffff16146107b157806040517f118cdaa70000000000000000000000000000000000000000000000000000000081526004016107a89190612c76565b60405180910390fd5b6107ba81612114565b50565b60006107c761214d565b905090565b6107d4611faf565b6107dc612204565b565b6000606080600080600060606107f2612266565b6107fa6122a1565b46306000801b600067ffffffffffffffff81111561081b5761081a613488565b5b6040519080825280602002602001820160405280156108495781602001602082028036833780820191505090505b507f0f00000000000000000000000000000000000000000000000000000000000000959493929190965096509650965096509650965090919293949596565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b6040518060400160405280601181526020017f44656c65676174696f6e4d616e6167657200000000000000000000000000000081525081565b6040518060400160405280600181526020017f310000000000000000000000000000000000000000000000000000000000000081525081565b61092b6122dc565b600086869050905082829050811415806109485750848490508114155b1561097f576040517f1bcaf69f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008167ffffffffffffffff81111561099b5761099a613488565b5b6040519080825280602002602001820160405280156109ce57816020015b60608152602001906001900390816109b95790505b50905060008267ffffffffffffffff8111156109ed576109ec613488565b5b604051908082528060200260200182016040528015610a2057816020015b6060815260200190600190039081610a0b5790505b50905060005b838110156111b65760008a8a83818110610a4357610a42613816565b5b9050602002810190610a559190613854565b810190610a629190613998565b90506000815103610b4d57600067ffffffffffffffff811115610a8857610a87613488565b5b604051908082528060200260200182016040528015610ac157816020015b610aae612a8c565b815260200190600190039081610aa65790505b50848381518110610ad557610ad4613816565b5b6020026020010181905250600067ffffffffffffffff811115610afb57610afa613488565b5b604051908082528060200260200182016040528015610b295781602001602082028036833780820191505090505b50838381518110610b3d57610b3c613816565b5b60200260200101819052506111aa565b80848381518110610b6157610b60613816565b5b60200260200101819052506000815167ffffffffffffffff811115610b8957610b88613488565b5b604051908082528060200260200182016040528015610bb75781602001602082028036833780820191505090505b50905080848481518110610bce57610bcd613816565b5b60200260200101819052503373ffffffffffffffffffffffffffffffffffffffff1682600081518110610c0457610c03613816565b5b60200260200101516000015173ffffffffffffffffffffffffffffffffffffffff1614158015610c815750610a1173ffffffffffffffffffffffffffffffffffffffff1682600081518110610c5c57610c5b613816565b5b60200260200101516000015173ffffffffffffffffffffffffffffffffffffffff1614155b15610cb8576040517fb586360400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b8251811015610f1d576000838281518110610cd957610cd8613816565b5b60200260200101519050610cec81612099565b838381518110610cff57610cfe613816565b5b6020026020010181815250506000816020015173ffffffffffffffffffffffffffffffffffffffff163b03610dd9576000610d68610d5e610d3e6107bd565b868681518110610d5157610d50613816565b5b602002602001015161231d565b8360a0015161235e565b9050816020015173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614610dd3576040517f3db6791c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50610f11565b6000610e06610de66107bd565b858581518110610df957610df8613816565b5b602002602001015161231d565b90506000826020015173ffffffffffffffffffffffffffffffffffffffff16631626ba7e838560a001516040518363ffffffff1660e01b8152600401610e4d929190613a36565b602060405180830381865afa158015610e6a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e8e9190613abe565b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19169050631626ba7e60e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19168114610f0e576040517f155ff42700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50505b50806001019050610cbb565b5060005b82518110156111a75760046000838381518110610f4157610f40613816565b5b6020026020010151815260200190815260200160002060009054906101000a900460ff1615610f9c576040517f05baa05200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60018351610faa9190613b1a565b81146111215781600182610fbe9190613b4e565b81518110610fcf57610fce613816565b5b6020026020010151838281518110610fea57610fe9613816565b5b6020026020010151604001511461102d576040517fded4370e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008360018361103d9190613b4e565b8151811061104e5761104d613816565b5b6020026020010151600001519050610a1173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16141580156110e457508073ffffffffffffffffffffffffffffffffffffffff168483815181106110bf576110be613816565b5b60200260200101516020015173ffffffffffffffffffffffffffffffffffffffff1614155b1561111b576040517fb586360400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5061119c565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60001b83828151811061115857611157613816565b5b6020026020010151604001511461119b576040517fded4370e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5b806001019050610f21565b50505b50806001019050610a26565b5060005b838110156113fb5760008382815181106111d7576111d6613816565b5b60200260200101515111156113f05760005b8382815181106111fc576111fb613816565b5b6020026020010151518110156113ee57600084838151811061122157611220613816565b5b6020026020010151828151811061123b5761123a613816565b5b602002602001015160600151905060005b81518110156113e157600082828151811061126a57611269613816565b5b60200260200101516000015190508073ffffffffffffffffffffffffffffffffffffffff1663414c3e338484815181106112a7576112a6613816565b5b6020026020010151602001518585815181106112c6576112c5613816565b5b6020026020010151604001518f8f8a8181106112e5576112e4613816565b5b905060200201358e8e8b8181106112ff576112fe613816565b5b90506020028101906113119190613854565b8c8c8151811061132457611323613816565b5b60200260200101518b8151811061133e5761133d613816565b5b60200260200101518e8d8151811061135957611358613816565b5b60200260200101518c8151811061137357611372613816565b5b602002602001015160200151336040518963ffffffff1660e01b81526004016113a3989796959493929190613bd0565b600060405180830381600087803b1580156113bd57600080fd5b505af11580156113d1573d6000803e3d6000fd5b505050505080600101905061124c565b50508060010190506111e9565b505b8060010190506111ba565b5060005b83811015611a8c57600083828151811061141c5761141b613816565b5b602002602001015151036114f1573373ffffffffffffffffffffffffffffffffffffffff1663d691c96489898481811061145957611458613816565b5b9050602002013588888581811061147357611472613816565b5b90506020028101906114859190613854565b6040518463ffffffff1660e01b81526004016114a393929190613c56565b6000604051808303816000875af11580156114c2573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f820116820180604052508101906114eb9190613dd9565b50611a81565b60005b83828151811061150757611506613816565b5b6020026020010151518110156116f957600084838151811061152c5761152b613816565b5b6020026020010151828151811061154657611545613816565b5b602002602001015160600151905060005b81518110156116ec57600082828151811061157557611574613816565b5b60200260200101516000015190508073ffffffffffffffffffffffffffffffffffffffff1663a145832a8484815181106115b2576115b1613816565b5b6020026020010151602001518585815181106115d1576115d0613816565b5b6020026020010151604001518f8f8a8181106115f0576115ef613816565b5b905060200201358e8e8b81811061160a57611609613816565b5b905060200281019061161c9190613854565b8c8c8151811061162f5761162e613816565b5b60200260200101518b8151811061164957611648613816565b5b60200260200101518e8d8151811061166457611663613816565b5b60200260200101518c8151811061167e5761167d613816565b5b602002602001015160200151336040518963ffffffff1660e01b81526004016116ae989796959493929190613bd0565b600060405180830381600087803b1580156116c857600080fd5b505af11580156116dc573d6000803e3d6000fd5b5050505050806001019050611557565b50508060010190506114f4565b5082818151811061170d5761170c613816565b5b6020026020010151600184838151811061172a57611729613816565b5b60200260200101515161173d9190613b1a565b8151811061174e5761174d613816565b5b60200260200101516020015173ffffffffffffffffffffffffffffffffffffffff1663d691c96489898481811061178857611787613816565b5b905060200201358888858181106117a2576117a1613816565b5b90506020028101906117b49190613854565b6040518463ffffffff1660e01b81526004016117d293929190613c56565b6000604051808303816000875af11580156117f1573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f8201168201806040525081019061181a9190613dd9565b5060008382815181106118305761182f613816565b5b60200260200101515190505b6000811115611a7f57600084838151811061185a57611859613816565b5b602002602001015160018361186f9190613b1a565b815181106118805761187f613816565b5b60200260200101516060015190506000815190505b6000811115611a6c576000826001836118ae9190613b1a565b815181106118bf576118be613816565b5b60200260200101516000015190508073ffffffffffffffffffffffffffffffffffffffff1663d3eddcc5846001856118f79190613b1a565b8151811061190857611907613816565b5b602002602001015160200151856001866119229190613b1a565b8151811061193357611932613816565b5b6020026020010151604001518f8f8a81811061195257611951613816565b5b905060200201358e8e8b81811061196c5761196b613816565b5b905060200281019061197e9190613854565b8c8c8151811061199157611990613816565b5b602002602001015160018c6119a69190613b1a565b815181106119b7576119b6613816565b5b60200260200101518e8d815181106119d2576119d1613816565b5b602002602001015160018d6119e79190613b1a565b815181106119f8576119f7613816565b5b602002602001015160200151336040518963ffffffff1660e01b8152600401611a28989796959493929190613bd0565b600060405180830381600087803b158015611a4257600080fd5b505af1158015611a56573d6000803e3d6000fd5b505050505080611a6590613e22565b9050611895565b505080611a7890613e22565b905061183c565b505b8060010190506113ff565b5060005b83811015611d2d576000838281518110611aad57611aac613816565b5b6020026020010151511115611d22576000838281518110611ad157611ad0613816565b5b60200260200101515190505b6000811115611d20576000848381518110611afb57611afa613816565b5b6020026020010151600183611b109190613b1a565b81518110611b2157611b20613816565b5b60200260200101516060015190506000815190505b6000811115611d0d57600082600183611b4f9190613b1a565b81518110611b6057611b5f613816565b5b60200260200101516000015190508073ffffffffffffffffffffffffffffffffffffffff1663ed46336784600185611b989190613b1a565b81518110611ba957611ba8613816565b5b60200260200101516020015185600186611bc39190613b1a565b81518110611bd457611bd3613816565b5b6020026020010151604001518f8f8a818110611bf357611bf2613816565b5b905060200201358e8e8b818110611c0d57611c0c613816565b5b9050602002810190611c1f9190613854565b8c8c81518110611c3257611c31613816565b5b602002602001015160018c611c479190613b1a565b81518110611c5857611c57613816565b5b60200260200101518e8d81518110611c7357611c72613816565b5b602002602001015160018d611c889190613b1a565b81518110611c9957611c98613816565b5b602002602001015160200151336040518963ffffffff1660e01b8152600401611cc9989796959493929190613bd0565b600060405180830381600087803b158015611ce357600080fd5b505af1158015611cf7573d6000803e3d6000fd5b505050505080611d0690613e22565b9050611b36565b505080611d1990613e22565b9050611add565b505b806001019050611a90565b5060005b83811015611e93576000838281518110611d4e57611d4d613816565b5b6020026020010151511115611e885760005b838281518110611d7357611d72613816565b5b602002602001015151811015611e86573373ffffffffffffffffffffffffffffffffffffffff16848381518110611dad57611dac613816565b5b60200260200101516001868581518110611dca57611dc9613816565b5b602002602001015151611ddd9190613b1a565b81518110611dee57611ded613816565b5b60200260200101516020015173ffffffffffffffffffffffffffffffffffffffff167f40dadaa36c6c2e3d7317e24757451ffb2d603d875f0ad5e92c5dd156573b1873868581518110611e4457611e43613816565b5b60200260200101518481518110611e5e57611e5d613816565b5b6020026020010151604051611e73919061401c565b60405180910390a3806001019050611d60565b505b806001019050611d31565b50505050505050505050565b6000600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b611ed1611faf565b80600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508073ffffffffffffffffffffffffffffffffffffffff16611f31610888565b73ffffffffffffffffffffffffffffffffffffffff167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b6040518060400160405280600581526020017f312e332e3000000000000000000000000000000000000000000000000000000081525081565b611fb7612145565b73ffffffffffffffffffffffffffffffffffffffff16611fd5610888565b73ffffffffffffffffffffffffffffffffffffffff161461203457611ff8612145565b6040517f118cdaa700000000000000000000000000000000000000000000000000000000815260040161202b9190612c76565b60405180910390fd5b565b61203e61238a565b6000600160146101000a81548160ff0219169083151502179055507f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa612082612145565b60405161208f9190612c76565b60405180910390a1565b6000807f88c1d2ecf185adf710588203a5f263f0ff61be0d33da39792cde19ba9aa4331e8360000151846020015185604001516120d987606001516123ca565b87608001516040516020016120f39695949392919061403e565b60405160208183030381529060405290508080519060200120915050919050565b600160006101000a81549073ffffffffffffffffffffffffffffffffffffffff0219169055612142816124a2565b50565b600033905090565b60007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff163073ffffffffffffffffffffffffffffffffffffffff161480156121c957507f000000000000000000000000000000000000000000000000000000000000000046145b156121f6577f00000000000000000000000000000000000000000000000000000000000000009050612201565b6121fe612566565b90505b90565b61220c6122dc565b60018060146101000a81548160ff0219169083151502179055507f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a25861224f612145565b60405161225c9190612c76565b60405180910390a1565b606061229c60027f00000000000000000000000000000000000000000000000000000000000000006125fc90919063ffffffff16565b905090565b60606122d760037f00000000000000000000000000000000000000000000000000000000000000006125fc90919063ffffffff16565b905090565b6122e46106e8565b1561231b576040517fd93c066500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b565b60006040517f190100000000000000000000000000000000000000000000000000000000000081528360028201528260228201526042812091505092915050565b60008060008061236e86866126ac565b92509250925061237e8282612708565b82935050505092915050565b6123926106e8565b6123c8576040517f8dfc202b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b565b600080825167ffffffffffffffff8111156123e8576123e7613488565b5b6040519080825280602002602001820160405280156124165781602001602082028036833780820191505090505b50905060005b83518110156124725761244884828151811061243b5761243a613816565b5b602002602001015161286c565b82828151811061245b5761245a613816565b5b60200260200101818152505080600101905061241c565b50806040516020016124849190614157565b60405160208183030381529060405280519060200120915050919050565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050816000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a35050565b60007f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f7f00000000000000000000000000000000000000000000000000000000000000007f000000000000000000000000000000000000000000000000000000000000000046306040516020016125e195949392919061416e565b60405160208183030381529060405280519060200120905090565b606060ff60001b831461261957612612836128d4565b90506126a6565b818054612625906141f0565b80601f0160208091040260200160405190810160405280929190818152602001828054612651906141f0565b801561269e5780601f106126735761010080835404028352916020019161269e565b820191906000526020600020905b81548152906001019060200180831161268157829003601f168201915b505050505090505b92915050565b600080600060418451036126f15760008060006020870151925060408701519150606087015160001a90506126e388828585612948565b955095509550505050612701565b60006002855160001b9250925092505b9250925092565b6000600381111561271c5761271b614221565b5b82600381111561272f5761272e614221565b5b0315612868576001600381111561274957612748614221565b5b82600381111561275c5761275b614221565b5b03612793576040517ff645eedf00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600260038111156127a7576127a6614221565b5b8260038111156127ba576127b9614221565b5b036127ff578060001c6040517ffce698f70000000000000000000000000000000000000000000000000000000081526004016127f69190614250565b60405180910390fd5b60038081111561281257612811614221565b5b82600381111561282557612824614221565b5b0361286757806040517fd78bce0c00000000000000000000000000000000000000000000000000000000815260040161285e9190612b0a565b60405180910390fd5b5b5050565b6000807f80ad7e1b04ee6d994a125f4714ca0720908bd80ed16063ec8aee4b88e9253e2d83600001518460200151805190602001206040516020016128b39392919061426b565b60405160208183030381529060405290508080519060200120915050919050565b606060006128e183612a3c565b90506000602067ffffffffffffffff811115612900576128ff613488565b5b6040519080825280601f01601f1916602001820160405280156129325781602001600182028036833780820191505090505b5090508181528360208201528092505050919050565b60008060007f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08460001c1115612988576000600385925092509250612a32565b6000600188888888604051600081526020016040526040516129ad94939291906142be565b6020604051602081039080840390855afa1580156129cf573d6000803e3d6000fd5b505050602060405103519050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603612a2357600060016000801b93509350935050612a32565b8060008060001b935093509350505b9450945094915050565b60008060ff8360001c169050601f811115612a83576040517fb3512b0c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80915050919050565b6040518060c00160405280600073ffffffffffffffffffffffffffffffffffffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff168152602001600080191681526020016060815260200160008152602001606081525090565b6000819050919050565b612b0481612af1565b82525050565b6000602082019050612b1f6000830184612afb565b92915050565b6000604051905090565b600080fd5b600080fd5b612b4281612af1565b8114612b4d57600080fd5b50565b600081359050612b5f81612b39565b92915050565b600060208284031215612b7b57612b7a612b2f565b5b6000612b8984828501612b50565b91505092915050565b60008115159050919050565b612ba781612b92565b82525050565b6000602082019050612bc26000830184612b9e565b92915050565b600080fd5b600060c08284031215612be357612be2612bc8565b5b81905092915050565b600060208284031215612c0257612c01612b2f565b5b600082013567ffffffffffffffff811115612c2057612c1f612b34565b5b612c2c84828501612bcd565b91505092915050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000612c6082612c35565b9050919050565b612c7081612c55565b82525050565b6000602082019050612c8b6000830184612c67565b92915050565b60007fff0000000000000000000000000000000000000000000000000000000000000082169050919050565b612cc681612c91565b82525050565b600081519050919050565b600082825260208201905092915050565b60005b83811015612d06578082015181840152602081019050612ceb565b60008484015250505050565b6000601f19601f8301169050919050565b6000612d2e82612ccc565b612d388185612cd7565b9350612d48818560208601612ce8565b612d5181612d12565b840191505092915050565b6000819050919050565b612d6f81612d5c565b82525050565b600081519050919050565b600082825260208201905092915050565b6000819050602082019050919050565b612daa81612d5c565b82525050565b6000612dbc8383612da1565b60208301905092915050565b6000602082019050919050565b6000612de082612d75565b612dea8185612d80565b9350612df583612d91565b8060005b83811015612e26578151612e0d8882612db0565b9750612e1883612dc8565b925050600181019050612df9565b5085935050505092915050565b600060e082019050612e48600083018a612cbd565b8181036020830152612e5a8189612d23565b90508181036040830152612e6e8188612d23565b9050612e7d6060830187612d66565b612e8a6080830186612c67565b612e9760a0830185612afb565b81810360c0830152612ea98184612dd5565b905098975050505050505050565b60006020820190508181036000830152612ed18184612d23565b905092915050565b600080fd5b600080fd5b600080fd5b60008083601f840112612efe57612efd612ed9565b5b8235905067ffffffffffffffff811115612f1b57612f1a612ede565b5b602083019150836020820283011115612f3757612f36612ee3565b5b9250929050565b60008083601f840112612f5457612f53612ed9565b5b8235905067ffffffffffffffff811115612f7157612f70612ede565b5b602083019150836020820283011115612f8d57612f8c612ee3565b5b9250929050565b60008060008060008060608789031215612fb157612fb0612b2f565b5b600087013567ffffffffffffffff811115612fcf57612fce612b34565b5b612fdb89828a01612ee8565b9650965050602087013567ffffffffffffffff811115612ffe57612ffd612b34565b5b61300a89828a01612f3e565b9450945050604087013567ffffffffffffffff81111561302d5761302c612b34565b5b61303989828a01612ee8565b92509250509295509295509295565b61305181612c55565b811461305c57600080fd5b50565b60008135905061306e81613048565b92915050565b60006020828403121561308a57613089612b2f565b5b60006130988482850161305f565b91505092915050565b60006130b0602084018461305f565b905092915050565b6130c181612c55565b82525050565b60006130d66020840184612b50565b905092915050565b6130e781612af1565b82525050565b600080fd5b600080fd5b600080fd5b60008083356001602003843603038112613119576131186130f7565b5b83810192508235915060208301925067ffffffffffffffff821115613141576131406130ed565b5b602082023603831315613157576131566130f2565b5b509250929050565b600082825260208201905092915050565b6000819050919050565b60008083356001602003843603038112613197576131966130f7565b5b83810192508235915060208301925067ffffffffffffffff8211156131bf576131be6130ed565b5b6001820236038313156131d5576131d46130f2565b5b509250929050565b600082825260208201905092915050565b82818337600083830152505050565b600061320983856131dd565b93506132168385846131ee565b61321f83612d12565b840190509392505050565b60006060830161323d60008401846130a1565b61324a60008601826130b8565b50613258602084018461317a565b858303602087015261326b8382846131fd565b9250505061327c604084018461317a565b858303604087015261328f8382846131fd565b925050508091505092915050565b60006132a9838361322a565b905092915050565b6000823560016060038336030381126132cd576132cc6130f7565b5b82810191505092915050565b6000602082019050919050565b60006132f2838561315f565b93508360208402850161330484613170565b8060005b8781101561334857848403895261331f82846132b1565b613329858261329d565b9450613334836132d9565b925060208a01995050600181019050613308565b50829750879450505050509392505050565b61336381612d5c565b811461336e57600080fd5b50565b6000813590506133808161335a565b92915050565b60006133956020840184613371565b905092915050565b600060c083016133b060008401846130a1565b6133bd60008601826130b8565b506133cb60208401846130a1565b6133d860208601826130b8565b506133e660408401846130c7565b6133f360408601826130de565b5061340160608401846130fc565b85830360608701526134148382846132e6565b925050506134256080840184613386565b6134326080860182612da1565b5061344060a084018461317a565b85830360a08701526134538382846131fd565b925050508091505092915050565b6000602082019050818103600083015261347b818461339d565b905092915050565b600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6134c082612d12565b810181811067ffffffffffffffff821117156134df576134de613488565b5b80604052505050565b60006134f2612b25565b90506134fe82826134b7565b919050565b600080fd5b600067ffffffffffffffff82111561352357613522613488565b5b602082029050602081019050919050565b600080fd5b600067ffffffffffffffff82111561355457613553613488565b5b61355d82612d12565b9050602081019050919050565b600061357d61357884613539565b6134e8565b90508281526020810184848401111561359957613598613534565b5b6135a48482856131ee565b509392505050565b600082601f8301126135c1576135c0612ed9565b5b81356135d184826020860161356a565b91505092915050565b6000606082840312156135f0576135ef613483565b5b6135fa60606134e8565b9050600061360a8482850161305f565b600083015250602082013567ffffffffffffffff81111561362e5761362d613503565b5b61363a848285016135ac565b602083015250604082013567ffffffffffffffff81111561365e5761365d613503565b5b61366a848285016135ac565b60408301525092915050565b600061368961368484613508565b6134e8565b905080838252602082019050602084028301858111156136ac576136ab612ee3565b5b835b818110156136f357803567ffffffffffffffff8111156136d1576136d0612ed9565b5b8086016136de89826135da565b855260208501945050506020810190506136ae565b5050509392505050565b600082601f83011261371257613711612ed9565b5b8135613722848260208601613676565b91505092915050565b600060c0828403121561374157613740613483565b5b61374b60c06134e8565b9050600061375b8482850161305f565b600083015250602061376f8482850161305f565b602083015250604061378384828501612b50565b604083015250606082013567ffffffffffffffff8111156137a7576137a6613503565b5b6137b3848285016136fd565b60608301525060806137c784828501613371565b60808301525060a082013567ffffffffffffffff8111156137eb576137ea613503565b5b6137f7848285016135ac565b60a08301525092915050565b600061380f368361372b565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600080fd5b600080fd5b600080fd5b6000808335600160200384360303811261387157613870613845565b5b80840192508235915067ffffffffffffffff8211156138935761389261384a565b5b6020830192506001820236038313156138af576138ae61384f565b5b509250929050565b600067ffffffffffffffff8211156138d2576138d1613488565b5b602082029050602081019050919050565b60006138f66138f1846138b7565b6134e8565b9050808382526020820190506020840283018581111561391957613918612ee3565b5b835b8181101561396057803567ffffffffffffffff81111561393e5761393d612ed9565b5b80860161394b898261372b565b8552602085019450505060208101905061391b565b5050509392505050565b600082601f83011261397f5761397e612ed9565b5b813561398f8482602086016138e3565b91505092915050565b6000602082840312156139ae576139ad612b2f565b5b600082013567ffffffffffffffff8111156139cc576139cb612b34565b5b6139d88482850161396a565b91505092915050565b600081519050919050565b600082825260208201905092915050565b6000613a08826139e1565b613a1281856139ec565b9350613a22818560208601612ce8565b613a2b81612d12565b840191505092915050565b6000604082019050613a4b6000830185612afb565b8181036020830152613a5d81846139fd565b90509392505050565b60007fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b613a9b81613a66565b8114613aa657600080fd5b50565b600081519050613ab881613a92565b92915050565b600060208284031215613ad457613ad3612b2f565b5b6000613ae284828501613aa9565b91505092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000613b2582612d5c565b9150613b3083612d5c565b9250828203905081811115613b4857613b47613aeb565b5b92915050565b6000613b5982612d5c565b9150613b6483612d5c565b9250828201905080821115613b7c57613b7b613aeb565b5b92915050565b6000613b8d82612af1565b9050919050565b613b9d81613b82565b82525050565b6000613baf83856139ec565b9350613bbc8385846131ee565b613bc583612d12565b840190509392505050565b600060e0820190508181036000830152613bea818b6139fd565b90508181036020830152613bfe818a6139fd565b9050613c0d6040830189613b94565b8181036060830152613c20818789613ba3565b9050613c2f6080830186612afb565b613c3c60a0830185612c67565b613c4960c0830184612c67565b9998505050505050505050565b6000604082019050613c6b6000830186613b94565b8181036020830152613c7e818486613ba3565b9050949350505050565b600067ffffffffffffffff821115613ca357613ca2613488565b5b602082029050602081019050919050565b6000613cc7613cc284613539565b6134e8565b905082815260208101848484011115613ce357613ce2613534565b5b613cee848285612ce8565b509392505050565b600082601f830112613d0b57613d0a612ed9565b5b8151613d1b848260208601613cb4565b91505092915050565b6000613d37613d3284613c88565b6134e8565b90508083825260208201905060208402830185811115613d5a57613d59612ee3565b5b835b81811015613da157805167ffffffffffffffff811115613d7f57613d7e612ed9565b5b808601613d8c8982613cf6565b85526020850194505050602081019050613d5c565b5050509392505050565b600082601f830112613dc057613dbf612ed9565b5b8151613dd0848260208601613d24565b91505092915050565b600060208284031215613def57613dee612b2f565b5b600082015167ffffffffffffffff811115613e0d57613e0c612b34565b5b613e1984828501613dab565b91505092915050565b6000613e2d82612d5c565b915060008203613e4057613e3f613aeb565b5b600182039050919050565b600081519050919050565b6000819050602082019050919050565b6000613e71826139e1565b613e7b81856131dd565b9350613e8b818560208601612ce8565b613e9481612d12565b840191505092915050565b6000606083016000830151613eb760008601826130b8565b5060208301518482036020860152613ecf8282613e66565b91505060408301518482036040860152613ee98282613e66565b9150508091505092915050565b6000613f028383613e9f565b905092915050565b6000602082019050919050565b6000613f2282613e4b565b613f2c818561315f565b935083602082028501613f3e85613e56565b8060005b85811015613f7a5784840389528151613f5b8582613ef6565b9450613f6683613f0a565b925060208a01995050600181019050613f42565b50829750879550505050505092915050565b600060c083016000830151613fa460008601826130b8565b506020830151613fb760208601826130b8565b506040830151613fca60408601826130de565b5060608301518482036060860152613fe28282613f17565b9150506080830151613ff76080860182612da1565b5060a083015184820360a086015261400f8282613e66565b9150508091505092915050565b600060208201905081810360008301526140368184613f8c565b905092915050565b600060c0820190506140536000830189612afb565b6140606020830188612c67565b61406d6040830187612c67565b61407a6060830186612afb565b6140876080830185612afb565b61409460a0830184612d66565b979650505050505050565b600081519050919050565b600081905092915050565b6000819050602082019050919050565b6140ce81612af1565b82525050565b60006140e083836140c5565b60208301905092915050565b6000602082019050919050565b60006141048261409f565b61410e81856140aa565b9350614119836140b5565b8060005b8381101561414a57815161413188826140d4565b975061413c836140ec565b92505060018101905061411d565b5085935050505092915050565b600061416382846140f9565b915081905092915050565b600060a0820190506141836000830188612afb565b6141906020830187612afb565b61419d6040830186612afb565b6141aa6060830185612d66565b6141b76080830184612c67565b9695505050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b6000600282049050600182168061420857607f821691505b60208210810361421b5761421a6141c1565b5b50919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b60006020820190506142656000830184612d66565b92915050565b60006060820190506142806000830186612afb565b61428d6020830185612c67565b61429a6040830184612afb565b949350505050565b600060ff82169050919050565b6142b8816142a2565b82525050565b60006080820190506142d36000830187612afb565b6142e060208301866142af565b6142ed6040830185612afb565b6142fa6060830184612afb565b9594505050505056fea26469706673582212205871db72351a516eb48063d38edefa8dca6451c54af96066cc36b7a433d5af5b64736f6c6343000817003300000000000000000000000070997970c51812dc3a010c7d01b50e0d17dc79c8", + "r": "0xacd742e2878281bbbe1dd2e28362032a426c19b11332c63c4488d7d88fc6b77e", + "s": "0x39b5d9dc413b908947d2f1321bae240af88e79f4033231d04051970dd4349fe1", + "yParity": "0x0", + "v": "0x0", + "hash": "0x306a855ddd01606d902339c6c61bc066165db32626858e2d9cc113954068a047" + } + }, + "impersonated_sender": null + } + ], + "ommers": [] + } + ], + "historical_states": null, + "transactions": [ + { + "info": { + "transaction_hash": "0x8143bef9c4369a296fdd4e985467bc7f2e9d4ed6331e97988201a7e5c18e6618", + "transaction_index": 0, + "from": "0x3c44cdddb6a900fa2b585dd299e03d12fa4293bc", + "to": null, + "contract_address": "0x2e983a1ba5e8b38aaaec4b440b9ddcfbf72e15d1", + "traces": [ + { + "parent": null, + "children": [1], + "idx": 0, + "trace": { + "depth": 0, + "success": true, + "caller": "0x3c44cdddb6a900fa2b585dd299e03d12fa4293bc", + "address": "0x2e983a1ba5e8b38aaaec4b440b9ddcfbf72e15d1", + "maybe_precompile": false, + "selfdestruct_address": null, + "selfdestruct_refund_target": null, + "selfdestruct_transferred_value": null, + "kind": "CREATE", + "value": "0x0", + "data": "0x60a060405260405162000012906200007e565b604051809103906000f0801580156200002f573d6000803e3d6000fd5b5073ffffffffffffffffffffffffffffffffffffffff1660809073ffffffffffffffffffffffffffffffffffffffff168152503480156200006f57600080fd5b5060016002819055506200008c565b610362806200677e83390190565b6080516166d6620000a86000396000612a8301526166d66000f3fe60806040526004361061010c5760003560e01c806370a0823111610095578063b760faf911610064578063b760faf9146103b5578063bb9fe6bf146103d1578063c23a5cea146103e8578063dbed18e014610411578063fc7e286d1461043a5761011c565b806370a08231146102fd578063765e827f1461033a578063850aaf62146103635780639b249f691461038c5761011c565b80631b2e01b8116100dc5780631b2e01b8146101e0578063205c28781461021d57806322cdde4c1461024657806335567e1a146102835780635287ce12146102c05761011c565b806242dc531461012157806301ffc9a71461015e5780630396cb601461019b5780630bd28e3b146101b75761011c565b3661011c5761011a3361047b565b005b600080fd5b34801561012d57600080fd5b5061014860048036038101906101439190613db0565b6104db565b6040516101559190613e51565b60405180910390f35b34801561016a57600080fd5b5061018560048036038101906101809190613ec4565b6106c1565b6040516101929190613f0c565b60405180910390f35b6101b560048036038101906101b09190613f63565b6108b7565b005b3480156101c357600080fd5b506101de60048036038101906101d99190613fe0565b610c13565b005b3480156101ec57600080fd5b506102076004803603810190610202919061400d565b610cb0565b6040516102149190613e51565b60405180910390f35b34801561022957600080fd5b50610244600480360381019061023f919061408b565b610cd5565b005b34801561025257600080fd5b5061026d600480360381019061026891906140f0565b610e78565b60405161027a9190614148565b60405180910390f35b34801561028f57600080fd5b506102aa60048036038101906102a5919061400d565b610eb4565b6040516102b79190613e51565b60405180910390f35b3480156102cc57600080fd5b506102e760048036038101906102e29190614163565b610f63565b6040516102f4919061426f565b60405180910390f35b34801561030957600080fd5b50610324600480360381019061031f9190614163565b611076565b6040516103319190613e51565b60405180910390f35b34801561034657600080fd5b50610361600480360381019061035c91906142e0565b6110c1565b005b34801561036f57600080fd5b5061038a60048036038101906103859190614340565b611255565b005b34801561039857600080fd5b506103b360048036038101906103ae91906143a0565b611303565b005b6103cf60048036038101906103ca9190614163565b61047b565b005b3480156103dd57600080fd5b506103e66113c9565b005b3480156103f457600080fd5b5061040f600480360381019061040a91906143ed565b611579565b005b34801561041d57600080fd5b5061043860048036038101906104339190614470565b611879565b005b34801561044657600080fd5b50610461600480360381019061045c9190614163565b611d90565b6040516104729594939291906144fd565b60405180910390f35b60006104878234611e0f565b90508173ffffffffffffffffffffffffffffffffffffffff167f2da466a7b24304f47e87fa2e1e5a81b9831ce54fec19055ce277ca2f39ba42c4826040516104cf9190613e51565b60405180910390a25050565b6000805a90503073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161461054f576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610546906145ad565b60405180910390fd5b6000856000015190506000816060015190506127108260a001518201016040603f5a02816105805761057f6145cd565b5b0410156105b1577fdeaddead0000000000000000000000000000000000000000000000000000000060005260206000fd5b600080895111156106555760006105cf846000015160008c86611e7a565b9050806106535760006105e3610800611e93565b905060008151111561064d57846000015173ffffffffffffffffffffffffffffffffffffffff168a602001517f1c4fada7374c0a9ee8841fc38afe82932dc0f8e69012e927f061a8bae611a20187602001518460405161064492919061467b565b60405180910390a35b60019250505b505b600088608001515a86030190506106b2828a8a8a8080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f8201169050808301925050505050505084611ec3565b95505050505050949350505050565b60007f3e84f021000000000000000000000000000000000000000000000000000000007fcf28ef97000000000000000000000000000000000000000000000000000000007f915074d80000000000000000000000000000000000000000000000000000000018187bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614806107d057507f915074d8000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b8061083857507fcf28ef97000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b806108a057507f3e84f021000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b806108b057506108af82612164565b5b9050919050565b60008060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020905060008263ffffffff1611610942576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610939906146f7565b60405180910390fd5b80600101600f9054906101000a900463ffffffff1663ffffffff168263ffffffff1610156109a5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161099c90614763565b60405180910390fd5b6000348260010160019054906101000a90046dffffffffffffffffffffffffffff166dffffffffffffffffffffffffffff166109e191906147b2565b905060008111610a26576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610a1d90614832565b60405180910390fd5b6dffffffffffffffffffffffffffff8016811115610a79576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610a709061489e565b60405180910390fd5b6040518060a0016040528083600001548152602001600115158152602001826dffffffffffffffffffffffffffff1681526020018463ffffffff168152602001600065ffffffffffff168152506000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000820151816000015560208201518160010160006101000a81548160ff02191690831515021790555060408201518160010160016101000a8154816dffffffffffffffffffffffffffff02191690836dffffffffffffffffffffffffffff160217905550606082015181600101600f6101000a81548163ffffffff021916908363ffffffff16021790555060808201518160010160136101000a81548165ffffffffffff021916908365ffffffffffff1602179055509050503373ffffffffffffffffffffffffffffffffffffffff167fa5ae833d0bb1dcd632d98a8b70973e8516812898e19bf27b70071ebc8dc52c018285604051610c069291906148f9565b60405180910390a2505050565b600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008277ffffffffffffffffffffffffffffffffffffffffffffffff1677ffffffffffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000815480929190610ca890614922565b919050555050565b6001602052816000526040600020602052806000526040600020600091509150505481565b60008060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002090508060000154821115610d5e576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610d55906149b6565b60405180910390fd5b818160000154610d6e91906149d6565b81600001819055503373ffffffffffffffffffffffffffffffffffffffff167fd1c19fbcd4551a5edfb66d43d2e337c04837afda3482b42bdf569a8fccdae5fb8484604051610dbe929190614a5f565b60405180910390a260008373ffffffffffffffffffffffffffffffffffffffff1683604051610dec90614ab9565b60006040518083038185875af1925050503d8060008114610e29576040519150601f19603f3d011682016040523d82523d6000602084013e610e2e565b606091505b5050905080610e72576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610e6990614b1a565b60405180910390fd5b50505050565b6000610e83826121ce565b3046604051602001610e9793929190614b49565b604051602081830303815290604052805190602001209050919050565b600060408277ffffffffffffffffffffffffffffffffffffffffffffffff16901b600160008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008477ffffffffffffffffffffffffffffffffffffffffffffffff1677ffffffffffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205417905092915050565b610f6b613853565b6000808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206040518060a0016040529081600082015481526020016001820160009054906101000a900460ff161515151581526020016001820160019054906101000a90046dffffffffffffffffffffffffffff166dffffffffffffffffffffffffffff166dffffffffffffffffffffffffffff16815260200160018201600f9054906101000a900463ffffffff1663ffffffff1663ffffffff1681526020016001820160139054906101000a900465ffffffffffff1665ffffffffffff1665ffffffffffff16815250509050919050565b60008060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600001549050919050565b6110c96121e7565b600083839050905060008167ffffffffffffffff8111156110ed576110ec6139cf565b5b60405190808252806020026020018201604052801561112657816020015b6111136138a2565b81526020019060019003908161110b5790505b50905060005b828110156111a657600082828151811061114957611148614b80565b5b60200260200101519050600080611185848a8a8781811061116d5761116c614b80565b5b905060200281019061117f9190614bbe565b8561222b565b915091506111968483836000612421565b505050808060010191505061112c565b5060007fbb47ee3e183a558b1a2ff0874b079f3fc5478b7454eacf2bfc5af2ff5878f97260405160405180910390a160005b8381101561123a57611229818888848181106111f7576111f6614b80565b5b90506020028101906112099190614bbe565b85848151811061121c5761121b614b80565b5b60200260200101516125b4565b8201915080806001019150506111d8565b506112458482612955565b505050611250612a75565b505050565b6000808473ffffffffffffffffffffffffffffffffffffffff16848460405161127f929190614c0c565b600060405180830381855af49150503d80600081146112ba576040519150601f19603f3d011682016040523d82523d6000602084013e6112bf565b606091505b509150915081816040517f994105540000000000000000000000000000000000000000000000000000000081526004016112fa929190614c25565b60405180910390fd5b600061130d612a7f565b73ffffffffffffffffffffffffffffffffffffffff1663570e1a3684846040518363ffffffff1660e01b8152600401611347929190614c82565b6020604051808303816000875af1158015611366573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061138a9190614cbb565b9050806040517f6ca7b8060000000000000000000000000000000000000000000000000000000081526004016113c09190614ce8565b60405180910390fd5b60008060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000209050600081600101600f9054906101000a900463ffffffff1663ffffffff1603611468576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161145f90614d4f565b60405180910390fd5b8060010160009054906101000a900460ff166114b9576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016114b090614dbb565b60405180910390fd5b600081600101600f9054906101000a900463ffffffff1663ffffffff16426114e19190614ddb565b9050808260010160136101000a81548165ffffffffffff021916908365ffffffffffff16021790555060008260010160006101000a81548160ff0219169083151502179055503373ffffffffffffffffffffffffffffffffffffffff167ffa9b3c14cc825c412c9ed81b3ba365a5b459439403f18829e572ed53a4180f0a8260405161156d9190614e46565b60405180910390a25050565b60008060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020905060008160010160019054906101000a90046dffffffffffffffffffffffffffff166dffffffffffffffffffffffffffff16905060008111611631576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161162890614ead565b60405180910390fd5b60008260010160139054906101000a900465ffffffffffff1665ffffffffffff1611611692576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161168990614f19565b60405180910390fd5b428260010160139054906101000a900465ffffffffffff1665ffffffffffff1611156116f3576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016116ea90614f85565b60405180910390fd5b600082600101600f6101000a81548163ffffffff021916908363ffffffff16021790555060008260010160136101000a81548165ffffffffffff021916908365ffffffffffff16021790555060008260010160016101000a8154816dffffffffffffffffffffffffffff02191690836dffffffffffffffffffffffffffff1602179055503373ffffffffffffffffffffffffffffffffffffffff167fb7c918e0e249f999e965cafeb6c664271b3f4317d296461500e71da39f0cbda384836040516117bf929190614a5f565b60405180910390a260008373ffffffffffffffffffffffffffffffffffffffff16826040516117ed90614ab9565b60006040518083038185875af1925050503d806000811461182a576040519150601f19603f3d011682016040523d82523d6000602084013e61182f565b606091505b5050905080611873576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161186a90614ff1565b60405180910390fd5b50505050565b6118816121e7565b60008383905090506000805b82811015611a6857368686838181106118a9576118a8614b80565b5b90506020028101906118bb9190615011565b90503660008280600001906118d09190615039565b9150915060008360200160208101906118e991906150da565b9050600173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff160361195a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161195190615153565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614611a46578073ffffffffffffffffffffffffffffffffffffffff16632dd8113384848780604001906119bc9190615173565b6040518563ffffffff1660e01b81526004016119db94939291906154ec565b60006040518083038186803b1580156119f357600080fd5b505afa925050508015611a04575060015b611a4557806040517f86a9f750000000000000000000000000000000000000000000000000000000008152600401611a3c9190614ce8565b60405180910390fd5b5b8282905086611a5591906147b2565b955050505050808060010191505061188d565b5060008167ffffffffffffffff811115611a8557611a846139cf565b5b604051908082528060200260200182016040528015611abe57816020015b611aab6138a2565b815260200190600190039081611aa35790505b5090506000805b84811015611bc85736888883818110611ae157611ae0614b80565b5b9050602002810190611af39190615011565b9050366000828060000190611b089190615039565b915091506000836020016020810190611b2191906150da565b9050600083839050905060005b81811015611bb5576000898981518110611b4b57611b4a614b80565b5b60200260200101519050600080611b878b898987818110611b6f57611b6e614b80565b5b9050602002810190611b819190614bbe565b8561222b565b91509150611b9784838389612421565b8a80611ba290614922565b9b50505050508080600101915050611b2e565b5050505050508080600101915050611ac5565b507fbb47ee3e183a558b1a2ff0874b079f3fc5478b7454eacf2bfc5af2ff5878f97260405160405180910390a1600080915060005b85811015611d2f5736898983818110611c1957611c18614b80565b5b9050602002810190611c2b9190615011565b9050806020016020810190611c4091906150da565b73ffffffffffffffffffffffffffffffffffffffff167f575ff3acadd5ab348fe1855e217e0f3678f8d767d7494c9f9fefbee2e17cca4d60405160405180910390a2366000828060000190611c959190615039565b91509150600082829050905060005b81811015611d1d57611cf588858584818110611cc357611cc2614b80565b5b9050602002810190611cd59190614bbe565b8b8b81518110611ce857611ce7614b80565b5b60200260200101516125b4565b87611d0091906147b2565b96508780611d0d90614922565b9850508080600101915050611ca4565b50505050508080600101915050611bfd565b50600073ffffffffffffffffffffffffffffffffffffffff167f575ff3acadd5ab348fe1855e217e0f3678f8d767d7494c9f9fefbee2e17cca4d60405160405180910390a2611d7e8682612955565b5050505050611d8b612a75565b505050565b60006020528060005260406000206000915090508060000154908060010160009054906101000a900460ff16908060010160019054906101000a90046dffffffffffffffffffffffffffff169080600101600f9054906101000a900463ffffffff16908060010160139054906101000a900465ffffffffffff16905085565b6000806000808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002090506000838260000154611e6491906147b2565b9050808260000181905550809250505092915050565b6000806000845160208601878987f19050949350505050565b60603d82811115611ea2578290505b604051602082018101604052818152816000602083013e8092505050919050565b6000805a9050600080866000015190506000611ede82612aa7565b905060008260e001519050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603611f295782600001519350612029565b809350600088511115612028578187029550600280811115611f4e57611f4d615527565b5b8a6002811115611f6157611f60615527565b5b14612027578073ffffffffffffffffffffffffffffffffffffffff16637c627b218460a001518c8b8a876040518663ffffffff1660e01b8152600401611faa949392919061559e565b600060405180830381600088803b158015611fc457600080fd5b5087f193505050508015611fd6575060015b612026576000611fe7610800611e93565b9050806040517fad7954bc00000000000000000000000000000000000000000000000000000000815260040161201d91906155ea565b60405180910390fd5b5b5b5b5a85038701965060008360a00151846060015101905060008a60800151890390508082111561207a576000818303905060006064600a83028161206f5761206e6145cd565b5b049050808b019a5050505b505081870295506000896040015190508681101561210a576002808111156120a5576120a4615527565b5b8b60028111156120b8576120b7615527565b5b036120db578096506120c98a612ae3565b6120d68a6000898b612b49565b612105565b7fdeadaa510000000000000000000000000000000000000000000000000000000060005260206000fd5b612156565b6000878203905061211b8682611e0f565b50600080600281111561213157612130615527565b5b8d600281111561214457612143615527565b5b1490506121538c828b8d612b49565b50505b505050505050949350505050565b60007f01ffc9a7000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916149050919050565b60006121d982612bd7565b805190602001209050919050565b6002805403612222576040517f3ee5aeb500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60028081905550565b60008060005a90506000846000015190506122468682612c9b565b61224f86610e78565b85602001818152505060008160400151905060008261012001518361010001518460a0015185608001518660600151868860c0015117171717171790506effffffffffffffffffffffffffffff80168111156122e0576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016122d790615658565b60405180910390fd5b60006122eb84612e57565b90506122fa8a8a8a8487612e89565b965061230e846000015185602001516130c6565b61234f57896040517f220266b600000000000000000000000000000000000000000000000000000000815260040161234691906156c4565b60405180910390fd5b825a8603111561239657896040517f220266b600000000000000000000000000000000000000000000000000000000815260040161238d919061573e565b60405180910390fd5b6060600073ffffffffffffffffffffffffffffffffffffffff168560e0015173ffffffffffffffffffffffffffffffffffffffff16146123e5576123dc8b8b8b85613184565b80985081925050505b818960400181815250506123f881613371565b8960600181815250508960a001355a870301896080018181525050505050505050935093915050565b60008061242d8561337b565b915091508173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16146124a157856040517f220266b600000000000000000000000000000000000000000000000000000000815260040161249891906157b8565b60405180910390fd5b80156124e457856040517f220266b60000000000000000000000000000000000000000000000000000000081526004016124db9190615832565b60405180910390fd5b60006124ef8561337b565b8093508192505050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161461256857866040517f220266b600000000000000000000000000000000000000000000000000000000815260040161255f91906158ac565b60405180910390fd5b81156125ab57866040517f220266b60000000000000000000000000000000000000000000000000000000081526004016125a2919061594c565b60405180910390fd5b50505050505050565b6000805a905060006125c984606001516133d4565b905060008060405190503660008880606001906125e69190615173565b91509150606060008260038111156125fd57843591505b50638dd7712f60e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916817bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916036127245760008b8b60200151604051602401612663929190615aa4565b604051602081830303815290604052638dd7712f60e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff838183161783525050505090503073ffffffffffffffffffffffffffffffffffffffff166242dc53828d8b6040516024016126da93929190615c0d565b604051602081830303815290604052915060e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff838183161783525050505092505061279b565b3073ffffffffffffffffffffffffffffffffffffffff166242dc5385858d8b6040516024016127569493929190615c54565b604051602081830303815290604052915060e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff838183161783525050505091505b602060008351602085016000305af1955060005198508460405250505050508061294b5760003d806020036127d65760206000803e60005191505b507fdeaddead00000000000000000000000000000000000000000000000000000000810361283b57876040517f220266b60000000000000000000000000000000000000000000000000000000081526004016128329190615ce9565b60405180910390fd5b7fdeadaa510000000000000000000000000000000000000000000000000000000081036128aa57600086608001515a8661287591906149d6565b61287f91906147b2565b905060008760400151905061289388612ae3565b6128a08860008385612b49565b8096505050612949565b85600001516000015173ffffffffffffffffffffffffffffffffffffffff1686602001517ff62676f440ff169a3a9afdbf812e89e7f95975ee8e5c31214ffdef631c5f4792886000015160200151612903610800611e93565b60405161291192919061467b565b60405180910390a3600086608001515a8661292c91906149d6565b61293691906147b2565b90506129456002888684611ec3565b9550505b505b5050509392505050565b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16036129c4576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016129bb90615d63565b60405180910390fd5b60008273ffffffffffffffffffffffffffffffffffffffff16826040516129ea90614ab9565b60006040518083038185875af1925050503d8060008114612a27576040519150601f19603f3d011682016040523d82523d6000602084013e612a2c565b606091505b5050905080612a70576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612a6790615dcf565b60405180910390fd5b505050565b6001600281905550565b60007f0000000000000000000000000000000000000000000000000000000000000000905090565b600080826101000151905060008361012001519050808203612acd578192505050612ade565b612ad9824883016133de565b925050505b919050565b80600001516000015173ffffffffffffffffffffffffffffffffffffffff1681602001517f67b4fa9642f42120bf031f3051d1824b0fe25627945b27b8a6a65d5761d5482e836000015160200151604051612b3e9190613e51565b60405180910390a350565b836000015160e0015173ffffffffffffffffffffffffffffffffffffffff1684600001516000015173ffffffffffffffffffffffffffffffffffffffff1685602001517f49628fd1471006c1482da88028e9ce4dbb080b815c9b0344d39e5a8e6ec1419f876000015160200151878787604051612bc99493929190615def565b60405180910390a450505050565b60606000612be4836133f7565b90506000836020013590506000612c09858060400190612c049190615173565b613407565b90506000612c25868060600190612c209190615173565b613407565b905060008660800135905060008760a00135905060008860c0013590506000612c5c8a8060e00190612c579190615173565b613407565b90508787878787878787604051602001612c7d989796959493929190615e34565b60405160208183030381529060405298505050505050505050919050565b816000016020810190612cae9190614163565b816000019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250508160200135816020018181525050612d00826080013561341e565b8260400183606001828152508281525050508160a001358160c0018181525050612d2d8260c0013561341e565b8261012001836101000182815250828152505050366000838060e00190612d549190615173565b915091506000828290501115612e01576034828290501015612dab576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612da290615efe565b60405180910390fd5b612db5828261345c565b8560e001866080018760a00183815250838152508373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815250505050612e51565b60008360e0019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff1681525050600083608001818152505060008360a00181815250505b50505050565b6000808260c001518360a001518460800151856060015186604001510101010190508261010001518102915050919050565b60008084600001519050600081600001519050612eb68887898060400190612eb19190615173565b6134fe565b60008260e00151905060008073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603612f17576000612eff84611076565b9050878111612f1057808803612f13565b60005b9150505b8273ffffffffffffffffffffffffffffffffffffffff166319822f7c878b8b60200151856040518563ffffffff1660e01b8152600401612f5993929190615f1e565b60206040518083038160008887f193505050508015612f9657506040513d601f19601f82011682018060405250810190612f939190615f71565b60015b612fe35789612fa6610800611e93565b6040517f65c8fd4d000000000000000000000000000000000000000000000000000000008152600401612fda929190615fea565b60405180910390fd5b80955050600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16036130b95760008060008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000209050600081600001549050808911156130ab578b6040517f220266b60000000000000000000000000000000000000000000000000000000081526004016130a29190616079565b60405180910390fd5b888103826000018190555050505b5050505095945050505050565b600080604083901c905060008390508067ffffffffffffffff16600160008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008477ffffffffffffffffffffffffffffffffffffffffffffffff1677ffffffffffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600081548092919061317590614922565b91905055149250505092915050565b60606000805a905060008560000151905060008160e00151905060008060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002090506000816000015490508781101561322e578a6040517f220266b600000000000000000000000000000000000000000000000000000000815260040161322591906160f3565b60405180910390fd5b87810382600001819055506000846080015190508373ffffffffffffffffffffffffffffffffffffffff166352b7512c828d8d602001518d6040518563ffffffff1660e01b815260040161328493929190615f1e565b60006040518083038160008887f1935050505080156132c657506040513d6000823e3d601f19601f820116820180604052508101906132c39190616191565b60015b613313578b6132d6610800611e93565b6040517f65c8fd4d00000000000000000000000000000000000000000000000000000000815260040161330a929190616239565b60405180910390fd5b8199508098505050805a87031115613362578b6040517f220266b600000000000000000000000000000000000000000000000000000000815260040161335991906162ee565b60405180910390fd5b50505050505094509492505050565b6000819050919050565b6000806000830361339257600080915091506133cf565b600061339d846137cf565b9050806040015165ffffffffffff164211806133c45750806020015165ffffffffffff1642105b915080600001519250505b915091565b6060819050919050565b60008183106133ed57816133ef565b825b905092915050565b6000808235905080915050919050565b600060405182808583378082209250505092915050565b6000808260801c8360001c816fffffffffffffffffffffffffffffffff169150806fffffffffffffffffffffffffffffffff16905091509150915091565b6000806000848460009060149261347593929190616326565b9061348091906163a5565b60601c858560149060249261349793929190616326565b906134a29190616430565b60801c86866024906034926134b993929190616326565b906134c49190616430565b60801c816fffffffffffffffffffffffffffffffff169150806fffffffffffffffffffffffffffffffff1690509250925092509250925092565b600082829050146137c9576000836000015160000151905060008173ffffffffffffffffffffffffffffffffffffffff163b1461357257846040517f220266b600000000000000000000000000000000000000000000000000000000815260040161356991906164db565b60405180910390fd5b600061357c612a7f565b73ffffffffffffffffffffffffffffffffffffffff1663570e1a3686600001516040015186866040518463ffffffff1660e01b81526004016135bf929190614c82565b60206040518083038160008887f11580156135de573d6000803e3d6000fd5b50505050506040513d601f19601f820116820180604052508101906136039190614cbb565b9050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff160361367657856040517f220266b600000000000000000000000000000000000000000000000000000000815260040161366d9190616555565b60405180910390fd5b8173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16146136e657856040517f220266b60000000000000000000000000000000000000000000000000000000081526004016136dd91906165cf565b60405180910390fd5b60008173ffffffffffffffffffffffffffffffffffffffff163b0361374257856040517f220266b60000000000000000000000000000000000000000000000000000000081526004016137399190616649565b60405180910390fd5b6000848460009060149261375893929190616326565b9061376391906163a5565b60601c90508273ffffffffffffffffffffffffffffffffffffffff1686602001517fd51a9c61267aa6196961883ecf5ff2da6619c37dac0fa92122513fb32c032d2d83896000015160e001516040516137bd929190616677565b60405180910390a35050505b50505050565b6137d76138da565b6000829050600060a084901c905060008165ffffffffffff16036137ff5765ffffffffffff90505b600060d085901c905060405180606001604052808473ffffffffffffffffffffffffffffffffffffffff1681526020018265ffffffffffff1681526020018365ffffffffffff168152509350505050919050565b6040518060a001604052806000815260200160001515815260200160006dffffffffffffffffffffffffffff168152602001600063ffffffff168152602001600065ffffffffffff1681525090565b6040518060a001604052806138b5613921565b8152602001600080191681526020016000815260200160008152602001600081525090565b6040518060600160405280600073ffffffffffffffffffffffffffffffffffffffff168152602001600065ffffffffffff168152602001600065ffffffffffff1681525090565b604051806101400160405280600073ffffffffffffffffffffffffffffffffffffffff168152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600073ffffffffffffffffffffffffffffffffffffffff16815260200160008152602001600081525090565b6000604051905090565b600080fd5b600080fd5b600080fd5b600080fd5b6000601f19601f8301169050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b613a07826139be565b810181811067ffffffffffffffff82111715613a2657613a256139cf565b5b80604052505050565b6000613a396139a0565b9050613a4582826139fe565b919050565b600067ffffffffffffffff821115613a6557613a646139cf565b5b613a6e826139be565b9050602081019050919050565b82818337600083830152505050565b6000613a9d613a9884613a4a565b613a2f565b905082815260208101848484011115613ab957613ab86139b9565b5b613ac4848285613a7b565b509392505050565b600082601f830112613ae157613ae06139b4565b5b8135613af1848260208601613a8a565b91505092915050565b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000613b2a82613aff565b9050919050565b613b3a81613b1f565b8114613b4557600080fd5b50565b600081359050613b5781613b31565b92915050565b6000819050919050565b613b7081613b5d565b8114613b7b57600080fd5b50565b600081359050613b8d81613b67565b92915050565b60006101408284031215613baa57613ba9613afa565b5b613bb5610140613a2f565b90506000613bc584828501613b48565b6000830152506020613bd984828501613b7e565b6020830152506040613bed84828501613b7e565b6040830152506060613c0184828501613b7e565b6060830152506080613c1584828501613b7e565b60808301525060a0613c2984828501613b7e565b60a08301525060c0613c3d84828501613b7e565b60c08301525060e0613c5184828501613b48565b60e083015250610100613c6684828501613b7e565b61010083015250610120613c7c84828501613b7e565b6101208301525092915050565b6000819050919050565b613c9c81613c89565b8114613ca757600080fd5b50565b600081359050613cb981613c93565b92915050565b60006101c08284031215613cd657613cd5613afa565b5b613ce060a0613a2f565b90506000613cf084828501613b93565b600083015250610140613d0584828501613caa565b602083015250610160613d1a84828501613b7e565b604083015250610180613d2f84828501613b7e565b6060830152506101a0613d4484828501613b7e565b60808301525092915050565b600080fd5b600080fd5b60008083601f840112613d7057613d6f6139b4565b5b8235905067ffffffffffffffff811115613d8d57613d8c613d50565b5b602083019150836001820283011115613da957613da8613d55565b5b9250929050565b6000806000806102008587031215613dcb57613dca6139aa565b5b600085013567ffffffffffffffff811115613de957613de86139af565b5b613df587828801613acc565b9450506020613e0687828801613cbf565b9350506101e085013567ffffffffffffffff811115613e2857613e276139af565b5b613e3487828801613d5a565b925092505092959194509250565b613e4b81613b5d565b82525050565b6000602082019050613e666000830184613e42565b92915050565b60007fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b613ea181613e6c565b8114613eac57600080fd5b50565b600081359050613ebe81613e98565b92915050565b600060208284031215613eda57613ed96139aa565b5b6000613ee884828501613eaf565b91505092915050565b60008115159050919050565b613f0681613ef1565b82525050565b6000602082019050613f216000830184613efd565b92915050565b600063ffffffff82169050919050565b613f4081613f27565b8114613f4b57600080fd5b50565b600081359050613f5d81613f37565b92915050565b600060208284031215613f7957613f786139aa565b5b6000613f8784828501613f4e565b91505092915050565b600077ffffffffffffffffffffffffffffffffffffffffffffffff82169050919050565b613fbd81613f90565b8114613fc857600080fd5b50565b600081359050613fda81613fb4565b92915050565b600060208284031215613ff657613ff56139aa565b5b600061400484828501613fcb565b91505092915050565b60008060408385031215614024576140236139aa565b5b600061403285828601613b48565b925050602061404385828601613fcb565b9150509250929050565b600061405882613aff565b9050919050565b6140688161404d565b811461407357600080fd5b50565b6000813590506140858161405f565b92915050565b600080604083850312156140a2576140a16139aa565b5b60006140b085828601614076565b92505060206140c185828601613b7e565b9150509250929050565b600080fd5b600061012082840312156140e7576140e66140cb565b5b81905092915050565b600060208284031215614106576141056139aa565b5b600082013567ffffffffffffffff811115614124576141236139af565b5b614130848285016140d0565b91505092915050565b61414281613c89565b82525050565b600060208201905061415d6000830184614139565b92915050565b600060208284031215614179576141786139aa565b5b600061418784828501613b48565b91505092915050565b61419981613b5d565b82525050565b6141a881613ef1565b82525050565b60006dffffffffffffffffffffffffffff82169050919050565b6141d1816141ae565b82525050565b6141e081613f27565b82525050565b600065ffffffffffff82169050919050565b614201816141e6565b82525050565b60a08201600082015161421d6000850182614190565b506020820151614230602085018261419f565b50604082015161424360408501826141c8565b50606082015161425660608501826141d7565b50608082015161426960808501826141f8565b50505050565b600060a0820190506142846000830184614207565b92915050565b60008083601f8401126142a05761429f6139b4565b5b8235905067ffffffffffffffff8111156142bd576142bc613d50565b5b6020830191508360208202830111156142d9576142d8613d55565b5b9250929050565b6000806000604084860312156142f9576142f86139aa565b5b600084013567ffffffffffffffff811115614317576143166139af565b5b6143238682870161428a565b9350935050602061433686828701614076565b9150509250925092565b600080600060408486031215614359576143586139aa565b5b600061436786828701613b48565b935050602084013567ffffffffffffffff811115614388576143876139af565b5b61439486828701613d5a565b92509250509250925092565b600080602083850312156143b7576143b66139aa565b5b600083013567ffffffffffffffff8111156143d5576143d46139af565b5b6143e185828601613d5a565b92509250509250929050565b600060208284031215614403576144026139aa565b5b600061441184828501614076565b91505092915050565b60008083601f8401126144305761442f6139b4565b5b8235905067ffffffffffffffff81111561444d5761444c613d50565b5b60208301915083602082028301111561446957614468613d55565b5b9250929050565b600080600060408486031215614489576144886139aa565b5b600084013567ffffffffffffffff8111156144a7576144a66139af565b5b6144b38682870161441a565b935093505060206144c686828701614076565b9150509250925092565b6144d9816141ae565b82525050565b6144e881613f27565b82525050565b6144f7816141e6565b82525050565b600060a0820190506145126000830188613e42565b61451f6020830187613efd565b61452c60408301866144d0565b61453960608301856144df565b61454660808301846144ee565b9695505050505050565b600082825260208201905092915050565b7f4141393220696e7465726e616c2063616c6c206f6e6c79000000000000000000600082015250565b6000614597601783614550565b91506145a282614561565b602082019050919050565b600060208201905081810360008301526145c68161458a565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b600081519050919050565b600082825260208201905092915050565b60005b8381101561463657808201518184015260208101905061461b565b60008484015250505050565b600061464d826145fc565b6146578185614607565b9350614667818560208601614618565b614670816139be565b840191505092915050565b60006040820190506146906000830185613e42565b81810360208301526146a28184614642565b90509392505050565b7f6d757374207370656369667920756e7374616b652064656c6179000000000000600082015250565b60006146e1601a83614550565b91506146ec826146ab565b602082019050919050565b60006020820190508181036000830152614710816146d4565b9050919050565b7f63616e6e6f7420646563726561736520756e7374616b652074696d6500000000600082015250565b600061474d601c83614550565b915061475882614717565b602082019050919050565b6000602082019050818103600083015261477c81614740565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60006147bd82613b5d565b91506147c883613b5d565b92508282019050808211156147e0576147df614783565b5b92915050565b7f6e6f207374616b65207370656369666965640000000000000000000000000000600082015250565b600061481c601283614550565b9150614827826147e6565b602082019050919050565b6000602082019050818103600083015261484b8161480f565b9050919050565b7f7374616b65206f766572666c6f77000000000000000000000000000000000000600082015250565b6000614888600e83614550565b915061489382614852565b602082019050919050565b600060208201905081810360008301526148b78161487b565b9050919050565b6000819050919050565b60006148e36148de6148d984613f27565b6148be565b613b5d565b9050919050565b6148f3816148c8565b82525050565b600060408201905061490e6000830185613e42565b61491b60208301846148ea565b9392505050565b600061492d82613b5d565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361495f5761495e614783565b5b600182019050919050565b7f576974686472617720616d6f756e7420746f6f206c6172676500000000000000600082015250565b60006149a0601983614550565b91506149ab8261496a565b602082019050919050565b600060208201905081810360008301526149cf81614993565b9050919050565b60006149e182613b5d565b91506149ec83613b5d565b9250828203905081811115614a0457614a03614783565b5b92915050565b6000614a25614a20614a1b84613aff565b6148be565b613aff565b9050919050565b6000614a3782614a0a565b9050919050565b6000614a4982614a2c565b9050919050565b614a5981614a3e565b82525050565b6000604082019050614a746000830185614a50565b614a816020830184613e42565b9392505050565b600081905092915050565b50565b6000614aa3600083614a88565b9150614aae82614a93565b600082019050919050565b6000614ac482614a96565b9150819050919050565b7f6661696c656420746f2077697468647261770000000000000000000000000000600082015250565b6000614b04601283614550565b9150614b0f82614ace565b602082019050919050565b60006020820190508181036000830152614b3381614af7565b9050919050565b614b4381613b1f565b82525050565b6000606082019050614b5e6000830186614139565b614b6b6020830185614b3a565b614b786040830184613e42565b949350505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600080fd5b600080fd5b600080fd5b60008235600161012003833603038112614bdb57614bda614baf565b5b80830191505092915050565b6000614bf38385614a88565b9350614c00838584613a7b565b82840190509392505050565b6000614c19828486614be7565b91508190509392505050565b6000604082019050614c3a6000830185613efd565b8181036020830152614c4c8184614642565b90509392505050565b6000614c618385614607565b9350614c6e838584613a7b565b614c77836139be565b840190509392505050565b60006020820190508181036000830152614c9d818486614c55565b90509392505050565b600081519050614cb581613b31565b92915050565b600060208284031215614cd157614cd06139aa565b5b6000614cdf84828501614ca6565b91505092915050565b6000602082019050614cfd6000830184614b3a565b92915050565b7f6e6f74207374616b656400000000000000000000000000000000000000000000600082015250565b6000614d39600a83614550565b9150614d4482614d03565b602082019050919050565b60006020820190508181036000830152614d6881614d2c565b9050919050565b7f616c726561647920756e7374616b696e67000000000000000000000000000000600082015250565b6000614da5601183614550565b9150614db082614d6f565b602082019050919050565b60006020820190508181036000830152614dd481614d98565b9050919050565b6000614de6826141e6565b9150614df1836141e6565b9250828201905065ffffffffffff811115614e0f57614e0e614783565b5b92915050565b6000614e30614e2b614e26846141e6565b6148be565b613b5d565b9050919050565b614e4081614e15565b82525050565b6000602082019050614e5b6000830184614e37565b92915050565b7f4e6f207374616b6520746f207769746864726177000000000000000000000000600082015250565b6000614e97601483614550565b9150614ea282614e61565b602082019050919050565b60006020820190508181036000830152614ec681614e8a565b9050919050565b7f6d7573742063616c6c20756e6c6f636b5374616b652829206669727374000000600082015250565b6000614f03601d83614550565b9150614f0e82614ecd565b602082019050919050565b60006020820190508181036000830152614f3281614ef6565b9050919050565b7f5374616b65207769746864726177616c206973206e6f74206475650000000000600082015250565b6000614f6f601b83614550565b9150614f7a82614f39565b602082019050919050565b60006020820190508181036000830152614f9e81614f62565b9050919050565b7f6661696c656420746f207769746864726177207374616b650000000000000000600082015250565b6000614fdb601883614550565b9150614fe682614fa5565b602082019050919050565b6000602082019050818103600083015261500a81614fce565b9050919050565b60008235600160600383360303811261502d5761502c614baf565b5b80830191505092915050565b6000808335600160200384360303811261505657615055614baf565b5b80840192508235915067ffffffffffffffff82111561507857615077614bb4565b5b60208301925060208202360383131561509457615093614bb9565b5b509250929050565b60006150a782613b1f565b9050919050565b6150b78161509c565b81146150c257600080fd5b50565b6000813590506150d4816150ae565b92915050565b6000602082840312156150f0576150ef6139aa565b5b60006150fe848285016150c5565b91505092915050565b7f4141393620696e76616c69642061676772656761746f72000000000000000000600082015250565b600061513d601783614550565b915061514882615107565b602082019050919050565b6000602082019050818103600083015261516c81615130565b9050919050565b600080833560016020038436030381126151905761518f614baf565b5b80840192508235915067ffffffffffffffff8211156151b2576151b1614bb4565b5b6020830192506001820236038313156151ce576151cd614bb9565b5b509250929050565b600082825260208201905092915050565b6000819050919050565b60006152006020840184613b48565b905092915050565b61521181613b1f565b82525050565b60006152266020840184613b7e565b905092915050565b600080fd5b600080fd5b600080fd5b6000808335600160200384360303811261525a57615259615238565b5b83810192508235915060208301925067ffffffffffffffff8211156152825761528161522e565b5b60018202360383131561529857615297615233565b5b509250929050565b600082825260208201905092915050565b60006152bd83856152a0565b93506152ca838584613a7b565b6152d3836139be565b840190509392505050565b60006152ed6020840184613caa565b905092915050565b6152fe81613c89565b82525050565b6000610120830161531860008401846151f1565b6153256000860182615208565b506153336020840184615217565b6153406020860182614190565b5061534e604084018461523d565b85830360408701526153618382846152b1565b92505050615372606084018461523d565b85830360608701526153858382846152b1565b9250505061539660808401846152de565b6153a360808601826152f5565b506153b160a0840184615217565b6153be60a0860182614190565b506153cc60c08401846152de565b6153d960c08601826152f5565b506153e760e084018461523d565b85830360e08701526153fa8382846152b1565b9250505061540c61010084018461523d565b8583036101008701526154208382846152b1565b925050508091505092915050565b600061543a8383615304565b905092915050565b6000823560016101200383360303811261545f5761545e615238565b5b82810191505092915050565b6000602082019050919050565b600061548483856151d6565b935083602084028501615496846151e7565b8060005b878110156154da5784840389526154b18284615442565b6154bb858261542e565b94506154c68361546b565b925060208a0199505060018101905061549a565b50829750879450505050509392505050565b60006040820190508181036000830152615507818688615478565b9050818103602083015261551c818486614c55565b905095945050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b6003811061556757615566615527565b5b50565b600081905061557882615556565b919050565b60006155888261556a565b9050919050565b6155988161557d565b82525050565b60006080820190506155b3600083018761558f565b81810360208301526155c58186614642565b90506155d46040830185613e42565b6155e16060830184613e42565b95945050505050565b600060208201905081810360008301526156048184614642565b905092915050565b7f41413934206761732076616c756573206f766572666c6f770000000000000000600082015250565b6000615642601883614550565b915061564d8261560c565b602082019050919050565b6000602082019050818103600083015261567181615635565b9050919050565b7f4141323520696e76616c6964206163636f756e74206e6f6e6365000000000000600082015250565b60006156ae601a83614550565b91506156b982615678565b602082019050919050565b60006040820190506156d96000830184613e42565b81810360208301526156ea816156a1565b905092915050565b7f41413236206f76657220766572696669636174696f6e4761734c696d69740000600082015250565b6000615728601e83614550565b9150615733826156f2565b602082019050919050565b60006040820190506157536000830184613e42565b81810360208301526157648161571b565b905092915050565b7f41413234207369676e6174757265206572726f72000000000000000000000000600082015250565b60006157a2601483614550565b91506157ad8261576c565b602082019050919050565b60006040820190506157cd6000830184613e42565b81810360208301526157de81615795565b905092915050565b7f414132322065787069726564206f72206e6f7420647565000000000000000000600082015250565b600061581c601783614550565b9150615827826157e6565b602082019050919050565b60006040820190506158476000830184613e42565b81810360208301526158588161580f565b905092915050565b7f41413334207369676e6174757265206572726f72000000000000000000000000600082015250565b6000615896601483614550565b91506158a182615860565b602082019050919050565b60006040820190506158c16000830184613e42565b81810360208301526158d281615889565b905092915050565b7f41413332207061796d61737465722065787069726564206f72206e6f7420647560008201527f6500000000000000000000000000000000000000000000000000000000000000602082015250565b6000615936602183614550565b9150615941826158da565b604082019050919050565b60006040820190506159616000830184613e42565b818103602083015261597281615929565b905092915050565b6000610120830161598e60008401846151f1565b61599b6000860182615208565b506159a96020840184615217565b6159b66020860182614190565b506159c4604084018461523d565b85830360408701526159d78382846152b1565b925050506159e8606084018461523d565b85830360608701526159fb8382846152b1565b92505050615a0c60808401846152de565b615a1960808601826152f5565b50615a2760a0840184615217565b615a3460a0860182614190565b50615a4260c08401846152de565b615a4f60c08601826152f5565b50615a5d60e084018461523d565b85830360e0870152615a708382846152b1565b92505050615a8261010084018461523d565b858303610100870152615a968382846152b1565b925050508091505092915050565b60006040820190508181036000830152615abe818561597a565b9050615acd6020830184614139565b9392505050565b61014082016000820151615aeb6000850182615208565b506020820151615afe6020850182614190565b506040820151615b116040850182614190565b506060820151615b246060850182614190565b506080820151615b376080850182614190565b5060a0820151615b4a60a0850182614190565b5060c0820151615b5d60c0850182614190565b5060e0820151615b7060e0850182615208565b50610100820151615b85610100850182614190565b50610120820151615b9a610120850182614190565b50505050565b6101c082016000820151615bb76000850182615ad4565b506020820151615bcb6101408501826152f5565b506040820151615bdf610160850182614190565b506060820151615bf3610180850182614190565b506080820151615c076101a0850182614190565b50505050565b6000610200820190508181036000830152615c288186614642565b9050615c376020830185615ba0565b8181036101e0830152615c4a8184614642565b9050949350505050565b6000610200820190508181036000830152615c70818688614c55565b9050615c7f6020830185615ba0565b8181036101e0830152615c928184614642565b905095945050505050565b7f41413935206f7574206f66206761730000000000000000000000000000000000600082015250565b6000615cd3600f83614550565b9150615cde82615c9d565b602082019050919050565b6000604082019050615cfe6000830184613e42565b8181036020830152615d0f81615cc6565b905092915050565b7f4141393020696e76616c69642062656e65666963696172790000000000000000600082015250565b6000615d4d601883614550565b9150615d5882615d17565b602082019050919050565b60006020820190508181036000830152615d7c81615d40565b9050919050565b7f41413931206661696c65642073656e6420746f2062656e656669636961727900600082015250565b6000615db9601f83614550565b9150615dc482615d83565b602082019050919050565b60006020820190508181036000830152615de881615dac565b9050919050565b6000608082019050615e046000830187613e42565b615e116020830186613efd565b615e1e6040830185613e42565b615e2b6060830184613e42565b95945050505050565b600061010082019050615e4a600083018b614b3a565b615e57602083018a613e42565b615e646040830189614139565b615e716060830188614139565b615e7e6080830187614139565b615e8b60a0830186613e42565b615e9860c0830185614139565b615ea560e0830184614139565b9998505050505050505050565b7f4141393320696e76616c6964207061796d6173746572416e6444617461000000600082015250565b6000615ee8601d83614550565b9150615ef382615eb2565b602082019050919050565b60006020820190508181036000830152615f1781615edb565b9050919050565b60006060820190508181036000830152615f38818661597a565b9050615f476020830185614139565b615f546040830184613e42565b949350505050565b600081519050615f6b81613b67565b92915050565b600060208284031215615f8757615f866139aa565b5b6000615f9584828501615f5c565b91505092915050565b7f4141323320726576657274656400000000000000000000000000000000000000600082015250565b6000615fd4600d83614550565b9150615fdf82615f9e565b602082019050919050565b6000606082019050615fff6000830185613e42565b818103602083015261601081615fc7565b905081810360408301526160248184614642565b90509392505050565b7f41413231206469646e2774207061792070726566756e64000000000000000000600082015250565b6000616063601783614550565b915061606e8261602d565b602082019050919050565b600060408201905061608e6000830184613e42565b818103602083015261609f81616056565b905092915050565b7f41413331207061796d6173746572206465706f73697420746f6f206c6f770000600082015250565b60006160dd601e83614550565b91506160e8826160a7565b602082019050919050565b60006040820190506161086000830184613e42565b8181036020830152616119816160d0565b905092915050565b600061613461612f84613a4a565b613a2f565b9050828152602081018484840111156161505761614f6139b9565b5b61615b848285614618565b509392505050565b600082601f830112616178576161776139b4565b5b8151616188848260208601616121565b91505092915050565b600080604083850312156161a8576161a76139aa565b5b600083015167ffffffffffffffff8111156161c6576161c56139af565b5b6161d285828601616163565b92505060206161e385828601615f5c565b9150509250929050565b7f4141333320726576657274656400000000000000000000000000000000000000600082015250565b6000616223600d83614550565b915061622e826161ed565b602082019050919050565b600060608201905061624e6000830185613e42565b818103602083015261625f81616216565b905081810360408301526162738184614642565b90509392505050565b7f41413336206f766572207061796d6173746572566572696669636174696f6e4760008201527f61734c696d697400000000000000000000000000000000000000000000000000602082015250565b60006162d8602783614550565b91506162e38261627c565b604082019050919050565b60006040820190506163036000830184613e42565b8181036020830152616314816162cb565b905092915050565b600080fd5b600080fd5b6000808585111561633a5761633961631c565b5b8386111561634b5761634a616321565b5b6001850283019150848603905094509492505050565b600082905092915050565b60007fffffffffffffffffffffffffffffffffffffffff00000000000000000000000082169050919050565b600082821b905092915050565b60006163b18383616361565b826163bc813561636c565b925060148210156163fc576163f77fffffffffffffffffffffffffffffffffffffffff00000000000000000000000083601403600802616398565b831692505b505092915050565b60007fffffffffffffffffffffffffffffffff0000000000000000000000000000000082169050919050565b600061643c8383616361565b826164478135616404565b92506010821015616487576164827fffffffffffffffffffffffffffffffff0000000000000000000000000000000083601003600802616398565b831692505b505092915050565b7f414131302073656e64657220616c726561647920636f6e737472756374656400600082015250565b60006164c5601f83614550565b91506164d08261648f565b602082019050919050565b60006040820190506164f06000830184613e42565b8181036020830152616501816164b8565b905092915050565b7f4141313320696e6974436f6465206661696c6564206f72204f4f470000000000600082015250565b600061653f601b83614550565b915061654a82616509565b602082019050919050565b600060408201905061656a6000830184613e42565b818103602083015261657b81616532565b905092915050565b7f4141313420696e6974436f6465206d7573742072657475726e2073656e646572600082015250565b60006165b9602083614550565b91506165c482616583565b602082019050919050565b60006040820190506165e46000830184613e42565b81810360208301526165f5816165ac565b905092915050565b7f4141313520696e6974436f6465206d757374206372656174652073656e646572600082015250565b6000616633602083614550565b915061663e826165fd565b602082019050919050565b600060408201905061665e6000830184613e42565b818103602083015261666f81616626565b905092915050565b600060408201905061668c6000830185614b3a565b6166996020830184614b3a565b939250505056fea2646970667358221220f6e7d5acc3b3ce47e8c4e79583caee84134eab4d0c55f3973f51a15d53351cdb64736f6c63430008170033608060405234801561001057600080fd5b50610342806100206000396000f3fe608060405234801561001057600080fd5b506004361061002b5760003560e01c8063570e1a3614610030575b600080fd5b61004a6004803603810190610045919061017b565b610060565b6040516100579190610209565b60405180910390f35b60008083836000906014926100779392919061022e565b9061008291906102ad565b60601c905060008484601490809261009c9392919061022e565b8080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f8201169050808301925050505050505090506000602060008351602085016000875af1905060005193508061010357600093505b50505092915050565b600080fd5b600080fd5b600080fd5b600080fd5b600080fd5b60008083601f84011261013b5761013a610116565b5b8235905067ffffffffffffffff8111156101585761015761011b565b5b60208301915083600182028301111561017457610173610120565b5b9250929050565b600080602083850312156101925761019161010c565b5b600083013567ffffffffffffffff8111156101b0576101af610111565b5b6101bc85828601610125565b92509250509250929050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b60006101f3826101c8565b9050919050565b610203816101e8565b82525050565b600060208201905061021e60008301846101fa565b92915050565b600080fd5b600080fd5b6000808585111561024257610241610224565b5b8386111561025357610252610229565b5b6001850283019150848603905094509492505050565b600082905092915050565b60007fffffffffffffffffffffffffffffffffffffffff00000000000000000000000082169050919050565b600082821b905092915050565b60006102b98383610269565b826102c48135610274565b92506014821015610304576102ff7fffffffffffffffffffffffffffffffffffffffff000000000000000000000000836014036008026102a0565b831692505b50509291505056fea264697066735822122050dbb7b87383c3f370ab6e7c31231f1967684cb78ec9da388509e2ca89e70f0a64736f6c63430008170033", + "output": "0x60806040526004361061010c5760003560e01c806370a0823111610095578063b760faf911610064578063b760faf9146103b5578063bb9fe6bf146103d1578063c23a5cea146103e8578063dbed18e014610411578063fc7e286d1461043a5761011c565b806370a08231146102fd578063765e827f1461033a578063850aaf62146103635780639b249f691461038c5761011c565b80631b2e01b8116100dc5780631b2e01b8146101e0578063205c28781461021d57806322cdde4c1461024657806335567e1a146102835780635287ce12146102c05761011c565b806242dc531461012157806301ffc9a71461015e5780630396cb601461019b5780630bd28e3b146101b75761011c565b3661011c5761011a3361047b565b005b600080fd5b34801561012d57600080fd5b5061014860048036038101906101439190613db0565b6104db565b6040516101559190613e51565b60405180910390f35b34801561016a57600080fd5b5061018560048036038101906101809190613ec4565b6106c1565b6040516101929190613f0c565b60405180910390f35b6101b560048036038101906101b09190613f63565b6108b7565b005b3480156101c357600080fd5b506101de60048036038101906101d99190613fe0565b610c13565b005b3480156101ec57600080fd5b506102076004803603810190610202919061400d565b610cb0565b6040516102149190613e51565b60405180910390f35b34801561022957600080fd5b50610244600480360381019061023f919061408b565b610cd5565b005b34801561025257600080fd5b5061026d600480360381019061026891906140f0565b610e78565b60405161027a9190614148565b60405180910390f35b34801561028f57600080fd5b506102aa60048036038101906102a5919061400d565b610eb4565b6040516102b79190613e51565b60405180910390f35b3480156102cc57600080fd5b506102e760048036038101906102e29190614163565b610f63565b6040516102f4919061426f565b60405180910390f35b34801561030957600080fd5b50610324600480360381019061031f9190614163565b611076565b6040516103319190613e51565b60405180910390f35b34801561034657600080fd5b50610361600480360381019061035c91906142e0565b6110c1565b005b34801561036f57600080fd5b5061038a60048036038101906103859190614340565b611255565b005b34801561039857600080fd5b506103b360048036038101906103ae91906143a0565b611303565b005b6103cf60048036038101906103ca9190614163565b61047b565b005b3480156103dd57600080fd5b506103e66113c9565b005b3480156103f457600080fd5b5061040f600480360381019061040a91906143ed565b611579565b005b34801561041d57600080fd5b5061043860048036038101906104339190614470565b611879565b005b34801561044657600080fd5b50610461600480360381019061045c9190614163565b611d90565b6040516104729594939291906144fd565b60405180910390f35b60006104878234611e0f565b90508173ffffffffffffffffffffffffffffffffffffffff167f2da466a7b24304f47e87fa2e1e5a81b9831ce54fec19055ce277ca2f39ba42c4826040516104cf9190613e51565b60405180910390a25050565b6000805a90503073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161461054f576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610546906145ad565b60405180910390fd5b6000856000015190506000816060015190506127108260a001518201016040603f5a02816105805761057f6145cd565b5b0410156105b1577fdeaddead0000000000000000000000000000000000000000000000000000000060005260206000fd5b600080895111156106555760006105cf846000015160008c86611e7a565b9050806106535760006105e3610800611e93565b905060008151111561064d57846000015173ffffffffffffffffffffffffffffffffffffffff168a602001517f1c4fada7374c0a9ee8841fc38afe82932dc0f8e69012e927f061a8bae611a20187602001518460405161064492919061467b565b60405180910390a35b60019250505b505b600088608001515a86030190506106b2828a8a8a8080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f8201169050808301925050505050505084611ec3565b95505050505050949350505050565b60007f3e84f021000000000000000000000000000000000000000000000000000000007fcf28ef97000000000000000000000000000000000000000000000000000000007f915074d80000000000000000000000000000000000000000000000000000000018187bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614806107d057507f915074d8000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b8061083857507fcf28ef97000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b806108a057507f3e84f021000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b806108b057506108af82612164565b5b9050919050565b60008060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020905060008263ffffffff1611610942576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610939906146f7565b60405180910390fd5b80600101600f9054906101000a900463ffffffff1663ffffffff168263ffffffff1610156109a5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161099c90614763565b60405180910390fd5b6000348260010160019054906101000a90046dffffffffffffffffffffffffffff166dffffffffffffffffffffffffffff166109e191906147b2565b905060008111610a26576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610a1d90614832565b60405180910390fd5b6dffffffffffffffffffffffffffff8016811115610a79576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610a709061489e565b60405180910390fd5b6040518060a0016040528083600001548152602001600115158152602001826dffffffffffffffffffffffffffff1681526020018463ffffffff168152602001600065ffffffffffff168152506000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000820151816000015560208201518160010160006101000a81548160ff02191690831515021790555060408201518160010160016101000a8154816dffffffffffffffffffffffffffff02191690836dffffffffffffffffffffffffffff160217905550606082015181600101600f6101000a81548163ffffffff021916908363ffffffff16021790555060808201518160010160136101000a81548165ffffffffffff021916908365ffffffffffff1602179055509050503373ffffffffffffffffffffffffffffffffffffffff167fa5ae833d0bb1dcd632d98a8b70973e8516812898e19bf27b70071ebc8dc52c018285604051610c069291906148f9565b60405180910390a2505050565b600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008277ffffffffffffffffffffffffffffffffffffffffffffffff1677ffffffffffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000815480929190610ca890614922565b919050555050565b6001602052816000526040600020602052806000526040600020600091509150505481565b60008060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002090508060000154821115610d5e576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610d55906149b6565b60405180910390fd5b818160000154610d6e91906149d6565b81600001819055503373ffffffffffffffffffffffffffffffffffffffff167fd1c19fbcd4551a5edfb66d43d2e337c04837afda3482b42bdf569a8fccdae5fb8484604051610dbe929190614a5f565b60405180910390a260008373ffffffffffffffffffffffffffffffffffffffff1683604051610dec90614ab9565b60006040518083038185875af1925050503d8060008114610e29576040519150601f19603f3d011682016040523d82523d6000602084013e610e2e565b606091505b5050905080610e72576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610e6990614b1a565b60405180910390fd5b50505050565b6000610e83826121ce565b3046604051602001610e9793929190614b49565b604051602081830303815290604052805190602001209050919050565b600060408277ffffffffffffffffffffffffffffffffffffffffffffffff16901b600160008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008477ffffffffffffffffffffffffffffffffffffffffffffffff1677ffffffffffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205417905092915050565b610f6b613853565b6000808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206040518060a0016040529081600082015481526020016001820160009054906101000a900460ff161515151581526020016001820160019054906101000a90046dffffffffffffffffffffffffffff166dffffffffffffffffffffffffffff166dffffffffffffffffffffffffffff16815260200160018201600f9054906101000a900463ffffffff1663ffffffff1663ffffffff1681526020016001820160139054906101000a900465ffffffffffff1665ffffffffffff1665ffffffffffff16815250509050919050565b60008060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600001549050919050565b6110c96121e7565b600083839050905060008167ffffffffffffffff8111156110ed576110ec6139cf565b5b60405190808252806020026020018201604052801561112657816020015b6111136138a2565b81526020019060019003908161110b5790505b50905060005b828110156111a657600082828151811061114957611148614b80565b5b60200260200101519050600080611185848a8a8781811061116d5761116c614b80565b5b905060200281019061117f9190614bbe565b8561222b565b915091506111968483836000612421565b505050808060010191505061112c565b5060007fbb47ee3e183a558b1a2ff0874b079f3fc5478b7454eacf2bfc5af2ff5878f97260405160405180910390a160005b8381101561123a57611229818888848181106111f7576111f6614b80565b5b90506020028101906112099190614bbe565b85848151811061121c5761121b614b80565b5b60200260200101516125b4565b8201915080806001019150506111d8565b506112458482612955565b505050611250612a75565b505050565b6000808473ffffffffffffffffffffffffffffffffffffffff16848460405161127f929190614c0c565b600060405180830381855af49150503d80600081146112ba576040519150601f19603f3d011682016040523d82523d6000602084013e6112bf565b606091505b509150915081816040517f994105540000000000000000000000000000000000000000000000000000000081526004016112fa929190614c25565b60405180910390fd5b600061130d612a7f565b73ffffffffffffffffffffffffffffffffffffffff1663570e1a3684846040518363ffffffff1660e01b8152600401611347929190614c82565b6020604051808303816000875af1158015611366573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061138a9190614cbb565b9050806040517f6ca7b8060000000000000000000000000000000000000000000000000000000081526004016113c09190614ce8565b60405180910390fd5b60008060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000209050600081600101600f9054906101000a900463ffffffff1663ffffffff1603611468576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161145f90614d4f565b60405180910390fd5b8060010160009054906101000a900460ff166114b9576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016114b090614dbb565b60405180910390fd5b600081600101600f9054906101000a900463ffffffff1663ffffffff16426114e19190614ddb565b9050808260010160136101000a81548165ffffffffffff021916908365ffffffffffff16021790555060008260010160006101000a81548160ff0219169083151502179055503373ffffffffffffffffffffffffffffffffffffffff167ffa9b3c14cc825c412c9ed81b3ba365a5b459439403f18829e572ed53a4180f0a8260405161156d9190614e46565b60405180910390a25050565b60008060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020905060008160010160019054906101000a90046dffffffffffffffffffffffffffff166dffffffffffffffffffffffffffff16905060008111611631576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161162890614ead565b60405180910390fd5b60008260010160139054906101000a900465ffffffffffff1665ffffffffffff1611611692576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161168990614f19565b60405180910390fd5b428260010160139054906101000a900465ffffffffffff1665ffffffffffff1611156116f3576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016116ea90614f85565b60405180910390fd5b600082600101600f6101000a81548163ffffffff021916908363ffffffff16021790555060008260010160136101000a81548165ffffffffffff021916908365ffffffffffff16021790555060008260010160016101000a8154816dffffffffffffffffffffffffffff02191690836dffffffffffffffffffffffffffff1602179055503373ffffffffffffffffffffffffffffffffffffffff167fb7c918e0e249f999e965cafeb6c664271b3f4317d296461500e71da39f0cbda384836040516117bf929190614a5f565b60405180910390a260008373ffffffffffffffffffffffffffffffffffffffff16826040516117ed90614ab9565b60006040518083038185875af1925050503d806000811461182a576040519150601f19603f3d011682016040523d82523d6000602084013e61182f565b606091505b5050905080611873576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161186a90614ff1565b60405180910390fd5b50505050565b6118816121e7565b60008383905090506000805b82811015611a6857368686838181106118a9576118a8614b80565b5b90506020028101906118bb9190615011565b90503660008280600001906118d09190615039565b9150915060008360200160208101906118e991906150da565b9050600173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff160361195a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161195190615153565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614611a46578073ffffffffffffffffffffffffffffffffffffffff16632dd8113384848780604001906119bc9190615173565b6040518563ffffffff1660e01b81526004016119db94939291906154ec565b60006040518083038186803b1580156119f357600080fd5b505afa925050508015611a04575060015b611a4557806040517f86a9f750000000000000000000000000000000000000000000000000000000008152600401611a3c9190614ce8565b60405180910390fd5b5b8282905086611a5591906147b2565b955050505050808060010191505061188d565b5060008167ffffffffffffffff811115611a8557611a846139cf565b5b604051908082528060200260200182016040528015611abe57816020015b611aab6138a2565b815260200190600190039081611aa35790505b5090506000805b84811015611bc85736888883818110611ae157611ae0614b80565b5b9050602002810190611af39190615011565b9050366000828060000190611b089190615039565b915091506000836020016020810190611b2191906150da565b9050600083839050905060005b81811015611bb5576000898981518110611b4b57611b4a614b80565b5b60200260200101519050600080611b878b898987818110611b6f57611b6e614b80565b5b9050602002810190611b819190614bbe565b8561222b565b91509150611b9784838389612421565b8a80611ba290614922565b9b50505050508080600101915050611b2e565b5050505050508080600101915050611ac5565b507fbb47ee3e183a558b1a2ff0874b079f3fc5478b7454eacf2bfc5af2ff5878f97260405160405180910390a1600080915060005b85811015611d2f5736898983818110611c1957611c18614b80565b5b9050602002810190611c2b9190615011565b9050806020016020810190611c4091906150da565b73ffffffffffffffffffffffffffffffffffffffff167f575ff3acadd5ab348fe1855e217e0f3678f8d767d7494c9f9fefbee2e17cca4d60405160405180910390a2366000828060000190611c959190615039565b91509150600082829050905060005b81811015611d1d57611cf588858584818110611cc357611cc2614b80565b5b9050602002810190611cd59190614bbe565b8b8b81518110611ce857611ce7614b80565b5b60200260200101516125b4565b87611d0091906147b2565b96508780611d0d90614922565b9850508080600101915050611ca4565b50505050508080600101915050611bfd565b50600073ffffffffffffffffffffffffffffffffffffffff167f575ff3acadd5ab348fe1855e217e0f3678f8d767d7494c9f9fefbee2e17cca4d60405160405180910390a2611d7e8682612955565b5050505050611d8b612a75565b505050565b60006020528060005260406000206000915090508060000154908060010160009054906101000a900460ff16908060010160019054906101000a90046dffffffffffffffffffffffffffff169080600101600f9054906101000a900463ffffffff16908060010160139054906101000a900465ffffffffffff16905085565b6000806000808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002090506000838260000154611e6491906147b2565b9050808260000181905550809250505092915050565b6000806000845160208601878987f19050949350505050565b60603d82811115611ea2578290505b604051602082018101604052818152816000602083013e8092505050919050565b6000805a9050600080866000015190506000611ede82612aa7565b905060008260e001519050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603611f295782600001519350612029565b809350600088511115612028578187029550600280811115611f4e57611f4d615527565b5b8a6002811115611f6157611f60615527565b5b14612027578073ffffffffffffffffffffffffffffffffffffffff16637c627b218460a001518c8b8a876040518663ffffffff1660e01b8152600401611faa949392919061559e565b600060405180830381600088803b158015611fc457600080fd5b5087f193505050508015611fd6575060015b612026576000611fe7610800611e93565b9050806040517fad7954bc00000000000000000000000000000000000000000000000000000000815260040161201d91906155ea565b60405180910390fd5b5b5b5b5a85038701965060008360a00151846060015101905060008a60800151890390508082111561207a576000818303905060006064600a83028161206f5761206e6145cd565b5b049050808b019a5050505b505081870295506000896040015190508681101561210a576002808111156120a5576120a4615527565b5b8b60028111156120b8576120b7615527565b5b036120db578096506120c98a612ae3565b6120d68a6000898b612b49565b612105565b7fdeadaa510000000000000000000000000000000000000000000000000000000060005260206000fd5b612156565b6000878203905061211b8682611e0f565b50600080600281111561213157612130615527565b5b8d600281111561214457612143615527565b5b1490506121538c828b8d612b49565b50505b505050505050949350505050565b60007f01ffc9a7000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916149050919050565b60006121d982612bd7565b805190602001209050919050565b6002805403612222576040517f3ee5aeb500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60028081905550565b60008060005a90506000846000015190506122468682612c9b565b61224f86610e78565b85602001818152505060008160400151905060008261012001518361010001518460a0015185608001518660600151868860c0015117171717171790506effffffffffffffffffffffffffffff80168111156122e0576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016122d790615658565b60405180910390fd5b60006122eb84612e57565b90506122fa8a8a8a8487612e89565b965061230e846000015185602001516130c6565b61234f57896040517f220266b600000000000000000000000000000000000000000000000000000000815260040161234691906156c4565b60405180910390fd5b825a8603111561239657896040517f220266b600000000000000000000000000000000000000000000000000000000815260040161238d919061573e565b60405180910390fd5b6060600073ffffffffffffffffffffffffffffffffffffffff168560e0015173ffffffffffffffffffffffffffffffffffffffff16146123e5576123dc8b8b8b85613184565b80985081925050505b818960400181815250506123f881613371565b8960600181815250508960a001355a870301896080018181525050505050505050935093915050565b60008061242d8561337b565b915091508173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16146124a157856040517f220266b600000000000000000000000000000000000000000000000000000000815260040161249891906157b8565b60405180910390fd5b80156124e457856040517f220266b60000000000000000000000000000000000000000000000000000000081526004016124db9190615832565b60405180910390fd5b60006124ef8561337b565b8093508192505050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161461256857866040517f220266b600000000000000000000000000000000000000000000000000000000815260040161255f91906158ac565b60405180910390fd5b81156125ab57866040517f220266b60000000000000000000000000000000000000000000000000000000081526004016125a2919061594c565b60405180910390fd5b50505050505050565b6000805a905060006125c984606001516133d4565b905060008060405190503660008880606001906125e69190615173565b91509150606060008260038111156125fd57843591505b50638dd7712f60e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916817bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916036127245760008b8b60200151604051602401612663929190615aa4565b604051602081830303815290604052638dd7712f60e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff838183161783525050505090503073ffffffffffffffffffffffffffffffffffffffff166242dc53828d8b6040516024016126da93929190615c0d565b604051602081830303815290604052915060e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff838183161783525050505092505061279b565b3073ffffffffffffffffffffffffffffffffffffffff166242dc5385858d8b6040516024016127569493929190615c54565b604051602081830303815290604052915060e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff838183161783525050505091505b602060008351602085016000305af1955060005198508460405250505050508061294b5760003d806020036127d65760206000803e60005191505b507fdeaddead00000000000000000000000000000000000000000000000000000000810361283b57876040517f220266b60000000000000000000000000000000000000000000000000000000081526004016128329190615ce9565b60405180910390fd5b7fdeadaa510000000000000000000000000000000000000000000000000000000081036128aa57600086608001515a8661287591906149d6565b61287f91906147b2565b905060008760400151905061289388612ae3565b6128a08860008385612b49565b8096505050612949565b85600001516000015173ffffffffffffffffffffffffffffffffffffffff1686602001517ff62676f440ff169a3a9afdbf812e89e7f95975ee8e5c31214ffdef631c5f4792886000015160200151612903610800611e93565b60405161291192919061467b565b60405180910390a3600086608001515a8661292c91906149d6565b61293691906147b2565b90506129456002888684611ec3565b9550505b505b5050509392505050565b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16036129c4576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016129bb90615d63565b60405180910390fd5b60008273ffffffffffffffffffffffffffffffffffffffff16826040516129ea90614ab9565b60006040518083038185875af1925050503d8060008114612a27576040519150601f19603f3d011682016040523d82523d6000602084013e612a2c565b606091505b5050905080612a70576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612a6790615dcf565b60405180910390fd5b505050565b6001600281905550565b60007f000000000000000000000000dd8a726a079a85effe3183ecfbe0de8ac36b1e65905090565b600080826101000151905060008361012001519050808203612acd578192505050612ade565b612ad9824883016133de565b925050505b919050565b80600001516000015173ffffffffffffffffffffffffffffffffffffffff1681602001517f67b4fa9642f42120bf031f3051d1824b0fe25627945b27b8a6a65d5761d5482e836000015160200151604051612b3e9190613e51565b60405180910390a350565b836000015160e0015173ffffffffffffffffffffffffffffffffffffffff1684600001516000015173ffffffffffffffffffffffffffffffffffffffff1685602001517f49628fd1471006c1482da88028e9ce4dbb080b815c9b0344d39e5a8e6ec1419f876000015160200151878787604051612bc99493929190615def565b60405180910390a450505050565b60606000612be4836133f7565b90506000836020013590506000612c09858060400190612c049190615173565b613407565b90506000612c25868060600190612c209190615173565b613407565b905060008660800135905060008760a00135905060008860c0013590506000612c5c8a8060e00190612c579190615173565b613407565b90508787878787878787604051602001612c7d989796959493929190615e34565b60405160208183030381529060405298505050505050505050919050565b816000016020810190612cae9190614163565b816000019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250508160200135816020018181525050612d00826080013561341e565b8260400183606001828152508281525050508160a001358160c0018181525050612d2d8260c0013561341e565b8261012001836101000182815250828152505050366000838060e00190612d549190615173565b915091506000828290501115612e01576034828290501015612dab576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612da290615efe565b60405180910390fd5b612db5828261345c565b8560e001866080018760a00183815250838152508373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815250505050612e51565b60008360e0019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff1681525050600083608001818152505060008360a00181815250505b50505050565b6000808260c001518360a001518460800151856060015186604001510101010190508261010001518102915050919050565b60008084600001519050600081600001519050612eb68887898060400190612eb19190615173565b6134fe565b60008260e00151905060008073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603612f17576000612eff84611076565b9050878111612f1057808803612f13565b60005b9150505b8273ffffffffffffffffffffffffffffffffffffffff166319822f7c878b8b60200151856040518563ffffffff1660e01b8152600401612f5993929190615f1e565b60206040518083038160008887f193505050508015612f9657506040513d601f19601f82011682018060405250810190612f939190615f71565b60015b612fe35789612fa6610800611e93565b6040517f65c8fd4d000000000000000000000000000000000000000000000000000000008152600401612fda929190615fea565b60405180910390fd5b80955050600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16036130b95760008060008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000209050600081600001549050808911156130ab578b6040517f220266b60000000000000000000000000000000000000000000000000000000081526004016130a29190616079565b60405180910390fd5b888103826000018190555050505b5050505095945050505050565b600080604083901c905060008390508067ffffffffffffffff16600160008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008477ffffffffffffffffffffffffffffffffffffffffffffffff1677ffffffffffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600081548092919061317590614922565b91905055149250505092915050565b60606000805a905060008560000151905060008160e00151905060008060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002090506000816000015490508781101561322e578a6040517f220266b600000000000000000000000000000000000000000000000000000000815260040161322591906160f3565b60405180910390fd5b87810382600001819055506000846080015190508373ffffffffffffffffffffffffffffffffffffffff166352b7512c828d8d602001518d6040518563ffffffff1660e01b815260040161328493929190615f1e565b60006040518083038160008887f1935050505080156132c657506040513d6000823e3d601f19601f820116820180604052508101906132c39190616191565b60015b613313578b6132d6610800611e93565b6040517f65c8fd4d00000000000000000000000000000000000000000000000000000000815260040161330a929190616239565b60405180910390fd5b8199508098505050805a87031115613362578b6040517f220266b600000000000000000000000000000000000000000000000000000000815260040161335991906162ee565b60405180910390fd5b50505050505094509492505050565b6000819050919050565b6000806000830361339257600080915091506133cf565b600061339d846137cf565b9050806040015165ffffffffffff164211806133c45750806020015165ffffffffffff1642105b915080600001519250505b915091565b6060819050919050565b60008183106133ed57816133ef565b825b905092915050565b6000808235905080915050919050565b600060405182808583378082209250505092915050565b6000808260801c8360001c816fffffffffffffffffffffffffffffffff169150806fffffffffffffffffffffffffffffffff16905091509150915091565b6000806000848460009060149261347593929190616326565b9061348091906163a5565b60601c858560149060249261349793929190616326565b906134a29190616430565b60801c86866024906034926134b993929190616326565b906134c49190616430565b60801c816fffffffffffffffffffffffffffffffff169150806fffffffffffffffffffffffffffffffff1690509250925092509250925092565b600082829050146137c9576000836000015160000151905060008173ffffffffffffffffffffffffffffffffffffffff163b1461357257846040517f220266b600000000000000000000000000000000000000000000000000000000815260040161356991906164db565b60405180910390fd5b600061357c612a7f565b73ffffffffffffffffffffffffffffffffffffffff1663570e1a3686600001516040015186866040518463ffffffff1660e01b81526004016135bf929190614c82565b60206040518083038160008887f11580156135de573d6000803e3d6000fd5b50505050506040513d601f19601f820116820180604052508101906136039190614cbb565b9050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff160361367657856040517f220266b600000000000000000000000000000000000000000000000000000000815260040161366d9190616555565b60405180910390fd5b8173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16146136e657856040517f220266b60000000000000000000000000000000000000000000000000000000081526004016136dd91906165cf565b60405180910390fd5b60008173ffffffffffffffffffffffffffffffffffffffff163b0361374257856040517f220266b60000000000000000000000000000000000000000000000000000000081526004016137399190616649565b60405180910390fd5b6000848460009060149261375893929190616326565b9061376391906163a5565b60601c90508273ffffffffffffffffffffffffffffffffffffffff1686602001517fd51a9c61267aa6196961883ecf5ff2da6619c37dac0fa92122513fb32c032d2d83896000015160e001516040516137bd929190616677565b60405180910390a35050505b50505050565b6137d76138da565b6000829050600060a084901c905060008165ffffffffffff16036137ff5765ffffffffffff90505b600060d085901c905060405180606001604052808473ffffffffffffffffffffffffffffffffffffffff1681526020018265ffffffffffff1681526020018365ffffffffffff168152509350505050919050565b6040518060a001604052806000815260200160001515815260200160006dffffffffffffffffffffffffffff168152602001600063ffffffff168152602001600065ffffffffffff1681525090565b6040518060a001604052806138b5613921565b8152602001600080191681526020016000815260200160008152602001600081525090565b6040518060600160405280600073ffffffffffffffffffffffffffffffffffffffff168152602001600065ffffffffffff168152602001600065ffffffffffff1681525090565b604051806101400160405280600073ffffffffffffffffffffffffffffffffffffffff168152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600073ffffffffffffffffffffffffffffffffffffffff16815260200160008152602001600081525090565b6000604051905090565b600080fd5b600080fd5b600080fd5b600080fd5b6000601f19601f8301169050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b613a07826139be565b810181811067ffffffffffffffff82111715613a2657613a256139cf565b5b80604052505050565b6000613a396139a0565b9050613a4582826139fe565b919050565b600067ffffffffffffffff821115613a6557613a646139cf565b5b613a6e826139be565b9050602081019050919050565b82818337600083830152505050565b6000613a9d613a9884613a4a565b613a2f565b905082815260208101848484011115613ab957613ab86139b9565b5b613ac4848285613a7b565b509392505050565b600082601f830112613ae157613ae06139b4565b5b8135613af1848260208601613a8a565b91505092915050565b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000613b2a82613aff565b9050919050565b613b3a81613b1f565b8114613b4557600080fd5b50565b600081359050613b5781613b31565b92915050565b6000819050919050565b613b7081613b5d565b8114613b7b57600080fd5b50565b600081359050613b8d81613b67565b92915050565b60006101408284031215613baa57613ba9613afa565b5b613bb5610140613a2f565b90506000613bc584828501613b48565b6000830152506020613bd984828501613b7e565b6020830152506040613bed84828501613b7e565b6040830152506060613c0184828501613b7e565b6060830152506080613c1584828501613b7e565b60808301525060a0613c2984828501613b7e565b60a08301525060c0613c3d84828501613b7e565b60c08301525060e0613c5184828501613b48565b60e083015250610100613c6684828501613b7e565b61010083015250610120613c7c84828501613b7e565b6101208301525092915050565b6000819050919050565b613c9c81613c89565b8114613ca757600080fd5b50565b600081359050613cb981613c93565b92915050565b60006101c08284031215613cd657613cd5613afa565b5b613ce060a0613a2f565b90506000613cf084828501613b93565b600083015250610140613d0584828501613caa565b602083015250610160613d1a84828501613b7e565b604083015250610180613d2f84828501613b7e565b6060830152506101a0613d4484828501613b7e565b60808301525092915050565b600080fd5b600080fd5b60008083601f840112613d7057613d6f6139b4565b5b8235905067ffffffffffffffff811115613d8d57613d8c613d50565b5b602083019150836001820283011115613da957613da8613d55565b5b9250929050565b6000806000806102008587031215613dcb57613dca6139aa565b5b600085013567ffffffffffffffff811115613de957613de86139af565b5b613df587828801613acc565b9450506020613e0687828801613cbf565b9350506101e085013567ffffffffffffffff811115613e2857613e276139af565b5b613e3487828801613d5a565b925092505092959194509250565b613e4b81613b5d565b82525050565b6000602082019050613e666000830184613e42565b92915050565b60007fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b613ea181613e6c565b8114613eac57600080fd5b50565b600081359050613ebe81613e98565b92915050565b600060208284031215613eda57613ed96139aa565b5b6000613ee884828501613eaf565b91505092915050565b60008115159050919050565b613f0681613ef1565b82525050565b6000602082019050613f216000830184613efd565b92915050565b600063ffffffff82169050919050565b613f4081613f27565b8114613f4b57600080fd5b50565b600081359050613f5d81613f37565b92915050565b600060208284031215613f7957613f786139aa565b5b6000613f8784828501613f4e565b91505092915050565b600077ffffffffffffffffffffffffffffffffffffffffffffffff82169050919050565b613fbd81613f90565b8114613fc857600080fd5b50565b600081359050613fda81613fb4565b92915050565b600060208284031215613ff657613ff56139aa565b5b600061400484828501613fcb565b91505092915050565b60008060408385031215614024576140236139aa565b5b600061403285828601613b48565b925050602061404385828601613fcb565b9150509250929050565b600061405882613aff565b9050919050565b6140688161404d565b811461407357600080fd5b50565b6000813590506140858161405f565b92915050565b600080604083850312156140a2576140a16139aa565b5b60006140b085828601614076565b92505060206140c185828601613b7e565b9150509250929050565b600080fd5b600061012082840312156140e7576140e66140cb565b5b81905092915050565b600060208284031215614106576141056139aa565b5b600082013567ffffffffffffffff811115614124576141236139af565b5b614130848285016140d0565b91505092915050565b61414281613c89565b82525050565b600060208201905061415d6000830184614139565b92915050565b600060208284031215614179576141786139aa565b5b600061418784828501613b48565b91505092915050565b61419981613b5d565b82525050565b6141a881613ef1565b82525050565b60006dffffffffffffffffffffffffffff82169050919050565b6141d1816141ae565b82525050565b6141e081613f27565b82525050565b600065ffffffffffff82169050919050565b614201816141e6565b82525050565b60a08201600082015161421d6000850182614190565b506020820151614230602085018261419f565b50604082015161424360408501826141c8565b50606082015161425660608501826141d7565b50608082015161426960808501826141f8565b50505050565b600060a0820190506142846000830184614207565b92915050565b60008083601f8401126142a05761429f6139b4565b5b8235905067ffffffffffffffff8111156142bd576142bc613d50565b5b6020830191508360208202830111156142d9576142d8613d55565b5b9250929050565b6000806000604084860312156142f9576142f86139aa565b5b600084013567ffffffffffffffff811115614317576143166139af565b5b6143238682870161428a565b9350935050602061433686828701614076565b9150509250925092565b600080600060408486031215614359576143586139aa565b5b600061436786828701613b48565b935050602084013567ffffffffffffffff811115614388576143876139af565b5b61439486828701613d5a565b92509250509250925092565b600080602083850312156143b7576143b66139aa565b5b600083013567ffffffffffffffff8111156143d5576143d46139af565b5b6143e185828601613d5a565b92509250509250929050565b600060208284031215614403576144026139aa565b5b600061441184828501614076565b91505092915050565b60008083601f8401126144305761442f6139b4565b5b8235905067ffffffffffffffff81111561444d5761444c613d50565b5b60208301915083602082028301111561446957614468613d55565b5b9250929050565b600080600060408486031215614489576144886139aa565b5b600084013567ffffffffffffffff8111156144a7576144a66139af565b5b6144b38682870161441a565b935093505060206144c686828701614076565b9150509250925092565b6144d9816141ae565b82525050565b6144e881613f27565b82525050565b6144f7816141e6565b82525050565b600060a0820190506145126000830188613e42565b61451f6020830187613efd565b61452c60408301866144d0565b61453960608301856144df565b61454660808301846144ee565b9695505050505050565b600082825260208201905092915050565b7f4141393220696e7465726e616c2063616c6c206f6e6c79000000000000000000600082015250565b6000614597601783614550565b91506145a282614561565b602082019050919050565b600060208201905081810360008301526145c68161458a565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b600081519050919050565b600082825260208201905092915050565b60005b8381101561463657808201518184015260208101905061461b565b60008484015250505050565b600061464d826145fc565b6146578185614607565b9350614667818560208601614618565b614670816139be565b840191505092915050565b60006040820190506146906000830185613e42565b81810360208301526146a28184614642565b90509392505050565b7f6d757374207370656369667920756e7374616b652064656c6179000000000000600082015250565b60006146e1601a83614550565b91506146ec826146ab565b602082019050919050565b60006020820190508181036000830152614710816146d4565b9050919050565b7f63616e6e6f7420646563726561736520756e7374616b652074696d6500000000600082015250565b600061474d601c83614550565b915061475882614717565b602082019050919050565b6000602082019050818103600083015261477c81614740565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60006147bd82613b5d565b91506147c883613b5d565b92508282019050808211156147e0576147df614783565b5b92915050565b7f6e6f207374616b65207370656369666965640000000000000000000000000000600082015250565b600061481c601283614550565b9150614827826147e6565b602082019050919050565b6000602082019050818103600083015261484b8161480f565b9050919050565b7f7374616b65206f766572666c6f77000000000000000000000000000000000000600082015250565b6000614888600e83614550565b915061489382614852565b602082019050919050565b600060208201905081810360008301526148b78161487b565b9050919050565b6000819050919050565b60006148e36148de6148d984613f27565b6148be565b613b5d565b9050919050565b6148f3816148c8565b82525050565b600060408201905061490e6000830185613e42565b61491b60208301846148ea565b9392505050565b600061492d82613b5d565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361495f5761495e614783565b5b600182019050919050565b7f576974686472617720616d6f756e7420746f6f206c6172676500000000000000600082015250565b60006149a0601983614550565b91506149ab8261496a565b602082019050919050565b600060208201905081810360008301526149cf81614993565b9050919050565b60006149e182613b5d565b91506149ec83613b5d565b9250828203905081811115614a0457614a03614783565b5b92915050565b6000614a25614a20614a1b84613aff565b6148be565b613aff565b9050919050565b6000614a3782614a0a565b9050919050565b6000614a4982614a2c565b9050919050565b614a5981614a3e565b82525050565b6000604082019050614a746000830185614a50565b614a816020830184613e42565b9392505050565b600081905092915050565b50565b6000614aa3600083614a88565b9150614aae82614a93565b600082019050919050565b6000614ac482614a96565b9150819050919050565b7f6661696c656420746f2077697468647261770000000000000000000000000000600082015250565b6000614b04601283614550565b9150614b0f82614ace565b602082019050919050565b60006020820190508181036000830152614b3381614af7565b9050919050565b614b4381613b1f565b82525050565b6000606082019050614b5e6000830186614139565b614b6b6020830185614b3a565b614b786040830184613e42565b949350505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600080fd5b600080fd5b600080fd5b60008235600161012003833603038112614bdb57614bda614baf565b5b80830191505092915050565b6000614bf38385614a88565b9350614c00838584613a7b565b82840190509392505050565b6000614c19828486614be7565b91508190509392505050565b6000604082019050614c3a6000830185613efd565b8181036020830152614c4c8184614642565b90509392505050565b6000614c618385614607565b9350614c6e838584613a7b565b614c77836139be565b840190509392505050565b60006020820190508181036000830152614c9d818486614c55565b90509392505050565b600081519050614cb581613b31565b92915050565b600060208284031215614cd157614cd06139aa565b5b6000614cdf84828501614ca6565b91505092915050565b6000602082019050614cfd6000830184614b3a565b92915050565b7f6e6f74207374616b656400000000000000000000000000000000000000000000600082015250565b6000614d39600a83614550565b9150614d4482614d03565b602082019050919050565b60006020820190508181036000830152614d6881614d2c565b9050919050565b7f616c726561647920756e7374616b696e67000000000000000000000000000000600082015250565b6000614da5601183614550565b9150614db082614d6f565b602082019050919050565b60006020820190508181036000830152614dd481614d98565b9050919050565b6000614de6826141e6565b9150614df1836141e6565b9250828201905065ffffffffffff811115614e0f57614e0e614783565b5b92915050565b6000614e30614e2b614e26846141e6565b6148be565b613b5d565b9050919050565b614e4081614e15565b82525050565b6000602082019050614e5b6000830184614e37565b92915050565b7f4e6f207374616b6520746f207769746864726177000000000000000000000000600082015250565b6000614e97601483614550565b9150614ea282614e61565b602082019050919050565b60006020820190508181036000830152614ec681614e8a565b9050919050565b7f6d7573742063616c6c20756e6c6f636b5374616b652829206669727374000000600082015250565b6000614f03601d83614550565b9150614f0e82614ecd565b602082019050919050565b60006020820190508181036000830152614f3281614ef6565b9050919050565b7f5374616b65207769746864726177616c206973206e6f74206475650000000000600082015250565b6000614f6f601b83614550565b9150614f7a82614f39565b602082019050919050565b60006020820190508181036000830152614f9e81614f62565b9050919050565b7f6661696c656420746f207769746864726177207374616b650000000000000000600082015250565b6000614fdb601883614550565b9150614fe682614fa5565b602082019050919050565b6000602082019050818103600083015261500a81614fce565b9050919050565b60008235600160600383360303811261502d5761502c614baf565b5b80830191505092915050565b6000808335600160200384360303811261505657615055614baf565b5b80840192508235915067ffffffffffffffff82111561507857615077614bb4565b5b60208301925060208202360383131561509457615093614bb9565b5b509250929050565b60006150a782613b1f565b9050919050565b6150b78161509c565b81146150c257600080fd5b50565b6000813590506150d4816150ae565b92915050565b6000602082840312156150f0576150ef6139aa565b5b60006150fe848285016150c5565b91505092915050565b7f4141393620696e76616c69642061676772656761746f72000000000000000000600082015250565b600061513d601783614550565b915061514882615107565b602082019050919050565b6000602082019050818103600083015261516c81615130565b9050919050565b600080833560016020038436030381126151905761518f614baf565b5b80840192508235915067ffffffffffffffff8211156151b2576151b1614bb4565b5b6020830192506001820236038313156151ce576151cd614bb9565b5b509250929050565b600082825260208201905092915050565b6000819050919050565b60006152006020840184613b48565b905092915050565b61521181613b1f565b82525050565b60006152266020840184613b7e565b905092915050565b600080fd5b600080fd5b600080fd5b6000808335600160200384360303811261525a57615259615238565b5b83810192508235915060208301925067ffffffffffffffff8211156152825761528161522e565b5b60018202360383131561529857615297615233565b5b509250929050565b600082825260208201905092915050565b60006152bd83856152a0565b93506152ca838584613a7b565b6152d3836139be565b840190509392505050565b60006152ed6020840184613caa565b905092915050565b6152fe81613c89565b82525050565b6000610120830161531860008401846151f1565b6153256000860182615208565b506153336020840184615217565b6153406020860182614190565b5061534e604084018461523d565b85830360408701526153618382846152b1565b92505050615372606084018461523d565b85830360608701526153858382846152b1565b9250505061539660808401846152de565b6153a360808601826152f5565b506153b160a0840184615217565b6153be60a0860182614190565b506153cc60c08401846152de565b6153d960c08601826152f5565b506153e760e084018461523d565b85830360e08701526153fa8382846152b1565b9250505061540c61010084018461523d565b8583036101008701526154208382846152b1565b925050508091505092915050565b600061543a8383615304565b905092915050565b6000823560016101200383360303811261545f5761545e615238565b5b82810191505092915050565b6000602082019050919050565b600061548483856151d6565b935083602084028501615496846151e7565b8060005b878110156154da5784840389526154b18284615442565b6154bb858261542e565b94506154c68361546b565b925060208a0199505060018101905061549a565b50829750879450505050509392505050565b60006040820190508181036000830152615507818688615478565b9050818103602083015261551c818486614c55565b905095945050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b6003811061556757615566615527565b5b50565b600081905061557882615556565b919050565b60006155888261556a565b9050919050565b6155988161557d565b82525050565b60006080820190506155b3600083018761558f565b81810360208301526155c58186614642565b90506155d46040830185613e42565b6155e16060830184613e42565b95945050505050565b600060208201905081810360008301526156048184614642565b905092915050565b7f41413934206761732076616c756573206f766572666c6f770000000000000000600082015250565b6000615642601883614550565b915061564d8261560c565b602082019050919050565b6000602082019050818103600083015261567181615635565b9050919050565b7f4141323520696e76616c6964206163636f756e74206e6f6e6365000000000000600082015250565b60006156ae601a83614550565b91506156b982615678565b602082019050919050565b60006040820190506156d96000830184613e42565b81810360208301526156ea816156a1565b905092915050565b7f41413236206f76657220766572696669636174696f6e4761734c696d69740000600082015250565b6000615728601e83614550565b9150615733826156f2565b602082019050919050565b60006040820190506157536000830184613e42565b81810360208301526157648161571b565b905092915050565b7f41413234207369676e6174757265206572726f72000000000000000000000000600082015250565b60006157a2601483614550565b91506157ad8261576c565b602082019050919050565b60006040820190506157cd6000830184613e42565b81810360208301526157de81615795565b905092915050565b7f414132322065787069726564206f72206e6f7420647565000000000000000000600082015250565b600061581c601783614550565b9150615827826157e6565b602082019050919050565b60006040820190506158476000830184613e42565b81810360208301526158588161580f565b905092915050565b7f41413334207369676e6174757265206572726f72000000000000000000000000600082015250565b6000615896601483614550565b91506158a182615860565b602082019050919050565b60006040820190506158c16000830184613e42565b81810360208301526158d281615889565b905092915050565b7f41413332207061796d61737465722065787069726564206f72206e6f7420647560008201527f6500000000000000000000000000000000000000000000000000000000000000602082015250565b6000615936602183614550565b9150615941826158da565b604082019050919050565b60006040820190506159616000830184613e42565b818103602083015261597281615929565b905092915050565b6000610120830161598e60008401846151f1565b61599b6000860182615208565b506159a96020840184615217565b6159b66020860182614190565b506159c4604084018461523d565b85830360408701526159d78382846152b1565b925050506159e8606084018461523d565b85830360608701526159fb8382846152b1565b92505050615a0c60808401846152de565b615a1960808601826152f5565b50615a2760a0840184615217565b615a3460a0860182614190565b50615a4260c08401846152de565b615a4f60c08601826152f5565b50615a5d60e084018461523d565b85830360e0870152615a708382846152b1565b92505050615a8261010084018461523d565b858303610100870152615a968382846152b1565b925050508091505092915050565b60006040820190508181036000830152615abe818561597a565b9050615acd6020830184614139565b9392505050565b61014082016000820151615aeb6000850182615208565b506020820151615afe6020850182614190565b506040820151615b116040850182614190565b506060820151615b246060850182614190565b506080820151615b376080850182614190565b5060a0820151615b4a60a0850182614190565b5060c0820151615b5d60c0850182614190565b5060e0820151615b7060e0850182615208565b50610100820151615b85610100850182614190565b50610120820151615b9a610120850182614190565b50505050565b6101c082016000820151615bb76000850182615ad4565b506020820151615bcb6101408501826152f5565b506040820151615bdf610160850182614190565b506060820151615bf3610180850182614190565b506080820151615c076101a0850182614190565b50505050565b6000610200820190508181036000830152615c288186614642565b9050615c376020830185615ba0565b8181036101e0830152615c4a8184614642565b9050949350505050565b6000610200820190508181036000830152615c70818688614c55565b9050615c7f6020830185615ba0565b8181036101e0830152615c928184614642565b905095945050505050565b7f41413935206f7574206f66206761730000000000000000000000000000000000600082015250565b6000615cd3600f83614550565b9150615cde82615c9d565b602082019050919050565b6000604082019050615cfe6000830184613e42565b8181036020830152615d0f81615cc6565b905092915050565b7f4141393020696e76616c69642062656e65666963696172790000000000000000600082015250565b6000615d4d601883614550565b9150615d5882615d17565b602082019050919050565b60006020820190508181036000830152615d7c81615d40565b9050919050565b7f41413931206661696c65642073656e6420746f2062656e656669636961727900600082015250565b6000615db9601f83614550565b9150615dc482615d83565b602082019050919050565b60006020820190508181036000830152615de881615dac565b9050919050565b6000608082019050615e046000830187613e42565b615e116020830186613efd565b615e1e6040830185613e42565b615e2b6060830184613e42565b95945050505050565b600061010082019050615e4a600083018b614b3a565b615e57602083018a613e42565b615e646040830189614139565b615e716060830188614139565b615e7e6080830187614139565b615e8b60a0830186613e42565b615e9860c0830185614139565b615ea560e0830184614139565b9998505050505050505050565b7f4141393320696e76616c6964207061796d6173746572416e6444617461000000600082015250565b6000615ee8601d83614550565b9150615ef382615eb2565b602082019050919050565b60006020820190508181036000830152615f1781615edb565b9050919050565b60006060820190508181036000830152615f38818661597a565b9050615f476020830185614139565b615f546040830184613e42565b949350505050565b600081519050615f6b81613b67565b92915050565b600060208284031215615f8757615f866139aa565b5b6000615f9584828501615f5c565b91505092915050565b7f4141323320726576657274656400000000000000000000000000000000000000600082015250565b6000615fd4600d83614550565b9150615fdf82615f9e565b602082019050919050565b6000606082019050615fff6000830185613e42565b818103602083015261601081615fc7565b905081810360408301526160248184614642565b90509392505050565b7f41413231206469646e2774207061792070726566756e64000000000000000000600082015250565b6000616063601783614550565b915061606e8261602d565b602082019050919050565b600060408201905061608e6000830184613e42565b818103602083015261609f81616056565b905092915050565b7f41413331207061796d6173746572206465706f73697420746f6f206c6f770000600082015250565b60006160dd601e83614550565b91506160e8826160a7565b602082019050919050565b60006040820190506161086000830184613e42565b8181036020830152616119816160d0565b905092915050565b600061613461612f84613a4a565b613a2f565b9050828152602081018484840111156161505761614f6139b9565b5b61615b848285614618565b509392505050565b600082601f830112616178576161776139b4565b5b8151616188848260208601616121565b91505092915050565b600080604083850312156161a8576161a76139aa565b5b600083015167ffffffffffffffff8111156161c6576161c56139af565b5b6161d285828601616163565b92505060206161e385828601615f5c565b9150509250929050565b7f4141333320726576657274656400000000000000000000000000000000000000600082015250565b6000616223600d83614550565b915061622e826161ed565b602082019050919050565b600060608201905061624e6000830185613e42565b818103602083015261625f81616216565b905081810360408301526162738184614642565b90509392505050565b7f41413336206f766572207061796d6173746572566572696669636174696f6e4760008201527f61734c696d697400000000000000000000000000000000000000000000000000602082015250565b60006162d8602783614550565b91506162e38261627c565b604082019050919050565b60006040820190506163036000830184613e42565b8181036020830152616314816162cb565b905092915050565b600080fd5b600080fd5b6000808585111561633a5761633961631c565b5b8386111561634b5761634a616321565b5b6001850283019150848603905094509492505050565b600082905092915050565b60007fffffffffffffffffffffffffffffffffffffffff00000000000000000000000082169050919050565b600082821b905092915050565b60006163b18383616361565b826163bc813561636c565b925060148210156163fc576163f77fffffffffffffffffffffffffffffffffffffffff00000000000000000000000083601403600802616398565b831692505b505092915050565b60007fffffffffffffffffffffffffffffffff0000000000000000000000000000000082169050919050565b600061643c8383616361565b826164478135616404565b92506010821015616487576164827fffffffffffffffffffffffffffffffff0000000000000000000000000000000083601003600802616398565b831692505b505092915050565b7f414131302073656e64657220616c726561647920636f6e737472756374656400600082015250565b60006164c5601f83614550565b91506164d08261648f565b602082019050919050565b60006040820190506164f06000830184613e42565b8181036020830152616501816164b8565b905092915050565b7f4141313320696e6974436f6465206661696c6564206f72204f4f470000000000600082015250565b600061653f601b83614550565b915061654a82616509565b602082019050919050565b600060408201905061656a6000830184613e42565b818103602083015261657b81616532565b905092915050565b7f4141313420696e6974436f6465206d7573742072657475726e2073656e646572600082015250565b60006165b9602083614550565b91506165c482616583565b602082019050919050565b60006040820190506165e46000830184613e42565b81810360208301526165f5816165ac565b905092915050565b7f4141313520696e6974436f6465206d757374206372656174652073656e646572600082015250565b6000616633602083614550565b915061663e826165fd565b602082019050919050565b600060408201905061665e6000830184613e42565b818103602083015261666f81616626565b905092915050565b600060408201905061668c6000830185614b3a565b6166996020830184614b3a565b939250505056fea2646970667358221220f6e7d5acc3b3ce47e8c4e79583caee84134eab4d0c55f3973f51a15d53351cdb64736f6c63430008170033", + "gas_used": 5492938, + "gas_limit": 5492938, + "status": "Return", + "steps": [], + "decoded": { + "label": null, + "return_data": null, + "call_data": null + } + }, + "logs": [], + "ordering": [{ "Call": 0 }] + }, + { + "parent": 0, + "children": [], + "idx": 1, + "trace": { + "depth": 1, + "success": true, + "caller": "0x2e983a1ba5e8b38aaaec4b440b9ddcfbf72e15d1", + "address": "0xdd8a726a079a85effe3183ecfbe0de8ac36b1e65", + "maybe_precompile": false, + "selfdestruct_address": null, + "selfdestruct_refund_target": null, + "selfdestruct_transferred_value": null, + "kind": "CREATE", + "value": "0x0", + "data": "0x608060405234801561001057600080fd5b50610342806100206000396000f3fe608060405234801561001057600080fd5b506004361061002b5760003560e01c8063570e1a3614610030575b600080fd5b61004a6004803603810190610045919061017b565b610060565b6040516100579190610209565b60405180910390f35b60008083836000906014926100779392919061022e565b9061008291906102ad565b60601c905060008484601490809261009c9392919061022e565b8080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f8201169050808301925050505050505090506000602060008351602085016000875af1905060005193508061010357600093505b50505092915050565b600080fd5b600080fd5b600080fd5b600080fd5b600080fd5b60008083601f84011261013b5761013a610116565b5b8235905067ffffffffffffffff8111156101585761015761011b565b5b60208301915083600182028301111561017457610173610120565b5b9250929050565b600080602083850312156101925761019161010c565b5b600083013567ffffffffffffffff8111156101b0576101af610111565b5b6101bc85828601610125565b92509250509250929050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b60006101f3826101c8565b9050919050565b610203816101e8565b82525050565b600060208201905061021e60008301846101fa565b92915050565b600080fd5b600080fd5b6000808585111561024257610241610224565b5b8386111561025357610252610229565b5b6001850283019150848603905094509492505050565b600082905092915050565b60007fffffffffffffffffffffffffffffffffffffffff00000000000000000000000082169050919050565b600082821b905092915050565b60006102b98383610269565b826102c48135610274565b92506014821015610304576102ff7fffffffffffffffffffffffffffffffffffffffff000000000000000000000000836014036008026102a0565b831692505b50509291505056fea264697066735822122050dbb7b87383c3f370ab6e7c31231f1967684cb78ec9da388509e2ca89e70f0a64736f6c63430008170033", + "output": "0x608060405234801561001057600080fd5b506004361061002b5760003560e01c8063570e1a3614610030575b600080fd5b61004a6004803603810190610045919061017b565b610060565b6040516100579190610209565b60405180910390f35b60008083836000906014926100779392919061022e565b9061008291906102ad565b60601c905060008484601490809261009c9392919061022e565b8080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f8201169050808301925050505050505090506000602060008351602085016000875af1905060005193508061010357600093505b50505092915050565b600080fd5b600080fd5b600080fd5b600080fd5b600080fd5b60008083601f84011261013b5761013a610116565b5b8235905067ffffffffffffffff8111156101585761015761011b565b5b60208301915083600182028301111561017457610173610120565b5b9250929050565b600080602083850312156101925761019161010c565b5b600083013567ffffffffffffffff8111156101b0576101af610111565b5b6101bc85828601610125565b92509250509250929050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b60006101f3826101c8565b9050919050565b610203816101e8565b82525050565b600060208201905061021e60008301846101fa565b92915050565b600080fd5b600080fd5b6000808585111561024257610241610224565b5b8386111561025357610252610229565b5b6001850283019150848603905094509492505050565b600082905092915050565b60007fffffffffffffffffffffffffffffffffffffffff00000000000000000000000082169050919050565b600082821b905092915050565b60006102b98383610269565b826102c48135610274565b92506014821015610304576102ff7fffffffffffffffffffffffffffffffffffffffff000000000000000000000000836014036008026102a0565b831692505b50509291505056fea264697066735822122050dbb7b87383c3f370ab6e7c31231f1967684cb78ec9da388509e2ca89e70f0a64736f6c63430008170033", + "gas_used": 167014, + "gas_limit": 5375291, + "status": "Return", + "steps": [], + "decoded": { + "label": null, + "return_data": null, + "call_data": null + } + }, + "logs": [], + "ordering": [] + } + ], + "exit": "Return", + "out": "0x60806040526004361061010c5760003560e01c806370a0823111610095578063b760faf911610064578063b760faf9146103b5578063bb9fe6bf146103d1578063c23a5cea146103e8578063dbed18e014610411578063fc7e286d1461043a5761011c565b806370a08231146102fd578063765e827f1461033a578063850aaf62146103635780639b249f691461038c5761011c565b80631b2e01b8116100dc5780631b2e01b8146101e0578063205c28781461021d57806322cdde4c1461024657806335567e1a146102835780635287ce12146102c05761011c565b806242dc531461012157806301ffc9a71461015e5780630396cb601461019b5780630bd28e3b146101b75761011c565b3661011c5761011a3361047b565b005b600080fd5b34801561012d57600080fd5b5061014860048036038101906101439190613db0565b6104db565b6040516101559190613e51565b60405180910390f35b34801561016a57600080fd5b5061018560048036038101906101809190613ec4565b6106c1565b6040516101929190613f0c565b60405180910390f35b6101b560048036038101906101b09190613f63565b6108b7565b005b3480156101c357600080fd5b506101de60048036038101906101d99190613fe0565b610c13565b005b3480156101ec57600080fd5b506102076004803603810190610202919061400d565b610cb0565b6040516102149190613e51565b60405180910390f35b34801561022957600080fd5b50610244600480360381019061023f919061408b565b610cd5565b005b34801561025257600080fd5b5061026d600480360381019061026891906140f0565b610e78565b60405161027a9190614148565b60405180910390f35b34801561028f57600080fd5b506102aa60048036038101906102a5919061400d565b610eb4565b6040516102b79190613e51565b60405180910390f35b3480156102cc57600080fd5b506102e760048036038101906102e29190614163565b610f63565b6040516102f4919061426f565b60405180910390f35b34801561030957600080fd5b50610324600480360381019061031f9190614163565b611076565b6040516103319190613e51565b60405180910390f35b34801561034657600080fd5b50610361600480360381019061035c91906142e0565b6110c1565b005b34801561036f57600080fd5b5061038a60048036038101906103859190614340565b611255565b005b34801561039857600080fd5b506103b360048036038101906103ae91906143a0565b611303565b005b6103cf60048036038101906103ca9190614163565b61047b565b005b3480156103dd57600080fd5b506103e66113c9565b005b3480156103f457600080fd5b5061040f600480360381019061040a91906143ed565b611579565b005b34801561041d57600080fd5b5061043860048036038101906104339190614470565b611879565b005b34801561044657600080fd5b50610461600480360381019061045c9190614163565b611d90565b6040516104729594939291906144fd565b60405180910390f35b60006104878234611e0f565b90508173ffffffffffffffffffffffffffffffffffffffff167f2da466a7b24304f47e87fa2e1e5a81b9831ce54fec19055ce277ca2f39ba42c4826040516104cf9190613e51565b60405180910390a25050565b6000805a90503073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161461054f576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610546906145ad565b60405180910390fd5b6000856000015190506000816060015190506127108260a001518201016040603f5a02816105805761057f6145cd565b5b0410156105b1577fdeaddead0000000000000000000000000000000000000000000000000000000060005260206000fd5b600080895111156106555760006105cf846000015160008c86611e7a565b9050806106535760006105e3610800611e93565b905060008151111561064d57846000015173ffffffffffffffffffffffffffffffffffffffff168a602001517f1c4fada7374c0a9ee8841fc38afe82932dc0f8e69012e927f061a8bae611a20187602001518460405161064492919061467b565b60405180910390a35b60019250505b505b600088608001515a86030190506106b2828a8a8a8080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f8201169050808301925050505050505084611ec3565b95505050505050949350505050565b60007f3e84f021000000000000000000000000000000000000000000000000000000007fcf28ef97000000000000000000000000000000000000000000000000000000007f915074d80000000000000000000000000000000000000000000000000000000018187bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614806107d057507f915074d8000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b8061083857507fcf28ef97000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b806108a057507f3e84f021000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b806108b057506108af82612164565b5b9050919050565b60008060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020905060008263ffffffff1611610942576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610939906146f7565b60405180910390fd5b80600101600f9054906101000a900463ffffffff1663ffffffff168263ffffffff1610156109a5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161099c90614763565b60405180910390fd5b6000348260010160019054906101000a90046dffffffffffffffffffffffffffff166dffffffffffffffffffffffffffff166109e191906147b2565b905060008111610a26576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610a1d90614832565b60405180910390fd5b6dffffffffffffffffffffffffffff8016811115610a79576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610a709061489e565b60405180910390fd5b6040518060a0016040528083600001548152602001600115158152602001826dffffffffffffffffffffffffffff1681526020018463ffffffff168152602001600065ffffffffffff168152506000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000820151816000015560208201518160010160006101000a81548160ff02191690831515021790555060408201518160010160016101000a8154816dffffffffffffffffffffffffffff02191690836dffffffffffffffffffffffffffff160217905550606082015181600101600f6101000a81548163ffffffff021916908363ffffffff16021790555060808201518160010160136101000a81548165ffffffffffff021916908365ffffffffffff1602179055509050503373ffffffffffffffffffffffffffffffffffffffff167fa5ae833d0bb1dcd632d98a8b70973e8516812898e19bf27b70071ebc8dc52c018285604051610c069291906148f9565b60405180910390a2505050565b600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008277ffffffffffffffffffffffffffffffffffffffffffffffff1677ffffffffffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000815480929190610ca890614922565b919050555050565b6001602052816000526040600020602052806000526040600020600091509150505481565b60008060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002090508060000154821115610d5e576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610d55906149b6565b60405180910390fd5b818160000154610d6e91906149d6565b81600001819055503373ffffffffffffffffffffffffffffffffffffffff167fd1c19fbcd4551a5edfb66d43d2e337c04837afda3482b42bdf569a8fccdae5fb8484604051610dbe929190614a5f565b60405180910390a260008373ffffffffffffffffffffffffffffffffffffffff1683604051610dec90614ab9565b60006040518083038185875af1925050503d8060008114610e29576040519150601f19603f3d011682016040523d82523d6000602084013e610e2e565b606091505b5050905080610e72576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610e6990614b1a565b60405180910390fd5b50505050565b6000610e83826121ce565b3046604051602001610e9793929190614b49565b604051602081830303815290604052805190602001209050919050565b600060408277ffffffffffffffffffffffffffffffffffffffffffffffff16901b600160008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008477ffffffffffffffffffffffffffffffffffffffffffffffff1677ffffffffffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205417905092915050565b610f6b613853565b6000808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206040518060a0016040529081600082015481526020016001820160009054906101000a900460ff161515151581526020016001820160019054906101000a90046dffffffffffffffffffffffffffff166dffffffffffffffffffffffffffff166dffffffffffffffffffffffffffff16815260200160018201600f9054906101000a900463ffffffff1663ffffffff1663ffffffff1681526020016001820160139054906101000a900465ffffffffffff1665ffffffffffff1665ffffffffffff16815250509050919050565b60008060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600001549050919050565b6110c96121e7565b600083839050905060008167ffffffffffffffff8111156110ed576110ec6139cf565b5b60405190808252806020026020018201604052801561112657816020015b6111136138a2565b81526020019060019003908161110b5790505b50905060005b828110156111a657600082828151811061114957611148614b80565b5b60200260200101519050600080611185848a8a8781811061116d5761116c614b80565b5b905060200281019061117f9190614bbe565b8561222b565b915091506111968483836000612421565b505050808060010191505061112c565b5060007fbb47ee3e183a558b1a2ff0874b079f3fc5478b7454eacf2bfc5af2ff5878f97260405160405180910390a160005b8381101561123a57611229818888848181106111f7576111f6614b80565b5b90506020028101906112099190614bbe565b85848151811061121c5761121b614b80565b5b60200260200101516125b4565b8201915080806001019150506111d8565b506112458482612955565b505050611250612a75565b505050565b6000808473ffffffffffffffffffffffffffffffffffffffff16848460405161127f929190614c0c565b600060405180830381855af49150503d80600081146112ba576040519150601f19603f3d011682016040523d82523d6000602084013e6112bf565b606091505b509150915081816040517f994105540000000000000000000000000000000000000000000000000000000081526004016112fa929190614c25565b60405180910390fd5b600061130d612a7f565b73ffffffffffffffffffffffffffffffffffffffff1663570e1a3684846040518363ffffffff1660e01b8152600401611347929190614c82565b6020604051808303816000875af1158015611366573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061138a9190614cbb565b9050806040517f6ca7b8060000000000000000000000000000000000000000000000000000000081526004016113c09190614ce8565b60405180910390fd5b60008060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000209050600081600101600f9054906101000a900463ffffffff1663ffffffff1603611468576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161145f90614d4f565b60405180910390fd5b8060010160009054906101000a900460ff166114b9576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016114b090614dbb565b60405180910390fd5b600081600101600f9054906101000a900463ffffffff1663ffffffff16426114e19190614ddb565b9050808260010160136101000a81548165ffffffffffff021916908365ffffffffffff16021790555060008260010160006101000a81548160ff0219169083151502179055503373ffffffffffffffffffffffffffffffffffffffff167ffa9b3c14cc825c412c9ed81b3ba365a5b459439403f18829e572ed53a4180f0a8260405161156d9190614e46565b60405180910390a25050565b60008060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020905060008160010160019054906101000a90046dffffffffffffffffffffffffffff166dffffffffffffffffffffffffffff16905060008111611631576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161162890614ead565b60405180910390fd5b60008260010160139054906101000a900465ffffffffffff1665ffffffffffff1611611692576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161168990614f19565b60405180910390fd5b428260010160139054906101000a900465ffffffffffff1665ffffffffffff1611156116f3576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016116ea90614f85565b60405180910390fd5b600082600101600f6101000a81548163ffffffff021916908363ffffffff16021790555060008260010160136101000a81548165ffffffffffff021916908365ffffffffffff16021790555060008260010160016101000a8154816dffffffffffffffffffffffffffff02191690836dffffffffffffffffffffffffffff1602179055503373ffffffffffffffffffffffffffffffffffffffff167fb7c918e0e249f999e965cafeb6c664271b3f4317d296461500e71da39f0cbda384836040516117bf929190614a5f565b60405180910390a260008373ffffffffffffffffffffffffffffffffffffffff16826040516117ed90614ab9565b60006040518083038185875af1925050503d806000811461182a576040519150601f19603f3d011682016040523d82523d6000602084013e61182f565b606091505b5050905080611873576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161186a90614ff1565b60405180910390fd5b50505050565b6118816121e7565b60008383905090506000805b82811015611a6857368686838181106118a9576118a8614b80565b5b90506020028101906118bb9190615011565b90503660008280600001906118d09190615039565b9150915060008360200160208101906118e991906150da565b9050600173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff160361195a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161195190615153565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614611a46578073ffffffffffffffffffffffffffffffffffffffff16632dd8113384848780604001906119bc9190615173565b6040518563ffffffff1660e01b81526004016119db94939291906154ec565b60006040518083038186803b1580156119f357600080fd5b505afa925050508015611a04575060015b611a4557806040517f86a9f750000000000000000000000000000000000000000000000000000000008152600401611a3c9190614ce8565b60405180910390fd5b5b8282905086611a5591906147b2565b955050505050808060010191505061188d565b5060008167ffffffffffffffff811115611a8557611a846139cf565b5b604051908082528060200260200182016040528015611abe57816020015b611aab6138a2565b815260200190600190039081611aa35790505b5090506000805b84811015611bc85736888883818110611ae157611ae0614b80565b5b9050602002810190611af39190615011565b9050366000828060000190611b089190615039565b915091506000836020016020810190611b2191906150da565b9050600083839050905060005b81811015611bb5576000898981518110611b4b57611b4a614b80565b5b60200260200101519050600080611b878b898987818110611b6f57611b6e614b80565b5b9050602002810190611b819190614bbe565b8561222b565b91509150611b9784838389612421565b8a80611ba290614922565b9b50505050508080600101915050611b2e565b5050505050508080600101915050611ac5565b507fbb47ee3e183a558b1a2ff0874b079f3fc5478b7454eacf2bfc5af2ff5878f97260405160405180910390a1600080915060005b85811015611d2f5736898983818110611c1957611c18614b80565b5b9050602002810190611c2b9190615011565b9050806020016020810190611c4091906150da565b73ffffffffffffffffffffffffffffffffffffffff167f575ff3acadd5ab348fe1855e217e0f3678f8d767d7494c9f9fefbee2e17cca4d60405160405180910390a2366000828060000190611c959190615039565b91509150600082829050905060005b81811015611d1d57611cf588858584818110611cc357611cc2614b80565b5b9050602002810190611cd59190614bbe565b8b8b81518110611ce857611ce7614b80565b5b60200260200101516125b4565b87611d0091906147b2565b96508780611d0d90614922565b9850508080600101915050611ca4565b50505050508080600101915050611bfd565b50600073ffffffffffffffffffffffffffffffffffffffff167f575ff3acadd5ab348fe1855e217e0f3678f8d767d7494c9f9fefbee2e17cca4d60405160405180910390a2611d7e8682612955565b5050505050611d8b612a75565b505050565b60006020528060005260406000206000915090508060000154908060010160009054906101000a900460ff16908060010160019054906101000a90046dffffffffffffffffffffffffffff169080600101600f9054906101000a900463ffffffff16908060010160139054906101000a900465ffffffffffff16905085565b6000806000808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002090506000838260000154611e6491906147b2565b9050808260000181905550809250505092915050565b6000806000845160208601878987f19050949350505050565b60603d82811115611ea2578290505b604051602082018101604052818152816000602083013e8092505050919050565b6000805a9050600080866000015190506000611ede82612aa7565b905060008260e001519050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603611f295782600001519350612029565b809350600088511115612028578187029550600280811115611f4e57611f4d615527565b5b8a6002811115611f6157611f60615527565b5b14612027578073ffffffffffffffffffffffffffffffffffffffff16637c627b218460a001518c8b8a876040518663ffffffff1660e01b8152600401611faa949392919061559e565b600060405180830381600088803b158015611fc457600080fd5b5087f193505050508015611fd6575060015b612026576000611fe7610800611e93565b9050806040517fad7954bc00000000000000000000000000000000000000000000000000000000815260040161201d91906155ea565b60405180910390fd5b5b5b5b5a85038701965060008360a00151846060015101905060008a60800151890390508082111561207a576000818303905060006064600a83028161206f5761206e6145cd565b5b049050808b019a5050505b505081870295506000896040015190508681101561210a576002808111156120a5576120a4615527565b5b8b60028111156120b8576120b7615527565b5b036120db578096506120c98a612ae3565b6120d68a6000898b612b49565b612105565b7fdeadaa510000000000000000000000000000000000000000000000000000000060005260206000fd5b612156565b6000878203905061211b8682611e0f565b50600080600281111561213157612130615527565b5b8d600281111561214457612143615527565b5b1490506121538c828b8d612b49565b50505b505050505050949350505050565b60007f01ffc9a7000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916149050919050565b60006121d982612bd7565b805190602001209050919050565b6002805403612222576040517f3ee5aeb500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60028081905550565b60008060005a90506000846000015190506122468682612c9b565b61224f86610e78565b85602001818152505060008160400151905060008261012001518361010001518460a0015185608001518660600151868860c0015117171717171790506effffffffffffffffffffffffffffff80168111156122e0576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016122d790615658565b60405180910390fd5b60006122eb84612e57565b90506122fa8a8a8a8487612e89565b965061230e846000015185602001516130c6565b61234f57896040517f220266b600000000000000000000000000000000000000000000000000000000815260040161234691906156c4565b60405180910390fd5b825a8603111561239657896040517f220266b600000000000000000000000000000000000000000000000000000000815260040161238d919061573e565b60405180910390fd5b6060600073ffffffffffffffffffffffffffffffffffffffff168560e0015173ffffffffffffffffffffffffffffffffffffffff16146123e5576123dc8b8b8b85613184565b80985081925050505b818960400181815250506123f881613371565b8960600181815250508960a001355a870301896080018181525050505050505050935093915050565b60008061242d8561337b565b915091508173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16146124a157856040517f220266b600000000000000000000000000000000000000000000000000000000815260040161249891906157b8565b60405180910390fd5b80156124e457856040517f220266b60000000000000000000000000000000000000000000000000000000081526004016124db9190615832565b60405180910390fd5b60006124ef8561337b565b8093508192505050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161461256857866040517f220266b600000000000000000000000000000000000000000000000000000000815260040161255f91906158ac565b60405180910390fd5b81156125ab57866040517f220266b60000000000000000000000000000000000000000000000000000000081526004016125a2919061594c565b60405180910390fd5b50505050505050565b6000805a905060006125c984606001516133d4565b905060008060405190503660008880606001906125e69190615173565b91509150606060008260038111156125fd57843591505b50638dd7712f60e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916817bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916036127245760008b8b60200151604051602401612663929190615aa4565b604051602081830303815290604052638dd7712f60e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff838183161783525050505090503073ffffffffffffffffffffffffffffffffffffffff166242dc53828d8b6040516024016126da93929190615c0d565b604051602081830303815290604052915060e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff838183161783525050505092505061279b565b3073ffffffffffffffffffffffffffffffffffffffff166242dc5385858d8b6040516024016127569493929190615c54565b604051602081830303815290604052915060e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff838183161783525050505091505b602060008351602085016000305af1955060005198508460405250505050508061294b5760003d806020036127d65760206000803e60005191505b507fdeaddead00000000000000000000000000000000000000000000000000000000810361283b57876040517f220266b60000000000000000000000000000000000000000000000000000000081526004016128329190615ce9565b60405180910390fd5b7fdeadaa510000000000000000000000000000000000000000000000000000000081036128aa57600086608001515a8661287591906149d6565b61287f91906147b2565b905060008760400151905061289388612ae3565b6128a08860008385612b49565b8096505050612949565b85600001516000015173ffffffffffffffffffffffffffffffffffffffff1686602001517ff62676f440ff169a3a9afdbf812e89e7f95975ee8e5c31214ffdef631c5f4792886000015160200151612903610800611e93565b60405161291192919061467b565b60405180910390a3600086608001515a8661292c91906149d6565b61293691906147b2565b90506129456002888684611ec3565b9550505b505b5050509392505050565b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16036129c4576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016129bb90615d63565b60405180910390fd5b60008273ffffffffffffffffffffffffffffffffffffffff16826040516129ea90614ab9565b60006040518083038185875af1925050503d8060008114612a27576040519150601f19603f3d011682016040523d82523d6000602084013e612a2c565b606091505b5050905080612a70576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612a6790615dcf565b60405180910390fd5b505050565b6001600281905550565b60007f000000000000000000000000dd8a726a079a85effe3183ecfbe0de8ac36b1e65905090565b600080826101000151905060008361012001519050808203612acd578192505050612ade565b612ad9824883016133de565b925050505b919050565b80600001516000015173ffffffffffffffffffffffffffffffffffffffff1681602001517f67b4fa9642f42120bf031f3051d1824b0fe25627945b27b8a6a65d5761d5482e836000015160200151604051612b3e9190613e51565b60405180910390a350565b836000015160e0015173ffffffffffffffffffffffffffffffffffffffff1684600001516000015173ffffffffffffffffffffffffffffffffffffffff1685602001517f49628fd1471006c1482da88028e9ce4dbb080b815c9b0344d39e5a8e6ec1419f876000015160200151878787604051612bc99493929190615def565b60405180910390a450505050565b60606000612be4836133f7565b90506000836020013590506000612c09858060400190612c049190615173565b613407565b90506000612c25868060600190612c209190615173565b613407565b905060008660800135905060008760a00135905060008860c0013590506000612c5c8a8060e00190612c579190615173565b613407565b90508787878787878787604051602001612c7d989796959493929190615e34565b60405160208183030381529060405298505050505050505050919050565b816000016020810190612cae9190614163565b816000019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250508160200135816020018181525050612d00826080013561341e565b8260400183606001828152508281525050508160a001358160c0018181525050612d2d8260c0013561341e565b8261012001836101000182815250828152505050366000838060e00190612d549190615173565b915091506000828290501115612e01576034828290501015612dab576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612da290615efe565b60405180910390fd5b612db5828261345c565b8560e001866080018760a00183815250838152508373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815250505050612e51565b60008360e0019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff1681525050600083608001818152505060008360a00181815250505b50505050565b6000808260c001518360a001518460800151856060015186604001510101010190508261010001518102915050919050565b60008084600001519050600081600001519050612eb68887898060400190612eb19190615173565b6134fe565b60008260e00151905060008073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603612f17576000612eff84611076565b9050878111612f1057808803612f13565b60005b9150505b8273ffffffffffffffffffffffffffffffffffffffff166319822f7c878b8b60200151856040518563ffffffff1660e01b8152600401612f5993929190615f1e565b60206040518083038160008887f193505050508015612f9657506040513d601f19601f82011682018060405250810190612f939190615f71565b60015b612fe35789612fa6610800611e93565b6040517f65c8fd4d000000000000000000000000000000000000000000000000000000008152600401612fda929190615fea565b60405180910390fd5b80955050600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16036130b95760008060008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000209050600081600001549050808911156130ab578b6040517f220266b60000000000000000000000000000000000000000000000000000000081526004016130a29190616079565b60405180910390fd5b888103826000018190555050505b5050505095945050505050565b600080604083901c905060008390508067ffffffffffffffff16600160008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008477ffffffffffffffffffffffffffffffffffffffffffffffff1677ffffffffffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600081548092919061317590614922565b91905055149250505092915050565b60606000805a905060008560000151905060008160e00151905060008060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002090506000816000015490508781101561322e578a6040517f220266b600000000000000000000000000000000000000000000000000000000815260040161322591906160f3565b60405180910390fd5b87810382600001819055506000846080015190508373ffffffffffffffffffffffffffffffffffffffff166352b7512c828d8d602001518d6040518563ffffffff1660e01b815260040161328493929190615f1e565b60006040518083038160008887f1935050505080156132c657506040513d6000823e3d601f19601f820116820180604052508101906132c39190616191565b60015b613313578b6132d6610800611e93565b6040517f65c8fd4d00000000000000000000000000000000000000000000000000000000815260040161330a929190616239565b60405180910390fd5b8199508098505050805a87031115613362578b6040517f220266b600000000000000000000000000000000000000000000000000000000815260040161335991906162ee565b60405180910390fd5b50505050505094509492505050565b6000819050919050565b6000806000830361339257600080915091506133cf565b600061339d846137cf565b9050806040015165ffffffffffff164211806133c45750806020015165ffffffffffff1642105b915080600001519250505b915091565b6060819050919050565b60008183106133ed57816133ef565b825b905092915050565b6000808235905080915050919050565b600060405182808583378082209250505092915050565b6000808260801c8360001c816fffffffffffffffffffffffffffffffff169150806fffffffffffffffffffffffffffffffff16905091509150915091565b6000806000848460009060149261347593929190616326565b9061348091906163a5565b60601c858560149060249261349793929190616326565b906134a29190616430565b60801c86866024906034926134b993929190616326565b906134c49190616430565b60801c816fffffffffffffffffffffffffffffffff169150806fffffffffffffffffffffffffffffffff1690509250925092509250925092565b600082829050146137c9576000836000015160000151905060008173ffffffffffffffffffffffffffffffffffffffff163b1461357257846040517f220266b600000000000000000000000000000000000000000000000000000000815260040161356991906164db565b60405180910390fd5b600061357c612a7f565b73ffffffffffffffffffffffffffffffffffffffff1663570e1a3686600001516040015186866040518463ffffffff1660e01b81526004016135bf929190614c82565b60206040518083038160008887f11580156135de573d6000803e3d6000fd5b50505050506040513d601f19601f820116820180604052508101906136039190614cbb565b9050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff160361367657856040517f220266b600000000000000000000000000000000000000000000000000000000815260040161366d9190616555565b60405180910390fd5b8173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16146136e657856040517f220266b60000000000000000000000000000000000000000000000000000000081526004016136dd91906165cf565b60405180910390fd5b60008173ffffffffffffffffffffffffffffffffffffffff163b0361374257856040517f220266b60000000000000000000000000000000000000000000000000000000081526004016137399190616649565b60405180910390fd5b6000848460009060149261375893929190616326565b9061376391906163a5565b60601c90508273ffffffffffffffffffffffffffffffffffffffff1686602001517fd51a9c61267aa6196961883ecf5ff2da6619c37dac0fa92122513fb32c032d2d83896000015160e001516040516137bd929190616677565b60405180910390a35050505b50505050565b6137d76138da565b6000829050600060a084901c905060008165ffffffffffff16036137ff5765ffffffffffff90505b600060d085901c905060405180606001604052808473ffffffffffffffffffffffffffffffffffffffff1681526020018265ffffffffffff1681526020018365ffffffffffff168152509350505050919050565b6040518060a001604052806000815260200160001515815260200160006dffffffffffffffffffffffffffff168152602001600063ffffffff168152602001600065ffffffffffff1681525090565b6040518060a001604052806138b5613921565b8152602001600080191681526020016000815260200160008152602001600081525090565b6040518060600160405280600073ffffffffffffffffffffffffffffffffffffffff168152602001600065ffffffffffff168152602001600065ffffffffffff1681525090565b604051806101400160405280600073ffffffffffffffffffffffffffffffffffffffff168152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600073ffffffffffffffffffffffffffffffffffffffff16815260200160008152602001600081525090565b6000604051905090565b600080fd5b600080fd5b600080fd5b600080fd5b6000601f19601f8301169050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b613a07826139be565b810181811067ffffffffffffffff82111715613a2657613a256139cf565b5b80604052505050565b6000613a396139a0565b9050613a4582826139fe565b919050565b600067ffffffffffffffff821115613a6557613a646139cf565b5b613a6e826139be565b9050602081019050919050565b82818337600083830152505050565b6000613a9d613a9884613a4a565b613a2f565b905082815260208101848484011115613ab957613ab86139b9565b5b613ac4848285613a7b565b509392505050565b600082601f830112613ae157613ae06139b4565b5b8135613af1848260208601613a8a565b91505092915050565b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000613b2a82613aff565b9050919050565b613b3a81613b1f565b8114613b4557600080fd5b50565b600081359050613b5781613b31565b92915050565b6000819050919050565b613b7081613b5d565b8114613b7b57600080fd5b50565b600081359050613b8d81613b67565b92915050565b60006101408284031215613baa57613ba9613afa565b5b613bb5610140613a2f565b90506000613bc584828501613b48565b6000830152506020613bd984828501613b7e565b6020830152506040613bed84828501613b7e565b6040830152506060613c0184828501613b7e565b6060830152506080613c1584828501613b7e565b60808301525060a0613c2984828501613b7e565b60a08301525060c0613c3d84828501613b7e565b60c08301525060e0613c5184828501613b48565b60e083015250610100613c6684828501613b7e565b61010083015250610120613c7c84828501613b7e565b6101208301525092915050565b6000819050919050565b613c9c81613c89565b8114613ca757600080fd5b50565b600081359050613cb981613c93565b92915050565b60006101c08284031215613cd657613cd5613afa565b5b613ce060a0613a2f565b90506000613cf084828501613b93565b600083015250610140613d0584828501613caa565b602083015250610160613d1a84828501613b7e565b604083015250610180613d2f84828501613b7e565b6060830152506101a0613d4484828501613b7e565b60808301525092915050565b600080fd5b600080fd5b60008083601f840112613d7057613d6f6139b4565b5b8235905067ffffffffffffffff811115613d8d57613d8c613d50565b5b602083019150836001820283011115613da957613da8613d55565b5b9250929050565b6000806000806102008587031215613dcb57613dca6139aa565b5b600085013567ffffffffffffffff811115613de957613de86139af565b5b613df587828801613acc565b9450506020613e0687828801613cbf565b9350506101e085013567ffffffffffffffff811115613e2857613e276139af565b5b613e3487828801613d5a565b925092505092959194509250565b613e4b81613b5d565b82525050565b6000602082019050613e666000830184613e42565b92915050565b60007fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b613ea181613e6c565b8114613eac57600080fd5b50565b600081359050613ebe81613e98565b92915050565b600060208284031215613eda57613ed96139aa565b5b6000613ee884828501613eaf565b91505092915050565b60008115159050919050565b613f0681613ef1565b82525050565b6000602082019050613f216000830184613efd565b92915050565b600063ffffffff82169050919050565b613f4081613f27565b8114613f4b57600080fd5b50565b600081359050613f5d81613f37565b92915050565b600060208284031215613f7957613f786139aa565b5b6000613f8784828501613f4e565b91505092915050565b600077ffffffffffffffffffffffffffffffffffffffffffffffff82169050919050565b613fbd81613f90565b8114613fc857600080fd5b50565b600081359050613fda81613fb4565b92915050565b600060208284031215613ff657613ff56139aa565b5b600061400484828501613fcb565b91505092915050565b60008060408385031215614024576140236139aa565b5b600061403285828601613b48565b925050602061404385828601613fcb565b9150509250929050565b600061405882613aff565b9050919050565b6140688161404d565b811461407357600080fd5b50565b6000813590506140858161405f565b92915050565b600080604083850312156140a2576140a16139aa565b5b60006140b085828601614076565b92505060206140c185828601613b7e565b9150509250929050565b600080fd5b600061012082840312156140e7576140e66140cb565b5b81905092915050565b600060208284031215614106576141056139aa565b5b600082013567ffffffffffffffff811115614124576141236139af565b5b614130848285016140d0565b91505092915050565b61414281613c89565b82525050565b600060208201905061415d6000830184614139565b92915050565b600060208284031215614179576141786139aa565b5b600061418784828501613b48565b91505092915050565b61419981613b5d565b82525050565b6141a881613ef1565b82525050565b60006dffffffffffffffffffffffffffff82169050919050565b6141d1816141ae565b82525050565b6141e081613f27565b82525050565b600065ffffffffffff82169050919050565b614201816141e6565b82525050565b60a08201600082015161421d6000850182614190565b506020820151614230602085018261419f565b50604082015161424360408501826141c8565b50606082015161425660608501826141d7565b50608082015161426960808501826141f8565b50505050565b600060a0820190506142846000830184614207565b92915050565b60008083601f8401126142a05761429f6139b4565b5b8235905067ffffffffffffffff8111156142bd576142bc613d50565b5b6020830191508360208202830111156142d9576142d8613d55565b5b9250929050565b6000806000604084860312156142f9576142f86139aa565b5b600084013567ffffffffffffffff811115614317576143166139af565b5b6143238682870161428a565b9350935050602061433686828701614076565b9150509250925092565b600080600060408486031215614359576143586139aa565b5b600061436786828701613b48565b935050602084013567ffffffffffffffff811115614388576143876139af565b5b61439486828701613d5a565b92509250509250925092565b600080602083850312156143b7576143b66139aa565b5b600083013567ffffffffffffffff8111156143d5576143d46139af565b5b6143e185828601613d5a565b92509250509250929050565b600060208284031215614403576144026139aa565b5b600061441184828501614076565b91505092915050565b60008083601f8401126144305761442f6139b4565b5b8235905067ffffffffffffffff81111561444d5761444c613d50565b5b60208301915083602082028301111561446957614468613d55565b5b9250929050565b600080600060408486031215614489576144886139aa565b5b600084013567ffffffffffffffff8111156144a7576144a66139af565b5b6144b38682870161441a565b935093505060206144c686828701614076565b9150509250925092565b6144d9816141ae565b82525050565b6144e881613f27565b82525050565b6144f7816141e6565b82525050565b600060a0820190506145126000830188613e42565b61451f6020830187613efd565b61452c60408301866144d0565b61453960608301856144df565b61454660808301846144ee565b9695505050505050565b600082825260208201905092915050565b7f4141393220696e7465726e616c2063616c6c206f6e6c79000000000000000000600082015250565b6000614597601783614550565b91506145a282614561565b602082019050919050565b600060208201905081810360008301526145c68161458a565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b600081519050919050565b600082825260208201905092915050565b60005b8381101561463657808201518184015260208101905061461b565b60008484015250505050565b600061464d826145fc565b6146578185614607565b9350614667818560208601614618565b614670816139be565b840191505092915050565b60006040820190506146906000830185613e42565b81810360208301526146a28184614642565b90509392505050565b7f6d757374207370656369667920756e7374616b652064656c6179000000000000600082015250565b60006146e1601a83614550565b91506146ec826146ab565b602082019050919050565b60006020820190508181036000830152614710816146d4565b9050919050565b7f63616e6e6f7420646563726561736520756e7374616b652074696d6500000000600082015250565b600061474d601c83614550565b915061475882614717565b602082019050919050565b6000602082019050818103600083015261477c81614740565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60006147bd82613b5d565b91506147c883613b5d565b92508282019050808211156147e0576147df614783565b5b92915050565b7f6e6f207374616b65207370656369666965640000000000000000000000000000600082015250565b600061481c601283614550565b9150614827826147e6565b602082019050919050565b6000602082019050818103600083015261484b8161480f565b9050919050565b7f7374616b65206f766572666c6f77000000000000000000000000000000000000600082015250565b6000614888600e83614550565b915061489382614852565b602082019050919050565b600060208201905081810360008301526148b78161487b565b9050919050565b6000819050919050565b60006148e36148de6148d984613f27565b6148be565b613b5d565b9050919050565b6148f3816148c8565b82525050565b600060408201905061490e6000830185613e42565b61491b60208301846148ea565b9392505050565b600061492d82613b5d565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361495f5761495e614783565b5b600182019050919050565b7f576974686472617720616d6f756e7420746f6f206c6172676500000000000000600082015250565b60006149a0601983614550565b91506149ab8261496a565b602082019050919050565b600060208201905081810360008301526149cf81614993565b9050919050565b60006149e182613b5d565b91506149ec83613b5d565b9250828203905081811115614a0457614a03614783565b5b92915050565b6000614a25614a20614a1b84613aff565b6148be565b613aff565b9050919050565b6000614a3782614a0a565b9050919050565b6000614a4982614a2c565b9050919050565b614a5981614a3e565b82525050565b6000604082019050614a746000830185614a50565b614a816020830184613e42565b9392505050565b600081905092915050565b50565b6000614aa3600083614a88565b9150614aae82614a93565b600082019050919050565b6000614ac482614a96565b9150819050919050565b7f6661696c656420746f2077697468647261770000000000000000000000000000600082015250565b6000614b04601283614550565b9150614b0f82614ace565b602082019050919050565b60006020820190508181036000830152614b3381614af7565b9050919050565b614b4381613b1f565b82525050565b6000606082019050614b5e6000830186614139565b614b6b6020830185614b3a565b614b786040830184613e42565b949350505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600080fd5b600080fd5b600080fd5b60008235600161012003833603038112614bdb57614bda614baf565b5b80830191505092915050565b6000614bf38385614a88565b9350614c00838584613a7b565b82840190509392505050565b6000614c19828486614be7565b91508190509392505050565b6000604082019050614c3a6000830185613efd565b8181036020830152614c4c8184614642565b90509392505050565b6000614c618385614607565b9350614c6e838584613a7b565b614c77836139be565b840190509392505050565b60006020820190508181036000830152614c9d818486614c55565b90509392505050565b600081519050614cb581613b31565b92915050565b600060208284031215614cd157614cd06139aa565b5b6000614cdf84828501614ca6565b91505092915050565b6000602082019050614cfd6000830184614b3a565b92915050565b7f6e6f74207374616b656400000000000000000000000000000000000000000000600082015250565b6000614d39600a83614550565b9150614d4482614d03565b602082019050919050565b60006020820190508181036000830152614d6881614d2c565b9050919050565b7f616c726561647920756e7374616b696e67000000000000000000000000000000600082015250565b6000614da5601183614550565b9150614db082614d6f565b602082019050919050565b60006020820190508181036000830152614dd481614d98565b9050919050565b6000614de6826141e6565b9150614df1836141e6565b9250828201905065ffffffffffff811115614e0f57614e0e614783565b5b92915050565b6000614e30614e2b614e26846141e6565b6148be565b613b5d565b9050919050565b614e4081614e15565b82525050565b6000602082019050614e5b6000830184614e37565b92915050565b7f4e6f207374616b6520746f207769746864726177000000000000000000000000600082015250565b6000614e97601483614550565b9150614ea282614e61565b602082019050919050565b60006020820190508181036000830152614ec681614e8a565b9050919050565b7f6d7573742063616c6c20756e6c6f636b5374616b652829206669727374000000600082015250565b6000614f03601d83614550565b9150614f0e82614ecd565b602082019050919050565b60006020820190508181036000830152614f3281614ef6565b9050919050565b7f5374616b65207769746864726177616c206973206e6f74206475650000000000600082015250565b6000614f6f601b83614550565b9150614f7a82614f39565b602082019050919050565b60006020820190508181036000830152614f9e81614f62565b9050919050565b7f6661696c656420746f207769746864726177207374616b650000000000000000600082015250565b6000614fdb601883614550565b9150614fe682614fa5565b602082019050919050565b6000602082019050818103600083015261500a81614fce565b9050919050565b60008235600160600383360303811261502d5761502c614baf565b5b80830191505092915050565b6000808335600160200384360303811261505657615055614baf565b5b80840192508235915067ffffffffffffffff82111561507857615077614bb4565b5b60208301925060208202360383131561509457615093614bb9565b5b509250929050565b60006150a782613b1f565b9050919050565b6150b78161509c565b81146150c257600080fd5b50565b6000813590506150d4816150ae565b92915050565b6000602082840312156150f0576150ef6139aa565b5b60006150fe848285016150c5565b91505092915050565b7f4141393620696e76616c69642061676772656761746f72000000000000000000600082015250565b600061513d601783614550565b915061514882615107565b602082019050919050565b6000602082019050818103600083015261516c81615130565b9050919050565b600080833560016020038436030381126151905761518f614baf565b5b80840192508235915067ffffffffffffffff8211156151b2576151b1614bb4565b5b6020830192506001820236038313156151ce576151cd614bb9565b5b509250929050565b600082825260208201905092915050565b6000819050919050565b60006152006020840184613b48565b905092915050565b61521181613b1f565b82525050565b60006152266020840184613b7e565b905092915050565b600080fd5b600080fd5b600080fd5b6000808335600160200384360303811261525a57615259615238565b5b83810192508235915060208301925067ffffffffffffffff8211156152825761528161522e565b5b60018202360383131561529857615297615233565b5b509250929050565b600082825260208201905092915050565b60006152bd83856152a0565b93506152ca838584613a7b565b6152d3836139be565b840190509392505050565b60006152ed6020840184613caa565b905092915050565b6152fe81613c89565b82525050565b6000610120830161531860008401846151f1565b6153256000860182615208565b506153336020840184615217565b6153406020860182614190565b5061534e604084018461523d565b85830360408701526153618382846152b1565b92505050615372606084018461523d565b85830360608701526153858382846152b1565b9250505061539660808401846152de565b6153a360808601826152f5565b506153b160a0840184615217565b6153be60a0860182614190565b506153cc60c08401846152de565b6153d960c08601826152f5565b506153e760e084018461523d565b85830360e08701526153fa8382846152b1565b9250505061540c61010084018461523d565b8583036101008701526154208382846152b1565b925050508091505092915050565b600061543a8383615304565b905092915050565b6000823560016101200383360303811261545f5761545e615238565b5b82810191505092915050565b6000602082019050919050565b600061548483856151d6565b935083602084028501615496846151e7565b8060005b878110156154da5784840389526154b18284615442565b6154bb858261542e565b94506154c68361546b565b925060208a0199505060018101905061549a565b50829750879450505050509392505050565b60006040820190508181036000830152615507818688615478565b9050818103602083015261551c818486614c55565b905095945050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b6003811061556757615566615527565b5b50565b600081905061557882615556565b919050565b60006155888261556a565b9050919050565b6155988161557d565b82525050565b60006080820190506155b3600083018761558f565b81810360208301526155c58186614642565b90506155d46040830185613e42565b6155e16060830184613e42565b95945050505050565b600060208201905081810360008301526156048184614642565b905092915050565b7f41413934206761732076616c756573206f766572666c6f770000000000000000600082015250565b6000615642601883614550565b915061564d8261560c565b602082019050919050565b6000602082019050818103600083015261567181615635565b9050919050565b7f4141323520696e76616c6964206163636f756e74206e6f6e6365000000000000600082015250565b60006156ae601a83614550565b91506156b982615678565b602082019050919050565b60006040820190506156d96000830184613e42565b81810360208301526156ea816156a1565b905092915050565b7f41413236206f76657220766572696669636174696f6e4761734c696d69740000600082015250565b6000615728601e83614550565b9150615733826156f2565b602082019050919050565b60006040820190506157536000830184613e42565b81810360208301526157648161571b565b905092915050565b7f41413234207369676e6174757265206572726f72000000000000000000000000600082015250565b60006157a2601483614550565b91506157ad8261576c565b602082019050919050565b60006040820190506157cd6000830184613e42565b81810360208301526157de81615795565b905092915050565b7f414132322065787069726564206f72206e6f7420647565000000000000000000600082015250565b600061581c601783614550565b9150615827826157e6565b602082019050919050565b60006040820190506158476000830184613e42565b81810360208301526158588161580f565b905092915050565b7f41413334207369676e6174757265206572726f72000000000000000000000000600082015250565b6000615896601483614550565b91506158a182615860565b602082019050919050565b60006040820190506158c16000830184613e42565b81810360208301526158d281615889565b905092915050565b7f41413332207061796d61737465722065787069726564206f72206e6f7420647560008201527f6500000000000000000000000000000000000000000000000000000000000000602082015250565b6000615936602183614550565b9150615941826158da565b604082019050919050565b60006040820190506159616000830184613e42565b818103602083015261597281615929565b905092915050565b6000610120830161598e60008401846151f1565b61599b6000860182615208565b506159a96020840184615217565b6159b66020860182614190565b506159c4604084018461523d565b85830360408701526159d78382846152b1565b925050506159e8606084018461523d565b85830360608701526159fb8382846152b1565b92505050615a0c60808401846152de565b615a1960808601826152f5565b50615a2760a0840184615217565b615a3460a0860182614190565b50615a4260c08401846152de565b615a4f60c08601826152f5565b50615a5d60e084018461523d565b85830360e0870152615a708382846152b1565b92505050615a8261010084018461523d565b858303610100870152615a968382846152b1565b925050508091505092915050565b60006040820190508181036000830152615abe818561597a565b9050615acd6020830184614139565b9392505050565b61014082016000820151615aeb6000850182615208565b506020820151615afe6020850182614190565b506040820151615b116040850182614190565b506060820151615b246060850182614190565b506080820151615b376080850182614190565b5060a0820151615b4a60a0850182614190565b5060c0820151615b5d60c0850182614190565b5060e0820151615b7060e0850182615208565b50610100820151615b85610100850182614190565b50610120820151615b9a610120850182614190565b50505050565b6101c082016000820151615bb76000850182615ad4565b506020820151615bcb6101408501826152f5565b506040820151615bdf610160850182614190565b506060820151615bf3610180850182614190565b506080820151615c076101a0850182614190565b50505050565b6000610200820190508181036000830152615c288186614642565b9050615c376020830185615ba0565b8181036101e0830152615c4a8184614642565b9050949350505050565b6000610200820190508181036000830152615c70818688614c55565b9050615c7f6020830185615ba0565b8181036101e0830152615c928184614642565b905095945050505050565b7f41413935206f7574206f66206761730000000000000000000000000000000000600082015250565b6000615cd3600f83614550565b9150615cde82615c9d565b602082019050919050565b6000604082019050615cfe6000830184613e42565b8181036020830152615d0f81615cc6565b905092915050565b7f4141393020696e76616c69642062656e65666963696172790000000000000000600082015250565b6000615d4d601883614550565b9150615d5882615d17565b602082019050919050565b60006020820190508181036000830152615d7c81615d40565b9050919050565b7f41413931206661696c65642073656e6420746f2062656e656669636961727900600082015250565b6000615db9601f83614550565b9150615dc482615d83565b602082019050919050565b60006020820190508181036000830152615de881615dac565b9050919050565b6000608082019050615e046000830187613e42565b615e116020830186613efd565b615e1e6040830185613e42565b615e2b6060830184613e42565b95945050505050565b600061010082019050615e4a600083018b614b3a565b615e57602083018a613e42565b615e646040830189614139565b615e716060830188614139565b615e7e6080830187614139565b615e8b60a0830186613e42565b615e9860c0830185614139565b615ea560e0830184614139565b9998505050505050505050565b7f4141393320696e76616c6964207061796d6173746572416e6444617461000000600082015250565b6000615ee8601d83614550565b9150615ef382615eb2565b602082019050919050565b60006020820190508181036000830152615f1781615edb565b9050919050565b60006060820190508181036000830152615f38818661597a565b9050615f476020830185614139565b615f546040830184613e42565b949350505050565b600081519050615f6b81613b67565b92915050565b600060208284031215615f8757615f866139aa565b5b6000615f9584828501615f5c565b91505092915050565b7f4141323320726576657274656400000000000000000000000000000000000000600082015250565b6000615fd4600d83614550565b9150615fdf82615f9e565b602082019050919050565b6000606082019050615fff6000830185613e42565b818103602083015261601081615fc7565b905081810360408301526160248184614642565b90509392505050565b7f41413231206469646e2774207061792070726566756e64000000000000000000600082015250565b6000616063601783614550565b915061606e8261602d565b602082019050919050565b600060408201905061608e6000830184613e42565b818103602083015261609f81616056565b905092915050565b7f41413331207061796d6173746572206465706f73697420746f6f206c6f770000600082015250565b60006160dd601e83614550565b91506160e8826160a7565b602082019050919050565b60006040820190506161086000830184613e42565b8181036020830152616119816160d0565b905092915050565b600061613461612f84613a4a565b613a2f565b9050828152602081018484840111156161505761614f6139b9565b5b61615b848285614618565b509392505050565b600082601f830112616178576161776139b4565b5b8151616188848260208601616121565b91505092915050565b600080604083850312156161a8576161a76139aa565b5b600083015167ffffffffffffffff8111156161c6576161c56139af565b5b6161d285828601616163565b92505060206161e385828601615f5c565b9150509250929050565b7f4141333320726576657274656400000000000000000000000000000000000000600082015250565b6000616223600d83614550565b915061622e826161ed565b602082019050919050565b600060608201905061624e6000830185613e42565b818103602083015261625f81616216565b905081810360408301526162738184614642565b90509392505050565b7f41413336206f766572207061796d6173746572566572696669636174696f6e4760008201527f61734c696d697400000000000000000000000000000000000000000000000000602082015250565b60006162d8602783614550565b91506162e38261627c565b604082019050919050565b60006040820190506163036000830184613e42565b8181036020830152616314816162cb565b905092915050565b600080fd5b600080fd5b6000808585111561633a5761633961631c565b5b8386111561634b5761634a616321565b5b6001850283019150848603905094509492505050565b600082905092915050565b60007fffffffffffffffffffffffffffffffffffffffff00000000000000000000000082169050919050565b600082821b905092915050565b60006163b18383616361565b826163bc813561636c565b925060148210156163fc576163f77fffffffffffffffffffffffffffffffffffffffff00000000000000000000000083601403600802616398565b831692505b505092915050565b60007fffffffffffffffffffffffffffffffff0000000000000000000000000000000082169050919050565b600061643c8383616361565b826164478135616404565b92506010821015616487576164827fffffffffffffffffffffffffffffffff0000000000000000000000000000000083601003600802616398565b831692505b505092915050565b7f414131302073656e64657220616c726561647920636f6e737472756374656400600082015250565b60006164c5601f83614550565b91506164d08261648f565b602082019050919050565b60006040820190506164f06000830184613e42565b8181036020830152616501816164b8565b905092915050565b7f4141313320696e6974436f6465206661696c6564206f72204f4f470000000000600082015250565b600061653f601b83614550565b915061654a82616509565b602082019050919050565b600060408201905061656a6000830184613e42565b818103602083015261657b81616532565b905092915050565b7f4141313420696e6974436f6465206d7573742072657475726e2073656e646572600082015250565b60006165b9602083614550565b91506165c482616583565b602082019050919050565b60006040820190506165e46000830184613e42565b81810360208301526165f5816165ac565b905092915050565b7f4141313520696e6974436f6465206d757374206372656174652073656e646572600082015250565b6000616633602083614550565b915061663e826165fd565b602082019050919050565b600060408201905061665e6000830184613e42565b818103602083015261666f81616626565b905092915050565b600060408201905061668c6000830185614b3a565b6166996020830184614b3a565b939250505056fea2646970667358221220f6e7d5acc3b3ce47e8c4e79583caee84134eab4d0c55f3973f51a15d53351cdb64736f6c63430008170033", + "nonce": 1, + "gas_used": 5951292 + }, + "receipt": { + "type": "0x2", + "status": "0x1", + "cumulativeGasUsed": "0x5acf3c", + "logs": [], + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + }, + "block_hash": "0x906d63b887e2dde832fec45ebb4edd648448e17419da605efdd9defc478a8885", + "block_number": 2 + }, + { + "info": { + "transaction_hash": "0x306a855ddd01606d902339c6c61bc066165db32626858e2d9cc113954068a047", + "transaction_index": 0, + "from": "0x3c44cdddb6a900fa2b585dd299e03d12fa4293bc", + "to": null, + "contract_address": "0x663f3ad617193148711d28f5334ee4ed07016602", + "traces": [ + { + "parent": null, + "children": [], + "idx": 0, + "trace": { + "depth": 0, + "success": true, + "caller": "0x3c44cdddb6a900fa2b585dd299e03d12fa4293bc", + "address": "0x663f3ad617193148711d28f5334ee4ed07016602", + "maybe_precompile": false, + "selfdestruct_address": null, + "selfdestruct_refund_target": null, + "selfdestruct_transferred_value": null, + "kind": "CREATE", + "value": "0x0", + "data": "0x6101606040523480156200001257600080fd5b5060405162004f4b38038062004f4b8339818101604052810190620000389190620005cd565b6040518060400160405280601181526020017f44656c65676174696f6e4d616e616765720000000000000000000000000000008152506040518060400160405280600181526020017f310000000000000000000000000000000000000000000000000000000000000081525082600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16036200011a5760006040517f1e4fbdf700000000000000000000000000000000000000000000000000000000815260040162000111919062000610565b60405180910390fd5b6200012b81620002d260201b60201c565b506000600160146101000a81548160ff0219169083151502179055506200015d6002836200030b60201b90919060201c565b61012081815250506200017b6003826200030b60201b90919060201c565b6101408181525050818051906020012060e08181525050808051906020012061010081815250504660a08181525050620001ba6200036360201b60201c565b608081815250503073ffffffffffffffffffffffffffffffffffffffff1660c08173ffffffffffffffffffffffffffffffffffffffff16815250505050600062000209620003c060201b60201c565b90503073ffffffffffffffffffffffffffffffffffffffff16817f04a46d9007577c7ff1e513b900545162ec25d25991ae3dc60cf26ec01a84806d6040518060400160405280601181526020017f44656c65676174696f6e4d616e616765720000000000000000000000000000008152506040518060400160405280600181526020017f310000000000000000000000000000000000000000000000000000000000000081525046604051620002c293929190620006e2565b60405180910390a3505062000bb7565b600160006101000a81549073ffffffffffffffffffffffffffffffffffffffff021916905562000308816200042860201b60201c565b50565b600060208351101562000331576200032983620004ec60201b60201c565b90506200035d565b8262000343836200055960201b60201c565b600001908162000354919062000992565b5060ff60001b90505b92915050565b60007f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f60e051610100514630604051602001620003a595949392919062000a94565b60405160208183030381529060405280519060200120905090565b600060c05173ffffffffffffffffffffffffffffffffffffffff163073ffffffffffffffffffffffffffffffffffffffff1614801562000401575060a05146145b156200041257608051905062000425565b620004226200036360201b60201c565b90505b90565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050816000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a35050565b600080829050601f815111156200053c57826040517f305a27a900000000000000000000000000000000000000000000000000000000815260040162000533919062000af1565b60405180910390fd5b8051816200054a9062000b47565b60001c1760001b915050919050565b6000819050919050565b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000620005958262000568565b9050919050565b620005a78162000588565b8114620005b357600080fd5b50565b600081519050620005c7816200059c565b92915050565b600060208284031215620005e657620005e562000563565b5b6000620005f684828501620005b6565b91505092915050565b6200060a8162000588565b82525050565b6000602082019050620006276000830184620005ff565b92915050565b600081519050919050565b600082825260208201905092915050565b60005b83811015620006695780820151818401526020810190506200064c565b60008484015250505050565b6000601f19601f8301169050919050565b600062000693826200062d565b6200069f818562000638565b9350620006b181856020860162000649565b620006bc8162000675565b840191505092915050565b6000819050919050565b620006dc81620006c7565b82525050565b60006060820190508181036000830152620006fe818662000686565b9050818103602083015262000714818562000686565b9050620007256040830184620006d1565b949350505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b60006002820490506001821680620007a457607f821691505b602082108103620007ba57620007b96200075c565b5b50919050565b60008190508160005260206000209050919050565b60006020601f8301049050919050565b600082821b905092915050565b600060088302620008247fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82620007e5565b620008308683620007e5565b95508019841693508086168417925050509392505050565b6000819050919050565b6000620008736200086d6200086784620006c7565b62000848565b620006c7565b9050919050565b6000819050919050565b6200088f8362000852565b620008a76200089e826200087a565b848454620007f2565b825550505050565b600090565b620008be620008af565b620008cb81848462000884565b505050565b5b81811015620008f357620008e7600082620008b4565b600181019050620008d1565b5050565b601f82111562000942576200090c81620007c0565b6200091784620007d5565b8101602085101562000927578190505b6200093f6200093685620007d5565b830182620008d0565b50505b505050565b600082821c905092915050565b6000620009676000198460080262000947565b1980831691505092915050565b600062000982838362000954565b9150826002028217905092915050565b6200099d826200062d565b67ffffffffffffffff811115620009b957620009b86200072d565b5b620009c582546200078b565b620009d2828285620008f7565b600060209050601f83116001811462000a0a5760008415620009f5578287015190505b62000a01858262000974565b86555062000a71565b601f19841662000a1a86620007c0565b60005b8281101562000a445784890151825560018201915060208501945060208101905062000a1d565b8683101562000a64578489015162000a60601f89168262000954565b8355505b6001600288020188555050505b505050505050565b6000819050919050565b62000a8e8162000a79565b82525050565b600060a08201905062000aab600083018862000a83565b62000aba602083018762000a83565b62000ac9604083018662000a83565b62000ad86060830185620006d1565b62000ae76080830184620005ff565b9695505050505050565b6000602082019050818103600083015262000b0d818462000686565b905092915050565b600081519050919050565b6000819050602082019050919050565b600062000b3e825162000a79565b80915050919050565b600062000b548262000b15565b8262000b608462000b20565b905062000b6d8162000b30565b9250602082101562000bb05762000bab7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff83602003600802620007e5565b831692505b5050919050565b60805160a05160c05160e05161010051610120516101405161433962000c1260003960006122aa0152600061226f015260006125ac0152600061258b01526000612151015260006121a7015260006121d001526143396000f3fe608060405234801561001057600080fd5b506004361061012c5760003560e01c806383ebb771116100ad578063acb8cc4911610071578063acb8cc49146102c9578063cef6d209146102e7578063e30c397814610303578063f2fde38b14610321578063ffa1ad741461033d5761012c565b806383ebb771146102415780638456cb591461025f57806384b0196e146102695780638da5cb5b1461028d578063a3f4df7e146102ab5761012c565b806358909ebc116100f457806358909ebc146101c15780635c975abb146101df57806366134607146101fd578063715018a61461022d57806379ba5097146102375761012c565b80631b13cac2146101315780632d40d0521461014f5780633ed010151461017f5780633f4ba83a1461019b57806349934047146101a5575b600080fd5b61013961035b565b6040516101469190612b0a565b60405180910390f35b61016960048036038101906101649190612b65565b610382565b6040516101769190612bad565b60405180910390f35b61019960048036038101906101949190612bec565b6103a2565b005b6101a3610539565b005b6101bf60048036038101906101ba9190612bec565b61054b565b005b6101c96106e2565b6040516101d69190612c76565b60405180910390f35b6101e76106e8565b6040516101f49190612bad565b60405180910390f35b61021760048036038101906102129190612bec565b6106ff565b6040516102249190612b0a565b60405180910390f35b61023561071a565b005b61023f61072e565b005b6102496107bd565b6040516102569190612b0a565b60405180910390f35b6102676107cc565b005b6102716107de565b6040516102849796959493929190612e33565b60405180910390f35b610295610888565b6040516102a29190612c76565b60405180910390f35b6102b36108b1565b6040516102c09190612eb7565b60405180910390f35b6102d16108ea565b6040516102de9190612eb7565b60405180910390f35b61030160048036038101906102fc9190612f94565b610923565b005b61030b611e9f565b6040516103189190612c76565b60405180910390f35b61033b60048036038101906103369190613074565b611ec9565b005b610345611f76565b6040516103529190612eb7565b60405180910390f35b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60001b81565b60046020528060005260406000206000915054906101000a900460ff1681565b8060200160208101906103b59190613074565b3373ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161461041a576040517fb9f0f17100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000610425836106ff565b90506004600082815260200190815260200160002060009054906101000a900460ff1661047e576040517ff2a5f75a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006004600083815260200190815260200160002060006101000a81548160ff0219169083151502179055508260000160208101906104bd9190613074565b73ffffffffffffffffffffffffffffffffffffffff168360200160208101906104e69190613074565b73ffffffffffffffffffffffffffffffffffffffff16827f3feadce88fc1b49db633a56fd5307ed6ee18734df83bcc4011daa720c9cd95f18660405161052c9190613461565b60405180910390a4505050565b610541611faf565b610549612036565b565b80602001602081019061055e9190613074565b3373ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16146105c3576040517fb9f0f17100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006105ce836106ff565b90506004600082815260200190815260200160002060009054906101000a900460ff1615610627576040517e5ecddb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60016004600083815260200190815260200160002060006101000a81548160ff0219169083151502179055508260000160208101906106669190613074565b73ffffffffffffffffffffffffffffffffffffffff1683602001602081019061068f9190613074565b73ffffffffffffffffffffffffffffffffffffffff16827fea589ba9473ee1fe77d352c7ed919747715a5d22931b972de9b02a907c66d5dd866040516106d59190613461565b60405180910390a4505050565b610a1181565b6000600160149054906101000a900460ff16905090565b60006107138261070e90613803565b612099565b9050919050565b610722611faf565b61072c6000612114565b565b6000610738612145565b90508073ffffffffffffffffffffffffffffffffffffffff16610759611e9f565b73ffffffffffffffffffffffffffffffffffffffff16146107b157806040517f118cdaa70000000000000000000000000000000000000000000000000000000081526004016107a89190612c76565b60405180910390fd5b6107ba81612114565b50565b60006107c761214d565b905090565b6107d4611faf565b6107dc612204565b565b6000606080600080600060606107f2612266565b6107fa6122a1565b46306000801b600067ffffffffffffffff81111561081b5761081a613488565b5b6040519080825280602002602001820160405280156108495781602001602082028036833780820191505090505b507f0f00000000000000000000000000000000000000000000000000000000000000959493929190965096509650965096509650965090919293949596565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b6040518060400160405280601181526020017f44656c65676174696f6e4d616e6167657200000000000000000000000000000081525081565b6040518060400160405280600181526020017f310000000000000000000000000000000000000000000000000000000000000081525081565b61092b6122dc565b600086869050905082829050811415806109485750848490508114155b1561097f576040517f1bcaf69f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008167ffffffffffffffff81111561099b5761099a613488565b5b6040519080825280602002602001820160405280156109ce57816020015b60608152602001906001900390816109b95790505b50905060008267ffffffffffffffff8111156109ed576109ec613488565b5b604051908082528060200260200182016040528015610a2057816020015b6060815260200190600190039081610a0b5790505b50905060005b838110156111b65760008a8a83818110610a4357610a42613816565b5b9050602002810190610a559190613854565b810190610a629190613998565b90506000815103610b4d57600067ffffffffffffffff811115610a8857610a87613488565b5b604051908082528060200260200182016040528015610ac157816020015b610aae612a8c565b815260200190600190039081610aa65790505b50848381518110610ad557610ad4613816565b5b6020026020010181905250600067ffffffffffffffff811115610afb57610afa613488565b5b604051908082528060200260200182016040528015610b295781602001602082028036833780820191505090505b50838381518110610b3d57610b3c613816565b5b60200260200101819052506111aa565b80848381518110610b6157610b60613816565b5b60200260200101819052506000815167ffffffffffffffff811115610b8957610b88613488565b5b604051908082528060200260200182016040528015610bb75781602001602082028036833780820191505090505b50905080848481518110610bce57610bcd613816565b5b60200260200101819052503373ffffffffffffffffffffffffffffffffffffffff1682600081518110610c0457610c03613816565b5b60200260200101516000015173ffffffffffffffffffffffffffffffffffffffff1614158015610c815750610a1173ffffffffffffffffffffffffffffffffffffffff1682600081518110610c5c57610c5b613816565b5b60200260200101516000015173ffffffffffffffffffffffffffffffffffffffff1614155b15610cb8576040517fb586360400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b8251811015610f1d576000838281518110610cd957610cd8613816565b5b60200260200101519050610cec81612099565b838381518110610cff57610cfe613816565b5b6020026020010181815250506000816020015173ffffffffffffffffffffffffffffffffffffffff163b03610dd9576000610d68610d5e610d3e6107bd565b868681518110610d5157610d50613816565b5b602002602001015161231d565b8360a0015161235e565b9050816020015173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614610dd3576040517f3db6791c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50610f11565b6000610e06610de66107bd565b858581518110610df957610df8613816565b5b602002602001015161231d565b90506000826020015173ffffffffffffffffffffffffffffffffffffffff16631626ba7e838560a001516040518363ffffffff1660e01b8152600401610e4d929190613a36565b602060405180830381865afa158015610e6a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e8e9190613abe565b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19169050631626ba7e60e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19168114610f0e576040517f155ff42700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50505b50806001019050610cbb565b5060005b82518110156111a75760046000838381518110610f4157610f40613816565b5b6020026020010151815260200190815260200160002060009054906101000a900460ff1615610f9c576040517f05baa05200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60018351610faa9190613b1a565b81146111215781600182610fbe9190613b4e565b81518110610fcf57610fce613816565b5b6020026020010151838281518110610fea57610fe9613816565b5b6020026020010151604001511461102d576040517fded4370e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008360018361103d9190613b4e565b8151811061104e5761104d613816565b5b6020026020010151600001519050610a1173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16141580156110e457508073ffffffffffffffffffffffffffffffffffffffff168483815181106110bf576110be613816565b5b60200260200101516020015173ffffffffffffffffffffffffffffffffffffffff1614155b1561111b576040517fb586360400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5061119c565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60001b83828151811061115857611157613816565b5b6020026020010151604001511461119b576040517fded4370e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5b806001019050610f21565b50505b50806001019050610a26565b5060005b838110156113fb5760008382815181106111d7576111d6613816565b5b60200260200101515111156113f05760005b8382815181106111fc576111fb613816565b5b6020026020010151518110156113ee57600084838151811061122157611220613816565b5b6020026020010151828151811061123b5761123a613816565b5b602002602001015160600151905060005b81518110156113e157600082828151811061126a57611269613816565b5b60200260200101516000015190508073ffffffffffffffffffffffffffffffffffffffff1663414c3e338484815181106112a7576112a6613816565b5b6020026020010151602001518585815181106112c6576112c5613816565b5b6020026020010151604001518f8f8a8181106112e5576112e4613816565b5b905060200201358e8e8b8181106112ff576112fe613816565b5b90506020028101906113119190613854565b8c8c8151811061132457611323613816565b5b60200260200101518b8151811061133e5761133d613816565b5b60200260200101518e8d8151811061135957611358613816565b5b60200260200101518c8151811061137357611372613816565b5b602002602001015160200151336040518963ffffffff1660e01b81526004016113a3989796959493929190613bd0565b600060405180830381600087803b1580156113bd57600080fd5b505af11580156113d1573d6000803e3d6000fd5b505050505080600101905061124c565b50508060010190506111e9565b505b8060010190506111ba565b5060005b83811015611a8c57600083828151811061141c5761141b613816565b5b602002602001015151036114f1573373ffffffffffffffffffffffffffffffffffffffff1663d691c96489898481811061145957611458613816565b5b9050602002013588888581811061147357611472613816565b5b90506020028101906114859190613854565b6040518463ffffffff1660e01b81526004016114a393929190613c56565b6000604051808303816000875af11580156114c2573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f820116820180604052508101906114eb9190613dd9565b50611a81565b60005b83828151811061150757611506613816565b5b6020026020010151518110156116f957600084838151811061152c5761152b613816565b5b6020026020010151828151811061154657611545613816565b5b602002602001015160600151905060005b81518110156116ec57600082828151811061157557611574613816565b5b60200260200101516000015190508073ffffffffffffffffffffffffffffffffffffffff1663a145832a8484815181106115b2576115b1613816565b5b6020026020010151602001518585815181106115d1576115d0613816565b5b6020026020010151604001518f8f8a8181106115f0576115ef613816565b5b905060200201358e8e8b81811061160a57611609613816565b5b905060200281019061161c9190613854565b8c8c8151811061162f5761162e613816565b5b60200260200101518b8151811061164957611648613816565b5b60200260200101518e8d8151811061166457611663613816565b5b60200260200101518c8151811061167e5761167d613816565b5b602002602001015160200151336040518963ffffffff1660e01b81526004016116ae989796959493929190613bd0565b600060405180830381600087803b1580156116c857600080fd5b505af11580156116dc573d6000803e3d6000fd5b5050505050806001019050611557565b50508060010190506114f4565b5082818151811061170d5761170c613816565b5b6020026020010151600184838151811061172a57611729613816565b5b60200260200101515161173d9190613b1a565b8151811061174e5761174d613816565b5b60200260200101516020015173ffffffffffffffffffffffffffffffffffffffff1663d691c96489898481811061178857611787613816565b5b905060200201358888858181106117a2576117a1613816565b5b90506020028101906117b49190613854565b6040518463ffffffff1660e01b81526004016117d293929190613c56565b6000604051808303816000875af11580156117f1573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f8201168201806040525081019061181a9190613dd9565b5060008382815181106118305761182f613816565b5b60200260200101515190505b6000811115611a7f57600084838151811061185a57611859613816565b5b602002602001015160018361186f9190613b1a565b815181106118805761187f613816565b5b60200260200101516060015190506000815190505b6000811115611a6c576000826001836118ae9190613b1a565b815181106118bf576118be613816565b5b60200260200101516000015190508073ffffffffffffffffffffffffffffffffffffffff1663d3eddcc5846001856118f79190613b1a565b8151811061190857611907613816565b5b602002602001015160200151856001866119229190613b1a565b8151811061193357611932613816565b5b6020026020010151604001518f8f8a81811061195257611951613816565b5b905060200201358e8e8b81811061196c5761196b613816565b5b905060200281019061197e9190613854565b8c8c8151811061199157611990613816565b5b602002602001015160018c6119a69190613b1a565b815181106119b7576119b6613816565b5b60200260200101518e8d815181106119d2576119d1613816565b5b602002602001015160018d6119e79190613b1a565b815181106119f8576119f7613816565b5b602002602001015160200151336040518963ffffffff1660e01b8152600401611a28989796959493929190613bd0565b600060405180830381600087803b158015611a4257600080fd5b505af1158015611a56573d6000803e3d6000fd5b505050505080611a6590613e22565b9050611895565b505080611a7890613e22565b905061183c565b505b8060010190506113ff565b5060005b83811015611d2d576000838281518110611aad57611aac613816565b5b6020026020010151511115611d22576000838281518110611ad157611ad0613816565b5b60200260200101515190505b6000811115611d20576000848381518110611afb57611afa613816565b5b6020026020010151600183611b109190613b1a565b81518110611b2157611b20613816565b5b60200260200101516060015190506000815190505b6000811115611d0d57600082600183611b4f9190613b1a565b81518110611b6057611b5f613816565b5b60200260200101516000015190508073ffffffffffffffffffffffffffffffffffffffff1663ed46336784600185611b989190613b1a565b81518110611ba957611ba8613816565b5b60200260200101516020015185600186611bc39190613b1a565b81518110611bd457611bd3613816565b5b6020026020010151604001518f8f8a818110611bf357611bf2613816565b5b905060200201358e8e8b818110611c0d57611c0c613816565b5b9050602002810190611c1f9190613854565b8c8c81518110611c3257611c31613816565b5b602002602001015160018c611c479190613b1a565b81518110611c5857611c57613816565b5b60200260200101518e8d81518110611c7357611c72613816565b5b602002602001015160018d611c889190613b1a565b81518110611c9957611c98613816565b5b602002602001015160200151336040518963ffffffff1660e01b8152600401611cc9989796959493929190613bd0565b600060405180830381600087803b158015611ce357600080fd5b505af1158015611cf7573d6000803e3d6000fd5b505050505080611d0690613e22565b9050611b36565b505080611d1990613e22565b9050611add565b505b806001019050611a90565b5060005b83811015611e93576000838281518110611d4e57611d4d613816565b5b6020026020010151511115611e885760005b838281518110611d7357611d72613816565b5b602002602001015151811015611e86573373ffffffffffffffffffffffffffffffffffffffff16848381518110611dad57611dac613816565b5b60200260200101516001868581518110611dca57611dc9613816565b5b602002602001015151611ddd9190613b1a565b81518110611dee57611ded613816565b5b60200260200101516020015173ffffffffffffffffffffffffffffffffffffffff167f40dadaa36c6c2e3d7317e24757451ffb2d603d875f0ad5e92c5dd156573b1873868581518110611e4457611e43613816565b5b60200260200101518481518110611e5e57611e5d613816565b5b6020026020010151604051611e73919061401c565b60405180910390a3806001019050611d60565b505b806001019050611d31565b50505050505050505050565b6000600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b611ed1611faf565b80600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508073ffffffffffffffffffffffffffffffffffffffff16611f31610888565b73ffffffffffffffffffffffffffffffffffffffff167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b6040518060400160405280600581526020017f312e332e3000000000000000000000000000000000000000000000000000000081525081565b611fb7612145565b73ffffffffffffffffffffffffffffffffffffffff16611fd5610888565b73ffffffffffffffffffffffffffffffffffffffff161461203457611ff8612145565b6040517f118cdaa700000000000000000000000000000000000000000000000000000000815260040161202b9190612c76565b60405180910390fd5b565b61203e61238a565b6000600160146101000a81548160ff0219169083151502179055507f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa612082612145565b60405161208f9190612c76565b60405180910390a1565b6000807f88c1d2ecf185adf710588203a5f263f0ff61be0d33da39792cde19ba9aa4331e8360000151846020015185604001516120d987606001516123ca565b87608001516040516020016120f39695949392919061403e565b60405160208183030381529060405290508080519060200120915050919050565b600160006101000a81549073ffffffffffffffffffffffffffffffffffffffff0219169055612142816124a2565b50565b600033905090565b60007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff163073ffffffffffffffffffffffffffffffffffffffff161480156121c957507f000000000000000000000000000000000000000000000000000000000000000046145b156121f6577f00000000000000000000000000000000000000000000000000000000000000009050612201565b6121fe612566565b90505b90565b61220c6122dc565b60018060146101000a81548160ff0219169083151502179055507f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a25861224f612145565b60405161225c9190612c76565b60405180910390a1565b606061229c60027f00000000000000000000000000000000000000000000000000000000000000006125fc90919063ffffffff16565b905090565b60606122d760037f00000000000000000000000000000000000000000000000000000000000000006125fc90919063ffffffff16565b905090565b6122e46106e8565b1561231b576040517fd93c066500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b565b60006040517f190100000000000000000000000000000000000000000000000000000000000081528360028201528260228201526042812091505092915050565b60008060008061236e86866126ac565b92509250925061237e8282612708565b82935050505092915050565b6123926106e8565b6123c8576040517f8dfc202b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b565b600080825167ffffffffffffffff8111156123e8576123e7613488565b5b6040519080825280602002602001820160405280156124165781602001602082028036833780820191505090505b50905060005b83518110156124725761244884828151811061243b5761243a613816565b5b602002602001015161286c565b82828151811061245b5761245a613816565b5b60200260200101818152505080600101905061241c565b50806040516020016124849190614157565b60405160208183030381529060405280519060200120915050919050565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050816000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a35050565b60007f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f7f00000000000000000000000000000000000000000000000000000000000000007f000000000000000000000000000000000000000000000000000000000000000046306040516020016125e195949392919061416e565b60405160208183030381529060405280519060200120905090565b606060ff60001b831461261957612612836128d4565b90506126a6565b818054612625906141f0565b80601f0160208091040260200160405190810160405280929190818152602001828054612651906141f0565b801561269e5780601f106126735761010080835404028352916020019161269e565b820191906000526020600020905b81548152906001019060200180831161268157829003601f168201915b505050505090505b92915050565b600080600060418451036126f15760008060006020870151925060408701519150606087015160001a90506126e388828585612948565b955095509550505050612701565b60006002855160001b9250925092505b9250925092565b6000600381111561271c5761271b614221565b5b82600381111561272f5761272e614221565b5b0315612868576001600381111561274957612748614221565b5b82600381111561275c5761275b614221565b5b03612793576040517ff645eedf00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600260038111156127a7576127a6614221565b5b8260038111156127ba576127b9614221565b5b036127ff578060001c6040517ffce698f70000000000000000000000000000000000000000000000000000000081526004016127f69190614250565b60405180910390fd5b60038081111561281257612811614221565b5b82600381111561282557612824614221565b5b0361286757806040517fd78bce0c00000000000000000000000000000000000000000000000000000000815260040161285e9190612b0a565b60405180910390fd5b5b5050565b6000807f80ad7e1b04ee6d994a125f4714ca0720908bd80ed16063ec8aee4b88e9253e2d83600001518460200151805190602001206040516020016128b39392919061426b565b60405160208183030381529060405290508080519060200120915050919050565b606060006128e183612a3c565b90506000602067ffffffffffffffff811115612900576128ff613488565b5b6040519080825280601f01601f1916602001820160405280156129325781602001600182028036833780820191505090505b5090508181528360208201528092505050919050565b60008060007f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08460001c1115612988576000600385925092509250612a32565b6000600188888888604051600081526020016040526040516129ad94939291906142be565b6020604051602081039080840390855afa1580156129cf573d6000803e3d6000fd5b505050602060405103519050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603612a2357600060016000801b93509350935050612a32565b8060008060001b935093509350505b9450945094915050565b60008060ff8360001c169050601f811115612a83576040517fb3512b0c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80915050919050565b6040518060c00160405280600073ffffffffffffffffffffffffffffffffffffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff168152602001600080191681526020016060815260200160008152602001606081525090565b6000819050919050565b612b0481612af1565b82525050565b6000602082019050612b1f6000830184612afb565b92915050565b6000604051905090565b600080fd5b600080fd5b612b4281612af1565b8114612b4d57600080fd5b50565b600081359050612b5f81612b39565b92915050565b600060208284031215612b7b57612b7a612b2f565b5b6000612b8984828501612b50565b91505092915050565b60008115159050919050565b612ba781612b92565b82525050565b6000602082019050612bc26000830184612b9e565b92915050565b600080fd5b600060c08284031215612be357612be2612bc8565b5b81905092915050565b600060208284031215612c0257612c01612b2f565b5b600082013567ffffffffffffffff811115612c2057612c1f612b34565b5b612c2c84828501612bcd565b91505092915050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000612c6082612c35565b9050919050565b612c7081612c55565b82525050565b6000602082019050612c8b6000830184612c67565b92915050565b60007fff0000000000000000000000000000000000000000000000000000000000000082169050919050565b612cc681612c91565b82525050565b600081519050919050565b600082825260208201905092915050565b60005b83811015612d06578082015181840152602081019050612ceb565b60008484015250505050565b6000601f19601f8301169050919050565b6000612d2e82612ccc565b612d388185612cd7565b9350612d48818560208601612ce8565b612d5181612d12565b840191505092915050565b6000819050919050565b612d6f81612d5c565b82525050565b600081519050919050565b600082825260208201905092915050565b6000819050602082019050919050565b612daa81612d5c565b82525050565b6000612dbc8383612da1565b60208301905092915050565b6000602082019050919050565b6000612de082612d75565b612dea8185612d80565b9350612df583612d91565b8060005b83811015612e26578151612e0d8882612db0565b9750612e1883612dc8565b925050600181019050612df9565b5085935050505092915050565b600060e082019050612e48600083018a612cbd565b8181036020830152612e5a8189612d23565b90508181036040830152612e6e8188612d23565b9050612e7d6060830187612d66565b612e8a6080830186612c67565b612e9760a0830185612afb565b81810360c0830152612ea98184612dd5565b905098975050505050505050565b60006020820190508181036000830152612ed18184612d23565b905092915050565b600080fd5b600080fd5b600080fd5b60008083601f840112612efe57612efd612ed9565b5b8235905067ffffffffffffffff811115612f1b57612f1a612ede565b5b602083019150836020820283011115612f3757612f36612ee3565b5b9250929050565b60008083601f840112612f5457612f53612ed9565b5b8235905067ffffffffffffffff811115612f7157612f70612ede565b5b602083019150836020820283011115612f8d57612f8c612ee3565b5b9250929050565b60008060008060008060608789031215612fb157612fb0612b2f565b5b600087013567ffffffffffffffff811115612fcf57612fce612b34565b5b612fdb89828a01612ee8565b9650965050602087013567ffffffffffffffff811115612ffe57612ffd612b34565b5b61300a89828a01612f3e565b9450945050604087013567ffffffffffffffff81111561302d5761302c612b34565b5b61303989828a01612ee8565b92509250509295509295509295565b61305181612c55565b811461305c57600080fd5b50565b60008135905061306e81613048565b92915050565b60006020828403121561308a57613089612b2f565b5b60006130988482850161305f565b91505092915050565b60006130b0602084018461305f565b905092915050565b6130c181612c55565b82525050565b60006130d66020840184612b50565b905092915050565b6130e781612af1565b82525050565b600080fd5b600080fd5b600080fd5b60008083356001602003843603038112613119576131186130f7565b5b83810192508235915060208301925067ffffffffffffffff821115613141576131406130ed565b5b602082023603831315613157576131566130f2565b5b509250929050565b600082825260208201905092915050565b6000819050919050565b60008083356001602003843603038112613197576131966130f7565b5b83810192508235915060208301925067ffffffffffffffff8211156131bf576131be6130ed565b5b6001820236038313156131d5576131d46130f2565b5b509250929050565b600082825260208201905092915050565b82818337600083830152505050565b600061320983856131dd565b93506132168385846131ee565b61321f83612d12565b840190509392505050565b60006060830161323d60008401846130a1565b61324a60008601826130b8565b50613258602084018461317a565b858303602087015261326b8382846131fd565b9250505061327c604084018461317a565b858303604087015261328f8382846131fd565b925050508091505092915050565b60006132a9838361322a565b905092915050565b6000823560016060038336030381126132cd576132cc6130f7565b5b82810191505092915050565b6000602082019050919050565b60006132f2838561315f565b93508360208402850161330484613170565b8060005b8781101561334857848403895261331f82846132b1565b613329858261329d565b9450613334836132d9565b925060208a01995050600181019050613308565b50829750879450505050509392505050565b61336381612d5c565b811461336e57600080fd5b50565b6000813590506133808161335a565b92915050565b60006133956020840184613371565b905092915050565b600060c083016133b060008401846130a1565b6133bd60008601826130b8565b506133cb60208401846130a1565b6133d860208601826130b8565b506133e660408401846130c7565b6133f360408601826130de565b5061340160608401846130fc565b85830360608701526134148382846132e6565b925050506134256080840184613386565b6134326080860182612da1565b5061344060a084018461317a565b85830360a08701526134538382846131fd565b925050508091505092915050565b6000602082019050818103600083015261347b818461339d565b905092915050565b600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6134c082612d12565b810181811067ffffffffffffffff821117156134df576134de613488565b5b80604052505050565b60006134f2612b25565b90506134fe82826134b7565b919050565b600080fd5b600067ffffffffffffffff82111561352357613522613488565b5b602082029050602081019050919050565b600080fd5b600067ffffffffffffffff82111561355457613553613488565b5b61355d82612d12565b9050602081019050919050565b600061357d61357884613539565b6134e8565b90508281526020810184848401111561359957613598613534565b5b6135a48482856131ee565b509392505050565b600082601f8301126135c1576135c0612ed9565b5b81356135d184826020860161356a565b91505092915050565b6000606082840312156135f0576135ef613483565b5b6135fa60606134e8565b9050600061360a8482850161305f565b600083015250602082013567ffffffffffffffff81111561362e5761362d613503565b5b61363a848285016135ac565b602083015250604082013567ffffffffffffffff81111561365e5761365d613503565b5b61366a848285016135ac565b60408301525092915050565b600061368961368484613508565b6134e8565b905080838252602082019050602084028301858111156136ac576136ab612ee3565b5b835b818110156136f357803567ffffffffffffffff8111156136d1576136d0612ed9565b5b8086016136de89826135da565b855260208501945050506020810190506136ae565b5050509392505050565b600082601f83011261371257613711612ed9565b5b8135613722848260208601613676565b91505092915050565b600060c0828403121561374157613740613483565b5b61374b60c06134e8565b9050600061375b8482850161305f565b600083015250602061376f8482850161305f565b602083015250604061378384828501612b50565b604083015250606082013567ffffffffffffffff8111156137a7576137a6613503565b5b6137b3848285016136fd565b60608301525060806137c784828501613371565b60808301525060a082013567ffffffffffffffff8111156137eb576137ea613503565b5b6137f7848285016135ac565b60a08301525092915050565b600061380f368361372b565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600080fd5b600080fd5b600080fd5b6000808335600160200384360303811261387157613870613845565b5b80840192508235915067ffffffffffffffff8211156138935761389261384a565b5b6020830192506001820236038313156138af576138ae61384f565b5b509250929050565b600067ffffffffffffffff8211156138d2576138d1613488565b5b602082029050602081019050919050565b60006138f66138f1846138b7565b6134e8565b9050808382526020820190506020840283018581111561391957613918612ee3565b5b835b8181101561396057803567ffffffffffffffff81111561393e5761393d612ed9565b5b80860161394b898261372b565b8552602085019450505060208101905061391b565b5050509392505050565b600082601f83011261397f5761397e612ed9565b5b813561398f8482602086016138e3565b91505092915050565b6000602082840312156139ae576139ad612b2f565b5b600082013567ffffffffffffffff8111156139cc576139cb612b34565b5b6139d88482850161396a565b91505092915050565b600081519050919050565b600082825260208201905092915050565b6000613a08826139e1565b613a1281856139ec565b9350613a22818560208601612ce8565b613a2b81612d12565b840191505092915050565b6000604082019050613a4b6000830185612afb565b8181036020830152613a5d81846139fd565b90509392505050565b60007fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b613a9b81613a66565b8114613aa657600080fd5b50565b600081519050613ab881613a92565b92915050565b600060208284031215613ad457613ad3612b2f565b5b6000613ae284828501613aa9565b91505092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000613b2582612d5c565b9150613b3083612d5c565b9250828203905081811115613b4857613b47613aeb565b5b92915050565b6000613b5982612d5c565b9150613b6483612d5c565b9250828201905080821115613b7c57613b7b613aeb565b5b92915050565b6000613b8d82612af1565b9050919050565b613b9d81613b82565b82525050565b6000613baf83856139ec565b9350613bbc8385846131ee565b613bc583612d12565b840190509392505050565b600060e0820190508181036000830152613bea818b6139fd565b90508181036020830152613bfe818a6139fd565b9050613c0d6040830189613b94565b8181036060830152613c20818789613ba3565b9050613c2f6080830186612afb565b613c3c60a0830185612c67565b613c4960c0830184612c67565b9998505050505050505050565b6000604082019050613c6b6000830186613b94565b8181036020830152613c7e818486613ba3565b9050949350505050565b600067ffffffffffffffff821115613ca357613ca2613488565b5b602082029050602081019050919050565b6000613cc7613cc284613539565b6134e8565b905082815260208101848484011115613ce357613ce2613534565b5b613cee848285612ce8565b509392505050565b600082601f830112613d0b57613d0a612ed9565b5b8151613d1b848260208601613cb4565b91505092915050565b6000613d37613d3284613c88565b6134e8565b90508083825260208201905060208402830185811115613d5a57613d59612ee3565b5b835b81811015613da157805167ffffffffffffffff811115613d7f57613d7e612ed9565b5b808601613d8c8982613cf6565b85526020850194505050602081019050613d5c565b5050509392505050565b600082601f830112613dc057613dbf612ed9565b5b8151613dd0848260208601613d24565b91505092915050565b600060208284031215613def57613dee612b2f565b5b600082015167ffffffffffffffff811115613e0d57613e0c612b34565b5b613e1984828501613dab565b91505092915050565b6000613e2d82612d5c565b915060008203613e4057613e3f613aeb565b5b600182039050919050565b600081519050919050565b6000819050602082019050919050565b6000613e71826139e1565b613e7b81856131dd565b9350613e8b818560208601612ce8565b613e9481612d12565b840191505092915050565b6000606083016000830151613eb760008601826130b8565b5060208301518482036020860152613ecf8282613e66565b91505060408301518482036040860152613ee98282613e66565b9150508091505092915050565b6000613f028383613e9f565b905092915050565b6000602082019050919050565b6000613f2282613e4b565b613f2c818561315f565b935083602082028501613f3e85613e56565b8060005b85811015613f7a5784840389528151613f5b8582613ef6565b9450613f6683613f0a565b925060208a01995050600181019050613f42565b50829750879550505050505092915050565b600060c083016000830151613fa460008601826130b8565b506020830151613fb760208601826130b8565b506040830151613fca60408601826130de565b5060608301518482036060860152613fe28282613f17565b9150506080830151613ff76080860182612da1565b5060a083015184820360a086015261400f8282613e66565b9150508091505092915050565b600060208201905081810360008301526140368184613f8c565b905092915050565b600060c0820190506140536000830189612afb565b6140606020830188612c67565b61406d6040830187612c67565b61407a6060830186612afb565b6140876080830185612afb565b61409460a0830184612d66565b979650505050505050565b600081519050919050565b600081905092915050565b6000819050602082019050919050565b6140ce81612af1565b82525050565b60006140e083836140c5565b60208301905092915050565b6000602082019050919050565b60006141048261409f565b61410e81856140aa565b9350614119836140b5565b8060005b8381101561414a57815161413188826140d4565b975061413c836140ec565b92505060018101905061411d565b5085935050505092915050565b600061416382846140f9565b915081905092915050565b600060a0820190506141836000830188612afb565b6141906020830187612afb565b61419d6040830186612afb565b6141aa6060830185612d66565b6141b76080830184612c67565b9695505050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b6000600282049050600182168061420857607f821691505b60208210810361421b5761421a6141c1565b5b50919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b60006020820190506142656000830184612d66565b92915050565b60006060820190506142806000830186612afb565b61428d6020830185612c67565b61429a6040830184612afb565b949350505050565b600060ff82169050919050565b6142b8816142a2565b82525050565b60006080820190506142d36000830187612afb565b6142e060208301866142af565b6142ed6040830185612afb565b6142fa6060830184612afb565b9594505050505056fea26469706673582212205871db72351a516eb48063d38edefa8dca6451c54af96066cc36b7a433d5af5b64736f6c6343000817003300000000000000000000000070997970c51812dc3a010c7d01b50e0d17dc79c8", + "output": "0x608060405234801561001057600080fd5b506004361061012c5760003560e01c806383ebb771116100ad578063acb8cc4911610071578063acb8cc49146102c9578063cef6d209146102e7578063e30c397814610303578063f2fde38b14610321578063ffa1ad741461033d5761012c565b806383ebb771146102415780638456cb591461025f57806384b0196e146102695780638da5cb5b1461028d578063a3f4df7e146102ab5761012c565b806358909ebc116100f457806358909ebc146101c15780635c975abb146101df57806366134607146101fd578063715018a61461022d57806379ba5097146102375761012c565b80631b13cac2146101315780632d40d0521461014f5780633ed010151461017f5780633f4ba83a1461019b57806349934047146101a5575b600080fd5b61013961035b565b6040516101469190612b0a565b60405180910390f35b61016960048036038101906101649190612b65565b610382565b6040516101769190612bad565b60405180910390f35b61019960048036038101906101949190612bec565b6103a2565b005b6101a3610539565b005b6101bf60048036038101906101ba9190612bec565b61054b565b005b6101c96106e2565b6040516101d69190612c76565b60405180910390f35b6101e76106e8565b6040516101f49190612bad565b60405180910390f35b61021760048036038101906102129190612bec565b6106ff565b6040516102249190612b0a565b60405180910390f35b61023561071a565b005b61023f61072e565b005b6102496107bd565b6040516102569190612b0a565b60405180910390f35b6102676107cc565b005b6102716107de565b6040516102849796959493929190612e33565b60405180910390f35b610295610888565b6040516102a29190612c76565b60405180910390f35b6102b36108b1565b6040516102c09190612eb7565b60405180910390f35b6102d16108ea565b6040516102de9190612eb7565b60405180910390f35b61030160048036038101906102fc9190612f94565b610923565b005b61030b611e9f565b6040516103189190612c76565b60405180910390f35b61033b60048036038101906103369190613074565b611ec9565b005b610345611f76565b6040516103529190612eb7565b60405180910390f35b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60001b81565b60046020528060005260406000206000915054906101000a900460ff1681565b8060200160208101906103b59190613074565b3373ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161461041a576040517fb9f0f17100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000610425836106ff565b90506004600082815260200190815260200160002060009054906101000a900460ff1661047e576040517ff2a5f75a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006004600083815260200190815260200160002060006101000a81548160ff0219169083151502179055508260000160208101906104bd9190613074565b73ffffffffffffffffffffffffffffffffffffffff168360200160208101906104e69190613074565b73ffffffffffffffffffffffffffffffffffffffff16827f3feadce88fc1b49db633a56fd5307ed6ee18734df83bcc4011daa720c9cd95f18660405161052c9190613461565b60405180910390a4505050565b610541611faf565b610549612036565b565b80602001602081019061055e9190613074565b3373ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16146105c3576040517fb9f0f17100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006105ce836106ff565b90506004600082815260200190815260200160002060009054906101000a900460ff1615610627576040517e5ecddb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60016004600083815260200190815260200160002060006101000a81548160ff0219169083151502179055508260000160208101906106669190613074565b73ffffffffffffffffffffffffffffffffffffffff1683602001602081019061068f9190613074565b73ffffffffffffffffffffffffffffffffffffffff16827fea589ba9473ee1fe77d352c7ed919747715a5d22931b972de9b02a907c66d5dd866040516106d59190613461565b60405180910390a4505050565b610a1181565b6000600160149054906101000a900460ff16905090565b60006107138261070e90613803565b612099565b9050919050565b610722611faf565b61072c6000612114565b565b6000610738612145565b90508073ffffffffffffffffffffffffffffffffffffffff16610759611e9f565b73ffffffffffffffffffffffffffffffffffffffff16146107b157806040517f118cdaa70000000000000000000000000000000000000000000000000000000081526004016107a89190612c76565b60405180910390fd5b6107ba81612114565b50565b60006107c761214d565b905090565b6107d4611faf565b6107dc612204565b565b6000606080600080600060606107f2612266565b6107fa6122a1565b46306000801b600067ffffffffffffffff81111561081b5761081a613488565b5b6040519080825280602002602001820160405280156108495781602001602082028036833780820191505090505b507f0f00000000000000000000000000000000000000000000000000000000000000959493929190965096509650965096509650965090919293949596565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b6040518060400160405280601181526020017f44656c65676174696f6e4d616e6167657200000000000000000000000000000081525081565b6040518060400160405280600181526020017f310000000000000000000000000000000000000000000000000000000000000081525081565b61092b6122dc565b600086869050905082829050811415806109485750848490508114155b1561097f576040517f1bcaf69f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008167ffffffffffffffff81111561099b5761099a613488565b5b6040519080825280602002602001820160405280156109ce57816020015b60608152602001906001900390816109b95790505b50905060008267ffffffffffffffff8111156109ed576109ec613488565b5b604051908082528060200260200182016040528015610a2057816020015b6060815260200190600190039081610a0b5790505b50905060005b838110156111b65760008a8a83818110610a4357610a42613816565b5b9050602002810190610a559190613854565b810190610a629190613998565b90506000815103610b4d57600067ffffffffffffffff811115610a8857610a87613488565b5b604051908082528060200260200182016040528015610ac157816020015b610aae612a8c565b815260200190600190039081610aa65790505b50848381518110610ad557610ad4613816565b5b6020026020010181905250600067ffffffffffffffff811115610afb57610afa613488565b5b604051908082528060200260200182016040528015610b295781602001602082028036833780820191505090505b50838381518110610b3d57610b3c613816565b5b60200260200101819052506111aa565b80848381518110610b6157610b60613816565b5b60200260200101819052506000815167ffffffffffffffff811115610b8957610b88613488565b5b604051908082528060200260200182016040528015610bb75781602001602082028036833780820191505090505b50905080848481518110610bce57610bcd613816565b5b60200260200101819052503373ffffffffffffffffffffffffffffffffffffffff1682600081518110610c0457610c03613816565b5b60200260200101516000015173ffffffffffffffffffffffffffffffffffffffff1614158015610c815750610a1173ffffffffffffffffffffffffffffffffffffffff1682600081518110610c5c57610c5b613816565b5b60200260200101516000015173ffffffffffffffffffffffffffffffffffffffff1614155b15610cb8576040517fb586360400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b8251811015610f1d576000838281518110610cd957610cd8613816565b5b60200260200101519050610cec81612099565b838381518110610cff57610cfe613816565b5b6020026020010181815250506000816020015173ffffffffffffffffffffffffffffffffffffffff163b03610dd9576000610d68610d5e610d3e6107bd565b868681518110610d5157610d50613816565b5b602002602001015161231d565b8360a0015161235e565b9050816020015173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614610dd3576040517f3db6791c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50610f11565b6000610e06610de66107bd565b858581518110610df957610df8613816565b5b602002602001015161231d565b90506000826020015173ffffffffffffffffffffffffffffffffffffffff16631626ba7e838560a001516040518363ffffffff1660e01b8152600401610e4d929190613a36565b602060405180830381865afa158015610e6a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e8e9190613abe565b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19169050631626ba7e60e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19168114610f0e576040517f155ff42700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50505b50806001019050610cbb565b5060005b82518110156111a75760046000838381518110610f4157610f40613816565b5b6020026020010151815260200190815260200160002060009054906101000a900460ff1615610f9c576040517f05baa05200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60018351610faa9190613b1a565b81146111215781600182610fbe9190613b4e565b81518110610fcf57610fce613816565b5b6020026020010151838281518110610fea57610fe9613816565b5b6020026020010151604001511461102d576040517fded4370e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008360018361103d9190613b4e565b8151811061104e5761104d613816565b5b6020026020010151600001519050610a1173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16141580156110e457508073ffffffffffffffffffffffffffffffffffffffff168483815181106110bf576110be613816565b5b60200260200101516020015173ffffffffffffffffffffffffffffffffffffffff1614155b1561111b576040517fb586360400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5061119c565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60001b83828151811061115857611157613816565b5b6020026020010151604001511461119b576040517fded4370e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5b806001019050610f21565b50505b50806001019050610a26565b5060005b838110156113fb5760008382815181106111d7576111d6613816565b5b60200260200101515111156113f05760005b8382815181106111fc576111fb613816565b5b6020026020010151518110156113ee57600084838151811061122157611220613816565b5b6020026020010151828151811061123b5761123a613816565b5b602002602001015160600151905060005b81518110156113e157600082828151811061126a57611269613816565b5b60200260200101516000015190508073ffffffffffffffffffffffffffffffffffffffff1663414c3e338484815181106112a7576112a6613816565b5b6020026020010151602001518585815181106112c6576112c5613816565b5b6020026020010151604001518f8f8a8181106112e5576112e4613816565b5b905060200201358e8e8b8181106112ff576112fe613816565b5b90506020028101906113119190613854565b8c8c8151811061132457611323613816565b5b60200260200101518b8151811061133e5761133d613816565b5b60200260200101518e8d8151811061135957611358613816565b5b60200260200101518c8151811061137357611372613816565b5b602002602001015160200151336040518963ffffffff1660e01b81526004016113a3989796959493929190613bd0565b600060405180830381600087803b1580156113bd57600080fd5b505af11580156113d1573d6000803e3d6000fd5b505050505080600101905061124c565b50508060010190506111e9565b505b8060010190506111ba565b5060005b83811015611a8c57600083828151811061141c5761141b613816565b5b602002602001015151036114f1573373ffffffffffffffffffffffffffffffffffffffff1663d691c96489898481811061145957611458613816565b5b9050602002013588888581811061147357611472613816565b5b90506020028101906114859190613854565b6040518463ffffffff1660e01b81526004016114a393929190613c56565b6000604051808303816000875af11580156114c2573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f820116820180604052508101906114eb9190613dd9565b50611a81565b60005b83828151811061150757611506613816565b5b6020026020010151518110156116f957600084838151811061152c5761152b613816565b5b6020026020010151828151811061154657611545613816565b5b602002602001015160600151905060005b81518110156116ec57600082828151811061157557611574613816565b5b60200260200101516000015190508073ffffffffffffffffffffffffffffffffffffffff1663a145832a8484815181106115b2576115b1613816565b5b6020026020010151602001518585815181106115d1576115d0613816565b5b6020026020010151604001518f8f8a8181106115f0576115ef613816565b5b905060200201358e8e8b81811061160a57611609613816565b5b905060200281019061161c9190613854565b8c8c8151811061162f5761162e613816565b5b60200260200101518b8151811061164957611648613816565b5b60200260200101518e8d8151811061166457611663613816565b5b60200260200101518c8151811061167e5761167d613816565b5b602002602001015160200151336040518963ffffffff1660e01b81526004016116ae989796959493929190613bd0565b600060405180830381600087803b1580156116c857600080fd5b505af11580156116dc573d6000803e3d6000fd5b5050505050806001019050611557565b50508060010190506114f4565b5082818151811061170d5761170c613816565b5b6020026020010151600184838151811061172a57611729613816565b5b60200260200101515161173d9190613b1a565b8151811061174e5761174d613816565b5b60200260200101516020015173ffffffffffffffffffffffffffffffffffffffff1663d691c96489898481811061178857611787613816565b5b905060200201358888858181106117a2576117a1613816565b5b90506020028101906117b49190613854565b6040518463ffffffff1660e01b81526004016117d293929190613c56565b6000604051808303816000875af11580156117f1573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f8201168201806040525081019061181a9190613dd9565b5060008382815181106118305761182f613816565b5b60200260200101515190505b6000811115611a7f57600084838151811061185a57611859613816565b5b602002602001015160018361186f9190613b1a565b815181106118805761187f613816565b5b60200260200101516060015190506000815190505b6000811115611a6c576000826001836118ae9190613b1a565b815181106118bf576118be613816565b5b60200260200101516000015190508073ffffffffffffffffffffffffffffffffffffffff1663d3eddcc5846001856118f79190613b1a565b8151811061190857611907613816565b5b602002602001015160200151856001866119229190613b1a565b8151811061193357611932613816565b5b6020026020010151604001518f8f8a81811061195257611951613816565b5b905060200201358e8e8b81811061196c5761196b613816565b5b905060200281019061197e9190613854565b8c8c8151811061199157611990613816565b5b602002602001015160018c6119a69190613b1a565b815181106119b7576119b6613816565b5b60200260200101518e8d815181106119d2576119d1613816565b5b602002602001015160018d6119e79190613b1a565b815181106119f8576119f7613816565b5b602002602001015160200151336040518963ffffffff1660e01b8152600401611a28989796959493929190613bd0565b600060405180830381600087803b158015611a4257600080fd5b505af1158015611a56573d6000803e3d6000fd5b505050505080611a6590613e22565b9050611895565b505080611a7890613e22565b905061183c565b505b8060010190506113ff565b5060005b83811015611d2d576000838281518110611aad57611aac613816565b5b6020026020010151511115611d22576000838281518110611ad157611ad0613816565b5b60200260200101515190505b6000811115611d20576000848381518110611afb57611afa613816565b5b6020026020010151600183611b109190613b1a565b81518110611b2157611b20613816565b5b60200260200101516060015190506000815190505b6000811115611d0d57600082600183611b4f9190613b1a565b81518110611b6057611b5f613816565b5b60200260200101516000015190508073ffffffffffffffffffffffffffffffffffffffff1663ed46336784600185611b989190613b1a565b81518110611ba957611ba8613816565b5b60200260200101516020015185600186611bc39190613b1a565b81518110611bd457611bd3613816565b5b6020026020010151604001518f8f8a818110611bf357611bf2613816565b5b905060200201358e8e8b818110611c0d57611c0c613816565b5b9050602002810190611c1f9190613854565b8c8c81518110611c3257611c31613816565b5b602002602001015160018c611c479190613b1a565b81518110611c5857611c57613816565b5b60200260200101518e8d81518110611c7357611c72613816565b5b602002602001015160018d611c889190613b1a565b81518110611c9957611c98613816565b5b602002602001015160200151336040518963ffffffff1660e01b8152600401611cc9989796959493929190613bd0565b600060405180830381600087803b158015611ce357600080fd5b505af1158015611cf7573d6000803e3d6000fd5b505050505080611d0690613e22565b9050611b36565b505080611d1990613e22565b9050611add565b505b806001019050611a90565b5060005b83811015611e93576000838281518110611d4e57611d4d613816565b5b6020026020010151511115611e885760005b838281518110611d7357611d72613816565b5b602002602001015151811015611e86573373ffffffffffffffffffffffffffffffffffffffff16848381518110611dad57611dac613816565b5b60200260200101516001868581518110611dca57611dc9613816565b5b602002602001015151611ddd9190613b1a565b81518110611dee57611ded613816565b5b60200260200101516020015173ffffffffffffffffffffffffffffffffffffffff167f40dadaa36c6c2e3d7317e24757451ffb2d603d875f0ad5e92c5dd156573b1873868581518110611e4457611e43613816565b5b60200260200101518481518110611e5e57611e5d613816565b5b6020026020010151604051611e73919061401c565b60405180910390a3806001019050611d60565b505b806001019050611d31565b50505050505050505050565b6000600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b611ed1611faf565b80600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508073ffffffffffffffffffffffffffffffffffffffff16611f31610888565b73ffffffffffffffffffffffffffffffffffffffff167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b6040518060400160405280600581526020017f312e332e3000000000000000000000000000000000000000000000000000000081525081565b611fb7612145565b73ffffffffffffffffffffffffffffffffffffffff16611fd5610888565b73ffffffffffffffffffffffffffffffffffffffff161461203457611ff8612145565b6040517f118cdaa700000000000000000000000000000000000000000000000000000000815260040161202b9190612c76565b60405180910390fd5b565b61203e61238a565b6000600160146101000a81548160ff0219169083151502179055507f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa612082612145565b60405161208f9190612c76565b60405180910390a1565b6000807f88c1d2ecf185adf710588203a5f263f0ff61be0d33da39792cde19ba9aa4331e8360000151846020015185604001516120d987606001516123ca565b87608001516040516020016120f39695949392919061403e565b60405160208183030381529060405290508080519060200120915050919050565b600160006101000a81549073ffffffffffffffffffffffffffffffffffffffff0219169055612142816124a2565b50565b600033905090565b60007f000000000000000000000000663f3ad617193148711d28f5334ee4ed0701660273ffffffffffffffffffffffffffffffffffffffff163073ffffffffffffffffffffffffffffffffffffffff161480156121c957507f000000000000000000000000000000000000000000000000000000000000053946145b156121f6577f8cdadf61c3a91a26e93fd395df1ff97693afe59cddc459306faa96608f5933d99050612201565b6121fe612566565b90505b90565b61220c6122dc565b60018060146101000a81548160ff0219169083151502179055507f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a25861224f612145565b60405161225c9190612c76565b60405180910390a1565b606061229c60027f44656c65676174696f6e4d616e616765720000000000000000000000000000116125fc90919063ffffffff16565b905090565b60606122d760037f31000000000000000000000000000000000000000000000000000000000000016125fc90919063ffffffff16565b905090565b6122e46106e8565b1561231b576040517fd93c066500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b565b60006040517f190100000000000000000000000000000000000000000000000000000000000081528360028201528260228201526042812091505092915050565b60008060008061236e86866126ac565b92509250925061237e8282612708565b82935050505092915050565b6123926106e8565b6123c8576040517f8dfc202b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b565b600080825167ffffffffffffffff8111156123e8576123e7613488565b5b6040519080825280602002602001820160405280156124165781602001602082028036833780820191505090505b50905060005b83518110156124725761244884828151811061243b5761243a613816565b5b602002602001015161286c565b82828151811061245b5761245a613816565b5b60200260200101818152505080600101905061241c565b50806040516020016124849190614157565b60405160208183030381529060405280519060200120915050919050565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050816000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a35050565b60007f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f7f604240e1ed005b9ba256cb7011059bf4ae645812b834bbcb5b22c93e2d1185cc7fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc646306040516020016125e195949392919061416e565b60405160208183030381529060405280519060200120905090565b606060ff60001b831461261957612612836128d4565b90506126a6565b818054612625906141f0565b80601f0160208091040260200160405190810160405280929190818152602001828054612651906141f0565b801561269e5780601f106126735761010080835404028352916020019161269e565b820191906000526020600020905b81548152906001019060200180831161268157829003601f168201915b505050505090505b92915050565b600080600060418451036126f15760008060006020870151925060408701519150606087015160001a90506126e388828585612948565b955095509550505050612701565b60006002855160001b9250925092505b9250925092565b6000600381111561271c5761271b614221565b5b82600381111561272f5761272e614221565b5b0315612868576001600381111561274957612748614221565b5b82600381111561275c5761275b614221565b5b03612793576040517ff645eedf00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600260038111156127a7576127a6614221565b5b8260038111156127ba576127b9614221565b5b036127ff578060001c6040517ffce698f70000000000000000000000000000000000000000000000000000000081526004016127f69190614250565b60405180910390fd5b60038081111561281257612811614221565b5b82600381111561282557612824614221565b5b0361286757806040517fd78bce0c00000000000000000000000000000000000000000000000000000000815260040161285e9190612b0a565b60405180910390fd5b5b5050565b6000807f80ad7e1b04ee6d994a125f4714ca0720908bd80ed16063ec8aee4b88e9253e2d83600001518460200151805190602001206040516020016128b39392919061426b565b60405160208183030381529060405290508080519060200120915050919050565b606060006128e183612a3c565b90506000602067ffffffffffffffff811115612900576128ff613488565b5b6040519080825280601f01601f1916602001820160405280156129325781602001600182028036833780820191505090505b5090508181528360208201528092505050919050565b60008060007f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08460001c1115612988576000600385925092509250612a32565b6000600188888888604051600081526020016040526040516129ad94939291906142be565b6020604051602081039080840390855afa1580156129cf573d6000803e3d6000fd5b505050602060405103519050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603612a2357600060016000801b93509350935050612a32565b8060008060001b935093509350505b9450945094915050565b60008060ff8360001c169050601f811115612a83576040517fb3512b0c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80915050919050565b6040518060c00160405280600073ffffffffffffffffffffffffffffffffffffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff168152602001600080191681526020016060815260200160008152602001606081525090565b6000819050919050565b612b0481612af1565b82525050565b6000602082019050612b1f6000830184612afb565b92915050565b6000604051905090565b600080fd5b600080fd5b612b4281612af1565b8114612b4d57600080fd5b50565b600081359050612b5f81612b39565b92915050565b600060208284031215612b7b57612b7a612b2f565b5b6000612b8984828501612b50565b91505092915050565b60008115159050919050565b612ba781612b92565b82525050565b6000602082019050612bc26000830184612b9e565b92915050565b600080fd5b600060c08284031215612be357612be2612bc8565b5b81905092915050565b600060208284031215612c0257612c01612b2f565b5b600082013567ffffffffffffffff811115612c2057612c1f612b34565b5b612c2c84828501612bcd565b91505092915050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000612c6082612c35565b9050919050565b612c7081612c55565b82525050565b6000602082019050612c8b6000830184612c67565b92915050565b60007fff0000000000000000000000000000000000000000000000000000000000000082169050919050565b612cc681612c91565b82525050565b600081519050919050565b600082825260208201905092915050565b60005b83811015612d06578082015181840152602081019050612ceb565b60008484015250505050565b6000601f19601f8301169050919050565b6000612d2e82612ccc565b612d388185612cd7565b9350612d48818560208601612ce8565b612d5181612d12565b840191505092915050565b6000819050919050565b612d6f81612d5c565b82525050565b600081519050919050565b600082825260208201905092915050565b6000819050602082019050919050565b612daa81612d5c565b82525050565b6000612dbc8383612da1565b60208301905092915050565b6000602082019050919050565b6000612de082612d75565b612dea8185612d80565b9350612df583612d91565b8060005b83811015612e26578151612e0d8882612db0565b9750612e1883612dc8565b925050600181019050612df9565b5085935050505092915050565b600060e082019050612e48600083018a612cbd565b8181036020830152612e5a8189612d23565b90508181036040830152612e6e8188612d23565b9050612e7d6060830187612d66565b612e8a6080830186612c67565b612e9760a0830185612afb565b81810360c0830152612ea98184612dd5565b905098975050505050505050565b60006020820190508181036000830152612ed18184612d23565b905092915050565b600080fd5b600080fd5b600080fd5b60008083601f840112612efe57612efd612ed9565b5b8235905067ffffffffffffffff811115612f1b57612f1a612ede565b5b602083019150836020820283011115612f3757612f36612ee3565b5b9250929050565b60008083601f840112612f5457612f53612ed9565b5b8235905067ffffffffffffffff811115612f7157612f70612ede565b5b602083019150836020820283011115612f8d57612f8c612ee3565b5b9250929050565b60008060008060008060608789031215612fb157612fb0612b2f565b5b600087013567ffffffffffffffff811115612fcf57612fce612b34565b5b612fdb89828a01612ee8565b9650965050602087013567ffffffffffffffff811115612ffe57612ffd612b34565b5b61300a89828a01612f3e565b9450945050604087013567ffffffffffffffff81111561302d5761302c612b34565b5b61303989828a01612ee8565b92509250509295509295509295565b61305181612c55565b811461305c57600080fd5b50565b60008135905061306e81613048565b92915050565b60006020828403121561308a57613089612b2f565b5b60006130988482850161305f565b91505092915050565b60006130b0602084018461305f565b905092915050565b6130c181612c55565b82525050565b60006130d66020840184612b50565b905092915050565b6130e781612af1565b82525050565b600080fd5b600080fd5b600080fd5b60008083356001602003843603038112613119576131186130f7565b5b83810192508235915060208301925067ffffffffffffffff821115613141576131406130ed565b5b602082023603831315613157576131566130f2565b5b509250929050565b600082825260208201905092915050565b6000819050919050565b60008083356001602003843603038112613197576131966130f7565b5b83810192508235915060208301925067ffffffffffffffff8211156131bf576131be6130ed565b5b6001820236038313156131d5576131d46130f2565b5b509250929050565b600082825260208201905092915050565b82818337600083830152505050565b600061320983856131dd565b93506132168385846131ee565b61321f83612d12565b840190509392505050565b60006060830161323d60008401846130a1565b61324a60008601826130b8565b50613258602084018461317a565b858303602087015261326b8382846131fd565b9250505061327c604084018461317a565b858303604087015261328f8382846131fd565b925050508091505092915050565b60006132a9838361322a565b905092915050565b6000823560016060038336030381126132cd576132cc6130f7565b5b82810191505092915050565b6000602082019050919050565b60006132f2838561315f565b93508360208402850161330484613170565b8060005b8781101561334857848403895261331f82846132b1565b613329858261329d565b9450613334836132d9565b925060208a01995050600181019050613308565b50829750879450505050509392505050565b61336381612d5c565b811461336e57600080fd5b50565b6000813590506133808161335a565b92915050565b60006133956020840184613371565b905092915050565b600060c083016133b060008401846130a1565b6133bd60008601826130b8565b506133cb60208401846130a1565b6133d860208601826130b8565b506133e660408401846130c7565b6133f360408601826130de565b5061340160608401846130fc565b85830360608701526134148382846132e6565b925050506134256080840184613386565b6134326080860182612da1565b5061344060a084018461317a565b85830360a08701526134538382846131fd565b925050508091505092915050565b6000602082019050818103600083015261347b818461339d565b905092915050565b600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6134c082612d12565b810181811067ffffffffffffffff821117156134df576134de613488565b5b80604052505050565b60006134f2612b25565b90506134fe82826134b7565b919050565b600080fd5b600067ffffffffffffffff82111561352357613522613488565b5b602082029050602081019050919050565b600080fd5b600067ffffffffffffffff82111561355457613553613488565b5b61355d82612d12565b9050602081019050919050565b600061357d61357884613539565b6134e8565b90508281526020810184848401111561359957613598613534565b5b6135a48482856131ee565b509392505050565b600082601f8301126135c1576135c0612ed9565b5b81356135d184826020860161356a565b91505092915050565b6000606082840312156135f0576135ef613483565b5b6135fa60606134e8565b9050600061360a8482850161305f565b600083015250602082013567ffffffffffffffff81111561362e5761362d613503565b5b61363a848285016135ac565b602083015250604082013567ffffffffffffffff81111561365e5761365d613503565b5b61366a848285016135ac565b60408301525092915050565b600061368961368484613508565b6134e8565b905080838252602082019050602084028301858111156136ac576136ab612ee3565b5b835b818110156136f357803567ffffffffffffffff8111156136d1576136d0612ed9565b5b8086016136de89826135da565b855260208501945050506020810190506136ae565b5050509392505050565b600082601f83011261371257613711612ed9565b5b8135613722848260208601613676565b91505092915050565b600060c0828403121561374157613740613483565b5b61374b60c06134e8565b9050600061375b8482850161305f565b600083015250602061376f8482850161305f565b602083015250604061378384828501612b50565b604083015250606082013567ffffffffffffffff8111156137a7576137a6613503565b5b6137b3848285016136fd565b60608301525060806137c784828501613371565b60808301525060a082013567ffffffffffffffff8111156137eb576137ea613503565b5b6137f7848285016135ac565b60a08301525092915050565b600061380f368361372b565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600080fd5b600080fd5b600080fd5b6000808335600160200384360303811261387157613870613845565b5b80840192508235915067ffffffffffffffff8211156138935761389261384a565b5b6020830192506001820236038313156138af576138ae61384f565b5b509250929050565b600067ffffffffffffffff8211156138d2576138d1613488565b5b602082029050602081019050919050565b60006138f66138f1846138b7565b6134e8565b9050808382526020820190506020840283018581111561391957613918612ee3565b5b835b8181101561396057803567ffffffffffffffff81111561393e5761393d612ed9565b5b80860161394b898261372b565b8552602085019450505060208101905061391b565b5050509392505050565b600082601f83011261397f5761397e612ed9565b5b813561398f8482602086016138e3565b91505092915050565b6000602082840312156139ae576139ad612b2f565b5b600082013567ffffffffffffffff8111156139cc576139cb612b34565b5b6139d88482850161396a565b91505092915050565b600081519050919050565b600082825260208201905092915050565b6000613a08826139e1565b613a1281856139ec565b9350613a22818560208601612ce8565b613a2b81612d12565b840191505092915050565b6000604082019050613a4b6000830185612afb565b8181036020830152613a5d81846139fd565b90509392505050565b60007fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b613a9b81613a66565b8114613aa657600080fd5b50565b600081519050613ab881613a92565b92915050565b600060208284031215613ad457613ad3612b2f565b5b6000613ae284828501613aa9565b91505092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000613b2582612d5c565b9150613b3083612d5c565b9250828203905081811115613b4857613b47613aeb565b5b92915050565b6000613b5982612d5c565b9150613b6483612d5c565b9250828201905080821115613b7c57613b7b613aeb565b5b92915050565b6000613b8d82612af1565b9050919050565b613b9d81613b82565b82525050565b6000613baf83856139ec565b9350613bbc8385846131ee565b613bc583612d12565b840190509392505050565b600060e0820190508181036000830152613bea818b6139fd565b90508181036020830152613bfe818a6139fd565b9050613c0d6040830189613b94565b8181036060830152613c20818789613ba3565b9050613c2f6080830186612afb565b613c3c60a0830185612c67565b613c4960c0830184612c67565b9998505050505050505050565b6000604082019050613c6b6000830186613b94565b8181036020830152613c7e818486613ba3565b9050949350505050565b600067ffffffffffffffff821115613ca357613ca2613488565b5b602082029050602081019050919050565b6000613cc7613cc284613539565b6134e8565b905082815260208101848484011115613ce357613ce2613534565b5b613cee848285612ce8565b509392505050565b600082601f830112613d0b57613d0a612ed9565b5b8151613d1b848260208601613cb4565b91505092915050565b6000613d37613d3284613c88565b6134e8565b90508083825260208201905060208402830185811115613d5a57613d59612ee3565b5b835b81811015613da157805167ffffffffffffffff811115613d7f57613d7e612ed9565b5b808601613d8c8982613cf6565b85526020850194505050602081019050613d5c565b5050509392505050565b600082601f830112613dc057613dbf612ed9565b5b8151613dd0848260208601613d24565b91505092915050565b600060208284031215613def57613dee612b2f565b5b600082015167ffffffffffffffff811115613e0d57613e0c612b34565b5b613e1984828501613dab565b91505092915050565b6000613e2d82612d5c565b915060008203613e4057613e3f613aeb565b5b600182039050919050565b600081519050919050565b6000819050602082019050919050565b6000613e71826139e1565b613e7b81856131dd565b9350613e8b818560208601612ce8565b613e9481612d12565b840191505092915050565b6000606083016000830151613eb760008601826130b8565b5060208301518482036020860152613ecf8282613e66565b91505060408301518482036040860152613ee98282613e66565b9150508091505092915050565b6000613f028383613e9f565b905092915050565b6000602082019050919050565b6000613f2282613e4b565b613f2c818561315f565b935083602082028501613f3e85613e56565b8060005b85811015613f7a5784840389528151613f5b8582613ef6565b9450613f6683613f0a565b925060208a01995050600181019050613f42565b50829750879550505050505092915050565b600060c083016000830151613fa460008601826130b8565b506020830151613fb760208601826130b8565b506040830151613fca60408601826130de565b5060608301518482036060860152613fe28282613f17565b9150506080830151613ff76080860182612da1565b5060a083015184820360a086015261400f8282613e66565b9150508091505092915050565b600060208201905081810360008301526140368184613f8c565b905092915050565b600060c0820190506140536000830189612afb565b6140606020830188612c67565b61406d6040830187612c67565b61407a6060830186612afb565b6140876080830185612afb565b61409460a0830184612d66565b979650505050505050565b600081519050919050565b600081905092915050565b6000819050602082019050919050565b6140ce81612af1565b82525050565b60006140e083836140c5565b60208301905092915050565b6000602082019050919050565b60006141048261409f565b61410e81856140aa565b9350614119836140b5565b8060005b8381101561414a57815161413188826140d4565b975061413c836140ec565b92505060018101905061411d565b5085935050505092915050565b600061416382846140f9565b915081905092915050565b600060a0820190506141836000830188612afb565b6141906020830187612afb565b61419d6040830186612afb565b6141aa6060830185612d66565b6141b76080830184612c67565b9695505050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b6000600282049050600182168061420857607f821691505b60208210810361421b5761421a6141c1565b5b50919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b60006020820190506142656000830184612d66565b92915050565b60006060820190506142806000830186612afb565b61428d6020830185612c67565b61429a6040830184612afb565b949350505050565b600060ff82169050919050565b6142b8816142a2565b82525050565b60006080820190506142d36000830187612afb565b6142e060208301866142af565b6142ed6040830185612afb565b6142fa6060830184612afb565b9594505050505056fea26469706673582212205871db72351a516eb48063d38edefa8dca6451c54af96066cc36b7a433d5af5b64736f6c63430008170033", + "gas_used": 3479579, + "gas_limit": 3479579, + "status": "Return", + "steps": [], + "decoded": { + "label": null, + "return_data": null, + "call_data": null + } + }, + "logs": [ + { + "raw_log": { + "topics": [ + "0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x00000000000000000000000070997970c51812dc3a010c7d01b50e0d17dc79c8" + ], + "data": "0x" + }, + "decoded": { "name": null, "params": null }, + "position": 0 + }, + { + "raw_log": { + "topics": [ + "0x04a46d9007577c7ff1e513b900545162ec25d25991ae3dc60cf26ec01a84806d", + "0x8cdadf61c3a91a26e93fd395df1ff97693afe59cddc459306faa96608f5933d9", + "0x000000000000000000000000663f3ad617193148711d28f5334ee4ed07016602" + ], + "data": "0x000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000539000000000000000000000000000000000000000000000000000000000000001144656c65676174696f6e4d616e6167657200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000013100000000000000000000000000000000000000000000000000000000000000" + }, + "decoded": { "name": null, "params": null }, + "position": 0 + } + ], + "ordering": [{ "Log": 0 }, { "Log": 1 }] + } + ], + "exit": "Return", + "out": "0x608060405234801561001057600080fd5b506004361061012c5760003560e01c806383ebb771116100ad578063acb8cc4911610071578063acb8cc49146102c9578063cef6d209146102e7578063e30c397814610303578063f2fde38b14610321578063ffa1ad741461033d5761012c565b806383ebb771146102415780638456cb591461025f57806384b0196e146102695780638da5cb5b1461028d578063a3f4df7e146102ab5761012c565b806358909ebc116100f457806358909ebc146101c15780635c975abb146101df57806366134607146101fd578063715018a61461022d57806379ba5097146102375761012c565b80631b13cac2146101315780632d40d0521461014f5780633ed010151461017f5780633f4ba83a1461019b57806349934047146101a5575b600080fd5b61013961035b565b6040516101469190612b0a565b60405180910390f35b61016960048036038101906101649190612b65565b610382565b6040516101769190612bad565b60405180910390f35b61019960048036038101906101949190612bec565b6103a2565b005b6101a3610539565b005b6101bf60048036038101906101ba9190612bec565b61054b565b005b6101c96106e2565b6040516101d69190612c76565b60405180910390f35b6101e76106e8565b6040516101f49190612bad565b60405180910390f35b61021760048036038101906102129190612bec565b6106ff565b6040516102249190612b0a565b60405180910390f35b61023561071a565b005b61023f61072e565b005b6102496107bd565b6040516102569190612b0a565b60405180910390f35b6102676107cc565b005b6102716107de565b6040516102849796959493929190612e33565b60405180910390f35b610295610888565b6040516102a29190612c76565b60405180910390f35b6102b36108b1565b6040516102c09190612eb7565b60405180910390f35b6102d16108ea565b6040516102de9190612eb7565b60405180910390f35b61030160048036038101906102fc9190612f94565b610923565b005b61030b611e9f565b6040516103189190612c76565b60405180910390f35b61033b60048036038101906103369190613074565b611ec9565b005b610345611f76565b6040516103529190612eb7565b60405180910390f35b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60001b81565b60046020528060005260406000206000915054906101000a900460ff1681565b8060200160208101906103b59190613074565b3373ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161461041a576040517fb9f0f17100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000610425836106ff565b90506004600082815260200190815260200160002060009054906101000a900460ff1661047e576040517ff2a5f75a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006004600083815260200190815260200160002060006101000a81548160ff0219169083151502179055508260000160208101906104bd9190613074565b73ffffffffffffffffffffffffffffffffffffffff168360200160208101906104e69190613074565b73ffffffffffffffffffffffffffffffffffffffff16827f3feadce88fc1b49db633a56fd5307ed6ee18734df83bcc4011daa720c9cd95f18660405161052c9190613461565b60405180910390a4505050565b610541611faf565b610549612036565b565b80602001602081019061055e9190613074565b3373ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16146105c3576040517fb9f0f17100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006105ce836106ff565b90506004600082815260200190815260200160002060009054906101000a900460ff1615610627576040517e5ecddb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60016004600083815260200190815260200160002060006101000a81548160ff0219169083151502179055508260000160208101906106669190613074565b73ffffffffffffffffffffffffffffffffffffffff1683602001602081019061068f9190613074565b73ffffffffffffffffffffffffffffffffffffffff16827fea589ba9473ee1fe77d352c7ed919747715a5d22931b972de9b02a907c66d5dd866040516106d59190613461565b60405180910390a4505050565b610a1181565b6000600160149054906101000a900460ff16905090565b60006107138261070e90613803565b612099565b9050919050565b610722611faf565b61072c6000612114565b565b6000610738612145565b90508073ffffffffffffffffffffffffffffffffffffffff16610759611e9f565b73ffffffffffffffffffffffffffffffffffffffff16146107b157806040517f118cdaa70000000000000000000000000000000000000000000000000000000081526004016107a89190612c76565b60405180910390fd5b6107ba81612114565b50565b60006107c761214d565b905090565b6107d4611faf565b6107dc612204565b565b6000606080600080600060606107f2612266565b6107fa6122a1565b46306000801b600067ffffffffffffffff81111561081b5761081a613488565b5b6040519080825280602002602001820160405280156108495781602001602082028036833780820191505090505b507f0f00000000000000000000000000000000000000000000000000000000000000959493929190965096509650965096509650965090919293949596565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b6040518060400160405280601181526020017f44656c65676174696f6e4d616e6167657200000000000000000000000000000081525081565b6040518060400160405280600181526020017f310000000000000000000000000000000000000000000000000000000000000081525081565b61092b6122dc565b600086869050905082829050811415806109485750848490508114155b1561097f576040517f1bcaf69f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008167ffffffffffffffff81111561099b5761099a613488565b5b6040519080825280602002602001820160405280156109ce57816020015b60608152602001906001900390816109b95790505b50905060008267ffffffffffffffff8111156109ed576109ec613488565b5b604051908082528060200260200182016040528015610a2057816020015b6060815260200190600190039081610a0b5790505b50905060005b838110156111b65760008a8a83818110610a4357610a42613816565b5b9050602002810190610a559190613854565b810190610a629190613998565b90506000815103610b4d57600067ffffffffffffffff811115610a8857610a87613488565b5b604051908082528060200260200182016040528015610ac157816020015b610aae612a8c565b815260200190600190039081610aa65790505b50848381518110610ad557610ad4613816565b5b6020026020010181905250600067ffffffffffffffff811115610afb57610afa613488565b5b604051908082528060200260200182016040528015610b295781602001602082028036833780820191505090505b50838381518110610b3d57610b3c613816565b5b60200260200101819052506111aa565b80848381518110610b6157610b60613816565b5b60200260200101819052506000815167ffffffffffffffff811115610b8957610b88613488565b5b604051908082528060200260200182016040528015610bb75781602001602082028036833780820191505090505b50905080848481518110610bce57610bcd613816565b5b60200260200101819052503373ffffffffffffffffffffffffffffffffffffffff1682600081518110610c0457610c03613816565b5b60200260200101516000015173ffffffffffffffffffffffffffffffffffffffff1614158015610c815750610a1173ffffffffffffffffffffffffffffffffffffffff1682600081518110610c5c57610c5b613816565b5b60200260200101516000015173ffffffffffffffffffffffffffffffffffffffff1614155b15610cb8576040517fb586360400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b8251811015610f1d576000838281518110610cd957610cd8613816565b5b60200260200101519050610cec81612099565b838381518110610cff57610cfe613816565b5b6020026020010181815250506000816020015173ffffffffffffffffffffffffffffffffffffffff163b03610dd9576000610d68610d5e610d3e6107bd565b868681518110610d5157610d50613816565b5b602002602001015161231d565b8360a0015161235e565b9050816020015173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614610dd3576040517f3db6791c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50610f11565b6000610e06610de66107bd565b858581518110610df957610df8613816565b5b602002602001015161231d565b90506000826020015173ffffffffffffffffffffffffffffffffffffffff16631626ba7e838560a001516040518363ffffffff1660e01b8152600401610e4d929190613a36565b602060405180830381865afa158015610e6a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e8e9190613abe565b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19169050631626ba7e60e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19168114610f0e576040517f155ff42700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50505b50806001019050610cbb565b5060005b82518110156111a75760046000838381518110610f4157610f40613816565b5b6020026020010151815260200190815260200160002060009054906101000a900460ff1615610f9c576040517f05baa05200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60018351610faa9190613b1a565b81146111215781600182610fbe9190613b4e565b81518110610fcf57610fce613816565b5b6020026020010151838281518110610fea57610fe9613816565b5b6020026020010151604001511461102d576040517fded4370e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008360018361103d9190613b4e565b8151811061104e5761104d613816565b5b6020026020010151600001519050610a1173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16141580156110e457508073ffffffffffffffffffffffffffffffffffffffff168483815181106110bf576110be613816565b5b60200260200101516020015173ffffffffffffffffffffffffffffffffffffffff1614155b1561111b576040517fb586360400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5061119c565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60001b83828151811061115857611157613816565b5b6020026020010151604001511461119b576040517fded4370e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5b806001019050610f21565b50505b50806001019050610a26565b5060005b838110156113fb5760008382815181106111d7576111d6613816565b5b60200260200101515111156113f05760005b8382815181106111fc576111fb613816565b5b6020026020010151518110156113ee57600084838151811061122157611220613816565b5b6020026020010151828151811061123b5761123a613816565b5b602002602001015160600151905060005b81518110156113e157600082828151811061126a57611269613816565b5b60200260200101516000015190508073ffffffffffffffffffffffffffffffffffffffff1663414c3e338484815181106112a7576112a6613816565b5b6020026020010151602001518585815181106112c6576112c5613816565b5b6020026020010151604001518f8f8a8181106112e5576112e4613816565b5b905060200201358e8e8b8181106112ff576112fe613816565b5b90506020028101906113119190613854565b8c8c8151811061132457611323613816565b5b60200260200101518b8151811061133e5761133d613816565b5b60200260200101518e8d8151811061135957611358613816565b5b60200260200101518c8151811061137357611372613816565b5b602002602001015160200151336040518963ffffffff1660e01b81526004016113a3989796959493929190613bd0565b600060405180830381600087803b1580156113bd57600080fd5b505af11580156113d1573d6000803e3d6000fd5b505050505080600101905061124c565b50508060010190506111e9565b505b8060010190506111ba565b5060005b83811015611a8c57600083828151811061141c5761141b613816565b5b602002602001015151036114f1573373ffffffffffffffffffffffffffffffffffffffff1663d691c96489898481811061145957611458613816565b5b9050602002013588888581811061147357611472613816565b5b90506020028101906114859190613854565b6040518463ffffffff1660e01b81526004016114a393929190613c56565b6000604051808303816000875af11580156114c2573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f820116820180604052508101906114eb9190613dd9565b50611a81565b60005b83828151811061150757611506613816565b5b6020026020010151518110156116f957600084838151811061152c5761152b613816565b5b6020026020010151828151811061154657611545613816565b5b602002602001015160600151905060005b81518110156116ec57600082828151811061157557611574613816565b5b60200260200101516000015190508073ffffffffffffffffffffffffffffffffffffffff1663a145832a8484815181106115b2576115b1613816565b5b6020026020010151602001518585815181106115d1576115d0613816565b5b6020026020010151604001518f8f8a8181106115f0576115ef613816565b5b905060200201358e8e8b81811061160a57611609613816565b5b905060200281019061161c9190613854565b8c8c8151811061162f5761162e613816565b5b60200260200101518b8151811061164957611648613816565b5b60200260200101518e8d8151811061166457611663613816565b5b60200260200101518c8151811061167e5761167d613816565b5b602002602001015160200151336040518963ffffffff1660e01b81526004016116ae989796959493929190613bd0565b600060405180830381600087803b1580156116c857600080fd5b505af11580156116dc573d6000803e3d6000fd5b5050505050806001019050611557565b50508060010190506114f4565b5082818151811061170d5761170c613816565b5b6020026020010151600184838151811061172a57611729613816565b5b60200260200101515161173d9190613b1a565b8151811061174e5761174d613816565b5b60200260200101516020015173ffffffffffffffffffffffffffffffffffffffff1663d691c96489898481811061178857611787613816565b5b905060200201358888858181106117a2576117a1613816565b5b90506020028101906117b49190613854565b6040518463ffffffff1660e01b81526004016117d293929190613c56565b6000604051808303816000875af11580156117f1573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f8201168201806040525081019061181a9190613dd9565b5060008382815181106118305761182f613816565b5b60200260200101515190505b6000811115611a7f57600084838151811061185a57611859613816565b5b602002602001015160018361186f9190613b1a565b815181106118805761187f613816565b5b60200260200101516060015190506000815190505b6000811115611a6c576000826001836118ae9190613b1a565b815181106118bf576118be613816565b5b60200260200101516000015190508073ffffffffffffffffffffffffffffffffffffffff1663d3eddcc5846001856118f79190613b1a565b8151811061190857611907613816565b5b602002602001015160200151856001866119229190613b1a565b8151811061193357611932613816565b5b6020026020010151604001518f8f8a81811061195257611951613816565b5b905060200201358e8e8b81811061196c5761196b613816565b5b905060200281019061197e9190613854565b8c8c8151811061199157611990613816565b5b602002602001015160018c6119a69190613b1a565b815181106119b7576119b6613816565b5b60200260200101518e8d815181106119d2576119d1613816565b5b602002602001015160018d6119e79190613b1a565b815181106119f8576119f7613816565b5b602002602001015160200151336040518963ffffffff1660e01b8152600401611a28989796959493929190613bd0565b600060405180830381600087803b158015611a4257600080fd5b505af1158015611a56573d6000803e3d6000fd5b505050505080611a6590613e22565b9050611895565b505080611a7890613e22565b905061183c565b505b8060010190506113ff565b5060005b83811015611d2d576000838281518110611aad57611aac613816565b5b6020026020010151511115611d22576000838281518110611ad157611ad0613816565b5b60200260200101515190505b6000811115611d20576000848381518110611afb57611afa613816565b5b6020026020010151600183611b109190613b1a565b81518110611b2157611b20613816565b5b60200260200101516060015190506000815190505b6000811115611d0d57600082600183611b4f9190613b1a565b81518110611b6057611b5f613816565b5b60200260200101516000015190508073ffffffffffffffffffffffffffffffffffffffff1663ed46336784600185611b989190613b1a565b81518110611ba957611ba8613816565b5b60200260200101516020015185600186611bc39190613b1a565b81518110611bd457611bd3613816565b5b6020026020010151604001518f8f8a818110611bf357611bf2613816565b5b905060200201358e8e8b818110611c0d57611c0c613816565b5b9050602002810190611c1f9190613854565b8c8c81518110611c3257611c31613816565b5b602002602001015160018c611c479190613b1a565b81518110611c5857611c57613816565b5b60200260200101518e8d81518110611c7357611c72613816565b5b602002602001015160018d611c889190613b1a565b81518110611c9957611c98613816565b5b602002602001015160200151336040518963ffffffff1660e01b8152600401611cc9989796959493929190613bd0565b600060405180830381600087803b158015611ce357600080fd5b505af1158015611cf7573d6000803e3d6000fd5b505050505080611d0690613e22565b9050611b36565b505080611d1990613e22565b9050611add565b505b806001019050611a90565b5060005b83811015611e93576000838281518110611d4e57611d4d613816565b5b6020026020010151511115611e885760005b838281518110611d7357611d72613816565b5b602002602001015151811015611e86573373ffffffffffffffffffffffffffffffffffffffff16848381518110611dad57611dac613816565b5b60200260200101516001868581518110611dca57611dc9613816565b5b602002602001015151611ddd9190613b1a565b81518110611dee57611ded613816565b5b60200260200101516020015173ffffffffffffffffffffffffffffffffffffffff167f40dadaa36c6c2e3d7317e24757451ffb2d603d875f0ad5e92c5dd156573b1873868581518110611e4457611e43613816565b5b60200260200101518481518110611e5e57611e5d613816565b5b6020026020010151604051611e73919061401c565b60405180910390a3806001019050611d60565b505b806001019050611d31565b50505050505050505050565b6000600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b611ed1611faf565b80600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508073ffffffffffffffffffffffffffffffffffffffff16611f31610888565b73ffffffffffffffffffffffffffffffffffffffff167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b6040518060400160405280600581526020017f312e332e3000000000000000000000000000000000000000000000000000000081525081565b611fb7612145565b73ffffffffffffffffffffffffffffffffffffffff16611fd5610888565b73ffffffffffffffffffffffffffffffffffffffff161461203457611ff8612145565b6040517f118cdaa700000000000000000000000000000000000000000000000000000000815260040161202b9190612c76565b60405180910390fd5b565b61203e61238a565b6000600160146101000a81548160ff0219169083151502179055507f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa612082612145565b60405161208f9190612c76565b60405180910390a1565b6000807f88c1d2ecf185adf710588203a5f263f0ff61be0d33da39792cde19ba9aa4331e8360000151846020015185604001516120d987606001516123ca565b87608001516040516020016120f39695949392919061403e565b60405160208183030381529060405290508080519060200120915050919050565b600160006101000a81549073ffffffffffffffffffffffffffffffffffffffff0219169055612142816124a2565b50565b600033905090565b60007f000000000000000000000000663f3ad617193148711d28f5334ee4ed0701660273ffffffffffffffffffffffffffffffffffffffff163073ffffffffffffffffffffffffffffffffffffffff161480156121c957507f000000000000000000000000000000000000000000000000000000000000053946145b156121f6577f8cdadf61c3a91a26e93fd395df1ff97693afe59cddc459306faa96608f5933d99050612201565b6121fe612566565b90505b90565b61220c6122dc565b60018060146101000a81548160ff0219169083151502179055507f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a25861224f612145565b60405161225c9190612c76565b60405180910390a1565b606061229c60027f44656c65676174696f6e4d616e616765720000000000000000000000000000116125fc90919063ffffffff16565b905090565b60606122d760037f31000000000000000000000000000000000000000000000000000000000000016125fc90919063ffffffff16565b905090565b6122e46106e8565b1561231b576040517fd93c066500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b565b60006040517f190100000000000000000000000000000000000000000000000000000000000081528360028201528260228201526042812091505092915050565b60008060008061236e86866126ac565b92509250925061237e8282612708565b82935050505092915050565b6123926106e8565b6123c8576040517f8dfc202b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b565b600080825167ffffffffffffffff8111156123e8576123e7613488565b5b6040519080825280602002602001820160405280156124165781602001602082028036833780820191505090505b50905060005b83518110156124725761244884828151811061243b5761243a613816565b5b602002602001015161286c565b82828151811061245b5761245a613816565b5b60200260200101818152505080600101905061241c565b50806040516020016124849190614157565b60405160208183030381529060405280519060200120915050919050565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050816000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a35050565b60007f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f7f604240e1ed005b9ba256cb7011059bf4ae645812b834bbcb5b22c93e2d1185cc7fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc646306040516020016125e195949392919061416e565b60405160208183030381529060405280519060200120905090565b606060ff60001b831461261957612612836128d4565b90506126a6565b818054612625906141f0565b80601f0160208091040260200160405190810160405280929190818152602001828054612651906141f0565b801561269e5780601f106126735761010080835404028352916020019161269e565b820191906000526020600020905b81548152906001019060200180831161268157829003601f168201915b505050505090505b92915050565b600080600060418451036126f15760008060006020870151925060408701519150606087015160001a90506126e388828585612948565b955095509550505050612701565b60006002855160001b9250925092505b9250925092565b6000600381111561271c5761271b614221565b5b82600381111561272f5761272e614221565b5b0315612868576001600381111561274957612748614221565b5b82600381111561275c5761275b614221565b5b03612793576040517ff645eedf00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600260038111156127a7576127a6614221565b5b8260038111156127ba576127b9614221565b5b036127ff578060001c6040517ffce698f70000000000000000000000000000000000000000000000000000000081526004016127f69190614250565b60405180910390fd5b60038081111561281257612811614221565b5b82600381111561282557612824614221565b5b0361286757806040517fd78bce0c00000000000000000000000000000000000000000000000000000000815260040161285e9190612b0a565b60405180910390fd5b5b5050565b6000807f80ad7e1b04ee6d994a125f4714ca0720908bd80ed16063ec8aee4b88e9253e2d83600001518460200151805190602001206040516020016128b39392919061426b565b60405160208183030381529060405290508080519060200120915050919050565b606060006128e183612a3c565b90506000602067ffffffffffffffff811115612900576128ff613488565b5b6040519080825280601f01601f1916602001820160405280156129325781602001600182028036833780820191505090505b5090508181528360208201528092505050919050565b60008060007f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08460001c1115612988576000600385925092509250612a32565b6000600188888888604051600081526020016040526040516129ad94939291906142be565b6020604051602081039080840390855afa1580156129cf573d6000803e3d6000fd5b505050602060405103519050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603612a2357600060016000801b93509350935050612a32565b8060008060001b935093509350505b9450945094915050565b60008060ff8360001c169050601f811115612a83576040517fb3512b0c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80915050919050565b6040518060c00160405280600073ffffffffffffffffffffffffffffffffffffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff168152602001600080191681526020016060815260200160008152602001606081525090565b6000819050919050565b612b0481612af1565b82525050565b6000602082019050612b1f6000830184612afb565b92915050565b6000604051905090565b600080fd5b600080fd5b612b4281612af1565b8114612b4d57600080fd5b50565b600081359050612b5f81612b39565b92915050565b600060208284031215612b7b57612b7a612b2f565b5b6000612b8984828501612b50565b91505092915050565b60008115159050919050565b612ba781612b92565b82525050565b6000602082019050612bc26000830184612b9e565b92915050565b600080fd5b600060c08284031215612be357612be2612bc8565b5b81905092915050565b600060208284031215612c0257612c01612b2f565b5b600082013567ffffffffffffffff811115612c2057612c1f612b34565b5b612c2c84828501612bcd565b91505092915050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000612c6082612c35565b9050919050565b612c7081612c55565b82525050565b6000602082019050612c8b6000830184612c67565b92915050565b60007fff0000000000000000000000000000000000000000000000000000000000000082169050919050565b612cc681612c91565b82525050565b600081519050919050565b600082825260208201905092915050565b60005b83811015612d06578082015181840152602081019050612ceb565b60008484015250505050565b6000601f19601f8301169050919050565b6000612d2e82612ccc565b612d388185612cd7565b9350612d48818560208601612ce8565b612d5181612d12565b840191505092915050565b6000819050919050565b612d6f81612d5c565b82525050565b600081519050919050565b600082825260208201905092915050565b6000819050602082019050919050565b612daa81612d5c565b82525050565b6000612dbc8383612da1565b60208301905092915050565b6000602082019050919050565b6000612de082612d75565b612dea8185612d80565b9350612df583612d91565b8060005b83811015612e26578151612e0d8882612db0565b9750612e1883612dc8565b925050600181019050612df9565b5085935050505092915050565b600060e082019050612e48600083018a612cbd565b8181036020830152612e5a8189612d23565b90508181036040830152612e6e8188612d23565b9050612e7d6060830187612d66565b612e8a6080830186612c67565b612e9760a0830185612afb565b81810360c0830152612ea98184612dd5565b905098975050505050505050565b60006020820190508181036000830152612ed18184612d23565b905092915050565b600080fd5b600080fd5b600080fd5b60008083601f840112612efe57612efd612ed9565b5b8235905067ffffffffffffffff811115612f1b57612f1a612ede565b5b602083019150836020820283011115612f3757612f36612ee3565b5b9250929050565b60008083601f840112612f5457612f53612ed9565b5b8235905067ffffffffffffffff811115612f7157612f70612ede565b5b602083019150836020820283011115612f8d57612f8c612ee3565b5b9250929050565b60008060008060008060608789031215612fb157612fb0612b2f565b5b600087013567ffffffffffffffff811115612fcf57612fce612b34565b5b612fdb89828a01612ee8565b9650965050602087013567ffffffffffffffff811115612ffe57612ffd612b34565b5b61300a89828a01612f3e565b9450945050604087013567ffffffffffffffff81111561302d5761302c612b34565b5b61303989828a01612ee8565b92509250509295509295509295565b61305181612c55565b811461305c57600080fd5b50565b60008135905061306e81613048565b92915050565b60006020828403121561308a57613089612b2f565b5b60006130988482850161305f565b91505092915050565b60006130b0602084018461305f565b905092915050565b6130c181612c55565b82525050565b60006130d66020840184612b50565b905092915050565b6130e781612af1565b82525050565b600080fd5b600080fd5b600080fd5b60008083356001602003843603038112613119576131186130f7565b5b83810192508235915060208301925067ffffffffffffffff821115613141576131406130ed565b5b602082023603831315613157576131566130f2565b5b509250929050565b600082825260208201905092915050565b6000819050919050565b60008083356001602003843603038112613197576131966130f7565b5b83810192508235915060208301925067ffffffffffffffff8211156131bf576131be6130ed565b5b6001820236038313156131d5576131d46130f2565b5b509250929050565b600082825260208201905092915050565b82818337600083830152505050565b600061320983856131dd565b93506132168385846131ee565b61321f83612d12565b840190509392505050565b60006060830161323d60008401846130a1565b61324a60008601826130b8565b50613258602084018461317a565b858303602087015261326b8382846131fd565b9250505061327c604084018461317a565b858303604087015261328f8382846131fd565b925050508091505092915050565b60006132a9838361322a565b905092915050565b6000823560016060038336030381126132cd576132cc6130f7565b5b82810191505092915050565b6000602082019050919050565b60006132f2838561315f565b93508360208402850161330484613170565b8060005b8781101561334857848403895261331f82846132b1565b613329858261329d565b9450613334836132d9565b925060208a01995050600181019050613308565b50829750879450505050509392505050565b61336381612d5c565b811461336e57600080fd5b50565b6000813590506133808161335a565b92915050565b60006133956020840184613371565b905092915050565b600060c083016133b060008401846130a1565b6133bd60008601826130b8565b506133cb60208401846130a1565b6133d860208601826130b8565b506133e660408401846130c7565b6133f360408601826130de565b5061340160608401846130fc565b85830360608701526134148382846132e6565b925050506134256080840184613386565b6134326080860182612da1565b5061344060a084018461317a565b85830360a08701526134538382846131fd565b925050508091505092915050565b6000602082019050818103600083015261347b818461339d565b905092915050565b600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6134c082612d12565b810181811067ffffffffffffffff821117156134df576134de613488565b5b80604052505050565b60006134f2612b25565b90506134fe82826134b7565b919050565b600080fd5b600067ffffffffffffffff82111561352357613522613488565b5b602082029050602081019050919050565b600080fd5b600067ffffffffffffffff82111561355457613553613488565b5b61355d82612d12565b9050602081019050919050565b600061357d61357884613539565b6134e8565b90508281526020810184848401111561359957613598613534565b5b6135a48482856131ee565b509392505050565b600082601f8301126135c1576135c0612ed9565b5b81356135d184826020860161356a565b91505092915050565b6000606082840312156135f0576135ef613483565b5b6135fa60606134e8565b9050600061360a8482850161305f565b600083015250602082013567ffffffffffffffff81111561362e5761362d613503565b5b61363a848285016135ac565b602083015250604082013567ffffffffffffffff81111561365e5761365d613503565b5b61366a848285016135ac565b60408301525092915050565b600061368961368484613508565b6134e8565b905080838252602082019050602084028301858111156136ac576136ab612ee3565b5b835b818110156136f357803567ffffffffffffffff8111156136d1576136d0612ed9565b5b8086016136de89826135da565b855260208501945050506020810190506136ae565b5050509392505050565b600082601f83011261371257613711612ed9565b5b8135613722848260208601613676565b91505092915050565b600060c0828403121561374157613740613483565b5b61374b60c06134e8565b9050600061375b8482850161305f565b600083015250602061376f8482850161305f565b602083015250604061378384828501612b50565b604083015250606082013567ffffffffffffffff8111156137a7576137a6613503565b5b6137b3848285016136fd565b60608301525060806137c784828501613371565b60808301525060a082013567ffffffffffffffff8111156137eb576137ea613503565b5b6137f7848285016135ac565b60a08301525092915050565b600061380f368361372b565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600080fd5b600080fd5b600080fd5b6000808335600160200384360303811261387157613870613845565b5b80840192508235915067ffffffffffffffff8211156138935761389261384a565b5b6020830192506001820236038313156138af576138ae61384f565b5b509250929050565b600067ffffffffffffffff8211156138d2576138d1613488565b5b602082029050602081019050919050565b60006138f66138f1846138b7565b6134e8565b9050808382526020820190506020840283018581111561391957613918612ee3565b5b835b8181101561396057803567ffffffffffffffff81111561393e5761393d612ed9565b5b80860161394b898261372b565b8552602085019450505060208101905061391b565b5050509392505050565b600082601f83011261397f5761397e612ed9565b5b813561398f8482602086016138e3565b91505092915050565b6000602082840312156139ae576139ad612b2f565b5b600082013567ffffffffffffffff8111156139cc576139cb612b34565b5b6139d88482850161396a565b91505092915050565b600081519050919050565b600082825260208201905092915050565b6000613a08826139e1565b613a1281856139ec565b9350613a22818560208601612ce8565b613a2b81612d12565b840191505092915050565b6000604082019050613a4b6000830185612afb565b8181036020830152613a5d81846139fd565b90509392505050565b60007fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b613a9b81613a66565b8114613aa657600080fd5b50565b600081519050613ab881613a92565b92915050565b600060208284031215613ad457613ad3612b2f565b5b6000613ae284828501613aa9565b91505092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000613b2582612d5c565b9150613b3083612d5c565b9250828203905081811115613b4857613b47613aeb565b5b92915050565b6000613b5982612d5c565b9150613b6483612d5c565b9250828201905080821115613b7c57613b7b613aeb565b5b92915050565b6000613b8d82612af1565b9050919050565b613b9d81613b82565b82525050565b6000613baf83856139ec565b9350613bbc8385846131ee565b613bc583612d12565b840190509392505050565b600060e0820190508181036000830152613bea818b6139fd565b90508181036020830152613bfe818a6139fd565b9050613c0d6040830189613b94565b8181036060830152613c20818789613ba3565b9050613c2f6080830186612afb565b613c3c60a0830185612c67565b613c4960c0830184612c67565b9998505050505050505050565b6000604082019050613c6b6000830186613b94565b8181036020830152613c7e818486613ba3565b9050949350505050565b600067ffffffffffffffff821115613ca357613ca2613488565b5b602082029050602081019050919050565b6000613cc7613cc284613539565b6134e8565b905082815260208101848484011115613ce357613ce2613534565b5b613cee848285612ce8565b509392505050565b600082601f830112613d0b57613d0a612ed9565b5b8151613d1b848260208601613cb4565b91505092915050565b6000613d37613d3284613c88565b6134e8565b90508083825260208201905060208402830185811115613d5a57613d59612ee3565b5b835b81811015613da157805167ffffffffffffffff811115613d7f57613d7e612ed9565b5b808601613d8c8982613cf6565b85526020850194505050602081019050613d5c565b5050509392505050565b600082601f830112613dc057613dbf612ed9565b5b8151613dd0848260208601613d24565b91505092915050565b600060208284031215613def57613dee612b2f565b5b600082015167ffffffffffffffff811115613e0d57613e0c612b34565b5b613e1984828501613dab565b91505092915050565b6000613e2d82612d5c565b915060008203613e4057613e3f613aeb565b5b600182039050919050565b600081519050919050565b6000819050602082019050919050565b6000613e71826139e1565b613e7b81856131dd565b9350613e8b818560208601612ce8565b613e9481612d12565b840191505092915050565b6000606083016000830151613eb760008601826130b8565b5060208301518482036020860152613ecf8282613e66565b91505060408301518482036040860152613ee98282613e66565b9150508091505092915050565b6000613f028383613e9f565b905092915050565b6000602082019050919050565b6000613f2282613e4b565b613f2c818561315f565b935083602082028501613f3e85613e56565b8060005b85811015613f7a5784840389528151613f5b8582613ef6565b9450613f6683613f0a565b925060208a01995050600181019050613f42565b50829750879550505050505092915050565b600060c083016000830151613fa460008601826130b8565b506020830151613fb760208601826130b8565b506040830151613fca60408601826130de565b5060608301518482036060860152613fe28282613f17565b9150506080830151613ff76080860182612da1565b5060a083015184820360a086015261400f8282613e66565b9150508091505092915050565b600060208201905081810360008301526140368184613f8c565b905092915050565b600060c0820190506140536000830189612afb565b6140606020830188612c67565b61406d6040830187612c67565b61407a6060830186612afb565b6140876080830185612afb565b61409460a0830184612d66565b979650505050505050565b600081519050919050565b600081905092915050565b6000819050602082019050919050565b6140ce81612af1565b82525050565b60006140e083836140c5565b60208301905092915050565b6000602082019050919050565b60006141048261409f565b61410e81856140aa565b9350614119836140b5565b8060005b8381101561414a57815161413188826140d4565b975061413c836140ec565b92505060018101905061411d565b5085935050505092915050565b600061416382846140f9565b915081905092915050565b600060a0820190506141836000830188612afb565b6141906020830187612afb565b61419d6040830186612afb565b6141aa6060830185612d66565b6141b76080830184612c67565b9695505050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b6000600282049050600182168061420857607f821691505b60208210810361421b5761421a6141c1565b5b50919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b60006020820190506142656000830184612d66565b92915050565b60006060820190506142806000830186612afb565b61428d6020830185612c67565b61429a6040830184612afb565b949350505050565b600060ff82169050919050565b6142b8816142a2565b82525050565b60006080820190506142d36000830187612afb565b6142e060208301866142af565b6142ed6040830185612afb565b6142fa6060830184612afb565b9594505050505056fea26469706673582212205871db72351a516eb48063d38edefa8dca6451c54af96066cc36b7a433d5af5b64736f6c63430008170033", + "nonce": 0, + "gas_used": 3835411 + }, + "receipt": { + "type": "0x2", + "status": "0x1", + "cumulativeGasUsed": "0x3a8613", + "logs": [ + { + "address": "0x663f3ad617193148711d28f5334ee4ed07016602", + "topics": [ + "0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x00000000000000000000000070997970c51812dc3a010c7d01b50e0d17dc79c8" + ], + "data": "0x" + }, + { + "address": "0x663f3ad617193148711d28f5334ee4ed07016602", + "topics": [ + "0x04a46d9007577c7ff1e513b900545162ec25d25991ae3dc60cf26ec01a84806d", + "0x8cdadf61c3a91a26e93fd395df1ff97693afe59cddc459306faa96608f5933d9", + "0x000000000000000000000000663f3ad617193148711d28f5334ee4ed07016602" + ], + "data": "0x000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000539000000000000000000000000000000000000000000000000000000000000001144656c65676174696f6e4d616e6167657200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000013100000000000000000000000000000000000000000000000000000000000000" + } + ], + "logsBloom": "0x00000000000000000002000000000000000000004000000000800000004000000000000000000000000000000000000000000000000000000000001000000020000000000000000000000000000000000001000000000020000000000000000000000800020000000000000000000800000000000000000000000000000000400000000000000000000000000000000000080000000000000001000000000000000000000000000800000000000000000000000000000000000000000000000000000000008040001000000000000000000000000000000000000200000020000000000000000000000000000000000001000000000000000000000000000000" + }, + "block_hash": "0xf1b02a58253c31b071b2fa814de80eb512d7d1f550385dc85a953186a7d4e44f", + "block_number": 1 + }, + { + "info": { + "transaction_hash": "0xdbc70e14bbeac0578540243bda21bd2ea8e38bbad034323f32866d1cf0c0e5a2", + "transaction_index": 0, + "from": "0x3c44cdddb6a900fa2b585dd299e03d12fa4293bc", + "to": null, + "contract_address": "0x8438ad1c834623cff278ab6829a248e37c2d7e3f", + "traces": [ + { + "parent": null, + "children": [], + "idx": 0, + "trace": { + "depth": 0, + "success": true, + "caller": "0x3c44cdddb6a900fa2b585dd299e03d12fa4293bc", + "address": "0x8438ad1c834623cff278ab6829a248e37c2d7e3f", + "maybe_precompile": false, + "selfdestruct_address": null, + "selfdestruct_refund_target": null, + "selfdestruct_transferred_value": null, + "kind": "CREATE", + "value": "0x0", + "data": "0x6101c06040523073ffffffffffffffffffffffffffffffffffffffff166101609073ffffffffffffffffffffffffffffffffffffffff168152503480156200004657600080fd5b50604051620057443803806200574483398181016040528101906200006c9190620004f1565b81816040518060400160405280601981526020017f4549503737303253746174656c65737344656c654761746f72000000000000008152506040518060400160405280600181526020017f31000000000000000000000000000000000000000000000000000000000000008152508181620000f26000836200030260201b90919060201c565b6101208181525050620001106001826200030260201b90919060201c565b6101408181525050818051906020012060e08181525050808051906020012061010081815250504660a081815250506200014f6200035a60201b60201c565b608081815250503073ffffffffffffffffffffffffffffffffffffffff1660c08173ffffffffffffffffffffffffffffffffffffffff16815250505050601f82511115620001c9576040517f6b66bce400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b601f8151111562000206576040517f9203c9d000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8373ffffffffffffffffffffffffffffffffffffffff166101808173ffffffffffffffffffffffffffffffffffffffff16815250508273ffffffffffffffffffffffffffffffffffffffff166101a08173ffffffffffffffffffffffffffffffffffffffff16815250508373ffffffffffffffffffffffffffffffffffffffff167fb2e8eb88b584ae71ef4e854c10847f4d39bd93e52599f147bfb4dcc8de52014d60405160405180910390a28273ffffffffffffffffffffffffffffffffffffffff167fee8699dc0e27105da2653bdba54be0edcaadc3e33890a3ad705517ffe9bf0a9960405160405180910390a250505050505062000a88565b600060208351101562000328576200032083620003b760201b60201c565b905062000354565b826200033a836200042460201b60201c565b60000190816200034b9190620007b2565b5060ff60001b90505b92915050565b60007f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f60e0516101005146306040516020016200039c959493929190620008d6565b60405160208183030381529060405280519060200120905090565b600080829050601f815111156200040757826040517f305a27a9000000000000000000000000000000000000000000000000000000008152600401620003fe9190620009c2565b60405180910390fd5b805181620004159062000a18565b60001c1760001b915050919050565b6000819050919050565b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000620004608262000433565b9050919050565b6000620004748262000453565b9050919050565b620004868162000467565b81146200049257600080fd5b50565b600081519050620004a6816200047b565b92915050565b6000620004b98262000453565b9050919050565b620004cb81620004ac565b8114620004d757600080fd5b50565b600081519050620004eb81620004c0565b92915050565b600080604083850312156200050b576200050a6200042e565b5b60006200051b8582860162000495565b92505060206200052e85828601620004da565b9150509250929050565b600081519050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b60006002820490506001821680620005ba57607f821691505b602082108103620005d057620005cf62000572565b5b50919050565b60008190508160005260206000209050919050565b60006020601f8301049050919050565b600082821b905092915050565b6000600883026200063a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82620005fb565b620006468683620005fb565b95508019841693508086168417925050509392505050565b6000819050919050565b6000819050919050565b6000620006936200068d62000687846200065e565b62000668565b6200065e565b9050919050565b6000819050919050565b620006af8362000672565b620006c7620006be826200069a565b84845462000608565b825550505050565b600090565b620006de620006cf565b620006eb818484620006a4565b505050565b5b81811015620007135762000707600082620006d4565b600181019050620006f1565b5050565b601f82111562000762576200072c81620005d6565b6200073784620005eb565b8101602085101562000747578190505b6200075f6200075685620005eb565b830182620006f0565b50505b505050565b600082821c905092915050565b6000620007876000198460080262000767565b1980831691505092915050565b6000620007a2838362000774565b9150826002028217905092915050565b620007bd8262000538565b67ffffffffffffffff811115620007d957620007d862000543565b5b620007e58254620005a1565b620007f282828562000717565b600060209050601f8311600181146200082a576000841562000815578287015190505b62000821858262000794565b86555062000891565b601f1984166200083a86620005d6565b60005b8281101562000864578489015182556001820191506020850194506020810190506200083d565b8683101562000884578489015162000880601f89168262000774565b8355505b6001600288020188555050505b505050505050565b6000819050919050565b620008ae8162000899565b82525050565b620008bf816200065e565b82525050565b620008d08162000453565b82525050565b600060a082019050620008ed6000830188620008a3565b620008fc6020830187620008a3565b6200090b6040830186620008a3565b6200091a6060830185620008b4565b620009296080830184620008c5565b9695505050505050565b600082825260208201905092915050565b60005b838110156200096457808201518184015260208101905062000947565b60008484015250505050565b6000601f19601f8301169050919050565b60006200098e8262000538565b6200099a818562000933565b9350620009ac81856020860162000944565b620009b78162000970565b840191505092915050565b60006020820190508181036000830152620009de818462000981565b905092915050565b600081519050919050565b6000819050602082019050919050565b600062000a0f825162000899565b80915050919050565b600062000a2582620009e6565b8262000a3184620009f1565b905062000a3e8162000a01565b9250602082101562000a815762000a7c7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff83602003600802620005fb565b831692505b5050919050565b60805160a05160c05160e05161010051610120516101405161016051610180516101a051614b9862000bac60003960008181610b8c01528181610ce001528181610d8301528181610f7301528181611145015281816111d3015281816112c6015281816113850152818161154101528181611601015281816116a0015281816118af01528181611c8d01526120c2015260008181610e4201528181610ed2015281816110320152818161175f015281816119530152611fe201526000818161073f01528181610a5801528181610af101528181610c11015281816110c001528181611567015261211b0152600061257201526000612537015260006129f7015260006129d6015260006121ee015260006122440152600061226d0152614b986000f3fe6080604052600436106101c65760003560e01c806384b0196e116100f7578063d03c791411610095578063ea4d3c9b11610064578063ea4d3c9b1461066b578063ed8101b514610696578063f23a6e61146106d3578063ffa1ad7414610710576101cd565b8063d03c7914146105b7578063d087d288146105f4578063d691c9641461061f578063e9ae5c531461064f576101cd565b8063b0d691fe116100d1578063b0d691fe146104fb578063bc197c8114610526578063c399ec8814610563578063cef6d2091461058e576101cd565b806384b0196e14610474578063a3f4df7e146104a5578063acb8cc49146104d0576101cd565b80633ed01015116101645780634a58db191161013e5780634a58db19146103fa5780635c1c6dcd146104045780637f07bfdc1461042057806383ebb77114610449576101cd565b80633ed010151461036b578063445140b81461039457806349934047146103d1576101cd565b80631626ba7e116101a05780631626ba7e1461028957806319822f7c146102c65780632b3afd99146103035780633e1b08121461032e576101cd565b806301ffc9a7146101d257806306394d671461020f578063150b7a021461024c576101cd565b366101cd57005b600080fd5b3480156101de57600080fd5b506101f960048036038101906101f49190612f07565b61073b565b6040516102069190612f4f565b60405180910390f35b34801561021b57600080fd5b5061023660048036038101906102319190612f8f565b610a32565b6040516102439190612ff1565b60405180910390f35b34801561025857600080fd5b50610273600480360381019061026e91906131e6565b610a54565b6040516102809190613278565b60405180910390f35b34801561029557600080fd5b506102b060048036038101906102ab919061331f565b610aed565b6040516102bd9190613278565b60405180910390f35b3480156102d257600080fd5b506102ed60048036038101906102e8919061337f565b610b88565b6040516102fa91906133fd565b60405180910390f35b34801561030f57600080fd5b50610318610cb8565b6040516103259190612ff1565b60405180910390f35b34801561033a57600080fd5b5061035560048036038101906103509190613468565b610cdc565b60405161036291906133fd565b60405180910390f35b34801561037757600080fd5b50610392600480360381019061038d91906134b4565b610d81565b005b3480156103a057600080fd5b506103bb60048036038101906103b691906134fd565b610ece565b6040516103c89190612f4f565b60405180910390f35b3480156103dd57600080fd5b506103f860048036038101906103f391906134b4565b610f71565b005b6104026110be565b005b61041e60048036038101906104199190613549565b6111d1565b005b34801561042c57600080fd5b50610447600480360381019061044291906135d0565b6112c4565b005b34801561045557600080fd5b5061045e611414565b60405161046b9190612ff1565b60405180910390f35b34801561048057600080fd5b50610489611423565b60405161049c9796959493929190613797565b60405180910390f35b3480156104b157600080fd5b506104ba6114cd565b6040516104c7919061381b565b60405180910390f35b3480156104dc57600080fd5b506104e5611506565b6040516104f2919061381b565b60405180910390f35b34801561050757600080fd5b5061051061153f565b60405161051d919061389c565b60405180910390f35b34801561053257600080fd5b5061054d6004803603810190610548919061397a565b611563565b60405161055a9190613278565b60405180910390f35b34801561056f57600080fd5b506105786115fd565b60405161058591906133fd565b60405180910390f35b34801561059a57600080fd5b506105b560048036038101906105b09190613af5565b61169e565b005b3480156105c357600080fd5b506105de60048036038101906105d99190613bd5565b6117fa565b6040516105eb9190612f4f565b60405180910390f35b34801561060057600080fd5b506106096118ab565b60405161061691906133fd565b60405180910390f35b61063960048036038101906106349190613c02565b61194f565b6040516106469190613d79565b60405180910390f35b61066960048036038101906106649190613c02565b611c8b565b005b34801561067757600080fd5b50610680611fe0565b60405161068d9190613dbc565b60405180910390f35b3480156106a257600080fd5b506106bd60048036038101906106b89190612f8f565b612004565b6040516106ca9190612ff1565b60405180910390f35b3480156106df57600080fd5b506106fa60048036038101906106f59190613dd7565b612117565b6040516107079190613278565b60405180910390f35b34801561071c57600080fd5b506107256121b1565b604051610732919061381b565b60405180910390f35b60007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff163073ffffffffffffffffffffffffffffffffffffffff16036107c2576040517f9f03a02600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7fd691c964000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916148061088b57507f150b7a02000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b806108f357507f4e2312e0000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b8061095b57507f01ffc9a7000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b806109c357507f1626ba7e000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b80610a2b57507f39922547000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b9050919050565b6000610a4d610a3f6121ea565b610a4884612004565b6122a1565b9050919050565b60007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff163073ffffffffffffffffffffffffffffffffffffffff1603610adb576040517f9f03a02600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b63150b7a0260e01b9050949350505050565b60007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff163073ffffffffffffffffffffffffffffffffffffffff1603610b74576040517f9f03a02600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610b7f8484846122e2565b90509392505050565b60007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610c0f576040517fd663742a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff163073ffffffffffffffffffffffffffffffffffffffff1603610c94576040517f9f03a02600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610ca684610ca186610a32565b612385565b9050610cb182612406565b9392505050565b7fbc37962d8bd1d319c95199bdfda6d3f92baa8903a61b32d5f4ec1f4b36a3bc1881565b60007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff166335567e1a30846040518363ffffffff1660e01b8152600401610d39929190613e7d565b602060405180830381865afa158015610d56573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d7a9190613ebb565b9050919050565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614158015610e0957503073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614155b15610e40576040517f0796d94500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16633ed01015826040518263ffffffff1660e01b8152600401610e99919061425c565b600060405180830381600087803b158015610eb357600080fd5b505af1158015610ec7573d6000803e3d6000fd5b5050505050565b60007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16632d40d052836040518263ffffffff1660e01b8152600401610f299190612ff1565b602060405180830381865afa158015610f46573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f6a91906142aa565b9050919050565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614158015610ff957503073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614155b15611030576040517f0796d94500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff166349934047826040518263ffffffff1660e01b8152600401611089919061425c565b600060405180830381600087803b1580156110a357600080fd5b505af11580156110b7573d6000803e3d6000fd5b5050505050565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff163073ffffffffffffffffffffffffffffffffffffffff1603611143576040517f9f03a02600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663b760faf934306040518363ffffffff1660e01b815260040161119d91906142d7565b6000604051808303818588803b1580156111b657600080fd5b505af11580156111ca573d6000803e3d6000fd5b5050505050565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161415801561125957503073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614155b15611290576040517f0796d94500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6112c08160000160208101906112a691906142f2565b82602001358380604001906112bb919061432e565b6124f2565b5050565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161415801561134c57503073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614155b15611383576040517f0796d94500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663205c287883836040518363ffffffff1660e01b81526004016113de9291906143a0565b600060405180830381600087803b1580156113f857600080fd5b505af115801561140c573d6000803e3d6000fd5b505050505050565b600061141e6121ea565b905090565b60006060806000806000606061143761252e565b61143f612569565b46306000801b600067ffffffffffffffff8111156114605761145f6130bb565b5b60405190808252806020026020018201604052801561148e5781602001602082028036833780820191505090505b507f0f00000000000000000000000000000000000000000000000000000000000000959493929190965096509650965096509650965090919293949596565b6040518060400160405280601981526020017f4549503737303253746174656c65737344656c654761746f720000000000000081525081565b6040518060400160405280600181526020017f310000000000000000000000000000000000000000000000000000000000000081525081565b7f000000000000000000000000000000000000000000000000000000000000000081565b60007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff163073ffffffffffffffffffffffffffffffffffffffff16036115ea576040517f9f03a02600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b63bc197c8160e01b905095945050505050565b60007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b815260040161165891906142d7565b602060405180830381865afa158015611675573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116999190613ebb565b905090565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161415801561172657503073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614155b1561175d576040517f0796d94500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663cef6d2098787878787876040518763ffffffff1660e01b81526004016117c096959493929190614541565b600060405180830381600087803b1580156117da57600080fd5b505af11580156117ee573d6000803e3d6000fd5b50505050505050505050565b600080600080600061180b866125a4565b935093509350935061182184600060f81b6125c6565b80611836575061183584600160f81b6125c6565b5b8015611861575061184b83600060f81b612617565b80611860575061185f83600160f81b612617565b5b5b8015611877575061187682600060e01b612668565b5b80156118a05750600060501b69ffffffffffffffffffff19168169ffffffffffffffffffff1916145b945050505050919050565b60007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff166335567e1a3060006040518363ffffffff1660e01b81526004016119099291906145ce565b602060405180830381865afa158015611926573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061194a9190613ebb565b905090565b60607f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146119d6576040517f1a4b3a0400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000806119e2866125a4565b5050915091506119f682600160f81b6125c6565b15611a9957366000611a0887876126b3565b91509150611a1a83600060f81b612617565b15611a3057611a2982826126cc565b9450611a92565b611a3e83600160f81b612617565b15611a5457611a4d82826127bd565b9450611a91565b826040517f1187dc06000000000000000000000000000000000000000000000000000000008152600401611a889190614618565b60405180910390fd5b5b5050611c82565b611aa782600060f81b6125c6565b15611c4457600080366000611abc898961290e565b9350935093509350600167ffffffffffffffff811115611adf57611ade6130bb565b5b604051908082528060200260200182016040528015611b1257816020015b6060815260200190600190039081611afd5790505b5096506000611b2586600060f81b612617565b15611b5a57611b36858585856124f2565b88600081518110611b4a57611b49614633565b5b6020026020010181905250611c3a565b611b6886600160f81b612617565b15611bfc57611b798585858561297c565b89600081518110611b8d57611b8c614633565b5b60200260200101819052819250505080611bf7577fe723f28f104e46b47fd3531f3608374ac226bcf3ddda334a23a266453e0efdb7600089600081518110611bd857611bd7614633565b5b6020026020010151604051611bee9291906146dd565b60405180910390a15b611c39565b856040517f1187dc06000000000000000000000000000000000000000000000000000000008152600401611c309190614618565b60405180910390fd5b5b5050505050611c81565b816040517fb96fcfe4000000000000000000000000000000000000000000000000000000008152600401611c78919061471c565b60405180910390fd5b5b50509392505050565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614158015611d1357503073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614155b15611d4a576040517f0796d94500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600080611d56856125a4565b505091509150611d6a82600160f81b6125c6565b15611e0b57366000611d7c86866126b3565b91509150611d8e83600060f81b612617565b15611da357611d9d82826126cc565b50611e04565b611db183600160f81b612617565b15611dc657611dc082826127bd565b50611e03565b826040517f1187dc06000000000000000000000000000000000000000000000000000000008152600401611dfa9190614618565b60405180910390fd5b5b5050611fd9565b611e1982600060f81b6125c6565b15611f9b57600080366000611e2e888861290e565b9350935093509350611e4485600060f81b612617565b15611e5b57611e55848484846124f2565b50611f92565b611e6985600160f81b612617565b15611f54576000600167ffffffffffffffff811115611e8b57611e8a6130bb565b5b604051908082528060200260200182016040528015611ebe57816020015b6060815260200190600190039081611ea95790505b5090506000611ecf8686868661297c565b83600081518110611ee357611ee2614633565b5b60200260200101819052819250505080611f4d577fe723f28f104e46b47fd3531f3608374ac226bcf3ddda334a23a266453e0efdb7600083600081518110611f2e57611f2d614633565b5b6020026020010151604051611f449291906146dd565b60405180910390a15b5050611f91565b846040517f1187dc06000000000000000000000000000000000000000000000000000000008152600401611f889190614618565b60405180910390fd5b5b50505050611fd8565b816040517fb96fcfe4000000000000000000000000000000000000000000000000000000008152600401611fcf919061471c565b60405180910390fd5b5b5050505050565b7f000000000000000000000000000000000000000000000000000000000000000081565b60007fbc37962d8bd1d319c95199bdfda6d3f92baa8903a61b32d5f4ec1f4b36a3bc1882600001602081019061203a91906142f2565b836020013584806040019061204f919061432e565b60405161205d929190614767565b6040518091039020858060600190612075919061432e565b604051612083929190614767565b604051809103902086608001358760a001358860c00135898060e001906120aa919061432e565b6040516120b8929190614767565b60405180910390207f00000000000000000000000000000000000000000000000000000000000000006040516020016120fa9a99989796959493929190614780565b604051602081830303815290604052805190602001209050919050565b60007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff163073ffffffffffffffffffffffffffffffffffffffff160361219e576040517f9f03a02600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b63f23a6e6160e01b905095945050505050565b6040518060400160405280600581526020017f312e332e3000000000000000000000000000000000000000000000000000000081525081565b60007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff163073ffffffffffffffffffffffffffffffffffffffff1614801561226657507f000000000000000000000000000000000000000000000000000000000000000046145b15612293577f0000000000000000000000000000000000000000000000000000000000000000905061229e565b61229b6129b1565b90505b90565b60006040517f190100000000000000000000000000000000000000000000000000000000000081528360028201528260228201526042812091505092915050565b60003073ffffffffffffffffffffffffffffffffffffffff166123498585858080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f82011690508083019250505050505050612a47565b73ffffffffffffffffffffffffffffffffffffffff160361237357631626ba7e60e01b905061237e565b63ffffffff60e01b90505b9392505050565b6000806123a2838580610100019061239d919061432e565b6122e2565b9050631626ba7e60e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916817bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916036123fa576000915050612400565b60019150505b92915050565b600081146124ef5760003373ffffffffffffffffffffffffffffffffffffffff16827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9060405161245690614842565b600060405180830381858888f193505050503d8060008114612494576040519150601f19603f3d011682016040523d82523d6000602084013e612499565b606091505b505090503373ffffffffffffffffffffffffffffffffffffffff167fa427c7d47f24d01b170779a7600b1d4c0d7cdbabaa0f19c4f0e6182053ffc93183836040516124e5929190614857565b60405180910390a2505b50565b6060604051905081838237600038838387895af1612513573d6000823e3d81fd5b3d8152602081013d6000823e3d810160405250949350505050565b606061256460007f0000000000000000000000000000000000000000000000000000000000000000612a7390919063ffffffff16565b905090565b606061259f60017f0000000000000000000000000000000000000000000000000000000000000000612a7390919063ffffffff16565b905090565b6000806000808493508460081b92508460301b91508460501b90509193509193565b6000817effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916837effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614905092915050565b6000817effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916837effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614905092915050565b6000817bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916837bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614905092915050565b3660008335840160208101925080359150509250929050565b606060008383905090508067ffffffffffffffff8111156126f0576126ef6130bb565b5b60405190808252806020026020018201604052801561272357816020015b606081526020019060019003908161270e5790505b50915060005b818110156127b5573685858381811061274557612744614633565b5b90506020028101906127579190614880565b905061278981600001602081019061276f91906142f2565b8260200135838060400190612784919061432e565b6124f2565b84838151811061279c5761279b614633565b5b6020026020010181905250508080600101915050612729565b505092915050565b606060008383905090508067ffffffffffffffff8111156127e1576127e06130bb565b5b60405190808252806020026020018201604052801561281457816020015b60608152602001906001900390816127ff5790505b50915060005b81811015612906573685858381811061283657612835614633565b5b90506020028101906128489190614880565b9050600061287c82600001602081019061286291906142f2565b8360200135848060400190612877919061432e565b61297c565b86858151811061288f5761288e614633565b5b602002602001018190528192505050806128f7577fe723f28f104e46b47fd3531f3608374ac226bcf3ddda334a23a266453e0efdb7838685815181106128d8576128d7614633565b5b60200260200101516040516128ee9291906148a8565b60405180910390a15b5050808060010191505061281a565b505092915050565b6000803660008585600090601492612928939291906148e2565b906129339190614961565b60601c9350858560149060349261294c939291906148e2565b9061295791906149c0565b60001c92508585603490809261296f939291906148e2565b9150915092959194509250565b600060606040519050828482376000388483888a5af11591503d8152602081013d6000823e3d81016040525094509492505050565b60007f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f7f00000000000000000000000000000000000000000000000000000000000000007f00000000000000000000000000000000000000000000000000000000000000004630604051602001612a2c959493929190614a1f565b60405160208183030381529060405280519060200120905090565b600080600080612a578686612b23565b925092509250612a678282612b7f565b82935050505092915050565b606060ff60001b8314612a9057612a8983612ce3565b9050612b1d565b818054612a9c90614aa1565b80601f0160208091040260200160405190810160405280929190818152602001828054612ac890614aa1565b8015612b155780601f10612aea57610100808354040283529160200191612b15565b820191906000526020600020905b815481529060010190602001808311612af857829003601f168201915b505050505090505b92915050565b60008060006041845103612b685760008060006020870151925060408701519150606087015160001a9050612b5a88828585612d57565b955095509550505050612b78565b60006002855160001b9250925092505b9250925092565b60006003811115612b9357612b92614ad2565b5b826003811115612ba657612ba5614ad2565b5b0315612cdf5760016003811115612bc057612bbf614ad2565b5b826003811115612bd357612bd2614ad2565b5b03612c0a576040517ff645eedf00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60026003811115612c1e57612c1d614ad2565b5b826003811115612c3157612c30614ad2565b5b03612c76578060001c6040517ffce698f7000000000000000000000000000000000000000000000000000000008152600401612c6d91906133fd565b60405180910390fd5b600380811115612c8957612c88614ad2565b5b826003811115612c9c57612c9b614ad2565b5b03612cde57806040517fd78bce0c000000000000000000000000000000000000000000000000000000008152600401612cd59190612ff1565b60405180910390fd5b5b5050565b60606000612cf083612e4b565b90506000602067ffffffffffffffff811115612d0f57612d0e6130bb565b5b6040519080825280601f01601f191660200182016040528015612d415781602001600182028036833780820191505090505b5090508181528360208201528092505050919050565b60008060007f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08460001c1115612d97576000600385925092509250612e41565b600060018888888860405160008152602001604052604051612dbc9493929190614b1d565b6020604051602081039080840390855afa158015612dde573d6000803e3d6000fd5b505050602060405103519050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603612e3257600060016000801b93509350935050612e41565b8060008060001b935093509350505b9450945094915050565b60008060ff8360001c169050601f811115612e92576040517fb3512b0c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80915050919050565b6000604051905090565b600080fd5b600080fd5b60007fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b612ee481612eaf565b8114612eef57600080fd5b50565b600081359050612f0181612edb565b92915050565b600060208284031215612f1d57612f1c612ea5565b5b6000612f2b84828501612ef2565b91505092915050565b60008115159050919050565b612f4981612f34565b82525050565b6000602082019050612f646000830184612f40565b92915050565b600080fd5b60006101208284031215612f8657612f85612f6a565b5b81905092915050565b600060208284031215612fa557612fa4612ea5565b5b600082013567ffffffffffffffff811115612fc357612fc2612eaa565b5b612fcf84828501612f6f565b91505092915050565b6000819050919050565b612feb81612fd8565b82525050565b60006020820190506130066000830184612fe2565b92915050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b60006130378261300c565b9050919050565b6130478161302c565b811461305257600080fd5b50565b6000813590506130648161303e565b92915050565b6000819050919050565b61307d8161306a565b811461308857600080fd5b50565b60008135905061309a81613074565b92915050565b600080fd5b600080fd5b6000601f19601f8301169050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6130f3826130aa565b810181811067ffffffffffffffff82111715613112576131116130bb565b5b80604052505050565b6000613125612e9b565b905061313182826130ea565b919050565b600067ffffffffffffffff821115613151576131506130bb565b5b61315a826130aa565b9050602081019050919050565b82818337600083830152505050565b600061318961318484613136565b61311b565b9050828152602081018484840111156131a5576131a46130a5565b5b6131b0848285613167565b509392505050565b600082601f8301126131cd576131cc6130a0565b5b81356131dd848260208601613176565b91505092915050565b60008060008060808587031215613200576131ff612ea5565b5b600061320e87828801613055565b945050602061321f87828801613055565b93505060406132308782880161308b565b925050606085013567ffffffffffffffff81111561325157613250612eaa565b5b61325d878288016131b8565b91505092959194509250565b61327281612eaf565b82525050565b600060208201905061328d6000830184613269565b92915050565b61329c81612fd8565b81146132a757600080fd5b50565b6000813590506132b981613293565b92915050565b600080fd5b600080fd5b60008083601f8401126132df576132de6130a0565b5b8235905067ffffffffffffffff8111156132fc576132fb6132bf565b5b602083019150836001820283011115613318576133176132c4565b5b9250929050565b60008060006040848603121561333857613337612ea5565b5b6000613346868287016132aa565b935050602084013567ffffffffffffffff81111561336757613366612eaa565b5b613373868287016132c9565b92509250509250925092565b60008060006060848603121561339857613397612ea5565b5b600084013567ffffffffffffffff8111156133b6576133b5612eaa565b5b6133c286828701612f6f565b93505060206133d3868287016132aa565b92505060406133e48682870161308b565b9150509250925092565b6133f78161306a565b82525050565b600060208201905061341260008301846133ee565b92915050565b600077ffffffffffffffffffffffffffffffffffffffffffffffff82169050919050565b61344581613418565b811461345057600080fd5b50565b6000813590506134628161343c565b92915050565b60006020828403121561347e5761347d612ea5565b5b600061348c84828501613453565b91505092915050565b600060c082840312156134ab576134aa612f6a565b5b81905092915050565b6000602082840312156134ca576134c9612ea5565b5b600082013567ffffffffffffffff8111156134e8576134e7612eaa565b5b6134f484828501613495565b91505092915050565b60006020828403121561351357613512612ea5565b5b6000613521848285016132aa565b91505092915050565b6000606082840312156135405761353f612f6a565b5b81905092915050565b60006020828403121561355f5761355e612ea5565b5b600082013567ffffffffffffffff81111561357d5761357c612eaa565b5b6135898482850161352a565b91505092915050565b600061359d8261300c565b9050919050565b6135ad81613592565b81146135b857600080fd5b50565b6000813590506135ca816135a4565b92915050565b600080604083850312156135e7576135e6612ea5565b5b60006135f5858286016135bb565b92505060206136068582860161308b565b9150509250929050565b60007fff0000000000000000000000000000000000000000000000000000000000000082169050919050565b61364581613610565b82525050565b600081519050919050565b600082825260208201905092915050565b60005b8381101561368557808201518184015260208101905061366a565b60008484015250505050565b600061369c8261364b565b6136a68185613656565b93506136b6818560208601613667565b6136bf816130aa565b840191505092915050565b6136d38161302c565b82525050565b600081519050919050565b600082825260208201905092915050565b6000819050602082019050919050565b61370e8161306a565b82525050565b60006137208383613705565b60208301905092915050565b6000602082019050919050565b6000613744826136d9565b61374e81856136e4565b9350613759836136f5565b8060005b8381101561378a5781516137718882613714565b975061377c8361372c565b92505060018101905061375d565b5085935050505092915050565b600060e0820190506137ac600083018a61363c565b81810360208301526137be8189613691565b905081810360408301526137d28188613691565b90506137e160608301876133ee565b6137ee60808301866136ca565b6137fb60a0830185612fe2565b81810360c083015261380d8184613739565b905098975050505050505050565b600060208201905081810360008301526138358184613691565b905092915050565b6000819050919050565b600061386261385d6138588461300c565b61383d565b61300c565b9050919050565b600061387482613847565b9050919050565b600061388682613869565b9050919050565b6138968161387b565b82525050565b60006020820190506138b1600083018461388d565b92915050565b600067ffffffffffffffff8211156138d2576138d16130bb565b5b602082029050602081019050919050565b60006138f66138f1846138b7565b61311b565b90508083825260208201905060208402830185811115613919576139186132c4565b5b835b81811015613942578061392e888261308b565b84526020840193505060208101905061391b565b5050509392505050565b600082601f830112613961576139606130a0565b5b81356139718482602086016138e3565b91505092915050565b600080600080600060a0868803121561399657613995612ea5565b5b60006139a488828901613055565b95505060206139b588828901613055565b945050604086013567ffffffffffffffff8111156139d6576139d5612eaa565b5b6139e28882890161394c565b935050606086013567ffffffffffffffff811115613a0357613a02612eaa565b5b613a0f8882890161394c565b925050608086013567ffffffffffffffff811115613a3057613a2f612eaa565b5b613a3c888289016131b8565b9150509295509295909350565b60008083601f840112613a5f57613a5e6130a0565b5b8235905067ffffffffffffffff811115613a7c57613a7b6132bf565b5b602083019150836020820283011115613a9857613a976132c4565b5b9250929050565b60008083601f840112613ab557613ab46130a0565b5b8235905067ffffffffffffffff811115613ad257613ad16132bf565b5b602083019150836020820283011115613aee57613aed6132c4565b5b9250929050565b60008060008060008060608789031215613b1257613b11612ea5565b5b600087013567ffffffffffffffff811115613b3057613b2f612eaa565b5b613b3c89828a01613a49565b9650965050602087013567ffffffffffffffff811115613b5f57613b5e612eaa565b5b613b6b89828a01613a9f565b9450945050604087013567ffffffffffffffff811115613b8e57613b8d612eaa565b5b613b9a89828a01613a49565b92509250509295509295509295565b613bb281612fd8565b8114613bbd57600080fd5b50565b600081359050613bcf81613ba9565b92915050565b600060208284031215613beb57613bea612ea5565b5b6000613bf984828501613bc0565b91505092915050565b600080600060408486031215613c1b57613c1a612ea5565b5b6000613c2986828701613bc0565b935050602084013567ffffffffffffffff811115613c4a57613c49612eaa565b5b613c56868287016132c9565b92509250509250925092565b600081519050919050565b600082825260208201905092915050565b6000819050602082019050919050565b600081519050919050565b600082825260208201905092915050565b6000613cb582613c8e565b613cbf8185613c99565b9350613ccf818560208601613667565b613cd8816130aa565b840191505092915050565b6000613cef8383613caa565b905092915050565b6000602082019050919050565b6000613d0f82613c62565b613d198185613c6d565b935083602082028501613d2b85613c7e565b8060005b85811015613d675784840389528151613d488582613ce3565b9450613d5383613cf7565b925060208a01995050600181019050613d2f565b50829750879550505050505092915050565b60006020820190508181036000830152613d938184613d04565b905092915050565b6000613da682613869565b9050919050565b613db681613d9b565b82525050565b6000602082019050613dd16000830184613dad565b92915050565b600080600080600060a08688031215613df357613df2612ea5565b5b6000613e0188828901613055565b9550506020613e1288828901613055565b9450506040613e238882890161308b565b9350506060613e348882890161308b565b925050608086013567ffffffffffffffff811115613e5557613e54612eaa565b5b613e61888289016131b8565b9150509295509295909350565b613e7781613418565b82525050565b6000604082019050613e9260008301856136ca565b613e9f6020830184613e6e565b9392505050565b600081519050613eb581613074565b92915050565b600060208284031215613ed157613ed0612ea5565b5b6000613edf84828501613ea6565b91505092915050565b6000613ef76020840184613055565b905092915050565b613f088161302c565b82525050565b6000613f1d60208401846132aa565b905092915050565b613f2e81612fd8565b82525050565b600080fd5b600080fd5b600080fd5b60008083356001602003843603038112613f6057613f5f613f3e565b5b83810192508235915060208301925067ffffffffffffffff821115613f8857613f87613f34565b5b602082023603831315613f9e57613f9d613f39565b5b509250929050565b600082825260208201905092915050565b6000819050919050565b60008083356001602003843603038112613fde57613fdd613f3e565b5b83810192508235915060208301925067ffffffffffffffff82111561400657614005613f34565b5b60018202360383131561401c5761401b613f39565b5b509250929050565b60006140308385613c99565b935061403d838584613167565b614046836130aa565b840190509392505050565b6000606083016140646000840184613ee8565b6140716000860182613eff565b5061407f6020840184613fc1565b8583036020870152614092838284614024565b925050506140a36040840184613fc1565b85830360408701526140b6838284614024565b925050508091505092915050565b60006140d08383614051565b905092915050565b6000823560016060038336030381126140f4576140f3613f3e565b5b82810191505092915050565b6000602082019050919050565b60006141198385613fa6565b93508360208402850161412b84613fb7565b8060005b8781101561416f57848403895261414682846140d8565b61415085826140c4565b945061415b83614100565b925060208a0199505060018101905061412f565b50829750879450505050509392505050565b6000614190602084018461308b565b905092915050565b600060c083016141ab6000840184613ee8565b6141b86000860182613eff565b506141c66020840184613ee8565b6141d36020860182613eff565b506141e16040840184613f0e565b6141ee6040860182613f25565b506141fc6060840184613f43565b858303606087015261420f83828461410d565b925050506142206080840184614181565b61422d6080860182613705565b5061423b60a0840184613fc1565b85830360a087015261424e838284614024565b925050508091505092915050565b600060208201905081810360008301526142768184614198565b905092915050565b61428781612f34565b811461429257600080fd5b50565b6000815190506142a48161427e565b92915050565b6000602082840312156142c0576142bf612ea5565b5b60006142ce84828501614295565b91505092915050565b60006020820190506142ec60008301846136ca565b92915050565b60006020828403121561430857614307612ea5565b5b600061431684828501613055565b91505092915050565b600080fd5b600080fd5b600080fd5b6000808335600160200384360303811261434b5761434a61431f565b5b80840192508235915067ffffffffffffffff82111561436d5761436c614324565b5b60208301925060018202360383131561438957614388614329565b5b509250929050565b61439a81613592565b82525050565b60006040820190506143b56000830185614391565b6143c260208301846133ee565b9392505050565b6000819050919050565b60006143e0848484614024565b90509392505050565b6000602082019050919050565b60006144028385613c6d565b935083602084028501614414846143c9565b8060005b8781101561445a57848403895261442f8284613fc1565b61443a8682846143d3565b9550614445846143e9565b935060208b019a505050600181019050614418565b50829750879450505050509392505050565b600082825260208201905092915050565b6000819050919050565b600061449282612fd8565b9050919050565b6144a281614487565b82525050565b60006144b48383614499565b60208301905092915050565b60006144cf6020840184613bc0565b905092915050565b6000602082019050919050565b60006144f0838561446c565b93506144fb8261447d565b8060005b858110156145345761451182846144c0565b61451b88826144a8565b9750614526836144d7565b9250506001810190506144ff565b5085925050509392505050565b6000606082019050818103600083015261455c81888a6143f6565b905081810360208301526145718186886144e4565b905081810360408301526145868184866143f6565b9050979650505050505050565b6000819050919050565b60006145b86145b36145ae84614593565b61383d565b613418565b9050919050565b6145c88161459d565b82525050565b60006040820190506145e360008301856136ca565b6145f060208301846145bf565b9392505050565b600061460282613610565b9050919050565b614612816145f7565b82525050565b600060208201905061462d6000830184614609565b92915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600061467d61467861467384614593565b61383d565b61306a565b9050919050565b61468d81614662565b82525050565b600082825260208201905092915050565b60006146af82613c8e565b6146b98185614693565b93506146c9818560208601613667565b6146d2816130aa565b840191505092915050565b60006040820190506146f26000830185614684565b818103602083015261470481846146a4565b90509392505050565b614716816145f7565b82525050565b6000602082019050614731600083018461470d565b92915050565b600081905092915050565b600061474e8385614737565b935061475b838584613167565b82840190509392505050565b6000614774828486614742565b91508190509392505050565b600061014082019050614796600083018d612fe2565b6147a3602083018c6136ca565b6147b0604083018b6133ee565b6147bd606083018a612fe2565b6147ca6080830189612fe2565b6147d760a0830188612fe2565b6147e460c08301876133ee565b6147f160e0830186612fe2565b6147ff610100830185612fe2565b61480d61012083018461388d565b9b9a5050505050505050505050565b50565b600061482c600083614737565b91506148378261481c565b600082019050919050565b600061484d8261481f565b9150819050919050565b600060408201905061486c60008301856133ee565b6148796020830184612f40565b9392505050565b60008235600160600383360303811261489c5761489b61431f565b5b80830191505092915050565b60006040820190506148bd60008301856133ee565b81810360208301526148cf81846146a4565b90509392505050565b600080fd5b600080fd5b600080858511156148f6576148f56148d8565b5b83861115614907576149066148dd565b5b6001850283019150848603905094509492505050565b600082905092915050565b60007fffffffffffffffffffffffffffffffffffffffff00000000000000000000000082169050919050565b600082821b905092915050565b600061496d838361491d565b826149788135614928565b925060148210156149b8576149b37fffffffffffffffffffffffffffffffffffffffff00000000000000000000000083601403600802614954565b831692505b505092915050565b60006149cc838361491d565b826149d78135612fd8565b92506020821015614a1757614a127fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff83602003600802614954565b831692505b505092915050565b600060a082019050614a346000830188612fe2565b614a416020830187612fe2565b614a4e6040830186612fe2565b614a5b60608301856133ee565b614a6860808301846136ca565b9695505050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b60006002820490506001821680614ab957607f821691505b602082108103614acc57614acb614a72565b5b50919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b600060ff82169050919050565b614b1781614b01565b82525050565b6000608082019050614b326000830187612fe2565b614b3f6020830186614b0e565b614b4c6040830185612fe2565b614b596060830184612fe2565b9594505050505056fea2646970667358221220844c650b3d2c0aceaf7c108a1ec343abb8963e1bdf5c88d4f28ea4bbdce3ff1a64736f6c63430008170033000000000000000000000000663f3ad617193148711d28f5334ee4ed070166020000000000000000000000002e983a1ba5e8b38aaaec4b440b9ddcfbf72e15d1", + "output": "0x6080604052600436106101c65760003560e01c806384b0196e116100f7578063d03c791411610095578063ea4d3c9b11610064578063ea4d3c9b1461066b578063ed8101b514610696578063f23a6e61146106d3578063ffa1ad7414610710576101cd565b8063d03c7914146105b7578063d087d288146105f4578063d691c9641461061f578063e9ae5c531461064f576101cd565b8063b0d691fe116100d1578063b0d691fe146104fb578063bc197c8114610526578063c399ec8814610563578063cef6d2091461058e576101cd565b806384b0196e14610474578063a3f4df7e146104a5578063acb8cc49146104d0576101cd565b80633ed01015116101645780634a58db191161013e5780634a58db19146103fa5780635c1c6dcd146104045780637f07bfdc1461042057806383ebb77114610449576101cd565b80633ed010151461036b578063445140b81461039457806349934047146103d1576101cd565b80631626ba7e116101a05780631626ba7e1461028957806319822f7c146102c65780632b3afd99146103035780633e1b08121461032e576101cd565b806301ffc9a7146101d257806306394d671461020f578063150b7a021461024c576101cd565b366101cd57005b600080fd5b3480156101de57600080fd5b506101f960048036038101906101f49190612f07565b61073b565b6040516102069190612f4f565b60405180910390f35b34801561021b57600080fd5b5061023660048036038101906102319190612f8f565b610a32565b6040516102439190612ff1565b60405180910390f35b34801561025857600080fd5b50610273600480360381019061026e91906131e6565b610a54565b6040516102809190613278565b60405180910390f35b34801561029557600080fd5b506102b060048036038101906102ab919061331f565b610aed565b6040516102bd9190613278565b60405180910390f35b3480156102d257600080fd5b506102ed60048036038101906102e8919061337f565b610b88565b6040516102fa91906133fd565b60405180910390f35b34801561030f57600080fd5b50610318610cb8565b6040516103259190612ff1565b60405180910390f35b34801561033a57600080fd5b5061035560048036038101906103509190613468565b610cdc565b60405161036291906133fd565b60405180910390f35b34801561037757600080fd5b50610392600480360381019061038d91906134b4565b610d81565b005b3480156103a057600080fd5b506103bb60048036038101906103b691906134fd565b610ece565b6040516103c89190612f4f565b60405180910390f35b3480156103dd57600080fd5b506103f860048036038101906103f391906134b4565b610f71565b005b6104026110be565b005b61041e60048036038101906104199190613549565b6111d1565b005b34801561042c57600080fd5b50610447600480360381019061044291906135d0565b6112c4565b005b34801561045557600080fd5b5061045e611414565b60405161046b9190612ff1565b60405180910390f35b34801561048057600080fd5b50610489611423565b60405161049c9796959493929190613797565b60405180910390f35b3480156104b157600080fd5b506104ba6114cd565b6040516104c7919061381b565b60405180910390f35b3480156104dc57600080fd5b506104e5611506565b6040516104f2919061381b565b60405180910390f35b34801561050757600080fd5b5061051061153f565b60405161051d919061389c565b60405180910390f35b34801561053257600080fd5b5061054d6004803603810190610548919061397a565b611563565b60405161055a9190613278565b60405180910390f35b34801561056f57600080fd5b506105786115fd565b60405161058591906133fd565b60405180910390f35b34801561059a57600080fd5b506105b560048036038101906105b09190613af5565b61169e565b005b3480156105c357600080fd5b506105de60048036038101906105d99190613bd5565b6117fa565b6040516105eb9190612f4f565b60405180910390f35b34801561060057600080fd5b506106096118ab565b60405161061691906133fd565b60405180910390f35b61063960048036038101906106349190613c02565b61194f565b6040516106469190613d79565b60405180910390f35b61066960048036038101906106649190613c02565b611c8b565b005b34801561067757600080fd5b50610680611fe0565b60405161068d9190613dbc565b60405180910390f35b3480156106a257600080fd5b506106bd60048036038101906106b89190612f8f565b612004565b6040516106ca9190612ff1565b60405180910390f35b3480156106df57600080fd5b506106fa60048036038101906106f59190613dd7565b612117565b6040516107079190613278565b60405180910390f35b34801561071c57600080fd5b506107256121b1565b604051610732919061381b565b60405180910390f35b60007f0000000000000000000000008438ad1c834623cff278ab6829a248e37c2d7e3f73ffffffffffffffffffffffffffffffffffffffff163073ffffffffffffffffffffffffffffffffffffffff16036107c2576040517f9f03a02600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7fd691c964000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916148061088b57507f150b7a02000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b806108f357507f4e2312e0000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b8061095b57507f01ffc9a7000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b806109c357507f1626ba7e000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b80610a2b57507f39922547000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b9050919050565b6000610a4d610a3f6121ea565b610a4884612004565b6122a1565b9050919050565b60007f0000000000000000000000008438ad1c834623cff278ab6829a248e37c2d7e3f73ffffffffffffffffffffffffffffffffffffffff163073ffffffffffffffffffffffffffffffffffffffff1603610adb576040517f9f03a02600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b63150b7a0260e01b9050949350505050565b60007f0000000000000000000000008438ad1c834623cff278ab6829a248e37c2d7e3f73ffffffffffffffffffffffffffffffffffffffff163073ffffffffffffffffffffffffffffffffffffffff1603610b74576040517f9f03a02600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610b7f8484846122e2565b90509392505050565b60007f0000000000000000000000002e983a1ba5e8b38aaaec4b440b9ddcfbf72e15d173ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610c0f576040517fd663742a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f0000000000000000000000008438ad1c834623cff278ab6829a248e37c2d7e3f73ffffffffffffffffffffffffffffffffffffffff163073ffffffffffffffffffffffffffffffffffffffff1603610c94576040517f9f03a02600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610ca684610ca186610a32565b612385565b9050610cb182612406565b9392505050565b7fbc37962d8bd1d319c95199bdfda6d3f92baa8903a61b32d5f4ec1f4b36a3bc1881565b60007f0000000000000000000000002e983a1ba5e8b38aaaec4b440b9ddcfbf72e15d173ffffffffffffffffffffffffffffffffffffffff166335567e1a30846040518363ffffffff1660e01b8152600401610d39929190613e7d565b602060405180830381865afa158015610d56573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d7a9190613ebb565b9050919050565b7f0000000000000000000000002e983a1ba5e8b38aaaec4b440b9ddcfbf72e15d173ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614158015610e0957503073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614155b15610e40576040517f0796d94500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f000000000000000000000000663f3ad617193148711d28f5334ee4ed0701660273ffffffffffffffffffffffffffffffffffffffff16633ed01015826040518263ffffffff1660e01b8152600401610e99919061425c565b600060405180830381600087803b158015610eb357600080fd5b505af1158015610ec7573d6000803e3d6000fd5b5050505050565b60007f000000000000000000000000663f3ad617193148711d28f5334ee4ed0701660273ffffffffffffffffffffffffffffffffffffffff16632d40d052836040518263ffffffff1660e01b8152600401610f299190612ff1565b602060405180830381865afa158015610f46573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f6a91906142aa565b9050919050565b7f0000000000000000000000002e983a1ba5e8b38aaaec4b440b9ddcfbf72e15d173ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614158015610ff957503073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614155b15611030576040517f0796d94500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f000000000000000000000000663f3ad617193148711d28f5334ee4ed0701660273ffffffffffffffffffffffffffffffffffffffff166349934047826040518263ffffffff1660e01b8152600401611089919061425c565b600060405180830381600087803b1580156110a357600080fd5b505af11580156110b7573d6000803e3d6000fd5b5050505050565b7f0000000000000000000000008438ad1c834623cff278ab6829a248e37c2d7e3f73ffffffffffffffffffffffffffffffffffffffff163073ffffffffffffffffffffffffffffffffffffffff1603611143576040517f9f03a02600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f0000000000000000000000002e983a1ba5e8b38aaaec4b440b9ddcfbf72e15d173ffffffffffffffffffffffffffffffffffffffff1663b760faf934306040518363ffffffff1660e01b815260040161119d91906142d7565b6000604051808303818588803b1580156111b657600080fd5b505af11580156111ca573d6000803e3d6000fd5b5050505050565b7f0000000000000000000000002e983a1ba5e8b38aaaec4b440b9ddcfbf72e15d173ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161415801561125957503073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614155b15611290576040517f0796d94500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6112c08160000160208101906112a691906142f2565b82602001358380604001906112bb919061432e565b6124f2565b5050565b7f0000000000000000000000002e983a1ba5e8b38aaaec4b440b9ddcfbf72e15d173ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161415801561134c57503073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614155b15611383576040517f0796d94500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f0000000000000000000000002e983a1ba5e8b38aaaec4b440b9ddcfbf72e15d173ffffffffffffffffffffffffffffffffffffffff1663205c287883836040518363ffffffff1660e01b81526004016113de9291906143a0565b600060405180830381600087803b1580156113f857600080fd5b505af115801561140c573d6000803e3d6000fd5b505050505050565b600061141e6121ea565b905090565b60006060806000806000606061143761252e565b61143f612569565b46306000801b600067ffffffffffffffff8111156114605761145f6130bb565b5b60405190808252806020026020018201604052801561148e5781602001602082028036833780820191505090505b507f0f00000000000000000000000000000000000000000000000000000000000000959493929190965096509650965096509650965090919293949596565b6040518060400160405280601981526020017f4549503737303253746174656c65737344656c654761746f720000000000000081525081565b6040518060400160405280600181526020017f310000000000000000000000000000000000000000000000000000000000000081525081565b7f0000000000000000000000002e983a1ba5e8b38aaaec4b440b9ddcfbf72e15d181565b60007f0000000000000000000000008438ad1c834623cff278ab6829a248e37c2d7e3f73ffffffffffffffffffffffffffffffffffffffff163073ffffffffffffffffffffffffffffffffffffffff16036115ea576040517f9f03a02600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b63bc197c8160e01b905095945050505050565b60007f0000000000000000000000002e983a1ba5e8b38aaaec4b440b9ddcfbf72e15d173ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b815260040161165891906142d7565b602060405180830381865afa158015611675573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116999190613ebb565b905090565b7f0000000000000000000000002e983a1ba5e8b38aaaec4b440b9ddcfbf72e15d173ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161415801561172657503073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614155b1561175d576040517f0796d94500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f000000000000000000000000663f3ad617193148711d28f5334ee4ed0701660273ffffffffffffffffffffffffffffffffffffffff1663cef6d2098787878787876040518763ffffffff1660e01b81526004016117c096959493929190614541565b600060405180830381600087803b1580156117da57600080fd5b505af11580156117ee573d6000803e3d6000fd5b50505050505050505050565b600080600080600061180b866125a4565b935093509350935061182184600060f81b6125c6565b80611836575061183584600160f81b6125c6565b5b8015611861575061184b83600060f81b612617565b80611860575061185f83600160f81b612617565b5b5b8015611877575061187682600060e01b612668565b5b80156118a05750600060501b69ffffffffffffffffffff19168169ffffffffffffffffffff1916145b945050505050919050565b60007f0000000000000000000000002e983a1ba5e8b38aaaec4b440b9ddcfbf72e15d173ffffffffffffffffffffffffffffffffffffffff166335567e1a3060006040518363ffffffff1660e01b81526004016119099291906145ce565b602060405180830381865afa158015611926573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061194a9190613ebb565b905090565b60607f000000000000000000000000663f3ad617193148711d28f5334ee4ed0701660273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146119d6576040517f1a4b3a0400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000806119e2866125a4565b5050915091506119f682600160f81b6125c6565b15611a9957366000611a0887876126b3565b91509150611a1a83600060f81b612617565b15611a3057611a2982826126cc565b9450611a92565b611a3e83600160f81b612617565b15611a5457611a4d82826127bd565b9450611a91565b826040517f1187dc06000000000000000000000000000000000000000000000000000000008152600401611a889190614618565b60405180910390fd5b5b5050611c82565b611aa782600060f81b6125c6565b15611c4457600080366000611abc898961290e565b9350935093509350600167ffffffffffffffff811115611adf57611ade6130bb565b5b604051908082528060200260200182016040528015611b1257816020015b6060815260200190600190039081611afd5790505b5096506000611b2586600060f81b612617565b15611b5a57611b36858585856124f2565b88600081518110611b4a57611b49614633565b5b6020026020010181905250611c3a565b611b6886600160f81b612617565b15611bfc57611b798585858561297c565b89600081518110611b8d57611b8c614633565b5b60200260200101819052819250505080611bf7577fe723f28f104e46b47fd3531f3608374ac226bcf3ddda334a23a266453e0efdb7600089600081518110611bd857611bd7614633565b5b6020026020010151604051611bee9291906146dd565b60405180910390a15b611c39565b856040517f1187dc06000000000000000000000000000000000000000000000000000000008152600401611c309190614618565b60405180910390fd5b5b5050505050611c81565b816040517fb96fcfe4000000000000000000000000000000000000000000000000000000008152600401611c78919061471c565b60405180910390fd5b5b50509392505050565b7f0000000000000000000000002e983a1ba5e8b38aaaec4b440b9ddcfbf72e15d173ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614158015611d1357503073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614155b15611d4a576040517f0796d94500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600080611d56856125a4565b505091509150611d6a82600160f81b6125c6565b15611e0b57366000611d7c86866126b3565b91509150611d8e83600060f81b612617565b15611da357611d9d82826126cc565b50611e04565b611db183600160f81b612617565b15611dc657611dc082826127bd565b50611e03565b826040517f1187dc06000000000000000000000000000000000000000000000000000000008152600401611dfa9190614618565b60405180910390fd5b5b5050611fd9565b611e1982600060f81b6125c6565b15611f9b57600080366000611e2e888861290e565b9350935093509350611e4485600060f81b612617565b15611e5b57611e55848484846124f2565b50611f92565b611e6985600160f81b612617565b15611f54576000600167ffffffffffffffff811115611e8b57611e8a6130bb565b5b604051908082528060200260200182016040528015611ebe57816020015b6060815260200190600190039081611ea95790505b5090506000611ecf8686868661297c565b83600081518110611ee357611ee2614633565b5b60200260200101819052819250505080611f4d577fe723f28f104e46b47fd3531f3608374ac226bcf3ddda334a23a266453e0efdb7600083600081518110611f2e57611f2d614633565b5b6020026020010151604051611f449291906146dd565b60405180910390a15b5050611f91565b846040517f1187dc06000000000000000000000000000000000000000000000000000000008152600401611f889190614618565b60405180910390fd5b5b50505050611fd8565b816040517fb96fcfe4000000000000000000000000000000000000000000000000000000008152600401611fcf919061471c565b60405180910390fd5b5b5050505050565b7f000000000000000000000000663f3ad617193148711d28f5334ee4ed0701660281565b60007fbc37962d8bd1d319c95199bdfda6d3f92baa8903a61b32d5f4ec1f4b36a3bc1882600001602081019061203a91906142f2565b836020013584806040019061204f919061432e565b60405161205d929190614767565b6040518091039020858060600190612075919061432e565b604051612083929190614767565b604051809103902086608001358760a001358860c00135898060e001906120aa919061432e565b6040516120b8929190614767565b60405180910390207f0000000000000000000000002e983a1ba5e8b38aaaec4b440b9ddcfbf72e15d16040516020016120fa9a99989796959493929190614780565b604051602081830303815290604052805190602001209050919050565b60007f0000000000000000000000008438ad1c834623cff278ab6829a248e37c2d7e3f73ffffffffffffffffffffffffffffffffffffffff163073ffffffffffffffffffffffffffffffffffffffff160361219e576040517f9f03a02600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b63f23a6e6160e01b905095945050505050565b6040518060400160405280600581526020017f312e332e3000000000000000000000000000000000000000000000000000000081525081565b60007f0000000000000000000000008438ad1c834623cff278ab6829a248e37c2d7e3f73ffffffffffffffffffffffffffffffffffffffff163073ffffffffffffffffffffffffffffffffffffffff1614801561226657507f000000000000000000000000000000000000000000000000000000000000053946145b15612293577f6e94388684165b3a90707922416b4045e752f62b048c387b3db54648f016a2d8905061229e565b61229b6129b1565b90505b90565b60006040517f190100000000000000000000000000000000000000000000000000000000000081528360028201528260228201526042812091505092915050565b60003073ffffffffffffffffffffffffffffffffffffffff166123498585858080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f82011690508083019250505050505050612a47565b73ffffffffffffffffffffffffffffffffffffffff160361237357631626ba7e60e01b905061237e565b63ffffffff60e01b90505b9392505050565b6000806123a2838580610100019061239d919061432e565b6122e2565b9050631626ba7e60e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916817bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916036123fa576000915050612400565b60019150505b92915050565b600081146124ef5760003373ffffffffffffffffffffffffffffffffffffffff16827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9060405161245690614842565b600060405180830381858888f193505050503d8060008114612494576040519150601f19603f3d011682016040523d82523d6000602084013e612499565b606091505b505090503373ffffffffffffffffffffffffffffffffffffffff167fa427c7d47f24d01b170779a7600b1d4c0d7cdbabaa0f19c4f0e6182053ffc93183836040516124e5929190614857565b60405180910390a2505b50565b6060604051905081838237600038838387895af1612513573d6000823e3d81fd5b3d8152602081013d6000823e3d810160405250949350505050565b606061256460007f4549503737303253746174656c65737344656c654761746f7200000000000019612a7390919063ffffffff16565b905090565b606061259f60017f3100000000000000000000000000000000000000000000000000000000000001612a7390919063ffffffff16565b905090565b6000806000808493508460081b92508460301b91508460501b90509193509193565b6000817effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916837effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614905092915050565b6000817effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916837effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614905092915050565b6000817bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916837bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614905092915050565b3660008335840160208101925080359150509250929050565b606060008383905090508067ffffffffffffffff8111156126f0576126ef6130bb565b5b60405190808252806020026020018201604052801561272357816020015b606081526020019060019003908161270e5790505b50915060005b818110156127b5573685858381811061274557612744614633565b5b90506020028101906127579190614880565b905061278981600001602081019061276f91906142f2565b8260200135838060400190612784919061432e565b6124f2565b84838151811061279c5761279b614633565b5b6020026020010181905250508080600101915050612729565b505092915050565b606060008383905090508067ffffffffffffffff8111156127e1576127e06130bb565b5b60405190808252806020026020018201604052801561281457816020015b60608152602001906001900390816127ff5790505b50915060005b81811015612906573685858381811061283657612835614633565b5b90506020028101906128489190614880565b9050600061287c82600001602081019061286291906142f2565b8360200135848060400190612877919061432e565b61297c565b86858151811061288f5761288e614633565b5b602002602001018190528192505050806128f7577fe723f28f104e46b47fd3531f3608374ac226bcf3ddda334a23a266453e0efdb7838685815181106128d8576128d7614633565b5b60200260200101516040516128ee9291906148a8565b60405180910390a15b5050808060010191505061281a565b505092915050565b6000803660008585600090601492612928939291906148e2565b906129339190614961565b60601c9350858560149060349261294c939291906148e2565b9061295791906149c0565b60001c92508585603490809261296f939291906148e2565b9150915092959194509250565b600060606040519050828482376000388483888a5af11591503d8152602081013d6000823e3d81016040525094509492505050565b60007f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f7f87e2b3436f0f6d8494dfcb826d860322ea231814dba9eb086540f62b8561c57b7fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc64630604051602001612a2c959493929190614a1f565b60405160208183030381529060405280519060200120905090565b600080600080612a578686612b23565b925092509250612a678282612b7f565b82935050505092915050565b606060ff60001b8314612a9057612a8983612ce3565b9050612b1d565b818054612a9c90614aa1565b80601f0160208091040260200160405190810160405280929190818152602001828054612ac890614aa1565b8015612b155780601f10612aea57610100808354040283529160200191612b15565b820191906000526020600020905b815481529060010190602001808311612af857829003601f168201915b505050505090505b92915050565b60008060006041845103612b685760008060006020870151925060408701519150606087015160001a9050612b5a88828585612d57565b955095509550505050612b78565b60006002855160001b9250925092505b9250925092565b60006003811115612b9357612b92614ad2565b5b826003811115612ba657612ba5614ad2565b5b0315612cdf5760016003811115612bc057612bbf614ad2565b5b826003811115612bd357612bd2614ad2565b5b03612c0a576040517ff645eedf00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60026003811115612c1e57612c1d614ad2565b5b826003811115612c3157612c30614ad2565b5b03612c76578060001c6040517ffce698f7000000000000000000000000000000000000000000000000000000008152600401612c6d91906133fd565b60405180910390fd5b600380811115612c8957612c88614ad2565b5b826003811115612c9c57612c9b614ad2565b5b03612cde57806040517fd78bce0c000000000000000000000000000000000000000000000000000000008152600401612cd59190612ff1565b60405180910390fd5b5b5050565b60606000612cf083612e4b565b90506000602067ffffffffffffffff811115612d0f57612d0e6130bb565b5b6040519080825280601f01601f191660200182016040528015612d415781602001600182028036833780820191505090505b5090508181528360208201528092505050919050565b60008060007f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08460001c1115612d97576000600385925092509250612e41565b600060018888888860405160008152602001604052604051612dbc9493929190614b1d565b6020604051602081039080840390855afa158015612dde573d6000803e3d6000fd5b505050602060405103519050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603612e3257600060016000801b93509350935050612e41565b8060008060001b935093509350505b9450945094915050565b60008060ff8360001c169050601f811115612e92576040517fb3512b0c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80915050919050565b6000604051905090565b600080fd5b600080fd5b60007fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b612ee481612eaf565b8114612eef57600080fd5b50565b600081359050612f0181612edb565b92915050565b600060208284031215612f1d57612f1c612ea5565b5b6000612f2b84828501612ef2565b91505092915050565b60008115159050919050565b612f4981612f34565b82525050565b6000602082019050612f646000830184612f40565b92915050565b600080fd5b60006101208284031215612f8657612f85612f6a565b5b81905092915050565b600060208284031215612fa557612fa4612ea5565b5b600082013567ffffffffffffffff811115612fc357612fc2612eaa565b5b612fcf84828501612f6f565b91505092915050565b6000819050919050565b612feb81612fd8565b82525050565b60006020820190506130066000830184612fe2565b92915050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b60006130378261300c565b9050919050565b6130478161302c565b811461305257600080fd5b50565b6000813590506130648161303e565b92915050565b6000819050919050565b61307d8161306a565b811461308857600080fd5b50565b60008135905061309a81613074565b92915050565b600080fd5b600080fd5b6000601f19601f8301169050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6130f3826130aa565b810181811067ffffffffffffffff82111715613112576131116130bb565b5b80604052505050565b6000613125612e9b565b905061313182826130ea565b919050565b600067ffffffffffffffff821115613151576131506130bb565b5b61315a826130aa565b9050602081019050919050565b82818337600083830152505050565b600061318961318484613136565b61311b565b9050828152602081018484840111156131a5576131a46130a5565b5b6131b0848285613167565b509392505050565b600082601f8301126131cd576131cc6130a0565b5b81356131dd848260208601613176565b91505092915050565b60008060008060808587031215613200576131ff612ea5565b5b600061320e87828801613055565b945050602061321f87828801613055565b93505060406132308782880161308b565b925050606085013567ffffffffffffffff81111561325157613250612eaa565b5b61325d878288016131b8565b91505092959194509250565b61327281612eaf565b82525050565b600060208201905061328d6000830184613269565b92915050565b61329c81612fd8565b81146132a757600080fd5b50565b6000813590506132b981613293565b92915050565b600080fd5b600080fd5b60008083601f8401126132df576132de6130a0565b5b8235905067ffffffffffffffff8111156132fc576132fb6132bf565b5b602083019150836001820283011115613318576133176132c4565b5b9250929050565b60008060006040848603121561333857613337612ea5565b5b6000613346868287016132aa565b935050602084013567ffffffffffffffff81111561336757613366612eaa565b5b613373868287016132c9565b92509250509250925092565b60008060006060848603121561339857613397612ea5565b5b600084013567ffffffffffffffff8111156133b6576133b5612eaa565b5b6133c286828701612f6f565b93505060206133d3868287016132aa565b92505060406133e48682870161308b565b9150509250925092565b6133f78161306a565b82525050565b600060208201905061341260008301846133ee565b92915050565b600077ffffffffffffffffffffffffffffffffffffffffffffffff82169050919050565b61344581613418565b811461345057600080fd5b50565b6000813590506134628161343c565b92915050565b60006020828403121561347e5761347d612ea5565b5b600061348c84828501613453565b91505092915050565b600060c082840312156134ab576134aa612f6a565b5b81905092915050565b6000602082840312156134ca576134c9612ea5565b5b600082013567ffffffffffffffff8111156134e8576134e7612eaa565b5b6134f484828501613495565b91505092915050565b60006020828403121561351357613512612ea5565b5b6000613521848285016132aa565b91505092915050565b6000606082840312156135405761353f612f6a565b5b81905092915050565b60006020828403121561355f5761355e612ea5565b5b600082013567ffffffffffffffff81111561357d5761357c612eaa565b5b6135898482850161352a565b91505092915050565b600061359d8261300c565b9050919050565b6135ad81613592565b81146135b857600080fd5b50565b6000813590506135ca816135a4565b92915050565b600080604083850312156135e7576135e6612ea5565b5b60006135f5858286016135bb565b92505060206136068582860161308b565b9150509250929050565b60007fff0000000000000000000000000000000000000000000000000000000000000082169050919050565b61364581613610565b82525050565b600081519050919050565b600082825260208201905092915050565b60005b8381101561368557808201518184015260208101905061366a565b60008484015250505050565b600061369c8261364b565b6136a68185613656565b93506136b6818560208601613667565b6136bf816130aa565b840191505092915050565b6136d38161302c565b82525050565b600081519050919050565b600082825260208201905092915050565b6000819050602082019050919050565b61370e8161306a565b82525050565b60006137208383613705565b60208301905092915050565b6000602082019050919050565b6000613744826136d9565b61374e81856136e4565b9350613759836136f5565b8060005b8381101561378a5781516137718882613714565b975061377c8361372c565b92505060018101905061375d565b5085935050505092915050565b600060e0820190506137ac600083018a61363c565b81810360208301526137be8189613691565b905081810360408301526137d28188613691565b90506137e160608301876133ee565b6137ee60808301866136ca565b6137fb60a0830185612fe2565b81810360c083015261380d8184613739565b905098975050505050505050565b600060208201905081810360008301526138358184613691565b905092915050565b6000819050919050565b600061386261385d6138588461300c565b61383d565b61300c565b9050919050565b600061387482613847565b9050919050565b600061388682613869565b9050919050565b6138968161387b565b82525050565b60006020820190506138b1600083018461388d565b92915050565b600067ffffffffffffffff8211156138d2576138d16130bb565b5b602082029050602081019050919050565b60006138f66138f1846138b7565b61311b565b90508083825260208201905060208402830185811115613919576139186132c4565b5b835b81811015613942578061392e888261308b565b84526020840193505060208101905061391b565b5050509392505050565b600082601f830112613961576139606130a0565b5b81356139718482602086016138e3565b91505092915050565b600080600080600060a0868803121561399657613995612ea5565b5b60006139a488828901613055565b95505060206139b588828901613055565b945050604086013567ffffffffffffffff8111156139d6576139d5612eaa565b5b6139e28882890161394c565b935050606086013567ffffffffffffffff811115613a0357613a02612eaa565b5b613a0f8882890161394c565b925050608086013567ffffffffffffffff811115613a3057613a2f612eaa565b5b613a3c888289016131b8565b9150509295509295909350565b60008083601f840112613a5f57613a5e6130a0565b5b8235905067ffffffffffffffff811115613a7c57613a7b6132bf565b5b602083019150836020820283011115613a9857613a976132c4565b5b9250929050565b60008083601f840112613ab557613ab46130a0565b5b8235905067ffffffffffffffff811115613ad257613ad16132bf565b5b602083019150836020820283011115613aee57613aed6132c4565b5b9250929050565b60008060008060008060608789031215613b1257613b11612ea5565b5b600087013567ffffffffffffffff811115613b3057613b2f612eaa565b5b613b3c89828a01613a49565b9650965050602087013567ffffffffffffffff811115613b5f57613b5e612eaa565b5b613b6b89828a01613a9f565b9450945050604087013567ffffffffffffffff811115613b8e57613b8d612eaa565b5b613b9a89828a01613a49565b92509250509295509295509295565b613bb281612fd8565b8114613bbd57600080fd5b50565b600081359050613bcf81613ba9565b92915050565b600060208284031215613beb57613bea612ea5565b5b6000613bf984828501613bc0565b91505092915050565b600080600060408486031215613c1b57613c1a612ea5565b5b6000613c2986828701613bc0565b935050602084013567ffffffffffffffff811115613c4a57613c49612eaa565b5b613c56868287016132c9565b92509250509250925092565b600081519050919050565b600082825260208201905092915050565b6000819050602082019050919050565b600081519050919050565b600082825260208201905092915050565b6000613cb582613c8e565b613cbf8185613c99565b9350613ccf818560208601613667565b613cd8816130aa565b840191505092915050565b6000613cef8383613caa565b905092915050565b6000602082019050919050565b6000613d0f82613c62565b613d198185613c6d565b935083602082028501613d2b85613c7e565b8060005b85811015613d675784840389528151613d488582613ce3565b9450613d5383613cf7565b925060208a01995050600181019050613d2f565b50829750879550505050505092915050565b60006020820190508181036000830152613d938184613d04565b905092915050565b6000613da682613869565b9050919050565b613db681613d9b565b82525050565b6000602082019050613dd16000830184613dad565b92915050565b600080600080600060a08688031215613df357613df2612ea5565b5b6000613e0188828901613055565b9550506020613e1288828901613055565b9450506040613e238882890161308b565b9350506060613e348882890161308b565b925050608086013567ffffffffffffffff811115613e5557613e54612eaa565b5b613e61888289016131b8565b9150509295509295909350565b613e7781613418565b82525050565b6000604082019050613e9260008301856136ca565b613e9f6020830184613e6e565b9392505050565b600081519050613eb581613074565b92915050565b600060208284031215613ed157613ed0612ea5565b5b6000613edf84828501613ea6565b91505092915050565b6000613ef76020840184613055565b905092915050565b613f088161302c565b82525050565b6000613f1d60208401846132aa565b905092915050565b613f2e81612fd8565b82525050565b600080fd5b600080fd5b600080fd5b60008083356001602003843603038112613f6057613f5f613f3e565b5b83810192508235915060208301925067ffffffffffffffff821115613f8857613f87613f34565b5b602082023603831315613f9e57613f9d613f39565b5b509250929050565b600082825260208201905092915050565b6000819050919050565b60008083356001602003843603038112613fde57613fdd613f3e565b5b83810192508235915060208301925067ffffffffffffffff82111561400657614005613f34565b5b60018202360383131561401c5761401b613f39565b5b509250929050565b60006140308385613c99565b935061403d838584613167565b614046836130aa565b840190509392505050565b6000606083016140646000840184613ee8565b6140716000860182613eff565b5061407f6020840184613fc1565b8583036020870152614092838284614024565b925050506140a36040840184613fc1565b85830360408701526140b6838284614024565b925050508091505092915050565b60006140d08383614051565b905092915050565b6000823560016060038336030381126140f4576140f3613f3e565b5b82810191505092915050565b6000602082019050919050565b60006141198385613fa6565b93508360208402850161412b84613fb7565b8060005b8781101561416f57848403895261414682846140d8565b61415085826140c4565b945061415b83614100565b925060208a0199505060018101905061412f565b50829750879450505050509392505050565b6000614190602084018461308b565b905092915050565b600060c083016141ab6000840184613ee8565b6141b86000860182613eff565b506141c66020840184613ee8565b6141d36020860182613eff565b506141e16040840184613f0e565b6141ee6040860182613f25565b506141fc6060840184613f43565b858303606087015261420f83828461410d565b925050506142206080840184614181565b61422d6080860182613705565b5061423b60a0840184613fc1565b85830360a087015261424e838284614024565b925050508091505092915050565b600060208201905081810360008301526142768184614198565b905092915050565b61428781612f34565b811461429257600080fd5b50565b6000815190506142a48161427e565b92915050565b6000602082840312156142c0576142bf612ea5565b5b60006142ce84828501614295565b91505092915050565b60006020820190506142ec60008301846136ca565b92915050565b60006020828403121561430857614307612ea5565b5b600061431684828501613055565b91505092915050565b600080fd5b600080fd5b600080fd5b6000808335600160200384360303811261434b5761434a61431f565b5b80840192508235915067ffffffffffffffff82111561436d5761436c614324565b5b60208301925060018202360383131561438957614388614329565b5b509250929050565b61439a81613592565b82525050565b60006040820190506143b56000830185614391565b6143c260208301846133ee565b9392505050565b6000819050919050565b60006143e0848484614024565b90509392505050565b6000602082019050919050565b60006144028385613c6d565b935083602084028501614414846143c9565b8060005b8781101561445a57848403895261442f8284613fc1565b61443a8682846143d3565b9550614445846143e9565b935060208b019a505050600181019050614418565b50829750879450505050509392505050565b600082825260208201905092915050565b6000819050919050565b600061449282612fd8565b9050919050565b6144a281614487565b82525050565b60006144b48383614499565b60208301905092915050565b60006144cf6020840184613bc0565b905092915050565b6000602082019050919050565b60006144f0838561446c565b93506144fb8261447d565b8060005b858110156145345761451182846144c0565b61451b88826144a8565b9750614526836144d7565b9250506001810190506144ff565b5085925050509392505050565b6000606082019050818103600083015261455c81888a6143f6565b905081810360208301526145718186886144e4565b905081810360408301526145868184866143f6565b9050979650505050505050565b6000819050919050565b60006145b86145b36145ae84614593565b61383d565b613418565b9050919050565b6145c88161459d565b82525050565b60006040820190506145e360008301856136ca565b6145f060208301846145bf565b9392505050565b600061460282613610565b9050919050565b614612816145f7565b82525050565b600060208201905061462d6000830184614609565b92915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600061467d61467861467384614593565b61383d565b61306a565b9050919050565b61468d81614662565b82525050565b600082825260208201905092915050565b60006146af82613c8e565b6146b98185614693565b93506146c9818560208601613667565b6146d2816130aa565b840191505092915050565b60006040820190506146f26000830185614684565b818103602083015261470481846146a4565b90509392505050565b614716816145f7565b82525050565b6000602082019050614731600083018461470d565b92915050565b600081905092915050565b600061474e8385614737565b935061475b838584613167565b82840190509392505050565b6000614774828486614742565b91508190509392505050565b600061014082019050614796600083018d612fe2565b6147a3602083018c6136ca565b6147b0604083018b6133ee565b6147bd606083018a612fe2565b6147ca6080830189612fe2565b6147d760a0830188612fe2565b6147e460c08301876133ee565b6147f160e0830186612fe2565b6147ff610100830185612fe2565b61480d61012083018461388d565b9b9a5050505050505050505050565b50565b600061482c600083614737565b91506148378261481c565b600082019050919050565b600061484d8261481f565b9150819050919050565b600060408201905061486c60008301856133ee565b6148796020830184612f40565b9392505050565b60008235600160600383360303811261489c5761489b61431f565b5b80830191505092915050565b60006040820190506148bd60008301856133ee565b81810360208301526148cf81846146a4565b90509392505050565b600080fd5b600080fd5b600080858511156148f6576148f56148d8565b5b83861115614907576149066148dd565b5b6001850283019150848603905094509492505050565b600082905092915050565b60007fffffffffffffffffffffffffffffffffffffffff00000000000000000000000082169050919050565b600082821b905092915050565b600061496d838361491d565b826149788135614928565b925060148210156149b8576149b37fffffffffffffffffffffffffffffffffffffffff00000000000000000000000083601403600802614954565b831692505b505092915050565b60006149cc838361491d565b826149d78135612fd8565b92506020821015614a1757614a127fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff83602003600802614954565b831692505b505092915050565b600060a082019050614a346000830188612fe2565b614a416020830187612fe2565b614a4e6040830186612fe2565b614a5b60608301856133ee565b614a6860808301846136ca565b9695505050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b60006002820490506001821680614ab957607f821691505b602082108103614acc57614acb614a72565b5b50919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b600060ff82169050919050565b614b1781614b01565b82525050565b6000608082019050614b326000830187612fe2565b614b3f6020830186614b0e565b614b4c6040830185612fe2565b614b596060830184612fe2565b9594505050505056fea2646970667358221220844c650b3d2c0aceaf7c108a1ec343abb8963e1bdf5c88d4f28ea4bbdce3ff1a64736f6c63430008170033", + "gas_used": 3880805, + "gas_limit": 3880805, + "status": "Return", + "steps": [], + "decoded": { + "label": null, + "return_data": null, + "call_data": null + } + }, + "logs": [ + { + "raw_log": { + "topics": [ + "0xb2e8eb88b584ae71ef4e854c10847f4d39bd93e52599f147bfb4dcc8de52014d", + "0x000000000000000000000000663f3ad617193148711d28f5334ee4ed07016602" + ], + "data": "0x" + }, + "decoded": { "name": null, "params": null }, + "position": 0 + }, + { + "raw_log": { + "topics": [ + "0xee8699dc0e27105da2653bdba54be0edcaadc3e33890a3ad705517ffe9bf0a99", + "0x0000000000000000000000002e983a1ba5e8b38aaaec4b440b9ddcfbf72e15d1" + ], + "data": "0x" + }, + "decoded": { "name": null, "params": null }, + "position": 0 + } + ], + "ordering": [{ "Log": 0 }, { "Log": 1 }] + } + ], + "exit": "Return", + "out": "0x6080604052600436106101c65760003560e01c806384b0196e116100f7578063d03c791411610095578063ea4d3c9b11610064578063ea4d3c9b1461066b578063ed8101b514610696578063f23a6e61146106d3578063ffa1ad7414610710576101cd565b8063d03c7914146105b7578063d087d288146105f4578063d691c9641461061f578063e9ae5c531461064f576101cd565b8063b0d691fe116100d1578063b0d691fe146104fb578063bc197c8114610526578063c399ec8814610563578063cef6d2091461058e576101cd565b806384b0196e14610474578063a3f4df7e146104a5578063acb8cc49146104d0576101cd565b80633ed01015116101645780634a58db191161013e5780634a58db19146103fa5780635c1c6dcd146104045780637f07bfdc1461042057806383ebb77114610449576101cd565b80633ed010151461036b578063445140b81461039457806349934047146103d1576101cd565b80631626ba7e116101a05780631626ba7e1461028957806319822f7c146102c65780632b3afd99146103035780633e1b08121461032e576101cd565b806301ffc9a7146101d257806306394d671461020f578063150b7a021461024c576101cd565b366101cd57005b600080fd5b3480156101de57600080fd5b506101f960048036038101906101f49190612f07565b61073b565b6040516102069190612f4f565b60405180910390f35b34801561021b57600080fd5b5061023660048036038101906102319190612f8f565b610a32565b6040516102439190612ff1565b60405180910390f35b34801561025857600080fd5b50610273600480360381019061026e91906131e6565b610a54565b6040516102809190613278565b60405180910390f35b34801561029557600080fd5b506102b060048036038101906102ab919061331f565b610aed565b6040516102bd9190613278565b60405180910390f35b3480156102d257600080fd5b506102ed60048036038101906102e8919061337f565b610b88565b6040516102fa91906133fd565b60405180910390f35b34801561030f57600080fd5b50610318610cb8565b6040516103259190612ff1565b60405180910390f35b34801561033a57600080fd5b5061035560048036038101906103509190613468565b610cdc565b60405161036291906133fd565b60405180910390f35b34801561037757600080fd5b50610392600480360381019061038d91906134b4565b610d81565b005b3480156103a057600080fd5b506103bb60048036038101906103b691906134fd565b610ece565b6040516103c89190612f4f565b60405180910390f35b3480156103dd57600080fd5b506103f860048036038101906103f391906134b4565b610f71565b005b6104026110be565b005b61041e60048036038101906104199190613549565b6111d1565b005b34801561042c57600080fd5b50610447600480360381019061044291906135d0565b6112c4565b005b34801561045557600080fd5b5061045e611414565b60405161046b9190612ff1565b60405180910390f35b34801561048057600080fd5b50610489611423565b60405161049c9796959493929190613797565b60405180910390f35b3480156104b157600080fd5b506104ba6114cd565b6040516104c7919061381b565b60405180910390f35b3480156104dc57600080fd5b506104e5611506565b6040516104f2919061381b565b60405180910390f35b34801561050757600080fd5b5061051061153f565b60405161051d919061389c565b60405180910390f35b34801561053257600080fd5b5061054d6004803603810190610548919061397a565b611563565b60405161055a9190613278565b60405180910390f35b34801561056f57600080fd5b506105786115fd565b60405161058591906133fd565b60405180910390f35b34801561059a57600080fd5b506105b560048036038101906105b09190613af5565b61169e565b005b3480156105c357600080fd5b506105de60048036038101906105d99190613bd5565b6117fa565b6040516105eb9190612f4f565b60405180910390f35b34801561060057600080fd5b506106096118ab565b60405161061691906133fd565b60405180910390f35b61063960048036038101906106349190613c02565b61194f565b6040516106469190613d79565b60405180910390f35b61066960048036038101906106649190613c02565b611c8b565b005b34801561067757600080fd5b50610680611fe0565b60405161068d9190613dbc565b60405180910390f35b3480156106a257600080fd5b506106bd60048036038101906106b89190612f8f565b612004565b6040516106ca9190612ff1565b60405180910390f35b3480156106df57600080fd5b506106fa60048036038101906106f59190613dd7565b612117565b6040516107079190613278565b60405180910390f35b34801561071c57600080fd5b506107256121b1565b604051610732919061381b565b60405180910390f35b60007f0000000000000000000000008438ad1c834623cff278ab6829a248e37c2d7e3f73ffffffffffffffffffffffffffffffffffffffff163073ffffffffffffffffffffffffffffffffffffffff16036107c2576040517f9f03a02600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7fd691c964000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916148061088b57507f150b7a02000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b806108f357507f4e2312e0000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b8061095b57507f01ffc9a7000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b806109c357507f1626ba7e000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b80610a2b57507f39922547000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b9050919050565b6000610a4d610a3f6121ea565b610a4884612004565b6122a1565b9050919050565b60007f0000000000000000000000008438ad1c834623cff278ab6829a248e37c2d7e3f73ffffffffffffffffffffffffffffffffffffffff163073ffffffffffffffffffffffffffffffffffffffff1603610adb576040517f9f03a02600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b63150b7a0260e01b9050949350505050565b60007f0000000000000000000000008438ad1c834623cff278ab6829a248e37c2d7e3f73ffffffffffffffffffffffffffffffffffffffff163073ffffffffffffffffffffffffffffffffffffffff1603610b74576040517f9f03a02600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610b7f8484846122e2565b90509392505050565b60007f0000000000000000000000002e983a1ba5e8b38aaaec4b440b9ddcfbf72e15d173ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610c0f576040517fd663742a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f0000000000000000000000008438ad1c834623cff278ab6829a248e37c2d7e3f73ffffffffffffffffffffffffffffffffffffffff163073ffffffffffffffffffffffffffffffffffffffff1603610c94576040517f9f03a02600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610ca684610ca186610a32565b612385565b9050610cb182612406565b9392505050565b7fbc37962d8bd1d319c95199bdfda6d3f92baa8903a61b32d5f4ec1f4b36a3bc1881565b60007f0000000000000000000000002e983a1ba5e8b38aaaec4b440b9ddcfbf72e15d173ffffffffffffffffffffffffffffffffffffffff166335567e1a30846040518363ffffffff1660e01b8152600401610d39929190613e7d565b602060405180830381865afa158015610d56573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d7a9190613ebb565b9050919050565b7f0000000000000000000000002e983a1ba5e8b38aaaec4b440b9ddcfbf72e15d173ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614158015610e0957503073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614155b15610e40576040517f0796d94500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f000000000000000000000000663f3ad617193148711d28f5334ee4ed0701660273ffffffffffffffffffffffffffffffffffffffff16633ed01015826040518263ffffffff1660e01b8152600401610e99919061425c565b600060405180830381600087803b158015610eb357600080fd5b505af1158015610ec7573d6000803e3d6000fd5b5050505050565b60007f000000000000000000000000663f3ad617193148711d28f5334ee4ed0701660273ffffffffffffffffffffffffffffffffffffffff16632d40d052836040518263ffffffff1660e01b8152600401610f299190612ff1565b602060405180830381865afa158015610f46573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f6a91906142aa565b9050919050565b7f0000000000000000000000002e983a1ba5e8b38aaaec4b440b9ddcfbf72e15d173ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614158015610ff957503073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614155b15611030576040517f0796d94500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f000000000000000000000000663f3ad617193148711d28f5334ee4ed0701660273ffffffffffffffffffffffffffffffffffffffff166349934047826040518263ffffffff1660e01b8152600401611089919061425c565b600060405180830381600087803b1580156110a357600080fd5b505af11580156110b7573d6000803e3d6000fd5b5050505050565b7f0000000000000000000000008438ad1c834623cff278ab6829a248e37c2d7e3f73ffffffffffffffffffffffffffffffffffffffff163073ffffffffffffffffffffffffffffffffffffffff1603611143576040517f9f03a02600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f0000000000000000000000002e983a1ba5e8b38aaaec4b440b9ddcfbf72e15d173ffffffffffffffffffffffffffffffffffffffff1663b760faf934306040518363ffffffff1660e01b815260040161119d91906142d7565b6000604051808303818588803b1580156111b657600080fd5b505af11580156111ca573d6000803e3d6000fd5b5050505050565b7f0000000000000000000000002e983a1ba5e8b38aaaec4b440b9ddcfbf72e15d173ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161415801561125957503073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614155b15611290576040517f0796d94500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6112c08160000160208101906112a691906142f2565b82602001358380604001906112bb919061432e565b6124f2565b5050565b7f0000000000000000000000002e983a1ba5e8b38aaaec4b440b9ddcfbf72e15d173ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161415801561134c57503073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614155b15611383576040517f0796d94500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f0000000000000000000000002e983a1ba5e8b38aaaec4b440b9ddcfbf72e15d173ffffffffffffffffffffffffffffffffffffffff1663205c287883836040518363ffffffff1660e01b81526004016113de9291906143a0565b600060405180830381600087803b1580156113f857600080fd5b505af115801561140c573d6000803e3d6000fd5b505050505050565b600061141e6121ea565b905090565b60006060806000806000606061143761252e565b61143f612569565b46306000801b600067ffffffffffffffff8111156114605761145f6130bb565b5b60405190808252806020026020018201604052801561148e5781602001602082028036833780820191505090505b507f0f00000000000000000000000000000000000000000000000000000000000000959493929190965096509650965096509650965090919293949596565b6040518060400160405280601981526020017f4549503737303253746174656c65737344656c654761746f720000000000000081525081565b6040518060400160405280600181526020017f310000000000000000000000000000000000000000000000000000000000000081525081565b7f0000000000000000000000002e983a1ba5e8b38aaaec4b440b9ddcfbf72e15d181565b60007f0000000000000000000000008438ad1c834623cff278ab6829a248e37c2d7e3f73ffffffffffffffffffffffffffffffffffffffff163073ffffffffffffffffffffffffffffffffffffffff16036115ea576040517f9f03a02600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b63bc197c8160e01b905095945050505050565b60007f0000000000000000000000002e983a1ba5e8b38aaaec4b440b9ddcfbf72e15d173ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b815260040161165891906142d7565b602060405180830381865afa158015611675573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116999190613ebb565b905090565b7f0000000000000000000000002e983a1ba5e8b38aaaec4b440b9ddcfbf72e15d173ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161415801561172657503073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614155b1561175d576040517f0796d94500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f000000000000000000000000663f3ad617193148711d28f5334ee4ed0701660273ffffffffffffffffffffffffffffffffffffffff1663cef6d2098787878787876040518763ffffffff1660e01b81526004016117c096959493929190614541565b600060405180830381600087803b1580156117da57600080fd5b505af11580156117ee573d6000803e3d6000fd5b50505050505050505050565b600080600080600061180b866125a4565b935093509350935061182184600060f81b6125c6565b80611836575061183584600160f81b6125c6565b5b8015611861575061184b83600060f81b612617565b80611860575061185f83600160f81b612617565b5b5b8015611877575061187682600060e01b612668565b5b80156118a05750600060501b69ffffffffffffffffffff19168169ffffffffffffffffffff1916145b945050505050919050565b60007f0000000000000000000000002e983a1ba5e8b38aaaec4b440b9ddcfbf72e15d173ffffffffffffffffffffffffffffffffffffffff166335567e1a3060006040518363ffffffff1660e01b81526004016119099291906145ce565b602060405180830381865afa158015611926573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061194a9190613ebb565b905090565b60607f000000000000000000000000663f3ad617193148711d28f5334ee4ed0701660273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146119d6576040517f1a4b3a0400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000806119e2866125a4565b5050915091506119f682600160f81b6125c6565b15611a9957366000611a0887876126b3565b91509150611a1a83600060f81b612617565b15611a3057611a2982826126cc565b9450611a92565b611a3e83600160f81b612617565b15611a5457611a4d82826127bd565b9450611a91565b826040517f1187dc06000000000000000000000000000000000000000000000000000000008152600401611a889190614618565b60405180910390fd5b5b5050611c82565b611aa782600060f81b6125c6565b15611c4457600080366000611abc898961290e565b9350935093509350600167ffffffffffffffff811115611adf57611ade6130bb565b5b604051908082528060200260200182016040528015611b1257816020015b6060815260200190600190039081611afd5790505b5096506000611b2586600060f81b612617565b15611b5a57611b36858585856124f2565b88600081518110611b4a57611b49614633565b5b6020026020010181905250611c3a565b611b6886600160f81b612617565b15611bfc57611b798585858561297c565b89600081518110611b8d57611b8c614633565b5b60200260200101819052819250505080611bf7577fe723f28f104e46b47fd3531f3608374ac226bcf3ddda334a23a266453e0efdb7600089600081518110611bd857611bd7614633565b5b6020026020010151604051611bee9291906146dd565b60405180910390a15b611c39565b856040517f1187dc06000000000000000000000000000000000000000000000000000000008152600401611c309190614618565b60405180910390fd5b5b5050505050611c81565b816040517fb96fcfe4000000000000000000000000000000000000000000000000000000008152600401611c78919061471c565b60405180910390fd5b5b50509392505050565b7f0000000000000000000000002e983a1ba5e8b38aaaec4b440b9ddcfbf72e15d173ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614158015611d1357503073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614155b15611d4a576040517f0796d94500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600080611d56856125a4565b505091509150611d6a82600160f81b6125c6565b15611e0b57366000611d7c86866126b3565b91509150611d8e83600060f81b612617565b15611da357611d9d82826126cc565b50611e04565b611db183600160f81b612617565b15611dc657611dc082826127bd565b50611e03565b826040517f1187dc06000000000000000000000000000000000000000000000000000000008152600401611dfa9190614618565b60405180910390fd5b5b5050611fd9565b611e1982600060f81b6125c6565b15611f9b57600080366000611e2e888861290e565b9350935093509350611e4485600060f81b612617565b15611e5b57611e55848484846124f2565b50611f92565b611e6985600160f81b612617565b15611f54576000600167ffffffffffffffff811115611e8b57611e8a6130bb565b5b604051908082528060200260200182016040528015611ebe57816020015b6060815260200190600190039081611ea95790505b5090506000611ecf8686868661297c565b83600081518110611ee357611ee2614633565b5b60200260200101819052819250505080611f4d577fe723f28f104e46b47fd3531f3608374ac226bcf3ddda334a23a266453e0efdb7600083600081518110611f2e57611f2d614633565b5b6020026020010151604051611f449291906146dd565b60405180910390a15b5050611f91565b846040517f1187dc06000000000000000000000000000000000000000000000000000000008152600401611f889190614618565b60405180910390fd5b5b50505050611fd8565b816040517fb96fcfe4000000000000000000000000000000000000000000000000000000008152600401611fcf919061471c565b60405180910390fd5b5b5050505050565b7f000000000000000000000000663f3ad617193148711d28f5334ee4ed0701660281565b60007fbc37962d8bd1d319c95199bdfda6d3f92baa8903a61b32d5f4ec1f4b36a3bc1882600001602081019061203a91906142f2565b836020013584806040019061204f919061432e565b60405161205d929190614767565b6040518091039020858060600190612075919061432e565b604051612083929190614767565b604051809103902086608001358760a001358860c00135898060e001906120aa919061432e565b6040516120b8929190614767565b60405180910390207f0000000000000000000000002e983a1ba5e8b38aaaec4b440b9ddcfbf72e15d16040516020016120fa9a99989796959493929190614780565b604051602081830303815290604052805190602001209050919050565b60007f0000000000000000000000008438ad1c834623cff278ab6829a248e37c2d7e3f73ffffffffffffffffffffffffffffffffffffffff163073ffffffffffffffffffffffffffffffffffffffff160361219e576040517f9f03a02600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b63f23a6e6160e01b905095945050505050565b6040518060400160405280600581526020017f312e332e3000000000000000000000000000000000000000000000000000000081525081565b60007f0000000000000000000000008438ad1c834623cff278ab6829a248e37c2d7e3f73ffffffffffffffffffffffffffffffffffffffff163073ffffffffffffffffffffffffffffffffffffffff1614801561226657507f000000000000000000000000000000000000000000000000000000000000053946145b15612293577f6e94388684165b3a90707922416b4045e752f62b048c387b3db54648f016a2d8905061229e565b61229b6129b1565b90505b90565b60006040517f190100000000000000000000000000000000000000000000000000000000000081528360028201528260228201526042812091505092915050565b60003073ffffffffffffffffffffffffffffffffffffffff166123498585858080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f82011690508083019250505050505050612a47565b73ffffffffffffffffffffffffffffffffffffffff160361237357631626ba7e60e01b905061237e565b63ffffffff60e01b90505b9392505050565b6000806123a2838580610100019061239d919061432e565b6122e2565b9050631626ba7e60e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916817bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916036123fa576000915050612400565b60019150505b92915050565b600081146124ef5760003373ffffffffffffffffffffffffffffffffffffffff16827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9060405161245690614842565b600060405180830381858888f193505050503d8060008114612494576040519150601f19603f3d011682016040523d82523d6000602084013e612499565b606091505b505090503373ffffffffffffffffffffffffffffffffffffffff167fa427c7d47f24d01b170779a7600b1d4c0d7cdbabaa0f19c4f0e6182053ffc93183836040516124e5929190614857565b60405180910390a2505b50565b6060604051905081838237600038838387895af1612513573d6000823e3d81fd5b3d8152602081013d6000823e3d810160405250949350505050565b606061256460007f4549503737303253746174656c65737344656c654761746f7200000000000019612a7390919063ffffffff16565b905090565b606061259f60017f3100000000000000000000000000000000000000000000000000000000000001612a7390919063ffffffff16565b905090565b6000806000808493508460081b92508460301b91508460501b90509193509193565b6000817effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916837effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614905092915050565b6000817effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916837effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614905092915050565b6000817bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916837bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614905092915050565b3660008335840160208101925080359150509250929050565b606060008383905090508067ffffffffffffffff8111156126f0576126ef6130bb565b5b60405190808252806020026020018201604052801561272357816020015b606081526020019060019003908161270e5790505b50915060005b818110156127b5573685858381811061274557612744614633565b5b90506020028101906127579190614880565b905061278981600001602081019061276f91906142f2565b8260200135838060400190612784919061432e565b6124f2565b84838151811061279c5761279b614633565b5b6020026020010181905250508080600101915050612729565b505092915050565b606060008383905090508067ffffffffffffffff8111156127e1576127e06130bb565b5b60405190808252806020026020018201604052801561281457816020015b60608152602001906001900390816127ff5790505b50915060005b81811015612906573685858381811061283657612835614633565b5b90506020028101906128489190614880565b9050600061287c82600001602081019061286291906142f2565b8360200135848060400190612877919061432e565b61297c565b86858151811061288f5761288e614633565b5b602002602001018190528192505050806128f7577fe723f28f104e46b47fd3531f3608374ac226bcf3ddda334a23a266453e0efdb7838685815181106128d8576128d7614633565b5b60200260200101516040516128ee9291906148a8565b60405180910390a15b5050808060010191505061281a565b505092915050565b6000803660008585600090601492612928939291906148e2565b906129339190614961565b60601c9350858560149060349261294c939291906148e2565b9061295791906149c0565b60001c92508585603490809261296f939291906148e2565b9150915092959194509250565b600060606040519050828482376000388483888a5af11591503d8152602081013d6000823e3d81016040525094509492505050565b60007f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f7f87e2b3436f0f6d8494dfcb826d860322ea231814dba9eb086540f62b8561c57b7fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc64630604051602001612a2c959493929190614a1f565b60405160208183030381529060405280519060200120905090565b600080600080612a578686612b23565b925092509250612a678282612b7f565b82935050505092915050565b606060ff60001b8314612a9057612a8983612ce3565b9050612b1d565b818054612a9c90614aa1565b80601f0160208091040260200160405190810160405280929190818152602001828054612ac890614aa1565b8015612b155780601f10612aea57610100808354040283529160200191612b15565b820191906000526020600020905b815481529060010190602001808311612af857829003601f168201915b505050505090505b92915050565b60008060006041845103612b685760008060006020870151925060408701519150606087015160001a9050612b5a88828585612d57565b955095509550505050612b78565b60006002855160001b9250925092505b9250925092565b60006003811115612b9357612b92614ad2565b5b826003811115612ba657612ba5614ad2565b5b0315612cdf5760016003811115612bc057612bbf614ad2565b5b826003811115612bd357612bd2614ad2565b5b03612c0a576040517ff645eedf00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60026003811115612c1e57612c1d614ad2565b5b826003811115612c3157612c30614ad2565b5b03612c76578060001c6040517ffce698f7000000000000000000000000000000000000000000000000000000008152600401612c6d91906133fd565b60405180910390fd5b600380811115612c8957612c88614ad2565b5b826003811115612c9c57612c9b614ad2565b5b03612cde57806040517fd78bce0c000000000000000000000000000000000000000000000000000000008152600401612cd59190612ff1565b60405180910390fd5b5b5050565b60606000612cf083612e4b565b90506000602067ffffffffffffffff811115612d0f57612d0e6130bb565b5b6040519080825280601f01601f191660200182016040528015612d415781602001600182028036833780820191505090505b5090508181528360208201528092505050919050565b60008060007f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08460001c1115612d97576000600385925092509250612e41565b600060018888888860405160008152602001604052604051612dbc9493929190614b1d565b6020604051602081039080840390855afa158015612dde573d6000803e3d6000fd5b505050602060405103519050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603612e3257600060016000801b93509350935050612e41565b8060008060001b935093509350505b9450945094915050565b60008060ff8360001c169050601f811115612e92576040517fb3512b0c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80915050919050565b6000604051905090565b600080fd5b600080fd5b60007fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b612ee481612eaf565b8114612eef57600080fd5b50565b600081359050612f0181612edb565b92915050565b600060208284031215612f1d57612f1c612ea5565b5b6000612f2b84828501612ef2565b91505092915050565b60008115159050919050565b612f4981612f34565b82525050565b6000602082019050612f646000830184612f40565b92915050565b600080fd5b60006101208284031215612f8657612f85612f6a565b5b81905092915050565b600060208284031215612fa557612fa4612ea5565b5b600082013567ffffffffffffffff811115612fc357612fc2612eaa565b5b612fcf84828501612f6f565b91505092915050565b6000819050919050565b612feb81612fd8565b82525050565b60006020820190506130066000830184612fe2565b92915050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b60006130378261300c565b9050919050565b6130478161302c565b811461305257600080fd5b50565b6000813590506130648161303e565b92915050565b6000819050919050565b61307d8161306a565b811461308857600080fd5b50565b60008135905061309a81613074565b92915050565b600080fd5b600080fd5b6000601f19601f8301169050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6130f3826130aa565b810181811067ffffffffffffffff82111715613112576131116130bb565b5b80604052505050565b6000613125612e9b565b905061313182826130ea565b919050565b600067ffffffffffffffff821115613151576131506130bb565b5b61315a826130aa565b9050602081019050919050565b82818337600083830152505050565b600061318961318484613136565b61311b565b9050828152602081018484840111156131a5576131a46130a5565b5b6131b0848285613167565b509392505050565b600082601f8301126131cd576131cc6130a0565b5b81356131dd848260208601613176565b91505092915050565b60008060008060808587031215613200576131ff612ea5565b5b600061320e87828801613055565b945050602061321f87828801613055565b93505060406132308782880161308b565b925050606085013567ffffffffffffffff81111561325157613250612eaa565b5b61325d878288016131b8565b91505092959194509250565b61327281612eaf565b82525050565b600060208201905061328d6000830184613269565b92915050565b61329c81612fd8565b81146132a757600080fd5b50565b6000813590506132b981613293565b92915050565b600080fd5b600080fd5b60008083601f8401126132df576132de6130a0565b5b8235905067ffffffffffffffff8111156132fc576132fb6132bf565b5b602083019150836001820283011115613318576133176132c4565b5b9250929050565b60008060006040848603121561333857613337612ea5565b5b6000613346868287016132aa565b935050602084013567ffffffffffffffff81111561336757613366612eaa565b5b613373868287016132c9565b92509250509250925092565b60008060006060848603121561339857613397612ea5565b5b600084013567ffffffffffffffff8111156133b6576133b5612eaa565b5b6133c286828701612f6f565b93505060206133d3868287016132aa565b92505060406133e48682870161308b565b9150509250925092565b6133f78161306a565b82525050565b600060208201905061341260008301846133ee565b92915050565b600077ffffffffffffffffffffffffffffffffffffffffffffffff82169050919050565b61344581613418565b811461345057600080fd5b50565b6000813590506134628161343c565b92915050565b60006020828403121561347e5761347d612ea5565b5b600061348c84828501613453565b91505092915050565b600060c082840312156134ab576134aa612f6a565b5b81905092915050565b6000602082840312156134ca576134c9612ea5565b5b600082013567ffffffffffffffff8111156134e8576134e7612eaa565b5b6134f484828501613495565b91505092915050565b60006020828403121561351357613512612ea5565b5b6000613521848285016132aa565b91505092915050565b6000606082840312156135405761353f612f6a565b5b81905092915050565b60006020828403121561355f5761355e612ea5565b5b600082013567ffffffffffffffff81111561357d5761357c612eaa565b5b6135898482850161352a565b91505092915050565b600061359d8261300c565b9050919050565b6135ad81613592565b81146135b857600080fd5b50565b6000813590506135ca816135a4565b92915050565b600080604083850312156135e7576135e6612ea5565b5b60006135f5858286016135bb565b92505060206136068582860161308b565b9150509250929050565b60007fff0000000000000000000000000000000000000000000000000000000000000082169050919050565b61364581613610565b82525050565b600081519050919050565b600082825260208201905092915050565b60005b8381101561368557808201518184015260208101905061366a565b60008484015250505050565b600061369c8261364b565b6136a68185613656565b93506136b6818560208601613667565b6136bf816130aa565b840191505092915050565b6136d38161302c565b82525050565b600081519050919050565b600082825260208201905092915050565b6000819050602082019050919050565b61370e8161306a565b82525050565b60006137208383613705565b60208301905092915050565b6000602082019050919050565b6000613744826136d9565b61374e81856136e4565b9350613759836136f5565b8060005b8381101561378a5781516137718882613714565b975061377c8361372c565b92505060018101905061375d565b5085935050505092915050565b600060e0820190506137ac600083018a61363c565b81810360208301526137be8189613691565b905081810360408301526137d28188613691565b90506137e160608301876133ee565b6137ee60808301866136ca565b6137fb60a0830185612fe2565b81810360c083015261380d8184613739565b905098975050505050505050565b600060208201905081810360008301526138358184613691565b905092915050565b6000819050919050565b600061386261385d6138588461300c565b61383d565b61300c565b9050919050565b600061387482613847565b9050919050565b600061388682613869565b9050919050565b6138968161387b565b82525050565b60006020820190506138b1600083018461388d565b92915050565b600067ffffffffffffffff8211156138d2576138d16130bb565b5b602082029050602081019050919050565b60006138f66138f1846138b7565b61311b565b90508083825260208201905060208402830185811115613919576139186132c4565b5b835b81811015613942578061392e888261308b565b84526020840193505060208101905061391b565b5050509392505050565b600082601f830112613961576139606130a0565b5b81356139718482602086016138e3565b91505092915050565b600080600080600060a0868803121561399657613995612ea5565b5b60006139a488828901613055565b95505060206139b588828901613055565b945050604086013567ffffffffffffffff8111156139d6576139d5612eaa565b5b6139e28882890161394c565b935050606086013567ffffffffffffffff811115613a0357613a02612eaa565b5b613a0f8882890161394c565b925050608086013567ffffffffffffffff811115613a3057613a2f612eaa565b5b613a3c888289016131b8565b9150509295509295909350565b60008083601f840112613a5f57613a5e6130a0565b5b8235905067ffffffffffffffff811115613a7c57613a7b6132bf565b5b602083019150836020820283011115613a9857613a976132c4565b5b9250929050565b60008083601f840112613ab557613ab46130a0565b5b8235905067ffffffffffffffff811115613ad257613ad16132bf565b5b602083019150836020820283011115613aee57613aed6132c4565b5b9250929050565b60008060008060008060608789031215613b1257613b11612ea5565b5b600087013567ffffffffffffffff811115613b3057613b2f612eaa565b5b613b3c89828a01613a49565b9650965050602087013567ffffffffffffffff811115613b5f57613b5e612eaa565b5b613b6b89828a01613a9f565b9450945050604087013567ffffffffffffffff811115613b8e57613b8d612eaa565b5b613b9a89828a01613a49565b92509250509295509295509295565b613bb281612fd8565b8114613bbd57600080fd5b50565b600081359050613bcf81613ba9565b92915050565b600060208284031215613beb57613bea612ea5565b5b6000613bf984828501613bc0565b91505092915050565b600080600060408486031215613c1b57613c1a612ea5565b5b6000613c2986828701613bc0565b935050602084013567ffffffffffffffff811115613c4a57613c49612eaa565b5b613c56868287016132c9565b92509250509250925092565b600081519050919050565b600082825260208201905092915050565b6000819050602082019050919050565b600081519050919050565b600082825260208201905092915050565b6000613cb582613c8e565b613cbf8185613c99565b9350613ccf818560208601613667565b613cd8816130aa565b840191505092915050565b6000613cef8383613caa565b905092915050565b6000602082019050919050565b6000613d0f82613c62565b613d198185613c6d565b935083602082028501613d2b85613c7e565b8060005b85811015613d675784840389528151613d488582613ce3565b9450613d5383613cf7565b925060208a01995050600181019050613d2f565b50829750879550505050505092915050565b60006020820190508181036000830152613d938184613d04565b905092915050565b6000613da682613869565b9050919050565b613db681613d9b565b82525050565b6000602082019050613dd16000830184613dad565b92915050565b600080600080600060a08688031215613df357613df2612ea5565b5b6000613e0188828901613055565b9550506020613e1288828901613055565b9450506040613e238882890161308b565b9350506060613e348882890161308b565b925050608086013567ffffffffffffffff811115613e5557613e54612eaa565b5b613e61888289016131b8565b9150509295509295909350565b613e7781613418565b82525050565b6000604082019050613e9260008301856136ca565b613e9f6020830184613e6e565b9392505050565b600081519050613eb581613074565b92915050565b600060208284031215613ed157613ed0612ea5565b5b6000613edf84828501613ea6565b91505092915050565b6000613ef76020840184613055565b905092915050565b613f088161302c565b82525050565b6000613f1d60208401846132aa565b905092915050565b613f2e81612fd8565b82525050565b600080fd5b600080fd5b600080fd5b60008083356001602003843603038112613f6057613f5f613f3e565b5b83810192508235915060208301925067ffffffffffffffff821115613f8857613f87613f34565b5b602082023603831315613f9e57613f9d613f39565b5b509250929050565b600082825260208201905092915050565b6000819050919050565b60008083356001602003843603038112613fde57613fdd613f3e565b5b83810192508235915060208301925067ffffffffffffffff82111561400657614005613f34565b5b60018202360383131561401c5761401b613f39565b5b509250929050565b60006140308385613c99565b935061403d838584613167565b614046836130aa565b840190509392505050565b6000606083016140646000840184613ee8565b6140716000860182613eff565b5061407f6020840184613fc1565b8583036020870152614092838284614024565b925050506140a36040840184613fc1565b85830360408701526140b6838284614024565b925050508091505092915050565b60006140d08383614051565b905092915050565b6000823560016060038336030381126140f4576140f3613f3e565b5b82810191505092915050565b6000602082019050919050565b60006141198385613fa6565b93508360208402850161412b84613fb7565b8060005b8781101561416f57848403895261414682846140d8565b61415085826140c4565b945061415b83614100565b925060208a0199505060018101905061412f565b50829750879450505050509392505050565b6000614190602084018461308b565b905092915050565b600060c083016141ab6000840184613ee8565b6141b86000860182613eff565b506141c66020840184613ee8565b6141d36020860182613eff565b506141e16040840184613f0e565b6141ee6040860182613f25565b506141fc6060840184613f43565b858303606087015261420f83828461410d565b925050506142206080840184614181565b61422d6080860182613705565b5061423b60a0840184613fc1565b85830360a087015261424e838284614024565b925050508091505092915050565b600060208201905081810360008301526142768184614198565b905092915050565b61428781612f34565b811461429257600080fd5b50565b6000815190506142a48161427e565b92915050565b6000602082840312156142c0576142bf612ea5565b5b60006142ce84828501614295565b91505092915050565b60006020820190506142ec60008301846136ca565b92915050565b60006020828403121561430857614307612ea5565b5b600061431684828501613055565b91505092915050565b600080fd5b600080fd5b600080fd5b6000808335600160200384360303811261434b5761434a61431f565b5b80840192508235915067ffffffffffffffff82111561436d5761436c614324565b5b60208301925060018202360383131561438957614388614329565b5b509250929050565b61439a81613592565b82525050565b60006040820190506143b56000830185614391565b6143c260208301846133ee565b9392505050565b6000819050919050565b60006143e0848484614024565b90509392505050565b6000602082019050919050565b60006144028385613c6d565b935083602084028501614414846143c9565b8060005b8781101561445a57848403895261442f8284613fc1565b61443a8682846143d3565b9550614445846143e9565b935060208b019a505050600181019050614418565b50829750879450505050509392505050565b600082825260208201905092915050565b6000819050919050565b600061449282612fd8565b9050919050565b6144a281614487565b82525050565b60006144b48383614499565b60208301905092915050565b60006144cf6020840184613bc0565b905092915050565b6000602082019050919050565b60006144f0838561446c565b93506144fb8261447d565b8060005b858110156145345761451182846144c0565b61451b88826144a8565b9750614526836144d7565b9250506001810190506144ff565b5085925050509392505050565b6000606082019050818103600083015261455c81888a6143f6565b905081810360208301526145718186886144e4565b905081810360408301526145868184866143f6565b9050979650505050505050565b6000819050919050565b60006145b86145b36145ae84614593565b61383d565b613418565b9050919050565b6145c88161459d565b82525050565b60006040820190506145e360008301856136ca565b6145f060208301846145bf565b9392505050565b600061460282613610565b9050919050565b614612816145f7565b82525050565b600060208201905061462d6000830184614609565b92915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600061467d61467861467384614593565b61383d565b61306a565b9050919050565b61468d81614662565b82525050565b600082825260208201905092915050565b60006146af82613c8e565b6146b98185614693565b93506146c9818560208601613667565b6146d2816130aa565b840191505092915050565b60006040820190506146f26000830185614684565b818103602083015261470481846146a4565b90509392505050565b614716816145f7565b82525050565b6000602082019050614731600083018461470d565b92915050565b600081905092915050565b600061474e8385614737565b935061475b838584613167565b82840190509392505050565b6000614774828486614742565b91508190509392505050565b600061014082019050614796600083018d612fe2565b6147a3602083018c6136ca565b6147b0604083018b6133ee565b6147bd606083018a612fe2565b6147ca6080830189612fe2565b6147d760a0830188612fe2565b6147e460c08301876133ee565b6147f160e0830186612fe2565b6147ff610100830185612fe2565b61480d61012083018461388d565b9b9a5050505050505050505050565b50565b600061482c600083614737565b91506148378261481c565b600082019050919050565b600061484d8261481f565b9150819050919050565b600060408201905061486c60008301856133ee565b6148796020830184612f40565b9392505050565b60008235600160600383360303811261489c5761489b61431f565b5b80830191505092915050565b60006040820190506148bd60008301856133ee565b81810360208301526148cf81846146a4565b90509392505050565b600080fd5b600080fd5b600080858511156148f6576148f56148d8565b5b83861115614907576149066148dd565b5b6001850283019150848603905094509492505050565b600082905092915050565b60007fffffffffffffffffffffffffffffffffffffffff00000000000000000000000082169050919050565b600082821b905092915050565b600061496d838361491d565b826149788135614928565b925060148210156149b8576149b37fffffffffffffffffffffffffffffffffffffffff00000000000000000000000083601403600802614954565b831692505b505092915050565b60006149cc838361491d565b826149d78135612fd8565b92506020821015614a1757614a127fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff83602003600802614954565b831692505b505092915050565b600060a082019050614a346000830188612fe2565b614a416020830187612fe2565b614a4e6040830186612fe2565b614a5b60608301856133ee565b614a6860808301846136ca565b9695505050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b60006002820490506001821680614ab957607f821691505b602082108103614acc57614acb614a72565b5b50919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b600060ff82169050919050565b614b1781614b01565b82525050565b6000608082019050614b326000830187612fe2565b614b3f6020830186614b0e565b614b4c6040830185612fe2565b614b596060830184612fe2565b9594505050505056fea2646970667358221220844c650b3d2c0aceaf7c108a1ec343abb8963e1bdf5c88d4f28ea4bbdce3ff1a64736f6c63430008170033", + "nonce": 2, + "gas_used": 4255871 + }, + "receipt": { + "type": "0x2", + "status": "0x1", + "cumulativeGasUsed": "0x40f07f", + "logs": [ + { + "address": "0x8438ad1c834623cff278ab6829a248e37c2d7e3f", + "topics": [ + "0xb2e8eb88b584ae71ef4e854c10847f4d39bd93e52599f147bfb4dcc8de52014d", + "0x000000000000000000000000663f3ad617193148711d28f5334ee4ed07016602" + ], + "data": "0x" + }, + { + "address": "0x8438ad1c834623cff278ab6829a248e37c2d7e3f", + "topics": [ + "0xee8699dc0e27105da2653bdba54be0edcaadc3e33890a3ad705517ffe9bf0a99", + "0x0000000000000000000000002e983a1ba5e8b38aaaec4b440b9ddcfbf72e15d1" + ], + "data": "0x" + } + ], + "logsBloom": "0x00000000000000000000002000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000810000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000800000000000000000000000000008000000000000000000000000800000001400000000000000000020000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040" + }, + "block_hash": "0x9cdb8aaba60547e8d92dd5cf406c32291e80a74b7048714f22b8ac06b6ca4e22", + "block_number": 3 + }, + { + "info": { + "transaction_hash": "0x92574096d598401cbf9b37ff4cd468c6e1eaeb0cc13d2e7327588e8be6c5af9b", + "transaction_index": 0, + "from": "0x3c44cdddb6a900fa2b585dd299e03d12fa4293bc", + "to": null, + "contract_address": "0xbc9129dc0487fc2e169941c75aabc539f208fb01", + "traces": [ + { + "parent": null, + "children": [], + "idx": 0, + "trace": { + "depth": 0, + "success": true, + "caller": "0x3c44cdddb6a900fa2b585dd299e03d12fa4293bc", + "address": "0xbc9129dc0487fc2e169941c75aabc539f208fb01", + "maybe_precompile": false, + "selfdestruct_address": null, + "selfdestruct_refund_target": null, + "selfdestruct_transferred_value": null, + "kind": "CREATE", + "value": "0x0", + "data": "0x608060405234801561001057600080fd5b5061171b806100206000396000f3fe608060405234801561001057600080fd5b50600436106100625760003560e01c8063414c3e3314610067578063a145832a14610083578063b99deb0e1461009f578063b9cf5249146100cf578063d3eddcc5146100ff578063ed4633671461011b575b600080fd5b610081600480360381019061007c9190610c7a565b610137565b005b61009d60048036038101906100989190610c7a565b610143565b005b6100b960048036038101906100b49190610d7d565b6107c3565b6040516100c69190610ef8565b60405180910390f35b6100e960048036038101906100e49190610f1a565b6109ac565b6040516100f69190610f75565b60405180910390f35b61011960048036038101906101149190610c7a565b6109db565b005b61013560048036038101906101309190610c7a565b6109e7565b005b50505050505050505050565b8561015a610150826109f3565b600160f81b6109fd565b610199576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161019090610fed565b60405180910390fd5b8660006101a582610a4e565b50509150506101b881600060f81b610a70565b6101f7576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016101ee9061107f565b60405180910390fd5b506000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600086815260200190815260200160002060009054906101000a900460ff1615610295576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161028c90611111565b60405180910390fd5b60016000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600087815260200190815260200160002060006101000a81548160ff02191690831515021790555036600061030a8989610ac1565b9150915060028282905014610354576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161034b906111a3565b60405180910390fd5b60006103608f8f6107c3565b9050806060015173ffffffffffffffffffffffffffffffffffffffff1683836000818110610391576103906111c3565b5b90506020028101906103a39190611201565b60000160208101906103b59190611229565b73ffffffffffffffffffffffffffffffffffffffff1614158061040257506000838360008181106103e9576103e86111c3565b5b90506020028101906103fb9190611201565b6020013514155b80610462575080608001518051906020012083836000818110610428576104276111c3565b5b905060200281019061043a9190611201565b80604001906104499190611256565b6040516104579291906112f8565b604051809103902014155b156104a2576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610499906113a9565b60405180910390fd5b806000015173ffffffffffffffffffffffffffffffffffffffff16838360018181106104d1576104d06111c3565b5b90506020028101906104e39190611201565b60000160208101906104f59190611229565b73ffffffffffffffffffffffffffffffffffffffff161415806105425750600083836001818110610529576105286111c3565b5b905060200281019061053b9190611201565b6020013514155b80610584575060448383600181811061055e5761055d6111c3565b5b90506020028101906105709190611201565b806040019061057f9190611256565b905014155b80610625575063a9059cbb60e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916838360018181106105c5576105c46111c3565b5b90506020028101906105d79190611201565b80604001906105e69190611256565b6000906004926105f8939291906113d3565b906106039190611452565b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614155b806106b45750806020015173ffffffffffffffffffffffffffffffffffffffff168383600181811061065a576106596111c3565b5b905060200281019061066c9190611201565b806040019061067b9190611256565b60049060249261068d939291906113d3565b9061069891906114b1565b60001c73ffffffffffffffffffffffffffffffffffffffff1614155b8061071757508060400151838360018181106106d3576106d26111c3565b5b90506020028101906106e59190611201565b80604001906106f49190611256565b602490604492610706939291906113d3565b9061071191906114b1565b60001c14155b15610757576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161074e906115a8565b60405180910390fd5b8673ffffffffffffffffffffffffffffffffffffffff16883373ffffffffffffffffffffffffffffffffffffffff167f76f83a16f9924b51c0c3ad67a44af3e517fbdec68ffa3729776df2ac0f03144060405160405180910390a4505050505050505050505050505050565b6107cb610ada565b605c838390501015610812576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108099061163a565b60405180910390fd5b8282600090601492610826939291906113d3565b906108319190611686565b60601c816000019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff1681525050828260149060289261087f939291906113d3565b9061088a9190611686565b60601c816020019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff168152505082826028906048926108d8939291906113d3565b906108e391906114b1565b60001c8160400181815250508282604890605c92610903939291906113d3565b9061090e9190611686565b60601c816060019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250508282605c90809261095b939291906113d3565b8080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f82011690508083019250505050505050816080018190525092915050565b60006020528160005260406000206020528060005260406000206000915091509054906101000a900460ff1681565b50505050505050505050565b50505050505050505050565b6000819050919050565b6000817effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916837effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614905092915050565b6000806000808493508460081b92508460301b91508460501b90509193509193565b6000817effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916837effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614905092915050565b3660008335840160208101925080359150509250929050565b6040518060a00160405280600073ffffffffffffffffffffffffffffffffffffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff16815260200160008152602001600073ffffffffffffffffffffffffffffffffffffffff168152602001606081525090565b600080fd5b600080fd5b600080fd5b600080fd5b600080fd5b60008083601f840112610b7a57610b79610b55565b5b8235905067ffffffffffffffff811115610b9757610b96610b5a565b5b602083019150836001820283011115610bb357610bb2610b5f565b5b9250929050565b6000819050919050565b610bcd81610bba565b8114610bd857600080fd5b50565b600081359050610bea81610bc4565b92915050565b610bf981610bba565b8114610c0457600080fd5b50565b600081359050610c1681610bf0565b92915050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000610c4782610c1c565b9050919050565b610c5781610c3c565b8114610c6257600080fd5b50565b600081359050610c7481610c4e565b92915050565b60008060008060008060008060008060e08b8d031215610c9d57610c9c610b4b565b5b60008b013567ffffffffffffffff811115610cbb57610cba610b50565b5b610cc78d828e01610b64565b9a509a505060208b013567ffffffffffffffff811115610cea57610ce9610b50565b5b610cf68d828e01610b64565b98509850506040610d098d828e01610bdb565b96505060608b013567ffffffffffffffff811115610d2a57610d29610b50565b5b610d368d828e01610b64565b95509550506080610d498d828e01610c07565b93505060a0610d5a8d828e01610c65565b92505060c0610d6b8d828e01610c65565b9150509295989b9194979a5092959850565b60008060208385031215610d9457610d93610b4b565b5b600083013567ffffffffffffffff811115610db257610db1610b50565b5b610dbe85828601610b64565b92509250509250929050565b610dd381610c3c565b82525050565b6000819050919050565b610dec81610dd9565b82525050565b600081519050919050565b600082825260208201905092915050565b60005b83811015610e2c578082015181840152602081019050610e11565b60008484015250505050565b6000601f19601f8301169050919050565b6000610e5482610df2565b610e5e8185610dfd565b9350610e6e818560208601610e0e565b610e7781610e38565b840191505092915050565b600060a083016000830151610e9a6000860182610dca565b506020830151610ead6020860182610dca565b506040830151610ec06040860182610de3565b506060830151610ed36060860182610dca565b5060808301518482036080860152610eeb8282610e49565b9150508091505092915050565b60006020820190508181036000830152610f128184610e82565b905092915050565b60008060408385031215610f3157610f30610b4b565b5b6000610f3f85828601610c65565b9250506020610f5085828601610c07565b9150509250929050565b60008115159050919050565b610f6f81610f5a565b82525050565b6000602082019050610f8a6000830184610f66565b92915050565b600082825260208201905092915050565b7f436176656174456e666f726365723a696e76616c69642d63616c6c2d74797065600082015250565b6000610fd7602083610f90565b9150610fe282610fa1565b602082019050919050565b6000602082019050818103600083015261100681610fca565b9050919050565b7f436176656174456e666f726365723a696e76616c69642d657865637574696f6e60008201527f2d74797065000000000000000000000000000000000000000000000000000000602082015250565b6000611069602583610f90565b91506110748261100d565b604082019050919050565b600060208201905081810360008301526110988161105c565b9050919050565b7f5370656369666963416374696f6e45524332305472616e73666572426174636860008201527f456e666f726365723a64656c65676174696f6e2d616c72656164792d75736564602082015250565b60006110fb604083610f90565b91506111068261109f565b604082019050919050565b6000602082019050818103600083015261112a816110ee565b9050919050565b7f5370656369666963416374696f6e45524332305472616e73666572426174636860008201527f456e666f726365723a696e76616c69642d62617463682d73697a650000000000602082015250565b600061118d603b83610f90565b915061119882611131565b604082019050919050565b600060208201905081810360008301526111bc81611180565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600080fd5b600080fd5b600080fd5b60008235600160600383360303811261121d5761121c6111f2565b5b80830191505092915050565b60006020828403121561123f5761123e610b4b565b5b600061124d84828501610c65565b91505092915050565b60008083356001602003843603038112611273576112726111f2565b5b80840192508235915067ffffffffffffffff821115611295576112946111f7565b5b6020830192506001820236038313156112b1576112b06111fc565b5b509250929050565b600081905092915050565b82818337600083830152505050565b60006112df83856112b9565b93506112ec8385846112c4565b82840190509392505050565b60006113058284866112d3565b91508190509392505050565b7f5370656369666963416374696f6e45524332305472616e73666572426174636860008201527f456e666f726365723a696e76616c69642d66697273742d7472616e736163746960208201527f6f6e000000000000000000000000000000000000000000000000000000000000604082015250565b6000611393604283610f90565b915061139e82611311565b606082019050919050565b600060208201905081810360008301526113c281611386565b9050919050565b600080fd5b600080fd5b600080858511156113e7576113e66113c9565b5b838611156113f8576113f76113ce565b5b6001850283019150848603905094509492505050565b600082905092915050565b60007fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b600082821b905092915050565b600061145e838361140e565b826114698135611419565b925060048210156114a9576114a47fffffffff0000000000000000000000000000000000000000000000000000000083600403600802611445565b831692505b505092915050565b60006114bd838361140e565b826114c88135610bba565b92506020821015611508576115037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff83602003600802611445565b831692505b505092915050565b7f5370656369666963416374696f6e45524332305472616e73666572426174636860008201527f456e666f726365723a696e76616c69642d7365636f6e642d7472616e7361637460208201527f696f6e0000000000000000000000000000000000000000000000000000000000604082015250565b6000611592604383610f90565b915061159d82611510565b606082019050919050565b600060208201905081810360008301526115c181611585565b9050919050565b7f5370656369666963416374696f6e45524332305472616e73666572426174636860008201527f456e666f726365723a696e76616c69642d7465726d732d6c656e677468000000602082015250565b6000611624603d83610f90565b915061162f826115c8565b604082019050919050565b6000602082019050818103600083015261165381611617565b9050919050565b60007fffffffffffffffffffffffffffffffffffffffff00000000000000000000000082169050919050565b6000611692838361140e565b8261169d813561165a565b925060148210156116dd576116d87fffffffffffffffffffffffffffffffffffffffff00000000000000000000000083601403600802611445565b831692505b50509291505056fea2646970667358221220bb45176bdb8ed7fb317c32e3295e9c2c5ef7b7344ac16b795cd46aff956325b064736f6c63430008170033", + "output": "0x608060405234801561001057600080fd5b50600436106100625760003560e01c8063414c3e3314610067578063a145832a14610083578063b99deb0e1461009f578063b9cf5249146100cf578063d3eddcc5146100ff578063ed4633671461011b575b600080fd5b610081600480360381019061007c9190610c7a565b610137565b005b61009d60048036038101906100989190610c7a565b610143565b005b6100b960048036038101906100b49190610d7d565b6107c3565b6040516100c69190610ef8565b60405180910390f35b6100e960048036038101906100e49190610f1a565b6109ac565b6040516100f69190610f75565b60405180910390f35b61011960048036038101906101149190610c7a565b6109db565b005b61013560048036038101906101309190610c7a565b6109e7565b005b50505050505050505050565b8561015a610150826109f3565b600160f81b6109fd565b610199576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161019090610fed565b60405180910390fd5b8660006101a582610a4e565b50509150506101b881600060f81b610a70565b6101f7576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016101ee9061107f565b60405180910390fd5b506000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600086815260200190815260200160002060009054906101000a900460ff1615610295576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161028c90611111565b60405180910390fd5b60016000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600087815260200190815260200160002060006101000a81548160ff02191690831515021790555036600061030a8989610ac1565b9150915060028282905014610354576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161034b906111a3565b60405180910390fd5b60006103608f8f6107c3565b9050806060015173ffffffffffffffffffffffffffffffffffffffff1683836000818110610391576103906111c3565b5b90506020028101906103a39190611201565b60000160208101906103b59190611229565b73ffffffffffffffffffffffffffffffffffffffff1614158061040257506000838360008181106103e9576103e86111c3565b5b90506020028101906103fb9190611201565b6020013514155b80610462575080608001518051906020012083836000818110610428576104276111c3565b5b905060200281019061043a9190611201565b80604001906104499190611256565b6040516104579291906112f8565b604051809103902014155b156104a2576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610499906113a9565b60405180910390fd5b806000015173ffffffffffffffffffffffffffffffffffffffff16838360018181106104d1576104d06111c3565b5b90506020028101906104e39190611201565b60000160208101906104f59190611229565b73ffffffffffffffffffffffffffffffffffffffff161415806105425750600083836001818110610529576105286111c3565b5b905060200281019061053b9190611201565b6020013514155b80610584575060448383600181811061055e5761055d6111c3565b5b90506020028101906105709190611201565b806040019061057f9190611256565b905014155b80610625575063a9059cbb60e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916838360018181106105c5576105c46111c3565b5b90506020028101906105d79190611201565b80604001906105e69190611256565b6000906004926105f8939291906113d3565b906106039190611452565b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614155b806106b45750806020015173ffffffffffffffffffffffffffffffffffffffff168383600181811061065a576106596111c3565b5b905060200281019061066c9190611201565b806040019061067b9190611256565b60049060249261068d939291906113d3565b9061069891906114b1565b60001c73ffffffffffffffffffffffffffffffffffffffff1614155b8061071757508060400151838360018181106106d3576106d26111c3565b5b90506020028101906106e59190611201565b80604001906106f49190611256565b602490604492610706939291906113d3565b9061071191906114b1565b60001c14155b15610757576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161074e906115a8565b60405180910390fd5b8673ffffffffffffffffffffffffffffffffffffffff16883373ffffffffffffffffffffffffffffffffffffffff167f76f83a16f9924b51c0c3ad67a44af3e517fbdec68ffa3729776df2ac0f03144060405160405180910390a4505050505050505050505050505050565b6107cb610ada565b605c838390501015610812576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108099061163a565b60405180910390fd5b8282600090601492610826939291906113d3565b906108319190611686565b60601c816000019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff1681525050828260149060289261087f939291906113d3565b9061088a9190611686565b60601c816020019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff168152505082826028906048926108d8939291906113d3565b906108e391906114b1565b60001c8160400181815250508282604890605c92610903939291906113d3565b9061090e9190611686565b60601c816060019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250508282605c90809261095b939291906113d3565b8080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f82011690508083019250505050505050816080018190525092915050565b60006020528160005260406000206020528060005260406000206000915091509054906101000a900460ff1681565b50505050505050505050565b50505050505050505050565b6000819050919050565b6000817effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916837effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614905092915050565b6000806000808493508460081b92508460301b91508460501b90509193509193565b6000817effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916837effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614905092915050565b3660008335840160208101925080359150509250929050565b6040518060a00160405280600073ffffffffffffffffffffffffffffffffffffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff16815260200160008152602001600073ffffffffffffffffffffffffffffffffffffffff168152602001606081525090565b600080fd5b600080fd5b600080fd5b600080fd5b600080fd5b60008083601f840112610b7a57610b79610b55565b5b8235905067ffffffffffffffff811115610b9757610b96610b5a565b5b602083019150836001820283011115610bb357610bb2610b5f565b5b9250929050565b6000819050919050565b610bcd81610bba565b8114610bd857600080fd5b50565b600081359050610bea81610bc4565b92915050565b610bf981610bba565b8114610c0457600080fd5b50565b600081359050610c1681610bf0565b92915050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000610c4782610c1c565b9050919050565b610c5781610c3c565b8114610c6257600080fd5b50565b600081359050610c7481610c4e565b92915050565b60008060008060008060008060008060e08b8d031215610c9d57610c9c610b4b565b5b60008b013567ffffffffffffffff811115610cbb57610cba610b50565b5b610cc78d828e01610b64565b9a509a505060208b013567ffffffffffffffff811115610cea57610ce9610b50565b5b610cf68d828e01610b64565b98509850506040610d098d828e01610bdb565b96505060608b013567ffffffffffffffff811115610d2a57610d29610b50565b5b610d368d828e01610b64565b95509550506080610d498d828e01610c07565b93505060a0610d5a8d828e01610c65565b92505060c0610d6b8d828e01610c65565b9150509295989b9194979a5092959850565b60008060208385031215610d9457610d93610b4b565b5b600083013567ffffffffffffffff811115610db257610db1610b50565b5b610dbe85828601610b64565b92509250509250929050565b610dd381610c3c565b82525050565b6000819050919050565b610dec81610dd9565b82525050565b600081519050919050565b600082825260208201905092915050565b60005b83811015610e2c578082015181840152602081019050610e11565b60008484015250505050565b6000601f19601f8301169050919050565b6000610e5482610df2565b610e5e8185610dfd565b9350610e6e818560208601610e0e565b610e7781610e38565b840191505092915050565b600060a083016000830151610e9a6000860182610dca565b506020830151610ead6020860182610dca565b506040830151610ec06040860182610de3565b506060830151610ed36060860182610dca565b5060808301518482036080860152610eeb8282610e49565b9150508091505092915050565b60006020820190508181036000830152610f128184610e82565b905092915050565b60008060408385031215610f3157610f30610b4b565b5b6000610f3f85828601610c65565b9250506020610f5085828601610c07565b9150509250929050565b60008115159050919050565b610f6f81610f5a565b82525050565b6000602082019050610f8a6000830184610f66565b92915050565b600082825260208201905092915050565b7f436176656174456e666f726365723a696e76616c69642d63616c6c2d74797065600082015250565b6000610fd7602083610f90565b9150610fe282610fa1565b602082019050919050565b6000602082019050818103600083015261100681610fca565b9050919050565b7f436176656174456e666f726365723a696e76616c69642d657865637574696f6e60008201527f2d74797065000000000000000000000000000000000000000000000000000000602082015250565b6000611069602583610f90565b91506110748261100d565b604082019050919050565b600060208201905081810360008301526110988161105c565b9050919050565b7f5370656369666963416374696f6e45524332305472616e73666572426174636860008201527f456e666f726365723a64656c65676174696f6e2d616c72656164792d75736564602082015250565b60006110fb604083610f90565b91506111068261109f565b604082019050919050565b6000602082019050818103600083015261112a816110ee565b9050919050565b7f5370656369666963416374696f6e45524332305472616e73666572426174636860008201527f456e666f726365723a696e76616c69642d62617463682d73697a650000000000602082015250565b600061118d603b83610f90565b915061119882611131565b604082019050919050565b600060208201905081810360008301526111bc81611180565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600080fd5b600080fd5b600080fd5b60008235600160600383360303811261121d5761121c6111f2565b5b80830191505092915050565b60006020828403121561123f5761123e610b4b565b5b600061124d84828501610c65565b91505092915050565b60008083356001602003843603038112611273576112726111f2565b5b80840192508235915067ffffffffffffffff821115611295576112946111f7565b5b6020830192506001820236038313156112b1576112b06111fc565b5b509250929050565b600081905092915050565b82818337600083830152505050565b60006112df83856112b9565b93506112ec8385846112c4565b82840190509392505050565b60006113058284866112d3565b91508190509392505050565b7f5370656369666963416374696f6e45524332305472616e73666572426174636860008201527f456e666f726365723a696e76616c69642d66697273742d7472616e736163746960208201527f6f6e000000000000000000000000000000000000000000000000000000000000604082015250565b6000611393604283610f90565b915061139e82611311565b606082019050919050565b600060208201905081810360008301526113c281611386565b9050919050565b600080fd5b600080fd5b600080858511156113e7576113e66113c9565b5b838611156113f8576113f76113ce565b5b6001850283019150848603905094509492505050565b600082905092915050565b60007fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b600082821b905092915050565b600061145e838361140e565b826114698135611419565b925060048210156114a9576114a47fffffffff0000000000000000000000000000000000000000000000000000000083600403600802611445565b831692505b505092915050565b60006114bd838361140e565b826114c88135610bba565b92506020821015611508576115037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff83602003600802611445565b831692505b505092915050565b7f5370656369666963416374696f6e45524332305472616e73666572426174636860008201527f456e666f726365723a696e76616c69642d7365636f6e642d7472616e7361637460208201527f696f6e0000000000000000000000000000000000000000000000000000000000604082015250565b6000611592604383610f90565b915061159d82611510565b606082019050919050565b600060208201905081810360008301526115c181611585565b9050919050565b7f5370656369666963416374696f6e45524332305472616e73666572426174636860008201527f456e666f726365723a696e76616c69642d7465726d732d6c656e677468000000602082015250565b6000611624603d83610f90565b915061162f826115c8565b604082019050919050565b6000602082019050818103600083015261165381611617565b9050919050565b60007fffffffffffffffffffffffffffffffffffffffff00000000000000000000000082169050919050565b6000611692838361140e565b8261169d813561165a565b925060148210156116dd576116d87fffffffffffffffffffffffffffffffffffffffff00000000000000000000000083601403600802611445565b831692505b50509291505056fea2646970667358221220bb45176bdb8ed7fb317c32e3295e9c2c5ef7b7344ac16b795cd46aff956325b064736f6c63430008170033", + "gas_used": 1184227, + "gas_limit": 1184227, + "status": "Return", + "steps": [], + "decoded": { + "label": null, + "return_data": null, + "call_data": null + } + }, + "logs": [], + "ordering": [] + } + ], + "exit": "Return", + "out": "0x608060405234801561001057600080fd5b50600436106100625760003560e01c8063414c3e3314610067578063a145832a14610083578063b99deb0e1461009f578063b9cf5249146100cf578063d3eddcc5146100ff578063ed4633671461011b575b600080fd5b610081600480360381019061007c9190610c7a565b610137565b005b61009d60048036038101906100989190610c7a565b610143565b005b6100b960048036038101906100b49190610d7d565b6107c3565b6040516100c69190610ef8565b60405180910390f35b6100e960048036038101906100e49190610f1a565b6109ac565b6040516100f69190610f75565b60405180910390f35b61011960048036038101906101149190610c7a565b6109db565b005b61013560048036038101906101309190610c7a565b6109e7565b005b50505050505050505050565b8561015a610150826109f3565b600160f81b6109fd565b610199576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161019090610fed565b60405180910390fd5b8660006101a582610a4e565b50509150506101b881600060f81b610a70565b6101f7576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016101ee9061107f565b60405180910390fd5b506000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600086815260200190815260200160002060009054906101000a900460ff1615610295576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161028c90611111565b60405180910390fd5b60016000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600087815260200190815260200160002060006101000a81548160ff02191690831515021790555036600061030a8989610ac1565b9150915060028282905014610354576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161034b906111a3565b60405180910390fd5b60006103608f8f6107c3565b9050806060015173ffffffffffffffffffffffffffffffffffffffff1683836000818110610391576103906111c3565b5b90506020028101906103a39190611201565b60000160208101906103b59190611229565b73ffffffffffffffffffffffffffffffffffffffff1614158061040257506000838360008181106103e9576103e86111c3565b5b90506020028101906103fb9190611201565b6020013514155b80610462575080608001518051906020012083836000818110610428576104276111c3565b5b905060200281019061043a9190611201565b80604001906104499190611256565b6040516104579291906112f8565b604051809103902014155b156104a2576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610499906113a9565b60405180910390fd5b806000015173ffffffffffffffffffffffffffffffffffffffff16838360018181106104d1576104d06111c3565b5b90506020028101906104e39190611201565b60000160208101906104f59190611229565b73ffffffffffffffffffffffffffffffffffffffff161415806105425750600083836001818110610529576105286111c3565b5b905060200281019061053b9190611201565b6020013514155b80610584575060448383600181811061055e5761055d6111c3565b5b90506020028101906105709190611201565b806040019061057f9190611256565b905014155b80610625575063a9059cbb60e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916838360018181106105c5576105c46111c3565b5b90506020028101906105d79190611201565b80604001906105e69190611256565b6000906004926105f8939291906113d3565b906106039190611452565b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614155b806106b45750806020015173ffffffffffffffffffffffffffffffffffffffff168383600181811061065a576106596111c3565b5b905060200281019061066c9190611201565b806040019061067b9190611256565b60049060249261068d939291906113d3565b9061069891906114b1565b60001c73ffffffffffffffffffffffffffffffffffffffff1614155b8061071757508060400151838360018181106106d3576106d26111c3565b5b90506020028101906106e59190611201565b80604001906106f49190611256565b602490604492610706939291906113d3565b9061071191906114b1565b60001c14155b15610757576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161074e906115a8565b60405180910390fd5b8673ffffffffffffffffffffffffffffffffffffffff16883373ffffffffffffffffffffffffffffffffffffffff167f76f83a16f9924b51c0c3ad67a44af3e517fbdec68ffa3729776df2ac0f03144060405160405180910390a4505050505050505050505050505050565b6107cb610ada565b605c838390501015610812576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108099061163a565b60405180910390fd5b8282600090601492610826939291906113d3565b906108319190611686565b60601c816000019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff1681525050828260149060289261087f939291906113d3565b9061088a9190611686565b60601c816020019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff168152505082826028906048926108d8939291906113d3565b906108e391906114b1565b60001c8160400181815250508282604890605c92610903939291906113d3565b9061090e9190611686565b60601c816060019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250508282605c90809261095b939291906113d3565b8080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f82011690508083019250505050505050816080018190525092915050565b60006020528160005260406000206020528060005260406000206000915091509054906101000a900460ff1681565b50505050505050505050565b50505050505050505050565b6000819050919050565b6000817effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916837effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614905092915050565b6000806000808493508460081b92508460301b91508460501b90509193509193565b6000817effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916837effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614905092915050565b3660008335840160208101925080359150509250929050565b6040518060a00160405280600073ffffffffffffffffffffffffffffffffffffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff16815260200160008152602001600073ffffffffffffffffffffffffffffffffffffffff168152602001606081525090565b600080fd5b600080fd5b600080fd5b600080fd5b600080fd5b60008083601f840112610b7a57610b79610b55565b5b8235905067ffffffffffffffff811115610b9757610b96610b5a565b5b602083019150836001820283011115610bb357610bb2610b5f565b5b9250929050565b6000819050919050565b610bcd81610bba565b8114610bd857600080fd5b50565b600081359050610bea81610bc4565b92915050565b610bf981610bba565b8114610c0457600080fd5b50565b600081359050610c1681610bf0565b92915050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000610c4782610c1c565b9050919050565b610c5781610c3c565b8114610c6257600080fd5b50565b600081359050610c7481610c4e565b92915050565b60008060008060008060008060008060e08b8d031215610c9d57610c9c610b4b565b5b60008b013567ffffffffffffffff811115610cbb57610cba610b50565b5b610cc78d828e01610b64565b9a509a505060208b013567ffffffffffffffff811115610cea57610ce9610b50565b5b610cf68d828e01610b64565b98509850506040610d098d828e01610bdb565b96505060608b013567ffffffffffffffff811115610d2a57610d29610b50565b5b610d368d828e01610b64565b95509550506080610d498d828e01610c07565b93505060a0610d5a8d828e01610c65565b92505060c0610d6b8d828e01610c65565b9150509295989b9194979a5092959850565b60008060208385031215610d9457610d93610b4b565b5b600083013567ffffffffffffffff811115610db257610db1610b50565b5b610dbe85828601610b64565b92509250509250929050565b610dd381610c3c565b82525050565b6000819050919050565b610dec81610dd9565b82525050565b600081519050919050565b600082825260208201905092915050565b60005b83811015610e2c578082015181840152602081019050610e11565b60008484015250505050565b6000601f19601f8301169050919050565b6000610e5482610df2565b610e5e8185610dfd565b9350610e6e818560208601610e0e565b610e7781610e38565b840191505092915050565b600060a083016000830151610e9a6000860182610dca565b506020830151610ead6020860182610dca565b506040830151610ec06040860182610de3565b506060830151610ed36060860182610dca565b5060808301518482036080860152610eeb8282610e49565b9150508091505092915050565b60006020820190508181036000830152610f128184610e82565b905092915050565b60008060408385031215610f3157610f30610b4b565b5b6000610f3f85828601610c65565b9250506020610f5085828601610c07565b9150509250929050565b60008115159050919050565b610f6f81610f5a565b82525050565b6000602082019050610f8a6000830184610f66565b92915050565b600082825260208201905092915050565b7f436176656174456e666f726365723a696e76616c69642d63616c6c2d74797065600082015250565b6000610fd7602083610f90565b9150610fe282610fa1565b602082019050919050565b6000602082019050818103600083015261100681610fca565b9050919050565b7f436176656174456e666f726365723a696e76616c69642d657865637574696f6e60008201527f2d74797065000000000000000000000000000000000000000000000000000000602082015250565b6000611069602583610f90565b91506110748261100d565b604082019050919050565b600060208201905081810360008301526110988161105c565b9050919050565b7f5370656369666963416374696f6e45524332305472616e73666572426174636860008201527f456e666f726365723a64656c65676174696f6e2d616c72656164792d75736564602082015250565b60006110fb604083610f90565b91506111068261109f565b604082019050919050565b6000602082019050818103600083015261112a816110ee565b9050919050565b7f5370656369666963416374696f6e45524332305472616e73666572426174636860008201527f456e666f726365723a696e76616c69642d62617463682d73697a650000000000602082015250565b600061118d603b83610f90565b915061119882611131565b604082019050919050565b600060208201905081810360008301526111bc81611180565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600080fd5b600080fd5b600080fd5b60008235600160600383360303811261121d5761121c6111f2565b5b80830191505092915050565b60006020828403121561123f5761123e610b4b565b5b600061124d84828501610c65565b91505092915050565b60008083356001602003843603038112611273576112726111f2565b5b80840192508235915067ffffffffffffffff821115611295576112946111f7565b5b6020830192506001820236038313156112b1576112b06111fc565b5b509250929050565b600081905092915050565b82818337600083830152505050565b60006112df83856112b9565b93506112ec8385846112c4565b82840190509392505050565b60006113058284866112d3565b91508190509392505050565b7f5370656369666963416374696f6e45524332305472616e73666572426174636860008201527f456e666f726365723a696e76616c69642d66697273742d7472616e736163746960208201527f6f6e000000000000000000000000000000000000000000000000000000000000604082015250565b6000611393604283610f90565b915061139e82611311565b606082019050919050565b600060208201905081810360008301526113c281611386565b9050919050565b600080fd5b600080fd5b600080858511156113e7576113e66113c9565b5b838611156113f8576113f76113ce565b5b6001850283019150848603905094509492505050565b600082905092915050565b60007fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b600082821b905092915050565b600061145e838361140e565b826114698135611419565b925060048210156114a9576114a47fffffffff0000000000000000000000000000000000000000000000000000000083600403600802611445565b831692505b505092915050565b60006114bd838361140e565b826114c88135610bba565b92506020821015611508576115037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff83602003600802611445565b831692505b505092915050565b7f5370656369666963416374696f6e45524332305472616e73666572426174636860008201527f456e666f726365723a696e76616c69642d7365636f6e642d7472616e7361637460208201527f696f6e0000000000000000000000000000000000000000000000000000000000604082015250565b6000611592604383610f90565b915061159d82611510565b606082019050919050565b600060208201905081810360008301526115c181611585565b9050919050565b7f5370656369666963416374696f6e45524332305472616e73666572426174636860008201527f456e666f726365723a696e76616c69642d7465726d732d6c656e677468000000602082015250565b6000611624603d83610f90565b915061162f826115c8565b604082019050919050565b6000602082019050818103600083015261165381611617565b9050919050565b60007fffffffffffffffffffffffffffffffffffffffff00000000000000000000000082169050919050565b6000611692838361140e565b8261169d813561165a565b925060148210156116dd576116d87fffffffffffffffffffffffffffffffffffffffff00000000000000000000000083601403600802611445565b831692505b50509291505056fea2646970667358221220bb45176bdb8ed7fb317c32e3295e9c2c5ef7b7344ac16b795cd46aff956325b064736f6c63430008170033", + "nonce": 3, + "gas_used": 1325923 + }, + "receipt": { + "type": "0x2", + "status": "0x1", + "cumulativeGasUsed": "0x143b63", + "logs": [], + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + }, + "block_hash": "0xcbb52c0aa705e93d339c988a63f196f1eb15f1dbf1ead30f0a66d2dfc4096ada", + "block_number": 4 + } + ] +} diff --git a/test/e2e/snaps/enums.js b/test/e2e/snaps/enums.js index 3b3ffb019a97..3d7db03af13b 100644 --- a/test/e2e/snaps/enums.js +++ b/test/e2e/snaps/enums.js @@ -1,3 +1,3 @@ module.exports = { - TEST_SNAPS_WEBSITE_URL: 'https://metamask.github.io/snaps/test-snaps/2.20.3', + TEST_SNAPS_WEBSITE_URL: 'https://metamask.github.io/snaps/test-snaps/2.21.1', }; diff --git a/test/e2e/snaps/test-snap-ethprovider.spec.js b/test/e2e/snaps/test-snap-ethprovider.spec.js index f0696f612df8..05e12076a507 100644 --- a/test/e2e/snaps/test-snap-ethprovider.spec.js +++ b/test/e2e/snaps/test-snap-ethprovider.spec.js @@ -47,6 +47,9 @@ describe('Test Snap ethereum_provider', function () { tag: 'button', }); + // wait and scroll if necessary + await driver.clickElementSafe('[data-testid="snap-install-scroll"]'); + // wait for and click confirm await driver.waitForSelector({ text: 'Confirm' }); await driver.clickElement({ diff --git a/test/e2e/snaps/test-snap-interactive-ui.spec.js b/test/e2e/snaps/test-snap-interactive-ui.spec.js index b39a4f865d03..dd94de057e16 100644 --- a/test/e2e/snaps/test-snap-interactive-ui.spec.js +++ b/test/e2e/snaps/test-snap-interactive-ui.spec.js @@ -97,7 +97,7 @@ describe('Test Snap Interactive UI', function () { await driver.clickElement({ tag: 'span', text: 'Checkbox' }); // try to click approve - await driver.clickElement('#submit'); + await driver.clickElement({ tag: 'span', text: 'Submit' }); // check for returned values await driver.waitForSelector({ text: 'foo bar', tag: 'p' }); @@ -106,16 +106,17 @@ describe('Test Snap Interactive UI', function () { await driver.waitForSelector({ text: 'true', tag: 'p' }); // click on approve and wait for window to close - await driver.clickElementAndWaitForWindowToClose( - '[data-testid="confirmation-submit-button"]', - ); + await driver.clickElementAndWaitForWindowToClose({ + tag: 'span', + text: 'OK', + }); // switch to test snaps tab await driver.switchToWindowWithTitle(WINDOW_TITLES.TestSnaps); - // look for returned true + // look for returned null await driver.waitForSelector({ - text: 'true', + text: 'null', css: '#interactiveUIResult', }); }, diff --git a/test/e2e/snaps/test-snap-revoke-perm.spec.js b/test/e2e/snaps/test-snap-revoke-perm.spec.js index 231bf2747cd6..9206928986dd 100644 --- a/test/e2e/snaps/test-snap-revoke-perm.spec.js +++ b/test/e2e/snaps/test-snap-revoke-perm.spec.js @@ -37,7 +37,6 @@ describe('Test Snap revoke permission', function () { // switch to metamask extension await driver.switchToWindowWithTitle(WINDOW_TITLES.Dialog); - // wait for and click connect await driver.waitForSelector({ text: 'Connect', tag: 'button', @@ -47,7 +46,10 @@ describe('Test Snap revoke permission', function () { tag: 'button', }); - // wait for and click connect + // wait and scroll if necessary + await driver.clickElementSafe('[data-testid="snap-install-scroll"]'); + + // wait for and click confirm await driver.waitForSelector({ text: 'Confirm' }); await driver.clickElement({ text: 'Confirm', diff --git a/test/e2e/snaps/test-snap-txinsights.spec.ts b/test/e2e/snaps/test-snap-txinsights.spec.ts index e6a2ea5849a6..9be6ba74c155 100644 --- a/test/e2e/snaps/test-snap-txinsights.spec.ts +++ b/test/e2e/snaps/test-snap-txinsights.spec.ts @@ -1,13 +1,23 @@ import { Driver } from '../webdriver/driver'; -import SnapInstall from '../page-objects/pages/dialog/snap-install'; import FixtureBuilder from '../fixture-builder'; import { loginWithoutBalanceValidation } from '../page-objects/flows/login.flow'; import { openTestSnapClickButtonAndInstall } from '../page-objects/flows/install-test-snap.flow'; -import { withFixtures, WINDOW_TITLES, openDapp } from '../helpers'; +import { + DAPP_URL, + withFixtures, + WINDOW_TITLES, + openDapp, + veryLargeDelayMs, +} from '../helpers'; import TestDapp from '../page-objects/pages/test-dapp'; +import { SMART_CONTRACTS } from '../seeder/smart-contracts'; +import ContractAddressRegistry from '../seeder/contract-address-registry'; +import { TestSuiteArguments } from '../tests/confirmations/transactions/shared'; +import TransactionConfirmation from '../page-objects/pages/confirmations/redesign/transaction-confirmation'; +import SnapTxInsights from '../page-objects/pages/dialog/snap-txinsight'; describe('Test Snap TxInsights', function () { - it(' validate the insights section appears', async function () { + it('shows insight for ERC20 transactions', async function () { await withFixtures( { dapp: true, @@ -18,9 +28,8 @@ describe('Test Snap TxInsights', function () { }, async ({ driver }: { driver: Driver }) => { await loginWithoutBalanceValidation(driver); - const testDapp = new TestDapp(driver); - const snapInstall = new SnapInstall(driver); + const snapTxInsights = new SnapTxInsights(driver); // Navigate to test snaps page and click to the transaction-insights test snap await openTestSnapClickButtonAndInstall( @@ -31,14 +40,92 @@ describe('Test Snap TxInsights', function () { // open the test-dapp page await openDapp(driver); await driver.switchToWindowWithTitle(WINDOW_TITLES.TestDApp); - - // click send tx await testDapp.clickMaliciousERC20TransferButton(); // Switch back to MetaMask dialog and validate the transaction insights title and type await driver.switchToWindowWithTitle(WINDOW_TITLES.Dialog); - await snapInstall.check_transactionInsightsTitle(); - await snapInstall.check_transactionInsightsType(); + await snapTxInsights.check_transactionInsightsTitle(); + await snapTxInsights.check_transactionInsightsType('ERC-20'); + }, + ); + }); + + it('shows insights for ERC721 transactions', async function () { + const smartContract = SMART_CONTRACTS.NFTS; + await withFixtures( + { + dapp: true, + fixtures: new FixtureBuilder() + .withPermissionControllerConnectedToTestDapp() + .build(), + smartContract, + title: this.test?.fullTitle(), + }, + async ({ driver, contractRegistry }: TestSuiteArguments) => { + await loginWithoutBalanceValidation(driver); + const testDapp = new TestDapp(driver); + const snapTxInsights = new SnapTxInsights(driver); + const contractAddress = await ( + contractRegistry as ContractAddressRegistry + ).getContractAddress(SMART_CONTRACTS.NFTS); + + // Navigate to test snaps page and click to the transaction-insights snap + await openTestSnapClickButtonAndInstall( + driver, + 'connectTransactionInsightButton', + ); + + await testDapp.openTestDappPage({ contractAddress, url: DAPP_URL }); + await testDapp.clickERC721MintButton(); + await driver.delay(veryLargeDelayMs); + await driver.switchToWindowWithTitle(WINDOW_TITLES.Dialog); + const mintConfirmation = new TransactionConfirmation(driver); + await mintConfirmation.clickFooterConfirmButton(); + await driver.switchToWindowWithTitle(WINDOW_TITLES.TestDApp); + await testDapp.clickERC721TransferFromButton(); + await driver.delay(veryLargeDelayMs); // this is needed for the transaction to be processed + + await driver.switchToWindowWithTitle(WINDOW_TITLES.Dialog); + await snapTxInsights.check_transactionInsightsTitle(); + await snapTxInsights.check_transactionAddress('0x5CfE7...6a7e1'); + await snapTxInsights.check_transactionAddress('0x581c3...45947'); + await snapTxInsights.check_transactionInsightsType('ERC-721'); + }, + ); + }); + + it('shows insights for ERC1155 transactions', async function () { + const smartContract = SMART_CONTRACTS.NFTS; + await withFixtures( + { + dapp: true, + fixtures: new FixtureBuilder() + .withPermissionControllerConnectedToTestDapp() + .build(), + smartContract, + title: this.test?.fullTitle(), + }, + async ({ driver, contractRegistry }: TestSuiteArguments) => { + await loginWithoutBalanceValidation(driver); + const testDapp = new TestDapp(driver); + const snapTxInsights = new SnapTxInsights(driver); + const contractAddress = await ( + contractRegistry as ContractAddressRegistry + ).getContractAddress(SMART_CONTRACTS.NFTS); + + // Navigate to test snaps page and click to the transaction-insights snap + await openTestSnapClickButtonAndInstall( + driver, + 'connectTransactionInsightButton', + ); + + await testDapp.openTestDappPage({ contractAddress, url: DAPP_URL }); + await testDapp.clickERC1155SetApprovalForAllButton(); + + await driver.switchToWindowWithTitle(WINDOW_TITLES.Dialog); + await snapTxInsights.check_transactionInsightsTitle(); + await snapTxInsights.check_transactionAddress('0x5CfE7...6a7e1'); + await snapTxInsights.check_transactionAddress('0x581c3...45947'); }, ); }); diff --git a/test/e2e/tests/confirmations/alerts/queued-confirmations.spec.ts b/test/e2e/tests/confirmations/alerts/queued-confirmations.spec.ts index a70f3e1dabdb..f6f88453ce33 100644 --- a/test/e2e/tests/confirmations/alerts/queued-confirmations.spec.ts +++ b/test/e2e/tests/confirmations/alerts/queued-confirmations.spec.ts @@ -36,7 +36,7 @@ describe('Queued Confirmations', function () { { dapp: true, fixtures: new FixtureBuilder() - .withNetworkControllerTripleGanache() + .withNetworkControllerTripleNode() .withSelectedNetworkControllerPerDomain() .build(), dappOptions: { numberOfDapps: 2 }, @@ -84,7 +84,7 @@ describe('Queued Confirmations', function () { { dapp: true, fixtures: new FixtureBuilder() - .withNetworkControllerTripleGanache() + .withNetworkControllerTripleNode() .withSelectedNetworkControllerPerDomain() .build(), @@ -140,7 +140,7 @@ describe('Queued Confirmations', function () { { dapp: true, fixtures: new FixtureBuilder() - .withNetworkControllerTripleGanache() + .withNetworkControllerTripleNode() .withPermissionControllerConnectedToTestDapp() .withSelectedNetworkControllerPerDomain() .build(), @@ -195,7 +195,7 @@ describe('Queued Confirmations', function () { { dapp: true, fixtures: new FixtureBuilder() - .withNetworkControllerTripleGanache() + .withNetworkControllerTripleNode() .withSelectedNetworkControllerPerDomain() .withMetaMetricsController({ @@ -284,7 +284,7 @@ describe('Queued Confirmations', function () { { dapp: true, fixtures: new FixtureBuilder() - .withNetworkControllerTripleGanache() + .withNetworkControllerTripleNode() .withPermissionControllerConnectedToTestDapp() .withSelectedNetworkControllerPerDomain() .withMetaMetricsController({ diff --git a/test/e2e/tests/confirmations/helpers.ts b/test/e2e/tests/confirmations/helpers.ts index 49b7ee297f15..8521c0281cf1 100644 --- a/test/e2e/tests/confirmations/helpers.ts +++ b/test/e2e/tests/confirmations/helpers.ts @@ -175,3 +175,39 @@ export async function mockedSourcifyTokenSend(mockServer: Mockttp) { }, })); } + +export async function mockEip7702FeatureFlag(mockServer: Mockttp) { + return [ + await mockServer + .forGet('https://client-config.api.cx.metamask.io/v1/flags') + .thenCallback(() => { + return { + ok: true, + statusCode: 200, + json: [ + { + confirmations_eip_7702: { + contracts: { + '0xaa36a7': [ + { + signature: + '0x016cf109489c415ba28e695eb3cb06ac46689c5c49e2aba101d7ec2f68c890282563b324f5c8df5e0536994451825aa235438b7346e8c18b4e64161d990781891c', + address: '0xCd8D6C5554e209Fbb0deC797C6293cf7eAE13454', + }, + ], + '0x539': [ + { + address: '0x8438Ad1C834623CfF278AB6829a248E37C2D7E3f', + signature: + '0x4c15775d0c6d5bd37a7aa7aafc62e85597ea705024581b8b5cb0edccc4e6a69e26c495b3ae725815a377c9789bff43bf19e4dd1eaa679e65133e49ceee3ea87f1b', + }, + ], + }, + supportedChains: ['0xaa36a7', '0x539'], + }, + }, + ], + }; + }), + ]; +} diff --git a/test/e2e/tests/confirmations/signatures/sign-typed-data-v4.spec.ts b/test/e2e/tests/confirmations/signatures/sign-typed-data-v4.spec.ts index 68f9d08091f4..8f210e1dcefb 100644 --- a/test/e2e/tests/confirmations/signatures/sign-typed-data-v4.spec.ts +++ b/test/e2e/tests/confirmations/signatures/sign-typed-data-v4.spec.ts @@ -1,7 +1,7 @@ import { TransactionEnvelopeType } from '@metamask/transaction-controller'; import { Suite } from 'mocha'; import { MockedEndpoint } from 'mockttp'; -import { WINDOW_TITLES } from '../../../helpers'; +import { unlockWallet, WINDOW_TITLES } from '../../../helpers'; import { Driver } from '../../../webdriver/driver'; import { mockSignatureApproved, @@ -10,8 +10,10 @@ import { withTransactionEnvelopeTypeFixtures, } from '../helpers'; import { TestSuiteArguments } from '../transactions/shared'; +import { DEFAULT_FIXTURE_ACCOUNT } from '../../../constants'; import SignTypedData from '../../../page-objects/pages/confirmations/redesign/sign-typed-data-confirmation'; import TestDapp from '../../../page-objects/pages/test-dapp'; +import TestDappIndividualRequest from '../../../page-objects/pages/test-dapp-individual-request'; import { assertAccountDetailsMetrics, assertHeaderInfoBalance, @@ -51,7 +53,7 @@ describe('Confirmation Signature - Sign Typed Data V4', function (this: Suite) { await copyAddressAndPasteWalletAddress(driver); await assertPastedAddress(); - await assertInfoValues(driver); + await assertInfoValues({ driver }); await scrollAndConfirmAndAssertConfirm(driver); await assertAccountDetailsMetrics( @@ -111,13 +113,41 @@ describe('Confirmation Signature - Sign Typed Data V4', function (this: Suite) { }, ); }); + + it('signs message with verifyingContract field missing', async function () { + await withTransactionEnvelopeTypeFixtures( + this.test?.fullTitle(), + TransactionEnvelopeType.legacy, + async ({ + driver, + }: TestSuiteArguments) => { + await unlockWallet(driver); + const testDappIndividualRequest = new TestDappIndividualRequest(driver); + + await testDappIndividualRequest.request( + 'eth_signTypedData_v4', + signatureMessageWithoutVerifyingContract, + ); + await driver.switchToWindowWithTitle(WINDOW_TITLES.Dialog); + await assertInfoValues({ driver, verifyingContract: false }); + await scrollAndConfirmAndAssertConfirm(driver); + await driver.switchToWindowWithTitle(WINDOW_TITLES.TestDappSendIndividualRequest); + + await testDappIndividualRequest.checkExpectedResult( + '0xdf05fb422b6623939c9ec6b622d21b97e3974cc8bf0d7534aa8e5972be4c1e954261493934ecd1088aa32f4b0686dc9a4a847bd51fb572aba1f69153035533781c', + ); + }, + ); + }); }); -async function assertInfoValues(driver: Driver) { +async function assertInfoValues({driver, verifyingContract = true} : {driver: Driver, verifyingContract?: boolean}) { const signTypedData = new SignTypedData(driver); await driver.switchToWindowWithTitle(WINDOW_TITLES.Dialog); + if (verifyingContract) { + await signTypedData.verifyContractPetName(); + }; await signTypedData.verifyOrigin(); - await signTypedData.verifyContractPetName(); await signTypedData.verifyPrimaryType(); await signTypedData.verifyFromName(); await signTypedData.verifyFromAddress(); @@ -136,3 +166,53 @@ async function assertVerifiedResults(driver: Driver, publicAddress: string) { '0xcd2f9c55840f5e1bcf61812e93c1932485b524ca673b36355482a4fbdf52f692684f92b4f4ab6f6c8572dacce46bd107da154be1c06939b855ecce57a1616ba71b', ); } + +const signatureMessageWithoutVerifyingContract = [ + DEFAULT_FIXTURE_ACCOUNT, + { + types: { + EIP712Domain: [ + { name: 'name', type: 'string' }, + { name: 'chainId', type: 'uint256' }, + { name: 'version', type: 'string' }, + ], + Person: [ + { name: 'name', type: 'string' }, + { name: 'wallets', type: 'address[]' }, + ], + Mail: [ + { name: 'from', type: 'Person' }, + { name: 'to', type: 'Person[]' }, + { name: 'contents', type: 'string' }, + { name: 'attachment', type: 'bytes' }, + ], + }, + primaryType: 'Mail', + domain: { + chainId: '0x539', + name: 'Ether Mail', + version: '1', + }, + message: { + contents: 'Hello, Bob!', + from: { + name: 'Cow', + wallets: [ + '0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826', + '0xDeaDbeefdEAdbeefdEadbEEFdeadbeEFdEaDbeeF', + ], + }, + to: [ + { + name: 'Bob', + wallets: [ + '0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB', + '0xB0BdaBea57B0BDABeA57b0bdABEA57b0BDabEa57', + '0xB0B0b0b0b0b0B000000000000000000000000000', + ], + }, + ], + attachment: '0x', + }, + }, +]; diff --git a/test/e2e/tests/confirmations/signatures/signature-helpers.ts b/test/e2e/tests/confirmations/signatures/signature-helpers.ts index 6a3bd53a0f75..295229aec725 100644 --- a/test/e2e/tests/confirmations/signatures/signature-helpers.ts +++ b/test/e2e/tests/confirmations/signatures/signature-helpers.ts @@ -14,6 +14,7 @@ import { BlockaidReason, BlockaidResultType, } from '../../../../../shared/constants/security-provider'; +import { loginWithBalanceValidation } from '../../../page-objects/flows/login.flow'; export const WALLET_ADDRESS = '0x5CfE73b6021E818B776b421B1c4Db2474086a7e1'; export const WALLET_ETH_BALANCE = '25'; @@ -397,8 +398,9 @@ export async function openDappAndTriggerSignature( driver: Driver, type: string, ) { - await unlockWallet(driver); + await loginWithBalanceValidation(driver); await testDapp.openTestDappPage({ url: DAPP_URL }); + await testDapp.check_pageIsLoaded(); await triggerSignature(type); await driver.switchToWindowWithTitle(WINDOW_TITLES.Dialog); } diff --git a/test/e2e/tests/confirmations/signatures/siwe.spec.ts b/test/e2e/tests/confirmations/signatures/siwe.spec.ts index a09602d2e78c..a6b19356888a 100644 --- a/test/e2e/tests/confirmations/signatures/siwe.spec.ts +++ b/test/e2e/tests/confirmations/signatures/siwe.spec.ts @@ -121,7 +121,6 @@ describe('Confirmation Signature - SIWE', function (this: Suite) { async function assertInfoValues(driver: Driver) { const confirmation = new PersonalSignConfirmation(driver); - await confirmation.clickCollapseSectionButton(); await confirmation.verifyOrigin(); - await confirmation.verifySiweMessage(); + await confirmation.check_siweMessage(); } diff --git a/test/e2e/tests/confirmations/transactions/eip7702-eip5792-upgrade-account.spec.ts b/test/e2e/tests/confirmations/transactions/eip7702-eip5792-upgrade-account.spec.ts new file mode 100644 index 000000000000..b160fab4f189 --- /dev/null +++ b/test/e2e/tests/confirmations/transactions/eip7702-eip5792-upgrade-account.spec.ts @@ -0,0 +1,87 @@ +import { strict as assert } from 'assert'; +import { Suite } from 'mocha'; +import { Anvil } from '@viem/anvil'; +import { Driver } from '../../../webdriver/driver'; +import { DEFAULT_FIXTURE_ACCOUNT } from '../../../constants'; +import FixtureBuilder from '../../../fixture-builder'; +import { WINDOW_TITLES, withFixtures } from '../../../helpers'; +import { loginWithBalanceValidation } from '../../../page-objects/flows/login.flow'; +import Eip7702AndSendCalls from '../../../page-objects/pages/confirmations/redesign/batch-confirmation'; +import ActivityListPage from '../../../page-objects/pages/home/activity-list'; +import HomePage from '../../../page-objects/pages/home/homepage'; +import TestDapp from '../../../page-objects/pages/test-dapp'; +import { mockEip7702FeatureFlag } from '../helpers'; + +describe('Upgrade Account', function (this: Suite) { + it('an EOA account can be upgraded when triggering a batch tx from a dapp in an odd chain id', async function () { + await withFixtures( + { + dapp: true, + fixtures: new FixtureBuilder() + .withPermissionControllerConnectedToTestDapp() + .build(), + localNodeOptions: [ + { + type: 'anvil', + options: { + hardfork: 'prague', + loadState: + './test/e2e/seeder/network-states/eip7702-state/withDelegatorContracts.json', + }, + }, + ], + testSpecificMock: mockEip7702FeatureFlag, + title: this.test?.fullTitle(), + }, + async ({ driver, localNodes }: { driver: Driver, localNodes: Anvil }) => { + await loginWithBalanceValidation(driver); + + // We check that we have an EOA account + let accountBytecode = await localNodes[0].getCode(DEFAULT_FIXTURE_ACCOUNT); + assert.strictEqual(accountBytecode, undefined); + + const testDapp = new TestDapp(driver); + await testDapp.openTestDappPage(); + await testDapp.clickSendCalls(); + + await driver.switchToWindowWithTitle(WINDOW_TITLES.Dialog); + + const upgradeAndBatchTxConfirmation = new Eip7702AndSendCalls(driver); + + // acknowledge splash page + await upgradeAndBatchTxConfirmation.tickSplashUpgradeButton(); + + await upgradeAndBatchTxConfirmation.check_expectedTxTypeIsDisplayed( + 'Smart account', + ); + await upgradeAndBatchTxConfirmation.check_expectedInteractingWithIsDisplayed( + 'Account 1', + ); + + // Open Settings and very tx details + await upgradeAndBatchTxConfirmation.clickAdvancedDetailsButton(); + await upgradeAndBatchTxConfirmation.check_batchTxListIsPresent(); + + // Confirm upgrade and batch tx + await upgradeAndBatchTxConfirmation.clickFooterConfirmButton(); + + await driver.switchToWindowWithTitle( + WINDOW_TITLES.ExtensionInFullScreenView, + ); + + // Check the batch transaction has been successfully performed + // which included x2 simple sends of 0.001ETH, so the ETH balance should also be updated + const homePage = new HomePage(driver); + await homePage.goToActivityList(); + + const activityList = new ActivityListPage(driver); + await activityList.check_confirmedTxNumberDisplayedInActivity(1); + await homePage.check_expectedBalanceIsDisplayed('24.9998', 'ETH'); + + // We check that we have an upgraded account + accountBytecode = await localNodes[0].getCode(DEFAULT_FIXTURE_ACCOUNT); + assert.strictEqual(accountBytecode, '0xef01008438ad1c834623cff278ab6829a248e37c2d7e3f'); + }, + ); + }); +}); diff --git a/test/e2e/tests/confirmations/transactions/erc20-approve-redesign.spec.ts b/test/e2e/tests/confirmations/transactions/erc20-approve-redesign.spec.ts index fd61d4878558..61ba0500a893 100644 --- a/test/e2e/tests/confirmations/transactions/erc20-approve-redesign.spec.ts +++ b/test/e2e/tests/confirmations/transactions/erc20-approve-redesign.spec.ts @@ -92,6 +92,12 @@ export async function importTST(driver: Driver) { text: 'Custom token', }); + await driver.clickElement( + '[data-testid="test-import-tokens-drop-down-custom-import"]', + ); + + await driver.clickElement('[data-testid="select-network-item-0x539"]'); + await driver.fill( '[data-testid="import-tokens-modal-custom-address"]', '0x581c3C1A2A4EBDE2A0Df29B5cf4c116E42945947', diff --git a/test/e2e/tests/confirmations/transactions/multiple-dapp-network-confirmation-routing.spec.ts b/test/e2e/tests/confirmations/transactions/multiple-dapp-network-confirmation-routing.spec.ts new file mode 100644 index 000000000000..b17070fd19a0 --- /dev/null +++ b/test/e2e/tests/confirmations/transactions/multiple-dapp-network-confirmation-routing.spec.ts @@ -0,0 +1,127 @@ +import { By } from 'selenium-webdriver'; + +import FixtureBuilder from '../../../fixture-builder'; +import { + DAPP_ONE_URL, + DAPP_URL, + unlockWallet, + WINDOW_TITLES, + withFixtures, +} from '../../../helpers'; +import TestDapp from '../../../page-objects/pages/test-dapp'; +import ConnectAccountConfirmation from '../../../page-objects/pages/confirmations/redesign/connect-account-confirmation'; + +describe('Routing confirmstions from Multiple Dapps and different networks', function () { + it('Confirmation requests from different DAPPS and networks should be in same queue, it is possible to navigate the queue.', async function () { + const port = 8546; + const chainId = 1338; + await withFixtures( + { + dapp: true, + fixtures: new FixtureBuilder() + .withNetworkControllerDoubleNode() + .build(), + dappOptions: { numberOfDapps: 2 }, + localNodeOptions: [ + { + type: 'anvil', + }, + { + type: 'anvil', + options: { + port, + chainId, + }, + }, + ], + title: this.test?.fullTitle(), + }, + + async ({ driver }) => { + if (process.env.EVM_MULTICHAIN_ENABLED === 'true') { + await unlockWallet(driver); + + // Open Dapp One + const testDapp1 = new TestDapp(driver); + await testDapp1.openTestDappPage({ url: DAPP_URL }); + // Connect to dapp 1 + await testDapp1.clickConnectAccountButton(); + + await driver.switchToWindowWithTitle(WINDOW_TITLES.Dialog); + + const connectAccountConfirmation1 = new ConnectAccountConfirmation( + driver, + ); + await connectAccountConfirmation1.check_pageIsLoaded(); + await connectAccountConfirmation1.confirmConnect(); + + // Wait for the first dapp's connect confirmation to disappear + await driver.switchToWindowWithTitle( + WINDOW_TITLES.ExtensionInFullScreenView, + ); + await driver.waitUntilXWindowHandles(2); + + // Connect to dapp 2 + const testDapp2 = new TestDapp(driver); + await testDapp2.openTestDappPage({ url: DAPP_ONE_URL }); + await testDapp2.clickConnectAccountButton(); + await driver.switchToWindowWithTitle(WINDOW_TITLES.Dialog); + const connectAccountConfirmation2 = new ConnectAccountConfirmation( + driver, + ); + await connectAccountConfirmation2.check_pageIsLoaded(); + await connectAccountConfirmation2.confirmConnect(); + + // Switch network on DAPP 2 + await driver.switchToWindowWithUrl(DAPP_ONE_URL); + await testDapp2.request('wallet_switchEthereumChain', [ + { chainId: '0x53a' }, + ]); + + // Dapp 1 send 2 tx + await driver.switchToWindowWithUrl(DAPP_URL); + await testDapp1.clickSimpleSendButton(); + await testDapp1.clickSimpleSendButton(); + + // Dapp 2 send 2 tx + await driver.switchToWindowWithUrl(DAPP_ONE_URL); + await testDapp2.clickSimpleSendButton(); + await testDapp2.clickSimpleSendButton(); + + // Dapp 1 send 1 more tx + await driver.switchToWindowWithUrl(DAPP_URL); + await testDapp1.clickSimpleSendButton(); + + await driver.switchToWindowWithTitle(WINDOW_TITLES.Dialog); + + await driver.waitForSelector( + By.xpath("//p[normalize-space(.)='1 of 5']"), + ); + + await driver.findElement({ + css: 'p', + text: 'Localhost 8546', + }); + + await driver.clickElement( + '[data-testid="confirm-nav__next-confirmation"]', + ); + await driver.clickElement( + '[data-testid="confirm-nav__next-confirmation"]', + ); + + await driver.findElement({ + css: 'p', + text: 'Localhost 8545', + }); + + // Reject All Transactions + await driver.clickElementAndWaitForWindowToClose({ + text: 'Reject all', + tag: 'button', + }); + } + }, + ); + }); +}); diff --git a/test/e2e/tests/confirmations/transactions/speed-up-and-cancel-confirmations.spec.ts b/test/e2e/tests/confirmations/transactions/speed-up-and-cancel-confirmations.spec.ts index c8d4a0c9214d..d5e1b2e340da 100644 --- a/test/e2e/tests/confirmations/transactions/speed-up-and-cancel-confirmations.spec.ts +++ b/test/e2e/tests/confirmations/transactions/speed-up-and-cancel-confirmations.spec.ts @@ -60,8 +60,9 @@ describe('Speed Up and Cancel Transaction Tests', function () { await activityListPage.click_transactionListItem(); await activityListPage.click_speedUpTransaction(); await activityListPage.click_confirmTransactionReplacement(); + await driver.delay(3000); // Delay needed to ensure the transaction is updated before mining (await localNodes?.[0]?.mineBlock()) ?? - console.error('localNodes is undefined or empty'); + console.error('localNodes is undefined or empty'); await activityListPage.check_waitForTransactionStatus('confirmed'); }, @@ -110,6 +111,7 @@ describe('Speed Up and Cancel Transaction Tests', function () { await activityListPage.click_cancelTransaction(); await activityListPage.click_confirmTransactionReplacement(); + await driver.delay(3000); // Delay needed to ensure the transaction updated before mining (await localNodes?.[0]?.mineBlock()) ?? console.error('localNodes is undefined or empty'); await activityListPage.check_waitForTransactionStatus('cancelled'); diff --git a/test/e2e/tests/connections/review-switch-permission-page.spec.ts b/test/e2e/tests/connections/review-switch-permission-page.spec.ts index 7496f68b669f..1797a81cc628 100644 --- a/test/e2e/tests/connections/review-switch-permission-page.spec.ts +++ b/test/e2e/tests/connections/review-switch-permission-page.spec.ts @@ -16,7 +16,7 @@ describe('Permissions Page when Dapp Switch to an enabled and non permissioned n { dapp: true, fixtures: new FixtureBuilder() - .withNetworkControllerDoubleGanache() + .withNetworkControllerDoubleNode() .withSelectedNetworkControllerPerDomain() .build(), localNodeOptions: [ diff --git a/test/e2e/tests/dapp-interactions/encrypt-decrypt.spec.js b/test/e2e/tests/dapp-interactions/encrypt-decrypt.spec.js deleted file mode 100644 index d8263839166e..000000000000 --- a/test/e2e/tests/dapp-interactions/encrypt-decrypt.spec.js +++ /dev/null @@ -1,233 +0,0 @@ -const { - withFixtures, - openDapp, - unlockWallet, - WINDOW_TITLES, -} = require('../../helpers'); -const FixtureBuilder = require('../../fixture-builder'); - -async function validateEncryptionKey(driver, encryptionKey) { - await driver.clickElement('#getEncryptionKeyButton'); - let windowHandles = await driver.waitUntilXWindowHandles(3); - await driver.switchToWindowWithTitle(WINDOW_TITLES.Dialog, windowHandles); - await driver.waitForSelector({ - css: '.request-encryption-public-key__header__text', - text: 'Request encryption public key', - }); - await driver.clickElement({ text: 'Provide', tag: 'button' }); - windowHandles = await driver.waitUntilXWindowHandles(2); - await driver.switchToWindowWithTitle('E2E Test Dapp', windowHandles); - await driver.findElement({ - css: '#encryptionKeyDisplay', - text: encryptionKey, - }); -} - -async function encryptMessage(driver, message) { - await driver.fill('#encryptMessageInput', message); - await driver.clickElement('#encryptButton'); - await driver.waitForSelector({ - css: '#ciphertextDisplay', - text: '0x', - }); -} - -async function decryptMessage(driver) { - await driver.clickElement('#decryptButton'); - const windowHandles = await driver.waitUntilXWindowHandles(3); - await driver.switchToWindowWithTitle(WINDOW_TITLES.Dialog, windowHandles); - await driver.waitForSelector({ - css: '.request-decrypt-message__header__text', - text: 'Decrypt request', - }); -} - -async function verifyDecryptedMessageMM(driver, message) { - await driver.clickElement({ text: 'Decrypt message', tag: 'div' }); - await driver.waitForSelector({ - text: message, - tag: 'div', - }); - await driver.clickElement({ text: 'Decrypt', tag: 'button' }); -} - -async function verifyDecryptedMessageDapp(driver, message) { - const windowHandles = await driver.getAllWindowHandles(); - await driver.switchToWindowWithTitle('E2E Test Dapp', windowHandles); - await driver.findElement({ - css: '#cleartextDisplay', - text: message, - }); -} - -describe('Encrypt Decrypt', function () { - const encryptionKey = 'fxYXfCbun026g5zcCQh7Ia+O0urAEVZWLG8H4Jzu7Xs='; - const message = 'Hello, Bob!'; - - it('should decrypt an encrypted message', async function () { - await withFixtures( - { - dapp: true, - fixtures: new FixtureBuilder() - .withPermissionControllerConnectedToTestDapp() - .build(), - title: this.test.fullTitle(), - }, - async ({ driver }) => { - await unlockWallet(driver); - await openDapp(driver); - - // ------ Get Encryption key ------ - await validateEncryptionKey(driver, encryptionKey); - - // ------ Encrypt ------ - await encryptMessage(driver, message); - - // ------ Decrypt ------ - await decryptMessage(driver); - - // Account balance is converted properly - await driver.waitForSelector({ - css: '.request-decrypt-message__balance-value', - text: '25 ETH', - }); - // Verify message in MetaMask Notification - await verifyDecryptedMessageMM(driver, message); - - // Verify message in Test Dapp - await driver.waitUntilXWindowHandles(2); - await verifyDecryptedMessageDapp(driver, message); - }, - ); - }); - - it('should encrypt and decrypt multiple messages', async function () { - const message2 = 'Hello, Alice!'; - await withFixtures( - { - dapp: true, - fixtures: new FixtureBuilder() - .withPermissionControllerConnectedToTestDapp() - .build(), - title: this.test.fullTitle(), - }, - async ({ driver }) => { - await unlockWallet(driver); - await openDapp(driver); - - // ------ Get Encryption key ------ - await validateEncryptionKey(driver, encryptionKey); - - // ------ Encrypt Message 1------ - await encryptMessage(driver, message); - - // ------ Decrypt Message 1 ------ - await decryptMessage(driver); - - // ------ Switch to Dapp ------ - let windowHandles = await driver.getAllWindowHandles(); - await driver.switchToWindowWithTitle('E2E Test Dapp', windowHandles); - - // ------ Encrypt Message 2------ - await encryptMessage(driver, message2); - - // ------ Decrypt Message 2 ------ - await decryptMessage(driver); - - // Verify message 1 in MetaMask Notification - await verifyDecryptedMessageMM(driver, message); - - // Verify message 1 in Test Dapp - await verifyDecryptedMessageDapp(driver, message); - - // ------ Switch to Dapp ------ - windowHandles = await driver.getAllWindowHandles(); - await driver.switchToWindowWithTitle( - WINDOW_TITLES.Dialog, - windowHandles, - ); - - // Verify message 2 in MetaMask Notification - await verifyDecryptedMessageMM(driver, message2); - - // Verify message 2 in Test Dapp - await verifyDecryptedMessageDapp(driver, message2); - }, - ); - }); - - it('should show balance correctly as ETH', async function () { - await withFixtures( - { - dapp: true, - fixtures: new FixtureBuilder() - .withPermissionControllerConnectedToTestDapp() - .build(), - title: this.test.fullTitle(), - }, - async ({ driver }) => { - await unlockWallet(driver); - await openDapp(driver); - - // ------ Get Encryption key and display ETH ------ - await driver.clickElement('#getEncryptionKeyButton'); - const windowHandles = await driver.waitUntilXWindowHandles(3); - await driver.switchToWindowWithTitle( - WINDOW_TITLES.Dialog, - windowHandles, - ); - await driver.waitForSelector({ - css: '.request-encryption-public-key__header__text', - text: 'Request encryption public key', - }); - // Account balance is converted properly - await driver.waitForSelector({ - css: '.request-encryption-public-key__balance-value', - text: '25 ETH', - }); - }, - ); - }); - - it('should show balance correctly in native tokens', async function () { - // In component ui/pages/confirm-encryption-public-key/confirm-encryption-public-key.container.js, after removing useNativeCurrencyAsPrimaryCurrency; - // We will display native balance in the confirm-encryption-public-key.component.js - await withFixtures( - { - dapp: true, - fixtures: new FixtureBuilder() - .withPermissionControllerConnectedToTestDapp() - .withPreferencesController({ - preferences: { - showNativeTokenAsMainBalance: false, - }, - }) - .build(), - title: this.test.fullTitle(), - }, - async ({ driver }) => { - await unlockWallet(driver); - - await openDapp(driver); - - // ------ Get Encryption key and display ETH ------ - await driver.clickElement('#getEncryptionKeyButton'); - const windowHandles = await driver.waitUntilXWindowHandles(3); - await driver.switchToWindowWithTitle( - WINDOW_TITLES.Dialog, - windowHandles, - ); - await driver.waitForSelector({ - css: '.request-encryption-public-key__header__text', - text: 'Request encryption public key', - }); - - // Account balance is converted properly - await driver.waitForSelector({ - css: '.request-encryption-public-key__balance-value', - text: '25 ETH', - }); - }, - ); - }); -}); diff --git a/test/e2e/tests/dapp-interactions/encrypt-decrypt.spec.ts b/test/e2e/tests/dapp-interactions/encrypt-decrypt.spec.ts new file mode 100644 index 000000000000..ab9e3a569ac9 --- /dev/null +++ b/test/e2e/tests/dapp-interactions/encrypt-decrypt.spec.ts @@ -0,0 +1,98 @@ +import { Suite } from 'mocha'; +import { WINDOW_TITLES, withFixtures } from '../../helpers'; +import FixtureBuilder from '../../fixture-builder'; +import DecryptMessageConfirmation from '../../page-objects/pages/confirmations/redesign/decrypt-message-confirmation'; +import TestDapp from '../../page-objects/pages/test-dapp'; +import { loginWithBalanceValidation } from '../../page-objects/flows/login.flow'; +import { decryptMessageAndVerifyResult, getEncryptionKeyInDapp } from '../../page-objects/flows/encrypt-decrypt.flow'; + +describe('Encrypt Decrypt', function (this: Suite) { + const encryptionKey = 'fxYXfCbun026g5zcCQh7Ia+O0urAEVZWLG8H4Jzu7Xs='; + const message = 'Hello, Bob!'; + + it('should decrypt an encrypted message', async function () { + await withFixtures( + { + dapp: true, + fixtures: new FixtureBuilder() + .withPermissionControllerConnectedToTestDapp() + .build(), + title: this.test?.fullTitle(), + }, + async ({ driver }) => { + await loginWithBalanceValidation(driver); + const testDapp = new TestDapp(driver); + await testDapp.openTestDappPage(); + await testDapp.check_pageIsLoaded(); + + // ------ Get Encryption key ------ + await getEncryptionKeyInDapp(driver, encryptionKey); + + // ------ Encrypt message ------ + await testDapp.encryptMessage(message); + + // ------ Decrypt message and verify the result ------ + await decryptMessageAndVerifyResult(driver, message); + + // ------ Verify decrypted message in Test Dapp ------ + await driver.switchToWindowWithTitle(WINDOW_TITLES.TestDApp); + await testDapp.check_pageIsLoaded(); + await testDapp.check_decryptedMessage(message); + }, + ); + }); + + it('should encrypt and decrypt multiple messages', async function () { + const message2 = 'Hello, Alice!'; + await withFixtures( + { + dapp: true, + fixtures: new FixtureBuilder() + .withPermissionControllerConnectedToTestDapp() + .build(), + title: this.test?.fullTitle(), + }, + async ({ driver }) => { + await loginWithBalanceValidation(driver); + const testDapp = new TestDapp(driver); + await testDapp.openTestDappPage(); + await testDapp.check_pageIsLoaded(); + + // ------ Get Encryption key ------ + await getEncryptionKeyInDapp(driver, encryptionKey); + + // ------ Encrypt Message 1------ + await testDapp.encryptMessage(message); + + // ------ Decrypt Message 1 on test dapp------ + await testDapp.clickDecryptButton(); + await driver.switchToWindowWithTitle(WINDOW_TITLES.Dialog); + const decryptMessageConfirmation = new DecryptMessageConfirmation(driver); + await decryptMessageConfirmation.check_pageIsLoaded(); + + // ------ Encrypt Message 2 ------ + await driver.switchToWindowWithTitle(WINDOW_TITLES.TestDApp); + await testDapp.check_pageIsLoaded(); + await testDapp.encryptMessage(message2); + + // ------ Decrypt Message 1 on test dapp and verify the result------ + await decryptMessageAndVerifyResult(driver, message); + await driver.switchToWindowWithTitle(WINDOW_TITLES.TestDApp); + await testDapp.check_pageIsLoaded(); + await testDapp.check_decryptedMessage(message); + + // ------ Decrypt Message 2 on and verify the result------ + await driver.switchToWindowWithTitle(WINDOW_TITLES.Dialog); + await decryptMessageConfirmation.check_pageIsLoaded(); + await decryptMessageConfirmation.clickDecryptMessageButton(); + await decryptMessageConfirmation.check_decryptedMessage(message2); + await decryptMessageConfirmation.clickToConfirmDecryptMessage(); + + // ------ Verify decrypted message 2 in Test Dapp ------ + await driver.switchToWindowWithTitle(WINDOW_TITLES.TestDApp); + await testDapp.check_pageIsLoaded(); + await testDapp.check_decryptedMessage(message2); + }, + ); + }); +}); diff --git a/test/e2e/tests/dapp-interactions/eth-subscribe.spec.js b/test/e2e/tests/dapp-interactions/eth-subscribe.spec.ts similarity index 72% rename from test/e2e/tests/dapp-interactions/eth-subscribe.spec.js rename to test/e2e/tests/dapp-interactions/eth-subscribe.spec.ts index df6ee273bedf..10894524d6be 100644 --- a/test/e2e/tests/dapp-interactions/eth-subscribe.spec.js +++ b/test/e2e/tests/dapp-interactions/eth-subscribe.spec.ts @@ -1,10 +1,7 @@ -const { - withFixtures, - openDapp, - DAPP_ONE_URL, - unlockWallet, -} = require('../../helpers'); -const FixtureBuilder = require('../../fixture-builder'); +import { DAPP_ONE_URL, withFixtures } from '../../helpers'; +import FixtureBuilder from '../../fixture-builder'; +import TestDapp from '../../page-objects/pages/test-dapp'; +import { loginWithBalanceValidation } from '../../page-objects/flows/login.flow'; describe('eth_subscribe', function () { it('only broadcasts subscription notifications on the page that registered the subscription', async function () { @@ -15,12 +12,13 @@ describe('eth_subscribe', function () { .withPermissionControllerConnectedToTestDapp() .build(), dappOptions: { numberOfDapps: 2 }, - title: this.test.fullTitle(), + title: this.test?.fullTitle(), }, async ({ driver }) => { - await unlockWallet(driver); - - await openDapp(driver); + await loginWithBalanceValidation(driver); + const testDapp = new TestDapp(driver); + await testDapp.openTestDappPage(); + await testDapp.check_pageIsLoaded(); const setupSubscriptionListener = ` const responseContainer = document.createElement('div'); @@ -52,18 +50,16 @@ describe('eth_subscribe', function () { `); // Verify that the new block is seen on the first dapp - await driver.findElement('[data-testid="eth-subscribe-response"]'); + await testDapp.check_ethSubscribeResponse(true); // Switch to the second dapp - await openDapp(driver, null, DAPP_ONE_URL); + const testDapp2 = new TestDapp(driver); + await testDapp2.openTestDappPage({ url: DAPP_ONE_URL }); + await testDapp2.check_pageIsLoaded(); // Setup the same subscription listener as on the first dapp, but without registering a new subscription await driver.executeScript(setupSubscriptionListener); - - await driver.assertElementNotPresent( - '[data-testid="eth-subscribe-response"]', - { waitAtLeastGuard: 1000 }, // A waitAtLeastGuard of 1000ms is the best choice here - ); + await testDapp2.check_ethSubscribeResponse(false); }, ); }); diff --git a/test/e2e/tests/dapp-interactions/permissions.spec.js b/test/e2e/tests/dapp-interactions/permissions.spec.js deleted file mode 100644 index 772fafd85cd5..000000000000 --- a/test/e2e/tests/dapp-interactions/permissions.spec.js +++ /dev/null @@ -1,71 +0,0 @@ -const { strict: assert } = require('assert'); -const { - withFixtures, - openDapp, - unlockWallet, - WINDOW_TITLES, -} = require('../../helpers'); -const FixtureBuilder = require('../../fixture-builder'); - -describe('Permissions', function () { - it('sets permissions and connect to Dapp', async function () { - await withFixtures( - { - dapp: true, - fixtures: new FixtureBuilder().build(), - title: this.test.fullTitle(), - }, - async ({ driver, localNodes }) => { - const addresses = await localNodes[0].getAccounts(); - const publicAddress = addresses[0].toLowerCase(); - await unlockWallet(driver); - - await openDapp(driver); - await driver.clickElement({ - text: 'Connect', - tag: 'button', - }); - - await driver.switchToWindowWithTitle(WINDOW_TITLES.Dialog); - await driver.clickElementAndWaitForWindowToClose({ - text: 'Connect', - tag: 'button', - }); - - await driver.switchToWindowWithTitle( - WINDOW_TITLES.ExtensionInFullScreenView, - ); - - // shows connected sites - await driver.clickElement( - '[data-testid="account-options-menu-button"]', - ); - await driver.clickElement({ - text: 'All Permissions', - tag: 'div', - }); - await driver.waitForSelector({ - text: '127.0.0.1:8080', - tag: 'p', - }); - const domains = await driver.findClickableElements( - '[data-testid="connection-list-item"]', - ); - assert.equal(domains.length, 1); - - // can get accounts within the dapp - await driver.switchToWindowWithTitle(WINDOW_TITLES.TestDApp); - - await driver.clickElement({ - text: 'eth_accounts', - tag: 'button', - }); - - await driver.waitForSelector({ - css: '#getAccountsResult', - text: publicAddress, - }); - }, - ); - }); -}); diff --git a/test/e2e/tests/dapp-interactions/permissions.spec.ts b/test/e2e/tests/dapp-interactions/permissions.spec.ts new file mode 100644 index 000000000000..bfe7c2607d0e --- /dev/null +++ b/test/e2e/tests/dapp-interactions/permissions.spec.ts @@ -0,0 +1,40 @@ +import { Suite } from 'mocha'; +import { withFixtures } from '../../helpers'; +import FixtureBuilder from '../../fixture-builder'; +import { DAPP_HOST_ADDRESS } from '../../constants'; +import HeaderNavbar from '../../page-objects/pages/header-navbar'; +import PermissionListPage from '../../page-objects/pages/permission/permission-list-page'; +import TestDapp from '../../page-objects/pages/test-dapp'; +import { loginWithBalanceValidation } from '../../page-objects/flows/login.flow'; + +describe('Permissions', function (this: Suite) { + it('sets permissions and connect to Dapp', async function () { + await withFixtures( + { + dapp: true, + fixtures: new FixtureBuilder() + .withPermissionControllerConnectedToTestDapp() + .build(), + title: this.test?.fullTitle(), + }, + async ({ driver, localNodes }) => { + const addresses = await localNodes[0].getAccounts(); + const publicAddress = addresses[0].toLowerCase(); + await loginWithBalanceValidation(driver); + + // open permissions page and check that the dapp is connected + await new HeaderNavbar(driver).openPermissionsPage(); + const permissionListPage = new PermissionListPage(driver); + await permissionListPage.check_pageIsLoaded(); + await permissionListPage.check_connectedToSite(DAPP_HOST_ADDRESS); + await permissionListPage.check_numberOfConnectedSites(); + + // can get accounts within the dapp + const testDapp = new TestDapp(driver); + await testDapp.openTestDappPage(); + await testDapp.check_pageIsLoaded(); + await testDapp.check_getAccountsResult(publicAddress); + }, + ); + }); +}); diff --git a/test/e2e/tests/dapp-interactions/provider-api.spec.js b/test/e2e/tests/dapp-interactions/provider-api.spec.ts similarity index 68% rename from test/e2e/tests/dapp-interactions/provider-api.spec.js rename to test/e2e/tests/dapp-interactions/provider-api.spec.ts index 75a63cd73de0..01778a5be816 100644 --- a/test/e2e/tests/dapp-interactions/provider-api.spec.js +++ b/test/e2e/tests/dapp-interactions/provider-api.spec.ts @@ -1,9 +1,12 @@ -const { strict: assert } = require('assert'); -const { errorCodes } = require('@metamask/rpc-errors'); -const { withFixtures, openDapp, unlockWallet } = require('../../helpers'); -const FixtureBuilder = require('../../fixture-builder'); +import { strict as assert } from 'assert'; +import { errorCodes } from '@metamask/rpc-errors'; +import { Suite } from 'mocha'; +import { withFixtures } from '../../helpers'; +import FixtureBuilder from '../../fixture-builder'; +import TestDapp from '../../page-objects/pages/test-dapp'; +import { loginWithBalanceValidation } from '../../page-objects/flows/login.flow'; -describe('MetaMask', function () { +describe('MetaMask', function (this: Suite) { it('should reject unsupported methods', async function () { await withFixtures( { @@ -11,12 +14,15 @@ describe('MetaMask', function () { fixtures: new FixtureBuilder() .withPermissionControllerConnectedToTestDapp() .build(), - title: this.test.fullTitle(), + title: this.test?.fullTitle(), }, async ({ driver }) => { - await unlockWallet(driver); + await loginWithBalanceValidation(driver); + + const testDapp = new TestDapp(driver); + await testDapp.openTestDappPage(); + await testDapp.check_pageIsLoaded(); - await openDapp(driver); for (const unsupportedMethod of ['eth_signTransaction']) { assert.equal( await driver.executeAsyncScript(` diff --git a/test/e2e/tests/dapp-interactions/revoke-permissions.spec.js b/test/e2e/tests/dapp-interactions/revoke-permissions.spec.js deleted file mode 100644 index a4c6ad86c69a..000000000000 --- a/test/e2e/tests/dapp-interactions/revoke-permissions.spec.js +++ /dev/null @@ -1,82 +0,0 @@ -const { withFixtures, openDapp, unlockWallet } = require('../../helpers'); -const FixtureBuilder = require('../../fixture-builder'); - -describe('Wallet Revoke Permissions', function () { - it('should revoke "eth_accounts" permissions via test dapp', async function () { - await withFixtures( - { - dapp: true, - fixtures: new FixtureBuilder() - .withPermissionControllerConnectedToTestDapp() - .build(), - title: this.test.fullTitle(), - }, - async ({ driver }) => { - await unlockWallet(driver); - await openDapp(driver); - - // Get initial accounts permissions - await driver.clickElement('#getPermissions'); - - await driver.waitForSelector({ - css: '#permissionsResult', - text: 'eth_accounts', - }); - - // Revoke eth_accounts permissions - await driver.clickElement('#revokeAccountsPermission'); - - // Get new allowed permissions - await driver.clickElement('#getPermissions'); - - // Eth_accounts permissions removed - await driver.waitForSelector({ - css: '#permissionsResult', - text: 'No permissions found.', - }); - }, - ); - }); - - it('should revoke "endowment:permitted-chains" permissions', async function () { - await withFixtures( - { - dapp: true, - fixtures: new FixtureBuilder() - .withPermissionControllerConnectedToTestDapp() - .build(), - title: this.test.fullTitle(), - }, - async ({ driver }) => { - await unlockWallet(driver); - await openDapp(driver); - - // Get initial accounts permissions - await driver.clickElement('#getPermissions'); - - const revokeChainsRequest = JSON.stringify({ - jsonrpc: '2.0', - method: 'wallet_revokePermissions', - params: [ - { - 'endowment:permitted-chains': {}, - }, - ], - }); - - await driver.executeScript( - `return window.ethereum.request(${revokeChainsRequest})`, - ); - - // Get new allowed permissions - await driver.clickElement('#getPermissions'); - - // Eth_accounts permissions removed - await driver.waitForSelector({ - css: '#permissionsResult', - text: 'No permissions found.', - }); - }, - ); - }); -}); diff --git a/test/e2e/tests/dapp-interactions/revoke-permissions.spec.ts b/test/e2e/tests/dapp-interactions/revoke-permissions.spec.ts new file mode 100644 index 000000000000..60204bb9051a --- /dev/null +++ b/test/e2e/tests/dapp-interactions/revoke-permissions.spec.ts @@ -0,0 +1,72 @@ +import { Suite } from 'mocha'; +import { withFixtures } from '../../helpers'; +import FixtureBuilder from '../../fixture-builder'; +import TestDapp from '../../page-objects/pages/test-dapp'; +import { loginWithBalanceValidation } from '../../page-objects/flows/login.flow'; + +describe('Wallet Revoke Permissions', function (this: Suite) { + it('should revoke "eth_accounts" permissions via test dapp', async function () { + await withFixtures( + { + dapp: true, + fixtures: new FixtureBuilder() + .withPermissionControllerConnectedToTestDapp() + .build(), + title: this.test?.fullTitle(), + }, + async ({ driver, localNodes }) => { + const addresses = await localNodes[0].getAccounts(); + const publicAddress = addresses[0].toLowerCase(); + await loginWithBalanceValidation(driver); + + // Get initial accounts permissions + const testDapp = new TestDapp(driver); + await testDapp.openTestDappPage(); + await testDapp.check_pageIsLoaded(); + await testDapp.check_getPermissionsResult('eth_accounts'); + + // Revoke eth_accounts permissions and check that the permission is removed + await testDapp.disconnectAccount(publicAddress); + await testDapp.check_getPermissionsResult('No permissions found.'); + }, + ); + }); + + it('should revoke "endowment:permitted-chains" permissions', async function () { + await withFixtures( + { + dapp: true, + fixtures: new FixtureBuilder() + .withPermissionControllerConnectedToTestDapp() + .build(), + title: this.test?.fullTitle(), + }, + async ({ driver }) => { + await loginWithBalanceValidation(driver); + const testDapp = new TestDapp(driver); + await testDapp.openTestDappPage(); + await testDapp.check_pageIsLoaded(); + + // Get initial accounts permissions + await testDapp.check_getPermissionsResult('eth_accounts'); + + const revokeChainsRequest = JSON.stringify({ + jsonrpc: '2.0', + method: 'wallet_revokePermissions', + params: [ + { + 'endowment:permitted-chains': {}, + }, + ], + }); + + await driver.executeScript( + `return window.ethereum.request(${revokeChainsRequest})`, + ); + + // Get new allowed permissions and check that the permission is removed + await testDapp.check_getPermissionsResult('No permissions found.'); + }, + ); + }); +}); diff --git a/test/e2e/tests/dapp-interactions/signin-with-ethereum.spec.js b/test/e2e/tests/dapp-interactions/signin-with-ethereum.spec.js deleted file mode 100644 index d273a01348b0..000000000000 --- a/test/e2e/tests/dapp-interactions/signin-with-ethereum.spec.js +++ /dev/null @@ -1,84 +0,0 @@ -const { strict: assert } = require('assert'); -const { - withFixtures, - openDapp, - unlockWallet, - WINDOW_TITLES, -} = require('../../helpers'); -const FixtureBuilder = require('../../fixture-builder'); - -describe('Sign in with ethereum', function () { - it('user should be able to confirm sign in with ethereum', async function () { - const expectedSigninMessageTitle = - 'A site wants you to sign in to prove you own this account.'; - const expectedSigninMessage = - 'I accept the MetaMask Terms of Service: https://community.metamask.io/tos'; - const expectedSignInResult = - '0xef8674a92d62a1876624547bdccaef6c67014ae821de18fa910fbff56577a65830f68848585b33d1f4b9ea1c3da1c1b11553b6aabe8446717daf7cd1e38a68271c'; - await withFixtures( - { - dapp: true, - fixtures: new FixtureBuilder() - .withPermissionControllerConnectedToTestDapp() - .build(), - title: this.test.fullTitle(), - }, - async ({ driver }) => { - await unlockWallet(driver); - - // Create a signin with ethereum request in test dapp - await openDapp(driver); - await driver.clickElement('#siwe'); - - // Wait for signature request popup and check the message title - await driver.waitUntilXWindowHandles(3); - let windowHandles = await driver.getAllWindowHandles(); - await driver.switchToWindowWithTitle( - WINDOW_TITLES.Dialog, - windowHandles, - ); - await driver.findElement({ - css: 'h2', - text: 'Sign-in request', - }); - await driver.findElement({ - css: 'p', - text: expectedSigninMessageTitle, - }); - await driver.findElement({ - css: 'p', - text: '127.0.0.1:8080', - }); - - // Check the displayed information in popup content - await driver.findElement({ - css: 'p', - text: expectedSigninMessage, - }); - await driver.findElement({ - css: 'p', - text: 'https://127.0.0.1:8080', - }); - await driver.findElement({ - css: 'p', - text: '1', - }); - await driver.findElement({ - css: 'p', - text: '1', - }); - - await driver.clickElement({ - css: 'button', - text: 'Confirm', - }); - - // Switch back to the dapp and verify the signed result - windowHandles = await driver.getAllWindowHandles(); - await driver.switchToWindowWithTitle('E2E Test Dapp', windowHandles); - const result = await driver.findElement('#siweResult'); - assert.equal(await result.getText(), expectedSignInResult); - }, - ); - }); -}); diff --git a/test/e2e/tests/metrics/errors.spec.js b/test/e2e/tests/metrics/errors.spec.js index 8c826a62acea..805163e7cbde 100644 --- a/test/e2e/tests/metrics/errors.spec.js +++ b/test/e2e/tests/metrics/errors.spec.js @@ -49,6 +49,7 @@ const maskedBackgroundFields = [ 'CurrencyController.currencyRates.ETH.conversionDate', 'CurrencyController.currencyRates.LineaETH.conversionDate', 'CurrencyController.currencyRates.SepoliaETH.conversionDate', + 'CurrencyController.currencyRates.MegaETH.conversionDate', ]; const maskedUiFields = maskedBackgroundFields.map(backgroundToUiField); diff --git a/test/e2e/tests/metrics/state-snapshots/errors-after-init-opt-in-background-state.json b/test/e2e/tests/metrics/state-snapshots/errors-after-init-opt-in-background-state.json index 01af4af1f45e..7a1e81c8bce1 100644 --- a/test/e2e/tests/metrics/state-snapshots/errors-after-init-opt-in-background-state.json +++ b/test/e2e/tests/metrics/state-snapshots/errors-after-init-opt-in-background-state.json @@ -63,34 +63,34 @@ "AuthenticationController": { "isSignedIn": "boolean" }, "BridgeController": { "bridgeFeatureFlags": { - "mobileConfig": "object", "extensionConfig": { - "refreshRate": "number", "maxRefreshCount": "number", + "refreshRate": "number", "support": "boolean", "chains": { "eip155:1": "object", "eip155:10": "object", + "eip155:56": "object", "eip155:137": "object", "eip155:324": "object", + "eip155:8453": "object", "eip155:42161": "object", "eip155:43114": "object", - "eip155:56": "object", "eip155:59144": "object", - "eip155:8453": "object", "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp": "object" } - } + }, + "mobileConfig": "object" }, "quoteRequest": { "srcTokenAddress": "0x0000000000000000000000000000000000000000" }, - "quotes": {}, - "quotesRefreshCount": 0, - "quoteFetchError": null, "quotesInitialLoadTime": null, + "quotes": {}, "quotesLastFetched": null, - "quotesLoadingStatus": null + "quotesLoadingStatus": null, + "quoteFetchError": null, + "quotesRefreshCount": 0 }, "BridgeStatusController": { "bridgeStatusState": { "txHistory": "object" } }, "CronjobController": { "jobs": "object", "events": "object" }, @@ -102,11 +102,6 @@ "conversionRate": 1700, "usdConversionRate": 1700 }, - "MegaETH": { - "conversionDate": null, - "conversionRate": null, - "usdConversionRate": null - }, "SepoliaETH": { "conversionDate": "number", "conversionRate": 1700, @@ -116,6 +111,11 @@ "conversionDate": "number", "conversionRate": 1700, "usdConversionRate": 1700 + }, + "MegaETH": { + "conversionDate": "number", + "conversionRate": 1700, + "usdConversionRate": 1700 } } }, @@ -138,6 +138,7 @@ "gasEstimateType": "none", "nonRPCGasFeeApisDisabled": "boolean" }, + "InstitutionalSnapController": "object", "KeyringController": { "isUnlocked": true, "keyrings": "object", @@ -189,6 +190,7 @@ "allNfts": "object", "ignoredNfts": "object" }, + "NftDetectionController": "object", "NotificationServicesController": { "subscriptionAccountsSeen": "object", "isMetamaskNotificationsFeatureSeen": "boolean", @@ -202,8 +204,8 @@ "isCheckingAccountsPresence": "boolean" }, "NotificationServicesPushController": { - "fcmToken": "string", "isPushEnabled": "boolean", + "fcmToken": "string", "isUpdatingFCMToken": "boolean" }, "OnboardingController": { @@ -238,7 +240,6 @@ "addSnapAccountEnabled": "boolean", "advancedGasFee": {}, "featureFlags": {}, - "incomingTransactionsPreferences": {}, "knownMethodData": "object", "currentLocale": "en", "identities": "object", @@ -269,7 +270,8 @@ "enableMV3TimestampSave": true, "useExternalServices": "boolean", "isMultiAccountBalancesEnabled": "boolean", - "showIncomingTransactions": "object" + "showIncomingTransactions": "object", + "manageInstitutionalWallets": "boolean" }, "QueuedRequestController": { "queuedRequestCount": 0 }, "RemoteFeatureFlagController": { diff --git a/test/e2e/tests/metrics/state-snapshots/errors-after-init-opt-in-ui-state.json b/test/e2e/tests/metrics/state-snapshots/errors-after-init-opt-in-ui-state.json index 114c27bf52c7..ea2cf44c063e 100644 --- a/test/e2e/tests/metrics/state-snapshots/errors-after-init-opt-in-ui-state.json +++ b/test/e2e/tests/metrics/state-snapshots/errors-after-init-opt-in-ui-state.json @@ -23,6 +23,7 @@ "externalServicesOnboardingToggleState": "boolean", "keyringRemovalSnapModal": "object", "showKeyringRemovalSnapModal": "boolean", + "showNewSrpAddedToast": "boolean", "importTokensModalOpen": "boolean", "deprecatedNetworkModalOpen": "boolean", "accountDetail": "object", @@ -109,9 +110,9 @@ "usdConversionRate": 1700 }, "MegaETH": { - "conversionDate": null, - "conversionRate": null, - "usdConversionRate": null + "conversionDate": "number", + "conversionRate": 1700, + "usdConversionRate": 1700 }, "SepoliaETH": { "conversionDate": "number", @@ -190,7 +191,6 @@ "bitcoinTestnetSupportEnabled": "boolean", "addSnapAccountEnabled": "boolean", "advancedGasFee": {}, - "incomingTransactionsPreferences": {}, "identities": "object", "lostIdentities": "object", "forgottenPassword": false, @@ -207,6 +207,7 @@ "useExternalServices": "boolean", "isMultiAccountBalancesEnabled": "boolean", "showIncomingTransactions": "object", + "manageInstitutionalWallets": "boolean", "metaMetricsId": "0x86bacb9b2bf9a7e8d2b147eadb95ac9aaa26842327cd24afc8bd4b3c1d136420", "marketingCampaignCookieId": null, "eventsBeforeMetricsOptIn": "object", diff --git a/test/e2e/tests/ppom/ppom-blockaid-alert-simple-send.spec.js b/test/e2e/tests/ppom/ppom-blockaid-alert-simple-send.spec.js index 9446f9d03d86..611b479d0d28 100644 --- a/test/e2e/tests/ppom/ppom-blockaid-alert-simple-send.spec.js +++ b/test/e2e/tests/ppom/ppom-blockaid-alert-simple-send.spec.js @@ -146,7 +146,7 @@ describe('Simple Send Security Alert - Blockaid', function () { async ({ driver }) => { await loginWithoutBalanceValidation(driver); - // We validate custom balance as it doesn't come from ganache but it's mocked + // We validate custom balance as it doesn't come from the local node but it's mocked await driver.waitForSelector({ css: '[data-testid="eth-overview__primary-currency"]', text: '20 ETH', @@ -186,7 +186,7 @@ describe('Simple Send Security Alert - Blockaid', function () { async ({ driver }) => { await loginWithoutBalanceValidation(driver); - // We validate custom balance as it doesn't come from ganache but it's mocked + // We validate custom balance as it doesn't come from the local node but it's mocked await driver.waitForSelector({ css: '[data-testid="eth-overview__primary-currency"]', text: '20 ETH', @@ -227,7 +227,7 @@ describe('Simple Send Security Alert - Blockaid', function () { async ({ driver }) => { await loginWithoutBalanceValidation(driver); - // We validate custom balance as it doesn't come from ganache but it's mocked + // We validate custom balance as it doesn't come from the local node but it's mocked await driver.waitForSelector({ css: '[data-testid="eth-overview__primary-currency"]', text: '20 ETH', diff --git a/test/e2e/tests/privacy/basic-functionality.spec.ts b/test/e2e/tests/privacy/basic-functionality.spec.ts index 9c301a5e86c2..519c77ca871f 100644 --- a/test/e2e/tests/privacy/basic-functionality.spec.ts +++ b/test/e2e/tests/privacy/basic-functionality.spec.ts @@ -11,6 +11,8 @@ import { completeImportSRPOnboardingFlow, importSRPOnboardingFlow, } from '../../page-objects/flows/onboarding.flow'; +import { mockEmptyPrices } from '../tokens/utils/mocks'; +import { CHAIN_IDS } from '../../../../shared/constants/network'; async function mockApis(mockServer: Mockttp) { return [ @@ -30,7 +32,7 @@ async function mockApis(mockServer: Mockttp) { }), await mockServer .forGet('https://min-api.cryptocompare.com/data/pricemulti') - .withQuery({ fsyms: 'ETH,MegaETH', tsyms: 'usd' }) + .withQuery({ fsyms: 'ETH', tsyms: 'usd' }) .thenCallback(() => { return { statusCode: 200, @@ -58,6 +60,7 @@ async function mockApis(mockServer: Mockttp) { }, }; }), + await mockEmptyPrices(mockServer, CHAIN_IDS.MAINNET), ]; } diff --git a/test/e2e/tests/request-queuing/batch-txs-per-dapp-diff-network.spec.js b/test/e2e/tests/request-queuing/batch-txs-per-dapp-diff-network.spec.js index f5356ecad70a..5451d60ee735 100644 --- a/test/e2e/tests/request-queuing/batch-txs-per-dapp-diff-network.spec.js +++ b/test/e2e/tests/request-queuing/batch-txs-per-dapp-diff-network.spec.js @@ -19,7 +19,7 @@ describe('Request Queuing for Multiple Dapps and Txs on different networks', fun { dapp: true, fixtures: new FixtureBuilder() - .withNetworkControllerDoubleGanache() + .withNetworkControllerDoubleNode() .build(), dappOptions: { numberOfDapps: 2 }, localNodeOptions: [ diff --git a/test/e2e/tests/request-queuing/batch-txs-per-dapp-extra-tx.spec.js b/test/e2e/tests/request-queuing/batch-txs-per-dapp-extra-tx.spec.js index 875a03b51aff..173f8931d009 100644 --- a/test/e2e/tests/request-queuing/batch-txs-per-dapp-extra-tx.spec.js +++ b/test/e2e/tests/request-queuing/batch-txs-per-dapp-extra-tx.spec.js @@ -19,7 +19,7 @@ describe('Request Queuing for Multiple Dapps and Txs on different networks', fun { dapp: true, fixtures: new FixtureBuilder() - .withNetworkControllerDoubleGanache() + .withNetworkControllerDoubleNode() .build(), dappOptions: { numberOfDapps: 2 }, localNodeOptions: [ diff --git a/test/e2e/tests/request-queuing/batch-txs-per-dapp-same-network.spec.js b/test/e2e/tests/request-queuing/batch-txs-per-dapp-same-network.spec.js index a20994729b7c..d54e1a71c0cc 100644 --- a/test/e2e/tests/request-queuing/batch-txs-per-dapp-same-network.spec.js +++ b/test/e2e/tests/request-queuing/batch-txs-per-dapp-same-network.spec.js @@ -19,7 +19,7 @@ describe('Request Queuing for Multiple Dapps and Txs on same networks', function { dapp: true, fixtures: new FixtureBuilder() - .withNetworkControllerTripleGanache() + .withNetworkControllerTripleNode() .build(), dappOptions: { numberOfDapps: 3 }, localNodeOptions: [ diff --git a/test/e2e/tests/request-queuing/chainid-check.spec.js b/test/e2e/tests/request-queuing/chainid-check.spec.js index 518fe6018d03..bf8a570119fa 100644 --- a/test/e2e/tests/request-queuing/chainid-check.spec.js +++ b/test/e2e/tests/request-queuing/chainid-check.spec.js @@ -7,7 +7,6 @@ const { DAPP_URL, regularDelayMs, WINDOW_TITLES, - switchToNotificationWindow, } = require('../../helpers'); const { PAGES } = require('../../webdriver/driver'); @@ -19,7 +18,7 @@ describe('Request Queueing chainId proxy sync', function () { { dapp: true, fixtures: new FixtureBuilder() - .withNetworkControllerDoubleGanache() + .withNetworkControllerDoubleNode() .withSelectedNetworkControllerPerDomain() .build(), localNodeOptions: [ @@ -81,14 +80,11 @@ describe('Request Queueing chainId proxy sync', function () { assert.equal(chainIdBeforeConnectAfterManualSwitch, '0x1'); // Connect to dapp - await driver.findClickableElement({ text: 'Connect', tag: 'button' }); await driver.clickElement('#connectButton'); - await driver.delay(regularDelayMs); - - await switchToNotificationWindow(driver); + await driver.switchToWindowWithTitle(WINDOW_TITLES.Dialog); - await driver.clickElement({ + await driver.clickElementAndWaitForWindowToClose({ text: 'Connect', tag: 'button', }); @@ -112,14 +108,12 @@ describe('Request Queueing chainId proxy sync', function () { `window.ethereum.request(${switchEthereumChainRequest})`, ); - await switchToNotificationWindow(driver); - await driver.findClickableElements({ + await driver.switchToWindowWithTitle(WINDOW_TITLES.Dialog); + await driver.clickElementAndWaitForWindowToClose({ text: 'Confirm', tag: 'button', }); - await driver.clickElement({ text: 'Confirm', tag: 'button' }); - await driver.switchToWindowWithTitle(WINDOW_TITLES.TestDApp); const chainIdAfterDappSwitch = await driver.executeScript( diff --git a/test/e2e/tests/request-queuing/dapp1-send-dapp2-signTypedData.spec.js b/test/e2e/tests/request-queuing/dapp1-send-dapp2-signTypedData.spec.js index be34bd380c7c..37af5accfc8e 100644 --- a/test/e2e/tests/request-queuing/dapp1-send-dapp2-signTypedData.spec.js +++ b/test/e2e/tests/request-queuing/dapp1-send-dapp2-signTypedData.spec.js @@ -18,7 +18,7 @@ describe('Request Queuing Dapp 1, Switch Tx -> Dapp 2 Send Tx', function () { { dapp: true, fixtures: new FixtureBuilder() - .withNetworkControllerTripleGanache() + .withNetworkControllerTripleNode() .withSelectedNetworkControllerPerDomain() .build(), dappOptions: { numberOfDapps: 2 }, diff --git a/test/e2e/tests/request-queuing/dapp1-subscribe-network-switch.spec.ts b/test/e2e/tests/request-queuing/dapp1-subscribe-network-switch.spec.ts index c4a54e572d11..b9371795d936 100644 --- a/test/e2e/tests/request-queuing/dapp1-subscribe-network-switch.spec.ts +++ b/test/e2e/tests/request-queuing/dapp1-subscribe-network-switch.spec.ts @@ -13,7 +13,7 @@ describe('Request Queueing', function () { { dapp: true, fixtures: new FixtureBuilder() - .withNetworkControllerDoubleGanache() + .withNetworkControllerDoubleNode() .build(), localNodeOptions: [ { diff --git a/test/e2e/tests/request-queuing/dapp1-switch-dapp2-eth-request-accounts.spec.js b/test/e2e/tests/request-queuing/dapp1-switch-dapp2-eth-request-accounts.spec.js index b4c5a67406ab..9dae40483cc4 100644 --- a/test/e2e/tests/request-queuing/dapp1-switch-dapp2-eth-request-accounts.spec.js +++ b/test/e2e/tests/request-queuing/dapp1-switch-dapp2-eth-request-accounts.spec.js @@ -18,7 +18,7 @@ describe('Request Queuing Dapp 1 Send Tx -> Dapp 2 Request Accounts Tx', functio { dapp: true, fixtures: new FixtureBuilder() - .withNetworkControllerDoubleGanache() + .withNetworkControllerDoubleNode() .withPermissionControllerConnectedToTestDapp() .build(), dappOptions: { numberOfDapps: 2 }, @@ -110,7 +110,7 @@ describe('Request Queuing Dapp 1 Send Tx -> Dapp 2 Request Accounts Tx', functio { dapp: true, fixtures: new FixtureBuilder() - .withNetworkControllerDoubleGanache() + .withNetworkControllerDoubleNode() .withPermissionControllerConnectedToTwoTestDapps() .build(), dappOptions: { numberOfDapps: 2 }, diff --git a/test/e2e/tests/request-queuing/dapp1-switch-dapp2-send.spec.js b/test/e2e/tests/request-queuing/dapp1-switch-dapp2-send.spec.js index 03341b6693b3..49c10fbdcc73 100644 --- a/test/e2e/tests/request-queuing/dapp1-switch-dapp2-send.spec.js +++ b/test/e2e/tests/request-queuing/dapp1-switch-dapp2-send.spec.js @@ -16,7 +16,7 @@ describe('Request Queuing Dapp 1, Switch Tx -> Dapp 2 Send Tx', function () { { dapp: true, fixtures: new FixtureBuilder() - .withNetworkControllerTripleGanache() + .withNetworkControllerTripleNode() .withSelectedNetworkControllerPerDomain() .build(), dappOptions: { numberOfDapps: 2 }, @@ -177,7 +177,7 @@ describe('Request Queuing Dapp 1, Switch Tx -> Dapp 2 Send Tx', function () { { dapp: true, fixtures: new FixtureBuilder() - .withNetworkControllerTripleGanache() + .withNetworkControllerTripleNode() .withSelectedNetworkControllerPerDomain() .build(), dappOptions: { numberOfDapps: 2 }, diff --git a/test/e2e/tests/request-queuing/multi-dapp-sendTx-revokePermission.spec.js b/test/e2e/tests/request-queuing/multi-dapp-sendTx-revokePermission.spec.js index 447a54e511b7..11d722511c20 100644 --- a/test/e2e/tests/request-queuing/multi-dapp-sendTx-revokePermission.spec.js +++ b/test/e2e/tests/request-queuing/multi-dapp-sendTx-revokePermission.spec.js @@ -16,7 +16,7 @@ describe('Request Queuing for Multiple Dapps and Txs on different networks revok { dapp: true, fixtures: new FixtureBuilder() - .withNetworkControllerDoubleGanache() + .withNetworkControllerDoubleNode() .build(), dappOptions: { numberOfDapps: 2 }, localNodeOptions: [ diff --git a/test/e2e/tests/request-queuing/multiple-networks-dapps-txs.spec.js b/test/e2e/tests/request-queuing/multiple-networks-dapps-txs.spec.js index 959ea75f4a15..ae78b8407489 100644 --- a/test/e2e/tests/request-queuing/multiple-networks-dapps-txs.spec.js +++ b/test/e2e/tests/request-queuing/multiple-networks-dapps-txs.spec.js @@ -17,7 +17,7 @@ describe('Request Queuing for Multiple Dapps and Txs on different networks.', fu { dapp: true, fixtures: new FixtureBuilder() - .withNetworkControllerDoubleGanache() + .withNetworkControllerDoubleNode() .withSelectedNetworkControllerPerDomain() .build(), dappOptions: { numberOfDapps: 2 }, diff --git a/test/e2e/tests/request-queuing/sendTx-switchChain-sendTx.spec.js b/test/e2e/tests/request-queuing/sendTx-switchChain-sendTx.spec.js index 64abaeb6fc20..dce29c8c0619 100644 --- a/test/e2e/tests/request-queuing/sendTx-switchChain-sendTx.spec.js +++ b/test/e2e/tests/request-queuing/sendTx-switchChain-sendTx.spec.js @@ -18,7 +18,7 @@ describe('Request Queuing Send Tx -> SwitchChain -> SendTx', function () { { dapp: true, fixtures: new FixtureBuilder() - .withNetworkControllerDoubleGanache() + .withNetworkControllerDoubleNode() .withPermissionControllerConnectedToTestDapp() .build(), diff --git a/test/e2e/tests/request-queuing/switch-network.spec.js b/test/e2e/tests/request-queuing/switch-network.spec.js index a3d79fcf0292..3e938995231a 100644 --- a/test/e2e/tests/request-queuing/switch-network.spec.js +++ b/test/e2e/tests/request-queuing/switch-network.spec.js @@ -17,7 +17,7 @@ describe('Request Queuing Switch Network on Dapp Send Tx while on different netw { dapp: true, fixtures: new FixtureBuilder() - .withNetworkControllerDoubleGanache() + .withNetworkControllerDoubleNode() .withPermissionControllerConnectedToTestDapp() .build(), localNodeOptions: [ diff --git a/test/e2e/tests/request-queuing/switchChain-sendTx.spec.js b/test/e2e/tests/request-queuing/switchChain-sendTx.spec.js index 6bb5672292cb..11c66f3aa81e 100644 --- a/test/e2e/tests/request-queuing/switchChain-sendTx.spec.js +++ b/test/e2e/tests/request-queuing/switchChain-sendTx.spec.js @@ -14,7 +14,7 @@ describe('Request Queuing SwitchChain -> SendTx', function () { { dapp: true, fixtures: new FixtureBuilder() - .withNetworkControllerDoubleGanache() + .withNetworkControllerDoubleNode() .build(), localNodeOptions: [ { diff --git a/test/e2e/tests/request-queuing/switchChain-watchAsset.spec.js b/test/e2e/tests/request-queuing/switchChain-watchAsset.spec.js index 3c7d07765b23..07d9c74ae34e 100644 --- a/test/e2e/tests/request-queuing/switchChain-watchAsset.spec.js +++ b/test/e2e/tests/request-queuing/switchChain-watchAsset.spec.js @@ -18,7 +18,7 @@ describe('Request Queue SwitchChain -> WatchAsset', function () { { dapp: true, fixtures: new FixtureBuilder() - .withNetworkControllerDoubleGanache() + .withNetworkControllerDoubleNode() .build(), localNodeOptions: [ diff --git a/test/e2e/tests/request-queuing/ui.spec.js b/test/e2e/tests/request-queuing/ui.spec.js index 36f77aa154d2..312eaa218450 100644 --- a/test/e2e/tests/request-queuing/ui.spec.js +++ b/test/e2e/tests/request-queuing/ui.spec.js @@ -202,7 +202,7 @@ describe('Request-queue UI changes', function () { { dapp: true, fixtures: new FixtureBuilder() - .withNetworkControllerDoubleGanache() + .withNetworkControllerDoubleNode() .build(), localNodeOptions: [ { @@ -265,7 +265,7 @@ describe('Request-queue UI changes', function () { { dapp: true, fixtures: new FixtureBuilder() - .withNetworkControllerTripleGanache() + .withNetworkControllerTripleNode() .build(), localNodeOptions: [ { @@ -391,7 +391,7 @@ describe('Request-queue UI changes', function () { { dapp: true, fixtures: new FixtureBuilder() - .withNetworkControllerDoubleGanache() + .withNetworkControllerDoubleNode() .withPreferencesController({ preferences: { showTestNetworks: true }, }) @@ -510,7 +510,7 @@ describe('Request-queue UI changes', function () { { dapp: true, fixtures: new FixtureBuilder() - .withNetworkControllerDoubleGanache() + .withNetworkControllerDoubleNode() .build(), localNodeOptions: [ { @@ -563,7 +563,7 @@ describe('Request-queue UI changes', function () { { dapp: true, fixtures: new FixtureBuilder() - .withNetworkControllerDoubleGanache() + .withNetworkControllerDoubleNode() .build(), localNodeOptions: [ { @@ -633,7 +633,7 @@ describe('Request-queue UI changes', function () { { dapp: true, fixtures: new FixtureBuilder() - .withNetworkControllerDoubleGanache() + .withNetworkControllerDoubleNode() .build(), localNodeOptions: [ { @@ -647,7 +647,7 @@ describe('Request-queue UI changes', function () { }, }, ], - // This test intentionally quits Ganache while the extension is using it, causing + // This test intentionally quits the local node server while the extension is using it, causing // PollingBlockTracker errors and others. These are expected. ignoredConsoleErrors: ['ignore-all'], dappOptions: { numberOfDapps: 2 }, @@ -671,7 +671,7 @@ describe('Request-queue UI changes', function () { text: 'Ethereum Mainnet', }); - // Kill ganache servers + // Kill local node servers await localNodes[0].quit(); await localNodes[1].quit(); @@ -700,7 +700,7 @@ describe('Request-queue UI changes', function () { // Presently confirmations take up to 10 seconds to display on a dead network driverOptions: { timeOut: 30000 }, fixtures: new FixtureBuilder() - .withNetworkControllerDoubleGanache() + .withNetworkControllerDoubleNode() .build(), localNodeOptions: [ diff --git a/test/e2e/tests/request-queuing/watchAsset-switchChain-watchAsset.spec.js b/test/e2e/tests/request-queuing/watchAsset-switchChain-watchAsset.spec.js index d9d295de975c..5186838fc376 100644 --- a/test/e2e/tests/request-queuing/watchAsset-switchChain-watchAsset.spec.js +++ b/test/e2e/tests/request-queuing/watchAsset-switchChain-watchAsset.spec.js @@ -19,7 +19,7 @@ describe('Request Queue WatchAsset -> SwitchChain -> WatchAsset', function () { { dapp: true, fixtures: new FixtureBuilder() - .withNetworkControllerDoubleGanache() + .withNetworkControllerDoubleNode() .withPermissionControllerConnectedToTestDapp() .build(), localNodeOptions: [ diff --git a/test/e2e/tests/safe-window-close.spec.ts b/test/e2e/tests/safe-window-close.spec.ts new file mode 100644 index 000000000000..20f345987f43 --- /dev/null +++ b/test/e2e/tests/safe-window-close.spec.ts @@ -0,0 +1,65 @@ +import { strict as assert } from 'assert'; +import { withFixtures, unlockWallet, WINDOW_TITLES } from '../helpers'; +import FixtureBuilder from '../fixture-builder'; +import { Driver, PAGES } from '../webdriver/driver'; +import { loginWithBalanceValidation } from '../page-objects/flows/login.flow'; +import TestDapp from '../page-objects/pages/test-dapp'; + +describe('Notification window closing', function () { + it('closes the window when running in a popup', async function () { + await withFixtures( + { + dapp: true, + fixtures: new FixtureBuilder().build(), + title: this.test?.title, + }, + async ({ driver }: { driver: Driver }) => { + await loginWithBalanceValidation(driver); + const testDapp = new TestDapp(driver); + await testDapp.openTestDappPage(); + + // wallet_requestPermissions + const requestPermissionsRequest = JSON.stringify({ + jsonrpc: '2.0', + method: 'wallet_requestPermissions', + params: [{ eth_accounts: {} }], + }); + await driver.executeScript( + `window.ethereum.request(${requestPermissionsRequest})`, + ); + + // confirm connect account + await driver.switchToWindowWithTitle(WINDOW_TITLES.Dialog); + await driver.clickElementAndWaitForWindowToClose( + '[data-testid="confirm-btn"]', + ); + }, + ); + }); + it('does not close the window when running in a tab', async function () { + await withFixtures( + { + // Use your regular extension fixtures + fixtures: new FixtureBuilder().withMetaMetricsController().build(), + title: this.test?.fullTitle(), + }, + async ({ driver }: { driver: Driver }) => { + await unlockWallet(driver); + + // Ensure the window does not close + // 1. Get the current window handle + const currentHandle = await driver.driver.getWindowHandle(); + + // Navigate to notification page in a tab. + await driver.navigate(PAGES.NOTIFICATION); + + // 2. Verify the window still exists by checking handles + const windowHandles = await driver.getAllWindowHandles(); + assert.ok( + windowHandles.includes(currentHandle), + 'Window closed unexpectedly', + ); + }, + ); + }); +}); diff --git a/test/e2e/tests/settings/change-language.spec.ts b/test/e2e/tests/settings/change-language.spec.ts index 02ad0af9362b..c46e9ada37fa 100644 --- a/test/e2e/tests/settings/change-language.spec.ts +++ b/test/e2e/tests/settings/change-language.spec.ts @@ -12,8 +12,12 @@ import SettingsPage from '../../page-objects/pages/settings/settings-page'; import { loginWithBalanceValidation } from '../../page-objects/flows/login.flow'; const selectors = { - labelSpanish: { tag: 'p', text: 'Idioma actual' }, - currentLanguageLabel: { tag: 'p', text: 'Current language' }, + currentLanguageDansk: { tag: 'p', text: 'NuvƦrende sprog' }, + currentLanguageDeutsch: { tag: 'p', text: 'Aktuelle Sprache' }, + currentLanguageEnglish: { tag: 'p', text: 'Current language' }, + currentLanguageMagyar: { tag: 'p', text: 'AktuĆ”lis nyelv' }, + currentLanguageSpanish: { tag: 'p', text: 'Idioma actual' }, + currentLanguageą¤µą¤°ą„ą¤¤ą¤®ą¤¾ą¤Ø: { tag: 'p', text: 'ą¤µą¤°ą„ą¤¤ą¤®ą¤¾ą¤Ø भाषा' }, advanceText: { text: 'Avanceret', tag: 'div' }, waterText: '[placeholder="SĆøg"]', headerTextDansk: { text: 'Indstillinger', tag: 'h3' }, @@ -41,7 +45,7 @@ describe('Settings - general tab', function (this: Suite) { // Change language to Spanish and validate that the word has changed correctly await generalSettings.changeLanguage('EspaƱol'); const isLanguageLabelChanged = await driver.isElementPresent( - selectors.labelSpanish, + selectors.currentLanguageSpanish, ); assert.equal(isLanguageLabelChanged, true, 'Language did not change'); @@ -49,7 +53,7 @@ describe('Settings - general tab', function (this: Suite) { await driver.refresh(); await generalSettings.check_pageIsLoaded(); assert.equal( - await driver.isElementPresent(selectors.labelSpanish), + await driver.isElementPresent(selectors.currentLanguageSpanish), true, 'Language did not change after refresh', ); @@ -57,7 +61,7 @@ describe('Settings - general tab', function (this: Suite) { // Change language back to English and validate that the word has changed correctly await generalSettings.changeLanguage('English'); const isLabelTextChanged = await driver.isElementPresent( - selectors.currentLanguageLabel, + selectors.currentLanguageEnglish, ); assert.equal(isLabelTextChanged, true, 'Language did not change'); }, @@ -78,6 +82,11 @@ describe('Settings - general tab', function (this: Suite) { // Select "Dansk" language await generalSettings.changeLanguage('Dansk'); + const isLanguageLabelChanged = await driver.isElementPresent( + selectors.currentLanguageDansk, + ); + assert.equal(isLanguageLabelChanged, true, 'Language did not change'); + await driver.clickElement(selectors.advanceText); const advancedSettings = new AdvancedSettings(driver); await advancedSettings.check_pageIsLoaded(); @@ -129,6 +138,11 @@ describe('Settings - general tab', function (this: Suite) { // Select "Deutsch" language await generalSettings.changeLanguage('Deutsch'); + const isLanguageLabelChanged = await driver.isElementPresent( + selectors.currentLanguageDeutsch, + ); + assert.equal(isLanguageLabelChanged, true, 'Language did not change'); + await new SettingsPage(driver).closeSettingsPage(); const homepage = new Homepage(driver); @@ -170,6 +184,12 @@ describe('Settings - general tab', function (this: Suite) { // Select "मानक ą¤¹ą¤æą¤Øą„ą¤¦ą„€" language await generalSettings.changeLanguage('मानक ą¤¹ą¤æą¤Øą„ą¤¦ą„€'); + + const isLabelTextChanged = await driver.isElementPresent( + selectors.currentLanguageą¤µą¤°ą„ą¤¤ą¤®ą¤¾ą¤Ø, + ); + assert.equal(isLabelTextChanged, true, 'Language did not change'); + await new SettingsPage(driver).closeSettingsPage(); const homepage = new Homepage(driver); await homepage.check_pageIsLoaded(); @@ -212,6 +232,11 @@ describe('Settings - general tab', function (this: Suite) { // Select "Magyar" language await generalSettings.changeLanguage('Magyar'); + const isLabelTextChanged = await driver.isElementPresent( + selectors.currentLanguageMagyar, + ); + assert.equal(isLabelTextChanged, true, 'Language did not change'); + await new SettingsPage(driver).closeSettingsPage(); const homepage = new Homepage(driver); await homepage.check_pageIsLoaded(); diff --git a/test/e2e/tests/settings/localization.spec.js b/test/e2e/tests/settings/localization.spec.js index f411f77726ba..84c477116289 100644 --- a/test/e2e/tests/settings/localization.spec.js +++ b/test/e2e/tests/settings/localization.spec.js @@ -4,7 +4,7 @@ const FixtureBuilder = require('../../fixture-builder'); async function mockPhpConversion(mockServer) { return await mockServer .forGet('https://min-api.cryptocompare.com/data/pricemulti') - .withQuery({ fsyms: 'ETH,MegaETH', tsyms: 'php,USD' }) + .withQuery({ fsyms: 'ETH', tsyms: 'php,USD' }) .thenCallback(() => { return { statusCode: 200, diff --git a/test/e2e/tests/swap-send/swap-send-eth-with-loaded-state.spec.ts b/test/e2e/tests/swap-send/swap-send-eth-with-loaded-state.spec.ts new file mode 100644 index 000000000000..be7e5601aa99 --- /dev/null +++ b/test/e2e/tests/swap-send/swap-send-eth-with-loaded-state.spec.ts @@ -0,0 +1,344 @@ +import { Suite } from 'mocha'; +import { MockttpServer } from 'mockttp'; +import { + logInWithBalanceValidation, + openActionMenuAndStartSendFlow, + withFixtures, +} from '../../helpers'; +import FixtureBuilder from '../../fixture-builder'; +import HeaderNavbar from '../../page-objects/pages/header-navbar'; +import SettingsPage from '../../page-objects/pages/settings/settings-page'; +import AdvancedSettings from '../../page-objects/pages/settings/advanced-settings'; +import HomePage from '../../page-objects/pages/home/homepage'; +import { DEFAULT_FIXTURE_ACCOUNT } from '../../constants'; +import { NATIVE_TOKEN_SYMBOL, SwapSendPage } from './swap-send-test-utils'; +import fs from 'fs'; + +async function mockSwapQuotes(mockServer: MockttpServer) { + const BRIDGE_GET_ALL_FEATURE_FLAGS_PATH = + 'test/e2e/mock-response-data/bridge-get-all-feature-flags.json'; + const BRIDGE_GET_ALL_FEATURE_FLAGS = fs.readFileSync( + BRIDGE_GET_ALL_FEATURE_FLAGS_PATH, + ); + return [ + await mockServer + .forGet('https://price.api.cx.metamask.io/v2/chains/1/spot-prices') + .thenCallback(() => ({ + statusCode: 200, + json: {}, + })), + + await mockServer + .forGet('https://bridge.dev-api.cx.metamask.io/getAllFeatureFlags') + .thenCallback(() => { + return { + statusCode: 200, + json: JSON.parse(BRIDGE_GET_ALL_FEATURE_FLAGS.toString()), + }; + }), + + await mockServer + .forGet( + 'https://accounts.api.cx.metamask.io/v2/accounts/0x5cfe73b6021e818b776b421b1c4db2474086a7e1/balances', + ) + .thenCallback(() => ({ + statusCode: 200, + json: { + count: 0, + balances: [ + { + object: 'token', + address: '0x0000000000000000000000000000000000000000', + symbol: 'ETH', + name: 'Ether', + type: 'native', + timestamp: '2015-07-30T03:26:13.000Z', + decimals: 18, + chainId: 1, + balance: '20', + }, + ], + unprocessedNetworks: [], + }, + })), + + await mockServer + .forGet('https://swap.api.cx.metamask.io/token/1') + .thenCallback(() => ({ + statusCode: 200, + json: { + symbol: 'WETH', + type: 'erc20', + aggregators: [ + 'metamask', + 'aave', + 'coinGecko', + 'oneInch', + 'pmm', + 'zerion', + 'lifi', + 'socket', + 'squid', + 'sonarwatch', + 'uniswapLabs', + 'coinmarketcap', + 'rango', + ], + occurrences: 13, + iconUrl: + 'https://raw.githubusercontent.com/MetaMask/contract-metadata/master/images/weth.svg', + address: '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2', + name: 'Wrapped Ether', + decimals: 18, + }, + })), + await mockServer + .forPost('https://transaction.api.cx.metamask.io/networks/1/getFees') + .thenCallback(() => ({ + statusCode: 200, + json: { + blockNumber: 22017409, + id: 'b6d9c5f3-4fee-4470-be1b-6c574fe61315', + txs: [ + { + cancelFees: [], + return: '0x', + status: 1, + gasUsed: 188186, + gasLimit: 241302, + fees: [ + { + maxFeePerGas: 6393950816, + maxPriorityFeePerGas: 1000000004, + gas: 241302, + balanceNeeded: 1542873120043734, + currentBalance: 30009434625664560, + error: '', + }, + ], + feeEstimate: 821886724082654, + baseFeePerGas: 3367416938, + maxFeeEstimate: 1542873119802432, + }, + ], + }, + })), + + await mockServer + .forGet('https://swap.api.cx.metamask.io/v2/networks/1/quotes') + .thenCallback(() => ({ + statusCode: 200, + json: [ + { + aggregator: 'WETH', + aggregatorType: 'CONTRACT', + destinationToken: '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2', + sourceToken: '0x0000000000000000000000000000000000000000', + sourceAmount: '10000000000000000000', + destinationAmount: '10000000000000000000', + trade: { + data: '0xd0e30db0', + from: '0x5CfE73b6021E818B776b421B1c4Db2474086a7e1', + to: '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2', + value: '10000000000000000000', + }, + sender: '0x5CfE73b6021E818B776b421B1c4Db2474086a7e1', + recipient: '0x5CfE73b6021E818B776b421B1c4Db2474086a7e1', + error: null, + gasParams: { + maxGas: 500000, + averageGas: 300000, + estimatedRefund: 0, + gasMultiplier: 1, + }, + fee: 0, + approvalNeeded: null, + priceSlippage: null, + sourceTokenRate: 1, + destinationTokenRate: 0.9999285710414016, + }, + ], + })), + + await mockServer + .forGet('https://swap.api.cx.metamask.io/networks/1') + .thenCallback(() => ({ + statusCode: 200, + json: { + active: true, + networkId: 1, + chainId: 1, + chainName: 'Ethereum Mainnet', + nativeCurrency: { + name: 'Ether', + symbol: 'ETH', + decimals: 18, + address: '0x0000000000000000000000000000000000000000', + }, + iconUrl: 'https://s3.amazonaws.com/airswap-token-images/ETH.png', + blockExplorerUrl: 'https://etherscan.io', + networkType: 'L1', + aggregators: [ + 'airswapV3', + 'airswapV4', + 'oneInchV4', + 'oneInchV5', + 'paraswap', + 'pmm', + 'zeroEx', + 'openOcean', + 'hashFlow', + 'wrappedNative', + 'kyberSwap', + 'airSwapV4_3', + 'hashFlowV3', + ], + refreshRates: { + quotes: 30, + quotesPrefetching: 30, + stxGetTransactions: 10, + stxBatchStatus: 1, + stxStatusDeadline: 160, + stxMaxFeeMultiplier: 2, + }, + parameters: { + refreshRates: { + quotes: 30, + quotesPrefetching: 30, + stxGetTransactions: 10, + stxBatchStatus: 1, + }, + stxStatusDeadline: 160, + stxMaxFeeMultiplier: 2, + }, + }, + })), + ]; +} + +describe('Swap-Send ETH', function () { + describe('to non-contract address with data that matches swap data signature', function (this: Suite) { + it('submits a transaction successfully with max amount', async function () { + await withFixtures( + { + fixtures: new FixtureBuilder() + .withNetworkControllerOnMainnet() + .withTokensController({ + allTokens: { + '0x1': { + '0x5cfe73b6021e818b776b421b1c4db2474086a7e1': [ + { + address: '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2', + symbol: 'WETH', + decimals: 18, + isERC721: false, + aggregators: [], + }, + ], + }, + }, + }) + .build(), + title: this.test?.fullTitle(), + testSpecificMock: mockSwapQuotes, + localNodeOptions: [ + { + type: 'anvil', + options: { + chainId: 1, + hardfork: 'london', + loadState: + './test/e2e/seeder/network-states/swap-state/withSwapContracts.json', + }, + }, + ], + }, + async ({ driver }) => { + const swapSendPage = new SwapSendPage(driver); + await logInWithBalanceValidation(driver); + + const homePage = new HomePage(driver); + await homePage.check_pageIsLoaded(); + await homePage.check_expectedTokenBalanceIsDisplayed('50', 'WETH'); + await homePage.check_expectedTokenBalanceIsDisplayed('25', 'ETH'); + + // disable smart transactions + const headerNavbar = new HeaderNavbar(driver); + await headerNavbar.check_pageIsLoaded(); + await headerNavbar.openSettingsPage(); + + const settingsPage = new SettingsPage(driver); + await settingsPage.check_pageIsLoaded(); + await settingsPage.clickAdvancedTab(); + const advancedSettingsPage = new AdvancedSettings(driver); + await advancedSettingsPage.check_pageIsLoaded(); + await advancedSettingsPage.toggleSmartTransactions(); + await settingsPage.closeSettingsPage(); + + // START SWAP AND SEND FLOW + await openActionMenuAndStartSendFlow(driver); + + await swapSendPage.fillRecipientAddressInput(DEFAULT_FIXTURE_ACCOUNT); + await swapSendPage.fillAmountInput('1'); + + await swapSendPage.verifyMaxButtonClick( + ['ETH', 'ETH'], + ['24.99945808355143', '24.99945808355143'], + ); + + await swapSendPage.fillAmountInput('10'); + await swapSendPage.verifyAssetSymbolsAndAmounts( + [NATIVE_TOKEN_SYMBOL, NATIVE_TOKEN_SYMBOL], + ['10', '10'], + ); + + await swapSendPage.fillAmountInput('10'); + + const ETH_WETH_TOKEN_INPUTS = [ + [NATIVE_TOKEN_SYMBOL, 'WETH'], + ['10', '10'], + ]; + const ETH_WETH_FIAT_INPUTS = [ + ['USD', 'USD'], + ['1,700.00', '1,701.09'], + ]; + + await swapSendPage.clickOnAsset('WETH', 'dest'); + await swapSendPage.verifyAssetSymbolsAndAmounts( + ETH_WETH_TOKEN_INPUTS[0], + ETH_WETH_TOKEN_INPUTS[1], + ); + + await swapSendPage.verifySwitchPrimaryCurrency( + ETH_WETH_TOKEN_INPUTS, + ETH_WETH_FIAT_INPUTS, + ); + + await swapSendPage.verifyQuoteDisplay( + '1 ETH = 1 WETH', + '0.0129028 ETH', + 'ā‰ˆ $21.93', + ); + + await swapSendPage.submitSwap(); + await swapSendPage.verifyHistoryEntry( + 'Send ETH as WETH', + 'Confirmed', + '-10 ETH', + '', + ); + + await homePage.goToTokensTab(); + await homePage.check_expectedTokenBalanceIsDisplayed('60', 'WETH'); + // https://github.com/MetaMask/metamask-extension/issues/31427 + // await homePage.check_expectedTokenBalanceIsDisplayed( + // '14.99994', + // 'ETH', + // ); + + driver.summarizeErrorsAndExceptions(); + }, + ); + }); + }); +}); diff --git a/test/e2e/tests/swap-send/swap-send-eth.spec.ts b/test/e2e/tests/swap-send/swap-send-eth.spec.ts deleted file mode 100644 index 875b856fb723..000000000000 --- a/test/e2e/tests/swap-send/swap-send-eth.spec.ts +++ /dev/null @@ -1,101 +0,0 @@ -import { Suite } from 'mocha'; -import { - logInWithBalanceValidation, - openActionMenuAndStartSendFlow, - withFixtures, -} from '../../helpers'; -import { - NATIVE_TOKEN_SYMBOL, - SwapSendPage, - getSwapSendFixtures, -} from './swap-send-test-utils'; - -const RECIPIENT_ADDRESS = '0xc427D562164062a23a5cFf596A4a3208e72Acd28'; - -describe('Swap-Send ETH', function () { - describe('to non-contract address with data that matches swap data signature', function (this: Suite) { - it('submits a transaction successfully', async function () { - await withFixtures( - getSwapSendFixtures(this.test?.fullTitle()), - async ({ driver }) => { - const swapSendPage = new SwapSendPage(driver); - await logInWithBalanceValidation(driver); - - // START SWAP AND SEND FLOW - await openActionMenuAndStartSendFlow(driver); - - await swapSendPage.fillRecipientAddressInput(RECIPIENT_ADDRESS); - await swapSendPage.fillAmountInput('1'); - - await swapSendPage.searchAndSelectToken('TST', 'src'); - await swapSendPage.verifyAssetSymbolsAndAmounts( - ['TST', 'TST'], - ['0', '0'], - ); - - await swapSendPage.searchAndSelectToken(NATIVE_TOKEN_SYMBOL, 'src'); - await swapSendPage.fillAmountInput('1'); - - const ETH_TST_TOKEN_INPUTS = [ - [NATIVE_TOKEN_SYMBOL, 'TST'], - ['1', '301075.4807'], - ]; - const ETH_TST_FIAT_INPUTS = [ - ['USD', 'USD'], - ['100', '3010.754807'], - ]; - - await swapSendPage.searchAndSelectToken('TST', 'dest'); - await swapSendPage.verifyAssetSymbolsAndAmounts( - ETH_TST_TOKEN_INPUTS[0], - ETH_TST_TOKEN_INPUTS[1], - ); - - await swapSendPage.verifySwitchPrimaryCurrency( - ETH_TST_TOKEN_INPUTS, - ETH_TST_FIAT_INPUTS, - ); - - await swapSendPage.verifyQuoteDisplay( - '1 ETH = 301075.4807 TST', - '0.0129028 ETH', - 'ā‰ˆ $38.84', - ); - - // TODO assert swap api request payload - - await swapSendPage.submitSwap(); - await swapSendPage.verifyHistoryEntry( - 'Send ETH as TST', - 'Confirmed', - '-1 ETH', - '', - ); - - driver.summarizeErrorsAndExceptions(); - }, - ); - }); - }); - - it('sets max amount', async function () { - await withFixtures( - getSwapSendFixtures(this.test?.fullTitle()), - async ({ driver }) => { - const swapSendPage = new SwapSendPage(driver); - await logInWithBalanceValidation(driver); - - // START SWAP AND SEND FLOW - await openActionMenuAndStartSendFlow(driver); - - await swapSendPage.fillRecipientAddressInput(RECIPIENT_ADDRESS); - await swapSendPage.fillAmountInput('1'); - - await swapSendPage.verifyMaxButtonClick( - ['ETH', 'ETH'], - ['24.9970184730279925', '24.9970184730279925'], - ); - }, - ); - }); -}); diff --git a/test/e2e/tests/swap-send/swap-send-test-utils.ts b/test/e2e/tests/swap-send/swap-send-test-utils.ts index 4c10a444afba..a6d6c5b57802 100644 --- a/test/e2e/tests/swap-send/swap-send-test-utils.ts +++ b/test/e2e/tests/swap-send/swap-send-test-utils.ts @@ -19,16 +19,36 @@ export class SwapSendPage { } fillRecipientAddressInput = async (address: string) => { + console.log('Step: fillRecipientAddressInput'); await this.driver.fill( 'input[placeholder="Enter public address (0x) or domain name"]', address, ); }; + async clickOnAsset( + assetName: string, + location: 'src' | 'dest' = 'src', + ): Promise { + console.log('Step: clickOnAsset'); + const isDest = location === 'dest'; + const buttons = await this.driver.findElements( + '[data-testid="asset-picker-button"]', + ); + const indexOfButtonToClick = isDest ? 1 : 0; + await buttons[indexOfButtonToClick].click(); + + await this.driver.clickElement({ + css: '[data-testid="multichain-token-list-item"]', + text: assetName, + }); + } + searchAndSelectToken = async ( symbol: string, location: 'src' | 'dest' = 'src', ) => { + console.log('Step: searchAndSelectToken'); const isDest = location === 'dest'; const buttons = await this.driver.findElements( '[data-testid="asset-picker-button"]', @@ -90,6 +110,7 @@ export class SwapSendPage { expectedInputValues: string[], delayInMs = 0, ) => { + console.log('Step: verifyAssetSymbolsAndAmounts'); await this.driver.delay(1000); const assetPickers = await this.driver.findElements( '[data-testid="asset-picker-button"]', @@ -123,6 +144,7 @@ export class SwapSendPage { }; fillAmountInput = async (amount: string) => { + console.log('Step: fillAmountInput'); await this.driver.waitForSelector('[data-testid="currency-input"]'); await this.driver.fill('[data-testid="currency-input"]', amount); }; @@ -131,6 +153,7 @@ export class SwapSendPage { expectedAssetSymbols: string[], expectedInputValues: string[], ) => { + console.log('Step: verifyMaxButtonClick'); const maxButton = await this.driver.findElement( '[data-testid="max-clear-button"]', ); @@ -153,6 +176,7 @@ export class SwapSendPage { initialParams: string[][], _expectedParams: string[][], ) => { + console.log('Step: switchPrimaryCurrency'); await this.verifyAssetSymbolsAndAmounts(initialParams[0], initialParams[1]); // TODO click currency switch button @@ -168,6 +192,7 @@ export class SwapSendPage { initialParams: string[][], expectedParams: string[][], ) => { + console.log('Step: verifySwitchPrimaryCurrency'); await this.switchPrimaryCurrency(initialParams, expectedParams); // TODO uncomment these // await this.switchPrimaryCurrency(expectedParams, initialParams); @@ -180,6 +205,7 @@ export class SwapSendPage { expectedGasFee: string, expectedGasFeeInFiat: string, ) => { + console.log('Step: verifyQuoteDisplay'); // TODO verify that swaps was only called once const quoteRate = await this.driver.findElement( '[data-testid="quote-card__conversion-rate"]', @@ -206,6 +232,7 @@ export class SwapSendPage { expectedTokenChange?: string, expectedFiatChange?: string, ) => { + console.log('Step: verifyHistoryEntry'); // TODO loop through entries by the same confirmation const status = await this.driver.findElement( `.transaction-status-label--${expectedStatus.toLowerCase()}`, @@ -239,6 +266,7 @@ export class SwapSendPage { }; submitSwap = async () => { + console.log('Step: submitSwap'); await ( await this.driver.findClickableElement({ text: 'Confirm', diff --git a/test/e2e/tests/swaps/swap-erc20-with-loaded-state.spec.ts b/test/e2e/tests/swaps/swap-erc20-with-loaded-state.spec.ts index f8cf72ecc6dc..6355857f95e1 100644 --- a/test/e2e/tests/swaps/swap-erc20-with-loaded-state.spec.ts +++ b/test/e2e/tests/swaps/swap-erc20-with-loaded-state.spec.ts @@ -1,4 +1,4 @@ -import { MockttpServer } from 'mockttp'; +import { MockttpServer, CompletedRequest } from 'mockttp'; import { withFixtures } from '../../helpers'; import FixtureBuilder from '../../fixture-builder'; import AssetListPage from '../../page-objects/pages/home/asset-list'; @@ -9,9 +9,19 @@ import AdvancedSettings from '../../page-objects/pages/settings/advanced-setting import HeaderNavbar from '../../page-objects/pages/header-navbar'; import SettingsPage from '../../page-objects/pages/settings/settings-page'; import SwapPage from '../../page-objects/pages/swap/swap-page'; +import { + mockEmptyHistoricalPrices, + mockEmptyPrices, +} from '../tokens/utils/mocks'; +import { DEFAULT_FIXTURE_ACCOUNT } from '../../constants'; async function mockSwapQuotes(mockServer: MockttpServer) { + const WETH_ADDRESS = '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2'; + const ETH_ADDRESS = '0x0000000000000000000000000000000000000000'; + return [ + await mockEmptyHistoricalPrices(mockServer, ETH_ADDRESS, '0x1'), + await mockEmptyPrices(mockServer, '1'), await mockServer .forGet('https://swap.api.cx.metamask.io/token/1') .thenCallback(() => ({ @@ -37,7 +47,7 @@ async function mockSwapQuotes(mockServer: MockttpServer) { occurrences: 13, iconUrl: 'https://raw.githubusercontent.com/MetaMask/contract-metadata/master/images/weth.svg', - address: '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2', + address: WETH_ADDRESS, name: 'Wrapped Ether', decimals: 18, }, @@ -75,124 +85,242 @@ async function mockSwapQuotes(mockServer: MockttpServer) { })), await mockServer .forGet('https://swap.api.cx.metamask.io/networks/1/trades') + .thenCallback((request: CompletedRequest) => { + const url = new URL(request.url); + const sourceToken = url.searchParams.get('sourceToken')?.toLowerCase(); + const destinationToken = url.searchParams + .get('destinationToken') + ?.toLowerCase(); + const walletAddress = + url.searchParams.get('walletAddress') || DEFAULT_FIXTURE_ACCOUNT; + const sourceAmount = url.searchParams.get('sourceAmount'); + + const isEthToWeth = + sourceToken === ETH_ADDRESS && destinationToken === WETH_ADDRESS; + + const data = isEthToWeth + ? '0xd0e30db0' + : '0x2e1a7d4d0000000000000000000000000000000000000000000000008ac7230489e80000'; + const response = { + statusCode: 200, + json: [ + { + trade: { + data, + to: WETH_ADDRESS, + value: isEthToWeth ? sourceAmount : '0', + from: walletAddress, + }, + hasRoute: false, + sourceAmount, + destinationAmount: sourceAmount, + error: null, + sourceToken: sourceToken || ETH_ADDRESS, + destinationToken: destinationToken || WETH_ADDRESS, + maxGas: 300000, + averageGas: 280000, + estimatedRefund: 0, + isGasIncludedTrade: false, + approvalNeeded: null, + fetchTime: 27, + aggregator: 'wrappedNative', + aggType: 'CONTRACT', + fee: 0, + quoteRefreshSeconds: 30, + gasMultiplier: 1.1, + sourceTokenRate: 1, + destinationTokenRate: 1.001552079142939, + priceSlippage: { + ratio: 1.0005795645538318, + calculationError: '', + bucket: 'low', + sourceAmountInUSD: 20705.2, + destinationAmountInUSD: 20693.2, + sourceAmountInNativeCurrency: 10, + destinationAmountInNativeCurrency: 10.01552079142939, + sourceAmountInETH: 10, + destinationAmountInETH: 10.01552079142939, + }, + }, + ], + }; + return response; + }), + + await mockServer + .forGet('https://swap.api.cx.metamask.io/networks/1') .thenCallback(() => ({ statusCode: 200, - json: [ - { - trade: { - data: '0x2e1a7d4d0000000000000000000000000000000000000000000000008ac7230489e80000', - to: '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2', - value: '0', - from: '0x5cfe73b6021e818b776b421b1c4db2474086a7e1', - }, - hasRoute: false, - sourceAmount: '10000000000000000000', - destinationAmount: '10000000000000000000', - error: null, - sourceToken: '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2', - destinationToken: '0x0000000000000000000000000000000000000000', - maxGas: 300000, - averageGas: 280000, - estimatedRefund: 0, - isGasIncludedTrade: false, - approvalNeeded: null, - fetchTime: 63, - aggregator: 'wrappedNative', - aggType: 'CONTRACT', - fee: 0, - quoteRefreshSeconds: 30, - gasMultiplier: 1.1, - sourceTokenRate: 0.9996738094827067, - destinationTokenRate: 1, - priceSlippage: { - ratio: 0.9997007391742396, - alculationError: '', - bucket: 'low', - sourceAmountInUSD: 20049.4, - destinationAmountInUSD: 20055.4, - sourceAmountInNativeCurrency: 9.996738094827068, - destinationAmountInNativeCurrency: 10, - sourceAmountInETH: 9.996738094827068, - destinationAmountInETH: 10, + json: { + active: true, + networkId: 1, + chainId: 1, + chainName: 'Ethereum Mainnet', + nativeCurrency: { + name: 'Ether', + symbol: 'ETH', + decimals: 18, + address: ETH_ADDRESS, + }, + iconUrl: 'https://s3.amazonaws.com/airswap-token-images/ETH.png', + blockExplorerUrl: 'https://etherscan.io', + networkType: 'L1', + aggregators: [ + 'airswapV3', + 'airswapV4', + 'oneInchV4', + 'oneInchV5', + 'paraswap', + 'pmm', + 'zeroEx', + 'openOcean', + 'hashFlow', + 'wrappedNative', + 'kyberSwap', + 'airSwapV4_3', + 'hashFlowV3', + ], + refreshRates: { + quotes: 30, + quotesPrefetching: 30, + stxGetTransactions: 10, + stxBatchStatus: 1, + stxStatusDeadline: 160, + stxMaxFeeMultiplier: 2, + }, + parameters: { + refreshRates: { + quotes: 30, + quotesPrefetching: 30, + stxGetTransactions: 10, + stxBatchStatus: 1, }, + stxStatusDeadline: 160, + stxMaxFeeMultiplier: 2, }, - ], + }, })), ]; } describe('Swap', function () { - it('should swap WETH to ETH', async function () { - await withFixtures( - { - fixtures: new FixtureBuilder() - .withNetworkControllerOnMainnet() - .withTokensController({ - allTokens: { - '0x1': { - '0x5cfe73b6021e818b776b421b1c4db2474086a7e1': [ - { - address: '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2', - symbol: 'WETH', - decimals: 18, - isERC721: false, - aggregators: [], - }, - ], + const swapTestCases = [ + { + name: 'should swap WETH to ETH', + sourceToken: 'WETH', + destinationToken: 'Ether', + sourceAmount: '10', + expectedWethBalance: '40', + expectedEthBalance: '34.99991', + dismissWarning: false, + }, + { + name: 'should swap ETH to WETH', + sourceToken: 'Ethereum', + destinationToken: 'WETH', + sourceAmount: '10', + expectedWethBalance: '60', + expectedEthBalance: '14.99992', + dismissWarning: true, + }, + ]; + + swapTestCases.forEach((testCase) => { + it(testCase.name, async function () { + await withFixtures( + { + fixtures: new FixtureBuilder() + .withNetworkControllerOnMainnet() + .withPreferencesController({ + preferences: { + tokenNetworkFilter: { + '0x1': true, + }, + }, + }) + .withTokensController({ + allTokens: { + '0x1': { + '0x5cfe73b6021e818b776b421b1c4db2474086a7e1': [ + { + address: '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2', + symbol: 'WETH', + decimals: 18, + isERC721: false, + aggregators: [], + }, + ], + }, + }, + }) + .build(), + title: this.test?.fullTitle(), + testSpecificMock: mockSwapQuotes, + localNodeOptions: [ + { + type: 'anvil', + options: { + chainId: 1, + hardfork: 'london', + loadState: + './test/e2e/seeder/network-states/swap-state/withSwapContracts.json', }, }, - }) - .build(), - title: this.test?.fullTitle(), - testSpecificMock: mockSwapQuotes, - localNodeOptions: [ - { - type: 'anvil', - options: { - chainId: 1, - hardfork: 'london', - loadState: - './test/e2e/seeder/network-states/swap-state/withSwapContracts.json', - }, - }, - ], - }, - async ({ driver, localNodes }) => { - await loginWithBalanceValidation(driver, localNodes[0]); - - const homePage = new HomePage(driver); - await homePage.check_pageIsLoaded(); - await homePage.check_expectedTokenBalanceIsDisplayed('50', 'WETH'); - - // disable smart transactions - const headerNavbar = new HeaderNavbar(driver); - await headerNavbar.check_pageIsLoaded(); - await headerNavbar.openSettingsPage(); - - const settingsPage = new SettingsPage(driver); - await settingsPage.check_pageIsLoaded(); - await settingsPage.clickAdvancedTab(); - const advancedSettingsPage = new AdvancedSettings(driver); - await advancedSettingsPage.check_pageIsLoaded(); - await advancedSettingsPage.toggleSmartTransactions(); - await settingsPage.closeSettingsPage(); - - // Swap WETH to ETH - const assetListPage = new AssetListPage(driver); - await assetListPage.clickOnAsset('WETH'); - - const tokenOverviewPage = new TokenOverviewPage(driver); - await tokenOverviewPage.check_pageIsLoaded(); - await tokenOverviewPage.clickSwap(); - - const swapPage = new SwapPage(driver); - await swapPage.check_pageIsLoaded(); - await swapPage.enterSwapAmount('10'); - await swapPage.selectDestinationToken('Ether'); - await swapPage.submitSwap(); - - await homePage.check_expectedTokenBalanceIsDisplayed('40', 'WETH'); - }, - ); + ], + }, + async ({ driver, localNodes }) => { + await loginWithBalanceValidation(driver, localNodes[0]); + + const homePage = new HomePage(driver); + await homePage.check_pageIsLoaded(); + await homePage.check_expectedTokenBalanceIsDisplayed('50', 'WETH'); + await homePage.check_expectedTokenBalanceIsDisplayed('25', 'ETH'); + + // disable smart transactions + const headerNavbar = new HeaderNavbar(driver); + await headerNavbar.check_pageIsLoaded(); + await headerNavbar.openSettingsPage(); + + const settingsPage = new SettingsPage(driver); + await settingsPage.check_pageIsLoaded(); + await settingsPage.clickAdvancedTab(); + const advancedSettingsPage = new AdvancedSettings(driver); + await advancedSettingsPage.check_pageIsLoaded(); + await advancedSettingsPage.toggleSmartTransactions(); + await settingsPage.closeSettingsPage(); + + // Swap tokens + const assetListPage = new AssetListPage(driver); + await assetListPage.clickOnAsset(testCase.sourceToken); + + const tokenOverviewPage = new TokenOverviewPage(driver); + await tokenOverviewPage.check_pageIsLoaded(); + await tokenOverviewPage.clickSwap(); + + const swapPage = new SwapPage(driver); + await swapPage.check_pageIsLoaded(); + await swapPage.enterSwapAmount(testCase.sourceAmount); + await swapPage.selectDestinationToken(testCase.destinationToken); + + // https://github.com/MetaMask/metamask-extension/issues/31426 + if (testCase.dismissWarning) { + await swapPage.dismissManualTokenWarning(); + } + await driver.delay(1500); + await swapPage.submitSwap(); + + await homePage.check_expectedTokenBalanceIsDisplayed( + testCase.expectedWethBalance, + 'WETH', + ); + + // https://github.com/MetaMask/metamask-extension/issues/31427 + // await homePage.check_expectedTokenBalanceIsDisplayed( + // testCase.expectedEthBalance, + // 'ETH', + // ); + }, + ); + }); }); }); diff --git a/test/e2e/tests/swaps/swaps-notifications.spec.ts b/test/e2e/tests/swaps/swaps-notifications.spec.ts index be18c166b93e..f2c0f70c8a97 100644 --- a/test/e2e/tests/swaps/swaps-notifications.spec.ts +++ b/test/e2e/tests/swaps/swaps-notifications.spec.ts @@ -167,6 +167,7 @@ describe('Swaps - notifications', function () { await withFixtures( { fixtures: new FixtureBuilder().build(), + testSpecificMock: mockSwapsTransactionQuote, title: this.test?.fullTitle(), }, async ({ driver }) => { diff --git a/test/e2e/tests/tokens/add-token-using-search.spec.ts b/test/e2e/tests/tokens/add-token-using-search.spec.ts index 450ab541cdbe..ab179414f135 100644 --- a/test/e2e/tests/tokens/add-token-using-search.spec.ts +++ b/test/e2e/tests/tokens/add-token-using-search.spec.ts @@ -42,6 +42,17 @@ describe('Add existing token using search', function () { address: '0x0d8775f648430679a709e98d2b0cb6250d2887ef', }, ], + tokensChainsCache: { + '0x38': { + data: { + '0x0d8775f648430679a709e98d2b0cb6250d2887ef': { + name: 'Basic Attention Token', + symbol: 'BAT', + address: '0x0d8775f648430679a709e98d2b0cb6250d2887ef', + }, + }, + }, + }, }) .withAppStateController({ [CHAIN_IDS.OPTIMISM]: true, diff --git a/test/e2e/tests/tokens/import-tokens.spec.ts b/test/e2e/tests/tokens/import-tokens.spec.ts index 0f7d208e0984..2f0a21d9029b 100644 --- a/test/e2e/tests/tokens/import-tokens.spec.ts +++ b/test/e2e/tests/tokens/import-tokens.spec.ts @@ -56,6 +56,22 @@ describe('Import flow', function () { address: '0x06af07097c9eeb7fd685c692751d5c66db49c215', }, ], + tokensChainsCache: { + '0x1': { + data: { + '0xc4c2614e694cf534d407ee49f8e44d125e4681c4': { + name: 'Chain Games', + symbol: 'CHAIN', + address: '0xc4c2614e694cf534d407ee49f8e44d125e4681c4', + }, + '0x7051faed0775f664a0286af4f75ef5ed74e02754': { + name: 'ChangeX', + symbol: 'CHANGE', + address: '0x7051faed0775f664a0286af4f75ef5ed74e02754', + }, + }, + }, + }, }) .build(), title: this.test?.fullTitle(), @@ -83,4 +99,132 @@ describe('Import flow', function () { }, ); }); + + it('allows importing multiple tokens from search across chains', async function () { + await withFixtures( + { + fixtures: new FixtureBuilder() + .withNetworkControllerOnMainnet() + .withNetworkControllerOnPolygon() + .withTokensController({ + tokenList: [], + tokensChainsCache: { + '0x1': { + data: { + '0x0a0e3bfd5a8ce610e735d4469bc1b3b130402267': { + name: 'Entropy', + aggregators: ['Lifi', 'Coinmarketcap', 'Rango'], + address: '0x0a0e3bfd5a8ce610e735d4469bc1b3b130402267', + decimals: 18, + iconUrl: + 'https://static.cx.metamask.io/api/v1/tokenIcons/1/0x0a0e3bfd5a8ce610e735d4469bc1b3b130402267.png', + occurrences: 3, + symbol: 'ERP', + }, + }, + }, + '0x89': { + data: { + '0xc2132D05D31c914a87C6611C10748AEb04B58e8F': { + name: 'USDT', + aggregators: ['Lifi', 'Coinmarketcap', 'Rango'], + address: '0xc2132D05D31c914a87C6611C10748AEb04B58e8F', + decimals: 6, + iconUrl: + 'https://static.cx.metamask.io/api/v1/tokenIcons/137/0xc2132D05D31c914a87C6611C10748AEb04B58e8F.png', + occurrences: 3, + symbol: 'USDT', + }, + }, + }, + }, + }) + .build(), + title: this.test?.fullTitle(), + testSpecificMock: mockPriceFetch, + }, + async ({ driver }) => { + await unlockWallet(driver); + + const homePage = new HomePage(driver); + await homePage.check_pageIsLoaded(); + + const assetListPage = new AssetListPage(driver); + + await assetListPage.importMultipleTokensBySearch(['ERP', 'USDT']); + + const tokenList = new AssetListPage(driver); + await tokenList.check_tokenItemNumber(5); // Polygon, Eth, linea, USDT, ERP + + await tokenList.check_tokenExistsInList('Ethereum'); + await tokenList.check_tokenExistsInList('ERP'); + await tokenList.check_tokenExistsInList('USDT'); + await tokenList.check_tokenExistsInList('POL'); + }, + ); + }); + + it('allows importing using contract address and not current network', async function () { + await withFixtures( + { + fixtures: new FixtureBuilder() + .withNetworkControllerOnMainnet() + .withNetworkControllerOnPolygon() + .withTokensController({ + tokenList: [], + tokensChainsCache: { + '0x1': { + data: { + '0x0a0e3bfd5a8ce610e735d4469bc1b3b130402267': { + name: 'Entropy', + aggregators: ['Lifi', 'Coinmarketcap', 'Rango'], + address: '0x0a0e3bfd5a8ce610e735d4469bc1b3b130402267', + decimals: 18, + iconUrl: + 'https://static.cx.metamask.io/api/v1/tokenIcons/1/0x0a0e3bfd5a8ce610e735d4469bc1b3b130402267.png', + symbol: 'ERP', + }, + }, + }, + '0x89': { + data: { + '0xc2132D05D31c914a87C6611C10748AEb04B58e8F': { + name: 'USDT', + aggregators: ['Lifi', 'Coinmarketcap', 'Rango'], + address: '0xc2132D05D31c914a87C6611C10748AEb04B58e8F', + decimals: 6, + iconUrl: + 'https://static.cx.metamask.io/api/v1/tokenIcons/137/0xc2132D05D31c914a87C6611C10748AEb04B58e8F.png', + occurrences: 3, + symbol: 'USDT', + }, + }, + }, + }, + }) + .build(), + title: this.test?.fullTitle(), + testSpecificMock: mockPriceFetch, + }, + async ({ driver }) => { + await unlockWallet(driver); + + const homePage = new HomePage(driver); + await homePage.check_pageIsLoaded(); + + const assetListPage = new AssetListPage(driver); + await assetListPage.importCustomTokenByChain( + '0xc2132D05D31c914a87C6611C10748AEb04B58e8F', + 'USDT', + '0x89', + ); + const tokenList = new AssetListPage(driver); + await tokenList.check_tokenItemNumber(4); // Polygon, Eth, linea, USDT + + await tokenList.check_tokenExistsInList('Ethereum'); + await tokenList.check_tokenExistsInList('USDT'); + await tokenList.check_tokenExistsInList('POL'); + }, + ); + }); }); diff --git a/test/e2e/tests/tokens/nft/import-erc1155.spec.js b/test/e2e/tests/tokens/nft/import-erc1155.spec.js deleted file mode 100644 index 6896f68c7b1d..000000000000 --- a/test/e2e/tests/tokens/nft/import-erc1155.spec.js +++ /dev/null @@ -1,89 +0,0 @@ -const { strict: assert } = require('assert'); -const { withFixtures, unlockWallet } = require('../../../helpers'); -const { SMART_CONTRACTS } = require('../../../seeder/smart-contracts'); -const FixtureBuilder = require('../../../fixture-builder'); - -describe('Import ERC1155 NFT', function () { - const smartContract = SMART_CONTRACTS.ERC1155; - - it('should be able to import an ERC1155 NFT that user owns', async function () { - await withFixtures( - { - dapp: true, - fixtures: new FixtureBuilder() - .withPermissionControllerConnectedToTestDapp() - .build(), - smartContract, - title: this.test.fullTitle(), - }, - async ({ driver, _, contractRegistry }) => { - const contractAddress = - contractRegistry.getContractAddress(smartContract); - await unlockWallet(driver); - - // After login, go to NFTs tab, open the import NFT/ERC1155 form - await driver.clickElement('[data-testid="account-overview__nfts-tab"]'); - await driver.clickElement({ text: 'Import NFT', tag: 'button' }); - - // Enter a valid NFT that belongs to user and check success message appears - await driver.fill('#address', contractAddress); - await driver.fill('#token-id', '1'); - await driver.clickElement( - '[data-testid="import-nfts-modal-import-button"]', - ); - - const newNftNotification = await driver.findVisibleElement({ - text: 'NFT was successfully added!', - tag: 'h6', - }); - assert.equal(await newNftNotification.isDisplayed(), true); - - // Check the imported ERC1155 and its image are displayed in the ERC1155 tab - const importedERC1155 = await driver.findElement( - '[data-testid="nft-item"]', - ); - assert.equal(await importedERC1155.isDisplayed(), true); - - const importedERC1155Image = await driver.findVisibleElement( - '.nft-item__container', - ); - assert.equal(await importedERC1155Image.isDisplayed(), true); - }, - ); - }); - - it('should not be able to import an ERC1155 NFT that does not belong to user', async function () { - await withFixtures( - { - dapp: true, - fixtures: new FixtureBuilder() - .withPermissionControllerConnectedToTestDapp() - .build(), - smartContract, - title: this.test.fullTitle(), - }, - async ({ driver, _, contractRegistry }) => { - const contractAddress = - contractRegistry.getContractAddress(smartContract); - await unlockWallet(driver); - - // After login, go to NFTs tab, open the import NFT form - await driver.clickElement('[data-testid="account-overview__nfts-tab"]'); - await driver.clickElement({ text: 'Import NFT', tag: 'button' }); - - // Enter an NFT that not belongs to user with a valid address and an invalid token id - await driver.fill('#address', contractAddress); - await driver.fill('#token-id', '4'); - await driver.clickElement( - '[data-testid="import-nfts-modal-import-button"]', - ); - // Check error message appears - const invalidNftNotification = await driver.findElement({ - text: 'NFT can’t be added as the ownership details do not match. Make sure you have entered correct information.', - tag: 'p', - }); - assert.equal(await invalidNftNotification.isDisplayed(), true); - }, - ); - }); -}); diff --git a/test/e2e/tests/tokens/nft/import-erc1155.spec.ts b/test/e2e/tests/tokens/nft/import-erc1155.spec.ts new file mode 100644 index 000000000000..8d8009923034 --- /dev/null +++ b/test/e2e/tests/tokens/nft/import-erc1155.spec.ts @@ -0,0 +1,64 @@ +import { withFixtures } from '../../../helpers'; +import { SMART_CONTRACTS } from '../../../seeder/smart-contracts'; +import FixtureBuilder from '../../../fixture-builder'; +import Homepage from '../../../page-objects/pages/home/homepage'; +import NftListPage from '../../../page-objects/pages/home/nft-list'; +import { loginWithBalanceValidation } from '../../../page-objects/flows/login.flow'; + +describe('Import ERC1155 NFT', function () { + const smartContract = SMART_CONTRACTS.ERC1155; + + it('should be able to import an ERC1155 NFT that user owns', async function () { + await withFixtures( + { + dapp: true, + fixtures: new FixtureBuilder() + .withPermissionControllerConnectedToTestDapp() + .build(), + smartContract, + title: this.test?.fullTitle(), + }, + async ({ driver, localNodes, contractRegistry }) => { + const contractAddress = + contractRegistry.getContractAddress(smartContract); + await loginWithBalanceValidation(driver, localNodes[0]); + + // Go to NFTs tab, import a valid ERC1155 token address and token id that belongs to user + const homepage = new Homepage(driver); + await homepage.goToNftTab(); + const nftList = new NftListPage(driver); + await nftList.importNft(contractAddress, '1'); + + // Check the ERC1155 token is successfully imported and its image is displayed + await nftList.check_successImportNftMessageIsDisplayed(); + await nftList.check_nftImageIsDisplayed(); + }, + ); + }); + + it('should not be able to import an ERC1155 NFT that does not belong to user', async function () { + await withFixtures( + { + dapp: true, + fixtures: new FixtureBuilder() + .withPermissionControllerConnectedToTestDapp() + .build(), + smartContract, + title: this.test?.fullTitle(), + }, + async ({ driver, localNodes, contractRegistry }) => { + const contractAddress = + contractRegistry.getContractAddress(smartContract); + await loginWithBalanceValidation(driver, localNodes[0]); + + // Import a valid ERC1155 token address and a token id that does not belong to user and check error message appears + await new Homepage(driver).goToNftTab(); + await new NftListPage(driver).importNft( + contractAddress, + '4', + 'NFT can’t be added as the ownership details do not match. Make sure you have entered correct information.', + ); + }, + ); + }); +}); diff --git a/test/e2e/tests/tokens/nft/remove-erc1155.spec.js b/test/e2e/tests/tokens/nft/remove-erc1155.spec.js deleted file mode 100644 index 8b6c4d70515e..000000000000 --- a/test/e2e/tests/tokens/nft/remove-erc1155.spec.js +++ /dev/null @@ -1,52 +0,0 @@ -const { strict: assert } = require('assert'); -const { withFixtures, unlockWallet } = require('../../../helpers'); -const { SMART_CONTRACTS } = require('../../../seeder/smart-contracts'); -const FixtureBuilder = require('../../../fixture-builder'); - -async function mockIPFSRequest(mockServer) { - return [ - await mockServer - .forGet( - 'https://bafkreifvhjdf6ve4jfv6qytqtux5nd4nwnelioeiqx5x2ez5yrgrzk7ypi.ipfs.dweb.link/', - ) - .thenCallback(() => ({ statusCode: 200 })), - ]; -} - -describe('Remove ERC1155 NFT', function () { - const smartContract = SMART_CONTRACTS.ERC1155; - - it('user should be able to remove ERC1155 NFT on details page', async function () { - await withFixtures( - { - dapp: true, - fixtures: new FixtureBuilder().withNftControllerERC1155().build(), - smartContract, - title: this.test.fullTitle(), - testSpecificMock: mockIPFSRequest, - }, - async ({ driver }) => { - await unlockWallet(driver); - - // Open the details page and click remove nft button - await driver.clickElement('[data-testid="account-overview__nfts-tab"]'); - await driver.clickElement('.nft-item__container'); - await driver.clickElement('[data-testid="nft-options__button"]'); - await driver.clickElement('[data-testid="nft-item-remove"]'); - - // Check the remove NFT toaster is displayed - const removeNftNotification = await driver.findElement({ - text: 'NFT was successfully removed!', - tag: 'h6', - }); - assert.equal(await removeNftNotification.isDisplayed(), true); - - // Check the imported ERC1155 NFT disappeared in the NFT tab - const noNftInfo = await driver.waitForSelector({ - text: 'No NFTs yet', - }); - assert.equal(await noNftInfo.isDisplayed(), true); - }, - ); - }); -}); diff --git a/test/e2e/tests/tokens/nft/remove-erc1155.spec.ts b/test/e2e/tests/tokens/nft/remove-erc1155.spec.ts new file mode 100644 index 000000000000..53266282bad7 --- /dev/null +++ b/test/e2e/tests/tokens/nft/remove-erc1155.spec.ts @@ -0,0 +1,103 @@ +import { MockttpServer } from 'mockttp'; +import { withFixtures } from '../../../helpers'; +import { SMART_CONTRACTS } from '../../../seeder/smart-contracts'; +import FixtureBuilder from '../../../fixture-builder'; +import Homepage from '../../../page-objects/pages/home/homepage'; +import NFTDetailsPage from '../../../page-objects/pages/nft-details-page'; +import NftListPage from '../../../page-objects/pages/home/nft-list'; +import { loginWithBalanceValidation } from '../../../page-objects/flows/login.flow'; +import { setupAutoDetectMocking } from './mocks'; +import SettingsPage from '../../../page-objects/pages/settings/settings-page'; +import HeaderNavbar from '../../../page-objects/pages/header-navbar'; +import PrivacySettings from '../../../page-objects/pages/settings/privacy-settings'; + +async function mockIPFSRequest(mockServer: MockttpServer) { + return [ + await mockServer + .forGet( + 'https://bafkreifvhjdf6ve4jfv6qytqtux5nd4nwnelioeiqx5x2ez5yrgrzk7ypi.ipfs.dweb.link/', + ) + .thenCallback(() => ({ statusCode: 200 })), + ]; +} + +describe('Remove ERC1155 NFT', function () { + const smartContract = SMART_CONTRACTS.ERC1155; + + it('user should be able to remove ERC1155 NFT on details page', async function () { + await withFixtures( + { + dapp: true, + fixtures: new FixtureBuilder().withNftControllerERC1155().build(), + smartContract, + title: this.test?.fullTitle(), + testSpecificMock: mockIPFSRequest, + }, + async ({ driver }) => { + await loginWithBalanceValidation(driver); + + // Open the NFT details page and click to remove NFT + await new Homepage(driver).goToNftTab(); + const nftListPage = new NftListPage(driver); + await nftListPage.clickNFTIconOnActivityList(); + + const nftDetailsPage = new NFTDetailsPage(driver); + await nftDetailsPage.check_pageIsLoaded(); + await nftDetailsPage.removeNFT(); + + // Check the success remove NFT toaster is displayed and the NFT is removed from the NFT tab + await nftListPage.check_successRemoveNftMessageIsDisplayed(); + await nftListPage.check_noNftInfoIsDisplayed(); + }, + ); + }); + + it('user should be able to remove an NFT while selected network is different than NFT network', async function () { + const driverOptions = { mock: true }; + await withFixtures( + { + fixtures: new FixtureBuilder().withNetworkControllerOnLinea().build(), + driverOptions, + title: this.test?.fullTitle(), + testSpecificMock: setupAutoDetectMocking, + }, + async ({ driver }) => { + await loginWithBalanceValidation(driver); + + // navigate to security & privacy settings and toggle on NFT autodetection + await new HeaderNavbar(driver).openSettingsPage(); + const settingsPage = new SettingsPage(driver); + await settingsPage.check_pageIsLoaded(); + await settingsPage.goToPrivacySettings(); + + const privacySettings = new PrivacySettings(driver); + await privacySettings.check_pageIsLoaded(); + await privacySettings.toggleAutodetectNft(); + await settingsPage.closeSettingsPage(); + + // check that nft is displayed + const homepage = new Homepage(driver); + await homepage.check_pageIsLoaded(); + await homepage.check_expectedBalanceIsDisplayed(); + await homepage.goToNftTab(); + const nftListPage = new NftListPage(driver); + await nftListPage.check_nftNameIsDisplayed( + 'ENS: Ethereum Name Service', + ); + await nftListPage.check_nftImageIsDisplayed(); + await nftListPage.clickNFTIconOnActivityList(); + + const nftDetailsPage = new NFTDetailsPage(driver); + await nftDetailsPage.check_pageIsLoaded(); + + await nftDetailsPage.removeNFT(); + await driver.delay(5000); + + // Remove NFT + await nftListPage.check_successRemoveNftMessageIsDisplayed(); + await nftListPage.check_noNftInfoIsDisplayed(); + await driver.delay(5000); + }, + ); + }); +}); diff --git a/test/e2e/tests/tokens/nft/remove-nft.spec.js b/test/e2e/tests/tokens/nft/remove-nft.spec.ts similarity index 53% rename from test/e2e/tests/tokens/nft/remove-nft.spec.js rename to test/e2e/tests/tokens/nft/remove-nft.spec.ts index fbd413fb47ff..ff5b000a77ea 100644 --- a/test/e2e/tests/tokens/nft/remove-nft.spec.js +++ b/test/e2e/tests/tokens/nft/remove-nft.spec.ts @@ -1,18 +1,17 @@ -const { strict: assert } = require('assert'); -const { - withFixtures, - unlockWallet, - getEventPayloads, -} = require('../../../helpers'); -const { SMART_CONTRACTS } = require('../../../seeder/smart-contracts'); -const FixtureBuilder = require('../../../fixture-builder'); -const { - MetaMetricsEventName, -} = require('../../../../../shared/constants/metametrics'); -const { CHAIN_IDS } = require('../../../../../shared/constants/network'); -const { MOCK_META_METRICS_ID } = require('../../../constants'); +import { strict as assert } from 'assert'; +import { MockttpServer } from 'mockttp'; +import { withFixtures, getEventPayloads } from '../../../helpers'; +import { SMART_CONTRACTS } from '../../../seeder/smart-contracts'; +import FixtureBuilder from '../../../fixture-builder'; +import { MetaMetricsEventName } from '../../../../../shared/constants/metametrics'; +import { CHAIN_IDS } from '../../../../../shared/constants/network'; +import { MOCK_META_METRICS_ID } from '../../../constants'; +import Homepage from '../../../page-objects/pages/home/homepage'; +import NFTDetailsPage from '../../../page-objects/pages/nft-details-page'; +import NftListPage from '../../../page-objects/pages/home/nft-list'; +import { loginWithBalanceValidation } from '../../../page-objects/flows/login.flow'; -async function mockedNftRemoved(mockServer) { +async function mockedNftRemoved(mockServer: MockttpServer) { return await mockServer .forPost('https://api.segment.io/v1/batch') .withJsonBodyIncluding({ @@ -29,7 +28,7 @@ describe('Remove NFT', function () { const smartContract = SMART_CONTRACTS.NFTS; it('user should be able to remove ERC721 NFT on details page and removeNft event should be emitted', async function () { - async function mockSegment(mockServer) { + async function mockSegment(mockServer: MockttpServer) { return [await mockedNftRemoved(mockServer)]; } await withFixtures( @@ -43,34 +42,28 @@ describe('Remove NFT', function () { }) .build(), smartContract, - title: this.test.fullTitle(), + title: this.test?.fullTitle(), testSpecificMock: mockSegment, }, async ({ driver, mockedEndpoint: mockedEndpoints, contractRegistry }) => { - await unlockWallet(driver); + await loginWithBalanceValidation(driver); const contractAddress = await contractRegistry.getContractAddress( smartContract, ); - // Open the details and click remove nft button - await driver.clickElement('[data-testid="account-overview__nfts-tab"]'); - await driver.clickElement('.nft-item__container'); - await driver.clickElement('[data-testid="nft-options__button"]'); - await driver.clickElement('[data-testid="nft-item-remove"]'); + // Open the NFT details page and click to remove NFT + await new Homepage(driver).goToNftTab(); + const nftListPage = new NftListPage(driver); + await nftListPage.clickNFTIconOnActivityList(); - // Check the remove NFT toaster is displayed - const removeNftNotification = await driver.findElement({ - text: 'NFT was successfully removed!', - tag: 'h6', - }); - assert.equal(await removeNftNotification.isDisplayed(), true); + const nftDetailsPage = new NFTDetailsPage(driver); + await nftDetailsPage.check_pageIsLoaded(); + await nftDetailsPage.removeNFT(); - // Check the imported NFT disappeared in the NFT tab - const noNftInfo = await driver.waitForSelector({ - text: 'No NFTs yet', - }); - assert.equal(await noNftInfo.isDisplayed(), true); + // Check the success remove NFT toaster is displayed and the NFT is removed from the NFT tab + await nftListPage.check_successRemoveNftMessageIsDisplayed(); + await nftListPage.check_noNftInfoIsDisplayed(); // Check if event was emitted const events = await getEventPayloads(driver, mockedEndpoints); diff --git a/test/e2e/tests/tokens/nft/view-erc1155-details.spec.js b/test/e2e/tests/tokens/nft/view-erc1155-details.spec.js deleted file mode 100644 index 9c7c76f27caa..000000000000 --- a/test/e2e/tests/tokens/nft/view-erc1155-details.spec.js +++ /dev/null @@ -1,57 +0,0 @@ -const { withFixtures, unlockWallet } = require('../../../helpers'); - -const { SMART_CONTRACTS } = require('../../../seeder/smart-contracts'); -const FixtureBuilder = require('../../../fixture-builder'); - -async function mockIPFSRequest(mockServer) { - return [ - await mockServer - .forGet( - 'https://bafkreifvhjdf6ve4jfv6qytqtux5nd4nwnelioeiqx5x2ez5yrgrzk7ypi.ipfs.dweb.link/', - ) - .thenCallback(() => ({ statusCode: 200 })), - ]; -} - -describe('View ERC1155 NFT details', function () { - const smartContract = SMART_CONTRACTS.ERC1155; - - it('user should be able to view ERC1155 NFT details', async function () { - await withFixtures( - { - dapp: true, - fixtures: new FixtureBuilder().withNftControllerERC1155().build(), - smartContract, - title: this.test.fullTitle(), - testSpecificMock: mockIPFSRequest, - }, - async ({ driver }) => { - await unlockWallet(driver); - - // Click to open the NFT details page and check displayed account - await driver.clickElement('[data-testid="account-overview__nfts-tab"]'); - - await driver.clickElement('.nft-item__container'); - - await driver.findElement('[data-testid="nft__back"]'); - - await driver.findElement({ - css: '[data-testid="nft-details__name"]', - text: 'Rocks', - }); - - await driver.findElement({ - css: '[data-testid="nft-details__description"]', - text: 'This is a collection of Rock NFTs.', - }); - - await driver.findVisibleElement('.nft-item__container'); - - await driver.findElement({ - css: '.nft-details__addressButton', - text: '0x581c3...45947', - }); - }, - ); - }); -}); diff --git a/test/e2e/tests/tokens/nft/view-erc1155-details.spec.ts b/test/e2e/tests/tokens/nft/view-erc1155-details.spec.ts new file mode 100644 index 000000000000..48552938f8c5 --- /dev/null +++ b/test/e2e/tests/tokens/nft/view-erc1155-details.spec.ts @@ -0,0 +1,54 @@ +import { MockttpServer } from 'mockttp'; +import { withFixtures } from '../../../helpers'; +import { SMART_CONTRACTS } from '../../../seeder/smart-contracts'; +import FixtureBuilder from '../../../fixture-builder'; +import Homepage from '../../../page-objects/pages/home/homepage'; +import NFTDetailsPage from '../../../page-objects/pages/nft-details-page'; +import NftListPage from '../../../page-objects/pages/home/nft-list'; +import { loginWithBalanceValidation } from '../../../page-objects/flows/login.flow'; + +async function mockIPFSRequest(mockServer: MockttpServer) { + return [ + await mockServer + .forGet( + 'https://bafkreifvhjdf6ve4jfv6qytqtux5nd4nwnelioeiqx5x2ez5yrgrzk7ypi.ipfs.dweb.link/', + ) + .thenCallback(() => ({ statusCode: 200 })), + ]; +} + +describe('View ERC1155 NFT details', function () { + const smartContract = SMART_CONTRACTS.ERC1155; + + it('user should be able to view ERC1155 NFT details', async function () { + await withFixtures( + { + dapp: true, + fixtures: new FixtureBuilder().withNftControllerERC1155().build(), + smartContract, + title: this.test?.fullTitle(), + testSpecificMock: mockIPFSRequest, + }, + async ({ driver }) => { + await loginWithBalanceValidation(driver); + + // Click to open the NFT details page and check displayed account + await new Homepage(driver).goToNftTab(); + const nftListPage = new NftListPage(driver); + await nftListPage.clickNFTIconOnActivityList(); + + // Check the NFT details are correctly displayed on NFT details page + const nftDetailsPage = new NFTDetailsPage(driver); + await nftDetailsPage.check_pageIsLoaded(); + await nftDetailsPage.check_nftNameIsDisplayed('Rocks'); + await nftDetailsPage.check_nftDescriptionIsDisplayed( + 'This is a collection of Rock NFTs.', + ); + await nftDetailsPage.check_nftImageContainerIsDisplayed(); + await nftDetailsPage.check_nftDetailsAddressIsDisplayed( + '0x581c3...45947', + ); + }, + ); + }); +}); diff --git a/test/e2e/tests/tokens/nft/view-nft-details.spec.js b/test/e2e/tests/tokens/nft/view-nft-details.spec.js deleted file mode 100644 index 15e6edc02b7c..000000000000 --- a/test/e2e/tests/tokens/nft/view-nft-details.spec.js +++ /dev/null @@ -1,48 +0,0 @@ -const { strict: assert } = require('assert'); -const { withFixtures, unlockWallet } = require('../../../helpers'); -const { SMART_CONTRACTS } = require('../../../seeder/smart-contracts'); -const FixtureBuilder = require('../../../fixture-builder'); - -describe('View NFT details', function () { - const smartContract = SMART_CONTRACTS.NFTS; - - it('user should be able to view ERC721 NFT details', async function () { - await withFixtures( - { - dapp: true, - fixtures: new FixtureBuilder().withNftControllerERC721().build(), - smartContract, - title: this.test.fullTitle(), - }, - async ({ driver }) => { - await unlockWallet(driver); - - // Click to open the NFT details page and check title - await driver.clickElement('[data-testid="account-overview__nfts-tab"]'); - await driver.clickElement('.nft-item__container'); - - await driver.findElement('[data-testid="nft__back"]'); - - // Check the displayed NFT details - - await driver.findElement({ - css: '[data-testid="nft-details__name"]', - text: 'Test Dapp NFTs #1', - }); - - await driver.findElement({ - css: '[data-testid="nft-details__description"]', - text: 'Test Dapp NFTs for testing.', - }); - - const nftImage = await driver.findElement('.nft-item__container'); - assert.equal(await nftImage.isDisplayed(), true); - - await driver.findElement({ - css: '.nft-details__addressButton', - text: '0x581c3...45947', - }); - }, - ); - }); -}); diff --git a/test/e2e/tests/tokens/nft/view-nft-details.spec.ts b/test/e2e/tests/tokens/nft/view-nft-details.spec.ts new file mode 100644 index 000000000000..8a44ea4fdc74 --- /dev/null +++ b/test/e2e/tests/tokens/nft/view-nft-details.spec.ts @@ -0,0 +1,43 @@ +import { withFixtures } from '../../../helpers'; +import { SMART_CONTRACTS } from '../../../seeder/smart-contracts'; +import FixtureBuilder from '../../../fixture-builder'; +import Homepage from '../../../page-objects/pages/home/homepage'; +import NFTDetailsPage from '../../../page-objects/pages/nft-details-page'; +import NftListPage from '../../../page-objects/pages/home/nft-list'; +import { loginWithBalanceValidation } from '../../../page-objects/flows/login.flow'; +import { Driver } from '../../../webdriver/driver'; + +describe('View NFT details', function () { + const smartContract = SMART_CONTRACTS.NFTS; + + it('user should be able to view ERC721 NFT details', async function () { + await withFixtures( + { + dapp: true, + fixtures: new FixtureBuilder().withNftControllerERC721().build(), + smartContract, + title: this.test?.fullTitle(), + }, + async ({ driver }: { driver: Driver }) => { + await loginWithBalanceValidation(driver); + + // Click to open the NFT details page and check title + await new Homepage(driver).goToNftTab(); + const nftListPage = new NftListPage(driver); + await nftListPage.clickNFTIconOnActivityList(); + + // Check the NFT details are correctly displayed on NFT details page + const nftDetailsPage = new NFTDetailsPage(driver); + await nftDetailsPage.check_pageIsLoaded(); + await nftDetailsPage.check_nftNameIsDisplayed('Test Dapp NFTs #1'); + await nftDetailsPage.check_nftDescriptionIsDisplayed( + 'Test Dapp NFTs for testing.', + ); + await nftDetailsPage.check_nftImageContainerIsDisplayed(); + await nftDetailsPage.check_nftDetailsAddressIsDisplayed( + '0x581c3...45947', + ); + }, + ); + }); +}); diff --git a/test/e2e/tests/tokens/nft/view-nft-full-image.spec.ts b/test/e2e/tests/tokens/nft/view-nft-full-image.spec.ts index fb316f76ff4e..988f55adf98d 100644 --- a/test/e2e/tests/tokens/nft/view-nft-full-image.spec.ts +++ b/test/e2e/tests/tokens/nft/view-nft-full-image.spec.ts @@ -6,8 +6,8 @@ import NFTListPage from '../../../page-objects/pages/home/nft-list'; import PrivacySettings from '../../../page-objects/pages/settings/privacy-settings'; import SettingsPage from '../../../page-objects/pages/settings/settings-page'; import { loginWithBalanceValidation } from '../../../page-objects/flows/login.flow'; -import NFTDetailsPage from '../../../page-objects/pages/nft-details-page'; import { setupAutoDetectMocking } from './mocks'; +import NFTDetailsPage from '../../../page-objects/pages/nft-details-page'; describe('NFT full', function () { it('displays NFT full image when NFT is on a network different from the current network', async function () { diff --git a/test/e2e/tests/tokens/token-details.spec.ts b/test/e2e/tests/tokens/token-details.spec.ts index 8a07aecf709b..3ffacb049fee 100644 --- a/test/e2e/tests/tokens/token-details.spec.ts +++ b/test/e2e/tests/tokens/token-details.spec.ts @@ -42,7 +42,11 @@ describe('Token Details', function () { const homePage = new HomePage(driver); const assetListPage = new AssetListPage(driver); await homePage.check_pageIsLoaded(); - await assetListPage.importCustomToken(tokenAddress, symbol); + await assetListPage.importCustomTokenByChain( + tokenAddress, + symbol, + chainId, + ); await assetListPage.dismissTokenImportedMessage(); await assetListPage.openTokenDetails(symbol); await assetListPage.check_tokenSymbolAndAddressDetails( @@ -88,7 +92,11 @@ describe('Token Details', function () { const homePage = new HomePage(driver); const assetListPage = new AssetListPage(driver); await homePage.check_pageIsLoaded(); - await assetListPage.importCustomToken(tokenAddress, symbol); + await assetListPage.importCustomTokenByChain( + tokenAddress, + symbol, + chainId, + ); await assetListPage.dismissTokenImportedMessage(); await assetListPage.openTokenDetails(symbol); await assetListPage.check_tokenSymbolAndAddressDetails( diff --git a/test/e2e/tests/tokens/token-list.spec.ts b/test/e2e/tests/tokens/token-list.spec.ts index de7c62b58e19..04077e6ce1fe 100644 --- a/test/e2e/tests/tokens/token-list.spec.ts +++ b/test/e2e/tests/tokens/token-list.spec.ts @@ -48,7 +48,11 @@ describe('Token List', function () { const assetListPage = new AssetListPage(driver); await homePage.check_pageIsLoaded(); - await assetListPage.importCustomToken(tokenAddress, symbol); + await assetListPage.importCustomTokenByChain( + tokenAddress, + symbol, + chainId, + ); await assetListPage.check_tokenGeneralChangePercentageNotPresent( zeroAddress(), @@ -101,7 +105,11 @@ describe('Token List', function () { const assetListPage = new AssetListPage(driver); await homePage.check_pageIsLoaded(); - await assetListPage.importCustomToken(tokenAddress, symbol); + await assetListPage.importCustomTokenByChain( + tokenAddress, + symbol, + chainId, + ); await assetListPage.check_tokenGeneralChangePercentage( zeroAddress(), diff --git a/test/e2e/tests/tokens/token-sort.spec.ts b/test/e2e/tests/tokens/token-sort.spec.ts index 1682ef1210f8..dcc8f41173c2 100644 --- a/test/e2e/tests/tokens/token-sort.spec.ts +++ b/test/e2e/tests/tokens/token-sort.spec.ts @@ -31,9 +31,10 @@ describe('Token List Sorting', function () { const assetListPage = new AssetListPage(driver); await homePage.check_pageIsLoaded(); - await assetListPage.importCustomToken( + await assetListPage.importCustomTokenByChain( customTokenAddress, customTokenSymbol, + CHAIN_IDS.MAINNET, ); await assetListPage.check_tokenExistsInList('Ethereum'); diff --git a/test/e2e/tests/transaction/incoming-transactions.spec.ts b/test/e2e/tests/transaction/incoming-transactions.spec.ts index e6c4cf6896cd..fe315e613d52 100644 --- a/test/e2e/tests/transaction/incoming-transactions.spec.ts +++ b/test/e2e/tests/transaction/incoming-transactions.spec.ts @@ -90,7 +90,7 @@ describe('Incoming Transactions', function () { await withFixtures( { fixtures: new FixtureBuilder() - .withIncomingTransactionsPreferences(true) + .withUseBasicFunctionalityEnabled() .build(), title: this.test?.fullTitle(), testSpecificMock: mockAccountsApi, @@ -112,7 +112,7 @@ describe('Incoming Transactions', function () { await withFixtures( { fixtures: new FixtureBuilder() - .withIncomingTransactionsPreferences(true) + .withUseBasicFunctionalityEnabled() .build(), title: this.test?.fullTitle(), testSpecificMock: (server: Mockttp) => @@ -134,7 +134,7 @@ describe('Incoming Transactions', function () { await withFixtures( { fixtures: new FixtureBuilder() - .withIncomingTransactionsPreferences(true) + .withUseBasicFunctionalityEnabled() .build(), title: this.test?.fullTitle(), testSpecificMock: (server: Mockttp) => @@ -153,7 +153,7 @@ describe('Incoming Transactions', function () { await withFixtures( { fixtures: new FixtureBuilder() - .withIncomingTransactionsPreferences(false) + .withUseBasicFunctionalityDisabled() .build(), title: this.test?.fullTitle(), testSpecificMock: mockAccountsApi, @@ -170,7 +170,7 @@ describe('Incoming Transactions', function () { await withFixtures( { fixtures: new FixtureBuilder() - .withIncomingTransactionsPreferences(true) + .withUseBasicFunctionalityEnabled() .withTransactions([ { hash: RESPONSE_STANDARD_MOCK.hash, diff --git a/test/e2e/tests/transaction/send-max.spec.js b/test/e2e/tests/transaction/send-max.spec.js index cc95c5106692..9593be4d7d08 100644 --- a/test/e2e/tests/transaction/send-max.spec.js +++ b/test/e2e/tests/transaction/send-max.spec.js @@ -215,7 +215,7 @@ describe('Sending with max amount', function () { // verify gas fee changed await driver.waitForSelector({ - text: '0.0005', + text: '0.0009', }); // verify initial max amount diff --git a/test/e2e/tsconfig.json b/test/e2e/tsconfig.json new file mode 100644 index 000000000000..fa85a7d6994c --- /dev/null +++ b/test/e2e/tsconfig.json @@ -0,0 +1,4 @@ +{ + "extends": "../../tsconfig.json", + "include": ["./**/*.js", "./**/*.ts"] +} diff --git a/test/e2e/vault-decryption-chrome.spec.ts b/test/e2e/vault-decryption-chrome.spec.ts index 958eeec7437e..d226489cefee 100644 --- a/test/e2e/vault-decryption-chrome.spec.ts +++ b/test/e2e/vault-decryption-chrome.spec.ts @@ -160,15 +160,14 @@ describe('Vault Decryptor Page', function () { await withFixtures( { disableServerMochaToBackground: true, + title: this.test?.fullTitle(), }, async ({ driver }) => { // we don't need to use navigate since MM will automatically open a new window in prod build await driver.waitUntilXWindowHandles(2); // we cannot use the customized driver functions as there is no socket for window communications in prod builds - await driver.switchToWindowByTitleWithoutSocket( - WINDOW_TITLES.ExtensionInFullScreenView, - ); + await driver.switchToWindowByTitleWithoutSocket(WINDOW_TITLES.ExtensionInFullScreenView); // switch to MetaMask window and create a new vault through onboarding flow await completeCreateNewWalletOnboardingFlowWithCustomSettings({ @@ -219,15 +218,14 @@ describe('Vault Decryptor Page', function () { await withFixtures( { disableServerMochaToBackground: true, + title: this.test?.fullTitle(), }, async ({ driver }) => { // we don't need to use navigate since MM will automatically open a new window in prod build await driver.waitUntilXWindowHandles(2); // we cannot use the customized driver functions as there is no socket for window communications in prod builds - await driver.switchToWindowByTitleWithoutSocket( - WINDOW_TITLES.ExtensionInFullScreenView, - ); + await driver.switchToWindowByTitleWithoutSocket(WINDOW_TITLES.ExtensionInFullScreenView); // switch to MetaMask window and create a new vault through onboarding flow await completeCreateNewWalletOnboardingFlowWithCustomSettings({ diff --git a/test/e2e/webdriver/driver.js b/test/e2e/webdriver/driver.js index 2fc3829d6159..aece841b1ad1 100644 --- a/test/e2e/webdriver/driver.js +++ b/test/e2e/webdriver/driver.js @@ -671,7 +671,7 @@ class Driver { * @param {string} testTitle - The title of the test */ #getArtifactDir(testTitle) { - return `./test-artifacts/${this.browser}/${lodash.escape(testTitle)}`; + return `./test-artifacts/${this.browser}/${sanitizeTestTitle(testTitle)}`; } /** @@ -1555,4 +1555,18 @@ function collectMetrics() { }; } +/** + * @param {string} testTitle - The title of the test + */ +function sanitizeTestTitle(testTitle) { + return testTitle + .toLowerCase() + .replace(/[<>:"/\\|?*\r\n]/gu, '') // Remove invalid characters + .trim() + .replace(/\s+/gu, '-') // Replace whitespace with dashes + .replace(/[^a-z0-9-]+/gu, '-') // Replace non-alphanumerics (excluding dash) with dash + .replace(/--+/gu, '-') // Collapse multiple dashes + .replace(/^-+|-+$/gu, ''); // Trim leading/trailing dashes +} + module.exports = { Driver, PAGES }; diff --git a/test/helpers/foundry/utils.ts b/test/helpers/foundry/utils.ts index cfeb0377a644..0c1c9e6b383c 100644 --- a/test/helpers/foundry/utils.ts +++ b/test/helpers/foundry/utils.ts @@ -1,4 +1,4 @@ -import { execSync } from 'node:child_process'; +import { execFileSync, execSync } from 'node:child_process'; import { arch } from 'node:os'; import { type Checksums, @@ -64,7 +64,7 @@ export function say(message: string) { */ export function getVersion(binPath: string): Buffer { try { - return execSync(`${binPath} --version`).subarray(0, -1); // ignore newline + return execFileSync(binPath, ['--version']).subarray(0, -1); // ignore newline } catch (error: unknown) { const msg = `Failed to get version for ${binPath} diff --git a/test/integration/data/integration-init-state.json b/test/integration/data/integration-init-state.json index 1e2be7ff911b..fa89630ca9e3 100644 --- a/test/integration/data/integration-init-state.json +++ b/test/integration/data/integration-init-state.json @@ -482,14 +482,6 @@ }, "ignoredNfts": [], "ignoredTokens": [], - "incomingTransactionsPreferences": { - "0x1": true, - "0xe708": false, - "0xfa": true, - "0x5": false, - "0xaa36a7": false, - "0xe704": true - }, "internalAccounts": { "accounts": { "cf8dace4-9439-4bd4-b3a8-88c821c8fcb3": { @@ -655,13 +647,13 @@ "multichainNetworkConfigurationsByChainId": { "bip122:000000000019d6689c085ae165831e93": { "chainId": "bip122:000000000019d6689c085ae165831e93", - "name": "Bitcoin Mainnet", + "name": "Bitcoin", "nativeCurrency": "bip122:000000000019d6689c085ae165831e93/slip44:0", "isEvm": false }, "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp": { "chainId": "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp", - "name": "Solana Mainnet", + "name": "Solana", "nativeCurrency": "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp/slip44:501", "isEvm": false } diff --git a/test/integration/data/onboarding-completion-route.json b/test/integration/data/onboarding-completion-route.json index ecdac6b9b7ec..e1e54a10d479 100644 --- a/test/integration/data/onboarding-completion-route.json +++ b/test/integration/data/onboarding-completion-route.json @@ -117,13 +117,6 @@ }, "ignoredNfts": [], "ignoredTokens": [], - "incomingTransactionsPreferences": { - "0x1": true, - "0xe708": true, - "0x5": true, - "0xaa36a7": true, - "0xe705": true - }, "interfaces": {}, "internalAccounts": { "accounts": { @@ -174,13 +167,13 @@ "multichainNetworkConfigurationsByChainId": { "bip122:000000000019d6689c085ae165831e93": { "chainId": "bip122:000000000019d6689c085ae165831e93", - "name": "Bitcoin Mainnet", + "name": "Bitcoin", "nativeCurrency": "bip122:000000000019d6689c085ae165831e93/slip44:0", "isEvm": false }, "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp": { "chainId": "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp", - "name": "Solana Mainnet", + "name": "Solana", "nativeCurrency": "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp/slip44:501", "isEvm": false } diff --git a/test/jest/mock-store.js b/test/jest/mock-store.js index 43807a0e0938..409866bc823f 100644 --- a/test/jest/mock-store.js +++ b/test/jest/mock-store.js @@ -1,15 +1,8 @@ import { EthAccountType, EthScope } from '@metamask/keyring-api'; -import { - getDefaultBridgeControllerState, - BRIDGE_PREFERRED_GAS_ESTIMATE, - formatChainIdToCaip, -} from '@metamask/bridge-controller'; import { CHAIN_IDS, CURRENCY_SYMBOLS } from '../../shared/constants/network'; import { KeyringType } from '../../shared/constants/keyring'; import { ETH_EOA_METHODS } from '../../shared/constants/eth-methods'; import { mockNetworkState } from '../stub/networks'; -import { DEFAULT_BRIDGE_STATUS_STATE } from '../../app/scripts/controllers/bridge-status/constants'; -import { mockTokenData } from '../data/bridge/mock-token-data'; export const createGetSmartTransactionFeesApiResponse = () => { return { @@ -725,96 +718,3 @@ export const createSwapsMockStore = () => { }, }; }; - -export const createBridgeMockStore = ( - { - featureFlagOverrides = {}, - bridgeSliceOverrides = {}, - bridgeStateOverrides = {}, - bridgeStatusStateOverrides = {}, - metamaskStateOverrides = {}, - } = { - featureFlagOverrides: {}, - bridgeSliceOverrides: {}, - bridgeStateOverrides: {}, - bridgeStatusStateOverrides: {}, - metamaskStateOverrides: {}, - }, -) => { - const swapsStore = createSwapsMockStore(); - return { - ...swapsStore, - // For initial state of dest asset picker - swaps: { - ...swapsStore.swaps, - topAssets: [], - }, - bridge: { - toChainId: null, - sortOrder: 'cost_ascending', - ...bridgeSliceOverrides, - }, - localeMessages: { currentLocale: 'es_419' }, - metamask: { - ...swapsStore.metamask, - ...mockNetworkState( - { chainId: CHAIN_IDS.MAINNET }, - { chainId: CHAIN_IDS.LINEA_MAINNET }, - ), - gasFeeEstimates: { - estimatedBaseFee: '0.00010456', - [BRIDGE_PREFERRED_GAS_ESTIMATE]: { - suggestedMaxFeePerGas: '0.00018456', - suggestedMaxPriorityFeePerGas: '0.0001', - }, - }, - currencyRates: { - ETH: { conversionRate: 2524.25 }, - usd: { conversionRate: 1 }, - }, - marketData: { - '0x1': { - '0x1f9840a85d5af5bf1d1762f925bdaddc4201f984': { - currency: 'usd', - price: 2.3, - }, - }, - }, - slides: [], - ...mockTokenData, - ...metamaskStateOverrides, - ...{ - ...getDefaultBridgeControllerState(), - bridgeFeatureFlags: { - ...featureFlagOverrides, - extensionConfig: { - support: false, - ...featureFlagOverrides?.extensionConfig, - chains: { - [formatChainIdToCaip('0x1')]: { - isActiveSrc: true, - isActiveDest: false, - }, - ...Object.fromEntries( - Object.entries( - featureFlagOverrides?.extensionConfig?.chains ?? {}, - ).map(([chainId, config]) => [ - formatChainIdToCaip(chainId), - config, - ]), - ), - }, - }, - }, - }, - ...bridgeStateOverrides, - bridgeStatusState: { - ...DEFAULT_BRIDGE_STATUS_STATE, - ...bridgeStatusStateOverrides, - }, - }, - send: { - swapsBlockedTokens: [], - }, - }; -}; diff --git a/test/stub/networks.ts b/test/stub/networks.ts index ff6496dddb4e..33eadb4ea783 100644 --- a/test/stub/networks.ts +++ b/test/stub/networks.ts @@ -80,13 +80,13 @@ export const mockMultichainNetworkState = multichainNetworkConfigurationsByChainId: { [BtcScope.Mainnet]: { chainId: BtcScope.Mainnet, - name: 'Bitcoin Mainnet', + name: 'Bitcoin', nativeCurrency: `${BtcScope.Mainnet}/slip44:0`, isEvm: false, }, [SolScope.Mainnet]: { chainId: SolScope.Mainnet, - name: 'Solana Mainnet', + name: 'Solana', nativeCurrency: `${SolScope.Mainnet}/slip44:501`, isEvm: false, }, diff --git a/tsconfig.json b/tsconfig.json index 820a583033f0..9537d75973d9 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -27,7 +27,10 @@ "exclude": [ // don't typecheck stories, as they don't yet pass the type checker. "**/*.stories.tsx", - "**/*.stories.ts" + "**/*.stories.ts", + // E2E test specs have their own tsconfig in test/e2e/tsconfig.json + "test/e2e/**/*.js", + "test/e2e/**/*.ts" ], // this should match our node version in .nvmrc "extends": "@tsconfig/node22/tsconfig.json", diff --git a/ui/components/app/alert-system/alert-modal/alert-modal.test.tsx b/ui/components/app/alert-system/alert-modal/alert-modal.test.tsx index d99d1141c275..06ebe105dc01 100644 --- a/ui/components/app/alert-system/alert-modal/alert-modal.test.tsx +++ b/ui/components/app/alert-system/alert-modal/alert-modal.test.tsx @@ -339,55 +339,55 @@ describe('AlertModal', () => { const testCases = [ { reason: BlockaidReason.rawSignatureFarming, - expectedKey: 'blockaidAlertInfoDescription3', + expectedKey: 'blockaidAlertDescriptionOthers', }, { reason: BlockaidReason.approvalFarming, - expectedKey: 'blockaidAlertInfoDescription2', + expectedKey: 'blockaidAlertDescriptionWithdraw', }, { reason: BlockaidReason.setApprovalForAll, - expectedKey: 'blockaidAlertInfoDescription2', + expectedKey: 'blockaidAlertDescriptionWithdraw', }, { reason: BlockaidReason.permitFarming, - expectedKey: 'blockaidAlertInfoDescription2', + expectedKey: 'blockaidAlertDescriptionWithdraw', }, { reason: BlockaidReason.transferFarming, - expectedKey: 'blockaidAlertInfoDescription', + expectedKey: 'blockaidAlertDescriptionTokenTransfer', }, { reason: BlockaidReason.transferFromFarming, - expectedKey: 'blockaidAlertInfoDescription', + expectedKey: 'blockaidAlertDescriptionTokenTransfer', }, { reason: BlockaidReason.rawNativeTokenTransfer, - expectedKey: 'blockaidAlertInfoDescription', + expectedKey: 'blockaidAlertDescriptionTokenTransfer', }, { reason: BlockaidReason.seaportFarming, - expectedKey: 'blockaidAlertInfoDescription4', + expectedKey: 'blockaidAlertDescriptionOpenSea', }, { reason: BlockaidReason.blurFarming, - expectedKey: 'blockaidAlertInfoDescription5', + expectedKey: 'blockaidAlertDescriptionBlur', }, { reason: BlockaidReason.maliciousDomain, - expectedKey: 'blockaidAlertInfoDescription6', + expectedKey: 'blockaidAlertDescriptionMalicious', }, { reason: BlockaidReason.tradeOrderFarming, - expectedKey: 'blockaidAlertInfoDescription7', + expectedKey: 'blockaidAlertDescriptionOthers', }, { reason: BlockaidReason.other, - expectedKey: 'blockaidAlertInfoDescription7', + expectedKey: 'blockaidAlertDescriptionOthers', }, { reason: 'unknown reason', - expectedKey: 'blockaidAlertInfoDescription7', + expectedKey: 'blockaidAlertDescriptionOthers', }, ]; @@ -431,7 +431,7 @@ describe('AlertModal', () => { ); expect( - getByText(tEn('blockaidAlertInfoDescription7') as string), + getByText(tEn('blockaidAlertDescriptionOthers') as string), ).toBeInTheDocument(); }); }); diff --git a/ui/components/app/alert-system/alert-modal/alert-modal.tsx b/ui/components/app/alert-system/alert-modal/alert-modal.tsx index d984fe2f1420..0d7311bab574 100644 --- a/ui/components/app/alert-system/alert-modal/alert-modal.tsx +++ b/ui/components/app/alert-system/alert-modal/alert-modal.tsx @@ -144,32 +144,30 @@ function BlockaidAlertDetails() { const { securityAlertResponse } = currentConfirmation; let copy; switch (securityAlertResponse?.reason) { - case BlockaidReason.rawSignatureFarming: - copy = t('blockaidAlertInfoDescription3'); - break; case BlockaidReason.approvalFarming: case BlockaidReason.setApprovalForAll: case BlockaidReason.permitFarming: - copy = t('blockaidAlertInfoDescription2'); + copy = t('blockaidAlertDescriptionWithdraw'); break; case BlockaidReason.transferFarming: case BlockaidReason.transferFromFarming: case BlockaidReason.rawNativeTokenTransfer: - copy = t('blockaidAlertInfoDescription'); + copy = t('blockaidAlertDescriptionTokenTransfer'); break; case BlockaidReason.seaportFarming: - copy = t('blockaidAlertInfoDescription4'); + copy = t('blockaidAlertDescriptionOpenSea'); break; case BlockaidReason.blurFarming: - copy = t('blockaidAlertInfoDescription5'); + copy = t('blockaidAlertDescriptionBlur'); break; case BlockaidReason.maliciousDomain: - copy = t('blockaidAlertInfoDescription6'); + copy = t('blockaidAlertDescriptionMalicious'); break; + case BlockaidReason.rawSignatureFarming: case BlockaidReason.tradeOrderFarming: case BlockaidReason.other: default: - copy = t('blockaidAlertInfoDescription7'); + copy = t('blockaidAlertDescriptionOthers'); } return ( diff --git a/ui/components/app/alert-system/utils.test.ts b/ui/components/app/alert-system/utils.test.ts index fea2e95d80d1..133d7b8b0362 100644 --- a/ui/components/app/alert-system/utils.test.ts +++ b/ui/components/app/alert-system/utils.test.ts @@ -37,7 +37,6 @@ describe('Utils', () => { { key: 'key 2', message: 'mocked message', severity: Severity.Danger }, ]; - // @ts-expect-error This is missing from the Mocha type definitions it.each([ [ `when the highest severity is ${Severity.Danger}`, @@ -62,7 +61,6 @@ describe('Utils', () => { }); describe('getBannerAlertSeverity', () => { - // @ts-expect-error This is missing from the Mocha type definitions it.each([ [Severity.Danger, 'danger'], [Severity.Warning, 'warning'], diff --git a/ui/components/app/app-components.scss b/ui/components/app/app-components.scss index 40ba76371dc7..02bde66c35c2 100644 --- a/ui/components/app/app-components.scss +++ b/ui/components/app/app-components.scss @@ -40,7 +40,6 @@ @import 'modals/index'; @import 'multiple-notifications/index'; @import 'network-display/index'; -@import 'incoming-trasaction-toggle/network-toggle'; @import 'permission-page-container/index'; @import 'permissions-connect-header/index'; @import 'permissions-connect-permission-list/index'; @@ -48,6 +47,8 @@ @import 'recovery-phrase-reminder/index'; @import 'step-progress-bar/index.scss'; @import 'selected-account/index'; +@import 'multichain-bridge-transaction-details-modal/index'; +@import 'multichain-bridge-transaction-list-item/index'; @import 'srp-input/srp-input'; @import 'snaps/snap-privacy-warning/index'; @import 'tab-bar/index'; diff --git a/ui/components/app/assets/asset-list/asset-list-control-bar/asset-list-control-bar.tsx b/ui/components/app/assets/asset-list/asset-list-control-bar/asset-list-control-bar.tsx index 5bb57fba9de0..747ac17b231e 100644 --- a/ui/components/app/assets/asset-list/asset-list-control-bar/asset-list-control-bar.tsx +++ b/ui/components/app/assets/asset-list/asset-list-control-bar/asset-list-control-bar.tsx @@ -102,10 +102,7 @@ const AssetListControlBar = ({ // We need to set the default filter for all users to be all included networks, rather than defaulting to empty object // This effect is to unblock and derisk in the short-term useEffect(() => { - if ( - process.env.PORTFOLIO_VIEW && - Object.keys(tokenNetworkFilter).length === 0 - ) { + if (Object.keys(tokenNetworkFilter).length === 0) { dispatch(setTokenNetworkFilter(allOpts)); } else { dispatch(setTokenNetworkFilter({ [currentNetwork.chainId]: true })); @@ -182,13 +179,11 @@ const AssetListControlBar = ({ {/* TODO: Remove isEvmNetwork check when we are ready to show the network filter in all networks including non-EVM */} - {process.env.PORTFOLIO_VIEW && isEvmNetwork ? ( + {isEvmNetwork ? ( ) => { - const account = useSelector(getSelectedInternalAccount); - const { isEvmNetwork } = useMultichainSelector( - getMultichainNetwork, - account, - ); const trackEvent = useContext(MetaMetricsContext); const { primaryCurrencyProperties } = usePrimaryCurrencyProperties(); const onTokenClick = useCallback( (chainId: string, tokenAddress: string) => { - if (isEvmNetwork) { - onClickAsset(chainId, tokenAddress); - trackEvent({ - event: MetaMetricsEventName.TokenScreenOpened, - category: MetaMetricsEventCategory.Navigation, - properties: { - token_symbol: primaryCurrencyProperties.suffix, - location: 'Home', - }, - }); - } + onClickAsset(chainId, tokenAddress); + trackEvent({ + event: MetaMetricsEventName.TokenScreenOpened, + category: MetaMetricsEventCategory.Navigation, + properties: { + token_symbol: primaryCurrencyProperties.suffix, + location: 'Home', + }, + }); }, [], ); diff --git a/ui/components/app/assets/asset-list/network-filter/network-filter.tsx b/ui/components/app/assets/asset-list/network-filter/network-filter.tsx index b2b3364f3ab2..e7418a586885 100644 --- a/ui/components/app/assets/asset-list/network-filter/network-filter.tsx +++ b/ui/components/app/assets/asset-list/network-filter/network-filter.tsx @@ -11,6 +11,7 @@ import { } from '../../../../../selectors'; import { getCurrentChainId, + getIsAllNetworksFilterEnabled, getNetworkConfigurationsByChainId, } from '../../../../../../shared/modules/selectors/networks'; import { useI18nContext } from '../../../../../hooks/useI18nContext'; @@ -40,11 +41,15 @@ import InfoTooltip from '../../../../ui/info-tooltip'; type SortControlProps = { handleClose: () => void; + handleFilterNetwork?: (chainFilters: Record) => void; + networkFilter?: Record; showTokenFiatBalance?: boolean; }; const NetworkFilter = ({ handleClose, + handleFilterNetwork, + networkFilter, showTokenFiatBalance = true, }: SortControlProps) => { const t = useI18nContext(); @@ -88,27 +93,33 @@ const NetworkFilter = ({ ); const handleFilter = (chainFilters: Record) => { - dispatch(setTokenNetworkFilter(chainFilters)); + if (handleFilterNetwork) { + handleFilterNetwork(chainFilters); + } else { + dispatch(setTokenNetworkFilter(chainFilters)); + } // TODO Add metrics handleClose(); }; - const allOpts: Record = {}; - Object.keys(allNetworks || {}).forEach((chain) => { - allOpts[chain] = true; - }); + const allOpts = useSelector(getIsAllNetworksFilterEnabled); const allAddedPopularNetworks = FEATURED_NETWORK_CHAIN_IDS.filter( (chain) => allOpts[chain], ).map((chain) => { return allNetworks[chain].name; }); + const filter = networkFilter || tokenNetworkFilter; return ( <> 1 && networkFilter[chainId] + : !isTokenNetworkFilterEqualCurrentNetwork + } onClick={() => handleFilter(allOpts)} testId="network-filter-all" > @@ -172,10 +183,7 @@ const NetworkFilter = ({ handleFilter({ [chainId]: true })} testId="network-filter-current" > diff --git a/ui/components/app/assets/hooks/useNetworkFilter.tsx b/ui/components/app/assets/hooks/useNetworkFilter.tsx index 1f8e352156a5..513ddf15315b 100644 --- a/ui/components/app/assets/hooks/useNetworkFilter.tsx +++ b/ui/components/app/assets/hooks/useNetworkFilter.tsx @@ -13,16 +13,14 @@ const useNetworkFilter = () => { const networkFilter = useSelector(getTokenNetworkFilter); useEffect(() => { - if (process.env.PORTFOLIO_VIEW) { - const allNetworkFilters = Object.fromEntries( - Object.keys(allNetworks).map((chainId) => [chainId, true]), - ); + const allNetworkFilters = Object.fromEntries( + Object.keys(allNetworks).map((chainId) => [chainId, true]), + ); - if (Object.keys(networkFilter).length > 1) { - dispatch(setTokenNetworkFilter(allNetworkFilters)); - } + if (Object.keys(networkFilter).length > 1) { + dispatch(setTokenNetworkFilter(allNetworkFilters)); } - }, [Object.keys(allNetworks).length, networkFilter, dispatch]); + }, [networkFilter, dispatch, allNetworks]); return { networkFilter }; }; diff --git a/ui/components/app/assets/hooks/useTokenDisplayInfo.tsx b/ui/components/app/assets/hooks/useTokenDisplayInfo.tsx index c66c172ce9df..ca3380be40b4 100644 --- a/ui/components/app/assets/hooks/useTokenDisplayInfo.tsx +++ b/ui/components/app/assets/hooks/useTokenDisplayInfo.tsx @@ -50,7 +50,9 @@ export const useTokenDisplayInfo = ({ // Format for fiat balance with currency style const secondary = - shouldShowFiat && token.tokenFiatAmount + shouldShowFiat && + token.tokenFiatAmount !== null && + token.tokenFiatAmount !== undefined ? formatWithThreshold( Number(token.tokenFiatAmount), secondaryThreshold, diff --git a/ui/components/app/assets/nfts/nft-details/__snapshots__/nft-details.test.js.snap b/ui/components/app/assets/nfts/nft-details/__snapshots__/nft-details.test.js.snap index 32778e3b60f9..f97312b16791 100644 --- a/ui/components/app/assets/nfts/nft-details/__snapshots__/nft-details.test.js.snap +++ b/ui/components/app/assets/nfts/nft-details/__snapshots__/nft-details.test.js.snap @@ -96,7 +96,7 @@ exports[`NFT Details should match minimal props and state snapshot 1`] = ` class="mm-box mm-box--display-flex mm-box--align-items-center" >

@@ -156,7 +156,7 @@ exports[`NFT Details should match minimal props and state snapshot 1`] = ` Token ID

1

@@ -170,7 +170,7 @@ exports[`NFT Details should match minimal props and state snapshot 1`] = ` Token standard

ERC721

diff --git a/ui/components/app/assets/nfts/nft-details/__snapshots__/nft-full-image.test.js.snap b/ui/components/app/assets/nfts/nft-details/__snapshots__/nft-full-image.test.js.snap index 7621f6457090..708127862d6b 100644 --- a/ui/components/app/assets/nfts/nft-details/__snapshots__/nft-full-image.test.js.snap +++ b/ui/components/app/assets/nfts/nft-details/__snapshots__/nft-full-image.test.js.snap @@ -86,7 +86,9 @@ exports[`NFT full image should match snapshot 1`] = ` />

+ > + Punk #4 +

diff --git a/ui/components/app/assets/nfts/nft-details/nft-detail-information-row.tsx b/ui/components/app/assets/nfts/nft-details/nft-detail-information-row.tsx index 2d7c1fe9dd4f..cf916c5544a6 100644 --- a/ui/components/app/assets/nfts/nft-details/nft-detail-information-row.tsx +++ b/ui/components/app/assets/nfts/nft-details/nft-detail-information-row.tsx @@ -71,7 +71,7 @@ const NftDetailInformationRow: React.FC = ({ { ...buttonAddressValue } ) : ( {value} @@ -81,7 +81,7 @@ const NftDetailInformationRow: React.FC = ({ ) : ( {withPopover && fullValue ? ( diff --git a/ui/components/app/assets/nfts/nft-details/nft-details.test.js b/ui/components/app/assets/nfts/nft-details/nft-details.test.js index c93a294ab5a3..380203ece0a3 100644 --- a/ui/components/app/assets/nfts/nft-details/nft-details.test.js +++ b/ui/components/app/assets/nfts/nft-details/nft-details.test.js @@ -121,6 +121,7 @@ describe('NFT Details', () => { await expect(removeAndIgnoreNft).toHaveBeenCalledWith( nfts[5].address, nfts[5].tokenId, + 'testNetworkConfigurationId', ); expect(setRemoveNftMessage).toHaveBeenCalledWith('success'); expect(mockHistoryPush).toHaveBeenCalledWith(DEFAULT_ROUTE); @@ -145,6 +146,7 @@ describe('NFT Details', () => { await expect(removeAndIgnoreNft).toHaveBeenCalledWith( nfts[5].address, nfts[5].tokenId, + 'testNetworkConfigurationId', ); expect(setRemoveNftMessage).toHaveBeenCalledWith('error'); expect(mockHistoryPush).toHaveBeenCalledWith(DEFAULT_ROUTE); @@ -180,7 +182,7 @@ describe('NFT Details', () => { await waitFor(() => { expect(startNewDraftTransaction).toHaveBeenCalledWith({ type: AssetType.NFT, - details: { ...nfts[5], tokenId: 1 }, + details: { ...nfts[5], tokenId: '1' }, }); expect(mockHistoryPush).toHaveBeenCalledWith(SEND_ROUTE); @@ -219,6 +221,37 @@ describe('NFT Details', () => { expect(nftSendButton).not.toBeDisabled(); }); + it('should render a single image if there is an array of images in an NFT', async () => { + const images = [ + 'ipfs://bafybeidgklvljyifilhtrxzh77brgnhcy6s2wxoxqc2l73zr2nxlwuxfcy', + 'ipfs://bafybeic26kitpujb3q5h5w7yovmvgmtxl3y4ldsb2pfgual5jq62emsmxq', + ]; + const mockNft = { + ...nfts[1], + image: images, + }; + + getAssetImageURL.mockResolvedValue( + 'https://bafybeidgklvljyifilhtrxzh77brgnhcy6s2wxoxqc2l73zr2nxlwuxfcy.ipfs.dweb.link', + ); + + const { findByTestId } = renderWithProvider( + , + mockStore, + ); + + // Assert - Component found + const image = await findByTestId('nft-image'); + expect(image).toHaveAttribute( + 'src', + 'https://bafybeidgklvljyifilhtrxzh77brgnhcy6s2wxoxqc2l73zr2nxlwuxfcy.ipfs.dweb.link', + ); + + // Assert - modified correct image + const getAssetImageCall1stParam = getAssetImageURL.mock.calls[0][0]; + expect(getAssetImageCall1stParam).toBe(images[0]); + }); + describe(`Alternative Networks' OpenSea Links`, () => { it('should open opeasea link with goeli testnet chainId', async () => { useParams.mockReturnValue({ chainId: CHAIN_IDS.GOERLI }); diff --git a/ui/components/app/assets/nfts/nft-details/nft-details.tsx b/ui/components/app/assets/nfts/nft-details/nft-details.tsx index 28e7ea9f0f95..6b4135b4f171 100644 --- a/ui/components/app/assets/nfts/nft-details/nft-details.tsx +++ b/ui/components/app/assets/nfts/nft-details/nft-details.tsx @@ -19,7 +19,7 @@ import { } from '../../../../../helpers/constants/design-system'; import { useI18nContext } from '../../../../../hooks/useI18nContext'; import { shortenAddress } from '../../../../../helpers/utils/util'; -import { getNftImageAlt } from '../../../../../helpers/utils/nfts'; +import { getNftImage, getNftImageAlt } from '../../../../../helpers/utils/nfts'; import { getCurrentChainId, getNetworkConfigurationsByChainId, @@ -78,13 +78,18 @@ import { } from '../../../../../ducks/metamask/metamask'; import { Numeric } from '../../../../../../shared/modules/Numeric'; // TODO: Remove restricted import -// eslint-disable-next-line import/no-restricted-paths -import { addUrlProtocolPrefix } from '../../../../../../app/scripts/lib/util'; +import { + addUrlProtocolPrefix, + isWebUrl, + // eslint-disable-next-line import/no-restricted-paths +} from '../../../../../../app/scripts/lib/util'; import useGetAssetImageUrl from '../../../../../hooks/useGetAssetImageUrl'; import { getImageForChainId } from '../../../../../selectors/multichain'; +import useFetchNftDetailsFromTokenURI from '../../../../../hooks/useFetchNftDetailsFromTokenURI'; import NftDetailInformationRow from './nft-detail-information-row'; import NftDetailInformationFrame from './nft-detail-information-frame'; import NftDetailDescription from './nft-detail-description'; +import { renderShortTokenId } from './utils'; const MAX_TOKEN_ID_LENGTH = 15; @@ -96,7 +101,7 @@ export function NftDetailsComponent({ nftChainId: string; }) { const { - image, + image: _image, imageOriginal, name, description, @@ -109,6 +114,7 @@ export function NftDetailsComponent({ rarityRank, topBid, attributes, + tokenURI, } = nft; const t = useI18nContext(); @@ -124,6 +130,9 @@ export function NftDetailsComponent({ const nftNetworkConfigs = useSelector(getNetworkConfigurationsByChainId); const nftChainNetwork = nftNetworkConfigs[nftChainId as Hex]; const nftChainImage = getImageForChainId(nftChainId as string); + const nftNetworkClientId = + nftChainNetwork?.rpcEndpoints?.[nftChainNetwork?.defaultRpcEndpointIndex] + .networkClientId; const networks = useSelector(getNetworkConfigurationIdByChainId) as Record< string, string @@ -131,11 +140,18 @@ export function NftDetailsComponent({ const [addressCopied, handleAddressCopy] = useCopyToClipboard(); + const { image: imageFromTokenURI, name: nameFromTokenURI } = + useFetchNftDetailsFromTokenURI(tokenURI); + const nftImageAlt = getNftImageAlt(nft); - const nftSrcUrl = imageOriginal ?? image; + const image = getNftImage(_image); + const nftSrcUrl = imageOriginal ?? image ?? imageFromTokenURI; const isIpfsURL = nftSrcUrl?.startsWith('ipfs:'); + const isImageHosted = - image?.startsWith('https:') || image?.startsWith('http:'); + (image && isWebUrl(image)) || + (imageFromTokenURI && isWebUrl(imageFromTokenURI)); + const nftImageURL = useGetAssetImageUrl( imageOriginal ?? image ?? undefined, ipfsGateway, @@ -206,7 +222,7 @@ export function NftDetailsComponent({ const onRemove = async () => { let isSuccessfulEvent = false; try { - await dispatch(removeAndIgnoreNft(address, tokenId)); + await dispatch(removeAndIgnoreNft(address, tokenId, nftNetworkClientId)); dispatch(setNewNftAddedMessage('')); dispatch(setRemoveNftMessage('success')); isSuccessfulEvent = true; @@ -292,8 +308,9 @@ export function NftDetailsComponent({ type: AssetType.NFT, details: { ...nft, - tokenId: Number(nft.tokenId), - image: nft.image ?? undefined, + tokenId: nft.tokenId as unknown as number, + image: nft.image ?? imageFromTokenURI ?? undefined, + name: nft.name ?? nameFromTokenURI ?? undefined, }, }), ); @@ -350,15 +367,7 @@ export function NftDetailsComponent({ return formatCurrency(new Numeric(value, 10).toString(), currency); }; - - const renderShortTokenId = (text: string, chars: number) => { - if (text.length <= MAX_TOKEN_ID_LENGTH) { - return text; - } - return `${text.slice(0, chars)}...${text.slice(-chars)}`; - }; - - const nftItemSrc = isImageHosted ? image : nftImageURL; + const nftItemSrc = isImageHosted ? image || imageFromTokenURI : nftImageURL; return ( @@ -410,7 +419,7 @@ export function NftDetailsComponent({ { expect(container).toMatchSnapshot(); }); }); + + it('should show the first image if an NFT has an array of images', async () => { + const images = [ + 'ipfs://bafybeidgklvljyifilhtrxzh77brgnhcy6s2wxoxqc2l73zr2nxlwuxfcy', + 'ipfs://bafybeic26kitpujb3q5h5w7yovmvgmtxl3y4ldsb2pfgual5jq62emsmxq', + ]; + const mockImageUrl = + 'https://bafybeidgklvljyifilhtrxzh77brgnhcy6s2wxoxqc2l73zr2nxlwuxfcy.ipfs.dweb.link'; + const mockUseGetAssetImageUrl = jest + .spyOn(UseGetAssetImageUrlModule, 'default') + .mockReturnValue(mockImageUrl); + + nfts[0].image = images; + + const { findByTestId } = renderWithProvider(, mockStore); + + const imageElem = await findByTestId('nft-image'); + expect(imageElem).toHaveAttribute('src', mockImageUrl); + expect(mockUseGetAssetImageUrl).toHaveBeenCalledWith( + images[0], + expect.any(String), + ); + }); }); diff --git a/ui/components/app/assets/nfts/nft-details/nft-full-image.tsx b/ui/components/app/assets/nfts/nft-details/nft-full-image.tsx index 5e9e9057a2ed..99857a7df47f 100644 --- a/ui/components/app/assets/nfts/nft-details/nft-full-image.tsx +++ b/ui/components/app/assets/nfts/nft-details/nft-full-image.tsx @@ -3,7 +3,7 @@ import { useSelector } from 'react-redux'; import { useHistory, useParams } from 'react-router-dom'; import { Nft } from '@metamask/assets-controllers'; import { toHex } from '@metamask/controller-utils'; -import { getNftImageAlt } from '../../../../../helpers/utils/nfts'; +import { getNftImage, getNftImageAlt } from '../../../../../helpers/utils/nfts'; import { getIpfsGateway } from '../../../../../selectors'; import { @@ -25,13 +25,16 @@ import { import { useI18nContext } from '../../../../../hooks/useI18nContext'; import { ASSET_ROUTE } from '../../../../../helpers/constants/routes'; import useGetAssetImageUrl from '../../../../../hooks/useGetAssetImageUrl'; +import useFetchNftDetailsFromTokenURI from '../../../../../hooks/useFetchNftDetailsFromTokenURI'; +// TODO: Remove restricted import +// eslint-disable-next-line import/no-restricted-paths +import { isWebUrl } from '../../../../../../app/scripts/lib/util'; import { getNetworkConfigurationsByChainId } from '../../../../../../shared/modules/selectors/networks'; import { getImageForChainId } from '../../../../../selectors/multichain'; export default function NftFullImage() { const t = useI18nContext(); const { asset, id } = useParams<{ asset: string; id: string }>(); - const allNfts = useSelector(getAllNfts); const nfts = Object.values(allNfts).flat() as Nft[]; const nft = nfts.find( @@ -40,17 +43,23 @@ export default function NftFullImage() { isEqualCaseInsensitive(address, asset) && id === tokenId.toString(), ); - const { image, imageOriginal, name, tokenId, chainId, description } = - nft as Nft; + const { + image: _image, + imageOriginal, + tokenURI, + name, + tokenId, + chainId, + description, + } = nft as Nft; + const { image: imageFromTokenURI } = useFetchNftDetailsFromTokenURI(tokenURI); + const image = getNftImage(_image); const ipfsGateway = useSelector(getIpfsGateway); const nftNetworkConfigs = useSelector(getNetworkConfigurationsByChainId); const nftChainNetwork = nftNetworkConfigs[toHex(chainId?.toString() ?? '')]; const nftChainImage = getImageForChainId(toHex(chainId?.toString() ?? '')); - const nftImageURL = useGetAssetImageUrl( - imageOriginal ?? (image || undefined), - ipfsGateway, - ); + const nftImageURL = useGetAssetImageUrl(imageOriginal ?? image, ipfsGateway); const nftImageAlt = getNftImageAlt({ name, @@ -59,7 +68,10 @@ export default function NftFullImage() { }); const nftSrcUrl = imageOriginal ?? image; const isIpfsURL = nftSrcUrl?.startsWith('ipfs:'); - const isImageHosted = image?.startsWith('https:'); + + const isImageHosted = + (image && isWebUrl(image)) || + (imageFromTokenURI && isWebUrl(imageFromTokenURI)); const history = useHistory(); const [visible, setVisible] = useState(false); @@ -95,7 +107,7 @@ export default function NftFullImage() { > { + if (text.length <= MAX_TOKEN_ID_LENGTH) { + return text; + } + return `${text.slice(0, chars)}...${text.slice(-chars)}`; +}; diff --git a/ui/components/app/assets/nfts/nft-grid/nft-grid.tsx b/ui/components/app/assets/nfts/nft-grid/nft-grid.tsx index 58ed44c6cbdd..d2f7ccda98c7 100644 --- a/ui/components/app/assets/nfts/nft-grid/nft-grid.tsx +++ b/ui/components/app/assets/nfts/nft-grid/nft-grid.tsx @@ -8,7 +8,7 @@ import { } from '../../../../../helpers/constants/design-system'; import { Box } from '../../../../component-library'; import Spinner from '../../../../ui/spinner'; -import { getNftImageAlt } from '../../../../../helpers/utils/nfts'; +import { getNftImageAlt, getNftImage } from '../../../../../helpers/utils/nfts'; import { NftItem } from '../../../../multichain/nft-item'; import { NFT } from '../../../../multichain/asset-picker-amount/asset-picker-modal/types'; import { @@ -18,6 +18,10 @@ import { import useGetAssetImageUrl from '../../../../../hooks/useGetAssetImageUrl'; import { getImageForChainId } from '../../../../../selectors/multichain'; import { getNetworkConfigurationsByChainId } from '../../../../../../shared/modules/selectors/networks'; +import useFetchNftDetailsFromTokenURI from '../../../../../hooks/useFetchNftDetailsFromTokenURI'; +// TODO: Remove restricted import +// eslint-disable-next-line import/no-restricted-paths +import { isWebUrl } from '../../../../../../app/scripts/lib/util'; import NFTGridItemErrorBoundary from './nft-grid-item-error-boundary'; const NFTGridItem = (props: { @@ -27,7 +31,9 @@ const NFTGridItem = (props: { }) => { const { nft, onClick, privacyMode } = props; - const { image, imageOriginal } = nft; + const { image: _image, imageOriginal, tokenURI } = nft; + const { image: imageFromTokenURI } = useFetchNftDetailsFromTokenURI(tokenURI); + const image = getNftImage(_image); const ipfsGateway = useSelector(getIpfsGateway); const nftImageURL = useGetAssetImageUrl( @@ -37,8 +43,9 @@ const NFTGridItem = (props: { const allNetworks = useSelector(getNetworkConfigurationsByChainId); const isImageHosted = - image?.startsWith('https:') || image?.startsWith('http:'); - const nftItemSrc = isImageHosted ? image : nftImageURL; + (image && isWebUrl(image)) || + (imageFromTokenURI && isWebUrl(imageFromTokenURI)); + const nftItemSrc = isImageHosted ? image || imageFromTokenURI : nftImageURL; const nftImageAlt = getNftImageAlt(nft); diff --git a/ui/components/app/assets/token-cell/__snapshots__/token-cell.test.tsx.snap b/ui/components/app/assets/token-cell/__snapshots__/token-cell.test.tsx.snap index c8a593fdc640..2e687ad5b479 100644 --- a/ui/components/app/assets/token-cell/__snapshots__/token-cell.test.tsx.snap +++ b/ui/components/app/assets/token-cell/__snapshots__/token-cell.test.tsx.snap @@ -8,13 +8,14 @@ exports[`Token Cell should match snapshot 1`] = `
TEST logo
network logo } marginRight={4} + style={{ alignSelf: 'center' }} > void; + disableHover?: boolean; }; export default function TokenCell({ token, privacyMode = false, onClick, + disableHover = false, }: TokenCellProps) { const dispatch = useDispatch(); const history = useHistory(); @@ -59,6 +61,7 @@ export default function TokenCell({ const trackEvent = useContext(MetaMetricsContext); const { safeChains } = useSafeChains(); const [showScamWarningModal, setShowScamWarningModal] = useState(false); + const [isHovered, setIsHovered] = useState(false); const decimalChainId = isEvm && parseInt(hexToDecimal(token.chainId), 10); @@ -130,7 +133,17 @@ export default function TokenCell({ paddingLeft={4} paddingRight={4} width={BlockSize.Full} - style={{ height: 62, cursor: onClick ? 'pointer' : 'auto' }} + style={{ + height: 62, + cursor: onClick ? 'pointer' : 'auto', + backgroundColor: + !disableHover && isHovered + ? 'var(--color-background-default-hover)' + : 'transparent', + transition: 'background-color 0.2s ease-in-out', + }} + onMouseEnter={() => !disableHover && setIsHovered(true)} + onMouseLeave={() => !disableHover && setIsHovered(false)} data-testid="multichain-token-list-button" > diff --git a/ui/components/app/assets/token-list/token-list.tsx b/ui/components/app/assets/token-list/token-list.tsx index a310c901e979..4980b0b14d4a 100644 --- a/ui/components/app/assets/token-list/token-list.tsx +++ b/ui/components/app/assets/token-list/token-list.tsx @@ -17,9 +17,9 @@ import { filterAssets } from '../util/filter'; import { sortAssets } from '../util/sort'; import useMultiChainAssets from '../hooks/useMultichainAssets'; import { - getMultichainIsEvm, - getMultichainNetwork, -} from '../../../../selectors/multichain'; + getSelectedMultichainNetworkConfiguration, + getIsEvmMultichainNetworkSelected, +} from '../../../../selectors/multichain/networks'; import { getTokenBalancesEvm } from '../../../../selectors/assets'; type TokenListProps = { @@ -27,10 +27,10 @@ type TokenListProps = { }; function TokenList({ onTokenClick }: TokenListProps) { - const isEvm = useSelector(getMultichainIsEvm); + const isEvm = useSelector(getIsEvmMultichainNetworkSelected); const chainIdsToPoll = useSelector(getChainIdsToPoll); const newTokensImported = useSelector(getNewTokensImported); - const currentNetwork = useSelector(getMultichainNetwork); + const currentNetwork = useSelector(getSelectedMultichainNetworkConfiguration); const { privacyMode } = useSelector(getPreferences); const tokenSortConfig = useSelector(getTokenSortConfig); const selectedAccount = useSelector(getSelectedAccount); diff --git a/ui/components/app/assets/util/importAllDetectedTokens.ts b/ui/components/app/assets/util/importAllDetectedTokens.ts index e66316a3fb8a..1b2dbf0b3fe3 100644 --- a/ui/components/app/assets/util/importAllDetectedTokens.ts +++ b/ui/components/app/assets/util/importAllDetectedTokens.ts @@ -17,7 +17,7 @@ export const importAllDetectedTokens = async ( trackTokenAddedEvent: (importedToken: Token, chainId: string) => void, ) => { // TODO add event for MetaMetricsEventName.TokenAdded - if (process.env.PORTFOLIO_VIEW && !isOnCurrentNetwork) { + if (!isOnCurrentNetwork) { const importPromises = Object.entries(detectedTokensMultichain).map( async ([networkId, tokens]) => { const chainConfig = allNetworks[networkId]; diff --git a/ui/components/app/connected-status-indicator/connected-status-indicator.js b/ui/components/app/connected-status-indicator/connected-status-indicator.js index 55d5b646ef9e..dd38f88ae5ee 100644 --- a/ui/components/app/connected-status-indicator/connected-status-indicator.js +++ b/ui/components/app/connected-status-indicator/connected-status-indicator.js @@ -14,16 +14,17 @@ import { } from '../../../helpers/constants/design-system'; import { useI18nContext } from '../../../hooks/useI18nContext'; import { + getAllPermittedAccountsForCurrentTab, getPermissionsForActiveTab, getSelectedInternalAccount, - getPermittedAccountsForCurrentTab, } from '../../../selectors'; import { ConnectedSiteMenu } from '../../multichain'; +import { isInternalAccountInPermittedAccountIds } from '../../../../shared/lib/multichain/chain-agnostic-permission-utils/caip-accounts'; export default function ConnectedStatusIndicator({ onClick, disabled }) { const t = useI18nContext(); - const { address: selectedAddress } = useSelector(getSelectedInternalAccount); + const selectedAccount = useSelector(getSelectedInternalAccount); const permissionsForActiveTab = useSelector(getPermissionsForActiveTab); @@ -31,10 +32,10 @@ export default function ConnectedStatusIndicator({ onClick, disabled }) { .map((permission) => permission.key) .includes(WALLET_SNAP_PERMISSION_KEY); - const permittedAccounts = useSelector(getPermittedAccountsForCurrentTab); - const currentTabIsConnectedToSelectedAddress = permittedAccounts.find( - (account) => account === selectedAddress, - ); + const permittedAccounts = useSelector(getAllPermittedAccountsForCurrentTab); + + const currentTabIsConnectedToSelectedAddress = + isInternalAccountInPermittedAccountIds(selectedAccount, permittedAccounts); let status; if (currentTabIsConnectedToSelectedAddress) { diff --git a/ui/components/app/detected-token/detected-token-selection-popover/detected-token-selection-popover.js b/ui/components/app/detected-token/detected-token-selection-popover/detected-token-selection-popover.js index 570e52fb055b..f8cf049febd7 100644 --- a/ui/components/app/detected-token/detected-token-selection-popover/detected-token-selection-popover.js +++ b/ui/components/app/detected-token/detected-token-selection-popover/detected-token-selection-popover.js @@ -9,7 +9,6 @@ import { MetaMetricsEventName, MetaMetricsTokenEventSource, } from '../../../../../shared/constants/metametrics'; -import { getCurrentChainId } from '../../../../../shared/modules/selectors/networks'; import { getAllDetectedTokensForSelectedAddress, getCurrentNetwork, @@ -34,8 +33,6 @@ const DetectedTokenSelectionPopover = ({ const t = useI18nContext(); const trackEvent = useContext(MetaMetricsContext); - const chainId = useSelector(getCurrentChainId); - const detectedTokens = useSelector(getDetectedTokensInCurrentNetwork); const isTokenNetworkFilterEqualCurrentNetwork = useSelector( getIsTokenNetworkFilterEqualCurrentNetwork, @@ -48,13 +45,12 @@ const DetectedTokenSelectionPopover = ({ ); const totalTokens = useMemo(() => { - return process.env.PORTFOLIO_VIEW && - !isTokenNetworkFilterEqualCurrentNetwork - ? Object.values(detectedTokensMultichain).reduce( + return isTokenNetworkFilterEqualCurrentNetwork + ? detectedTokens.length + : Object.values(detectedTokensMultichain).reduce( (count, tokenArray) => count + tokenArray.length, 0, - ) - : detectedTokens.length; + ); }, [ detectedTokensMultichain, detectedTokens, @@ -77,9 +73,7 @@ const DetectedTokenSelectionPopover = ({ properties: { source_connection_method: MetaMetricsTokenEventSource.Detected, tokens: eventTokensDetails, - ...(process.env.PORTFOLIO_VIEW - ? { chain_ids: chainIds } - : { chain_id: chainId }), + chain_ids: chainIds, }, }); }; @@ -119,8 +113,21 @@ const DetectedTokenSelectionPopover = ({ onClose={onClose} footer={footer} > - {process.env.PORTFOLIO_VIEW && - !isTokenNetworkFilterEqualCurrentNetwork ? ( + {isTokenNetworkFilterEqualCurrentNetwork ? ( + + {detectedTokens.map((token, index) => { + return ( + + ); + })} + + ) : ( {Object.entries(detectedTokensMultichain).map( ([networkId, tokens]) => { @@ -136,20 +143,6 @@ const DetectedTokenSelectionPopover = ({ }, )} - ) : ( - - {detectedTokens.map((token, index) => { - return ( - - ); - })} - )} ); diff --git a/ui/components/app/import-token/network-filter-import-token/__snapshots__/index.test.tsx.snap b/ui/components/app/import-token/network-filter-import-token/__snapshots__/index.test.tsx.snap new file mode 100644 index 000000000000..11a2daf49d80 --- /dev/null +++ b/ui/components/app/import-token/network-filter-import-token/__snapshots__/index.test.tsx.snap @@ -0,0 +1,91 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`NetworkFilterImportToken should match snapshot 1`] = ` +
+
+ + +
+
+`; + +exports[`NetworkFilterImportToken should renders "popular networks" text when isTokenNetworkFilterEqualCurrentNetwork is true 1`] = ` +
+
+ + +
+`; diff --git a/ui/components/app/import-token/network-filter-import-token/index.test.tsx b/ui/components/app/import-token/network-filter-import-token/index.test.tsx new file mode 100644 index 000000000000..ba4129b19e9d --- /dev/null +++ b/ui/components/app/import-token/network-filter-import-token/index.test.tsx @@ -0,0 +1,74 @@ +import React from 'react'; +import configureStore from 'redux-mock-store'; +import { screen } from '@testing-library/react'; +import '@testing-library/jest-dom'; +import { useSelector } from 'react-redux'; +import { renderWithProvider } from '../../../../../test/lib/render-helpers'; +import mockState from '../../../../../test/data/mock-state.json'; +import { getIsTokenNetworkFilterEqualCurrentNetwork } from '../../../../selectors/selectors'; +import { getNetworkConfigurationsByChainId } from '../../../../../shared/modules/selectors/networks'; +import { mockNetworkState } from '../../../../../test/stub/networks'; +import { CHAIN_IDS } from '../../../../../shared/constants/network'; +import { NetworkFilterImportToken } from '.'; + +jest.mock('react-redux', () => { + const actual = jest.requireActual('react-redux'); + return { + ...actual, + useSelector: jest.fn(), + useDispatch: jest.fn(), + }; +}); + +describe('NetworkFilterImportToken', () => { + const store = configureStore()(mockState); + + (useSelector as jest.Mock).mockImplementation((selector) => { + if (selector === getIsTokenNetworkFilterEqualCurrentNetwork) { + return true; + } + if (selector === getNetworkConfigurationsByChainId) { + return mockNetworkState( + { chainId: CHAIN_IDS.MAINNET }, + { chainId: CHAIN_IDS.GOERLI }, + ); + } + return undefined; + }); + + const props = { + buttonDataTestId: 'mockButtonDataTestId', + title: 'mockTitle', + openListNetwork: jest.fn(), + }; + + it('should match snapshot', () => { + const { container } = renderWithProvider( + , + store, + ); + expect(screen.getByText('Current network')).toBeInTheDocument(); + expect(container).toMatchSnapshot(); + }); + + it('should renders "popular networks" text when isTokenNetworkFilterEqualCurrentNetwork is true', () => { + (useSelector as jest.Mock).mockImplementation((selector) => { + if (selector === getIsTokenNetworkFilterEqualCurrentNetwork) { + return false; + } + if (selector === getNetworkConfigurationsByChainId) { + return mockNetworkState( + { chainId: CHAIN_IDS.MAINNET }, + { chainId: CHAIN_IDS.GOERLI }, + ); + } + return undefined; + }); + const { container } = renderWithProvider( + , + store, + ); + expect(screen.getByText('Popular networks')).toBeInTheDocument(); + expect(container).toMatchSnapshot(); + }); +}); diff --git a/ui/components/app/import-token/network-filter-import-token/index.tsx b/ui/components/app/import-token/network-filter-import-token/index.tsx new file mode 100644 index 000000000000..72f5f4b0a3f0 --- /dev/null +++ b/ui/components/app/import-token/network-filter-import-token/index.tsx @@ -0,0 +1,101 @@ +import React, { useMemo, useRef, useState } from 'react'; +import { useSelector } from 'react-redux'; +import { TextVariant } from '../../../../helpers/constants/design-system'; +import { + Box, + Popover, + PopoverPosition, + Label, +} from '../../../component-library'; +import NetworkFilter from '../../assets/asset-list/network-filter'; +import { + getCurrentNetwork, + getIsTokenNetworkFilterEqualCurrentNetwork, +} from '../../../../selectors'; +import { getNetworkConfigurationsByChainId } from '../../../../../shared/modules/selectors/networks'; +import { getImageForChainId } from '../../../../selectors/multichain'; +import { NetworkFilterDropdown } from './network-filter-dropdown'; + +export const NetworkFilterImportToken = ({ + title, + buttonDataTestId, + openListNetwork, + networkFilter, + setNetworkFilter, +}: { + title: string; + buttonDataTestId: string; + openListNetwork: () => void; + networkFilter?: Record; + setNetworkFilter?: (network: Record) => void; +}) => { + const dropdown = useRef(null); + const [isDropdownOpen, setIsDropdownOpen] = useState(false); + const isTokenNetworkFilterEqualCurrentNetwork = useSelector( + getIsTokenNetworkFilterEqualCurrentNetwork, + ); + const currentNetwork = useSelector(getCurrentNetwork); + const currentNetworkImageUrl = getImageForChainId(currentNetwork?.chainId); + const allNetworks = useSelector(getNetworkConfigurationsByChainId); + + const allOpts = useMemo( + () => + Object.keys(allNetworks || {}).reduce>( + (acc, chain) => { + acc[chain] = true; + return acc; + }, + {}, + ), + [allNetworks], + ); + + const isCurrentNetwork = networkFilter + ? Object.keys(networkFilter).length === 1 && + networkFilter[currentNetwork?.chainId] + : isTokenNetworkFilterEqualCurrentNetwork; + + return ( + + {title ? : null} + + setIsDropdownOpen(false)} + isOpen={isDropdownOpen} + position={PopoverPosition.BottomStart} + referenceElement={dropdown.current} + matchWidth + style={{ + zIndex: 10, + display: 'flex', + flexDirection: 'column', + padding: 0, + }} + > + setIsDropdownOpen(false)} + handleFilterNetwork={(chainFilters) => { + if (setNetworkFilter) { + setNetworkFilter(chainFilters); + } + }} + {...(networkFilter && { + networkFilter, + })} + /> + + + ); +}; + +export default NetworkFilterImportToken; diff --git a/ui/components/app/import-token/network-filter-import-token/network-filter-dropdown/__snapshots__/index.test.tsx.snap b/ui/components/app/import-token/network-filter-import-token/network-filter-dropdown/__snapshots__/index.test.tsx.snap new file mode 100644 index 000000000000..e6894c7c9e7c --- /dev/null +++ b/ui/components/app/import-token/network-filter-import-token/network-filter-dropdown/__snapshots__/index.test.tsx.snap @@ -0,0 +1,46 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`NetworkFilterDropdown should render correctly 1`] = ` +
+ +
+`; diff --git a/ui/components/app/import-token/network-filter-import-token/network-filter-dropdown/index.test.tsx b/ui/components/app/import-token/network-filter-import-token/network-filter-dropdown/index.test.tsx new file mode 100644 index 000000000000..565f57646b14 --- /dev/null +++ b/ui/components/app/import-token/network-filter-import-token/network-filter-dropdown/index.test.tsx @@ -0,0 +1,31 @@ +import React from 'react'; +import { render } from '@testing-library/react'; +import { NetworkFilterDropdown } from '.'; + +jest.mock('react-redux', () => { + const actual = jest.requireActual('react-redux'); + return { + ...actual, + useSelector: jest.fn(), + }; +}); + +describe('NetworkFilterDropdown', () => { + it('should render correctly', () => { + const { getByTestId, container } = render( + null} + currentNetworkImageUrl="mockCurrentNetworkImageUrl" + allOpts={{}} + isDropdownOpen={true} + setIsDropdownOpen={() => null} + dropdownRef={React.createRef()} + />, + ); + expect(getByTestId('mockButtonDataTestId')).toBeDefined(); + expect(container).toMatchSnapshot(); + }); +}); diff --git a/ui/components/app/import-token/network-filter-import-token/network-filter-dropdown/index.tsx b/ui/components/app/import-token/network-filter-import-token/network-filter-dropdown/index.tsx new file mode 100644 index 000000000000..41e9bdf3a40c --- /dev/null +++ b/ui/components/app/import-token/network-filter-import-token/network-filter-dropdown/index.tsx @@ -0,0 +1,76 @@ +import React, { useCallback } from 'react'; +import { + Box, + ButtonIcon, + IconName, + ButtonIconSize, +} from '../../../../component-library'; +import { + BorderRadius, + AlignItems, + Display, + JustifyContent, + BorderColor, +} from '../../../../../helpers/constants/design-system'; +import { NetworkFilterDropdownItem } from './network-filter-drop-down-item'; + +type NetworkFilterDropdownProps = { + title: string; + buttonDataTestId: string; + isCurrentNetwork: boolean; + openListNetwork: () => void; + currentNetworkImageUrl: string; + allOpts: Record; + isDropdownOpen: boolean; + setIsDropdownOpen: (isOpen: boolean) => void; + dropdownRef: React.RefObject; +}; + +export const NetworkFilterDropdown = ({ + title, + buttonDataTestId, + isCurrentNetwork, + openListNetwork, + currentNetworkImageUrl, + allOpts, + isDropdownOpen, + setIsDropdownOpen, + dropdownRef, +}: NetworkFilterDropdownProps) => { + const setDropdownOpen = useCallback(() => { + setIsDropdownOpen(!isDropdownOpen); + }, [isDropdownOpen, setIsDropdownOpen]); + + return ( + + + + + ); +}; + +export default NetworkFilterDropdown; diff --git a/ui/components/app/import-token/network-filter-import-token/network-filter-dropdown/network-filter-drop-down-item/__snapshots__/index.test.tsx.snap b/ui/components/app/import-token/network-filter-import-token/network-filter-dropdown/network-filter-drop-down-item/__snapshots__/index.test.tsx.snap new file mode 100644 index 000000000000..7c0eac47865f --- /dev/null +++ b/ui/components/app/import-token/network-filter-import-token/network-filter-dropdown/network-filter-drop-down-item/__snapshots__/index.test.tsx.snap @@ -0,0 +1,32 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`NetworkFilterDropdownItem renders current network correctly and matches snapshot 1`] = ` +
+
+
+

+ Mock Network +

+
+
+
+ http://current-network.com logo +
+
+
+
+`; diff --git a/ui/components/app/import-token/network-filter-import-token/network-filter-dropdown/network-filter-drop-down-item/index.test.tsx b/ui/components/app/import-token/network-filter-import-token/network-filter-dropdown/network-filter-drop-down-item/index.test.tsx new file mode 100644 index 000000000000..c5257c0ee36d --- /dev/null +++ b/ui/components/app/import-token/network-filter-import-token/network-filter-dropdown/network-filter-drop-down-item/index.test.tsx @@ -0,0 +1,57 @@ +import React from 'react'; +import { useSelector } from 'react-redux'; +import { getCurrentNetwork } from '../../../../../../selectors'; +import { renderWithProvider } from '../../../../../../../test/lib/render-helpers'; +import { getNetworkConfigurationsByChainId } from '../../../../../../../shared/modules/selectors/networks'; +import { NetworkFilterDropdownItem } from '.'; + +// Mock react-redux useSelector +jest.mock('react-redux', () => { + const originalModule = jest.requireActual('react-redux'); + return { + ...originalModule, + useSelector: jest.fn(), + }; +}); +const mockOpenListNetwork = jest.fn(); + +const renderComponent = () => { + (useSelector as jest.Mock).mockImplementation((selector) => { + if (selector === getCurrentNetwork) { + return { + nickname: 'Mock Network', + }; + } + if (selector === getNetworkConfigurationsByChainId) { + return { + chainId: '0x1', + nickname: 'Mock Network', + }; + } + return undefined; + }); + + return renderWithProvider( + ({})} + />, + ); +}; + +describe('NetworkFilterDropdownItem', () => { + afterEach(() => { + jest.clearAllMocks(); + }); + + it('renders current network correctly and matches snapshot', () => { + const { container, getByText } = renderComponent(); + + // Verify the nickname is rendered + expect(getByText('Mock Network')).toBeDefined(); + expect(container).toMatchSnapshot(); + }); +}); diff --git a/ui/components/app/import-token/network-filter-import-token/network-filter-dropdown/network-filter-drop-down-item/index.tsx b/ui/components/app/import-token/network-filter-import-token/network-filter-dropdown/network-filter-drop-down-item/index.tsx new file mode 100644 index 000000000000..1d904da6ced7 --- /dev/null +++ b/ui/components/app/import-token/network-filter-import-token/network-filter-dropdown/network-filter-drop-down-item/index.tsx @@ -0,0 +1,111 @@ +import React from 'react'; +import { useSelector } from 'react-redux'; +import { + Box, + AvatarNetwork, + Text, + AvatarNetworkSize, +} from '../../../../../component-library'; +import { + TextVariant, + BlockSize, + TextColor, + AlignItems, + Display, + JustifyContent, +} from '../../../../../../helpers/constants/design-system'; +import { + CHAIN_ID_TO_NETWORK_IMAGE_URL_MAP, + FEATURED_NETWORK_CHAIN_IDS, +} from '../../../../../../../shared/constants/network'; +import { useI18nContext } from '../../../../../../hooks/useI18nContext'; +import { getCurrentNetwork } from '../../../../../../selectors'; + +type NetworkFilterDropdownItemProps = { + isCurrentNetwork: boolean; + openListNetwork: () => void; + currentNetworkImageUrl: string; + allOpts: Record; + setDropdownOpen: () => void; +}; + +export const NetworkFilterDropdownItem = ({ + isCurrentNetwork, + openListNetwork, + currentNetworkImageUrl, + allOpts, + setDropdownOpen, +}: NetworkFilterDropdownItemProps) => { + const t = useI18nContext(); + const currentNetwork = useSelector(getCurrentNetwork); + + if (isCurrentNetwork) { + return ( + + + + {currentNetwork?.nickname ?? t('currentNetwork')} + + + + + + + ); + } + + return ( + + + {t('popularNetworks')} + + + {FEATURED_NETWORK_CHAIN_IDS.filter((chain) => allOpts[chain]).map( + (chain, index) => { + const networkImageUrl = CHAIN_ID_TO_NETWORK_IMAGE_URL_MAP[chain]; + return ( + + ); + }, + )} + + + ); +}; diff --git a/ui/components/app/import-token/network-selector-custom-import/__snapshots__/index.test.tsx.snap b/ui/components/app/import-token/network-selector-custom-import/__snapshots__/index.test.tsx.snap new file mode 100644 index 000000000000..c0fb63352eed --- /dev/null +++ b/ui/components/app/import-token/network-selector-custom-import/__snapshots__/index.test.tsx.snap @@ -0,0 +1,33 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`NetworkSelectorCustomImport should match snapshot 1`] = ` +
+
+ +
+
+`; diff --git a/ui/components/app/import-token/network-selector-custom-import/index.test.tsx b/ui/components/app/import-token/network-selector-custom-import/index.test.tsx new file mode 100644 index 000000000000..5963211aaa69 --- /dev/null +++ b/ui/components/app/import-token/network-selector-custom-import/index.test.tsx @@ -0,0 +1,50 @@ +import React from 'react'; +import configureStore from 'redux-mock-store'; +import { fireEvent, screen } from '@testing-library/react'; +import '@testing-library/jest-dom'; +import { renderWithProvider } from '../../../../../test/lib/render-helpers'; +import mockState from '../../../../../test/data/mock-state.json'; +import { NetworkSelectorCustomImport } from '.'; + +describe('NetworkSelectorCustomImport', () => { + const store = configureStore()(mockState); + + it('should match snapshot', () => { + const props = { + title: 'Test Title', + buttonDataTestId: 'network-selector-button', + chainId: '1', + onSelectNetwork: jest.fn(), + }; + + const { container } = renderWithProvider( + , + store, + ); + + expect(screen.getByText('Test Title')).toBeInTheDocument(); + expect(container).toMatchSnapshot(); + }); + + it('should call onSelectNetwork when container is clicked', () => { + const onSelectNetwork = jest.fn(); + + const props = { + title: 'Clickable Network', + buttonDataTestId: 'network-selector-click', + chainId: '1', + onSelectNetwork, + }; + + const { getByTestId } = renderWithProvider( + , + store, + ); + + const button = getByTestId('network-selector-click'); + + // Simulate click on the outer Box container + fireEvent.click(button); + expect(onSelectNetwork).toHaveBeenCalledTimes(1); + }); +}); diff --git a/ui/components/app/import-token/network-selector-custom-import/index.tsx b/ui/components/app/import-token/network-selector-custom-import/index.tsx new file mode 100644 index 000000000000..ca5c5484a8aa --- /dev/null +++ b/ui/components/app/import-token/network-selector-custom-import/index.tsx @@ -0,0 +1,81 @@ +import React from 'react'; +import { + TextVariant, + TextColor, + BorderRadius, + AlignItems, + Display, + JustifyContent, + BorderColor, +} from '../../../../helpers/constants/design-system'; +import { + ButtonIcon, + Box, + ButtonIconSize, + IconName, + Text, + AvatarNetwork, + AvatarNetworkSize, +} from '../../../component-library'; +import { getImageForChainId } from '../../../../selectors/multichain'; + +export const NetworkSelectorCustomImport = ({ + title, + buttonDataTestId, + chainId, + onSelectNetwork, +}: { + title: string; + buttonDataTestId: string; + chainId: string; + onSelectNetwork: () => void; +}) => { + const networkImageUrl = getImageForChainId(chainId); + + return ( + + + + {title} + + + {networkImageUrl ? ( + + ) : null} + + + + + ); +}; + +export default NetworkSelectorCustomImport; diff --git a/ui/components/app/import-token/token-list/token-list.component.js b/ui/components/app/import-token/token-list/token-list.component.js index f63c8eaf34f1..1204e8911361 100644 --- a/ui/components/app/import-token/token-list/token-list.component.js +++ b/ui/components/app/import-token/token-list/token-list.component.js @@ -1,7 +1,10 @@ import React, { Component } from 'react'; import PropTypes from 'prop-types'; import classnames from 'classnames'; -import { checkExistingAddresses } from '../../../../helpers/utils/util'; +import { + checkExistingAllTokens, + checkExistingAddresses, +} from '../../../../helpers/utils/util'; import { Box, Text, @@ -21,6 +24,7 @@ import { FlexWrap, BackgroundColor, } from '../../../../helpers/constants/design-system'; +import { CHAIN_ID_TO_NETWORK_IMAGE_URL_MAP } from '../../../../../shared/constants/network'; import TokenListPlaceholder from './token-list-placeholder'; export default class TokenList extends Component { @@ -30,11 +34,14 @@ export default class TokenList extends Component { static propTypes = { tokens: PropTypes.array, + allTokens: PropTypes.object, results: PropTypes.array, selectedTokens: PropTypes.object, onToggleToken: PropTypes.func, currentNetwork: PropTypes.object, testNetworkBackgroundColor: PropTypes.object, + isTokenNetworkFilterEqualCurrentNetwork: PropTypes.bool, + accountAddress: PropTypes.string, }; render() { @@ -44,8 +51,11 @@ export default class TokenList extends Component { onToggleToken, tokens = [], + allTokens = {}, + accountAddress, currentNetwork, testNetworkBackgroundColor, + isTokenNetworkFilterEqualCurrentNetwork, } = this.props; return ( @@ -64,14 +74,23 @@ export default class TokenList extends Component { display={Display.Flex} flexDirection={FlexDirection.Column} > - {Array(12) + {Array(Math.min(12, results.length)) .fill(undefined) .map((_, i) => { - const { symbol, name, address } = results[i] || {}; - const tokenAlreadyAdded = checkExistingAddresses( - address, - tokens, - ); + const { symbol, name, address, chainId } = results[i] || {}; + let tokenAlreadyAdded = false; + if (isTokenNetworkFilterEqualCurrentNetwork) { + tokenAlreadyAdded = checkExistingAddresses(address, tokens); + results[i].chainId = currentNetwork?.chainId; + } else { + tokenAlreadyAdded = checkExistingAllTokens( + address, + chainId, + accountAddress, + allTokens, + ); + } + const onClick = () => !tokenAlreadyAdded && onToggleToken(results[i]); return ( @@ -115,7 +134,15 @@ export default class TokenList extends Component { diff --git a/ui/components/app/import-token/token-list/token-list.container.js b/ui/components/app/import-token/token-list/token-list.container.js index 7b6b0147b8de..29508ef82181 100644 --- a/ui/components/app/import-token/token-list/token-list.container.js +++ b/ui/components/app/import-token/token-list/token-list.container.js @@ -1,10 +1,15 @@ import { connect } from 'react-redux'; +import { getSelectedInternalAccount } from '../../../../selectors'; import TokenList from './token-list.component'; const mapStateToProps = (state) => { const { tokens } = state.metamask; + const { allTokens } = state.metamask; + const { address } = getSelectedInternalAccount(state); return { tokens, + allTokens, + accountAddress: address, }; }; diff --git a/ui/components/app/import-token/token-search/token-search.component.js b/ui/components/app/import-token/token-search/token-search.component.js index 1a6fe63c1c0b..fb63534f027a 100644 --- a/ui/components/app/import-token/token-search/token-search.component.js +++ b/ui/components/app/import-token/token-search/token-search.component.js @@ -1,12 +1,14 @@ -import React, { useState, useEffect } from 'react'; +import React, { useState, useEffect, useMemo } from 'react'; +import { useSelector } from 'react-redux'; import PropTypes from 'prop-types'; import Fuse from 'fuse.js'; import { isEqualCaseInsensitive } from '../../../../../shared/modules/string-utils'; import { TextFieldSearch } from '../../../component-library/text-field-search/deprecated'; import { BlockSize, Size } from '../../../../helpers/constants/design-system'; import { useI18nContext } from '../../../../hooks/useI18nContext'; +import { getCurrentNetwork } from '../../../../selectors'; -const getTokens = (tokenList) => Object.values(tokenList); +const getTokens = (tokenList = {}) => Object.values(tokenList); const createTokenSearchFuse = (tokenList) => { return new Fuse(getTokens(tokenList), { @@ -27,23 +29,38 @@ export default function TokenSearch({ error, tokenList, searchClassName, + networkFilter, + setSearchResults, }) { const t = useI18nContext(); + const isTokenNetworkFilterEqualCurrentNetwork = + Object.keys(networkFilter).length === 1; + + const { chainId } = useSelector(getCurrentNetwork); + + const filteredTokenList = useMemo(() => { + if (isTokenNetworkFilterEqualCurrentNetwork) { + return tokenList?.[chainId]?.data; + } + return Object.entries(tokenList).flatMap(([networkId, { data }]) => + Object.values(data).map((item) => ({ ...item, chainId: networkId })), + ); + }, [tokenList, isTokenNetworkFilterEqualCurrentNetwork, chainId]); const [searchQuery, setSearchQuery] = useState(''); const [tokenSearchFuse, setTokenSearchFuse] = useState( - createTokenSearchFuse(tokenList), + createTokenSearchFuse(filteredTokenList), ); useEffect(() => { - setTokenSearchFuse(createTokenSearchFuse(tokenList)); - }, [tokenList]); + setTokenSearchFuse(createTokenSearchFuse(filteredTokenList)); + }, [filteredTokenList]); const handleSearch = (newSearchQuery) => { setSearchQuery(newSearchQuery); const fuseSearchResult = tokenSearchFuse.search(newSearchQuery); - const addressSearchResult = getTokens(tokenList).filter((token) => { + const addressSearchResult = getTokens(filteredTokenList).filter((token) => { return ( token.address && newSearchQuery && @@ -56,8 +73,13 @@ export default function TokenSearch({ const clear = () => { setSearchQuery(''); + setSearchResults([]); }; + useEffect(() => { + clear(); + }, [isTokenNetworkFilterEqualCurrentNetwork]); + return ( ); @@ -81,4 +103,6 @@ TokenSearch.propTypes = { error: PropTypes.object, tokenList: PropTypes.object.isRequired, searchClassName: PropTypes.string.isRequired, + networkFilter: PropTypes.object.isRequired, + setSearchResults: PropTypes.func.isRequired, }; diff --git a/ui/components/app/import-token/token-search/token-search.stories.js b/ui/components/app/import-token/token-search/token-search.stories.js index 57ec57cea7d3..403d30dd944a 100644 --- a/ui/components/app/import-token/token-search/token-search.stories.js +++ b/ui/components/app/import-token/token-search/token-search.stories.js @@ -1,4 +1,5 @@ import React from 'react'; +import { CHAIN_IDS } from '@metamask/transaction-controller'; import testData from '../../../../../.storybook/test-data'; import TokenSearch from './token-search.component'; @@ -16,7 +17,16 @@ export default { }; export const DefaultStory = (args) => { - return ; + return ( + ({})} + /> + ); }; DefaultStory.storyName = 'Default'; diff --git a/ui/components/app/incoming-trasaction-toggle/__snapshots__/incoming-transaction-toggle.test.js.snap b/ui/components/app/incoming-trasaction-toggle/__snapshots__/incoming-transaction-toggle.test.js.snap deleted file mode 100644 index bc268b8cbb73..000000000000 --- a/ui/components/app/incoming-trasaction-toggle/__snapshots__/incoming-transaction-toggle.test.js.snap +++ /dev/null @@ -1,621 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`IncomingTransactionToggle should render existing incoming transaction preferences 1`] = ` -
-
-

- Show incoming transactions -

-

- This relies on different third-party APIs for each network, which expose your Ethereum address and your IP address. -

-
- -
-
-
-
-
-
-
-
-
- -
-
- - Off - - - On - -
- -
-
-
- -
-