智能合约——提案demo

目录

这是一个超超超级简单的智能合约提案项目,你确定不点进来看一下吗?

引言:

1、搭建开发环境:

2、编写智能合约:

3、部署智能合约:

​编辑​编辑4、编写前端交互代码(使用web3.js):

5、设计关于提案平台的html:


这是一个超超超级简单的智能合约提案项目,你确定不点进来看一下吗?

引言:

作为一个"新手"写智能合约,我选择做提案项目的目的是学习和成长。在这个项目中,我计划使用Solidity编程语言来编写智能合约,并进行部署和测试。我将设计一个简单而有趣的提案系统,允许用户提交提案并进行投票。我将利用前端技术,如HTML、CSS和JavaScript,来开发一个直观且易于使用的界面。通过这个项目,我希望能够提高我的编程能力和设计技巧。

1、搭建开发环境:

1.安装并配置必要的开发工具,如Node.js、Truffle Suite或Hardhat等。

2.部署一个本地的以太坊测试网络(如Ganache,Geth)或连接到以太坊的公共测试网络(如Ropsten)。

3.使用Remix,Remix是一个在线的Solidity IDE,其提供了Solidity编译器、调试器和运行环境。

4.MetaMask 是一种加密货币钱包,使用户能够访问分散式应用程序(dapps)的 Web 3 生态系统。

简单来说:

  • MetaMask 是一种加密货币钱包,使用户能够存储以太币和其他 ERC-20 代币。

  • 钱包还可用于与去中心化应用程序或 dapp 进行交互

2、编写智能合约:

编写提案智能合约及实现一个基于 ERC20 标准的代币合约。

定义合约的数据结构、状态变量、函数以及相关的事件。

javascript 复制代码
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;

 
import"@openzeppelin/contracts/token/ERC20/ERC20.sol";
contract MyToken1 is ERC20 {
    constructor(string memory name, string memory symbol) ERC20(name, symbol) {
        _mint(msg.sender, 111 * 10**uint(decimals()));
    }
    
    function getDEcimals() public view returns (uint){
        return  decimals();
    }
    
}
javascript 复制代码
//SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;

