如何将我的 Solidity 合约定义为 javascript 对象?
How can I define my Solidity contract as a javascript object?
我正在制作一个简单的应用程序作为智能合约的前端。该合同具有 public 字符串属性 'message',我希望能够通过 newContract.methods.message().call()
.
访问该属性
我定义了一个对 showMessage() 函数的 onclick 调用,该函数应该将消息属性记录到控制台,但是当我单击具有 onclick 事件的按钮时,我收到此 [=39] 底部的错误消息=].
新合约对象实例化下方的检查表明该类型不是未定义的,但我仍然收到 'undefined' 错误。
编辑:
删除了无关的 ABI 部分并添加了智能合约源代码。
问题似乎与 newContract
对象的范围有关。即使它是用 var
声明的,它也不能通过 showMessage()
函数内的全局 window 对象访问。正确的范围是什么?
<!DOCTYPE html>
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/web3/1.3.5/web3.min.js" integrity="sha512-S/O+gH5szs/+/dUylm15Jp/JZJsIoWlpSVMwT6yAS4Rh7kazaRUxSzFBwnqE2/jBphcr7xovTQJaopiEZAzi+A==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script type="text/javascript">
let web3js;
function startApp() {
var address = "...";
const jsoninterface = [
{
"inputs": [
{
"internalType": "string",
"name": "_newMessage",
"type": "string"
}
],
"name": "setMessage",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "message",
"outputs": [
{
"internalType": "string",
"name": "",
"type": "string"
}
],
"stateMutability": "view",
"type": "function"
}
]
var newContract = new web3js.eth.Contract(jsoninterface, address);
if (typeof newContract === 'object' && typeof newContract !== 'undefined' && newContract !== null){
console.log("contract created")
} else {
console.log("contract not created")
}
}
window.addEventListener('load', function() {
// Checking if Web3 has been injected by the browser (Mist/MetaMask)
if (typeof web3 !== 'undefined') {
// Use Mist/MetaMask's provider
web3js = new Web3(web3.currentProvider);
} else {
alert("Please install Metamask to continue");
// Handle the case where the user doesn't have Metamask installed
// Probably show them a message prompting them to install Metamask
}
// Now you can start your app & access web3 freely:
startApp();
console.log('startapp finished')
})
function showMessage(){
var retval = window.newContract.methods.message().call();
console.log(retval);
}
</script>
</head>
<body>
<!-- the content goes here -->
<button onclick="showMessage()">click here</button>
</body>
</html>
这是控制台的输出。
contract created
startapp finished
Uncaught TypeError: Cannot read property 'message' of undefined
at showMessage ((index):132)
at HTMLButtonElement.onclick ((index):140)
showMessage @ (index):132
onclick @ (index):140
以下是智能合约代码
pragma solidity >=0.7.0 <0.9.0;
contract HelloWorld {
string public message = "Hello World";
uint public counter = 0;
function setMessage(string calldata _newMessage) public {
message = _newMessage;
}
function incrementCounter() public {
counter++;
}
}
您的 ABI JSON 定义了一个 setMessage()
函数,但没有 message
属性(或函数)。如果你的合约中有 message
属性 (或函数),它需要是 external
或 public
才能从合约外部读取。
在将 属性 或函数设为外部或 public 后,您还需要重新生成 ABI JSON。
问题确实是合同变量的范围,进行下面箭头指示的两个更改让我解决了我的问题。
<!DOCTYPE html>
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/web3/1.3.5/web3.min.js" integrity="sha512-S/O+gH5szs/+/dUylm15Jp/JZJsIoWlpSVMwT6yAS4Rh7kazaRUxSzFBwnqE2/jBphcr7xovTQJaopiEZAzi+A==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script type="text/javascript">
let web3js;
---------> var newContract;
function startApp() {
var address = "...";
const jsoninterface = [
{
"inputs": [
{
"internalType": "string",
"name": "_newMessage",
"type": "string"
}
],
"name": "setMessage",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "message",
"outputs": [
{
"internalType": "string",
"name": "",
"type": "string"
}
],
"stateMutability": "view",
"type": "function"
}
]
---------> window.newContract = new web3js.eth.Contract(jsoninterface, address);
if (typeof newContract === 'object' && typeof newContract !== 'undefined' && newContract !== null){
console.log("contract created")
} else {
console.log("contract not created")
}
}
window.addEventListener('load', function() {
// Checking if Web3 has been injected by the browser (Mist/MetaMask)
if (typeof web3 !== 'undefined') {
// Use Mist/MetaMask's provider
web3js = new Web3(web3.currentProvider);
} else {
alert("Please install Metamask to continue");
// Handle the case where the user doesn't have Metamask installed
// Probably show them a message prompting them to install Metamask
}
// Now you can start your app & access web3 freely:
startApp();
console.log('startapp finished')
})
function showMessage(){
var retval = window.newContract.methods.message().call();
console.log(retval);
}
</script>
</head>
<body>
<!-- the content goes here -->
<button onclick="showMessage()">click here</button>
</body>
</html>
我正在制作一个简单的应用程序作为智能合约的前端。该合同具有 public 字符串属性 'message',我希望能够通过 newContract.methods.message().call()
.
我定义了一个对 showMessage() 函数的 onclick 调用,该函数应该将消息属性记录到控制台,但是当我单击具有 onclick 事件的按钮时,我收到此 [=39] 底部的错误消息=].
新合约对象实例化下方的检查表明该类型不是未定义的,但我仍然收到 'undefined' 错误。
编辑:
删除了无关的 ABI 部分并添加了智能合约源代码。
问题似乎与 newContract
对象的范围有关。即使它是用 var
声明的,它也不能通过 showMessage()
函数内的全局 window 对象访问。正确的范围是什么?
<!DOCTYPE html>
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/web3/1.3.5/web3.min.js" integrity="sha512-S/O+gH5szs/+/dUylm15Jp/JZJsIoWlpSVMwT6yAS4Rh7kazaRUxSzFBwnqE2/jBphcr7xovTQJaopiEZAzi+A==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script type="text/javascript">
let web3js;
function startApp() {
var address = "...";
const jsoninterface = [
{
"inputs": [
{
"internalType": "string",
"name": "_newMessage",
"type": "string"
}
],
"name": "setMessage",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "message",
"outputs": [
{
"internalType": "string",
"name": "",
"type": "string"
}
],
"stateMutability": "view",
"type": "function"
}
]
var newContract = new web3js.eth.Contract(jsoninterface, address);
if (typeof newContract === 'object' && typeof newContract !== 'undefined' && newContract !== null){
console.log("contract created")
} else {
console.log("contract not created")
}
}
window.addEventListener('load', function() {
// Checking if Web3 has been injected by the browser (Mist/MetaMask)
if (typeof web3 !== 'undefined') {
// Use Mist/MetaMask's provider
web3js = new Web3(web3.currentProvider);
} else {
alert("Please install Metamask to continue");
// Handle the case where the user doesn't have Metamask installed
// Probably show them a message prompting them to install Metamask
}
// Now you can start your app & access web3 freely:
startApp();
console.log('startapp finished')
})
function showMessage(){
var retval = window.newContract.methods.message().call();
console.log(retval);
}
</script>
</head>
<body>
<!-- the content goes here -->
<button onclick="showMessage()">click here</button>
</body>
</html>
这是控制台的输出。
contract created
startapp finished
Uncaught TypeError: Cannot read property 'message' of undefined
at showMessage ((index):132)
at HTMLButtonElement.onclick ((index):140)
showMessage @ (index):132
onclick @ (index):140
以下是智能合约代码
pragma solidity >=0.7.0 <0.9.0;
contract HelloWorld {
string public message = "Hello World";
uint public counter = 0;
function setMessage(string calldata _newMessage) public {
message = _newMessage;
}
function incrementCounter() public {
counter++;
}
}
您的 ABI JSON 定义了一个 setMessage()
函数,但没有 message
属性(或函数)。如果你的合约中有 message
属性 (或函数),它需要是 external
或 public
才能从合约外部读取。
在将 属性 或函数设为外部或 public 后,您还需要重新生成 ABI JSON。
问题确实是合同变量的范围,进行下面箭头指示的两个更改让我解决了我的问题。
<!DOCTYPE html>
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/web3/1.3.5/web3.min.js" integrity="sha512-S/O+gH5szs/+/dUylm15Jp/JZJsIoWlpSVMwT6yAS4Rh7kazaRUxSzFBwnqE2/jBphcr7xovTQJaopiEZAzi+A==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script type="text/javascript">
let web3js;
---------> var newContract;
function startApp() {
var address = "...";
const jsoninterface = [
{
"inputs": [
{
"internalType": "string",
"name": "_newMessage",
"type": "string"
}
],
"name": "setMessage",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "message",
"outputs": [
{
"internalType": "string",
"name": "",
"type": "string"
}
],
"stateMutability": "view",
"type": "function"
}
]
---------> window.newContract = new web3js.eth.Contract(jsoninterface, address);
if (typeof newContract === 'object' && typeof newContract !== 'undefined' && newContract !== null){
console.log("contract created")
} else {
console.log("contract not created")
}
}
window.addEventListener('load', function() {
// Checking if Web3 has been injected by the browser (Mist/MetaMask)
if (typeof web3 !== 'undefined') {
// Use Mist/MetaMask's provider
web3js = new Web3(web3.currentProvider);
} else {
alert("Please install Metamask to continue");
// Handle the case where the user doesn't have Metamask installed
// Probably show them a message prompting them to install Metamask
}
// Now you can start your app & access web3 freely:
startApp();
console.log('startapp finished')
})
function showMessage(){
var retval = window.newContract.methods.message().call();
console.log(retval);
}
</script>
</head>
<body>
<!-- the content goes here -->
<button onclick="showMessage()">click here</button>
</body>
</html>