paint-brush
Solidity スマート コントラクトを作成して Ropsten にデプロイする方法@johnjvester
679 測定値
679 測定値

Solidity スマート コントラクトを作成して Ropsten にデプロイする方法

John Vester35m2022/08/05
Read on Terminal Reader
Read this story w/o Javascript

長すぎる; 読むには

スマート コントラクトでは、2 つの当事者が契約を結ぶことができます。スマート コントラクトを深く掘り下げて、単一のコントラクトを何度も再利用する方法を示します。

People Mentioned

Mention Thumbnail
Mention Thumbnail

Companies Mentioned

Mention Thumbnail
Mention Thumbnail

Coin Mentioned

Mention Thumbnail
featured image - Solidity スマート コントラクトを作成して Ropsten にデプロイする方法
John Vester HackerNoon profile picture


フルスタック開発者から Web3 パイオニアへの移行」の出版物は、フルスタックの開発者が Web3 開発の世界を垣間見ることができるように、高レベルの概要を提供しました。その記事を確認する機会がなかった場合は、Web3 の優れた紹介も提供しているため、一読することを検討してください。


私の最初の記事の最終結果は、住宅所有者協会 (HOA) が Web3 テクノロジーを使用して選挙投票用紙をホストする方法を示しました。元の設計の問題は、基礎となるスマート コントラクトが 1 つの「はい」または「いいえ」の回答しか許可されていなかったことです。これは、Web3 テクノロジを使用して HOA 投票を作成するために必要な他の概念を導入しながら、スマート コントラクトをシンプルに保つための設計によるものです。


この出版物の目的は、スマート コントラクトを深く掘り下げて、HOA 投票の現実的なニーズと機能を捉えるだけでなく、選挙ごとに再利用できるものを設計するアプリケーションを構築することです。

スマートコントラクトについて

始める前に、スマート コントラクトを定義しましょう。

「スマートコントラクトは、イーサリアム上のアドレスで実行されるプログラムです。それらは、トランザクションの受信時に実行できるデータと機能で構成されています。これがスマートコントラクトを構成するものの概要です。」


ソースethereum.org


ガムボールマシン

信じられないかもしれませんが、スマート コントラクトの簡単な例として、単純なガムボール マシンがあります。


ガムボール マシンの購入にかかるコストを簡単に理解できます。通常、これは (米国) 四半期です。ここで重要なことは、顧客が匿名であることです。なぜなら、ガムボール マシンは、香ばしいガムを顧客に渡す前に、顧客が誰であるかを知る必要がないからです。


匿名の消費者は、通貨をガムボール マシンに入れ、ダイヤルを回して契約条件を受け入れます。トランザクションは透過的でピアツーピアであるため、この手順は重要です。つまり、ユーザーとマシンの間です。ガムボール マシンを使用するには、予想される通貨を提供する必要があるため、トランザクションも保護されます。


通貨がガムボール マシン内に落ちると、契約条件が受け入れられ、ガムボールがマシンの底に向かって転がり、顧客は購入品を受け取ることができます。この時点で、契約は完全に実行されます。


つまり、ガムボールを返却したり、ダイヤルを逆にして通貨を取り戻すことはできません。同様に、スマート コントラクトは通常、元に戻すことも変更することもできません。

スマート コントラクトのユース ケース

金融主導の例は別として、元に戻すことも変更することもできない、匿名、トラストレス、分散型、透明性のあるやり取りを実装できるいくつかのシナリオを以下に示します。

  • 臨床試験 - 独立した試験の結果
  • 選挙 - 投票参加者
  • アイデンティティ - 個人が自分のアイデンティティを誰と共有するかを決定できるようにします
  • 保険証券 - 個々の保険証券と条件
  • 製品と供給の追跡 - 生産と供給の追跡のためのステータス追跡
  • 不動産および土地 - 不動産および土地に関連する証書。いつでも現在の所有者を導き出すために使用できます。
  • 記録情報 - 公式記録と写し (ゲティスバーグの住所)