import"@openzeppelin/contracts/token/ERC20/ERC20.sol";



 contract EthVoting {

    //附议人信息
    struct Voter {
        uint voteTimeStamp; //投票时的区块时间
        uint voterMoney;
        bool initialized;   //判断是否投过票的标志
        
    }
    
    
    
    //提案内容
    struct  Proposal {
        string pName;        //提案标题
		string pCtx;         //提案内容
		address chairperson; //提案主持人
        uint voteCount;      //附议人数
        bool initialized;    //判断提案是否存在的标志
        uint limitTime;      //附议限制时间
        uint money;  //该提案的已经募集到的金额
        uint r_money;//该提案目标募集的金额
		mapping(address => Voter) voters; //附议列表
    } 
    
    //提案内容-加入的数组中
        struct  Proposal_group {
        string pName;        //提案标题
		string pCtx;         //提案内容
		address chairperson; //提案主持人
        uint voteCount;      //附议人数
        bool initialized;    //判断提案是否存在的标志
        uint limitTime;      //附议限制时间
        uint money;  //该提案的已经募集到的金额
        uint r_money;//该提案目标募集的金额
	
    }
 
 

 //声明一个全局变量成为部署当前合约的调用者   
address public  master;

 //声明一个全局变量成为master指定一个账户成为提案合法提取者
address   receiver;


 
  //ERC20的合约地址赋值给这个变量
   address public ercaddress;
    
   
    constructor (address ercaddress_ ) {
 
       //实例化合约token合约对象
 master=msg.sender;
       //实例化一个token
  ercaddress =ercaddress_;
    }


//转ERC20代币
   function transfer2other(address to_ ,uint ercnum_) public {
        IERC20(ercaddress).transfer(to_,ercnum_*(10**18));

   }
   //获取某个ERC20代币余额
     function getBalance() public  view  returns (uint256) {
        return IERC20(ercaddress).balanceOf(address(this));
    }
   
 
	
//提案编号
uint pId;

//函数修饰符,表示只有master账户才能执行的函数
modifier  onlyMaster(){

require(msg.sender==master,"it must be  master");
    _;

}   
   
   //函数修饰符,表示只有指定账户才能提取提案里的钱
modifier  onlyReceiver(){

require(msg.sender==receivers[msg.sender]&&msg.sender==receivers[msg.sender]&&msg.sender==receivers[msg.sender],"it must be  receiver");
    _;

}

//函数修饰符,表示只有指定账户才能进行提案的附议
modifier  onlySomeDoVoting(){
require(msg.sender!=receiver,"it can not be  receiver");
require(msg.sender!=master,"it can not be  master");
    _;
}

    //所有提案列表
    mapping(uint => Proposal) public proposals;
    
//提案余额提取者
   mapping(address=>address) public receivers;
    
//所有提案列表-加入到数组中
     mapping(uint => Proposal_group) public proposales;
//所有提案列表-加入到数组中
    mapping(uint=>Proposal_group[]) public Proposal_groups;
	
	//附议事件
	event VoteEvt(string indexed eventType, address _voter, uint timestamp);
	
	//提案事件
	event ProposeEvt(string indexed eventType, uint _proposalId, uint _limitTime);
	//创建新提案
	function createProposal(string  memory _pName, string memory  _pCtx, uint _limitTime ,uint r_money) public payable returns (uint){

//赋值语句
	   	   pId=pId+1;
           Proposal storage _proposal = proposals[pId];
	   	  _proposal.pName = _pName;
	   	  _proposal.pCtx = _pCtx;
	   	  _proposal.chairperson = msg.sender;
	   	  _proposal.initialized = true;
	   	  _proposal.limitTime=block.timestamp+ _limitTime;
	   	  _proposal.r_money= r_money;
	   	  _proposal.voteCount = 0;

//赋值并加入到数组中,以获取所有的提案
    Proposal_group storage _proposales = proposales[pId];
	   	  _proposales.pName = _pName;
	   	  _proposales.pCtx = _pCtx;
	   	  _proposales.chairperson = msg.sender;
	   	  _proposales.initialized = true;
	   	  _proposales.limitTime=block.timestamp+ _limitTime;
	   	  _proposales.r_money= r_money;
	   	  _proposales.voteCount = 0;
  

         Proposal_groups[1].push(_proposales);
         
	   	   emit ProposeEvt("propose", pId, _limitTime);

          return pId;
      
  
	}
	
	 //提案提取人数量
    uint receiverCount;
	
		//master添加提案提取人
	function addReceiver(address voterAddr) public  payable onlyMaster{
	    require(receiverCount<=3,"receiver can not exceed 3!");
	 receiverCount+=1;
    receivers[voterAddr]=voterAddr;
	  

	}
	
	//master删除提案提取人
	function deleteReceiver(address voterAddr) public  payable onlyMaster{
    delete receivers[voterAddr];
	  receiverCount-=1;

	}
	
	
	//进行附议
	function doVoting(uint pId1) public payable  {
	    
	    	  if (proposals[pId1].chairperson == msg.sender)
	    revert("proposal person is not youself");
	    
	  	  if (msg.value <2)
	    revert("money is lower than 2");
	  
	  //提案是否存在
	  if (proposals[pId1].initialized == false)
	    revert("proposal not exist");
	  
	  uint currentTime = block.timestamp;
	  
	  //是否已超过提案时限
	  if (proposals[pId1].limitTime < currentTime)
	    revert("exceed voting time");
	  
	  //是否已经投过票
	  if (proposals[pId1].voters[msg.sender].initialized == true)
	   revert("already vote");
	  
	    if (proposals[pId1].money>=proposals[pId1].r_money)
	   revert("money is enough!");
	  
	  //新投票信息
	  Voter memory voter = Voter({
	     voteTimeStamp: block.timestamp,
	     initialized: true,
	     voterMoney:msg.value
	  });
    
	  //记录投票信息
	  proposals[pId1].voters[msg.sender] = voter;
	  proposals[pId1].voteCount+=1;
      
      proposals[pId1].money+=msg.value;
	  
	  
	 


	   
	  emit VoteEvt("vote", msg.sender, block.timestamp);
	}	
	

    //提案里的钱由合法提取者提取出来
    function collectMoney(uint pId1) public payable onlyReceiver{
payable(receiver).transfer(proposals[pId1].money);
 proposals[pId1].money=0;
 
 delete proposals[pId1];

    }
    
   
	
	//查询是否附议
	function queryVoting(uint pId1, address voterAddr) public view returns (uint,uint){
	  //提案是否存在
	  if (proposals[pId1].initialized == false)
	    revert("proposal not exist");
	  
	  //返回投票时间和和金额
	  return (proposals[pId1].voters[voterAddr].voteTimeStamp,proposals[pId1].voters[voterAddr].voterMoney);
	}	
	
	//获取区块链时间
    function getBlockTime() public view returns (uint t) { 
     t = block.timestamp;
    }
    
    
    
    //  //查询所有提案
    function getProposals() public view returns (Proposal_group[] memory) { 
     
     return Proposal_groups[1];
    } 	

  // 查询附议提案
    function queryP_dovot(uint pid) public view returns (uint,uint ) { 
     
     return (proposals[pid].voteCount,proposals[pid].money);
    } 

    //查询提案标题
    function getProposalName(uint pId1) public view returns (string memory s) { 
     s = proposals[pId1].pName;
    } 	
	
	//查询提案内容
    function getProposalCtx(uint pId1) public view returns (string memory s) { 
     s = proposals[pId1].pCtx;
    }
	
	//查询提案内容
    function getProposalVCnt(uint pId1) public view returns (uint v) { 
     v = proposals[pId1].voteCount;
    }
	
	//查询提案期限
    function getProposalLimit(uint pId1) public view returns (uint t) { 
     t = proposals[pId1].limitTime;
    }


}

