From 2b031603a679902540b43857ff98b0fb0fb3919b Mon Sep 17 00:00:00 2001 From: Aniket-Engg Date: Fri, 6 May 2022 14:12:47 +0530 Subject: [PATCH] default template in dir --- apps/remix-ide/webpack.config.js | 8 + .../workspace/src/lib/actions/workspace.ts | 2 +- .../src/lib/templates/remixDefault.ts | 406 ------------------ .../src/lib/templates/remixDefault/README.txt | 26 ++ .../remixDefault/contracts/1_Storage.sol | 29 ++ .../remixDefault/contracts/2_Owner.sol | 54 +++ .../remixDefault/contracts/3_Ballot.sol | 138 ++++++ .../src/lib/templates/remixDefault/index.ts | 13 + .../scripts/deploy_with_ethers.ts | 14 + .../remixDefault/scripts/deploy_with_web3.ts | 14 + .../templates/remixDefault/scripts/ethers.ts | 24 ++ .../templates/remixDefault/scripts/web3.ts | 24 ++ .../remixDefault/tests/Ballot_test.sol | 28 ++ .../remixDefault/tests/storage.test.js | 22 + 14 files changed, 395 insertions(+), 407 deletions(-) delete mode 100644 libs/remix-ui/workspace/src/lib/templates/remixDefault.ts create mode 100644 libs/remix-ui/workspace/src/lib/templates/remixDefault/README.txt create mode 100644 libs/remix-ui/workspace/src/lib/templates/remixDefault/contracts/1_Storage.sol create mode 100644 libs/remix-ui/workspace/src/lib/templates/remixDefault/contracts/2_Owner.sol create mode 100644 libs/remix-ui/workspace/src/lib/templates/remixDefault/contracts/3_Ballot.sol create mode 100644 libs/remix-ui/workspace/src/lib/templates/remixDefault/index.ts create mode 100644 libs/remix-ui/workspace/src/lib/templates/remixDefault/scripts/deploy_with_ethers.ts create mode 100644 libs/remix-ui/workspace/src/lib/templates/remixDefault/scripts/deploy_with_web3.ts create mode 100644 libs/remix-ui/workspace/src/lib/templates/remixDefault/scripts/ethers.ts create mode 100644 libs/remix-ui/workspace/src/lib/templates/remixDefault/scripts/web3.ts create mode 100644 libs/remix-ui/workspace/src/lib/templates/remixDefault/tests/Ballot_test.sol create mode 100644 libs/remix-ui/workspace/src/lib/templates/remixDefault/tests/storage.test.js diff --git a/apps/remix-ide/webpack.config.js b/apps/remix-ide/webpack.config.js index 529fe58d39..c1c806505d 100644 --- a/apps/remix-ide/webpack.config.js +++ b/apps/remix-ide/webpack.config.js @@ -3,6 +3,7 @@ const TerserPlugin = require('terser-webpack-plugin') const CopyWebpackPlugin = require('copy-webpack-plugin') const version = require('../../package.json').version const fs = require('fs') +const path = require('path') const versionData = { version: version, @@ -14,6 +15,13 @@ fs.writeFileSync('./apps/remix-ide/src/assets/version.json', JSON.stringify(vers module.exports = config => { const nxWebpackConfig = nxWebpack(config) + + nxWebpackConfig.module.rules.push({ test: /\.txt$/, use: 'raw-loader' }) + nxWebpackConfig.module.rules.push({ test: /\.sol$/, use: 'raw-loader' }) + nxWebpackConfig.module.rules.push({ test: /\.test\.js$/, use: 'raw-loader' }) + nxWebpackConfig.module.rules.push({ test: /\web3.ts$/, use: 'raw-loader' }) + nxWebpackConfig.module.rules.push({ test: /\ethers.ts$/, use: 'raw-loader' }) + const webpackConfig = { ...nxWebpackConfig, node: { diff --git a/libs/remix-ui/workspace/src/lib/actions/workspace.ts b/libs/remix-ui/workspace/src/lib/actions/workspace.ts index ccde0a4ff8..724db395cd 100644 --- a/libs/remix-ui/workspace/src/lib/actions/workspace.ts +++ b/libs/remix-ui/workspace/src/lib/actions/workspace.ts @@ -157,7 +157,7 @@ export const loadWorkspacePreset = async (template: WorkspaceTemplate = 'remixDe const files = templateWithContent[template] for (const file in files) { try { - await workspaceProvider.set(files[file].name, files[file].content) + await workspaceProvider.set(file, files[file]) } catch (error) { console.error(error) } diff --git a/libs/remix-ui/workspace/src/lib/templates/remixDefault.ts b/libs/remix-ui/workspace/src/lib/templates/remixDefault.ts deleted file mode 100644 index 8b596ec049..0000000000 --- a/libs/remix-ui/workspace/src/lib/templates/remixDefault.ts +++ /dev/null @@ -1,406 +0,0 @@ -'use strict' - -const storage = `// SPDX-License-Identifier: GPL-3.0 - -pragma solidity >=0.7.0 <0.9.0; - -/** - * @title Storage - * @dev Store & retrieve value in a variable - * @custom:dev-run-script ./scripts/deploy_with_ethers.ts - */ -contract Storage { - - uint256 number; - - /** - * @dev Store value in variable - * @param num value to store - */ - function store(uint256 num) public { - number = num; - } - - /** - * @dev Return value - * @return value of 'number' - */ - function retrieve() public view returns (uint256){ - return number; - } -}` - -const owner = `// SPDX-License-Identifier: GPL-3.0 - -pragma solidity >=0.7.0 <0.9.0; - -import "hardhat/console.sol"; - -/** - * @title Owner - * @dev Set & change owner - */ -contract Owner { - - address private owner; - - // event for EVM logging - event OwnerSet(address indexed oldOwner, address indexed newOwner); - - // modifier to check if caller is owner - modifier isOwner() { - // If the first argument of 'require' evaluates to 'false', execution terminates and all - // changes to the state and to Ether balances are reverted. - // This used to consume all gas in old EVM versions, but not anymore. - // It is often a good idea to use 'require' to check if functions are called correctly. - // As a second argument, you can also provide an explanation about what went wrong. - require(msg.sender == owner, "Caller is not owner"); - _; - } - - /** - * @dev Set contract deployer as owner - */ - constructor() { - console.log("Owner contract deployed by:", msg.sender); - owner = msg.sender; // 'msg.sender' is sender of current call, contract deployer for a constructor - emit OwnerSet(address(0), owner); - } - - /** - * @dev Change owner - * @param newOwner address of new owner - */ - function changeOwner(address newOwner) public isOwner { - emit OwnerSet(owner, newOwner); - owner = newOwner; - } - - /** - * @dev Return owner address - * @return address of owner - */ - function getOwner() external view returns (address) { - return owner; - } -}` - -const ballot = `// SPDX-License-Identifier: GPL-3.0 - -pragma solidity >=0.7.0 <0.9.0; - -/** - * @title Ballot - * @dev Implements voting process along with vote delegation - */ -contract Ballot { - - struct Voter { - uint weight; // weight is accumulated by delegation - bool voted; // if true, that person already voted - address delegate; // person delegated to - uint vote; // index of the voted proposal - } - - struct Proposal { - // If you can limit the length to a certain number of bytes, - // always use one of bytes1 to bytes32 because they are much cheaper - bytes32 name; // short name (up to 32 bytes) - uint voteCount; // number of accumulated votes - } - - address public chairperson; - - mapping(address => Voter) public voters; - - Proposal[] public proposals; - - /** - * @dev Create a new ballot to choose one of 'proposalNames'. - * @param proposalNames names of proposals - */ - constructor(bytes32[] memory proposalNames) { - chairperson = msg.sender; - voters[chairperson].weight = 1; - - for (uint i = 0; i < proposalNames.length; i++) { - // 'Proposal({...})' creates a temporary - // Proposal object and 'proposals.push(...)' - // appends it to the end of 'proposals'. - proposals.push(Proposal({ - name: proposalNames[i], - voteCount: 0 - })); - } - } - - /** - * @dev Give 'voter' the right to vote on this ballot. May only be called by 'chairperson'. - * @param voter address of voter - */ - function giveRightToVote(address voter) public { - require( - msg.sender == chairperson, - "Only chairperson can give right to vote." - ); - require( - !voters[voter].voted, - "The voter already voted." - ); - require(voters[voter].weight == 0); - voters[voter].weight = 1; - } - - /** - * @dev Delegate your vote to the voter 'to'. - * @param to address to which vote is delegated - */ - function delegate(address to) public { - Voter storage sender = voters[msg.sender]; - require(!sender.voted, "You already voted."); - require(to != msg.sender, "Self-delegation is disallowed."); - - while (voters[to].delegate != address(0)) { - to = voters[to].delegate; - - // We found a loop in the delegation, not allowed. - require(to != msg.sender, "Found loop in delegation."); - } - sender.voted = true; - sender.delegate = to; - Voter storage delegate_ = voters[to]; - if (delegate_.voted) { - // If the delegate already voted, - // directly add to the number of votes - proposals[delegate_.vote].voteCount += sender.weight; - } else { - // If the delegate did not vote yet, - // add to her weight. - delegate_.weight += sender.weight; - } - } - - /** - * @dev Give your vote (including votes delegated to you) to proposal 'proposals[proposal].name'. - * @param proposal index of proposal in the proposals array - */ - function vote(uint proposal) public { - Voter storage sender = voters[msg.sender]; - require(sender.weight != 0, "Has no right to vote"); - require(!sender.voted, "Already voted."); - sender.voted = true; - sender.vote = proposal; - - // If 'proposal' is out of the range of the array, - // this will throw automatically and revert all - // changes. - proposals[proposal].voteCount += sender.weight; - } - - /** - * @dev Computes the winning proposal taking all previous votes into account. - * @return winningProposal_ index of winning proposal in the proposals array - */ - function winningProposal() public view - returns (uint winningProposal_) - { - uint winningVoteCount = 0; - for (uint p = 0; p < proposals.length; p++) { - if (proposals[p].voteCount > winningVoteCount) { - winningVoteCount = proposals[p].voteCount; - winningProposal_ = p; - } - } - } - - /** - * @dev Calls winningProposal() function to get the index of the winner contained in the proposals array and then - * @return winnerName_ the name of the winner - */ - function winnerName() public view - returns (bytes32 winnerName_) - { - winnerName_ = proposals[winningProposal()].name; - } -} -` - -const ballotTest = `// SPDX-License-Identifier: GPL-3.0 - -pragma solidity >=0.7.0 <0.9.0; -import "remix_tests.sol"; // this import is automatically injected by Remix. -import "hardhat/console.sol"; -import "../contracts/3_Ballot.sol"; - -contract BallotTest { - - bytes32[] proposalNames; - - Ballot ballotToTest; - function beforeAll () public { - proposalNames.push(bytes32("candidate1")); - ballotToTest = new Ballot(proposalNames); - } - - function checkWinningProposal () public { - console.log("Running checkWinningProposal"); - ballotToTest.vote(0); - Assert.equal(ballotToTest.winningProposal(), uint(0), "proposal at index 0 should be the winning proposal"); - Assert.equal(ballotToTest.winnerName(), bytes32("candidate1"), "candidate1 should be the winner name"); - } - - function checkWinninProposalWithReturnValue () public view returns (bool) { - return ballotToTest.winningProposal() == 0; - } -} -` - -/* eslint-disable no-useless-escape */ -const deployWithWeb3 = ` -// This script can be used to deploy the "Storage" contract using Web3 library. -// Please make sure to compile "./contracts/1_Storage.sol" file before running this script. -// And use Right click -> "Run" from context menu of the file to run the script. Shortcut: Ctrl+Shift+S - -import { deploy } from './web3.ts' - -(async () => { - try { - const result = await deploy('Storage', []) - console.log(\`address: \${result.address\}\`) - } catch (e) { - console.log(e.message) - } -})()` - -const deployWithEthers = ` -// This script can be used to deploy the "Storage" contract using ethers.js library. -// Please make sure to compile "./contracts/1_Storage.sol" file before running this script. -// And use Right click -> "Run" from context menu of the file to run the script. Shortcut: Ctrl+Shift+S - -import { deploy } from './ethers.ts' - -(async () => { - try { - const result = await deploy('Storage', []) - console.log(\`address: \${result.address\}\`) - } catch (e) { - console.log(e.message) - } - })()` - -const libWeb3 = ` -export const deploy = async (contractName: string, arguments: Array, from?: string, gas?: number) => { - - console.log(\`deploying \${contractName\}\`) - // Note that the script needs the ABI which is generated from the compilation artifact. - // Make sure contract is compiled and artifacts are generated - const artifactsPath = \`browser/contracts/artifacts/\${contractName\}.json\` // Change this for different path - - const metadata = JSON.parse(await remix.call('fileManager', 'getFile', artifactsPath)) - - const accounts = await web3.eth.getAccounts() - - let contract = new web3.eth.Contract(metadata.abi) - - contract = contract.deploy({ - data: metadata.data.bytecode.object, - arguments - }) - - const newContractInstance = await contract.send({ - from: from || accounts[0], - gas: gas || 1500000 - }) - return newContractInstance.options -}: Promise` - -const libEthers = ` -export const deploy = async (contractName: string, arguments: Array, from?: string) => { - - console.log(\`deploying \${contractName\}\`) - // Note that the script needs the ABI which is generated from the compilation artifact. - // Make sure contract is compiled and artifacts are generated - const artifactsPath = \`browser/contracts/artifacts/\${contractName\}.json\` // Change this for different path - - const metadata = JSON.parse(await remix.call('fileManager', 'getFile', artifactsPath)) - // 'web3Provider' is a remix global variable object - const signer = (new ethers.providers.Web3Provider(web3Provider)).getSigner() - - let factory = new ethers.ContractFactory(metadata.abi, metadata.data.bytecode.object, signer); - - let contract - if (from) { - contract = await factory.connect(from).deploy(...arguments); - } else { - contract = await factory.deploy(...arguments); - } - - // The contract is NOT deployed yet; we must wait until it is mined - await contract.deployed() - return contract -}: Promise` -/* eslint-enable no-useless-escape */ - -const storageTestJs = `// Right click on the script name and hit "Run" to execute -const { expect } = require("chai"); -const { ethers } = require("hardhat"); - -describe("Storage", function () { - it("test initial value", async function () { - const Storage = await ethers.getContractFactory("Storage"); - const storage = await Storage.deploy(); - await storage.deployed(); - console.log('storage deployed at:'+ storage.address) - expect((await storage.retrieve()).toNumber()).to.equal(0); - }); - it("test updating and retrieving updated value", async function () { - const Storage = await ethers.getContractFactory("Storage"); - const storage = await Storage.deploy(); - await storage.deployed(); - const storage2 = await ethers.getContractAt("Storage", storage.address); - const setValue = await storage2.store(56); - await setValue.wait(); - expect((await storage2.retrieve()).toNumber()).to.equal(56); - }); -});` - -const readme = `REMIX DEFAULT WORKSPACE - -Remix default workspace is present when: -i. Remix loads for the very first time -ii. A new workspace is created -iii. There are no files existing in the File Explorer - -This workspace contains 3 directories: - -1. 'contracts': Holds three contracts with different complexity level, denoted with number prefix in file name. -2. 'scripts': Holds two scripts to deploy a contract. It is explained below. -3. 'tests': Contains one Solidity test file for 'Ballot' contract & one JS test file for 'Storage' contract - -SCRIPTS - -The 'scripts' folder contains two example async/await scripts for deploying the 'Storage' contract. -For the deployment of any other contract, 'contractName' and 'constructorArgs' should be updated (along with other code if required). - -Also, there is a script containing some unit tests for Storage contract inside tests directory. - -To run a script, right click on file name in the file explorer and click 'Run'. Remember, Solidity file must already be compiled. -Output from script will appear in remix terminal. - -Please note, 'require' statement is supported in a limited manner for Remix supported modules. -For now, modules supported by Remix are ethers, web3, swarmgw, chai, remix and hardhat only for hardhat.ethers object/plugin. -For unsupported modules, an error like this will be thrown: ' module require is not supported by Remix IDE will be shown.' -` - -export default { - storage: { name: 'contracts/1_Storage.sol', content: storage }, - owner: { name: 'contracts/2_Owner.sol', content: owner }, - ballot: { name: 'contracts/3_Ballot.sol', content: ballot }, - storageTestJs: { name: 'tests/storage.test.js', content: storageTestJs }, - ballot_test: { name: 'tests/Ballot_test.sol', content: ballotTest }, - deployWithWeb3: { name: 'scripts/deploy_with_web3.ts', content: deployWithWeb3 }, - deployWithEthers: { name: 'scripts/deploy_with_ethers.ts', content: deployWithEthers }, - web3: { name: 'scripts/web3.ts', content: libWeb3 }, - ethers: { name: 'scripts/ethers.ts', content: libEthers }, - readme: { name: 'README.txt', content: readme } -} diff --git a/libs/remix-ui/workspace/src/lib/templates/remixDefault/README.txt b/libs/remix-ui/workspace/src/lib/templates/remixDefault/README.txt new file mode 100644 index 0000000000..a71c4dc2d0 --- /dev/null +++ b/libs/remix-ui/workspace/src/lib/templates/remixDefault/README.txt @@ -0,0 +1,26 @@ +REMIX DEFAULT WORKSPACE + +Remix default workspace is present when: +i. Remix loads for the very first time +ii. A new workspace is created +iii. There are no files existing in the File Explorer + +This workspace contains 3 directories: + +1. 'contracts': Holds three contracts with different complexity level, denoted with number prefix in file name. +2. 'scripts': Holds two scripts to deploy a contract. It is explained below. +3. 'tests': Contains one Solidity test file for 'Ballot' contract & one JS test file for 'Storage' contract + +SCRIPTS + +The 'scripts' folder contains two example async/await scripts for deploying the 'Storage' contract. +For the deployment of any other contract, 'contractName' and 'constructorArgs' should be updated (along with other code if required). + +Also, there is a script containing some unit tests for Storage contract inside tests directory. + +To run a script, right click on file name in the file explorer and click 'Run'. Remember, Solidity file must already be compiled. +Output from script will appear in remix terminal. + +Please note, 'require' statement is supported in a limited manner for Remix supported modules. +For now, modules supported by Remix are ethers, web3, swarmgw, chai, remix and hardhat only for hardhat.ethers object/plugin. +For unsupported modules, an error like this will be thrown: ' module require is not supported by Remix IDE will be shown.' diff --git a/libs/remix-ui/workspace/src/lib/templates/remixDefault/contracts/1_Storage.sol b/libs/remix-ui/workspace/src/lib/templates/remixDefault/contracts/1_Storage.sol new file mode 100644 index 0000000000..6aa93223af --- /dev/null +++ b/libs/remix-ui/workspace/src/lib/templates/remixDefault/contracts/1_Storage.sol @@ -0,0 +1,29 @@ +// SPDX-License-Identifier: GPL-3.0 + +pragma solidity >=0.7.0 <0.9.0; + +/** + * @title Storage + * @dev Store & retrieve value in a variable + * @custom:dev-run-script ./scripts/deploy_with_ethers.ts + */ +contract Storage { + + uint256 number; + + /** + * @dev Store value in variable + * @param num value to store + */ + function store(uint256 num) public { + number = num; + } + + /** + * @dev Return value + * @return value of 'number' + */ + function retrieve() public view returns (uint256){ + return number; + } +} \ No newline at end of file diff --git a/libs/remix-ui/workspace/src/lib/templates/remixDefault/contracts/2_Owner.sol b/libs/remix-ui/workspace/src/lib/templates/remixDefault/contracts/2_Owner.sol new file mode 100644 index 0000000000..e6bc652c0f --- /dev/null +++ b/libs/remix-ui/workspace/src/lib/templates/remixDefault/contracts/2_Owner.sol @@ -0,0 +1,54 @@ +// SPDX-License-Identifier: GPL-3.0 + +pragma solidity >=0.7.0 <0.9.0; + +import "hardhat/console.sol"; + +/** + * @title Owner + * @dev Set & change owner + */ +contract Owner { + + address private owner; + + // event for EVM logging + event OwnerSet(address indexed oldOwner, address indexed newOwner); + + // modifier to check if caller is owner + modifier isOwner() { + // If the first argument of 'require' evaluates to 'false', execution terminates and all + // changes to the state and to Ether balances are reverted. + // This used to consume all gas in old EVM versions, but not anymore. + // It is often a good idea to use 'require' to check if functions are called correctly. + // As a second argument, you can also provide an explanation about what went wrong. + require(msg.sender == owner, "Caller is not owner"); + _; + } + + /** + * @dev Set contract deployer as owner + */ + constructor() { + console.log("Owner contract deployed by:", msg.sender); + owner = msg.sender; // 'msg.sender' is sender of current call, contract deployer for a constructor + emit OwnerSet(address(0), owner); + } + + /** + * @dev Change owner + * @param newOwner address of new owner + */ + function changeOwner(address newOwner) public isOwner { + emit OwnerSet(owner, newOwner); + owner = newOwner; + } + + /** + * @dev Return owner address + * @return address of owner + */ + function getOwner() external view returns (address) { + return owner; + } +} \ No newline at end of file diff --git a/libs/remix-ui/workspace/src/lib/templates/remixDefault/contracts/3_Ballot.sol b/libs/remix-ui/workspace/src/lib/templates/remixDefault/contracts/3_Ballot.sol new file mode 100644 index 0000000000..09fab7bc15 --- /dev/null +++ b/libs/remix-ui/workspace/src/lib/templates/remixDefault/contracts/3_Ballot.sol @@ -0,0 +1,138 @@ +// SPDX-License-Identifier: GPL-3.0 + +pragma solidity >=0.7.0 <0.9.0; + +/** + * @title Ballot + * @dev Implements voting process along with vote delegation + */ +contract Ballot { + + struct Voter { + uint weight; // weight is accumulated by delegation + bool voted; // if true, that person already voted + address delegate; // person delegated to + uint vote; // index of the voted proposal + } + + struct Proposal { + // If you can limit the length to a certain number of bytes, + // always use one of bytes1 to bytes32 because they are much cheaper + bytes32 name; // short name (up to 32 bytes) + uint voteCount; // number of accumulated votes + } + + address public chairperson; + + mapping(address => Voter) public voters; + + Proposal[] public proposals; + + /** + * @dev Create a new ballot to choose one of 'proposalNames'. + * @param proposalNames names of proposals + */ + constructor(bytes32[] memory proposalNames) { + chairperson = msg.sender; + voters[chairperson].weight = 1; + + for (uint i = 0; i < proposalNames.length; i++) { + // 'Proposal({...})' creates a temporary + // Proposal object and 'proposals.push(...)' + // appends it to the end of 'proposals'. + proposals.push(Proposal({ + name: proposalNames[i], + voteCount: 0 + })); + } + } + + /** + * @dev Give 'voter' the right to vote on this ballot. May only be called by 'chairperson'. + * @param voter address of voter + */ + function giveRightToVote(address voter) public { + require( + msg.sender == chairperson, + "Only chairperson can give right to vote." + ); + require( + !voters[voter].voted, + "The voter already voted." + ); + require(voters[voter].weight == 0); + voters[voter].weight = 1; + } + + /** + * @dev Delegate your vote to the voter 'to'. + * @param to address to which vote is delegated + */ + function delegate(address to) public { + Voter storage sender = voters[msg.sender]; + require(!sender.voted, "You already voted."); + require(to != msg.sender, "Self-delegation is disallowed."); + + while (voters[to].delegate != address(0)) { + to = voters[to].delegate; + + // We found a loop in the delegation, not allowed. + require(to != msg.sender, "Found loop in delegation."); + } + sender.voted = true; + sender.delegate = to; + Voter storage delegate_ = voters[to]; + if (delegate_.voted) { + // If the delegate already voted, + // directly add to the number of votes + proposals[delegate_.vote].voteCount += sender.weight; + } else { + // If the delegate did not vote yet, + // add to her weight. + delegate_.weight += sender.weight; + } + } + + /** + * @dev Give your vote (including votes delegated to you) to proposal 'proposals[proposal].name'. + * @param proposal index of proposal in the proposals array + */ + function vote(uint proposal) public { + Voter storage sender = voters[msg.sender]; + require(sender.weight != 0, "Has no right to vote"); + require(!sender.voted, "Already voted."); + sender.voted = true; + sender.vote = proposal; + + // If 'proposal' is out of the range of the array, + // this will throw automatically and revert all + // changes. + proposals[proposal].voteCount += sender.weight; + } + + /** + * @dev Computes the winning proposal taking all previous votes into account. + * @return winningProposal_ index of winning proposal in the proposals array + */ + function winningProposal() public view + returns (uint winningProposal_) + { + uint winningVoteCount = 0; + for (uint p = 0; p < proposals.length; p++) { + if (proposals[p].voteCount > winningVoteCount) { + winningVoteCount = proposals[p].voteCount; + winningProposal_ = p; + } + } + } + + /** + * @dev Calls winningProposal() function to get the index of the winner contained in the proposals array and then + * @return winnerName_ the name of the winner + */ + function winnerName() public view + returns (bytes32 winnerName_) + { + winnerName_ = proposals[winningProposal()].name; + } +} \ No newline at end of file diff --git a/libs/remix-ui/workspace/src/lib/templates/remixDefault/index.ts b/libs/remix-ui/workspace/src/lib/templates/remixDefault/index.ts new file mode 100644 index 0000000000..7140e4a49a --- /dev/null +++ b/libs/remix-ui/workspace/src/lib/templates/remixDefault/index.ts @@ -0,0 +1,13 @@ +export default { + 'contracts/1_Storage.sol': require('./contracts/1_Storage.sol').default, + 'contracts/2_Owner.sol': require('./contracts/2_Owner.sol').default, + 'contracts/3_Ballot.sol': require('./contracts/3_Ballot.sol').default, + 'scripts/deploy_with_ethers.ts': require('./scripts/deploy_with_ethers.ts').default, + 'scripts/deploy_with_web3.ts': require('./scripts/deploy_with_web3.ts').default, + 'scripts/ethers.ts': require('./scripts/ethers.ts').default, + 'scripts/web3.ts': require('./scripts/web3.ts').default, + 'tests/Ballot_test.sol': require('./tests/Ballot_test.sol').default, + 'tests/storage.test.js': require('./tests/storage.test.js').default, + 'README.txt': require('./README.txt').default, + +} \ No newline at end of file diff --git a/libs/remix-ui/workspace/src/lib/templates/remixDefault/scripts/deploy_with_ethers.ts b/libs/remix-ui/workspace/src/lib/templates/remixDefault/scripts/deploy_with_ethers.ts new file mode 100644 index 0000000000..2166c05842 --- /dev/null +++ b/libs/remix-ui/workspace/src/lib/templates/remixDefault/scripts/deploy_with_ethers.ts @@ -0,0 +1,14 @@ +// This script can be used to deploy the "Storage" contract using ethers.js library. +// Please make sure to compile "./contracts/1_Storage.sol" file before running this script. +// And use Right click -> "Run" from context menu of the file to run the script. Shortcut: Ctrl+Shift+S + +import { deploy } from './ethers.ts' + +(async () => { + try { + const result = await deploy('Storage', []) + console.log(`address: ${result.address}`) + } catch (e) { + console.log(e.message) + } + })() \ No newline at end of file diff --git a/libs/remix-ui/workspace/src/lib/templates/remixDefault/scripts/deploy_with_web3.ts b/libs/remix-ui/workspace/src/lib/templates/remixDefault/scripts/deploy_with_web3.ts new file mode 100644 index 0000000000..d6fc672929 --- /dev/null +++ b/libs/remix-ui/workspace/src/lib/templates/remixDefault/scripts/deploy_with_web3.ts @@ -0,0 +1,14 @@ +// This script can be used to deploy the "Storage" contract using Web3 library. +// Please make sure to compile "./contracts/1_Storage.sol" file before running this script. +// And use Right click -> "Run" from context menu of the file to run the script. Shortcut: Ctrl+Shift+S + +import { deploy } from './web3.ts' + +(async () => { + try { + const result = await deploy('Storage', []) + console.log(`address: ${result.address}`) + } catch (e) { + console.log(e.message) + } +})() \ No newline at end of file diff --git a/libs/remix-ui/workspace/src/lib/templates/remixDefault/scripts/ethers.ts b/libs/remix-ui/workspace/src/lib/templates/remixDefault/scripts/ethers.ts new file mode 100644 index 0000000000..be75c474c3 --- /dev/null +++ b/libs/remix-ui/workspace/src/lib/templates/remixDefault/scripts/ethers.ts @@ -0,0 +1,24 @@ +export const deploy = async (contractName: string, args: Array, from?: string): Promise => { + + console.log(`deploying ${contractName}`) + // Note that the script needs the ABI which is generated from the compilation artifact. + // Make sure contract is compiled and artifacts are generated + const artifactsPath = `browser/contracts/artifacts/${contractName}.json` // Change this for different path + + const metadata = JSON.parse(await remix.call('fileManager', 'getFile', artifactsPath)) + // 'web3Provider' is a remix global variable object + const signer = (new ethers.providers.Web3Provider(web3Provider)).getSigner() + + let factory = new ethers.ContractFactory(metadata.abi, metadata.data.bytecode.object, signer); + + let contract + if (from) { + contract = await factory.connect(from).deploy(...args); + } else { + contract = await factory.deploy(...arguments); + } + + // The contract is NOT deployed yet; we must wait until it is mined + await contract.deployed() + return contract +} \ No newline at end of file diff --git a/libs/remix-ui/workspace/src/lib/templates/remixDefault/scripts/web3.ts b/libs/remix-ui/workspace/src/lib/templates/remixDefault/scripts/web3.ts new file mode 100644 index 0000000000..7b9ee72236 --- /dev/null +++ b/libs/remix-ui/workspace/src/lib/templates/remixDefault/scripts/web3.ts @@ -0,0 +1,24 @@ +export const deploy = async (contractName: string, args: Array, from?: string, gas?: number): Promise => { + + console.log(`deploying ${contractName}`) + // Note that the script needs the ABI which is generated from the compilation artifact. + // Make sure contract is compiled and artifacts are generated + const artifactsPath = `browser/contracts/artifacts/${contractName}.json` // Change this for different path + + const metadata = JSON.parse(await remix.call('fileManager', 'getFile', artifactsPath)) + + const accounts = await web3.eth.getAccounts() + + let contract = new web3.eth.Contract(metadata.abi) + + contract = contract.deploy({ + data: metadata.data.bytecode.object, + arguments: args + }) + + const newContractInstance = await contract.send({ + from: from || accounts[0], + gas: gas || 1500000 + }) + return newContractInstance.options +} \ No newline at end of file diff --git a/libs/remix-ui/workspace/src/lib/templates/remixDefault/tests/Ballot_test.sol b/libs/remix-ui/workspace/src/lib/templates/remixDefault/tests/Ballot_test.sol new file mode 100644 index 0000000000..f3b81075f2 --- /dev/null +++ b/libs/remix-ui/workspace/src/lib/templates/remixDefault/tests/Ballot_test.sol @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: GPL-3.0 + +pragma solidity >=0.7.0 <0.9.0; +import "remix_tests.sol"; // this import is automatically injected by Remix. +import "hardhat/console.sol"; +import "../contracts/3_Ballot.sol"; + +contract BallotTest { + + bytes32[] proposalNames; + + Ballot ballotToTest; + function beforeAll () public { + proposalNames.push(bytes32("candidate1")); + ballotToTest = new Ballot(proposalNames); + } + + function checkWinningProposal () public { + console.log("Running checkWinningProposal"); + ballotToTest.vote(0); + Assert.equal(ballotToTest.winningProposal(), uint(0), "proposal at index 0 should be the winning proposal"); + Assert.equal(ballotToTest.winnerName(), bytes32("candidate1"), "candidate1 should be the winner name"); + } + + function checkWinninProposalWithReturnValue () public view returns (bool) { + return ballotToTest.winningProposal() == 0; + } +} \ No newline at end of file diff --git a/libs/remix-ui/workspace/src/lib/templates/remixDefault/tests/storage.test.js b/libs/remix-ui/workspace/src/lib/templates/remixDefault/tests/storage.test.js new file mode 100644 index 0000000000..aa14b35a00 --- /dev/null +++ b/libs/remix-ui/workspace/src/lib/templates/remixDefault/tests/storage.test.js @@ -0,0 +1,22 @@ +// Right click on the script name and hit "Run" to execute +const { expect } = require("chai"); +const { ethers } = require("hardhat"); + +describe("Storage", function () { + it("test initial value", async function () { + const Storage = await ethers.getContractFactory("Storage"); + const storage = await Storage.deploy(); + await storage.deployed(); + console.log('storage deployed at:'+ storage.address) + expect((await storage.retrieve()).toNumber()).to.equal(0); + }); + it("test updating and retrieving updated value", async function () { + const Storage = await ethers.getContractFactory("Storage"); + const storage = await Storage.deploy(); + await storage.deployed(); + const storage2 = await ethers.getContractAt("Storage", storage.address); + const setValue = await storage2.store(56); + await setValue.wait(); + expect((await storage2.retrieve()).toNumber()).to.equal(56); + }); +}); \ No newline at end of file