いずれの場合も、スマート コントラクトの内容は、結果を変更または修正することなく、できるだけ頻繁に呼び出して確認できます。上記の各ユース ケースは、基になる情報の記録システムとしてスマート コントラクトを提供します。

スマートコントラクトではないもの

現時点では、いくつかの例外を除いて、スマート コントラクトは法的拘束力のある契約ではありません。これは、スマート コントラクトの結果に満足できない場合、法廷システムの裁判官に問題を提起することは不可能であることを意味します。

スマート コントラクトが法的拘束力があると見なされるアリゾナ州のように、いくつかの例外があります。さらに、あなたがカリフォルニア州にいて、マリッジ ライセンスがスマート コントラクトに含まれている場合、そのコントラクトにも法的拘束力があります。将来的には、より多くの政府がスマート コントラクトを法的拘束力のある契約として認識するようになると予想されます。

ユースケース: 現実的な HOA 投票用紙の作成

「Moving From Full-Stack Developer To Web3 Pioneer」出版物からの単純なバイナリ (はい/いいえ) スマート コントラクトに基づいて、一歩前進し、単一のコミュニティの HOA 投票に次の要件が存在すると仮定します。埋める位置:

  • HOA社長を選ぶ


理想的には、HOA の選択が行われるたびに単一のスマート コントラクトが使用されるようにすることが目標です。大統領職に立候補する者は、選挙ごとに変わることが予想されます。

それでは、ニーズを処理するスマート コントラクトの作成を始めましょう。

新しいスマート コントラクトの定義

Solidityを使用して、私はポール・マカヴィニー、誰が私たちのスマートコントラクト以下に示すように、HOA投票の場合:


 // SPDX-License-Identifier: MIT pragma solidity ^0.8.13; /********************************************************/ /* For learning purposes ONLY. Do not use in production */ /********************************************************/ // Download into project folder with `npm install @openzeppelin/contracts` import "@openzeppelin/contracts/access/Ownable.sol"; // Inherits the Ownable contract so we can use its functions and modifiers contract HOABallot is Ownable { // Custom type to describe a Presidential Candidate and hold votes struct Candidate { string name; uint256 votes; } // Array of Presidential Candidates Candidate[] public candidates; // Add a President Candidate - onlyOwner function addCandidate(string memory _name) public onlyOwner { require(bytes(_name).length > 0, "addCandidate Error: Please enter a name"); candidates.push(Candidate({name: _name, votes: 0})); } // Remove a Candidate - onlyOwner function removeCandidate(string memory _name) public onlyOwner { require(bytes(_name).length > 0, "removeCandidate Error: Please enter a name"); bool foundCandidate = false; uint256 index; bytes32 nameEncoded = keccak256(abi.encodePacked(_name)); // Set index number for specific candidate for (uint256 i = 0; i < candidates.length; i++) { if (keccak256(abi.encodePacked(candidates[i].name)) == nameEncoded) { index = i; foundCandidate = true; } } // Make sure a candidate was found require(foundCandidate, "removeCandidate Error: Candidate not found"); // shift candidate to be removed to the end of the array and the rest forward for (uint256 i = index; i < candidates.length - 1; i++) { candidates[i] = candidates[i + 1]; } // remove last item from array candidates.pop(); } // Reset the President Vote Counts - onlyOwner function resetVoteCount() public onlyOwner { for (uint256 p = 0; p < candidates.length; p++) { candidates[p].votes = 0; } } // Add a vote to a candidate by name function addVoteByName(string memory _name) public { require(bytes(_name).length > 0, "addVoteByName Error: Please enter a name"); // Encode name so only need to do once bytes32 nameEncoded = keccak256(abi.encodePacked(_name)); for (uint256 i = 0; i < candidates.length; i++) { // solidity can't compare strings directly, need to compare hash if (keccak256(abi.encodePacked(candidates[i].name)) == nameEncoded) { candidates[i].votes += 1; } } } // Returns all the Presidential Candidates and their vote counts function getCandidates() public view returns (Candidate[] memory) { return candidates; } function getWinner() public view returns (Candidate memory winner) { uint256 winningVoteCount = 0; for (uint256 i = 0; i < candidates.length; i++) { if (candidates[i].votes > winningVoteCount) { winningVoteCount = candidates[i].votes; winner = candidates[i]; } } return winner; } }