3、部署智能合约:

编译智能合约代码,生成合约的字节码和ABI(Application Binary Interface)。

将合约部署到所选择的以太坊网络中。

4、编写前端交互代码(使用web3.js):

创建一个前端应用程序,可以是基于HTML/CSS/JavaScript的简单界面。

使用web3.js库与部署的智能合约进行交互,包括调用合约方法、处理交易等。

配置MetaMask或其他以太坊钱包插件,使用户可以通过浏览器与智能合约交互并进行以太币交易。

具体功能见代码注释

javascript 复制代码
const web3 = new Web3(Web3.givenProvider);
const abi = [];
let changeAccount = [];
var myContract = new web3.eth.Contract(
  abi,
  "0xa9dC761F2B9986Ce04694c3f279f0d62bb82A9CA"
);
let Accounts = [];
console.log(web3);
web3.eth.getAccounts().then(function (accounts) {
  Accounts = accounts;
});
ethereum.on("accountsChanged", function (account) {
  changeAccount = account;
});
function handle() {
  var Title = document.getElementById("Title").value;
  var content = document.getElementById("content").value;
  var time = document.getElementById("time").value;
  var eth = document.getElementById("eth").value;
  var start = new Date("1970-01-01");
  var end = new Date(time);
  var t_start = start.getTime();
  var t_end = end.getTime();
  var days = (t_end - t_start) / 1000 / 60 / 60 / 24; //10
  var s = days * 24 * 60 * 60;
  //添加提案
  myContract.methods
    ._createProposal(Title, content, s, eth)
    .send({ from: changeAccount[0], gas: 3000000 })
    .then(function (receipt) {
      alert("提案添加成功");
    });
}
//查询提案列表
function queryall() {
  myContract.methods
    ._getProposals()
    .call({ from: changeAccount[0] })
    .then(function (receipt) {
      console.log(receipt);
    });
}

