我正在尝试为彩票智能合同构建一个分散的应用程序,部署在本地的ganache ethereum网络上,但在这种情况下,我使用的是来自Truffle的毛毛雨工具。
这是智能契约,非常简单,它有pickWinner、enter和getPlayers函数。
contract Lottery {
address public manager;
address payable[] public players;
uint256 index;
constructor() payable {
manager = msg.sender;
}
function enter() public payable {
require(msg.value == .02 ether);
players.push(payable(msg.sender));
}
function random() private view returns (uint256) {
return
uint256(
keccak256(
abi.encodePacked(block.difficulty, block.timestamp, players)
)
);
}
function pickWinner() public restricted {
index = random() % players.length;
players[index].transfer(address(this).balance);
players = new address payable[](0);
}
modifier restricted() {
require(msg.sender == manager);
_;
}
function getPlayers() public view returns (address payable[] memory) {
return players;
}
}我已经安装了@微雨/商店和web3模块。我还创建了一个名为contracts的文件夹与智能契约在本地Ganache网络上部署时生成的工件之间的符号链接,这是为了创建智能契约的一个实例,以及在通过毛毛雨访问智能契约时,如果更新了它的最后一个版本。我在-s ./../构建/合同中使用。
在这个项目上,我有一个index.js文件。这是在负责创建一个毛毛雨对象,并从与工件链接的源文件加载智能契约,然后有一个Redux商店来包含彩票智能契约的状态,并在应用程序的App组件中包含微流对象。
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import { Drizzle, generateStore } from "@drizzle/store";
import Lottery from "./contracts/Lottery.json";
const options = { contracts: [Lottery] };
const drizzleStore = generateStore(options);
const drizzle = new Drizzle(options, drizzleStore);
ReactDOM.render(<App drizzle={drizzle} />, document.getElementById("root"));那么我就有了一个App.js文件。这是在负责定义,这个组件是传递一个毛毛雨对象和毛毛雨存储从index.js文件。App组件使用它们订阅毛毛雨商店的更新。由于应用程序是模块化的,有一些子组件,为了访问和更新彩票智能契约,向其中传递drizzleState对象和毛毛雨对象。
import React, { Component } from 'react';
import './App.css';
import ViewPlayers from "./ViewPlayers";
import EnterLottery from "./EnterLottery";
import PickWinner from "./PickWinner";
import ViewDetails from "./ViewDetails";
class App extends Component {
state = { loading: true, drizzleState: null };
async componentDidMount() {
const { drizzle } = this.props;
this.unsubscribe = drizzle.store.subscribe(() => {
const drizzleState = drizzle.store.getState();
if (drizzleState.drizzleStatus.initialized) {
this.setState({ loading: false, drizzleState });
}
});
}
compomentWillUnmount() {
this.unsubscribe();
}
render() {
if (this.state.loading) return "Loading Drizzle...";
return (
<div className="App">
<h2 >Lottery Contract</h2>
<div align="left">
<ViewDetails
drizzle={this.props.drizzle}
drizzleState={this.state.drizzleState}
/>
</div>
<hr />
<div align="left">
<ViewPlayers
drizzle={this.props.drizzle}
drizzleState={this.state.drizzleState}
/>
</div>
<hr />
<div align="left">
<EnterLottery
drizzle={this.props.drizzle}
drizzleState={this.state.drizzleState}
/>
</div>
<hr />
<div align="left">
<PickWinner
drizzle={this.props.drizzle}
drizzleState={this.state.drizzleState}
/>
</div>
<hr />
</div>
);
}
}
export default App;然后,ViewPlayers、EnterLottery、PickWinner和ViewDetails子组件定义如下:
// ViewPlayers.js
import React from "react";
class ViewPlayers extends React.Component {
state = { dataKey: null };
componentDidMount() {
const { drizzle } = this.props;
const contract = drizzle.contracts.Lottery;
var dataKey = contract.methods.getPlayers.cacheCall();
console.log(contract);
this.setState({ dataKey });
}
render() {
const { Lottery } = this.props.drizzleState.contracts;
const players = Lottery.getPlayers[this.state.dataKey];
var rows = [];
for (var i = 0; i < (players && players.value.length); i++) {
rows.push(<label key={i}> <br />Player {i+1} - {players && players.value[i]} </label>);
}
return <p>All {players && players.value.length } players are {rows}</p>;
}
}
export default ViewPlayers;// EnterLottery.js
import React from "react";
class EnterLottery extends React.Component {
enter = () => {
const { drizzle, drizzleState } = this.props;
const contract = drizzle.contracts.Lottery;
contract.methods.enter.cacheSend({
from: drizzleState.accounts[0],
value: window.web3.utils.toWei(0.2, 'ether')
});
};
render() {
return (
<div>
<h4>Want to try your luck?</h4>
<label>Pay 0.2 ether to enter</label> <br /><br />
<button className='button'
style={{height: 40,
width: 150,
borderRadius: 10,
fontSize: 15}}
onClick={this.enter}> <b>Enter</b> </button>
</div>
);
}
}
export default EnterLottery;// PickWinner.js
import React from "react";
class PickWinner extends React.Component {
pick = () => {
const { drizzle, drizzleState } = this.props;
const contract = drizzle.contracts.Lottery;
contract.methods.pickWinner.cacheSend({
from: drizzleState.accounts[0]
});
};
render() {
return (
<div>
<h4>Ready to pick a winner?</h4>
<div><button className='button'
style={{height: 40,
width: 150,
borderRadius: 10,
fontSize: 15}}
onClick={this.pick} >
<b>Pick Winner</b>
</button></div>
</div>
);
}
}
export default PickWinner;// ViewDetails.js
import React from "react";
class ViewDetails extends React.Component {
state = { manager: null, winningPrize: null};
async componentDidMount() {
const { drizzle } = this.props;
console.log(drizzle);
const contract = drizzle.contracts.Lottery;
var manager = contract.methods.manager.cacheCall();
var winningPrize = await drizzle.web3.eth.getBalance(contract.address)
this.setState({ manager, winningPrize});
}
render() {
const { drizzle } = this.props;
const { Lottery } = this.props.drizzleState.contracts;
const manager = Lottery.manager[this.state.manager];
const balance = this.state.winningPrize;
return (
<p>This contract is managed by <b>{manager && manager.value}</b>.
All players are competing to win <b>{balance && drizzle.web3.utils.fromWei(balance,'ether')}</b> ether!</p>
)
}
}
export default ViewDetails;我和Metamask有联系。
然后,当我运行npm时,网页会呈现出来,但是当我单击enter按钮时,它不会连接到Metamask。我在浏览器控制台上有一个日志:
MetaMask no longer injects web3. For details, see: https://docs.metamask.io/guide/provider-migration.html#replacing-window-web3Uncaught TypeError: Cannot read properties of undefined (reading 'toWei')
at EnterLottery.enter (EnterLottery.js:17:1)
at HTMLUnknownElement.callCallback (react-dom.development.js:3945:1)
at Object.invokeGuardedCallbackDev (react-dom.development.js:3994:1)
at invokeGuardedCallback (react-dom.development.js:4056:1)
at invokeGuardedCallbackAndCatchFirstError (react-dom.development.js:4070:1)
at executeDispatch (react-dom.development.js:8243:1)
at processDispatchQueueItemsInOrder (react-dom.development.js:8275:1)
at processDispatchQueue (react-dom.development.js:8288:1)
at dispatchEventsForPlugins (react-dom.development.js:8299:1)
at react-dom.development.js:8508:1从日志中,我了解到web3注入不再受支持,所以有一种解决方案是使用window.web3.currentProvider,但我不知道如何在EnterLottery.js文件上使用它(也许我甚至应该在其他地方使用它?),我不知道在哪里实现更改才能工作。嗯,我也有一个错误的toWei方法的web3模块。
我该怎么做呢?
发布于 2022-03-13 16:58:19
使用ethereum对象,如元面罩中所述。
https://ethereum.stackexchange.com/questions/123703
复制相似问题