スマート コントラクトの設計に関連するいくつかの重要な項目を次に示します。


  • デフォルトでは、投票に候補者はいません。
  • addCandidate() 関数を使用して、(スマート コントラクトの所有者のみが) 候補を追加できます。
  • 同様に、候補は removeCandidate() 関数を使用して (スマート コントラクトの所有者のみが) 削除できます。
  • 投票は getCandidates() 関数を活用します。この関数は、対応する Dapp で addVoteByName() 関数を呼び出すために使用できます。
  • 同じ getCandidates() メソッドを呼び出して、現在の投票数を確認できます。
  • OpenZeppelin の Ownable コントラクトは、コントラクトの所有権と、所有権を別のアドレスに転送する機能を有効にします。


それでは、スマート コントラクトを使用する準備をしましょう。

スマート コントラクトを使用するための準備

スマート コントラクトを使用できるようにするために、単純な Truffle プロジェクトを構築し、コントラクトを Ropsten テストネットにデプロイします。これを行うには、まず最新バージョンの Truffle が必要です。とNPMがインストールされています、次のコマンドを実行します。


 npm install -g truffle


最新バージョンをインストールすると、トリュフのダッシュボードこれにより、プライベート ウォレット キーやニーモニック フレーズを共有する必要がないため、スマート コントラクトの展開が非常に簡単かつ安全になります。それについては少し後で説明します。


次に、新しいディレクトリを作成し、新しい Truffle プロジェクトを初期化します。


 mkdir hoa-ballot-contract && cd hoa-ballot-contract truffle init


これにより、必要に応じて入力できるベアボーン スマート コントラクト プロジェクトが作成されます。お気に入りのコード エディターでプロジェクトを開き、プロジェクトに取り掛かりましょう。


OpenZeppelin を利用するには、プロジェクト フォルダーでも次のコマンドを実行する必要があります。


 npm install @openzeppelin/contracts


truffle-config.jsファイルを開き、 networksオブジェクト内に Truffle ダッシュボードを追加します。コメントアウトされたすべてのボイラープレートを除けば、オブジェクトは次のようになります。


 networks: { dashboard: { port: 24012, } }


次のステップでは、新しいスマート コントラクト ファイルを作成します。契約フォルダー内で、新しいファイルを作成し、 HOABallot.solという名前を付けます。ここからは、上記のスマート コントラクトを貼り付けます。


このコントラクトをデプロイする前に最後に行う必要があるのは、デプロイ スクリプトのセットアップです。以下の内容を使用して、移行フォルダーに2_hoaballot_migration.jsという新しいファイルを作成する必要があります。


 const HOABallot = artifacts.require("HOABallot"); Module.exports = function (deployer) { deployer.deploy(HOABallot); }


これで、コントラクトを Ropsten テストネットにデプロイする準備が整いました。新しいターミナル ウィンドウで、次のコマンドを入力してダッシュボードを開始します。


 truffle dashboard


実行すると、ブラウザがポップアップし、ウォレットを接続するように求めるインターフェイスが表示されます。これが表示されない場合は、 localhost:24012に移動します。


METAMASKボタンを 1 回クリックすると、ブラウザ プラグインを介して MetaMask が起動します。ウォレット ブラウザ拡張機能がインストールされていない場合は、次の URL で入手できます。 metamask.io .手順に従ってアカウントを作成し、Truffle ダッシュボードに戻って接続します。