var personAdd = [];
//添加提案余额提取人
function handle1() {
  var Person = document.getElementById("Person").value;
  var Person1 = document.getElementById("Person1").value;
  console.log(Person == "");
  console.log(Person1 == "");
  if (Person != "") {
    personAdd[0] = Person;
    myContract.methods
      ._addReceiver(personAdd[0])
      .send({ from: changeAccount[0], gas: 3000000 })
      .then(function (receipt) {
        alert("添加提案余额提取人成功");
      });
  }
  if (Person1 != "") {
    personAdd[0] = Person1;
    myContract.methods
      ._deleteReceiver(personAdd[0])
      .send({ from: changeAccount[0], gas: 3000000 })
      .then(function (receipt) {
        alert("删除提案余额提取人成功");
      });
  }
}
//附议提案
function handle2() {
  var id = document.getElementById("id").value;
  var eth = document.getElementById("eth").value;

  web3.eth.getAccounts().then(function (accounts) {
    Accounts = accounts;
  });
  myContract.methods
    ._doVoting(id)
    .send({ from: changeAccount[0], gas: 3000000, value: eth })
    .then(function (receipt) {
      alert("提案附议成功");
      var amount = 10;
      myContract.methods
        ._transfer2other(Accounts[0], amount)
        .send({ from: changeAccount[0], gas: 3000000 })
        .then(function (receipt) {
          alert("附议成功,该账户获得10个ERC20代币");
        });
    });
}

//receiver接收提案中的金额
function handle3() {
  web3.eth.getAccounts().then(function (accounts) {
    Accounts = accounts;
  });
  var id = document.getElementById("id").value;
  myContract.methods
    ._collectMoney(id)
    .send({ from: changeAccount[0], gas: 3000000 })
    .then(function (receipt) {
      alert("receiver提取成功");
    });
}
//查询提案附议结果
function handle4() {
  web3.eth.getAccounts().then(function (accounts) {
    Accounts = accounts;
  });

  var id = document.getElementById("id").value;
  var id1 = document.getElementById("id1").value;
  var Address = document.getElementById("Address").value;

  if (id != "") {
    myContract.methods
      ._queryP_dovot(id)
      .call({ from: changeAccount[0] })
      .then(function (receipt) {
        alert("查询成功");

        console.log(receipt);
      });
  }
  if (id1 != "") {
    //查询某人附议结果(pid,address)
    personAdd[0] = Address;
    myContract.methods
      ._queryVoting(id1, personAdd[0])
      .call({ from: changeAccount[0] })
      .then(function (receipt) {
        alert("查询成功");

        console.log(receipt);
      });
  }
}

5、设计关于提案平台的html:

1、是的,HTML代码我没给全,比如设置提案接收人,提案附议页面,查询提案页面我都没给,看到这个文章的有缘人,你们要靠你们自己了!

html 复制代码
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>首页</title>

<!--bootstrap css 挺方便简洁的一款第三方前端开发框架-->
<link rel="stylesheet" href="css/bootstrap.css" />

<link rel="stylesheet" href="css/style.css" />

</head>
<body>


<div class="span12 content" style="width: 1180px;">
	<div class="box" style="    margin-top: 166px;
    margin-left: 245px;">
		<div class="box-head">
			<h3>公告提案平台</h3>
			<a href="/setReveiver.html"><button>设置提案接收人</button></a>
			<a href="/dovot.html"><button>附议页面</button></a>
			<a href="/searchPid.html"><button>查询提案</button></a>
			<a href="/reveiver.html"><button>余额提取页面</button></a>
			<button onclick="queryall()">查询提案列表(控制台查看)</button>
		</div>
		<div class="box-content">
			<div class="form-horizontal">
			
				<div class="control-group">
					<label class="control-label">标题</label>
					<div class="controls">
						<div class="input-append">
							<input id="csyTitle" type="text" class="tip" />
							<!-- <span class="tip add-on"  id="jieshouren"> -->
								<!-- <i class="icon-user" style="cursor:pointer" ></i> -->
								<!-- <div style="display:none" id="selectlxr"></div> -->
							</span>
						</div>
					</div>
				</div>
				
				<div class="control-group">
					<label class="control-label">内容</label>
					<div class="controls">
						<textarea id="csycontent" class="span6 input-square"></textarea>
						
					</div>
				</div>
				<div class="control-group">
					<label class="control-label">截止时间</label>
					<div class="controls">
						<input id="csytime" type="datetime-local" />
					</div>
				</div>
				<div class="control-group">
					<label class="control-label">所需费用</label>
					<div class="controls">
						<input type="text" id="csyeth" class="tip" />
					</div>
				</div>
				
				<div class="control-group">
					<label class="control-label">&nbsp;</label>
					<div class="controls">
						<input type="button" class="btn btn-fo" onclick="handle()" value="新建提案" />
					</div>
				</div>
			
			</div>
		</div>
	</div>
