├── package.json ├── hardhat.config.js ├── .gitignore ├── scripts ├── deploy.js ├── getMessage.js └── setMessage.js ├── contracts └── Hello_swtr.sol ├── ignition └── modules │ └── Lock.js ├── loader.sh ├── README.md ├── test └── Lock.js └── swisstronik.sh /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "devDependencies": { 3 | "@nomicfoundation/hardhat-toolbox": "^5.0.0", 4 | "hardhat": "^2.22.6" 5 | }, 6 | "dependencies": { 7 | "@swisstronik/utils": "^1.3.0", 8 | "dotenv": "^16.4.5" 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /hardhat.config.js: -------------------------------------------------------------------------------- 1 | require("@nomicfoundation/hardhat-toolbox"); 2 | require("dotenv").config(); 3 | 4 | module.exports = { 5 | solidity: "0.8.19", 6 | networks: { 7 | swisstronik: { 8 | url: "https://json-rpc.testnet.swisstronik.com/", 9 | accounts: [`0x${process.env.PRIVATE_KEY}`], 10 | }, 11 | }, 12 | }; 13 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .env 3 | 4 | # Hardhat files 5 | /cache 6 | /artifacts 7 | 8 | # TypeChain files 9 | /typechain 10 | /typechain-types 11 | 12 | # solidity-coverage files 13 | /coverage 14 | /coverage.json 15 | 16 | # Hardhat Ignition default folder for deployments against a local node 17 | ignition/deployments/chain-31337 18 | -------------------------------------------------------------------------------- /scripts/deploy.js: -------------------------------------------------------------------------------- 1 | const hre = require("hardhat"); 2 | 3 | async function main() { 4 | const contract = await hre.ethers.deployContract("Swisstronik", ["Hello Swisstronik from Happy Cuan Airdrop!!"]); 5 | await contract.waitForDeployment(); 6 | console.log(`Swisstronik contract deployed to ${contract.target}`); 7 | } 8 | 9 | main().catch((error) => { 10 | console.error(error); 11 | process.exitCode = 1; 12 | }); 13 | -------------------------------------------------------------------------------- /contracts/Hello_swtr.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity ^0.8.19; 3 | 4 | contract Swisstronik { 5 | string private message; 6 | 7 | constructor(string memory _message) payable { 8 | message = _message; 9 | } 10 | 11 | function setMessage(string memory _message) public { 12 | message = _message; 13 | } 14 | 15 | function getMessage() public view returns(string memory) { 16 | return message; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /ignition/modules/Lock.js: -------------------------------------------------------------------------------- 1 | const { buildModule } = require("@nomicfoundation/hardhat-ignition/modules"); 2 | 3 | const JAN_1ST_2030 = 1893456000; 4 | const ONE_GWEI = 1_000_000_000n; 5 | 6 | module.exports = buildModule("LockModule", (m) => { 7 | const unlockTime = m.getParameter("unlockTime", JAN_1ST_2030); 8 | const lockedAmount = m.getParameter("lockedAmount", ONE_GWEI); 9 | 10 | const lock = m.contract("Lock", [unlockTime], { 11 | value: lockedAmount, 12 | }); 13 | 14 | return { lock }; 15 | }); 16 | -------------------------------------------------------------------------------- /loader.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | tput civis 3 | 4 | # Clear Line 5 | CL="\e[2K" 6 | # Spinner Character 7 | SPINNER="⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏" 8 | 9 | function spinner() { 10 | task=$1 11 | msg=$2 12 | while :; do 13 | jobs %1 > /dev/null 2>&1 14 | [ $? = 0 ] || { 15 | printf "${CL}✓ ${task} Done\n" 16 | break 17 | } 18 | for (( i=0; i<${#SPINNER}; i++ )); do 19 | sleep 0.05 20 | printf "${CL}${SPINNER:$i:1} ${task} ${msg}\r" 21 | done 22 | done 23 | } 24 | 25 | msg="${2-InProgress}" 26 | task="${3-$1}" 27 | $1 & spinner "$task" "$msg" 28 | 29 | tput cnorm 30 | 31 | # usage => ./loader.sh "" "" "" 32 | # e.g => ./loader.sh "sleep 5" "..." "Installing Dependencies" 33 | -------------------------------------------------------------------------------- /scripts/getMessage.js: -------------------------------------------------------------------------------- 1 | const hre = require("hardhat"); 2 | const { encryptDataField, decryptNodeResponse } = require("@swisstronik/utils"); 3 | 4 | const sendShieldedQuery = async (provider, destination, data) => { 5 | const rpclink = hre.network.config.url; 6 | const [encryptedData, usedEncryptedKey] = await encryptDataField(rpclink, data); 7 | const response = await provider.call({ 8 | to: destination, 9 | data: encryptedData, 10 | }); 11 | return await decryptNodeResponse(rpclink, response, usedEncryptedKey); 12 | }; 13 | 14 | async function main() { 15 | const contractAddress = "0xf84Df872D385997aBc28E3f07A2E3cd707c9698a"; 16 | const [signer] = await hre.ethers.getSigners(); 17 | const contractFactory = await hre.ethers.getContractFactory("Swisstronik"); 18 | const contract = contractFactory.attach(contractAddress); 19 | const functionName = "getMessage"; 20 | const responseMessage = await sendShieldedQuery(signer.provider, contractAddress, contract.interface.encodeFunctionData(functionName)); 21 | console.log("Decoded response:", contract.interface.decodeFunctionResult(functionName, responseMessage)[0]); 22 | } 23 | 24 | main().catch((error) => { 25 | console.error(error); 26 | process.exitCode = 1; 27 | }); 28 | -------------------------------------------------------------------------------- /scripts/setMessage.js: -------------------------------------------------------------------------------- 1 | const hre = require("hardhat"); 2 | const { encryptDataField, decryptNodeResponse } = require("@swisstronik/utils"); 3 | 4 | const sendShieldedTransaction = async (signer, destination, data, value) => { 5 | const rpclink = hre.network.config.url; 6 | const [encryptedData] = await encryptDataField(rpclink, data); 7 | return await signer.sendTransaction({ 8 | from: signer.address, 9 | to: destination, 10 | data: encryptedData, 11 | value, 12 | }); 13 | }; 14 | 15 | async function main() { 16 | const contractAddress = "0xf84Df872D385997aBc28E3f07A2E3cd707c9698a"; 17 | const [signer] = await hre.ethers.getSigners(); 18 | const contractFactory = await hre.ethers.getContractFactory("Swisstronik"); 19 | const contract = contractFactory.attach(contractAddress); 20 | const functionName = "setMessage"; 21 | const messageToSet = "Hello Swisstronik from Happy Cuan Airdrop!!"; 22 | const setMessageTx = await sendShieldedTransaction(signer, contractAddress, contract.interface.encodeFunctionData(functionName, [messageToSet]), 0); 23 | await setMessageTx.wait(); 24 | console.log("Transaction Receipt: ", setMessageTx); 25 | } 26 | 27 | main().catch((error) => { 28 | console.error(error); 29 | process.exitCode = 1; 30 | }); 31 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Swisstronik Testnet Task: Deploy a simple contract using Hardhat 2 | https://www.swisstronik.com/testnet2/dashboard# 3 | 4 | ## 1) Download and create a swisstronik wallet and get faucet in the task dashboard 5 | https://chromewebstore.google.com/detail/swisstronik/acfhdnikkbldnocbgmfginnmhjfkimjo?utm_team=devs_front&utm_channel&utm_lang=en&utm_date=45216 6 | 7 | ## 2) Setup Instructions 8 | 9 | 1. **Clone the Repository:** 10 | 11 | ```sh 12 | git clone https://github.com/dante4rt/swisstronik-testnet.git 13 | cd swisstronik-testnet 14 | ``` 15 | 16 | 2. **Run the Setup Script:** 17 | 18 | ```sh 19 | ./swisstronik.sh 20 | ``` 21 | 22 | 3. **Follow the Prompts:** 23 | 24 | - Enter your Swisstronik private key 25 | - Use the default directory (just press Enter). 26 | - Press **y** to confirm any prompts. 27 | 28 | 4. **Copy your Contract address** 29 | 30 | ![Screenshot_122](https://github.com/user-attachments/assets/146f84cb-c210-42bf-9066-2779e4d5e145) 31 | 32 | 33 | 5. **Upload your .sol contract file** 34 | 35 | - Create a repository in github 36 | - Create a new file and name it: `Hello_swtr.sol` 37 | - paste following code in it and save it 38 | ```sh 39 | // SPDX-License-Identifier: UNLICENSED 40 | pragma solidity ^0.8.19; 41 | 42 | contract Swisstronik { 43 | string private message; 44 | 45 | constructor(string memory _message) payable { 46 | message = _message; 47 | } 48 | 49 | function setMessage(string memory _message) public { 50 | message = _message; 51 | } 52 | 53 | function getMessage() public view returns(string memory) { 54 | return message; 55 | } 56 | ``` 57 | ## 3) Complete task: Deploy a simple contract using Hardhat 58 | **Submit your `Hello_swtr.sol github url` + `contract address`** 59 | 60 | https://www.swisstronik.com/testnet2/dashboard# 61 | -------------------------------------------------------------------------------- /test/Lock.js: -------------------------------------------------------------------------------- 1 | const { 2 | time, 3 | loadFixture, 4 | } = require("@nomicfoundation/hardhat-toolbox/network-helpers"); 5 | const { anyValue } = require("@nomicfoundation/hardhat-chai-matchers/withArgs"); 6 | const { expect } = require("chai"); 7 | 8 | describe("Lock", function () { 9 | // We define a fixture to reuse the same setup in every test. 10 | // We use loadFixture to run this setup once, snapshot that state, 11 | // and reset Hardhat Network to that snapshot in every test. 12 | async function deployOneYearLockFixture() { 13 | const ONE_YEAR_IN_SECS = 365 * 24 * 60 * 60; 14 | const ONE_GWEI = 1_000_000_000; 15 | 16 | const lockedAmount = ONE_GWEI; 17 | const unlockTime = (await time.latest()) + ONE_YEAR_IN_SECS; 18 | 19 | // Contracts are deployed using the first signer/account by default 20 | const [owner, otherAccount] = await ethers.getSigners(); 21 | 22 | const Lock = await ethers.getContractFactory("Lock"); 23 | const lock = await Lock.deploy(unlockTime, { value: lockedAmount }); 24 | 25 | return { lock, unlockTime, lockedAmount, owner, otherAccount }; 26 | } 27 | 28 | describe("Deployment", function () { 29 | it("Should set the right unlockTime", async function () { 30 | const { lock, unlockTime } = await loadFixture(deployOneYearLockFixture); 31 | 32 | expect(await lock.unlockTime()).to.equal(unlockTime); 33 | }); 34 | 35 | it("Should set the right owner", async function () { 36 | const { lock, owner } = await loadFixture(deployOneYearLockFixture); 37 | 38 | expect(await lock.owner()).to.equal(owner.address); 39 | }); 40 | 41 | it("Should receive and store the funds to lock", async function () { 42 | const { lock, lockedAmount } = await loadFixture( 43 | deployOneYearLockFixture 44 | ); 45 | 46 | expect(await ethers.provider.getBalance(lock.target)).to.equal( 47 | lockedAmount 48 | ); 49 | }); 50 | 51 | it("Should fail if the unlockTime is not in the future", async function () { 52 | // We don't use the fixture here because we want a different deployment 53 | const latestTime = await time.latest(); 54 | const Lock = await ethers.getContractFactory("Lock"); 55 | await expect(Lock.deploy(latestTime, { value: 1 })).to.be.revertedWith( 56 | "Unlock time should be in the future" 57 | ); 58 | }); 59 | }); 60 | 61 | describe("Withdrawals", function () { 62 | describe("Validations", function () { 63 | it("Should revert with the right error if called too soon", async function () { 64 | const { lock } = await loadFixture(deployOneYearLockFixture); 65 | 66 | await expect(lock.withdraw()).to.be.revertedWith( 67 | "You can't withdraw yet" 68 | ); 69 | }); 70 | 71 | it("Should revert with the right error if called from another account", async function () { 72 | const { lock, unlockTime, otherAccount } = await loadFixture( 73 | deployOneYearLockFixture 74 | ); 75 | 76 | // We can increase the time in Hardhat Network 77 | await time.increaseTo(unlockTime); 78 | 79 | // We use lock.connect() to send a transaction from another account 80 | await expect(lock.connect(otherAccount).withdraw()).to.be.revertedWith( 81 | "You aren't the owner" 82 | ); 83 | }); 84 | 85 | it("Shouldn't fail if the unlockTime has arrived and the owner calls it", async function () { 86 | const { lock, unlockTime } = await loadFixture( 87 | deployOneYearLockFixture 88 | ); 89 | 90 | // Transactions are sent using the first signer by default 91 | await time.increaseTo(unlockTime); 92 | 93 | await expect(lock.withdraw()).not.to.be.reverted; 94 | }); 95 | }); 96 | 97 | describe("Events", function () { 98 | it("Should emit an event on withdrawals", async function () { 99 | const { lock, unlockTime, lockedAmount } = await loadFixture( 100 | deployOneYearLockFixture 101 | ); 102 | 103 | await time.increaseTo(unlockTime); 104 | 105 | await expect(lock.withdraw()) 106 | .to.emit(lock, "Withdrawal") 107 | .withArgs(lockedAmount, anyValue); // We accept any value as `when` arg 108 | }); 109 | }); 110 | 111 | describe("Transfers", function () { 112 | it("Should transfer the funds to the owner", async function () { 113 | const { lock, unlockTime, lockedAmount, owner } = await loadFixture( 114 | deployOneYearLockFixture 115 | ); 116 | 117 | await time.increaseTo(unlockTime); 118 | 119 | await expect(lock.withdraw()).to.changeEtherBalances( 120 | [owner, lock], 121 | [lockedAmount, -lockedAmount] 122 | ); 123 | }); 124 | }); 125 | }); 126 | }); 127 | -------------------------------------------------------------------------------- /swisstronik.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | wget -O loader.sh https://raw.githubusercontent.com/DiscoverMyself/Ramanode-Guides/main/loader.sh && chmod +x loader.sh && ./loader.sh 4 | curl -s https://raw.githubusercontent.com/DiscoverMyself/Ramanode-Guides/main/logo.sh | bash 5 | sleep 4 6 | 7 | sudo apt-get update && sudo apt get upgrade -y 8 | clear 9 | 10 | echo "Installing Hardhat and dotenv..." 11 | npm install --save-dev hardhat 12 | npm install dotenv 13 | npm install @swisstronik/utils 14 | echo "Installation completed." 15 | 16 | echo "Creating a Hardhat project..." 17 | npx hardhat 18 | 19 | rm -f contracts/Lock.sol 20 | echo "Lock.sol removed." 21 | 22 | echo "Hardhat project created." 23 | 24 | echo "Installing Hardhat toolbox..." 25 | npm install --save-dev @nomicfoundation/hardhat-toolbox 26 | echo "Hardhat toolbox installed." 27 | 28 | echo "Creating .env file..." 29 | read -p "Enter your private key: " PRIVATE_KEY 30 | echo "PRIVATE_KEY=$PRIVATE_KEY" > .env 31 | echo ".env file created." 32 | 33 | echo "Configuring Hardhat..." 34 | cat < hardhat.config.js 35 | require("@nomicfoundation/hardhat-toolbox"); 36 | require("dotenv").config(); 37 | 38 | module.exports = { 39 | solidity: "0.8.19", 40 | networks: { 41 | swisstronik: { 42 | url: "https://json-rpc.testnet.swisstronik.com/", 43 | accounts: [\`0x\${process.env.PRIVATE_KEY}\`], 44 | }, 45 | }, 46 | }; 47 | EOL 48 | echo "Hardhat configuration completed." 49 | 50 | echo "Creating Hello_swtr.sol contract..." 51 | mkdir -p contracts 52 | cat < contracts/Hello_swtr.sol 53 | // SPDX-License-Identifier: UNLICENSED 54 | pragma solidity ^0.8.19; 55 | 56 | contract Swisstronik { 57 | string private message; 58 | 59 | constructor(string memory _message) payable { 60 | message = _message; 61 | } 62 | 63 | function setMessage(string memory _message) public { 64 | message = _message; 65 | } 66 | 67 | function getMessage() public view returns(string memory) { 68 | return message; 69 | } 70 | } 71 | EOL 72 | echo "Hello_swtr.sol contract created." 73 | 74 | echo "Compiling the contract..." 75 | npx hardhat compile 76 | echo "Contract compiled." 77 | 78 | echo "Creating deploy.js script..." 79 | mkdir -p scripts 80 | cat < scripts/deploy.js 81 | const hre = require("hardhat"); 82 | 83 | async function main() { 84 | const contract = await hre.ethers.deployContract("Swisstronik", ["Hello Swisstronik from Happy Cuan Airdrop!!"]); 85 | await contract.waitForDeployment(); 86 | console.log(\`Swisstronik contract deployed to \${contract.target}\`); 87 | } 88 | 89 | main().catch((error) => { 90 | console.error(error); 91 | process.exitCode = 1; 92 | }); 93 | EOL 94 | echo "deploy.js script created." 95 | 96 | echo "Deploying the contract..." 97 | npx hardhat run scripts/deploy.js --network swisstronik 98 | echo "Contract deployed." 99 | 100 | echo "Creating setMessage.js script..." 101 | cat < scripts/setMessage.js 102 | const hre = require("hardhat"); 103 | const { encryptDataField, decryptNodeResponse } = require("@swisstronik/utils"); 104 | 105 | const sendShieldedTransaction = async (signer, destination, data, value) => { 106 | const rpclink = hre.network.config.url; 107 | const [encryptedData] = await encryptDataField(rpclink, data); 108 | return await signer.sendTransaction({ 109 | from: signer.address, 110 | to: destination, 111 | data: encryptedData, 112 | value, 113 | }); 114 | }; 115 | 116 | async function main() { 117 | const contractAddress = "0xf84Df872D385997aBc28E3f07A2E3cd707c9698a"; 118 | const [signer] = await hre.ethers.getSigners(); 119 | const contractFactory = await hre.ethers.getContractFactory("Swisstronik"); 120 | const contract = contractFactory.attach(contractAddress); 121 | const functionName = "setMessage"; 122 | const messageToSet = "Hello Swisstronik from Happy Cuan Airdrop!!"; 123 | const setMessageTx = await sendShieldedTransaction(signer, contractAddress, contract.interface.encodeFunctionData(functionName, [messageToSet]), 0); 124 | await setMessageTx.wait(); 125 | console.log("Transaction Receipt: ", setMessageTx); 126 | } 127 | 128 | main().catch((error) => { 129 | console.error(error); 130 | process.exitCode = 1; 131 | }); 132 | EOL 133 | echo "setMessage.js script created." 134 | 135 | echo "Running setMessage.js..." 136 | npx hardhat run scripts/setMessage.js --network swisstronik 137 | echo "Message set." 138 | 139 | echo "Creating getMessage.js script..." 140 | cat < scripts/getMessage.js 141 | const hre = require("hardhat"); 142 | const { encryptDataField, decryptNodeResponse } = require("@swisstronik/utils"); 143 | 144 | const sendShieldedQuery = async (provider, destination, data) => { 145 | const rpclink = hre.network.config.url; 146 | const [encryptedData, usedEncryptedKey] = await encryptDataField(rpclink, data); 147 | const response = await provider.call({ 148 | to: destination, 149 | data: encryptedData, 150 | }); 151 | return await decryptNodeResponse(rpclink, response, usedEncryptedKey); 152 | }; 153 | 154 | async function main() { 155 | const contractAddress = "0xf84Df872D385997aBc28E3f07A2E3cd707c9698a"; 156 | const [signer] = await hre.ethers.getSigners(); 157 | const contractFactory = await hre.ethers.getContractFactory("Swisstronik"); 158 | const contract = contractFactory.attach(contractAddress); 159 | const functionName = "getMessage"; 160 | const responseMessage = await sendShieldedQuery(signer.provider, contractAddress, contract.interface.encodeFunctionData(functionName)); 161 | console.log("Decoded response:", contract.interface.decodeFunctionResult(functionName, responseMessage)[0]); 162 | } 163 | 164 | main().catch((error) => { 165 | console.error(error); 166 | process.exitCode = 1; 167 | }); 168 | EOL 169 | echo "getMessage.js script created." 170 | 171 | echo "Running getMessage.js..." 172 | npx hardhat run scripts/getMessage.js --network swisstronik 173 | echo "Message retrieved." 174 | echo "Done! Subscribe: https://t.me/HappyCuanAirdrop" --------------------------------------------------------------------------------