有効なパスワードを入力して [ロック解除] ボタンを使用すると、Truffle ダッシュボードは使用するネットワークを確認します。


CONFIRMボタンをクリックすると、Truffle ダッシュボードはリクエストをリッスンします。


展開を実行するには Ropsten Eth が必要です。持っていない場合は、できますこの蛇口でいくつかリクエストしてください.


あとはコントラクトをデプロイするだけです。元のターミナル ウィンドウで、プロジェクト フォルダーにいることを確認し、次のコマンドを入力します。


 truffle migrate --network dashboard


Truffle は自動的にスマート コントラクトをコンパイルし、ダッシュボードを介してリクエストをルーティングします。各リクエストは、以下に示す同じフローに従います。


まず、Truffle ダッシュボードは、リクエストを処理するための確認を求めます。


PROCESSボタンを押すと、MetaMask プラグインも確認を求めます。


確認ボタンを使用すると、各リクエストを処理するために、この関連付けられたウォレットから資金を削除できます。


プロセスが完了すると、truffle migrate コマンドの発行に使用されるターミナル ウィンドウに次の情報が表示されます。


 2_hoaballot_migration.js ======================== Deploying 'HOABallot' --------------------- > transaction hash: 0x5370b6f9ee1f69e92cc6289f9cb0880386f15bff389b54ab09a966c5d144f59esage. > Blocks: 0 Seconds: 32 > contract address: 0x2981d347e288E2A4040a3C17c7e5985422e3cAf2 > block number: 12479257 > block timestamp: 1656386400 > account: 0x7fC3EF335D16C0Fd4905d2C44f49b29BdC233C94 > balance: 41.088173901232893417 > gas used: 1639525 (0x190465) > gas price: 2.50000001 gwei > value sent: 0 ETH > total cost: 0.00409881251639525 ETH > Saving migration to chain. > Saving artifacts ------------------------------------- > Total cost: 0.00409881251639525 ETH Summary ======= > Total deployments: 1 > Final cost: 0.00409881251639525 ETH


ここで、コントラクト アドレスの値を使用して、次の URL を使用してスマート コントラクトを検証できます。

https://ropsten.etherscan.io/address/0x2981d347e288E2A4040a3C17c7e5985422e3cAf2


これで切り替えて、Dapp の構築を開始できます。

React を使用して HOA 投票 Dapp を作成する

React CLI を使用して、 hoa-ballot-clientという React アプリケーションを作成します。


 npx create-react-app hoa-ballot-client


次に、ディレクトリを新しく作成したフォルダーに変更し、次のコマンドを実行して web3 と OpenZepplin の依存関係を React アプリケーションにインストールします。

 cd hoa-ballot-client npm install web3 npm install @openzeppelin/contracts —save