</div>
<script src="web3.min.js"></script>
<script src="app1.js"></script>
<script src="js/jQuery.js"></script>
<script src="js/jquery.artDialog.js?skin=idialog"></script>
<!--js结束-->
<script>
//循环输出创建十个复选框
var chtml = "";
for (var i = 0; i < 10; i++) {
   chtml += "<div style='word-wrap:break-word; width:450px; '>";
   chtml += '<label style="float:left;padding:15px"><input type="checkbox" name="aaa" value="1" class="{required:true}" /><span style="margin-left:10px">小'+i+'</span></label>';
   chtml += "</div>";
}
//把得到字符串利用jquery添加到元素里面生成checkbox
$("#selectlxr").html(chtml);
//创建一个 dialog弹出框(第三方插件有兴趣可以看下 超赞的一款插件 http://www.planeart.cn/demo/artDialog/) 把创建好的弹出框隐藏起来
var dia = $.dialog(
   {
	   title: "选择联系人", width: "500px",
	   content: $("#selectlxr").html(),
	   close: function () {
		   this.hide();
		   return false;
	   },
	   follow: document.getElementById("jieshouren")
   }
   ).hide();

//点击 显示
$("#jieshouren").click(function () {
   dia.show();
})
//事件 获取checkbox点击时候的父元素的值 添加到text 如果点击收的选中状态为checked 则添加 否则 删除
$("input[type=checkbox]").click(function () {
   try {
	   if ($(this).attr("checked")) {
		   $("#jsrtxt").val($("#jsrtxt").val() + $(this).parent().text() + ";");
	   } else {
		   $("#jsrtxt").val($("#jsrtxt").val().replace($(this).parent().text() + ';', ""));
	   }
   } catch (e) {
	   $("#jsrtxt").val("");
   }
})
//初步测试 暂无小bug 可以为text增加一个只读  
</script>

</body>
</html>
相关推荐
十一吖i2 小时前
vue3表格显示隐藏列全屏拖动功能
前端·javascript·vue.js
徐同保4 小时前
tailwindcss暗色主题切换
开发语言·前端·javascript
生莫甲鲁浪戴4 小时前
Android Studio新手开发第二十七天
前端·javascript·android studio
细节控菜鸡6 小时前
【2025最新】ArcGIS for JS 实现随着时间变化而变化的热力图
开发语言·javascript·arcgis
拉不动的猪7 小时前
h5后台切换检测利用visibilitychange的缺点分析
前端·javascript·面试
桃子不吃李子7 小时前
nextTick的使用
前端·javascript·vue.js
报错小能手8 小时前
项目——基于C/S架构的预约系统平台 (1)
开发语言·c++·笔记·学习·架构
openHiTLS密码开源社区8 小时前
从 “对话” 到 “证书”:零知识证明的魔法工具箱 —— 让隐私验证走进普通人的数字生活
区块链·零知识证明·隐私泄露·zkp
赤月幼狼9 小时前
clickhouse学习笔记(一)基础概念与架构
笔记·学习·clickhouse
Devil枫9 小时前
HarmonyOS鸿蒙应用:仓颉语言与JavaScript核心差异深度解析
开发语言·javascript·ecmascript