├── .eslintignore ├── .eslintrc.js ├── .github └── workflows │ └── deploy.yaml ├── .gitignore ├── .npmrc ├── .nvmrc ├── .vscode ├── launch.json ├── settings.json └── tasks.json ├── .vscodeignore ├── CHANGELOG.md ├── README.md ├── bin ├── solppc │ └── .keep └── vite │ ├── .vscode │ └── launch.json │ ├── HelloWorld.solpp │ ├── clean.bat │ ├── clean.sh │ ├── devdata │ └── wallet │ │ └── vite_e41be57d38c796984952fad618a9bc91637329b5255cb18906 │ ├── genesis.json │ ├── kill.sh │ ├── node_config.json │ ├── startup.bat │ └── startup.sh ├── debug-contract-data.json ├── examples ├── .vscode │ └── launch.json ├── HelloWorld.solpp ├── h2.solpp ├── luck9.solpp └── test.solpp ├── images └── vscode.png ├── package-lock.json ├── package.json ├── soliditypp-configuration.json ├── src ├── autoComplete.ts ├── constant.ts ├── createGvite.ts ├── createSolppc.ts ├── debugAdapterDescriptorFactory.ts ├── debugConfigurationProvider.ts ├── debugSession.ts ├── extension.ts ├── extensionRequestProcessor.ts ├── httpServer.ts ├── test │ ├── runTest.ts │ └── suite │ │ ├── index.ts │ │ └── sampleext.test.ts ├── uri.ts ├── utils │ ├── linesParser.test.ts │ └── linesParser.ts └── viewRequestProcessor.ts ├── syntax └── soliditypp.json ├── tsconfig.json ├── tslint.json ├── view ├── app.vue ├── components │ ├── accountBlock.vue │ ├── baseInfo.vue │ ├── contract.vue │ ├── contractList.vue │ ├── debug.vue │ ├── debugInfo.vue │ ├── deploy.vue │ ├── deployList.vue │ ├── help.vue │ ├── logItem.vue │ ├── logList.vue │ ├── resultList.vue │ ├── selectToken.vue │ ├── setting.vue │ ├── tokenUnits.vue │ ├── transfer.vue │ ├── units.vue │ └── vcLogin.vue ├── global │ ├── Account.js │ ├── VcAccount.js │ ├── constants.js │ ├── vite.js │ └── vscode.js ├── i18n │ ├── en.js │ └── zh.js ├── index.html ├── index.js ├── index.scss ├── router.js ├── services │ ├── compile.js │ └── vc.js ├── store │ └── store.js ├── utils │ ├── postError.js │ ├── receiveAllOnroadTx.js │ ├── request.js │ ├── storage.js │ └── task.js └── webpackConfig │ ├── base.config.js │ └── plugins.js ├── webpack.config.js └── yarn.lock /.eslintignore: -------------------------------------------------------------------------------- 1 | **/*.js 2 | !view/**/* -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | "env": { 3 | "browser": true, 4 | "commonjs": true, 5 | "es6": true, 6 | "node": true 7 | }, 8 | "parserOptions": { 9 | "parser": "babel-eslint", 10 | "ecmaFeatures": { 11 | "jsx": true 12 | }, 13 | "sourceType": "module" 14 | }, 15 | "globals": { 16 | "TradingView": true, 17 | "window": true, 18 | "viteWallet": true, 19 | "$ViteJS": true, 20 | "webViteEventEmitter": true, 21 | "_hmt": true, 22 | "viteWalletStorage": true, 23 | "acquireVsCodeApi": true 24 | }, 25 | "extends": [ 26 | "eslint:recommended", 27 | 'plugin:vue/essential' 28 | ], 29 | "rules": { 30 | "indent": ["error", 4], 31 | "linebreak-style": ["error", "unix"], 32 | "vue/require-v-for-key": "off", 33 | "quotes": ["error", "single"], 34 | "semi": ["error", "always"], 35 | "no-console": "off", 36 | "no-useless-escape": "off", 37 | "vue/html-indent": ["error", 4], 38 | 'no-debugger': 0, 39 | } 40 | }; -------------------------------------------------------------------------------- /.github/workflows/deploy.yaml: -------------------------------------------------------------------------------- 1 | # This is a basic workflow to help you get started with Actions 2 | 3 | name: Publish To VSCode [manual] 4 | 5 | # Controls when the action will run. 6 | on: 7 | workflow_dispatch: 8 | inputs: 9 | branch: 10 | description: 'Choose an branch to deploy' 11 | required: true 12 | default: 'master' 13 | version: 14 | description: 'Choose version bump types: major | minor | patch' 15 | required: true 16 | default: 'patch' 17 | dryRun: 18 | description: 'Set this option to true to package your extension but do not publish it.' 19 | required: true 20 | default: 'false' 21 | 22 | # A workflow run is made up of one or more jobs that can run sequentially or in parallel 23 | jobs: 24 | # This workflow contains a single job called "build" 25 | deploy: 26 | # The type of runner that the job will run on 27 | runs-on: ubuntu-latest 28 | 29 | environment: vscode 30 | 31 | # Steps represent a sequence of tasks that will be executed as part of the job 32 | steps: 33 | # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it 34 | - uses: actions/checkout@v2 35 | with: 36 | ref: ${{ github.event.inputs.branch }} 37 | 38 | - name: Read .nvmrc 39 | run: echo ::set-output name=NVMRC::$(cat .nvmrc) 40 | id: nvm 41 | 42 | - name: Setup Node 43 | uses: actions/setup-node@v2.1.2 44 | with: 45 | node-version: '${{ steps.nvm.outputs.NVMRC }}' 46 | 47 | - uses: bahmutov/npm-install@v1 48 | 49 | # - name: Bump Version 50 | # run: | 51 | # git config --local user.email "41898282+github-actions[bot]@users.noreply.github.com" 52 | # git config --local user.name "github-actions[bot]" 53 | # npm version ${{ github.event.inputs.version }} 54 | 55 | - name: Publish to Visual Studio Marketplace 56 | uses: HaaLeo/publish-vscode-extension@v0 57 | with: 58 | pat: ${{ secrets.VS_MARKETPLACE_TOKEN }} 59 | registryUrl: https://marketplace.visualstudio.com 60 | yarn: true 61 | dryRun: ${{ github.event.inputs.dryRun }} 62 | 63 | # - name: Push changes 64 | # uses: ad-m/github-push-action@v0.6.0 65 | # with: 66 | # github_token: ${{ secrets.GITHUB_TOKEN }} 67 | # branch: ${{ github.event.inputs.branch }} 68 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | out 3 | out_view 4 | gvite 5 | gvite.log 6 | gvite.exe 7 | .DS_Store 8 | ledger 9 | *.vsix 10 | bin/solppc/* 11 | !bin/solppc/.keep 12 | solppc_*.tar.gz 13 | __MACOSX 14 | bin/vite/gvite-*.tar.gz 15 | gvite-v*/ 16 | example 17 | accountBlock_test.js 18 | nbproject 19 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | registry=https://registry.npmjs.org/ 2 | -------------------------------------------------------------------------------- /.nvmrc: -------------------------------------------------------------------------------- 1 | v14 -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.2.0", 3 | "configurations": [ 4 | { 5 | "type": "soliditypp", 6 | "request": "launch", 7 | "name": "Soliditypp Debug", 8 | "program": "" 9 | }, 10 | { 11 | "name": "Run Extension", 12 | "type": "extensionHost", 13 | "request": "launch", 14 | "runtimeExecutable": "${execPath}", 15 | "args": [ 16 | "--extensionDevelopmentPath=${workspaceFolder}", 17 | "--disable-extensions", 18 | ], 19 | "outFiles": ["${workspaceFolder}/out/**/*.js"] 20 | // "preLaunchTask": "npm: watch" 21 | // "preLaunchTask": "npm: view:build:watch" 22 | }, 23 | { 24 | "name": "Extension Tests", 25 | "type": "extensionHost", 26 | "request": "launch", 27 | "runtimeExecutable": "${execPath}", 28 | "args": [ 29 | "--extensionDevelopmentPath=${workspaceFolder}", 30 | "--extensionTestsPath=${workspaceFolder}/out/test/suite/index", 31 | "--disable-extensions", 32 | ], 33 | "outFiles": ["${workspaceFolder}/out/test/**/*.js"] 34 | } 35 | ] 36 | } 37 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | } -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | // See https://go.microsoft.com/fwlink/?LinkId=733558 3 | // for the documentation about the tasks.json format 4 | "version": "2.0.0", 5 | "tasks": [ 6 | { 7 | "type": "npm", 8 | "script": "watch", 9 | "problemMatcher": [] 10 | } 11 | ] 12 | } -------------------------------------------------------------------------------- /.vscodeignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | gvite 3 | gvite.log 4 | gvite.exe 5 | .DS_Store 6 | ledger 7 | *.vsix 8 | bin/solppc/* 9 | !bin/solppc/.keep 10 | solppc_*.tar.gz 11 | __MACOSX 12 | bin/vite/gvite-*.tar.gz 13 | gvite-v*/ 14 | example 15 | accountBlock_test.js 16 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Soliditypp extension for Visual Studio Code 2 | ## 0.6.1 3 | ### Fixes 4 | 1. Fix the problem of showing balance. 5 | 6 | ## 0.6.0 7 | ### Fixes 8 | 1. Update gvite and @vite/vitejs version. 9 | 10 | ## v0.5.3 11 | ### Fixes 12 | 1. Update gvite and @vite/vitejs version. 13 | 14 | ## v0.5.2 15 | ### Fixes 16 | 1. Fix about contract input params of array type 17 | 18 | ## v0.5.1 19 | ### Fixes 20 | 1. Fix that gvite process is alive after stop debugging 21 | 22 | ## v0.5.0 23 | 24 | ### Features 25 | 1. Support gvite@2.2.0 26 | 2. Support solppc@0.4.3 27 | 28 | ### Optimize 29 | 1. Upgrade GUI completelly 30 | 2. Reduce plug-in package size from 20M to 1M 31 | 32 | ### Fixes 33 | 1. Fix the bug about deployment timeout and calling method timeout 34 | 2. Fix lacking compile error hint when save file 35 | 36 | ## v0.4.3 37 | 38 | ### Fixes 39 | 1. Fix that fail to run `gvite` on windows 40 | 41 | ## v0.4.2 42 | 43 | ### Features 44 | 1. Remove unused files to reduce plugin size 45 | 46 | ## v0.4.0 47 | 48 | ### Features 49 | 1. Support for offchain querying 50 | 2. Adapt to multiple platforms(Linux、Darwin、Win64) 51 | 3. Compatible with gvite@2.1.4 -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Soliditypp extension for Visual Studio Code 2 | 3 | [Soliditypp](https://marketplace.visualstudio.com/items?itemName=ViteLabs.soliditypp) is the smart contract programming language used in Vite. Vite is a DAG-based, asynchronous, high-performance and fee-less dApp platform where transactions can be executed quickly and confirmed in seconds. The extension contains following features: 4 | 5 | ## Features 6 | * Syntax highlighting 7 | * Code completion 8 | * Auto compilation when saving the contract 9 | * Compilation error highlighting 10 | * Detailed error message displaying when mouse over 11 | * One-click smart contract deployment and debugging 12 | * Support for multiple smart contracts 13 | * Deployment / debugging result displaying 14 | * Support for offchain querying 15 | * Support import mnemonics 16 | * Support to call contract and create contract by vc connect 17 | * Support deploy contract and call contract on testnet and mainnet 18 | * Support call any contract on mainnet 19 | * Examples 20 | 21 | ## Tutorial 22 | See the [Vite Wiki](https://vite.wiki/tutorial/contract/debug.html) for details. 23 | 24 | 25 | ## Publish 26 | 27 | https://code.visualstudio.com/api/working-with-extensions/publishing-extension 28 | 29 | ``` 30 | # Bump package version 31 | npm version patch 32 | 33 | # Publish to VC marketplace 34 | vsce publish 35 | ``` -------------------------------------------------------------------------------- /bin/solppc/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vitelabs/soliditypp-vscode/c77df4f9eac10877f331ea96e73edbb0937935d2/bin/solppc/.keep -------------------------------------------------------------------------------- /bin/vite/.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "type": "soliditypp", 9 | "request": "launch", 10 | "name": "Soliditypp Debug", 11 | "program": "${file}" 12 | } 13 | ] 14 | } -------------------------------------------------------------------------------- /bin/vite/HelloWorld.solpp: -------------------------------------------------------------------------------- 1 | pragma soliditypp ^0.4.2; 2 | contract HelloWorld { 3 | event transfer(address indexed addr,uint256 amount); 4 | onMessage SayHello(address addr) payable { 5 | addr.transfer(msg.tokenid ,msg.amount); 6 | emit transfer(addr, msg.amount); 7 | } 8 | } -------------------------------------------------------------------------------- /bin/vite/clean.bat: -------------------------------------------------------------------------------- 1 | rd /s/q ledger -------------------------------------------------------------------------------- /bin/vite/clean.sh: -------------------------------------------------------------------------------- 1 | rm -rf ./ledger -------------------------------------------------------------------------------- /bin/vite/devdata/wallet/vite_e41be57d38c796984952fad618a9bc91637329b5255cb18906: -------------------------------------------------------------------------------- 1 | {"primaryAddress":"vite_e41be57d38c796984952fad618a9bc91637329b5255cb18906","crypto":{"ciphername":"aes-256-gcm","ciphertext":"807e09cc3e9f48c1742b22096404d98ba61e5c892994242515d48eb84cbee5f2ed93c7805ec32adb259e166fcd62428b","nonce":"41d76fee25bfa544b8212cf6","kdf":"scrypt","scryptparams":{"n":262144,"r":8,"p":1,"keylen":32,"salt":"64c5f11657f91680c53bf8b618416a2a4d0c8e46c2cc6dc753fd11c9fc77441c"}},"seedstoreversion":1,"timestamp":1544422238} -------------------------------------------------------------------------------- /bin/vite/genesis.json: -------------------------------------------------------------------------------- 1 | { 2 | "GenesisAccountAddress": "vite_bb6ad02107a4422d6a324fd2e3707ad53cfed9359378a78792", 3 | "UpgradeCfg": { 4 | "Level": "latest" 5 | }, 6 | "GovernanceInfo": { 7 | "ConsensusGroupInfoMap": { 8 | "00000000000000000001": { 9 | "NodeCount": 1, 10 | "Interval": 1, 11 | "PerCount": 3, 12 | "RandCount": 0, 13 | "RandRank": 100, 14 | "Repeat": 1, 15 | "CheckLevel": 0, 16 | "CountingTokenId": "tti_5649544520544f4b454e6e40", 17 | "RegisterConditionId": 1, 18 | "RegisterConditionParam": { 19 | "StakeAmount": 500000000000000000000000, 20 | "StakeHeight": 1, 21 | "StakeToken": "tti_5649544520544f4b454e6e40" 22 | }, 23 | "VoteConditionId": 1, 24 | "VoteConditionParam": {}, 25 | "Owner": "vite_bb6ad02107a4422d6a324fd2e3707ad53cfed9359378a78792", 26 | "StakeAmount": 0, 27 | "ExpirationHeight": 1 28 | }, 29 | "00000000000000000002": { 30 | "NodeCount": 1, 31 | "Interval": 3, 32 | "PerCount": 1, 33 | "RandCount": 0, 34 | "RandRank": 100, 35 | "Repeat": 48, 36 | "CheckLevel": 1, 37 | "CountingTokenId": "tti_5649544520544f4b454e6e40", 38 | "RegisterConditionId": 1, 39 | "RegisterConditionParam": { 40 | "StakeAmount": 500000000000000000000000, 41 | "StakeToken": "tti_5649544520544f4b454e6e40" 42 | }, 43 | "VoteConditionId": 1, 44 | "VoteConditionParam": {}, 45 | "Owner": "vite_bb6ad02107a4422d6a324fd2e3707ad53cfed9359378a78792", 46 | "StakeAmount": 0, 47 | "ExpirationHeight": 1 48 | } 49 | }, 50 | 51 | "RegistrationInfoMap": { 52 | "00000000000000000001": { 53 | "s1": { 54 | "BlockProducingAddress": "vite_e41be57d38c796984952fad618a9bc91637329b5255cb18906", 55 | "StakeAddress": "vite_e41be57d38c796984952fad618a9bc91637329b5255cb18906", 56 | "Amount": 500000000000000000000000, 57 | "ExpirationHeight": 7776000, 58 | "RewardTime": 1, 59 | "RevokeTime": 0, 60 | "HistoryAddressList": [ 61 | "vite_e41be57d38c796984952fad618a9bc91637329b5255cb18906" 62 | ] 63 | } 64 | }, 65 | "00000000000000000002": { 66 | "s1": { 67 | "BlockProducingAddress": "vite_e41be57d38c796984952fad618a9bc91637329b5255cb18906", 68 | "StakeAddress": "vite_e41be57d38c796984952fad618a9bc91637329b5255cb18906", 69 | "Amount": 500000000000000000000000, 70 | "ExpirationHeight": 7776000, 71 | "RewardTime": 1, 72 | "RevokeTime": 0, 73 | "HistoryAddressList": [ 74 | "vite_e41be57d38c796984952fad618a9bc91637329b5255cb18906" 75 | ] 76 | } 77 | } 78 | } 79 | }, 80 | "AssetInfo": { 81 | "TokenInfoMap": { 82 | "tti_5649544520544f4b454e6e40": { 83 | "TokenName": "Vite Token", 84 | "TokenSymbol": "VITE", 85 | "TotalSupply": 1000000000000000000000000000, 86 | "Decimals": 18, 87 | "Owner": "vite_bb6ad02107a4422d6a324fd2e3707ad53cfed9359378a78792", 88 | "MaxSupply": 115792089237316195423570985008687907853269984665640564039457584007913129639935, 89 | "IsOwnerBurnOnly": false, 90 | "IsReIssuable": true 91 | } 92 | }, 93 | "LogList": [ 94 | { 95 | "Data": "", 96 | "Topics": [ 97 | "3f9dcc00d5e929040142c3fb2b67a3be1b0e91e98dac18d5bc2b7817a4cfecb6", 98 | "000000000000000000000000000000000000000000005649544520544f4b454e" 99 | ] 100 | } 101 | ] 102 | }, 103 | "QuotaInfo": { 104 | "StakeBeneficialMap": { 105 | "vite_bb6ad02107a4422d6a324fd2e3707ad53cfed9359378a78792": 10000000000000000000000, 106 | "vite_56fd05b23ff26cd7b0a40957fb77bde60c9fd6ebc35f809c23": 10000000000000000000000 107 | }, 108 | "StakeInfoMap": { 109 | "vite_bb6ad02107a4422d6a324fd2e3707ad53cfed9359378a78792": [ 110 | { 111 | "Amount": 10000000000000000000000, 112 | "ExpirationHeight": 259200, 113 | "Beneficiary": "vite_bb6ad02107a4422d6a324fd2e3707ad53cfed9359378a78792" 114 | } 115 | ], 116 | "vite_56fd05b23ff26cd7b0a40957fb77bde60c9fd6ebc35f809c23": [ 117 | { 118 | "Amount": 10000000000000000000000, 119 | "ExpirationHeight": 259200, 120 | "Beneficiary": "vite_56fd05b23ff26cd7b0a40957fb77bde60c9fd6ebc35f809c23" 121 | } 122 | ] 123 | } 124 | }, 125 | "AccountBalanceMap": { 126 | "vite_bb6ad02107a4422d6a324fd2e3707ad53cfed9359378a78792": { 127 | "tti_5649544520544f4b454e6e40": 899980000000000000000000000 128 | }, 129 | "vite_56fd05b23ff26cd7b0a40957fb77bde60c9fd6ebc35f809c23": { 130 | "tti_5649544520544f4b454e6e40": 100000000000000000000000000 131 | }, 132 | "vite_e41be57d38c796984952fad618a9bc91637329b5255cb18906": { 133 | "tti_5649544520544f4b454e6e40": 0 134 | } 135 | } 136 | } 137 | -------------------------------------------------------------------------------- /bin/vite/kill.sh: -------------------------------------------------------------------------------- 1 | pgrep gvite | xargs kill -9 -------------------------------------------------------------------------------- /bin/vite/node_config.json: -------------------------------------------------------------------------------- 1 | { 2 | "LogLevel": "info", 3 | "NetID": 3, 4 | "GenesisFile": "./genesis.json", 5 | "PrivateKey": "511a6d8762bd95ce12819267f2c0fa092687ed6f47b21d43a35112a2792e4ebad7e63ddca1e41d311db9668bb0f6ff549cab9c24de03ecaa1643940a8fdc3937", 6 | "Identity": "vite-single", 7 | "MaxPeers": 100, 8 | "MaxPendingPeers": 20, 9 | "BootNodes": [], 10 | "PublicModules": [ 11 | "ledger", 12 | "net", 13 | "contract", 14 | "util", 15 | "debug", 16 | "sbpstats", 17 | "dashboard", 18 | "subscribe", 19 | "public_onroad", 20 | "tx", 21 | "wallet", 22 | "pledge", 23 | "register", 24 | "vote", 25 | "mintage", 26 | "consensusGroup" 27 | ], 28 | "Port": 8487, 29 | "RPCEnabled": true, 30 | "HttpHost": "0.0.0.0", 31 | "HttpPort": 23456, 32 | "WSEnabled": true, 33 | "WSHost": "0.0.0.0", 34 | "WSPort": 23457, 35 | "TestTokenHexPrivKey": "7488b076b27aec48692230c88cbe904411007b71981057ea47d757c1e7f7ef24f4da4390a6e2618bec08053a86a6baf98830430cbefc078d978cf396e1c43e3a", 36 | "TestTokenTti": "tti_5649544520544f4b454e6e40", 37 | "CoinBase": "0:vite_e41be57d38c796984952fad618a9bc91637329b5255cb18906", 38 | "Miner": true, 39 | "Single": true, 40 | "EntropyStorePath": "vite_e41be57d38c796984952fad618a9bc91637329b5255cb18906", 41 | "EntropyStorePassword": "123", 42 | "VMTestEnabled": true, 43 | "VMDebug": true, 44 | "DataDir": "ledger", 45 | "KeyStoreDir": "./", 46 | "SubscribeEnabled": true, 47 | "OpenPlugins": true, 48 | "vmLogAll": true 49 | } 50 | -------------------------------------------------------------------------------- /bin/vite/startup.bat: -------------------------------------------------------------------------------- 1 | gvite.exe --pprof > gvite.log -------------------------------------------------------------------------------- /bin/vite/startup.sh: -------------------------------------------------------------------------------- 1 | # gvite=$1 2 | # if [ ! $gvite ]; then 3 | # gvite="gvite" 4 | # fi 5 | 6 | # ./kill.sh 7 | 8 | # ./${gvite} --pprof > gvite.log 9 | exec ./gvite --pprof > gvite.log -------------------------------------------------------------------------------- /debug-contract-data.json: -------------------------------------------------------------------------------- 1 | {"bytecodesList":["608060405234801561001057600080fd5b50610141806100206000396000f3fe608060405260043610610041576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806391a6cb4b14610046575b600080fd5b6100896004803603602081101561005c57600080fd5b81019080803574ffffffffffffffffffffffffffffffffffffffffff16906020019092919050505061008b565b005b8074ffffffffffffffffffffffffffffffffffffffffff164669ffffffffffffffffffff163460405160405180820390838587f1505050508074ffffffffffffffffffffffffffffffffffffffffff167faa65281f5df4b4bd3c71f2ba25905b907205fce0809a816ef8e04b4d496a85bb346040518082815260200191505060405180910390a25056fea165627a7a72305820a2598ba3d6edda466f22e78381d3aa29bc40d52219f5b337b4baadf8c0a7536a0029","608060405234801561001057600080fd5b50336000806101000a81548174ffffffffffffffffffffffffffffffffffffffffff021916908374ffffffffffffffffffffffffffffffffffffffffff1602179055506111b0806100626000396000f3fe608060405260043610610057576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063075dc04c146100595780635ad1c67914610097578063e925e30d146100a1575b005b34801561006557600080fd5b506100956004803603602081101561007c57600080fd5b81019080803560ff1690602001909291905050506100dc565b005b61009f610326565b005b3480156100ad57600080fd5b506100da600480360360208110156100c457600080fd5b81019080803590602001909291905050506107a6565b005b600160003374ffffffffffffffffffffffffffffffffffffffffff1674ffffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002160020160009054906101000a900460ff16151561013957600080fd5b6000600b8260ff16141561030557600061015433600161083f565b905060006101ea600160003374ffffffffffffffffffffffffffffffffffffffffff1674ffffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002160040154600160003374ffffffffffffffffffffffffffffffffffffffffff1674ffffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002160050154610a7d565b905060158110156102f0573374ffffffffffffffffffffffffffffffffffffffffff167fb3367811e6ddbe6c4c60575fd49aa0357bb5823809dbed0406bf81c8adbb267f600160003374ffffffffffffffffffffffffffffffffffffffffff1674ffffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002160040154600160003374ffffffffffffffffffffffffffffffffffffffffff1674ffffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002160060154600080604051808581526020018481526020018360ff16815260200182815260200194505050505060405180910390a2505050610323565b60158111156102fe57600292505b5050610317565b600e8260ff16141561031657600490505b5b6103213382610aec565b505b50565b60003411801561033f5750683635c9adc5dea000003411155b151561034a57600080fd5b34600160003374ffffffffffffffffffffffffffffffffffffffffff1674ffffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000216001018190555060018060003374ffffffffffffffffffffffffffffffffffffffffff1674ffffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002160020160006101000a81548160ff0219169083151502179055506000600160003374ffffffffffffffffffffffffffffffffffffffffff1674ffffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000216003018190555046600160003374ffffffffffffffffffffffffffffffffffffffffff1674ffffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002160000160006101000a81548169ffffffffffffffffffff021916908369ffffffffffffffffffff1602179055506000600160003374ffffffffffffffffffffffffffffffffffffffffff1674ffffffffffffffffffffffffffffffffffffffffff168152602001908152602001600021600401819055506000600160003374ffffffffffffffffffffffffffffffffffffffffff1674ffffffffffffffffffffffffffffffffffffffffff168152602001908152602001600021600501819055506000600160003374ffffffffffffffffffffffffffffffffffffffffff1674ffffffffffffffffffffffffffffffffffffffffff168152602001908152602001600021600601819055506000600160003374ffffffffffffffffffffffffffffffffffffffffff1674ffffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000216007018190555060006105dd33600161083f565b905060006105ec33600161083f565b905060006105fb33600061083f565b90506000610691600160003374ffffffffffffffffffffffffffffffffffffffffff1674ffffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002160040154600160003374ffffffffffffffffffffffffffffffffffffffffff1674ffffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002160050154610a7d565b905060158114156106ac576106a7336000610aec565b6107a0565b3374ffffffffffffffffffffffffffffffffffffffffff167fb3367811e6ddbe6c4c60575fd49aa0357bb5823809dbed0406bf81c8adbb267f600160003374ffffffffffffffffffffffffffffffffffffffffff1674ffffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002160040154600160003374ffffffffffffffffffffffffffffffffffffffffff1674ffffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002160060154600080604051808581526020018481526020018360ff16815260200182815260200194505050505060405180910390a25b50505050565b3374ffffffffffffffffffffffffffffffffffffffffff166000809054906101000a900474ffffffffffffffffffffffffffffffffffffffffff1674ffffffffffffffffffffffffffffffffffffffffff1614151561080457600080fd5b3374ffffffffffffffffffffffffffffffffffffffffff164669ffffffffffffffffffff168260405160405180820390838587f15050505050565b6000806000610891600160008774ffffffffffffffffffffffffffffffffffffffffff1674ffffffffffffffffffffffffffffffffffffffffff168152602001908152602001600021600301546110d1565b600160008874ffffffffffffffffffffffffffffffffffffffffff1674ffffffffffffffffffffffffffffffffffffffffff168152602001908152602001600021600301600082955083919050555050819050600d828115156108f057fe5b069150600060098310151561090857600a905061090f565b6001830190505b84156109c5578160019060020a02600160008874ffffffffffffffffffffffffffffffffffffffffff1674ffffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000216004016000828254179250508190555080600160008874ffffffffffffffffffffffffffffffffffffffffff1674ffffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002160050160008282540192505081905550610a71565b8160019060020a02600160008874ffffffffffffffffffffffffffffffffffffffffff1674ffffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000216006016000828254179250508190555080600160008874ffffffffffffffffffffffffffffffffffffffffff1674ffffffffffffffffffffffffffffffffffffffffff168152602001908152602001600021600701600082825401925050819055505b81935050505092915050565b600080600060018516141580610a9857506000612000851614155b80610aaa575060006304000000851614155b80610abd57506000648000000000851614155b9050808015610ad057506015600a840111155b15610ae157600a8301915050610ae6565b829150505b92915050565b6000808260ff161415610de2576000610b8d600160008674ffffffffffffffffffffffffffffffffffffffffff1674ffffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002160060154600160008774ffffffffffffffffffffffffffffffffffffffffff1674ffffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002160070154610a7d565b90505b6011811015610c3e57610ba484600061083f565b50610c37600160008674ffffffffffffffffffffffffffffffffffffffffff1674ffffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002160060154600160008774ffffffffffffffffffffffffffffffffffffffffff1674ffffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002160070154610a7d565b9050610b90565b6000610cd2600160008774ffffffffffffffffffffffffffffffffffffffffff1674ffffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002160040154600160008874ffffffffffffffffffffffffffffffffffffffffff1674ffffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002160050154610a7d565b90506015811115610ce65760029350610d1f565b6015821115610cf85760019350610d1e565b81811415610d095760039350610d1d565b818111610d17576002610d1a565b60015b93505b5b5b60018460ff161415610d8657600a6013600160008874ffffffffffffffffffffffffffffffffffffffffff1674ffffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000216001015402811515610d7e57fe5b049250610ddb565b60038460ff161415610dda57600160008674ffffffffffffffffffffffffffffffffffffffffff1674ffffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000216001015492505b5b5050610e43565b60048260ff161415610e42576002600160003374ffffffffffffffffffffffffffffffffffffffffff1674ffffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002160010154811515610e3e57fe5b0490505b5b6000600160008574ffffffffffffffffffffffffffffffffffffffffff1674ffffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002160020160006101000a81548160ff0219169083151502179055506000811115610f3c578274ffffffffffffffffffffffffffffffffffffffffff16600160008574ffffffffffffffffffffffffffffffffffffffffff1674ffffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002160000160009054906101000a900469ffffffffffffffffffff1669ffffffffffffffffffff168260405160405180820390838587f1505050505b6000693ccb0fe9845a720b650390508374ffffffffffffffffffffffffffffffffffffffffff168169ffffffffffffffffffff1660646005600160003374ffffffffffffffffffffffffffffffffffffffffff1674ffffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000216001015402811515610fc357fe5b0460405160405180820390838587f1505050508374ffffffffffffffffffffffffffffffffffffffffff167fb3367811e6ddbe6c4c60575fd49aa0357bb5823809dbed0406bf81c8adbb267f600160008774ffffffffffffffffffffffffffffffffffffffffff1674ffffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002160040154600160008874ffffffffffffffffffffffffffffffffffffffffff1674ffffffffffffffffffffffffffffffffffffffffff168152602001908152602001600021600601548686604051808581526020018481526020018360ff1660ff16815260200182815260200194505050505060405180910390a250505050565b60008060004a905060348167ffffffffffffffff168115156110ef57fe5b069050600080905060008090505b60348160ff1610156111765760348160ff16840167ffffffffffffffff1681151561112457fe5b06925060008367ffffffffffffffff1660019060020a0267ffffffffffffffff1690506000818816141561116a578367ffffffffffffffff169250808717965050611176565b508060010190506110fd565b50848193509350505091509156fea165627a7a723058200a472473b40c6198d4a49f680deca835ee5b77f16a62eae5944b6ad32b6e690e0029"],"offchainCodesList":["608060405260043610600f57600f565b00fea165627a7a72305820a2598ba3d6edda466f22e78381d3aa29bc40d52219f5b337b4baadf8c0a7536a0029","608060405260043610600f57600f565b00fea165627a7a723058200a472473b40c6198d4a49f680deca835ee5b77f16a62eae5944b6ad32b6e690e0029"],"abiList":[[{"constant":false,"inputs":[{"name":"addr","type":"address"}],"name":"SayHello","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"anonymous":false,"inputs":[{"indexed":true,"name":"addr","type":"address"},{"indexed":false,"name":"amount","type":"uint256"}],"name":"transfer","type":"event"}],[{"constant":false,"inputs":[{"name":"action","type":"uint8"}],"name":"gameAction","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"startGame","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":false,"inputs":[{"name":"amount","type":"uint256"}],"name":"DrawMoney","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"inputs":[],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"payable":true,"stateMutability":"payable","type":"fallback"},{"anonymous":false,"inputs":[{"indexed":true,"name":"addr","type":"address"},{"indexed":false,"name":"playerCards","type":"uint256"},{"indexed":false,"name":"npcCards","type":"uint256"},{"indexed":false,"name":"result","type":"uint8"},{"indexed":false,"name":"reward","type":"uint256"}],"name":"blackjack","type":"event"}]],"contractNameList":["HelloWorld","ViteBet"]} -------------------------------------------------------------------------------- /examples/.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.2.0", 3 | "configurations": [ 4 | { 5 | "type": "soliditypp", 6 | "request": "launch", 7 | "name": "Soliditypp Debug", 8 | "program": "" 9 | } 10 | ] 11 | } 12 | -------------------------------------------------------------------------------- /examples/HelloWorld.solpp: -------------------------------------------------------------------------------- 1 | pragma soliditypp ^0.4.2; 2 | contract HelloWorld { 3 | event transfer(address indexed addr,uint256 amount); 4 | onMessage SayHello(address addr) payable { 5 | addr.transfer(msg.tokenid ,msg.amount); 6 | emit transfer(addr, msg.amount); 7 | } 8 | } -------------------------------------------------------------------------------- /examples/h2.solpp: -------------------------------------------------------------------------------- 1 | pragma soliditypp >0.7.0; 2 | 3 | contract HelloWorld { 4 | event transfer(address indexed addr,uint256 amount); 5 | onMessage SayHello(address addr) payable { 6 | addr.transfer(msg.tokenid ,msg.amount); 7 | emit transfer(addr, msg.amount); 8 | } 9 | } -------------------------------------------------------------------------------- /examples/luck9.solpp: -------------------------------------------------------------------------------- 1 | // Source from: https://forum.vite.net/topic/1975/lucky-9-application 2 | 3 | pragma soliditypp ^0.4.2; 4 | contract ViteBet{ 5 | address owner; 6 | 7 | struct BetLimit { 8 | uint256 lowerLimit; 9 | uint256 upperLimit; 10 | uint256 tipPer; 11 | } 12 | 13 | tokenId[] tokens = ["tti_5649544520544f4b454e6e40"]; 14 | mapping(tokenId => BetLimit) public tokenMap; 15 | 16 | event cardnums(address indexed addr, uint256 betAmount, uint256 customerCard1, uint256 customerCard2, uint256 myCard1, uint256 myCard2); 17 | event win(address indexed addr, uint256 betAmount, uint256 customerCard1, uint256 customerCard2, uint256 myCard1, uint256 myCard2, uint256 winAmount); 18 | event lose(address indexed addr, uint256 betAmount, uint256 customerCard1, uint256 customerCard2, uint256 myCard1, uint256 myCard2); 19 | event draw(address indexed addr, uint256 betAmount, uint256 customerCard1, uint256 customerCard2, uint256 myCard1, uint256 myCard2); 20 | event suspendBet(address indexed addr, uint256 betAmount, uint256 customerCard1, uint256 customerCard2, uint256 myCard1, uint256 myCard2, uint256 winAmount); 21 | 22 | constructor() public { 23 | owner = msg.sender; 24 | tokenMap["tti_5649544520544f4b454e6e40"].lowerLimit = 1 vite; 25 | tokenMap["tti_5649544520544f4b454e6e40"].upperLimit = 1000 vite; 26 | tokenMap["tti_5649544520544f4b454e6e40"].tipPer = 10; 27 | } 28 | 29 | onMessage () payable { 30 | } 31 | 32 | // Configure the upper and lower limits of the token bet 33 | // Configure the draw ratio (0 to 20) 34 | onMessage configBetLimit(uint256 ll, uint256 ul, uint256 tp) { 35 | require(owner == msg.sender); 36 | require(ll > 0 && ll <= ul); 37 | require(tp >= 0 && tp <= 20); 38 | if (tokenMap[msg.tokenid].lowerLimit == 0){ 39 | tokens.push(msg.tokenid); 40 | } 41 | tokenMap[msg.tokenid].lowerLimit = ll; 42 | tokenMap[msg.tokenid].upperLimit = ul; 43 | tokenMap[msg.tokenid].tipPer = tp; 44 | } 45 | 46 | onMessage DrawMoney(uint256 amount) { 47 | require(owner == msg.sender); 48 | require(amount <= balance(msg.tokenid)); 49 | msg.sender.transfer(msg.tokenid, amount); 50 | } 51 | 52 | // Get the upper and lower limits of the token and the rate 53 | getter getBetLimit(tokenId token) returns(uint256 ll, uint256 ul, uint256 tipPer) { 54 | return (tokenMap[token].lowerLimit, tokenMap[token].upperLimit, tokenMap[token].tipPer); 55 | } 56 | 57 | // Get the token list 58 | getter getTokenList() returns(tokenId[] memory) { 59 | return tokens; 60 | } 61 | 62 | onMessage BetAndRoll() payable { 63 | uint256 betAmount = msg.amount; 64 | address betAddr = msg.sender; 65 | uint256 ll = tokenMap[msg.tokenid].lowerLimit; 66 | uint256 ul = tokenMap[msg.tokenid].upperLimit; 67 | require(ll > 0 && ll <= ul); 68 | require(betAmount >= ll && betAmount <= ul); 69 | 70 | uint256[4] memory cards = getCardsSum(); 71 | uint256 customerCardSum = (cards[0] + cards[1]) % 10; 72 | uint256 myCardSum = (cards[2] + cards[3]) % 10; 73 | 74 | emit cardnums(betAddr, betAmount, cards[0], cards[1], cards[2], cards[3]); 75 | 76 | if (customerCardSum > myCardSum) { // customer win 77 | uint256 winAmount = calcWinAmount(betAmount, msg.tokenid); 78 | if (winAmount > balance(msg.tokenid)) { // money is not enough 79 | betAddr.transfer(msg.tokenid, betAmount); // return back betAmount 80 | emit suspendBet(betAddr, betAmount, cards[0], cards[1], cards[2], cards[3], winAmount); 81 | } else { 82 | betAddr.transfer(msg.tokenid, winAmount); 83 | emit win(betAddr, betAmount, cards[0], cards[1], cards[2], cards[3], winAmount); 84 | } 85 | } else if (customerCardSum == myCardSum) { // draw 86 | betAddr.transfer(msg.tokenid, betAmount); // return back betAmount 87 | emit draw(betAddr, betAmount, cards[0], cards[1], cards[2], cards[3]); 88 | } else { // customer lose 89 | emit lose(betAddr, betAmount, cards[0], cards[1], cards[2], cards[3]); 90 | } 91 | } 92 | 93 | function getCardsSum() public returns(uint256[4] memory) { 94 | uint64 seed = random64(); 95 | uint256[4] memory cards = [uint256(0), uint256(0), uint256(0), uint256(0)]; 96 | for (uint i = 0; i < 4; i++) { 97 | uint16 card = uint16(seed >> i * 16); 98 | card = card % 13 + 1; 99 | if (card >= 10) { 100 | card = 0; 101 | } 102 | cards[i] = uint256(card); 103 | } 104 | return cards; 105 | } 106 | 107 | function calcWinAmount(uint256 betAmount, tokenId token) public view returns(uint256) { 108 | uint256 bonus = betAmount; 109 | return betAmount + bonus * (100 - tokenMap[token].tipPer) / 100; 110 | } 111 | } -------------------------------------------------------------------------------- /examples/test.solpp: -------------------------------------------------------------------------------- 1 | pragma soliditypp ^0.4.3; 2 | contract HelloWorld { 3 | address owner; 4 | 5 | event transfer(address indexed addr,uint256 amount); 6 | 7 | 8 | onMessage SayHello(address addr) payable { 9 | addr.transfer(msg.tokenid ,msg.amount); 10 | emit transfer(addr, msg.amount); 11 | } 12 | 13 | constructor() public { 14 | owner = msg.sender; 15 | } 16 | 17 | getter getOwner() returns(address) { 18 | return owner; 19 | } 20 | } -------------------------------------------------------------------------------- /images/vscode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vitelabs/soliditypp-vscode/c77df4f9eac10877f331ea96e73edbb0937935d2/images/vscode.png -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "soliditypp", 3 | "displayName": "Solidityppcc", 4 | "description": "Soliditypp extension for Visual Studio Code", 5 | "version": "0.7.11", 6 | "publisher": "ViteLabs", 7 | "icon": "images/vscode.png", 8 | "repository": { 9 | "type": "git", 10 | "url": "https://github.com/vitelabs/soliditypp-vscode.git" 11 | }, 12 | "engines": { 13 | "vscode": "^1.30.0" 14 | }, 15 | "categories": [ 16 | "Debuggers", 17 | "Programming Languages" 18 | ], 19 | "license": "MIT", 20 | "keywords": [ 21 | "soliditypp", 22 | "vite", 23 | "ViteLabs", 24 | "Smart contract" 25 | ], 26 | "activationEvents": [ 27 | "onLanguage:soliditypp", 28 | "onDebug", 29 | "onCommand:soliditypp.generateHelloWorld" 30 | ], 31 | "main": "./out/extension.js", 32 | "contributes": { 33 | "languages": [ 34 | { 35 | "id": "soliditypp", 36 | "extensions": [ 37 | ".solpp" 38 | ], 39 | "aliases": [ 40 | "Soliditypp", 41 | "soliditypp" 42 | ], 43 | "configuration": "./soliditypp-configuration.json" 44 | } 45 | ], 46 | "debuggers": [ 47 | { 48 | "type": "soliditypp", 49 | "label": "Soliditypp", 50 | "configurationAttributes": { 51 | "required": [ 52 | "program" 53 | ], 54 | "properties": { 55 | "program": { 56 | "type": "string", 57 | "description": "Path to a soliditypp file.", 58 | "default": "${file}" 59 | } 60 | } 61 | }, 62 | "initialConfigurations": [ 63 | { 64 | "type": "soliditypp", 65 | "request": "launch", 66 | "name": "Soliditypp Debug", 67 | "program": "${file}" 68 | } 69 | ], 70 | "configurationSnippets": [ 71 | { 72 | "label": "Soliditypp Debug: Launch", 73 | "description": "A new configuration for 'debugging' a user selected soliditypp project.", 74 | "body": { 75 | "type": "soliditypp", 76 | "request": "launch", 77 | "name": "Soliditypp Debug", 78 | "program": "${file}" 79 | } 80 | } 81 | ] 82 | } 83 | ], 84 | "grammars": [ 85 | { 86 | "language": "soliditypp", 87 | "scopeName": "source.soliditypp", 88 | "path": "./syntax/soliditypp.json" 89 | } 90 | ], 91 | "commands": [ 92 | { 93 | "command": "soliditypp.generateHelloWorld", 94 | "title": "soliditypp: Generate HelloWorld.solpp" 95 | } 96 | ] 97 | }, 98 | "scripts": { 99 | "vscode:prepublish": "npm run compile", 100 | "compile": "npm run lint && webpack && npm run view:build:prod", 101 | "watch": "tsc -w -p ./ & npm run view:build:watch", 102 | "test": "npm run compile && node ./src/test/runTest", 103 | "view:clean": "rm -rf out_view", 104 | "lint": "eslint --ext .js,.vue ./", 105 | "dev": "tsc -w -p ./ & NODE_ENV=dev webpack serve --port 3001 --config view/webpackConfig/base.config.js", 106 | "view:build:windows": "webpack --watch --config view/webpackConfig/base.config.js", 107 | "view:build:watch": "npm run view:clean && NODE_ENV=dev webpack --watch --config view/webpackConfig/base.config.js && rm out_view/index.js", 108 | "view:build:dev": "npm run view:clean && NODE_ENV=dev webpack --config view/webpackConfig/base.config.js && rm out_view/index.js", 109 | "view:build:prod": "npm run view:clean && NODE_ENV=prod webpack --config view/webpackConfig/base.config.js" 110 | }, 111 | "devDependencies": { 112 | "@babel/core": "^7.3.3", 113 | "@babel/plugin-proposal-class-properties": "^7.3.3", 114 | "@babel/preset-env": "^7.3.1", 115 | "@types/decompress": "^4.2.3", 116 | "@types/fs-extra": "^9.0.13", 117 | "@types/mocha": "^9.0.0", 118 | "@types/node": "^8.10.40", 119 | "@types/shelljs": "^0.8.3", 120 | "@types/vscode": "^1.30.0", 121 | "babel-eslint": "^10.0.1", 122 | "babel-loader": "^8.0.5", 123 | "babel-plugin-component": "^1.1.1", 124 | "clean-webpack-plugin": "^3.0.0", 125 | "css-loader": "^2.1.0", 126 | "element-theme": "^2.0.1", 127 | "element-theme-chalk": "^2.9.1", 128 | "eslint": "^5.16.0", 129 | "eslint-plugin-vue": "^5.2.2", 130 | "golb": "^0.0.9", 131 | "html-webpack-inline-source-plugin": "0.0.10", 132 | "html-webpack-plugin": "^3.2.0", 133 | "mocha": "^9.1.3", 134 | "node-sass": "^4.14.1", 135 | "sass-loader": "^7.1.0", 136 | "style-loader": "^0.23.1", 137 | "ts-loader": "^6.0.4", 138 | "tslint": "^5.8.0", 139 | "typescript": "^3.9.10", 140 | "uglifyjs-webpack-plugin": "^2.2.0", 141 | "url-loader": "^1.1.2", 142 | "vue-loader": "^15.6.3", 143 | "vue-template-compiler": "^2.6.6", 144 | "webpack": "^4.44.2", 145 | "webpack-cli": "^4.1.0", 146 | "webpack-dev-server": "^3.11.0" 147 | }, 148 | "dependencies": { 149 | "@types/express": "^4.17.8", 150 | "@types/opn": "^5.5.0", 151 | "@types/request": "^2.48.1", 152 | "@vite/connector": "0.0.2", 153 | "@vite/vitejs": "^2.3.16", 154 | "@vite/vitejs-ws": "^2.3.3", 155 | "@vscode/test-electron": "^1.6.2", 156 | "babel-polyfill": "^6.26.0", 157 | "bignumber.js": "^9.0.0", 158 | "clipboard": "^2.0.4", 159 | "dayjs": "^1.8.14", 160 | "decompress": "^4.2.1", 161 | "decompress-targz": "^4.1.1", 162 | "element-ui": "^2.10.1", 163 | "events": "^3.0.0", 164 | "express": "^4.17.1", 165 | "fs-extra": "^10.0.0", 166 | "get-port": "^5.1.1", 167 | "install": "^0.13.0", 168 | "is-root": "^2.1.0", 169 | "jsonrpc-lite": "^2.0.7", 170 | "npm": "^6.14.8", 171 | "opn": "^6.0.0", 172 | "qrcode": "^1.4.4", 173 | "request": "^2.88.0", 174 | "rollup": "^1.16.7", 175 | "ts-node": "^8.1.0", 176 | "vscode-debugadapter": "^1.33.0", 177 | "vue": "^2.6.6", 178 | "vue-i18n": "^8.11.2", 179 | "vue-json-pretty": "^1.8.0", 180 | "vue-router": "^3.4.8", 181 | "vue-split-panel": "^1.0.4", 182 | "vuex": "^3.1.1" 183 | } 184 | } 185 | -------------------------------------------------------------------------------- /soliditypp-configuration.json: -------------------------------------------------------------------------------- 1 | { 2 | "comments": { 3 | "lineComment": "//", 4 | "blockComment": [ "/*", "*/" ] 5 | }, 6 | "brackets": [ 7 | ["{", "}"], 8 | ["[", "]"], 9 | ["(", ")"] 10 | ], 11 | "autoClosingPairs": [ 12 | { "open": "{", "close": "}" }, 13 | { "open": "[", "close": "]" }, 14 | { "open": "(", "close": ")" }, 15 | { "open": "/**", "close": " */", "notIn": ["string"] }, 16 | { "open": "\"", "close": "\"", "notIn": ["string"] } 17 | ], 18 | "surroundingPairs": [ 19 | ["{", "}"], 20 | ["[", "]"], 21 | ["(", ")"], 22 | ["\"", "\""] 23 | ], 24 | "properties": { 25 | "solpp.serverPort": { 26 | "type": "number", 27 | "default": 8081, 28 | "description": "This is the port that Simple HTTP Server will be running on." 29 | }, 30 | "solpp.serverHost": { 31 | "type": "string", 32 | "default": "127.0.0.1", 33 | "description": "This is the host that Simple HTTP Server will be running on." 34 | } 35 | } 36 | } -------------------------------------------------------------------------------- /src/constant.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from 'vscode'; 2 | import * as process from 'process'; 3 | import * as os from 'os'; 4 | import * as path from 'path'; 5 | 6 | export const extensionId = 'ViteLabs.soliditypp'; 7 | 8 | let _extensionPath = ''; 9 | let extension = vscode.extensions.getExtension(extensionId); 10 | if (extension) { 11 | _extensionPath = extension.extensionPath; 12 | } 13 | export const extensionPath = _extensionPath; 14 | 15 | export const debuggerType = 'soliditypp'; 16 | export const languageId = 'soliditypp'; 17 | export const BIN_DIR = path.resolve(extensionPath, 'bin/'); 18 | export const VITE_DIR = path.resolve(BIN_DIR, 'vite/'); 19 | export const SOLPPC_DIR = path.resolve(BIN_DIR, 'solppc/'); 20 | export const PLATFORM_ERROR = 'don\'t support win32'; 21 | export const GVITE_VERSION = 'v2.11.0'; 22 | export const SOLPPC_VERSION = 'v0.4.3'; 23 | 24 | export enum OS_PLATFORM { 25 | WIN32 = 1, 26 | WIN64 = 2, 27 | DARWIN = 3, 28 | LINUX = 4 29 | } 30 | 31 | export const EXEC_SUFFIX = inWindows() ? 'bat' : 'sh'; 32 | 33 | export function getOsPlatform(): OS_PLATFORM { 34 | let platform = process.platform; 35 | let arch = os.arch(); 36 | if (platform === 'darwin') { 37 | return OS_PLATFORM.DARWIN; 38 | } else if (platform === 'win32') { 39 | if (arch === 'ia32') { 40 | return OS_PLATFORM.WIN32; 41 | } else if (arch === 'x64') { 42 | return OS_PLATFORM.WIN64; 43 | } 44 | } 45 | return OS_PLATFORM.LINUX; 46 | } 47 | export function getGviteName(): string { 48 | let osPlatform = getOsPlatform(); 49 | 50 | if (osPlatform === OS_PLATFORM.WIN32 || osPlatform === OS_PLATFORM.WIN64) { 51 | return 'gvite.exe'; 52 | } else { 53 | return 'gvite'; 54 | } 55 | } 56 | 57 | function getSolppcName(): string { 58 | let osPlatform = getOsPlatform(); 59 | 60 | if (osPlatform === OS_PLATFORM.WIN32 || osPlatform === OS_PLATFORM.WIN64) { 61 | return 'solppc.exe'; 62 | } else { 63 | return 'solppc'; 64 | } 65 | } 66 | 67 | export function getSolppcPath(): string { 68 | return path.resolve(SOLPPC_DIR, getSolppcName()); 69 | } 70 | 71 | export function inWindows(): boolean { 72 | let osPlatform = getOsPlatform(); 73 | return osPlatform === OS_PLATFORM.WIN32 || osPlatform === OS_PLATFORM.WIN64; 74 | } 75 | -------------------------------------------------------------------------------- /src/createGvite.ts: -------------------------------------------------------------------------------- 1 | import * as path from "path"; 2 | import { 3 | VITE_DIR, 4 | getOsPlatform, 5 | getGviteName, 6 | OS_PLATFORM, 7 | PLATFORM_ERROR, 8 | GVITE_VERSION 9 | } from "./constant"; 10 | import * as fs from "fs"; 11 | import uri from "./uri"; 12 | import * as request from "request"; 13 | import * as decompress from "decompress"; 14 | import SolidityppDebugSession from "./debugSession"; 15 | import { OutputEvent } from "vscode-debugadapter"; 16 | 17 | // const decompressUnzip = require( 'decompress-unzip'); 18 | const child_process = require("child_process"); 19 | const decompressTargz = require("decompress-targz"); 20 | 21 | function getOrigGviteName(): string { 22 | let osPlatform = getOsPlatform(); 23 | switch (osPlatform) { 24 | case OS_PLATFORM.WIN32: 25 | throw PLATFORM_ERROR; 26 | case OS_PLATFORM.WIN64: 27 | return "gvite-windows-amd64.exe"; 28 | default: 29 | return "gvite"; 30 | } 31 | } 32 | 33 | function getGvitePath(): string { 34 | return path.resolve(VITE_DIR, getGviteName()); 35 | } 36 | 37 | function getGviteCompressedPath(): string { 38 | let osPlatform = getOsPlatform(); 39 | let compressedFilePath = ""; 40 | switch (osPlatform) { 41 | case OS_PLATFORM.DARWIN: { 42 | compressedFilePath = path.resolve(VITE_DIR, "gvite-darwin.tar.gz"); 43 | break; 44 | } 45 | case OS_PLATFORM.LINUX: { 46 | compressedFilePath = path.resolve(VITE_DIR, "gvite-linux.tar.gz"); 47 | break; 48 | } 49 | case OS_PLATFORM.WIN64: { 50 | compressedFilePath = path.resolve(VITE_DIR, "gvite-win64.tar.gz"); 51 | break; 52 | } 53 | case OS_PLATFORM.WIN32: { 54 | throw PLATFORM_ERROR; 55 | } 56 | } 57 | return compressedFilePath; 58 | } 59 | 60 | function checkGviteIsExisted(): boolean { 61 | return fs.existsSync(getGvitePath()); 62 | } 63 | function checkGviteVersion(ds: SolidityppDebugSession): boolean { 64 | let result; 65 | try { 66 | result = String(child_process.execSync(`${getGvitePath()} -v`)); 67 | } catch (err) { 68 | ds.sendEvent( 69 | new OutputEvent( 70 | `An error occurred when check the version of gvite, Error: ${err.toString()}` 71 | ) 72 | ); 73 | return false; 74 | } 75 | 76 | let version = result.slice(result.lastIndexOf("v")).replace(/\n/g, ""); 77 | if (version !== GVITE_VERSION) { 78 | ds.sendEvent( 79 | new OutputEvent( 80 | `Current version is ${version}, required version is ${GVITE_VERSION}` 81 | ) 82 | ); 83 | return false; 84 | } 85 | 86 | return true; 87 | } 88 | 89 | function checkCompressedGviteIsExisted() :boolean{ 90 | return fs.existsSync(getGviteCompressedPath()); 91 | } 92 | 93 | async function downloadGvite(ds: SolidityppDebugSession) { 94 | let osPlatform = getOsPlatform(); 95 | let downloadUri = ""; 96 | 97 | switch (osPlatform) { 98 | case OS_PLATFORM.DARWIN: { 99 | downloadUri = uri.createGviteDownload(GVITE_VERSION, "darwin"); 100 | break; 101 | } 102 | case OS_PLATFORM.LINUX: { 103 | downloadUri = uri.createGviteDownload(GVITE_VERSION, "linux"); 104 | break; 105 | } 106 | case OS_PLATFORM.WIN64: { 107 | downloadUri = uri.createGviteDownload(GVITE_VERSION, "windows"); 108 | break; 109 | } 110 | case OS_PLATFORM.WIN32: { 111 | throw PLATFORM_ERROR; 112 | } 113 | } 114 | 115 | // download 116 | await new Promise(function(resolve, reject) { 117 | let runTask = () => { 118 | ds.sendEvent( 119 | new OutputEvent(`Prepare download vite from ${downloadUri}\n`, "stdout") 120 | ); 121 | 122 | let requestStrem = request.get(downloadUri, { 123 | timeout: 15000 124 | }); 125 | 126 | let fsStream = fs.createWriteStream(getGviteCompressedPath()); 127 | 128 | let downloadedSize = 0; 129 | let totalSize = 0; 130 | requestStrem 131 | .on("error", function(err: any) { 132 | if (err.code === "ETIMEDOUT" || err.code === "ESOCKETTIMEDOUT") { 133 | ds.sendEvent( 134 | new OutputEvent(`Download vite timeout, retrying\n`, "stdout") 135 | ); 136 | runTask(); 137 | return; 138 | } 139 | reject(err); 140 | }) 141 | .on("response", function(response) { 142 | if (response.statusCode != 200) { 143 | return reject(response); 144 | } 145 | 146 | totalSize = Number(response.headers["content-length"]); 147 | }) 148 | .on("data", function(d) { 149 | downloadedSize += d.length; 150 | ds.sendEvent( 151 | new OutputEvent( 152 | `Downloading vite: ${((downloadedSize / totalSize) * 100).toFixed( 153 | 2 154 | )}%\n`, 155 | "stdout" 156 | ) 157 | ); 158 | }) 159 | .pipe(fsStream); 160 | 161 | fsStream.on("finish", function() { 162 | ds.sendEvent(new OutputEvent("Vite downloaded complete\n", "stdout")); 163 | resolve(); 164 | }); 165 | }; 166 | runTask(); 167 | }); 168 | } 169 | 170 | async function uncompressGvite() { 171 | let files = await decompress(getGviteCompressedPath(), VITE_DIR, { 172 | plugins: [decompressTargz()] 173 | }); 174 | let gviteName = getGviteName(); 175 | let origGviteName = getOrigGviteName(); 176 | let directory = files[0].path; 177 | for (let i = 1; i < files.length; i++) { 178 | let filePath = files[i].path; 179 | let fileName = filePath.replace(directory, ""); 180 | if (fileName === origGviteName) { 181 | fs.renameSync( 182 | path.join(VITE_DIR, filePath), 183 | path.join(VITE_DIR, gviteName) 184 | ); 185 | break; 186 | } 187 | } 188 | 189 | 190 | 191 | } 192 | 193 | export default async function createGvite(ds: SolidityppDebugSession) { 194 | if (checkGviteIsExisted() && checkGviteVersion(ds)) { 195 | return; 196 | } 197 | 198 | if (!checkCompressedGviteIsExisted()) { 199 | } 200 | await downloadGvite(ds); 201 | 202 | await uncompressGvite(); 203 | } 204 | -------------------------------------------------------------------------------- /src/createSolppc.ts: -------------------------------------------------------------------------------- 1 | import * as fs from "fs"; 2 | import { 3 | SOLPPC_DIR, 4 | SOLPPC_VERSION, 5 | getOsPlatform, 6 | getSolppcPath, 7 | OS_PLATFORM, 8 | PLATFORM_ERROR 9 | } from "./constant"; 10 | import uri from "./uri"; 11 | import * as path from "path"; 12 | 13 | import * as request from "request"; 14 | 15 | const decompress = require("decompress"); 16 | const decompressTargz = require("decompress-targz"); 17 | 18 | function getSolppcCompressedPath(): string { 19 | let osPlatform = getOsPlatform(); 20 | let compressedFilePath = ""; 21 | switch (osPlatform) { 22 | case OS_PLATFORM.DARWIN: { 23 | compressedFilePath = path.resolve(SOLPPC_DIR, "solppc_darwin.tar.gz"); 24 | break; 25 | } 26 | case OS_PLATFORM.LINUX: { 27 | compressedFilePath = path.resolve(SOLPPC_DIR, "solppc_linux.tar.gz"); 28 | break; 29 | } 30 | case OS_PLATFORM.WIN64: { 31 | compressedFilePath = path.resolve(SOLPPC_DIR, "solppc_win.tar.gz"); 32 | break; 33 | } 34 | case OS_PLATFORM.WIN32: { 35 | throw PLATFORM_ERROR; 36 | } 37 | } 38 | return compressedFilePath; 39 | } 40 | 41 | async function downloadSolppc( 42 | print: ((s: string, progress: number, downloadUrl: string) => void) | null 43 | ) { 44 | let osPlatform = getOsPlatform(); 45 | let downloadUri = ""; 46 | 47 | switch (osPlatform) { 48 | case OS_PLATFORM.DARWIN: { 49 | downloadUri = uri.createSolppcDownload(SOLPPC_VERSION, "darwin"); 50 | break; 51 | } 52 | case OS_PLATFORM.LINUX: { 53 | // compressedFilePath = path.resolve(VITE_DIR, "gvite-linux.zip"); 54 | downloadUri = uri.createSolppcDownload(SOLPPC_VERSION, "linux"); 55 | break; 56 | } 57 | case OS_PLATFORM.WIN64: { 58 | downloadUri = uri.createSolppcDownload(SOLPPC_VERSION, "win"); 59 | // compressedFilePath = path.resolve(VITE_DIR, "gvite-win64.zip"); 60 | break; 61 | } 62 | case OS_PLATFORM.WIN32: { 63 | throw PLATFORM_ERROR; 64 | // compressedFilePath = path.resolve(VITE_DIR, "gvite-win32.zip"); 65 | } 66 | } 67 | 68 | // download 69 | await new Promise(function(resolve, reject) { 70 | let runTask = () => { 71 | print && 72 | print(`Prepare to download solppc from ${downloadUri}`, 0, downloadUri); 73 | 74 | let requestStrem = request.get(downloadUri, { 75 | timeout: 15000 76 | }); 77 | let fsStream = fs.createWriteStream(getSolppcCompressedPath()); 78 | 79 | let downloadedSize = 0; 80 | let totalSize = 0; 81 | requestStrem 82 | .on("error", function(err: any) { 83 | if (err.code === "ETIMEDOUT" || err.code === "ESOCKETTIMEDOUT") { 84 | print && print(`Download solppc timeout, retrying`, 0, downloadUri); 85 | runTask(); 86 | return; 87 | } 88 | reject(err); 89 | }) 90 | .on("response", function(response: any) { 91 | if (response.statusCode != 200) { 92 | return reject(response); 93 | } 94 | 95 | totalSize = Number(response.headers["content-length"]); 96 | }) 97 | .on("data", function(d: any) { 98 | downloadedSize += d.length; 99 | 100 | print && 101 | print( 102 | "Downloading solppc", 103 | Number(((downloadedSize / totalSize) * 100).toFixed(2)), 104 | downloadUri 105 | ); 106 | }) 107 | .pipe(fsStream); 108 | 109 | fsStream.on("finish", function() { 110 | print && print("Solppc downloaded complete", 100, downloadUri); 111 | 112 | resolve(); 113 | }); 114 | }; 115 | runTask(); 116 | }); 117 | } 118 | 119 | async function uncompressSolppc() { 120 | let files = await decompress(getSolppcCompressedPath(), SOLPPC_DIR, { 121 | plugins: [decompressTargz()] 122 | }); 123 | 124 | if (getOsPlatform() === OS_PLATFORM.WIN64) { 125 | for (let i = 0; i < files.length; i++) { 126 | let file = files[i]; 127 | let basename = path.basename(file.path) 128 | if (file.type !== 'file' || basename.indexOf('.') === 0) { 129 | continue; 130 | } 131 | fs.renameSync(path.join(SOLPPC_DIR, file.path), path.join(SOLPPC_DIR, basename)) 132 | 133 | } 134 | } 135 | } 136 | 137 | function checkSolppcIsExisted(): boolean { 138 | return fs.existsSync(getSolppcPath()); 139 | } 140 | 141 | export function checkSolppcAvailable(): boolean { 142 | return checkSolppcIsExisted(); 143 | } 144 | 145 | export default async function( 146 | print: ((s: string, progress: number, downloadUrl: string) => void) | null 147 | ) { 148 | if (checkSolppcAvailable()) { 149 | return; 150 | } 151 | 152 | await downloadSolppc(print); 153 | 154 | await uncompressSolppc(); 155 | } 156 | -------------------------------------------------------------------------------- /src/debugAdapterDescriptorFactory.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from 'vscode'; 2 | import * as Net from 'net'; 3 | import SolidityppDebugSession from './debugSession' 4 | 5 | export default class SolidityppDebugAdapterDescriptorFactory implements vscode.DebugAdapterDescriptorFactory { 6 | 7 | private server?: Net.Server; 8 | 9 | createDebugAdapterDescriptor(session: vscode.DebugSession, executable: vscode.DebugAdapterExecutable | undefined): vscode.ProviderResult { 10 | 11 | if (!this.server) { 12 | // start listening on a random port 13 | this.server = Net.createServer(socket => { 14 | const session = new SolidityppDebugSession(); 15 | session.setRunAsServer(true); 16 | session.start(socket, socket); 17 | }).listen(0); 18 | } 19 | 20 | // make VS Code connect to debug server 21 | return new vscode.DebugAdapterServer(this.server.address().port); 22 | } 23 | 24 | dispose() { 25 | if (this.server) { 26 | this.server.close(); 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/debugConfigurationProvider.ts: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | import { languageId } from "./constant"; 4 | import * as vscode from "vscode"; 5 | 6 | export default class SolidityConfigurationProvider 7 | implements vscode.DebugConfigurationProvider { 8 | resolveDebugConfiguration( 9 | folder: vscode.WorkspaceFolder | undefined, 10 | config: vscode.DebugConfiguration, 11 | token?: vscode.CancellationToken 12 | ): vscode.ProviderResult { 13 | // if launch.json is missing or empty 14 | if (!config.type) { 15 | config.type = "soliditypp"; 16 | } 17 | if (!config.request) { 18 | config.request = "launch"; 19 | } 20 | if (!config.name) { 21 | config.name = "Soliditypp Debug"; 22 | } 23 | 24 | if (!config.program) { 25 | const editor = vscode.window.activeTextEditor; 26 | if ( 27 | !editor || 28 | !editor.document || 29 | editor.document.languageId !== languageId 30 | ) { 31 | vscode.window.showErrorMessage( 32 | 'Can\'t find soliditypp file! You can set the value of "program" to soliditypp file path in ".vscode/launch.json" , or open and focus on soliditypp file' 33 | ); 34 | return null; 35 | } 36 | config.program = "${file}"; 37 | } 38 | 39 | return config; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/debugSession.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from 'vscode'; 2 | import { OutputEvent, DebugSession } from 'vscode-debugadapter'; 3 | import { DebugProtocol } from 'vscode-debugprotocol'; 4 | import ViewRequestProcessor from './viewRequestProcessor'; 5 | 6 | import { getSolppcPath, VITE_DIR, EXEC_SUFFIX, inWindows } from './constant'; 7 | import { HTTPServer } from './httpServer'; 8 | 9 | import * as os from 'os'; 10 | 11 | import { ChildProcess, spawnSync, exec, execSync } from 'child_process'; 12 | import ExtensionRequestProcessor from './extensionRequestProcessor'; 13 | 14 | import createGvite from './createGvite'; 15 | import createSolppc from './createSolppc'; 16 | import { linesParser } from './utils/linesParser'; 17 | const httpServer = new HTTPServer(); 18 | 19 | interface LaunchRequestArguments extends DebugProtocol.LaunchRequestArguments { 20 | /** An absolute path to the "program" to debug. */ 21 | program: string; 22 | } 23 | 24 | const VIEW_COMMAND_PREFIX = 'view2debugAdapter.'; 25 | const EXTENSION_COMMAND_PREFIX = 'extension2debugAdapter.'; 26 | 27 | export default class SolidityppDebugSession extends DebugSession { 28 | private viewRequestProcessor: ViewRequestProcessor; 29 | private extensionRequestProcessor: ExtensionRequestProcessor; 30 | 31 | // the initial (and one and only) file we are 'debugging' 32 | private _sourceFilePath: string = ''; 33 | public get sourceFilePath() { 34 | return this._sourceFilePath; 35 | } 36 | 37 | private _asmList: string[] = []; 38 | public get asmList() { 39 | return this._asmList; 40 | } 41 | private _offAsmList: string[] = []; 42 | public get offAsmList() { 43 | return this._offAsmList; 44 | } 45 | private _contractNameList: string[] = []; 46 | public get contractNameList() { 47 | return this._contractNameList; 48 | } 49 | 50 | private _bytecodesList: string[] = []; 51 | public get bytecodesList() { 52 | return this._bytecodesList; 53 | } 54 | 55 | private _offchainCodesList: string[] = []; 56 | public get offchainCodesList() { 57 | return this._offchainCodesList; 58 | } 59 | 60 | private _abiList: any[][] = []; 61 | public get abiList() { 62 | return this._abiList; 63 | } 64 | 65 | private _viteChildProcess: ChildProcess | undefined; 66 | 67 | public constructor() { 68 | super(); 69 | this.viewRequestProcessor = new ViewRequestProcessor(this); 70 | this.extensionRequestProcessor = new ExtensionRequestProcessor(this); 71 | return this; 72 | } 73 | 74 | protected async customRequest( 75 | command: string, 76 | response: DebugProtocol.Response, 77 | args: any 78 | ): Promise { 79 | if (command.indexOf(VIEW_COMMAND_PREFIX) === 0) { 80 | let actualCommand = command.replace(VIEW_COMMAND_PREFIX, ''); 81 | this.sendResponse( 82 | await this.viewRequestProcessor.serve( 83 | actualCommand, 84 | response, 85 | args 86 | ) 87 | ); 88 | } else if (command.indexOf(EXTENSION_COMMAND_PREFIX) === 0) { 89 | let actualCommand = command.replace(EXTENSION_COMMAND_PREFIX, ''); 90 | this.sendResponse( 91 | await this.extensionRequestProcessor.serve( 92 | actualCommand, 93 | response, 94 | args 95 | ) 96 | ); 97 | } 98 | } 99 | 100 | protected initializeRequest( 101 | response: DebugProtocol.InitializeResponse, 102 | args: DebugProtocol.InitializeRequestArguments 103 | ): void { 104 | response.body = { 105 | supportsTerminateRequest: true 106 | }; 107 | 108 | this.sendResponse(response); 109 | } 110 | 111 | protected async launchRequest( 112 | response: DebugProtocol.LaunchResponse, 113 | args: LaunchRequestArguments 114 | ) { 115 | try { 116 | await vscode.commands.executeCommand( 117 | 'workbench.debug.panel.action.clearReplAction' 118 | ); 119 | 120 | this.sendEvent(new OutputEvent('Preparing vite...\n', 'stdout')); 121 | 122 | await createGvite(this); 123 | await createSolppc((s, p) => { 124 | this.sendEvent(new OutputEvent(`${s} ${p}% \n`, 'stdout')); 125 | }); 126 | 127 | // set source file path 128 | this._sourceFilePath = args.program; 129 | 130 | if (!(await this.compileSource())) { 131 | return; 132 | } 133 | 134 | this.initVite(); 135 | httpServer.setup({ 136 | bytecodesList: this._bytecodesList, 137 | offchainCodesList: this._offchainCodesList, 138 | abiList: this._abiList, 139 | contractNameList: this._contractNameList, 140 | asmList:this._asmList, 141 | offAsmList:this._offAsmList 142 | }); 143 | this.sendEvent(new OutputEvent('Vite is ready!\n', 'stdout')); 144 | this.sendResponse(response); 145 | } catch (err) { 146 | this.sendEvent(new OutputEvent('Vite is terminated!\n', 'stdout')); 147 | 148 | let msg = err.stack; 149 | if (!msg) { 150 | msg = JSON.stringify(err); 151 | } 152 | this.aborted(msg, 1); 153 | } 154 | } 155 | 156 | private async compileSource(): Promise { 157 | let result; 158 | try { 159 | result = String( 160 | execSync( 161 | `${getSolppcPath()} --bin --abi ${this.sourceFilePath}` 162 | ) 163 | ); 164 | } catch (err) { 165 | this.aborted('Compile failed: \n' + err.toString(), 1); 166 | return false; 167 | } 168 | this.sendEvent({ 169 | event: 'output', 170 | body: { 171 | category: 'std', 172 | output: result 173 | } 174 | }); 175 | 176 | // TODO need compile source 177 | let lines = result.split(os.EOL); 178 | const parseRes = linesParser(lines); 179 | this._contractNameList.push(...(parseRes.name || [])); 180 | this._asmList.push(...(parseRes.asm || [])); 181 | this._offAsmList.push(...(parseRes.offAsm || [])); 182 | this._bytecodesList.push(...(parseRes.bin || [])); 183 | this._offchainCodesList.push(...(parseRes.offBin || [])); 184 | this._abiList.push(...(parseRes.abi || []).map(s => JSON.parse(s))); 185 | 186 | return true; 187 | } 188 | 189 | private initVite() { 190 | this.cleanVite(); 191 | 192 | let execCmd = `startup.${EXEC_SUFFIX}`; 193 | 194 | if (!inWindows()) { 195 | execCmd = `./${execCmd}`; 196 | } 197 | 198 | this._viteChildProcess = exec( 199 | execCmd, 200 | { 201 | cwd: VITE_DIR 202 | }, 203 | () => {} 204 | ); 205 | 206 | this._viteChildProcess.stderr.on('data', stderr => { 207 | // init vite failed 208 | this.aborted( 209 | `An error occurred with gvite , error is ${stderr}`, 210 | 1 211 | ); 212 | }); 213 | 214 | this._viteChildProcess.stdout.on('data', data => { 215 | this.sendEvent(new OutputEvent(`${data}`, 'stdout')); 216 | }); 217 | 218 | this._viteChildProcess.on('close', code => { 219 | // init vite failed 220 | if (code > 0) { 221 | this.sendEvent({ 222 | event: 'output', 223 | body: { 224 | category: 'stderr', 225 | output: `vite exited with code ${code}` 226 | } 227 | }); 228 | } 229 | 230 | this.terminateSession(code); 231 | }); 232 | } 233 | 234 | private cleanVite() { 235 | if (this._viteChildProcess && !this._viteChildProcess.killed) { 236 | if (inWindows()) { 237 | exec('taskkill /pid ' + this._viteChildProcess.pid + ' /T /F'); 238 | } else { 239 | // kill shell 240 | this._viteChildProcess.kill('SIGKILL'); 241 | } 242 | } 243 | 244 | let execCmd = `clean.${EXEC_SUFFIX}`; 245 | 246 | if (!inWindows()) { 247 | execCmd = `./${execCmd}`; 248 | } 249 | 250 | spawnSync(execCmd, [], { 251 | cwd: VITE_DIR, 252 | shell: true 253 | }); 254 | } 255 | 256 | protected terminateRequest( 257 | response: DebugProtocol.TerminateResponse, 258 | args: DebugProtocol.TerminateArguments 259 | ) { 260 | this.terminateSession(); 261 | this.sendResponse(response); 262 | } 263 | 264 | protected disconnectRequest( 265 | response: DebugProtocol.DisconnectResponse, 266 | args: DebugProtocol.DisconnectArguments 267 | ) { 268 | this.cleanVite(); 269 | this.sendResponse(response); 270 | } 271 | 272 | public aborted(errorMsg: string = '', code: number = 0) { 273 | this.sendEvent({ 274 | event: 'output', 275 | body: { 276 | category: 'stderr', 277 | output: errorMsg 278 | } 279 | }); 280 | this.terminateSession(code); 281 | } 282 | 283 | public terminateSession(code: number = 0) { 284 | this.cleanVite(); 285 | 286 | this.sendEvent({ 287 | event: 'terminated' 288 | }); 289 | 290 | this.sendEvent({ 291 | event: 'exited', 292 | body: { 293 | exitCode: code 294 | } 295 | }); 296 | } 297 | } 298 | -------------------------------------------------------------------------------- /src/extension.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from "vscode"; 2 | import * as path from "path"; 3 | 4 | import SolidityConfigurationProvider from "./debugConfigurationProvider"; 5 | import SolidityppDebugAdapterDescriptorFactory from "./debugAdapterDescriptorFactory"; 6 | import { debuggerType } from "./constant"; 7 | import { completeItemList } from "./autoComplete"; 8 | import { extensionPath, getOsPlatform, getSolppcPath, OS_PLATFORM } from "./constant"; 9 | 10 | import createSolppc, { checkSolppcAvailable } from "./createSolppc"; 11 | import * as fs from "fs"; 12 | const child_process = require("child_process"); 13 | 14 | // enum DEBUGGER_STATUS { 15 | // STOPPING = 1, 16 | // STOPPED = 2, 17 | // STARTING = 3, 18 | // STARTED = 4 19 | // } 20 | 21 | let diagnosticCollection: vscode.DiagnosticCollection; 22 | 23 | export async function activate(context: vscode.ExtensionContext) { 24 | // check solppc 25 | await installSolppc(); 26 | 27 | let debuggerPanel: vscode.WebviewPanel | undefined; 28 | // let debuggerStatus: DEBUGGER_STATUS = DEBUGGER_STATUS.STOPPED; 29 | 30 | const provider = new SolidityConfigurationProvider(); 31 | context.subscriptions.push( 32 | vscode.debug.registerDebugConfigurationProvider(debuggerType, provider) 33 | ); 34 | 35 | const factory = new SolidityppDebugAdapterDescriptorFactory(); 36 | context.subscriptions.push( 37 | vscode.debug.registerDebugAdapterDescriptorFactory(debuggerType, factory) 38 | ); 39 | context.subscriptions.push(factory); 40 | 41 | // auto complete 42 | let staticProvider = vscode.languages.registerCompletionItemProvider( 43 | "soliditypp", 44 | { 45 | provideCompletionItems( 46 | ) { 47 | return completeItemList; 48 | } 49 | } 50 | ); 51 | context.subscriptions.push(staticProvider); 52 | 53 | // compile on save 54 | diagnosticCollection = vscode.languages.createDiagnosticCollection( 55 | "soliditypp auto compile" 56 | ); 57 | context.subscriptions.push(diagnosticCollection); 58 | vscode.workspace.onDidSaveTextDocument(compileSource); 59 | 60 | // generate test code 61 | context.subscriptions.push( 62 | vscode.commands.registerCommand("soliditypp.generateHelloWorld", () => { 63 | let workspaceFolders = vscode.workspace.workspaceFolders; 64 | if (workspaceFolders && workspaceFolders.length > 0) { 65 | let newFile = path.join( 66 | workspaceFolders[0].uri.path, 67 | "HelloWorld.solpp" 68 | ); 69 | fs.copyFile( 70 | path.resolve(extensionPath, "bin/vite/HelloWorld.solpp"), 71 | newFile, 72 | function(err) { 73 | if (err) { 74 | console.log(err); 75 | return false; 76 | } 77 | } 78 | ); 79 | let uri = vscode.Uri.file(newFile); 80 | vscode.workspace 81 | .openTextDocument(uri) 82 | .then(doc => vscode.window.showTextDocument(doc)); 83 | } 84 | }) 85 | ); 86 | 87 | 88 | function terminateDebuggerPanel() { 89 | if (debuggerPanel) { 90 | debuggerPanel.dispose(); 91 | debuggerPanel = undefined; 92 | } 93 | } 94 | 95 | vscode.debug.onDidStartDebugSession(function(event) { 96 | if (event.type != debuggerType) { 97 | return; 98 | } 99 | 100 | // debuggerStatus = DEBUGGER_STATUS.STARTING; 101 | 102 | terminateDebuggerPanel(); 103 | 104 | 105 | // debuggerStatus = DEBUGGER_STATUS.STARTED; 106 | }); 107 | 108 | vscode.debug.onDidTerminateDebugSession(function(event) { 109 | if (event.type != debuggerType) { 110 | return; 111 | } 112 | // debuggerStatus = DEBUGGER_STATUS.STOPPING; 113 | 114 | terminateDebuggerPanel(); 115 | // debuggerStatus = DEBUGGER_STATUS.STOPPED; 116 | }); 117 | 118 | console.log('Congratulations, your extension "soliditypp" is now active!'); 119 | } 120 | 121 | export function deactivate() { 122 | console.log('Your extension "soliditypp" is now deactive!'); 123 | } 124 | 125 | 126 | async function compileSource(textDocument: vscode.TextDocument) { 127 | if (textDocument.languageId != "soliditypp") { 128 | return; 129 | } 130 | diagnosticCollection.clear(); 131 | 132 | try { 133 | await child_process.execSync( 134 | `${getSolppcPath()} --bin --abi ${textDocument.fileName}` 135 | ); 136 | } catch (err) { 137 | let errStr = err.output[2].toString(); 138 | 139 | let filename = textDocument.fileName 140 | if (getOsPlatform() === OS_PLATFORM.WIN64) { 141 | filename = filename.replace(/\\/g, '/') 142 | } 143 | 144 | let lines = errStr.split(filename + ":"); 145 | if (lines && lines.length > 1) { 146 | lines = lines[1].split(":"); 147 | if (lines && lines.length > 1) { 148 | let lineNum = +lines[0] - 1; 149 | let columnNum = +lines[1] - 1; 150 | let line = textDocument.lineAt(lineNum); 151 | let diagnostics: vscode.Diagnostic[] = []; 152 | let diagnosic: vscode.Diagnostic = { 153 | severity: vscode.DiagnosticSeverity.Error, 154 | range: new vscode.Range( 155 | lineNum, 156 | columnNum, 157 | lineNum, 158 | line.range.end.character 159 | ), 160 | message: errStr 161 | }; 162 | diagnostics.push(diagnosic); 163 | diagnosticCollection.set(textDocument.uri, diagnostics); 164 | return; 165 | } 166 | } 167 | } 168 | } 169 | 170 | function installSolppc() { 171 | if (checkSolppcAvailable()) { 172 | return; 173 | } 174 | return vscode.window.withProgress( 175 | { 176 | cancellable: false, 177 | location: vscode.ProgressLocation.Notification, 178 | title: "Download solppc" 179 | }, 180 | (progress) => { 181 | return new Promise((resolve) => { 182 | createSolppc(function(s, p) { 183 | if (p >= 100) { 184 | resolve(); 185 | return; 186 | } 187 | progress.report({ 188 | message: `${p}%. ${s}. Solppc is the compiler of soliditypp language.`, 189 | increment: p / 10 190 | }); 191 | }); 192 | }); 193 | } 194 | ); 195 | } 196 | -------------------------------------------------------------------------------- /src/extensionRequestProcessor.ts: -------------------------------------------------------------------------------- 1 | import { DebugProtocol } from 'vscode-debugprotocol'; 2 | import SolidityppDebugSession from './debugSession'; 3 | 4 | 5 | export default class ExtensionRequestProcessor { 6 | debugSession: SolidityppDebugSession 7 | public constructor (debugSession: SolidityppDebugSession) { 8 | this.debugSession = debugSession; 9 | return this 10 | } 11 | 12 | public async serve (command: string, response: DebugProtocol.Response, args: any): Promise { 13 | switch(command) { 14 | case "terminate": { 15 | this.debugSession.terminateSession() 16 | } 17 | } 18 | 19 | return response 20 | } 21 | 22 | public getCompileResult ():any { 23 | return { 24 | bytecodesList: this.debugSession.bytecodesList, 25 | offchainCodesList: this.debugSession.offchainCodesList, 26 | abiList: this.debugSession.abiList 27 | } 28 | 29 | } 30 | 31 | } -------------------------------------------------------------------------------- /src/httpServer.ts: -------------------------------------------------------------------------------- 1 | import * as http from 'http'; 2 | import * as path from 'path'; 3 | 4 | import * as express from 'express'; 5 | const opn = require('opn'); 6 | const getPort = require('get-port'); 7 | 8 | const app = express(); 9 | 10 | export class HTTPServer { 11 | private httpServer: http.Server | undefined; 12 | private contractData: any; 13 | 14 | constructor() { 15 | app.use(express.static(path.join(__dirname, '../out_view'))); 16 | app.use("/contractData", (request: any, response: any) => { 17 | response.json(this.contractData); 18 | }); 19 | } 20 | 21 | public setup(contractData: any): void { 22 | this.contractData = contractData; 23 | this.setupServer(); 24 | } 25 | 26 | private setupServer(): void { 27 | const host: any = '127.0.0.1'; 28 | 29 | getPort({port: getPort.makeRange(9000, 9800)}).then((port: any) => { 30 | if (this.httpServer) 31 | this.httpServer.close(); 32 | 33 | this.httpServer = http.createServer(app); 34 | 35 | 36 | this.httpServer.listen(port, host, () => this.onHTTPServerListening(`${host}:${port}`)); 37 | }); 38 | } 39 | 40 | private onHTTPServerListening(address: string): void { 41 | console.log(address); 42 | address = address === "0.0.0.0" ? "127.0.0.1" : address 43 | 44 | opn("http://" + address + "/#/debug"); 45 | } 46 | 47 | } -------------------------------------------------------------------------------- /src/test/runTest.ts: -------------------------------------------------------------------------------- 1 | import * as path from 'path'; 2 | 3 | import { runTests } from '@vscode/test-electron'; 4 | 5 | async function main() { 6 | try { 7 | // The folder containing the Extension Manifest package.json 8 | // Passed to `--extensionDevelopmentPath` 9 | const extensionDevelopmentPath = path.resolve(__dirname, '../../'); 10 | 11 | // The path to the extension test runner script 12 | // Passed to --extensionTestsPath 13 | const extensionTestsPath = path.resolve(__dirname, './suite/index'); 14 | console.log(88888) 15 | // Download VS Code, unzip it and run the integration test 16 | await runTests({ extensionDevelopmentPath, extensionTestsPath }); 17 | console.log(999999) 18 | } catch (err) { 19 | console.error(err); 20 | console.error('Failed to run tests'); 21 | process.exit(1); 22 | } 23 | } 24 | 25 | main(); -------------------------------------------------------------------------------- /src/test/suite/index.ts: -------------------------------------------------------------------------------- 1 | import * as path from 'path'; 2 | import * as Mocha from 'mocha'; 3 | import * as glob from 'glob'; 4 | 5 | export function run(): Promise { 6 | // Create the mocha test 7 | const mocha = new Mocha({ 8 | ui: 'tdd', 9 | color: true 10 | }); 11 | 12 | const testsRoot = path.resolve(__dirname, '..'); 13 | 14 | return new Promise((c, e) => { 15 | glob('**/**.test.js', { cwd: testsRoot }, (err, files) => { 16 | if (err) { 17 | return e(err); 18 | } 19 | 20 | // Add files to the test suite 21 | files.forEach(f => mocha.addFile(path.resolve(testsRoot, f))); 22 | 23 | try { 24 | // Run the mocha test 25 | mocha.run(failures => { 26 | if (failures > 0) { 27 | e(new Error(`${failures} tests failed.`)); 28 | } else { 29 | c(); 30 | } 31 | }); 32 | } catch (err) { 33 | console.error(err); 34 | e(err); 35 | } 36 | }); 37 | }); 38 | } -------------------------------------------------------------------------------- /src/test/suite/sampleext.test.ts: -------------------------------------------------------------------------------- 1 | import * as assert from 'assert'; 2 | import { after } from 'mocha'; 3 | 4 | // You can import and use all API from the 'vscode' module 5 | // as well as import your extension to test it 6 | import * as vscode from 'vscode'; 7 | // import * as myExtension from '../extension'; 8 | 9 | suite('Extension Test Suite', () => { 10 | after(() => { 11 | vscode.window.showInformationMessage('All tests done!'); 12 | }); 13 | 14 | test('Sample test', () => { 15 | assert.strictEqual(-1, [1, 2, 3].indexOf(5)); 16 | assert.strictEqual(-1, [1, 2, 3].indexOf(0)); 17 | }); 18 | }); 19 | -------------------------------------------------------------------------------- /src/uri.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | createSolppcDownload(version: string, platform: string) { 3 | return `https://github.com/vitelabs/soliditypp-bin/releases/download/${version}/solppc_${platform}.tar.gz`; 4 | }, 5 | createGviteDownload(version: string, platform: string) { 6 | return `https://github.com/vitelabs/go-vite/releases/download/${version}/gvite-${version}-${platform}.tar.gz`; 7 | } 8 | }; 9 | -------------------------------------------------------------------------------- /src/utils/linesParser.ts: -------------------------------------------------------------------------------- 1 | type keyWordsType = 2 | | 'bin' 3 | | 'offBin' 4 | | 'abi' 5 | | 'asm' 6 | | 'offAsm' 7 | | 'stoper' 8 | | 'name'; 9 | const keyWords: { matcher: RegExp; name: keyWordsType }[] = [ 10 | { 11 | matcher: /^Binary:/, 12 | name: 'bin' 13 | }, 14 | { 15 | matcher: /^OffChain Binary:/, 16 | name: 'offBin' 17 | }, 18 | { 19 | matcher: /^Contract JSON ABI/, 20 | name: 'abi' 21 | }, 22 | { 23 | matcher: /^EVM assembly:/, 24 | name: 'asm' 25 | }, 26 | { 27 | matcher: /^Offchain assembly:/, 28 | name: 'offAsm' 29 | }, 30 | { 31 | matcher: /======= .+:(.+) =======/, 32 | name: 'name' 33 | }, 34 | { 35 | matcher: /^=======/, 36 | name: 'stoper' 37 | } 38 | ]; 39 | export function linesParser(lines: string[]) { 40 | const parser: { 41 | pos: number; 42 | curType: null | keyWordsType; 43 | curContent: string; 44 | end: number; 45 | } = { 46 | pos: 0, 47 | curType: null, 48 | curContent: '', 49 | end: lines.length - 1 50 | }; 51 | const result: Partial> = {}; 52 | while (true) { 53 | const line = lines[parser.pos]; 54 | const keyType = keyWords.find(key => key.matcher.test(line)); 55 | /** save token */ 56 | if (keyType || parser.pos > parser.end) { 57 | if (parser.curType) { 58 | result[parser.curType] = result[parser.curType] || []; 59 | result[parser.curType]?.push(parser.curContent); 60 | parser.curContent = ''; 61 | parser.curType = null; 62 | } 63 | } 64 | /**last line */ 65 | if (parser.pos > parser.end) { 66 | break; 67 | } 68 | if (!keyType) { 69 | parser.curContent += line || ''; 70 | parser.pos++; 71 | continue; 72 | } 73 | 74 | if (keyType?.name === 'stoper') { 75 | parser.pos++; 76 | continue; 77 | } 78 | if (keyType?.name === 'name') { 79 | parser.curContent += line.match(keyType.matcher)?.[1] || ''; 80 | parser.curType = 'name'; 81 | parser.pos++; 82 | continue; 83 | } 84 | if (keyType?.name === 'asm' || keyType?.name === 'offAsm') { 85 | parser.curType = keyType?.name; 86 | parser.pos = parser.pos + 2; 87 | continue; 88 | } 89 | parser.curType = keyType?.name; 90 | parser.pos++; 91 | } 92 | return result; 93 | } 94 | -------------------------------------------------------------------------------- /src/viewRequestProcessor.ts: -------------------------------------------------------------------------------- 1 | import { DebugProtocol } from 'vscode-debugprotocol'; 2 | import SolidityppDebugSession from './debugSession'; 3 | 4 | 5 | export default class ViewRequestProcessor { 6 | debugSession: SolidityppDebugSession 7 | public constructor (debugSession: SolidityppDebugSession) { 8 | this.debugSession = debugSession; 9 | return this 10 | } 11 | 12 | public async serve (command: string, response: DebugProtocol.Response, args: any): Promise { 13 | switch(command) { 14 | case "compileResult": { 15 | response.body = this.getCompileResult() 16 | } 17 | } 18 | 19 | return response 20 | } 21 | 22 | public getCompileResult ():any { 23 | return { 24 | bytecodesList: this.debugSession.bytecodesList, 25 | offchainCodesList: this.debugSession.offchainCodesList, 26 | abiList: this.debugSession.abiList, 27 | contractNameList: this.debugSession.contractNameList 28 | } 29 | 30 | } 31 | 32 | } -------------------------------------------------------------------------------- /syntax/soliditypp.json: -------------------------------------------------------------------------------- 1 | { 2 | "fileTypes": [ 3 | "solpp" 4 | ], 5 | "name": "soliditypp", 6 | "patterns": [ 7 | { 8 | "include": "#comment" 9 | }, 10 | { 11 | "include": "#operator" 12 | }, 13 | { 14 | "include": "#control" 15 | }, 16 | { 17 | "include": "#constant" 18 | }, 19 | { 20 | "include": "#number" 21 | }, 22 | { 23 | "include": "#string" 24 | }, 25 | { 26 | "include": "#type" 27 | }, 28 | { 29 | "include": "#global" 30 | }, 31 | { 32 | "include": "#declaration" 33 | }, 34 | { 35 | "include": "#function-call" 36 | }, 37 | { 38 | "include": "#assembly" 39 | }, 40 | { 41 | "include": "#punctuation" 42 | } 43 | ], 44 | "repository": { 45 | "comment": { 46 | "patterns": [ 47 | { 48 | "include": "#comment-line" 49 | }, 50 | { 51 | "include": "#comment-block" 52 | } 53 | ] 54 | }, 55 | "comment-line": { 56 | "match": "(?(?!>)|>=|\\&\\&|\\|\\||\\:(?!=)|\\?)", 85 | "name": "keyword.operator.logic.soliditypp" 86 | }, 87 | "operator-mapping": { 88 | "match": "(=>)", 89 | "name": "keyword.operator.mapping.soliditypp" 90 | }, 91 | "operator-arithmetic": { 92 | "match": "(\\+|\\-|\\/|\\*)", 93 | "name": "keyword.operator.arithmetic.soliditypp" 94 | }, 95 | "operator-binary": { 96 | "match": "(\\^|\\&|\\||<<|>>)", 97 | "name": "keyword.operator.binary.soliditypp" 98 | }, 99 | "operator-assignment": { 100 | "match": "(\\:?=)", 101 | "name": "keyword.operator.assignment.soliditypp" 102 | }, 103 | "control": { 104 | "patterns": [ 105 | { 106 | "include": "#control-flow" 107 | }, 108 | { 109 | "include": "#control-using" 110 | }, 111 | { 112 | "include": "#control-import" 113 | }, 114 | { 115 | "include": "#control-pragma" 116 | }, 117 | { 118 | "include": "#control-underscore" 119 | }, 120 | { 121 | "include": "#control-other" 122 | } 123 | ] 124 | }, 125 | "control-flow": { 126 | "match": "\\b(if|else|for|while|do|break|continue|throw|returns?)\\b", 127 | "name": "keyword.control.flow.soliditypp" 128 | }, 129 | "control-using": { 130 | "match": "\\b(using)\\b", 131 | "name": "keyword.control.using.soliditypp" 132 | }, 133 | "control-import": { 134 | "match": "\\b(import)\\b", 135 | "name": "keyword.control.import.soliditypp" 136 | }, 137 | "control-pragma": { 138 | "match": "\\b(pragma)(?:\\s+([A-Za-z_]\\w+)\\s+([^\\s]+))?\\b", 139 | "captures": { 140 | "1": { 141 | "name": "keyword.control.pragma.soliditypp" 142 | }, 143 | "2": { 144 | "name": "entity.name.tag.pragma.soliditypp" 145 | }, 146 | "3": { 147 | "name": "constant.other.pragma.soliditypp" 148 | } 149 | } 150 | }, 151 | "control-underscore": { 152 | "match": "\\b(_)\\b", 153 | "name": "constant.other.underscore.soliditypp" 154 | }, 155 | "control-other": { 156 | "match": "\\b(new|delete|emit)\\b", 157 | "name": "keyword.control.soliditypp" 158 | }, 159 | "constant": { 160 | "patterns": [ 161 | { 162 | "include": "#constant-boolean" 163 | }, 164 | { 165 | "include": "#constant-time" 166 | }, 167 | { 168 | "include": "#constant-currency" 169 | } 170 | ] 171 | }, 172 | "constant-boolean": { 173 | "match": "\\b(true|false)\\b", 174 | "name": "constant.language.boolean.soliditypp" 175 | }, 176 | "constant-time": { 177 | "match": "\\b(seconds|minutes|hours|days|weeks|years)\\b", 178 | "name": "constant.language.time.soliditypp" 179 | }, 180 | "constant-currency": { 181 | "match": "\\b(attov|vite)\\b", 182 | "name": "constant.language.currency.soliditypp" 183 | }, 184 | "number": { 185 | "patterns": [ 186 | { 187 | "include": "#number-decimal" 188 | }, 189 | { 190 | "include": "#number-hex" 191 | } 192 | ] 193 | }, 194 | "number-decimal": { 195 | "match": "\\b(\\d+(\\.\\d+)?)\\b", 196 | "name": "constant.numeric.decimal.soliditypp" 197 | }, 198 | "number-hex": { 199 | "match": "\\b(0[xX][a-fA-F0-9]+)\\b", 200 | "name": "constant.numeric.hexadecimal.soliditypp" 201 | }, 202 | "string": { 203 | "patterns": [ 204 | { 205 | "match": "\\\".*?\\\"", 206 | "name": "string.quoted.double.soliditypp" 207 | }, 208 | { 209 | "match": "\\'.*?\\'", 210 | "name": "string.quoted.single.soliditypp" 211 | } 212 | ] 213 | }, 214 | "type": { 215 | "patterns": [ 216 | { 217 | "include": "#type-primitive" 218 | } 219 | ] 220 | }, 221 | "type-primitive": { 222 | "match": "\\b(address|gid|tokenId|string\\d*|bytes\\d*|int\\d*|uint\\d*|bool|hash\\d*)\\b", 223 | "name": "support.type.primitive.soliditypp" 224 | }, 225 | "global": { 226 | "patterns": [ 227 | { 228 | "include": "#global-variables" 229 | }, 230 | { 231 | "include": "#global-functions" 232 | } 233 | ] 234 | }, 235 | "global-variables": { 236 | "patterns": [ 237 | { 238 | "match": "\\b(msg|block|tx|now)\\b", 239 | "name": "variable.language.transaction.soliditypp" 240 | }, 241 | { 242 | "match": "\\b(this)\\b", 243 | "name": "variable.language.this.soliditypp" 244 | }, 245 | { 246 | "match": "\\b(super)\\b", 247 | "name": "variable.language.super.soliditypp" 248 | } 249 | ] 250 | }, 251 | "global-functions": { 252 | "patterns": [ 253 | { 254 | "match": "\\b(require|assert|revert)\\b", 255 | "name": "keyword.control.exceptions.soliditypp" 256 | }, 257 | { 258 | "match": "\\b(selfdestruct|suicide)\\b", 259 | "name": "keyword.control.contract.soliditypp" 260 | }, 261 | { 262 | "match": "\\b(addmod|mulmod|blake2b)\\b", 263 | "name": "support.function.math.soliditypp" 264 | }, 265 | { 266 | "match": "\\b(blockhash)\\b", 267 | "name": "variable.language.transaction.soliditypp" 268 | } 269 | ] 270 | }, 271 | "declaration": { 272 | "patterns": [ 273 | { 274 | "include": "#declaration-contract" 275 | }, 276 | { 277 | "include": "#declaration-interface" 278 | }, 279 | { 280 | "include": "#declaration-library" 281 | }, 282 | { 283 | "include": "#declaration-struct" 284 | }, 285 | { 286 | "include": "#declaration-event" 287 | }, 288 | { 289 | "include": "#declaration-enum" 290 | }, 291 | { 292 | "include": "#declaration-function" 293 | }, 294 | { 295 | "include": "#declaration-constructor" 296 | }, 297 | { 298 | "include": "#declaration-modifier" 299 | }, 300 | { 301 | "include": "#declaration-mapping" 302 | } 303 | ] 304 | }, 305 | "declaration-contract": { 306 | "patterns": [ 307 | { 308 | "match": "\\b(contract)(\\s+([A-Za-z_]\\w*))?\\b", 309 | "captures": { 310 | "1": { 311 | "name": "storage.type.contract.soliditypp" 312 | }, 313 | "3": { 314 | "name": "entity.name.type.contract.soliditypp" 315 | } 316 | } 317 | }, 318 | { 319 | "match": "\\b(is)\\b", 320 | "name": "storage.modifier.is.soliditypp" 321 | } 322 | ] 323 | }, 324 | "declaration-interface": { 325 | "match": "\\b(message)(\\s+([A-Za-z_]\\w*))?\\b", 326 | "captures": { 327 | "1": { 328 | "name": "storage.type.interface.soliditypp" 329 | }, 330 | "3": { 331 | "name": "entity.name.type.interface.soliditypp" 332 | } 333 | } 334 | }, 335 | "declaration-library": { 336 | "match": "\\b(library)(\\s+([A-Za-z_]\\w*))?\\b", 337 | "captures": { 338 | "1": { 339 | "name": "storage.type.library.soliditypp" 340 | }, 341 | "3": { 342 | "name": "entity.name.type.library.soliditypp" 343 | } 344 | } 345 | }, 346 | "declaration-struct": { 347 | "match": "\\b(struct)(\\s+([A-Za-z_]\\w*))?\\b", 348 | "captures": { 349 | "1": { 350 | "name": "storage.type.struct.soliditypp" 351 | }, 352 | "3": { 353 | "name": "entity.name.type.struct.soliditypp" 354 | } 355 | } 356 | }, 357 | "declaration-event": { 358 | "match": "\\b(event)(\\s+([A-Za-z_]\\w*))?\\b", 359 | "captures": { 360 | "1": { 361 | "name": "storage.type.event.soliditypp" 362 | }, 363 | "3": { 364 | "name": "entity.name.type.event.soliditypp" 365 | } 366 | } 367 | }, 368 | "declaration-constructor": { 369 | "match": "\\b(constructor)\\b", 370 | "captures": { 371 | "1": { 372 | "name": "storage.type.constructor.soliditypp" 373 | } 374 | } 375 | }, 376 | "declaration-enum": { 377 | "match": "\\b(enum)(\\s+([A-Za-z_]\\w*))?\\b", 378 | "captures": { 379 | "1": { 380 | "name": "storage.type.enum.soliditypp" 381 | }, 382 | "3": { 383 | "name": "entity.name.type.enum.soliditypp" 384 | } 385 | } 386 | }, 387 | "declaration-function": { 388 | "patterns": [ 389 | { 390 | "match": "\\b(function)\\s+([A-Za-z_]\\w*)\\b", 391 | "captures": { 392 | "1": { 393 | "name": "storage.type.function.soliditypp" 394 | }, 395 | "2": { 396 | "name": "entity.name.function.soliditypp" 397 | } 398 | } 399 | }, 400 | { 401 | "match": "\\b(onMessage)\\s+([A-Za-z_]\\w*)\\b", 402 | "captures": { 403 | "1": { 404 | "name": "storage.type.onMessage.soliditypp" 405 | }, 406 | "2": { 407 | "name": "entity.name.onMessage.soliditypp" 408 | } 409 | } 410 | }, 411 | { 412 | "match": "\\b(public|pure|view|payable|nonpayable|inherited|indexed|storage|memory)\\b", 413 | "name": "storage.type.mofifier.soliditypp" 414 | } 415 | ] 416 | }, 417 | "declaration-modifier": { 418 | "match": "\\b(modifier)(\\s+([A-Za-z_]\\w*))?\\b", 419 | "captures": { 420 | "1": { 421 | "name": "storage.type.modifier.soliditypp" 422 | }, 423 | "3": { 424 | "name": "entity.name.function.soliditypp" 425 | } 426 | } 427 | }, 428 | "declaration-mapping": { 429 | "match": "\\b(mapping)\\b", 430 | "name": "storage.type.mapping.soliditypp" 431 | }, 432 | "function-call": { 433 | "match": "\\b([A-Za-z_]\\w*)\\s*\\(", 434 | "captures": { 435 | "1": { 436 | "name": "entity.name.function.soliditypp" 437 | } 438 | } 439 | }, 440 | "punctuation": { 441 | "patterns": [ 442 | { 443 | "match": ";", 444 | "name": "punctuation.terminator.statement.soliditypp" 445 | }, 446 | { 447 | "match": "\\.", 448 | "name": "punctuation.accessor.soliditypp" 449 | }, 450 | { 451 | "match": ",", 452 | "name": "punctuation.separator.soliditypp" 453 | } 454 | ] 455 | } 456 | }, 457 | "scopeName": "source.soliditypp" 458 | } 459 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "CommonJS", 4 | "target": "es6", 5 | "outDir": "out", 6 | // "outFile": "out/out_out_out.js", 7 | 8 | "lib": ["es6"], 9 | "sourceMap": true, 10 | 11 | "rootDir": "src", 12 | /* Strict Type-Checking Option */ 13 | "strict": true /* enable all strict type-checking options */, 14 | /* Additional Checks */ 15 | "noUnusedLocals": true /* Report errors on unused locals. */ 16 | // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ 17 | // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ 18 | // "noUnusedParameters": true, /* Report errors on unused parameters. */ 19 | }, 20 | "exclude": ["node_modules/vscode", ".vscode-test", "view"] 21 | } 22 | -------------------------------------------------------------------------------- /tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "rules": { 3 | "no-string-throw": true, 4 | "no-unused-expression": true, 5 | "no-duplicate-variable": true, 6 | "curly": true, 7 | "class-name": true, 8 | "semicolon": [true, "always"], 9 | "triple-equals": true 10 | }, 11 | "defaultSeverity": "warning" 12 | } 13 | -------------------------------------------------------------------------------- /view/app.vue: -------------------------------------------------------------------------------- 1 | 22 | 23 | 85 | 86 | -------------------------------------------------------------------------------- /view/components/accountBlock.vue: -------------------------------------------------------------------------------- 1 | 22 | 23 | 76 | 77 | 103 | 104 | -------------------------------------------------------------------------------- /view/components/baseInfo.vue: -------------------------------------------------------------------------------- 1 | 118 | 163 | 181 | 182 | 200 | -------------------------------------------------------------------------------- /view/components/contract.vue: -------------------------------------------------------------------------------- 1 | 98 | 99 | 318 | 319 | -------------------------------------------------------------------------------- /view/components/contractList.vue: -------------------------------------------------------------------------------- 1 | 34 | 35 | 70 | 71 | 76 | 77 | -------------------------------------------------------------------------------- /view/components/debug.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 21 | 22 | -------------------------------------------------------------------------------- /view/components/debugInfo.vue: -------------------------------------------------------------------------------- 1 | 164 | 165 | 282 | 283 | 291 | -------------------------------------------------------------------------------- /view/components/deploy.vue: -------------------------------------------------------------------------------- 1 | 64 | 65 | 185 | -------------------------------------------------------------------------------- /view/components/deployList.vue: -------------------------------------------------------------------------------- 1 | 41 | 42 | 249 | 250 | 279 | 280 | 291 | -------------------------------------------------------------------------------- /view/components/help.vue: -------------------------------------------------------------------------------- 1 | 4 | 17 | -------------------------------------------------------------------------------- /view/components/logItem.vue: -------------------------------------------------------------------------------- 1 | 24 | 56 | 57 | 96 | -------------------------------------------------------------------------------- /view/components/logList.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 40 | -------------------------------------------------------------------------------- /view/components/resultList.vue: -------------------------------------------------------------------------------- 1 | 50 | 51 | 177 | -------------------------------------------------------------------------------- /view/components/selectToken.vue: -------------------------------------------------------------------------------- 1 | 12 | 13 | 55 | 56 | -------------------------------------------------------------------------------- /view/components/setting.vue: -------------------------------------------------------------------------------- 1 | 23 | 24 | 65 | 66 | -------------------------------------------------------------------------------- /view/components/tokenUnits.vue: -------------------------------------------------------------------------------- 1 | 8 | 51 | -------------------------------------------------------------------------------- /view/components/transfer.vue: -------------------------------------------------------------------------------- 1 | 23 | 24 | 64 | 65 | -------------------------------------------------------------------------------- /view/components/units.vue: -------------------------------------------------------------------------------- 1 | 9 | 37 | -------------------------------------------------------------------------------- /view/components/vcLogin.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | -------------------------------------------------------------------------------- /view/global/Account.js: -------------------------------------------------------------------------------- 1 | import { accountBlock, utils, wallet } from '@vite/vitejs'; 2 | 3 | import * as vite from './vite'; 4 | import receiveAllOnroadTx from '../utils/receiveAllOnroadTx'; 5 | 6 | const { createAccountBlock } = accountBlock; 7 | 8 | export default class Account { 9 | constructor({ privateKey }) { 10 | if (!privateKey) { 11 | privateKey = utils._Buffer.from(utils.ed25519.keyPair().privateKey).toString('hex'); 12 | } 13 | 14 | this.privateKey = privateKey; 15 | this.address = wallet.createAddressByPrivateKey(privateKey).address; 16 | this.type = 'local'; 17 | } 18 | 19 | _createAccountBlock(type, params) { 20 | let _accountBlock = createAccountBlock(type, { 21 | address: this.address, 22 | ...params 23 | }); 24 | _accountBlock.setProvider(vite.getVite()).setPrivateKey(this.privateKey); 25 | return _accountBlock; 26 | } 27 | 28 | async _send(_accountBlock) { 29 | await _accountBlock.autoSetPreviousAccountBlock(); 30 | // console.log('toaddress: '); 31 | // console.log(_accountBlock.toAddress); 32 | let result = await _accountBlock.sign().send(); 33 | // console.log(JSON.stringify(result, null, 4)); 34 | return result; 35 | } 36 | 37 | async receiveTx({ sendBlockHash }) { 38 | const _accountBlock = this._createAccountBlock('receive', { 39 | sendBlockHash 40 | }); 41 | 42 | return this._send(_accountBlock); 43 | } 44 | 45 | async receiveAllOnroadTx() { 46 | return receiveAllOnroadTx(vite.getVite(), this); 47 | } 48 | 49 | async sendTx({ toAddress, tokenId, amount }) { 50 | let _accountBlock = this._createAccountBlock('send', { 51 | toAddress, 52 | tokenId, 53 | amount 54 | }); 55 | 56 | return this._send(_accountBlock); 57 | } 58 | 59 | async createContract({ amount, hexCode, quotaMultiplier, responseLatency, randomDegree, abi, params }) { 60 | // console.log('randomDegree: '); 61 | // console.log(randomDegree); 62 | let _accountBlock = this._createAccountBlock('createContract', { 63 | abi, 64 | code: hexCode, 65 | responseLatency, 66 | params, 67 | quotaMultiplier, 68 | randomDegree 69 | }); 70 | _accountBlock.amount = amount; 71 | return this._send(_accountBlock); 72 | } 73 | 74 | async callContract({ tokenId, amount, abi, params, toAddress }) { 75 | let _accountBlock = this._createAccountBlock('callContract', { 76 | tokenId, 77 | amount, 78 | abi, 79 | params, 80 | toAddress 81 | }); 82 | return this._send(_accountBlock, abi); 83 | } 84 | 85 | async getBalance() { 86 | return vite.getVite().getBalanceInfo(this.address); 87 | } 88 | } -------------------------------------------------------------------------------- /view/global/VcAccount.js: -------------------------------------------------------------------------------- 1 | import { accountBlock as accountBlockUtils } from '@vite/vitejs'; 2 | import * as vite from './vite'; 3 | 4 | 5 | import Account from './Account'; 6 | import { sendVcTx } from 'services/vc'; 7 | 8 | const { createAccountBlock } = accountBlockUtils; 9 | 10 | export default class VcAccount extends Account { 11 | constructor({ address }) { 12 | super({}); 13 | if (!address) { 14 | throw new Error('address should not be empty'); 15 | } 16 | this.address = address; 17 | this.privateKey = null; 18 | this.type = 'vc'; 19 | } 20 | 21 | _createAccountBlock(type, params) { 22 | let _accountBlock = createAccountBlock(type, { 23 | address: this.address, 24 | ...params 25 | }); 26 | _accountBlock.setProvider(vite.getVite()); 27 | return _accountBlock; 28 | } 29 | 30 | async _send(_accountBlock, abi) { 31 | return sendVcTx({ 32 | block: _accountBlock.accountBlock, 33 | abi 34 | }); 35 | } 36 | 37 | async createContract({ amount, hexCode, quotaMultiplier, responseLatency, randomDegree, abi, params }) { 38 | let _accountBlock = this._createAccountBlock('createContract', { 39 | abi, 40 | code: hexCode, 41 | responseLatency, 42 | params, 43 | quotaMultiplier, 44 | randomDegree 45 | }); 46 | _accountBlock.amount = amount; 47 | await _accountBlock.autoSetPreviousAccountBlock(); 48 | return sendVcTx({ 49 | block: _accountBlock.accountBlock, 50 | }); 51 | } 52 | } -------------------------------------------------------------------------------- /view/global/constants.js: -------------------------------------------------------------------------------- 1 | export const CUSTOM_NET_MAP = 'CUSTOM_NET_MAP'; 2 | export const storageKeyMap = { 3 | 'mnemonics': 'vite_soliditypp_mnemonics', 4 | 'enableVc': 'vite_soliditypp_enableVc', 5 | 'CUSTOM_NET_MAP':'CUSTOM_NET_MAP' 6 | }; 7 | -------------------------------------------------------------------------------- /view/global/vite.js: -------------------------------------------------------------------------------- 1 | import WS_RPC from '@vite/vitejs-ws'; 2 | import { utils, wallet } from '@vite/vitejs'; 3 | import { abi as abiutils } from '@vite/vitejs'; 4 | import { ViteAPI } from '@vite/vitejs'; 5 | import receiveAllOnroadTx from 'utils/receiveAllOnroadTx'; 6 | 7 | const BigNumber = require('bignumber.js'); 8 | 9 | import Account from './Account'; 10 | 11 | const VITE_TOKEN_ID = 'tti_5649544520544f4b454e6e40'; 12 | const WS_SERVER = 'ws://localhost:23457'; 13 | const GENESIS_PRIVATEKEY = 14 | '7488b076b27aec48692230c88cbe904411007b71981057ea47d757c1e7f7ef24f4da4390a6e2618bec08053a86a6baf98830430cbefc078d978cf396e1c43e3a'; 15 | const VITE_DECIMAL = new BigNumber('1e18'); 16 | export const ACCOUNT_INIT_AMOUNT = VITE_DECIMAL.multipliedBy(1000); 17 | 18 | let viteClient; 19 | let genesisAccount; 20 | let mnemonicsDeriveIndex = 0; 21 | 22 | export function setupNode(server = WS_SERVER, cb) { 23 | server = server || WS_SERVER; 24 | let provider = new WS_RPC(server, 30 * 1000, { 25 | retryInterval: 100, 26 | retryTimes: 100 27 | }); 28 | 29 | viteClient = new ViteAPI(provider, cb); 30 | return viteClient; 31 | } 32 | 33 | export async function init() { 34 | genesisAccount = new Account({ 35 | privateKey: GENESIS_PRIVATEKEY, 36 | client: viteClient 37 | }); 38 | 39 | // genesis account receive onroad blocks 40 | await receiveAllOnroadTx(viteClient, genesisAccount); 41 | } 42 | 43 | export function getVite() { 44 | return viteClient; 45 | } 46 | 47 | export function getGenesisAccount() { 48 | return genesisAccount; 49 | } 50 | 51 | export function createAccount(mnemonics, index = mnemonicsDeriveIndex) { 52 | const { privateKey } = wallet.deriveAddress({ 53 | mnemonics, 54 | index 55 | }); 56 | let account = new Account({ 57 | privateKey 58 | }); 59 | mnemonicsDeriveIndex = index + 1; 60 | return account; 61 | } 62 | 63 | export async function initBalance(account, balance) { 64 | let genesisAccount = getGenesisAccount(); 65 | // send money to test accout 66 | await genesisAccount.sendTx({ 67 | toAddress: account.address, 68 | tokenId: VITE_TOKEN_ID, 69 | amount: balance 70 | }); 71 | 72 | await receiveAllOnroadTx(viteClient, account); 73 | } 74 | 75 | export async function createContract( 76 | account, 77 | contract, 78 | amount, 79 | responseLatency, 80 | quotaMultiplier, 81 | randomDegree, 82 | params 83 | ) { 84 | let createContractBlock = await account.createContract({ 85 | amount: amount.toString(), 86 | hexCode: contract.bytecodes, 87 | quotaMultiplier, 88 | responseLatency, 89 | randomDegree, 90 | abi: contract.abi, 91 | params: params 92 | }); 93 | return createContractBlock; 94 | } 95 | 96 | export async function sendContractTx( 97 | account, 98 | contractAddress, 99 | abi, 100 | amount = 0, 101 | params, 102 | tokenId = VITE_TOKEN_ID 103 | ) { 104 | console.log(params); 105 | let callContractBlock = await account.callContract({ 106 | tokenId, 107 | amount: amount.toString(), 108 | abi: abi, 109 | params: params, 110 | toAddress: contractAddress 111 | }); 112 | return callContractBlock; 113 | } 114 | 115 | export async function callOffchainMethod( 116 | contractAddress, 117 | abi, 118 | offchaincode, 119 | params 120 | ) { 121 | let data = abiutils.encodeFunctionCall(abi, params); 122 | let dataBase64 = Buffer.from(data, 'hex').toString('base64'); 123 | let codeBase64 = Buffer.from(offchaincode, 'hex').toString('base64'); 124 | let result = await viteClient.request('contract_callOffChainMethod', { 125 | address: contractAddress, 126 | code: codeBase64, 127 | data: dataBase64 128 | }); 129 | if (result) { 130 | let resultBytes = Buffer.from(result, 'base64').toString('hex'); 131 | let outputs = []; 132 | for (let i = 0; i < abi.outputs.length; i++) { 133 | outputs.push(abi.outputs[i].type); 134 | } 135 | let offchainDecodeResult = abiutils.decodeParameters( 136 | outputs, 137 | resultBytes 138 | ); 139 | let resultList = []; 140 | for (let i = 0; i < abi.outputs.length; i++) { 141 | if (abi.outputs[i].name) { 142 | resultList.push({ 143 | name: abi.outputs[i].name, 144 | value: offchainDecodeResult[i] 145 | }); 146 | } else { 147 | resultList.push({ 148 | name: '', 149 | value: offchainDecodeResult[i] 150 | }); 151 | } 152 | } 153 | return resultList; 154 | } 155 | return ''; 156 | } 157 | 158 | export async function queryVmLogList(contractBlock, abi) { 159 | if (!contractBlock.logHash) { 160 | return; 161 | } 162 | 163 | let vmLogList = await viteClient.request( 164 | 'ledger_getVmLogList', 165 | contractBlock.hash 166 | ); 167 | let vmLogs = []; 168 | if (vmLogList) { 169 | vmLogList.forEach(vmLog => { 170 | let topics = vmLog.topics; 171 | for (let j = 0; j < abi.length; j++) { 172 | let abiItem = abi[j]; 173 | 174 | if (abiutils.encodeLogSignature(abiItem) === topics[0]) { 175 | let dataBytes = ''; 176 | if (vmLog.data) { 177 | dataBytes = utils._Buffer.from(vmLog.data, 'base64'); 178 | } 179 | let log = { 180 | topic: topics[0], 181 | args: abiutils.decodeLog( 182 | abiItem.inputs, 183 | dataBytes.toString('hex'), 184 | topics.slice(1) 185 | ), 186 | event: abiItem.name 187 | }; 188 | vmLogs.push(log); 189 | break; 190 | } 191 | } 192 | }); 193 | } 194 | return vmLogs; 195 | } 196 | 197 | export function transformViteBalance(amount, units) { 198 | let transformedAmount = amount; 199 | switch (units) { 200 | case 'vite': 201 | transformedAmount = new BigNumber(transformedAmount) 202 | .multipliedBy(VITE_DECIMAL) 203 | .toFixed(); 204 | break; 205 | case 'attov': 206 | break; 207 | } 208 | return transformedAmount; 209 | } 210 | 211 | export function transformTokenAmount(amount, units) { 212 | return new BigNumber(amount) 213 | .multipliedBy(new BigNumber(`1e${units || 0}`)) 214 | .toFixed(); 215 | } 216 | 217 | export function isSendBlock(blockType) { 218 | return ( 219 | blockType === 1 || blockType === 2 || blockType === 3 || blockType === 6 220 | ); 221 | } 222 | 223 | export function isReceiveBlock(blockType) { 224 | return blockType === 4 || blockType === 5 || blockType === 7; 225 | } 226 | 227 | export async function transfer(account, amount) { 228 | const sendTx = await genesisAccount.sendTx({ 229 | toAddress: account.address, 230 | tokenId: VITE_TOKEN_ID, 231 | amount: amount 232 | }); 233 | 234 | await receiveAllOnroadTx(viteClient, account); 235 | 236 | return sendTx; 237 | } 238 | -------------------------------------------------------------------------------- /view/global/vscode.js: -------------------------------------------------------------------------------- 1 | let vscode = acquireVsCodeApi(); 2 | 3 | export default vscode; 4 | 5 | -------------------------------------------------------------------------------- /view/i18n/en.js: -------------------------------------------------------------------------------- 1 | module.exports = {}; 2 | -------------------------------------------------------------------------------- /view/i18n/zh.js: -------------------------------------------------------------------------------- 1 | module.exports = {}; 2 | -------------------------------------------------------------------------------- /view/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | <%= htmlWebpackPlugin.options.title %> 6 | 7 | 8 |
9 |
10 | 11 | -------------------------------------------------------------------------------- /view/index.js: -------------------------------------------------------------------------------- 1 | import 'babel-polyfill'; 2 | 3 | import './index.scss'; 4 | 5 | import Vue from 'vue'; 6 | import VueRouter from 'vue-router'; 7 | import VueSplit from 'vue-split-panel'; 8 | import ElementUI from 'element-ui'; 9 | import 'element-ui/lib/theme-chalk/index.css'; 10 | 11 | import store from 'store/store'; 12 | import App from './app.vue'; 13 | import router from './router'; 14 | 15 | 16 | import Help from 'components/help'; 17 | 18 | Vue.use(VueRouter); 19 | Vue.use(ElementUI); 20 | 21 | Vue.use(VueSplit); 22 | 23 | Vue.component('help', Help); 24 | 25 | new Vue({ 26 | el: '#app', 27 | store: store, 28 | components: { App }, 29 | template: '', 30 | router 31 | }); 32 | -------------------------------------------------------------------------------- /view/index.scss: -------------------------------------------------------------------------------- 1 | html, 2 | body { 3 | padding: 0; 4 | margin: 0; 5 | height: 100%; 6 | } 7 | 8 | .module-wrapper { 9 | border-top: 1px solid #999; 10 | border-bottom: 1px solid #999; 11 | margin-bottom: 10px; 12 | } 13 | .title { 14 | padding: 10px; 15 | font-size: 16px; 16 | font-weight: 600; 17 | } 18 | 19 | .minor-title { 20 | font-weight: 600; 21 | border-bottom: 1px solid #fff; 22 | font-size: 14px; 23 | line-height: 30px; 24 | margin-bottom: 10px; 25 | } 26 | 27 | .prop-row { 28 | height: 36px; 29 | line-height: 15px; 30 | } 31 | 32 | .prop-label { 33 | text-align: center; 34 | color: #ddd; 35 | font-weight: 600; 36 | } 37 | -------------------------------------------------------------------------------- /view/router.js: -------------------------------------------------------------------------------- 1 | import VueRouter from 'vue-router'; 2 | 3 | import Setting from 'components/setting'; 4 | import Debug from 'components/debug'; 5 | 6 | 7 | const routes = [ 8 | { path: '/debug', component: Debug, name: 'debug' }, 9 | { path: '/setting', component: Setting, name: 'setting' } 10 | ]; 11 | 12 | export default new VueRouter({ 13 | routes 14 | }); 15 | 16 | -------------------------------------------------------------------------------- /view/services/compile.js: -------------------------------------------------------------------------------- 1 | export default function getCompileResult () { 2 | let url = '/contractData'; 3 | if (process.env.NODE_ENV === 'dev') { 4 | url = 'http://localhost:9000' + url; 5 | } 6 | return fetch(url).then(res => res.json()); 7 | } 8 | 9 | -------------------------------------------------------------------------------- /view/services/vc.js: -------------------------------------------------------------------------------- 1 | import Connector from '@vite/connector'; 2 | 3 | const BRIDGE = 'wss://biforst.vite.net'; 4 | 5 | const vbInstance = new Connector({ bridge: BRIDGE }); 6 | 7 | export const initVC = async () => { 8 | await vbInstance.createSession(); 9 | return vbInstance.uri; 10 | }; 11 | 12 | export const getVc = () => vbInstance; 13 | 14 | export const sendVcTx = async (...args) => { 15 | let vc = getVc(); 16 | return new Promise((res, rej) => { 17 | vc.on('disconnect', () => { 18 | rej({ code: 11020, message: 'vc disconnect' }); 19 | }); 20 | 21 | vc.sendCustomRequest({ method: 'vite_signAndSendTx', params: args }).then(r => { 22 | res(r); 23 | }).catch(e => { 24 | rej(e); 25 | }); 26 | }); 27 | }; 28 | 29 | -------------------------------------------------------------------------------- /view/store/store.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue'; 2 | import Vuex from 'vuex'; 3 | import dayjs from 'dayjs'; 4 | import * as vite from 'global/vite'; 5 | import WS_RPC from '@vite/vitejs-ws'; 6 | import { wallet } from '@vite/vitejs'; 7 | import { CUSTOM_NET_MAP } from 'global/constants'; 8 | 9 | import * as storage from 'utils/storage'; 10 | 11 | /* 12 | deployInfo struct: 13 | 14 | var deployInfo = { 15 | compileInfo: '', 16 | selectedAccount: '', 17 | selectedAccountAddress: '', 18 | accounts: [], // [viteAccount] 19 | contractList: [] // [contractList] 20 | logs: [] 21 | }; 22 | */ 23 | 24 | export const NET_MAPS = { 25 | debug: 'ws://localhost:23457', 26 | testnet: 'wss://buidl.vite.net/gvite/ws', 27 | mainnet: 'wss://node.vite.net/gvite/ws' 28 | }; 29 | 30 | Vue.use(Vuex); 31 | let mnemonicsDefault = storage.get('mnemonics'); 32 | if (!wallet.validateMnemonics(mnemonicsDefault)) { 33 | mnemonicsDefault = wallet.createMnemonics(); 34 | storage.set('mnemonics', mnemonicsDefault); 35 | } 36 | 37 | const initialAccount = vite.createAccount(mnemonicsDefault, 0); 38 | const enableVc = !!storage.get('enableVc'); 39 | const initCustomNetsMap = storage.get(CUSTOM_NET_MAP); 40 | 41 | const store = new Vuex.Store({ 42 | state: { 43 | snapshotHeight: 1, 44 | deployInfoList: [], 45 | compileResult: null, 46 | vcConnected: false, // vc connect status 47 | accounts: [initialAccount], 48 | selectedAddress: initialAccount.address, 49 | accountStates: {}, 50 | netType: 'debug', // debug(local debug network) / testnet(vite testnet) / mainnet(vite mainnet) 51 | contracts: [], 52 | mnemonics: mnemonicsDefault, 53 | enableVc, 54 | dynamicNetMap: { ...NET_MAPS,...initCustomNetsMap } 55 | }, 56 | getters: { 57 | addressMap(state, getters) { 58 | let ob = {}; 59 | getters.accountsFilter.forEach(item => { 60 | ob[item.address] = item; 61 | ob[item.address].accountState = 62 | state.accountStates[item.address]; 63 | }); 64 | return ob; 65 | }, 66 | accountsFilter(state) { 67 | const { enableVc } = state; 68 | if (!enableVc) { 69 | return state.accounts.filter(item => item.type === 'local'); 70 | } 71 | return state.accounts.filter(item => item.type === 'vc'); 72 | }, 73 | selectedAccount(state, getters) { 74 | return getters.addressMap[state.selectedAddress] || {}; 75 | }, 76 | currentNode(state) { 77 | return state.dynamicNetMap[state.netType]; 78 | }, 79 | isDebugEnv(state) { 80 | return state.netType === 'debug'; 81 | }, 82 | netTypeList() { 83 | return ['debug', 'testnet', 'mainnet', 'custom']; 84 | } 85 | }, 86 | mutations: { 87 | setDynamicNetItem(state, { url, name }) { 88 | state.dynamicNetMap[name] = url; 89 | }, 90 | setCompileResult(state, { compileResult }) { 91 | state.compileResult = compileResult; 92 | }, 93 | 94 | setNetType(state, netType) { 95 | state.netType = netType; 96 | }, 97 | setVcConnected(state, status) { 98 | state.vcConnected = status; 99 | }, 100 | 101 | setEnableVc(state, status) { 102 | state.enableVc = !!status; 103 | }, 104 | 105 | init(state, { compileResult }) { 106 | let deployInfoList = []; 107 | 108 | for (let i = 0; i < compileResult.abiList.length; i++) { 109 | let compileInfo = { 110 | abi: compileResult.abiList[i], 111 | bytecodes: compileResult.bytecodesList[i], 112 | 113 | contractName: compileResult.contractNameList[i], 114 | offchainCode: compileResult.offchainCodesList[i], 115 | asm:compileResult.asmList[i], 116 | offAsm:compileResult.offAsmList[i] 117 | }; 118 | 119 | let deployInfo = { 120 | index: i, 121 | compileInfo, 122 | logs: [], 123 | contracts: [] 124 | }; 125 | 126 | deployInfoList.push(deployInfo); 127 | } 128 | 129 | state.deployInfoList = deployInfoList; 130 | }, 131 | 132 | setMnemonics(state, payload) { 133 | state.mnemonics = payload; 134 | }, 135 | 136 | addAccount(state, { account }) { 137 | state.accounts = state.accounts.concat([account]); 138 | }, 139 | 140 | setAccounts(state, accounts) { 141 | state.accounts = accounts; 142 | }, 143 | 144 | setSelectedAddress(state, address) { 145 | state.selectedAddress = address; 146 | }, 147 | 148 | updateAccountState(state, { address, accountState }) { 149 | state.accountStates = { 150 | ...state.accountStates, 151 | [address]: accountState 152 | }; 153 | }, 154 | 155 | updateSnapshotHeight(state, { snapshotHeight }) { 156 | state.snapshotHeight = snapshotHeight; 157 | }, 158 | 159 | // deployInfo: this.deployInfo, 160 | // sendCreateBlock: createContractBlock 161 | deployed(state, { contract, contractName }) { 162 | // contractAddress: contractBlock.toAddress, 163 | // contractBlock, 164 | // abi, 165 | // contractName, 166 | // offchainCode 167 | state.contracts = state.contracts.concat([ 168 | { 169 | ...contract, 170 | contractName 171 | } 172 | ]); 173 | }, 174 | 175 | addLog( 176 | state, 177 | { deployInfo, log, title = '', type = 'info', dataType = 'text' } 178 | ) { 179 | let content = log; 180 | if (type === 'error') { 181 | if (content.stack) { 182 | content = log.toString(); 183 | } else { 184 | content = JSON.stringify(content); 185 | } 186 | } 187 | console.log(type); 188 | deployInfo.logs.push({ 189 | createdTime: dayjs(), 190 | title: title, 191 | content: content, 192 | type, 193 | dataType 194 | }); 195 | } 196 | }, 197 | 198 | actions: { 199 | changeNetType({ state, getters, commit }, netType) { 200 | if (netType !== state.netType) { 201 | commit('setNetType', netType); 202 | commit( 203 | 'setSelectedAddress', 204 | getters.accountsFilter[0] && 205 | getters.accountsFilter[0].address 206 | ); 207 | vite.getVite().setProvider( 208 | new WS_RPC(getters.currentNode, 60000), 209 | () => { 210 | console.log( 211 | `connect to ${getters.currentNode} success.` 212 | ); 213 | }, 214 | true 215 | ); 216 | } 217 | }, 218 | addAccount({ commit }, newAccount) { 219 | commit('addAccount', { account: newAccount }); 220 | commit('setSelectedAddress', newAccount.address); 221 | }, 222 | importWallet({ commit, state }, payload) { 223 | if (payload === state.mnemonics) { 224 | return; 225 | } 226 | commit('setMnemonics', payload); 227 | storage.set('mnemonics', payload); 228 | let newAccount = vite.createAccount(payload, 0); 229 | commit('setAccounts', [newAccount]); 230 | commit('setSelectedAddress', newAccount.address); 231 | }, 232 | enableVc({ commit }, status) { 233 | commit('setEnableVc', status); 234 | storage.set('enableVc', !!status); 235 | }, 236 | updateDynamicNetItem({ commit }, { name, url }) { 237 | const customNetsMap = storage.get(CUSTOM_NET_MAP); 238 | storage.set(CUSTOM_NET_MAP,{...customNetsMap,[name]:url}); 239 | commit('setDynamicNetItem', { name, url }); 240 | } 241 | } 242 | }); 243 | 244 | export default store; 245 | -------------------------------------------------------------------------------- /view/utils/postError.js: -------------------------------------------------------------------------------- 1 | import vscode from 'global/vscode'; 2 | 3 | const COMMAND_PREFIX = 'view2extension.'; 4 | 5 | export default function postError(err) { 6 | let body = err.toString(); 7 | if (!body || body === '[object Object]') { 8 | body = JSON.stringify(err); 9 | } 10 | 11 | vscode.postMessage({ 12 | command: COMMAND_PREFIX + 'error', 13 | body 14 | }); 15 | } 16 | -------------------------------------------------------------------------------- /view/utils/receiveAllOnroadTx.js: -------------------------------------------------------------------------------- 1 | const RECEIVE_PER_ROUND = 10; 2 | 3 | export default async function receiveAllOnroadTx(viteClient, account) { 4 | let blocks = await viteClient.request('ledger_getUnreceivedBlocksByAddress', account.address, 0, RECEIVE_PER_ROUND); 5 | for (let i =0 ;i < blocks.length; i++) { 6 | let block = blocks[i]; 7 | // receive on road 8 | await account.receiveTx({ 9 | sendBlockHash: block.hash 10 | }); 11 | } 12 | if (blocks.length >= RECEIVE_PER_ROUND) { 13 | await receiveAllOnroadTx(viteClient, account); 14 | } 15 | } -------------------------------------------------------------------------------- /view/utils/request.js: -------------------------------------------------------------------------------- 1 | import vscode from 'global/vscode'; 2 | import EventEmitter from 'events'; 3 | 4 | const COMMAND_PREFIX = 'view2debugAdapter.'; 5 | 6 | let latestRequestId = 1; 7 | let ee = new EventEmitter(); 8 | 9 | window.addEventListener('message', event => { 10 | const message = event.data; 11 | if (!message.id) { 12 | return; 13 | } 14 | 15 | ee.emit(message.id.toString(), message); 16 | }); 17 | 18 | 19 | function request (command, body) { 20 | let messageId = latestRequestId; 21 | latestRequestId += 1; 22 | 23 | return new Promise(function (resolve, reject) { 24 | vscode.postMessage({ 25 | command: COMMAND_PREFIX + command, 26 | body: body, 27 | id: messageId 28 | }); 29 | 30 | ee.once(messageId.toString(), function (res) { 31 | 32 | if (res.error) { 33 | return reject(res.error); 34 | } 35 | return resolve(res.body); 36 | }); 37 | }); 38 | } 39 | 40 | export default request; 41 | -------------------------------------------------------------------------------- /view/utils/storage.js: -------------------------------------------------------------------------------- 1 | import { storageKeyMap } from 'global/constants'; 2 | 3 | 4 | export const get = key => { 5 | if (!storageKeyMap[key]) { 6 | throw new Error(`Can't find the storage key: ${key}`); 7 | } 8 | 9 | let str = localStorage.getItem(storageKeyMap[key]); 10 | let json; 11 | if (str == null) { 12 | return str; 13 | } 14 | try { 15 | json = JSON.parse(str); 16 | } catch (err) { 17 | console.log(err); 18 | } 19 | return json; 20 | }; 21 | 22 | export const set = (key, value) => { 23 | if (!storageKeyMap[key]) { 24 | throw new Error(`Can't find the storage key: ${key}`); 25 | } 26 | localStorage.setItem(storageKeyMap[key], JSON.stringify(value)); 27 | }; 28 | -------------------------------------------------------------------------------- /view/utils/task.js: -------------------------------------------------------------------------------- 1 | class Task { 2 | _taskTimer 3 | _taskInterval 4 | _task 5 | 6 | constructor (task, interval) { 7 | this._task = task; 8 | this._taskInterval = interval; 9 | 10 | return this; 11 | } 12 | 13 | _run () { 14 | this._taskTimer = setTimeout(async () => { 15 | if (!this._task) { 16 | return; 17 | } 18 | if (!(await this._task())) { 19 | return; 20 | } 21 | this._run(); 22 | }, this._taskInterval); 23 | } 24 | 25 | start () { 26 | if (this._taskTimer) { 27 | return; 28 | } 29 | 30 | this._run(); 31 | } 32 | 33 | 34 | stop () { 35 | if (!this._taskTimer) { 36 | return; 37 | } 38 | window.clearTimeout(this._taskTimer); 39 | this._taskTimer = undefined; 40 | } 41 | } 42 | 43 | module.exports = Task; 44 | -------------------------------------------------------------------------------- /view/webpackConfig/base.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const UglifyJsPlugin = require('uglifyjs-webpack-plugin'); 3 | const plugins = require('./plugins.js'); 4 | 5 | const debugContractData = require('../../debug-contract-data.json'); 6 | const SRC_PATH = path.join(__dirname, '../'); 7 | const STATIC_PATH = path.join(__dirname, '../../out_view'); 8 | let development = ['dev', 'test']; 9 | 10 | let config = { 11 | mode: 12 | development.indexOf(process.env.NODE_ENV) > -1 13 | ? 'development' 14 | : 'production', 15 | devtool: 'source-map', 16 | 17 | entry: { 18 | index: path.join(SRC_PATH, '/index.js') 19 | }, 20 | output: { 21 | path: STATIC_PATH 22 | }, 23 | optimization: { 24 | splitChunks: { 25 | chunks: 'all', 26 | }, 27 | }, 28 | plugins, 29 | module: { 30 | rules: [ 31 | { 32 | test: /\.vue$/, 33 | use: [ 34 | { 35 | loader: 'vue-loader' 36 | } 37 | ] 38 | }, 39 | { 40 | test: /\.(svg|png|jpg|gif)$/, 41 | loader: 'url-loader', 42 | query: { 43 | limit: 10 * 1024 //10KB 44 | } 45 | }, 46 | { 47 | test: /\.js$/, 48 | exclude: /node_modules/, 49 | use: { 50 | loader: 'babel-loader', 51 | options: { 52 | presets: ['@babel/preset-env'], 53 | plugins: [ 54 | '@babel/plugin-proposal-class-properties' 55 | // [ 56 | // 'component', 57 | // { 58 | // 'libraryName': 'element-ui', 59 | // 'styleLibraryName': 'theme-chalk' 60 | // } 61 | // ] 62 | ] 63 | } 64 | } 65 | }, 66 | { 67 | test: /(\.scss$|\.css$|\.sass$)/, 68 | use: [ 69 | { 70 | loader: 'style-loader' 71 | }, 72 | { 73 | loader: 'css-loader' 74 | }, 75 | { 76 | loader: 'sass-loader' 77 | } 78 | ] 79 | }, 80 | { 81 | test: /\.(woff(2)?|ttf|eot|svg)(\?v=\d+\.\d+\.\d+)?$/, 82 | loader: 'url-loader' 83 | } 84 | ] 85 | }, 86 | resolve: { 87 | alias: { 88 | vue: 'vue/dist/vue.js', 89 | src: SRC_PATH, 90 | components: path.join(SRC_PATH, '/components'), 91 | services: path.join(SRC_PATH, '/services'), 92 | utils: path.join(SRC_PATH, '/utils'), 93 | global: path.join(SRC_PATH, '/global'), 94 | store: path.join(SRC_PATH, '/store'), 95 | i18n: path.join(SRC_PATH, 'i18n') 96 | }, 97 | extensions: ['.js', '.scss', '.vue', '.json'] 98 | }, 99 | devServer: { 100 | before: function(app) { 101 | app.get('/contractData', function(req, res) { 102 | res.json(debugContractData); 103 | }); 104 | } 105 | } 106 | }; 107 | 108 | if (config.mode === 'production') { 109 | config.optimization = { 110 | minimizer: [ 111 | // we specify a custom UglifyJsPlugin here to get source maps in production 112 | new UglifyJsPlugin({ 113 | cache: true, 114 | parallel: true, 115 | uglifyOptions: { 116 | compress: false, 117 | ecma: 6, 118 | mangle: true 119 | }, 120 | sourceMap: false 121 | }) 122 | ] 123 | }; 124 | } 125 | 126 | module.exports = config; 127 | -------------------------------------------------------------------------------- /view/webpackConfig/plugins.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const HtmlWebpackPlugin = require('html-webpack-plugin'); 3 | // const HtmlWebpackInlineSourcePlugin = require('html-webpack-inline-source-plugin'); 4 | const VueLoaderPlugin = require('vue-loader/lib/plugin'); 5 | 6 | const TEMPLATE_PATH = path.join(__dirname, '../index.html'); 7 | 8 | let plugins = [ 9 | new HtmlWebpackPlugin({ 10 | title: 'Soliditypp Debugger', 11 | template: TEMPLATE_PATH, 12 | inlineSource: '.+' 13 | }), 14 | // new HtmlWebpackInlineSourcePlugin(), 15 | new VueLoaderPlugin() 16 | ]; 17 | 18 | module.exports = plugins; 19 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require("path"); 2 | const { CleanWebpackPlugin } = require("clean-webpack-plugin"); 3 | module.exports = { 4 | entry: path.resolve(__dirname, "src/extension.ts"), 5 | module: { 6 | rules: [ 7 | { 8 | test: /\.ts$/, 9 | use: { 10 | loader: "ts-loader" 11 | } 12 | } 13 | ] 14 | }, 15 | output: { 16 | path: path.resolve(__dirname, "out"), 17 | filename: "extension.js", 18 | libraryTarget: "commonjs2" 19 | }, 20 | resolve: { 21 | extensions: [".ts", ".js"] 22 | }, 23 | externals: { 24 | vscode: "commonjs vscode" 25 | }, 26 | plugins: [new CleanWebpackPlugin()], 27 | target: "node", 28 | node: { 29 | __dirname: false 30 | } 31 | }; 32 | --------------------------------------------------------------------------------