HOABallot.solスマート コントラクト ファイルの内容に基づいて、build/contracts フォルダーに移動し、 abi.jsファイルを開き、 HOBallot.jsonファイルのhoaBallot定数の "abi" プロパティの値を次のように使用しました。下に示された:


 export const hoaBallot = [ { "anonymous": false, "inputs": [ { "indexed": true, "internalType": "address", "name": "previousOwner", "type": "address" }, { "indexed": true, "internalType": "address", "name": "newOwner", "type": "address" } ], "name": "OwnershipTransferred", "type": "event" }, { "inputs": [ { "internalType": "uint256", "name": "", "type": "uint256" } ], "name": "candidates", "outputs": [ { "internalType": "string", "name": "name", "type": "string" }, { "internalType": "uint256", "name": "votes", "type": "uint256" } ], "stateMutability": "view", "type": "function", "constant": true }, { "inputs": [], "name": "owner", "outputs": [ { "internalType": "address", "name": "", "type": "address" } ], "stateMutability": "view", "type": "function", "constant": true }, { "inputs": [], "name": "renounceOwnership", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, { "inputs": [ { "internalType": "address", "name": "newOwner", "type": "address" } ], "name": "transferOwnership", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, { "inputs": [ { "internalType": "string", "name": "_name", "type": "string" } ], "name": "addCandidate", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, { "inputs": [ { "internalType": "string", "name": "_name", "type": "string" } ], "name": "removeCandidate", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, { "inputs": [], "name": "resetVoteCount", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, { "inputs": [ { "internalType": "string", "name": "_name", "type": "string" } ], "name": "addVoteByName", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, { "inputs": [], "name": "getCandidates", "outputs": [ { "components": [ { "internalType": "string", "name": "name", "type": "string" }, { "internalType": "uint256", "name": "votes", "type": "uint256" } ], "internalType": "struct HOABallot.Candidate[]", "name": "", "type": "tuple[]" } ], "stateMutability": "view", "type": "function", "constant": true }, { "inputs": [], "name": "getWinner", "outputs": [ { "components": [ { "internalType": "string", "name": "name", "type": "string" }, { "internalType": "uint256", "name": "votes", "type": "uint256" } ], "internalType": "struct HOABallot.Candidate", "name": "winner", "type": "tuple" } ], "stateMutability": "view", "type": "function", "constant": true } ];


このファイルは、React アプリケーションの src フォルダー内に新しく作成された abi フォルダーに配置されました。


ここで、React Apps.jsファイルを更新する必要があります。まず、以下に示すように構成する必要があるファイルの先頭から始めましょう。


 import React, { useState } from "react"; import { hoaBallot } from "./abi/abi"; import Web3 from "web3"; import "./App.css"; const web3 = new Web3(Web3.givenProvider); const contractAddress = "0x2981d347e288E2A4040a3C17c7e5985422e3cAf2"; const storageContract = new web3.eth.Contract(hoaBallot, contractAddress);


contractAddressは、さまざまな方法で見つけることができます。この場合、結果を truffle — migrate CLI コマンドで使用しました。別のオプションは、Etherscan サイトを使用することです。


あとは、次のことを達成するための標準の React コードを作成するだけです。


  • HOA 大統領候補を追加する
  • HOA 大統領候補を削除する
  • HOA 大統領候補のリストを取得する
  • HOA大統領候補に投票する
  • HOA社長の決定


私の出版物「フルスタック開発者から Web3 パイオニアへの移行」では、投票者のアドレスが簡単に参照できるように Nav コンポーネントも追加しました。


更新された React アプリケーションは次のように表示されます。


 const web3 = new Web3(Web3.givenProvider); const contractAddress = "0x2981d347e288E2A4040a3C17c7e5985422e3cAf2"; const storageContract = new web3.eth.Contract(hoaBallot, contractAddress); const gasMultiplier = 1.5; const useStyles = makeStyles((theme) => ({ root: { "& > *": { margin: theme.spacing(1), }, }, })); const StyledTableCell = styled(TableCell)(({ theme }) => ({ [`&.${tableCellClasses.head}`]: { backgroundColor: theme.palette.common.black, color: theme.palette.common.white, fontSize: 14, fontWeight: 'bold' }, [`&.${tableCellClasses.body}`]: { fontSize: 14 }, })); function App() { const classes = useStyles(); const [newCandidateName, setNewCandidateName] = useState(""); const [account, setAccount] = useState(""); const [owner, setOwner] = useState(""); const [candidates, updateCandidates] = useState([]); const [winner, setWinner] = useState("unknown candidate"); const [waiting, setWaiting] = useState(false); const loadAccount = async(useSpinner) => { if (useSpinner) { setWaiting(true); } const web3 = new Web3(Web3.givenProvider || "http://localhost:8080"); const accounts = await web3.eth.getAccounts(); setAccount(accounts[0]); if (useSpinner) { setWaiting(false); } } const getOwner = async (useSpinner) => { if (useSpinner) { setWaiting(true); } const owner = await storageContract.methods.owner().call(); setOwner(owner); if (useSpinner) { setWaiting(false); } }; const getCandidates = async (useSpinner) => { if (useSpinner) { setWaiting(true); } const candidates = await storageContract.methods.getCandidates().call(); updateCandidates(candidates); await determineWinner(); if (useSpinner) { setWaiting(false); } }; const determineWinner = async () => { const winner = await storageContract.methods.getWinner().call(); if (winner && winner.name) { setWinner(winner.name); } else { setWinner("<unknown candidate>") } } const vote = async (candidate) => { setWaiting(true); const gas = (await storageContract.methods.addVoteByName(candidate).estimateGas({ data: candidate, from: account })) * gasMultiplier; let gasAsInt = gas.toFixed(0); await storageContract.methods.addVoteByName(candidate).send({ from: account, data: candidate, gasAsInt, }); await getCandidates(false); setWaiting(false); } const removeCandidate = async (candidate) => { setWaiting(true); const gas = (await storageContract.methods.removeCandidate(candidate).estimateGas({ data: candidate, from: account })) * gasMultiplier; let gasAsInt = gas.toFixed(0); await storageContract.methods.removeCandidate(candidate).send({ from: account, data: candidate, gasAsInt, }); await getCandidates(false); setWaiting(false); } const addCandidate = async () => { setWaiting(true); const gas = (await storageContract.methods.addCandidate(newCandidateName).estimateGas({ data: newCandidateName, from: account })) * gasMultiplier; let gasAsInt = gas.toFixed(0); await storageContract.methods.addCandidate(newCandidateName).send({ from: account, data: newCandidateName, gasAsInt, }); await getCandidates(false); setWaiting(false); } React.useEffect(() => { setWaiting(true); getOwner(false).then(r => { loadAccount(false).then(r => { getCandidates(false).then(r => { setWaiting(false); }); }); }); // eslint-disable-next-line react-hooks/exhaustive-deps },[]); return ( <div className={classes.root}> <Nav /> <div className="main"> <div className="card"> <Typography variant="h3"> HOABallot </Typography> {(owner && owner.length > 0) && ( <div className="paddingBelow"> <Typography variant="caption" > This ballot is owned by: {owner} </Typography> </div> )} {waiting && ( <div className="spinnerArea" > <CircularProgress /> <Typography gutterBottom> Processing Request ... please wait </Typography> </div> )} {(owner && owner.length > 0 && account && account.length > 0 && owner === account) && ( <div className="ownerActions generalPadding"> <Grid container spacing={3}> <Grid item xs={12}> <Typography variant="h6" gutterBottom> Ballot Owner Actions </Typography> </Grid> <Grid item xs={6} sm={6}> <TextField id="newCandidateName" value={newCandidateName} label="Candidate Name" variant="outlined" onChange={event => { const { value } = event.target; setNewCandidateName(value); }} /> </Grid> <Grid item xs={6} sm={6}> <Button id="addCandidateButton" className="button" variant="contained" color="primary" type="button" size="large" onClick={addCandidate}>Add New Candidate</Button> </Grid> </Grid> </div> )} <Typography variant="h5" gutterBottom className="generalPadding"> Candidates </Typography> {(!candidates || candidates.length === 0) && ( <div> <div className="paddingBelow"> <Typography variant="normal"> No candidates current exist. </Typography> </div> <div> <Typography variant="normal" gutterBottom> Ballot owner must use the <strong>ADD NEW CANDIDATE</strong> button to add candidates. </Typography> </div> </div> )} {(candidates && candidates.length > 0) && ( <div> <TableContainer component={Paper}> <Table sx={{ minWidth: 650 }} aria-label="customized table"> <TableHead> <TableRow> <StyledTableCell>Candidate Name</StyledTableCell> <StyledTableCell align="right">Votes</StyledTableCell> <StyledTableCell align="center">Actions</StyledTableCell> </TableRow> </TableHead> <TableBody> {candidates.map((row) => ( <TableRow key={row.name} sx={{ '&:last-child td, &:last-child th': { border: 0 } }} > <TableCell component="th" scope="row"> {row.name} </TableCell> <TableCell align="right">{row.votes}</TableCell> <TableCell align="center"> <Button color="success" variant="contained" onClick={() => { vote(row.name); }} > Vote </Button> &nbsp; {(owner && owner.length > 0 && account && account.length > 0 && owner === account) && <Button color="error" variant="contained" onClick={() => { removeCandidate(row.name); }} > Remove Candidate </Button> } </TableCell> </TableRow> ))} </TableBody> </Table> </TableContainer> <div className="generalPadding"> <Typography variant="normal" gutterBottom> {winner} is winning the election. </Typography> </div> </div> )} </div> </div> </div> ); } export default App;


React ベースの Dapp を開始するには、Yarn CLI を使用できます。


 yarn start


コンパイルと検証が完了すると、次のようにアプリケーションが画面に表示されます。



ビデオ中:


  • 「接続されたアドレス」の値が「この投票の所有者」の値と完全に一致し、「投票所有者のアクション」セクションが表示されるため、私が契約所有者であることを確認しました。
  • 契約所有者として、私は [新しい候補者を追加] ボタンを表示して使用し、選挙の候補者を確立することができました。この例では、Dave Brown と Steve Smith という名前を使用しました。
  • 契約所有者として、REMOVE CANDIDATE ボタンも使用できました。
  • 両方の候補者を作成した後、目的の候補者と同じ行にある VOTE ボタンを使用して、2 つの候補者のうちの 1 つに投票しました。私はデイブ・ブラウンに投票しました。
  • 選挙の現在の勝者は、候補者の表の下に表示されます。この場合、それは Dave Brown です。


スマート コントラクトをデプロイして以来、誰でも次の URL で完全な履歴を表示できます。


https://ropsten.etherscan.io/address/0x2981d347e288E2A4040a3C17c7e5985422e3cAf2


結論

2021 年以来、私は次のミッション ステートメントに従って生きようとしてきました。これは、あらゆるテクノロジー プロフェッショナルに当てはまると思います。


「知的財産の価値を拡張する機能を提供することに時間を集中してください。他のすべてのフレームワーク、製品、およびサービスを活用してください。」
J.ベスター


スマート コントラクトは、2 つの当事者が契約の結果がトランザクションの確定的な公式記録となる契約を締結できるようにする機能を提供します。スマート コントラクトの採用は、そのようなコントラクトの必要性が生じたときに、基礎となるフレームワークが車輪の再発明を回避するという点で、私の個人的なミッション ステートメントに準拠しています。


同時に、スマート コントラクトの設計自体はさらに一歩進んでおり、再利用性という点で私のミッション ステートメントを満たしています。この例では、現在の選挙で異なる候補者が出馬しているにもかかわらず、同じ HOA スマート コントラクトを使用できます。ここでは、スマート コントラクトの力を利用して、選挙のたびに新しいスマート コントラクトを作成することを回避します。


Etherscan を使用して、Google の ETH から USD へのコンバーターを使用してトランザクションの 1 つのコンバージョン値を検索すると、トランザクションあたりのコストは 0.0001348975 ETH で 0.24 (USD) でした。皮肉なことに、それは私が子供の頃、ガムボール マシンから出てきた控えめなガムボールのコストでした。


スマート コントラクトについて詳しく知りたい場合は、 ConsenSysのチームが優れたリソースを提供しており、アイデアのプロトタイプを作成して、スマート コントラクトの採用が有効なユース ケースであるかどうかを確認するのに役立ちます。


この記事のソース コードに興味がある場合は、次の URL で見つけることができます。


https://github.com/paul-mcaviney/smart-contract-deep-dive/blob/main/HOABallot.sol

https://gitlab.com/johnjvester/hoa-ballot-contract

https://gitlab.com/johnjvester/hoa-ballot-client


本当に素晴らしい一日を!