|
@@ -1,25 +1,356 @@
|
|
|
-import logo from './logo.svg';
|
|
|
+import React, { useEffect, useState } from "react";
|
|
|
+import { BigNumber, ethers } from "ethers";
|
|
|
import './App.css';
|
|
|
+import abi from './contracts/abi/HappyRedPacket.json';
|
|
|
+import Button from 'react-bootstrap/Button';
|
|
|
+import Modal from 'react-bootstrap/Modal';
|
|
|
+// import Web3Utils from 'web3-utils'
|
|
|
|
|
|
-function App() {
|
|
|
- return (
|
|
|
- <div className="App">
|
|
|
- <header className="App-header">
|
|
|
- <img src={logo} className="App-logo" alt="logo" />
|
|
|
- <p>
|
|
|
- Edit <code>src/App.js</code> and save to reload.
|
|
|
- </p>
|
|
|
- <a
|
|
|
- className="App-link"
|
|
|
- href="https://reactjs.org"
|
|
|
- target="_blank"
|
|
|
- rel="noopener noreferrer"
|
|
|
- >
|
|
|
- Learn React
|
|
|
- </a>
|
|
|
- </header>
|
|
|
- </div>
|
|
|
- );
|
|
|
-}
|
|
|
-
|
|
|
-export default App;
|
|
|
+// const Web3 = require('web3');
|
|
|
+// var web3 = new Web3(new Web3.providers.HttpProvider("http://localhost:3000"));
|
|
|
+// var account = web3.eth.accounts.create();
|
|
|
+// var private_key = account.privateKey;
|
|
|
+// var public_key = account.address;
|
|
|
+
|
|
|
+// 部署红包测试环境的地址
|
|
|
+const contractAddress = '0x4B20EbcFD9a74f969a77B9233a881FC5266930E1';
|
|
|
+
|
|
|
+/**
|
|
|
+ * 红包 id
|
|
|
+ */
|
|
|
+const redid = '0x1ef203acb1627c163918f3c8d97860ed866195e18707d1f2b0284be6c6240015'
|
|
|
+/**
|
|
|
+ * 私钥
|
|
|
+ */
|
|
|
+let privateKey = "6084c2a5e39fa83d5a119c3a864a442e77287f4b03bad93cef38ec5f44bca630";
|
|
|
+
|
|
|
+
|
|
|
+const App = () => {
|
|
|
+ const [showModal, setShowModal] = useState(false);
|
|
|
+ const [currentAccount, setCurrentAccount] = useState("");
|
|
|
+ const [mining, setMining] = useState(false);
|
|
|
+ const read_packet_abi = abi.abi;
|
|
|
+
|
|
|
+ console.log('*', read_packet_abi);
|
|
|
+
|
|
|
+ const handleClose = () => {
|
|
|
+ window.location.reload(false);
|
|
|
+ }
|
|
|
+
|
|
|
+ const checkIfWalletIsConnected = async () => {
|
|
|
+ try {
|
|
|
+ const { ethereum } = window;
|
|
|
+
|
|
|
+ if (!ethereum) {
|
|
|
+ console.log("Make sure you have metamask!");
|
|
|
+ return;
|
|
|
+ } else {
|
|
|
+ console.log("We have the ethereum object", ethereum);
|
|
|
+ }
|
|
|
+
|
|
|
+ const accounts = await ethereum.request({ method: 'eth_accounts' });
|
|
|
+ if (accounts.length !== 0) {
|
|
|
+ const account = accounts[0];
|
|
|
+ console.log("Found an authorized account:", account);
|
|
|
+ setCurrentAccount(account);
|
|
|
+ } else {
|
|
|
+ console.log("No authorized account found")
|
|
|
+ }
|
|
|
+ } catch (error) {
|
|
|
+ console.log(error);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Implement your connectWallet method here
|
|
|
+ */
|
|
|
+ const connectWallet = async () => {
|
|
|
+ try {
|
|
|
+ const { ethereum } = window;
|
|
|
+
|
|
|
+ if (!ethereum) {
|
|
|
+ alert("Get MetaMask!");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ const accounts = await ethereum.request({ method: "eth_requestAccounts" });
|
|
|
+
|
|
|
+ console.log("Connected", accounts[0]);
|
|
|
+ setCurrentAccount(accounts[0]);
|
|
|
+ } catch (error) {
|
|
|
+ console.log(error)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ function stringToByte(str) {
|
|
|
+ var bytes = new Array();
|
|
|
+ var len, c;
|
|
|
+ len = str.length;
|
|
|
+ for (var i = 0; i < len; i++) {
|
|
|
+ c = str.charCodeAt(i);
|
|
|
+ if (c >= 0x010000 && c <= 0x10FFFF) {
|
|
|
+ bytes.push(((c >> 18) & 0x07) | 0xF0);
|
|
|
+ bytes.push(((c >> 12) & 0x3F) | 0x80);
|
|
|
+ bytes.push(((c >> 6) & 0x3F) | 0x80);
|
|
|
+ bytes.push((c & 0x3F) | 0x80);
|
|
|
+ } else if (c >= 0x000800 && c <= 0x00FFFF) {
|
|
|
+ bytes.push(((c >> 12) & 0x0F) | 0xE0);
|
|
|
+ bytes.push(((c >> 6) & 0x3F) | 0x80);
|
|
|
+ bytes.push((c & 0x3F) | 0x80);
|
|
|
+ } else if (c >= 0x000080 && c <= 0x0007FF) {
|
|
|
+ bytes.push(((c >> 6) & 0x1F) | 0xC0);
|
|
|
+ bytes.push((c & 0x3F) | 0x80);
|
|
|
+ } else {
|
|
|
+ bytes.push(c & 0xFF);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return bytes;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 退钱
|
|
|
+ */
|
|
|
+ const refund = async () => {
|
|
|
+ //拿到 window 中以太坊的属性
|
|
|
+ const { ethereum } = window;
|
|
|
+ if (ethereum) {
|
|
|
+ try {
|
|
|
+ const provider = new ethers.providers.Web3Provider(ethereum);
|
|
|
+ const signer = provider.getSigner();
|
|
|
+ const redPacketContract = new ethers.Contract(contractAddress, read_packet_abi, signer);
|
|
|
+ console.log("red packet contract addree", redPacketContract.address);
|
|
|
+ const accounts = await ethereum.request({ method: "eth_requestAccounts" });
|
|
|
+ let id = redid;
|
|
|
+ // 签名文本消息
|
|
|
+ let creationParams = {
|
|
|
+ id: id,
|
|
|
+ gasLimit: 310000
|
|
|
+ }
|
|
|
+ console.log("id", id)
|
|
|
+ redPacketContract.on("RefundSuccess", (id, token_address, remaining_tokens) => {
|
|
|
+ console.log("RefundSuccess ->", id, token_address, remaining_tokens);
|
|
|
+ });
|
|
|
+ // await redPacketContract.refund(creationParams.id, { gasLimit: creationParams.gasLimit, from: accounts[0] });
|
|
|
+ await redPacketContract.refund(creationParams.id,{ gasLimit: creationParams.gasLimit });
|
|
|
+ } catch (error) {
|
|
|
+ console.log("refund ", error)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ /**
|
|
|
+ * 领取红包
|
|
|
+ */
|
|
|
+ const claim_tokens = async () => {
|
|
|
+ //拿到 window 中以太坊的属性
|
|
|
+ const { ethereum } = window;
|
|
|
+ if (ethereum) {
|
|
|
+ try {
|
|
|
+ const provider = new ethers.providers.Web3Provider(ethereum);
|
|
|
+ const signer = provider.getSigner();
|
|
|
+ const redPacketContract = new ethers.Contract(contractAddress, read_packet_abi, signer);
|
|
|
+ console.log("red packet contract addree", redPacketContract.address);
|
|
|
+ const accounts = await ethereum.request({ method: "eth_requestAccounts" });
|
|
|
+ let id = redid;
|
|
|
+ console.log("claim_tokens red id ->", id);
|
|
|
+ // let sigMsg = signer.signMessage(accounts[0],privateKey);
|
|
|
+ // let wallet = new ethers.Wallet(privateKey);
|
|
|
+ // let sigMsg = await wallet.signMessage(wallet.publicKey, wallet.privateKey)
|
|
|
+ // console.log('sigMsg',sigMsg,accounts[0],wallet.privateKey)
|
|
|
+
|
|
|
+ // let flatSig = signer.signMessage(accounts[0]);
|
|
|
+ // sigMsg= ethers.utils.splitSignature(flatSig);
|
|
|
+ // sigMsg ="0";
|
|
|
+ // console.log("sigMsg--->>",sigMsg);
|
|
|
+ // sigMsg = '0xced71e9bd9e1f7730d1dab6070904b8f670fecdcbd8690b2c7bc16440cf3189f64708e8d17b69d23bcab7724cab3ac07a47667f9a7e13123d39b83eefab233761b';
|
|
|
+ // sigMsg = '0x6c4f1ef1ac7e21d76df9e0023bf893206afbcb6026fa234878ad9dcfb9ff6a293858f592df5fada79e857014452b51e21230bdc0742735f93bc826142638abb21b';
|
|
|
+ // 签名文本消息
|
|
|
+ // signedMsg = signer.signedMsg(signedMsg);
|
|
|
+ let creationParams = {
|
|
|
+ id: id,
|
|
|
+ // signedMsg: signedMsg,
|
|
|
+ // signedMsg: sigMsg,
|
|
|
+ recipient: accounts[0],
|
|
|
+ gasLimit: 310000
|
|
|
+ }
|
|
|
+ console.log("id", id)
|
|
|
+ redPacketContract.on("ClaimSuccess", (id, recipient, claimed_tokens, token_address) => {
|
|
|
+ console.log("ClaimSuccess ->", id, recipient, claimed_tokens.toString(10), token_address);
|
|
|
+ });
|
|
|
+ let res = await redPacketContract.claim(creationParams.id, creationParams.recipient, { gasLimit: creationParams.gasLimit });
|
|
|
+
|
|
|
+ // let res = await redPacketContract.claim(creationParams.id, creationParams.signedMsg, creationParams.recipient, { gasLimit: creationParams.gasLimit, from: accounts[0] });
|
|
|
+ // let res = await redPacketContract.claim(creationParams.id, creationParams.signedMsg, creationParams.recipient);
|
|
|
+ console.log("claim res", res)
|
|
|
+ } catch (error) {
|
|
|
+ console.log("claim_tokens ", error)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 检查红包状态
|
|
|
+ */
|
|
|
+ const check_availability = async () => {
|
|
|
+ let password_bytes32 = ethers.utils.formatBytes32String("19921001");
|
|
|
+ let password = ethers.utils.keccak256(password_bytes32);
|
|
|
+ console.log('password',password)
|
|
|
+ //拿到 window 中以太坊的属性
|
|
|
+ const { ethereum } = window;
|
|
|
+ if (ethereum) {
|
|
|
+ try {
|
|
|
+ const provider = new ethers.providers.Web3Provider(ethereum);
|
|
|
+ const signer = provider.getSigner();
|
|
|
+ const redPacketContract = new ethers.Contract(contractAddress, read_packet_abi, signer);
|
|
|
+ console.log("red packet contract addree", redPacketContract.address);
|
|
|
+ const accounts = await ethereum.request({ method: "eth_requestAccounts" });
|
|
|
+ let id = redid;
|
|
|
+ let checkParams = {
|
|
|
+ id: id
|
|
|
+ }
|
|
|
+ console.log("id", id)
|
|
|
+ redPacketContract.check_availability(checkParams.id).then((res) => {
|
|
|
+ console.log("res", res)
|
|
|
+ console.log("当前token_address=%s 红包余额balance=%s 红包总数total=%s 领取红包数claimed=%s", res[0], res[1].toString(10), res[2].toString(10), res[3].toString(10))
|
|
|
+ }).catch()
|
|
|
+ } catch (error) {
|
|
|
+ console.log("check_availability ", error)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ //创建一个红包
|
|
|
+ const create_red_packet = async () => {
|
|
|
+ try {
|
|
|
+ //拿到 window 中以太坊的属性
|
|
|
+ const { ethereum } = window;
|
|
|
+ if (ethereum) {
|
|
|
+ const provider = new ethers.providers.Web3Provider(ethereum);
|
|
|
+ const signer = provider.getSigner();
|
|
|
+ const redPacketContract = new ethers.Contract(contractAddress, read_packet_abi, signer);
|
|
|
+ console.log("red packet contract addree", redPacketContract.address);
|
|
|
+ let rands = (Math.ceil(Math.random() * 100)).toString();
|
|
|
+ let seed_bytes32 = ethers.utils.formatBytes32String(rands);
|
|
|
+ let seed_v = ethers.utils.keccak256(seed_bytes32);
|
|
|
+ console.log("seed",seed_v)
|
|
|
+ const accounts = await ethereum.request({ method: "eth_requestAccounts" });
|
|
|
+ let creationParams = {
|
|
|
+ public_key: accounts[0],
|
|
|
+ number: 1,//红包数量
|
|
|
+ ifrandom: true,//是否随机
|
|
|
+ duration: 1000*600,//红包有效时间 毫秒
|
|
|
+ seed: seed_v,//随机种子
|
|
|
+ message: 'Hi-devyk-test-red-packet',
|
|
|
+ name: 'devyk',
|
|
|
+ token_type: 0,
|
|
|
+ token_addr:accounts[0],
|
|
|
+ total_tokens: BigNumber.from('10000000000000000'),//红包总的金币
|
|
|
+ gasLimit: 310000
|
|
|
+ }
|
|
|
+
|
|
|
+ console.log("gasLimit=", ethers.utils.formatEther(creationParams.gasLimit))
|
|
|
+ console.log("value=", ethers.utils.formatEther(creationParams.total_tokens))
|
|
|
+ redPacketContract.on("CreationSuccess", (received_amount, _id, _name, _message, msg_sender, block_timestamp, _token_addr, number, ifrandom, duration) => {
|
|
|
+ console.log("CreationSuccess ->", received_amount, _id, _name, _message, msg_sender, block_timestamp, _token_addr, number, ifrandom, duration);
|
|
|
+ console.log("CreationSuccess id ->", _id);
|
|
|
+ });
|
|
|
+
|
|
|
+ let testUpgradeable = await redPacketContract.getTestUpgradeable();
|
|
|
+ console.log("getTestUpgradeable value=", testUpgradeable.toString(10))
|
|
|
+
|
|
|
+ await redPacketContract.create_red_packet(
|
|
|
+ creationParams.public_key,
|
|
|
+ creationParams.number,
|
|
|
+ creationParams.ifrandom,
|
|
|
+ creationParams.duration,
|
|
|
+ creationParams.seed,
|
|
|
+ creationParams.message,
|
|
|
+ creationParams.name,
|
|
|
+ creationParams.token_type,
|
|
|
+ creationParams.token_addr,
|
|
|
+ creationParams.total_tokens,
|
|
|
+ { gasLimit: creationParams.gasLimit, value: creationParams.total_tokens }
|
|
|
+ )
|
|
|
+ console.log("create_red_packet ok ----> create info:", creationParams)
|
|
|
+ }
|
|
|
+ } catch (error) {
|
|
|
+ console.log("create_red_packet ", error)
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ useEffect(() => {
|
|
|
+ checkIfWalletIsConnected();
|
|
|
+ // eslint-disable-next-line react-hooks/exhaustive-deps
|
|
|
+ }, [])
|
|
|
+
|
|
|
+ return (
|
|
|
+ <div className="mainContainer">
|
|
|
+ <div className="dataContainer">
|
|
|
+ <div className="header">
|
|
|
+
|
|
|
+ </div>
|
|
|
+ {/*
|
|
|
+ <div className="bio">
|
|
|
+ Hiya there! I'm <a href="https://twitter.com/seanplusplus" target="_blank" rel="noopener noreferrer" >Sean</a>, and I'm a Sr Software Engineer at Disney digital media.
|
|
|
+ This is a prototype I am <a href="https://github.com/SeanPlusPlus/waveportal-starter-project" target="_blank" rel="noopener noreferrer" >hacking together</a> based on <a href="https://app.buildspace.so/projects/CO02cf0f1c-f996-4f50-9669-cf945ca3fb0b/lessons/LEe9f04c2e-fe9c-4e87-81b2-efb677a1720c" target="_blank" rel="noopener noreferrer" >this tutorial</a>.
|
|
|
+ Connect your Ethereum wallet (make sure you're on the Rinkeby test network), craft a message, and wave at me!
|
|
|
+ To start, you probably should <a href="https://web3hackathon.vercel.app/how-to" target="_blank" rel="noopener noreferrer" >follow this</a> (you can go and mint your very own 🏈 NFT there while you're at it).
|
|
|
+ </div> */}
|
|
|
+
|
|
|
+ {currentAccount && (
|
|
|
+ <>
|
|
|
+ <button className="create_red_packet" onClick={create_red_packet}>
|
|
|
+ {!mining && `create_red_packet`}
|
|
|
+ {mining && `Mining ...`}
|
|
|
+ </button>
|
|
|
+
|
|
|
+ <button className="check_availability" onClick={check_availability}>
|
|
|
+ check_availability
|
|
|
+ </button>
|
|
|
+
|
|
|
+ <button className="claim_tokens" onClick={claim_tokens}>
|
|
|
+ claim_tokens
|
|
|
+ </button>
|
|
|
+
|
|
|
+ <button className="refund" onClick={refund}>
|
|
|
+ refund
|
|
|
+ </button>
|
|
|
+
|
|
|
+ {!mining &&
|
|
|
+ <span className="smiling">
|
|
|
+ <span role="img" aria-label="smile">😃</span>
|
|
|
+ </span>
|
|
|
+ }
|
|
|
+
|
|
|
+ {mining &&
|
|
|
+ <span className="mining">
|
|
|
+ <span role="img" aria-label="waiting">⏳</span>
|
|
|
+ </span>
|
|
|
+ }
|
|
|
+ </>
|
|
|
+ )}
|
|
|
+
|
|
|
+ {/*
|
|
|
+ * If there is no currentAccount render this button
|
|
|
+ */}
|
|
|
+ {!currentAccount && (
|
|
|
+ <button className="connectWallet" onClick={connectWallet}>
|
|
|
+ Connect Wallet
|
|
|
+ </button>
|
|
|
+ )}
|
|
|
+ </div>
|
|
|
+ <Modal show={showModal} onHide={handleClose}>
|
|
|
+ <Modal.Header closeButton>
|
|
|
+ <Modal.Title>Heads Up!</Modal.Title>
|
|
|
+ </Modal.Header>
|
|
|
+ <Modal.Body><span role="img" aria-label="warn">⛔️</span> Must wait 30 seconds before waving again.</Modal.Body>
|
|
|
+ <Modal.Footer>
|
|
|
+ <Button variant="secondary" onClick={handleClose}>
|
|
|
+ Got it
|
|
|
+ </Button>
|
|
|
+ </Modal.Footer>
|
|
|
+ </Modal>
|
|
|
+ </div>
|
|
|
+ );
|
|
|
+ }
|
|
|
+
|
|
|
+ export default App
|