我试图使用以太坊.js从智能合约中消费一个函数。该函数检索之前登录的用户的信息(在其他函数的帮助下)。这是函数片段。
function getUser(address _userAddress)
public
onlyAuthCaller
returns (
string memory name,
string memory info,
string memory role,
)
{
User memory tmpData = userDetails[_userAddress];
return (
tmpData.name,
tmpData.info,
tmpData.role
);
}
与React,我渲染一个按钮来获取用户信息,如下所示:
const GetUser = () => {
const askUser = async () => {
const provider = new ethers.providers.Web3Provider(window.ethereum);
const account = await window.ethereum.request({
method: "eth_requestAccounts",
});
const signer = provider.getSigner();
const erc20 = new ethers.Contract(
ContractAddress,
ContractABI.abi,
signer
);
try {
const user = await erc20.getUser(account[0]);
console.log(user);
} catch (error) {
console.log("ERROR AT GETTING USER: ", error);
}
};
return (
<div>
<Button type="submit" variant="contained" onClick={askUser}>
GET USER
</Button>
</div>
);
};
我想知道为什么我没有得到智能合约getUser
函数的返回结果,我在等待函数后期待const user
的信息。相反,在const user
上,我有事务元数据,如下所示:
{hash: '0x24818569ec29d328b66f58736750a420a5a3bd8e28a72a6a0f72fd8ba5e088d8', type: 2, accessList: null, blockHash: null, blockNumber: null, …}
accessList: null
blockHash: null
blockNumber: null
chainId: 0
confirmations: 0
creates: null
data: "0x6f77926b00000000000000000000000086b2b772014a87730928c7e54f4762d2c09ea4e5"
from: "0x86b2b772014A87730928c7e54F4762d2c09eA4e5"
gasLimit: BigNumber {_hex: '0xd15f', _isBigNumber: true}
gasPrice: BigNumber {_hex: '0x73a20d0c', _isBigNumber: true}
hash: "0x24818569ec29d328b66f58736750a420a5a3bd8e28a72a6a0f72fd8ba5e088d8"
maxFeePerGas: BigNumber {_hex: '0x73a20d0c', _isBigNumber: true}
maxPriorityFeePerGas: BigNumber {_hex: '0x73a20d00', _isBigNumber: true}
nonce: 5
r: "0x6a8fed76397e03a2fc564d18e1ec12abdf39a38fbe825df990f744bb50fc4a8b"
s: "0x66e9b4513047b65aac724dc6fb07d069967f6ca6fd8cd5fe85f6dbe495864765"
to: "0x9719E9dC77A7eDD3825844c77a68c896d4a7BB2b"
transactionIndex: null
type: 2
v: 0
value: BigNumber {_hex: '0x00', _isBigNumber: true}
wait: confirmations => {…}
length: 1
name: ""
arguments: (…)
caller: (…)
[[FunctionLocation]]: index.ts:336
[[Prototype]]: ƒ ()
[[Scopes]]: Scopes[4]
[[Prototype]]: Object
当我在Remix IDE上尝试我的合同功能时,一切都如预期的那样工作。例如,在Remix中,我得到了这个答案,其中函数检索的数据在decoded output
上。
status true Transaction mined and execution succeed
transaction hash 0x206af46a0f8e6bcc04ae632c85da005c901d8fc82f650e8d40a445f6988adcc2
from 0x5B38Da6a701c568545dCfcB03FcB875f56beddC4
to SupplychainUser.getUser(address) 0xD7ACd2a9FD159E69Bb102A1ca21C9a3e3A5F771B
gas 61639 gas
transaction cost 53599 gas
execution cost 53599 gas
input 0x6f7...35cb2
decoded input {
"address _userAddress": "0xAb8483F64d9C6d1EcF9b849Ae677dD3315835cb2"
}
decoded output {
"0": "string: name Carl Bertz",
"1": "string: info 0987654321",
"2": "string: role processor",
}
logs []
val 0 wei
我想和React一样,所以我怎么能从合同getUser
函数返回数据?
调用getUser
时获得事务元数据的原因是因为getUser
函数不是view
函数。不是view
函数会导致区块链为该特定函数调用创建一个交易,该交易必须由区块链验证,并且在执行getUser
函数时不可用。
对于这种情况,推荐的方法是使用事件,即发出带有所需信息的事件,并在反应端侦听该事件。
考虑将getUser
函数改为view
函数,因为它不会改变合约的状态:
function getUser(address _userAddress)
public
view
onlyAuthCaller
returns (
string memory name,
string memory info,
string memory role,
)
{
User memory tmpData = userDetails[_userAddress];
return (
tmpData.name,
tmpData.info,
tmpData.role
);
}
你想在你的合约上使用callStatic,就像
await erc20.callStatic.getUser(account[0])
让你call
函数,而不是运行执行事务的send
(消耗gas)
这是为了回答其中一个评论中的一个问题:EVM支持几种"调用",您可以在这里的Yul文档中看到(https://docs.soliditylang.org/en/latest/yul.html#evm-dialect)。静态调用告诉EVM期望不会运行任何状态改变指令(即强制调用到"视图");功能)。其他调用类型与其他类型的调用相关(例如,delegatecall()是支持代理的核心)。
call(g, a, v, in, insize, out, outsize)
call contract at address a with input mem[in…(in+insize)) providing g gas and v wei and output area mem[out…(out+outsize)) returning 0 on error (eg. out of gas) and 1 on success See more
callcode(g, a, v, in, insize, out, outsize)
identical to call but only use the code from a and stay in the context of the current contract otherwise See more
delegatecall(g, a, in, insize, out, outsize)
identical to callcode but also keep caller and callvalue See more
staticcall(g, a, in, insize, out, outsize)
identical to call(g, a, 0, in, insize, out, outsize) but do not allow state modifications See more