如何使用ethers.js从智能合约功能中获取返回的数据?

发布于 2025-01-22 22:33:29 字数 3469 浏览 0 评论 0原文

我正在尝试使用ethers.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用户。而是在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

当我在混合iDE上尝试合同的功能时,所有这些功能都按预期工作。例如,在混音中,我得到了此答案,其中该函数检索到的数据是在解码的输出上。

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函数中获得返回的数据?

I'm trying to consume a function from a smart contract using ethers.js. The function retrieve the info of a user logged before (with the help of other function). This is the function snippet.

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
        );
    }

With React, I'm rendering a button to get user info, as follow:

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>
    );
};

I wonder why I'm not getting the return result of the smart contract getUser function, I expected that info at const user after awaiting the function. Instead on const user, I'm having the transaction metadata, as follow:

{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

When I tried my contract's functions on Remix IDE, all worked as expected. For instance, at Remix I get this answer, in which the data retrieved by the function is on 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

I would like the same but with React, so how can I have the returned data from the contract getUser function?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

故事未完 2025-01-29 22:33:29

调用getuser时,您要获得事务元数据的原因是因为getuser函数不是view> view函数。
不是view函数会导致区块链为该特定功能调用创建交易,该函数必须由区块链验证,并且在执行GetUser的那一刻不可用。功能。

对于这种情况,推荐的方法是使用事件,即发出事件,其中包含您需要的信息,然后在React方面聆听该事件。

考虑使getuser函数<代码>视图函数,因为它不会更改合同的状态:

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
        );
    }

The reason you are getting the transaction metadata when calling getUser is because the getUser function is not a view function.
Not being a view function causes the blockchain to create a transaction for that specific function call which has to be validated by the blockchain and is not available at the moment you execute your getUser function.

For that type of situation, the recommended approach is to use events i.e. emitting an event with the information you need and, on the react side, listen for the event.

Consider making the getUser function a view function, as it does not change the state of the contract:

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
        );
    }

您想在合同上使用呼叫线,类似于

await erc20.callStatic.getUser(account[0])

call该功能,而不是运行send执行交易(成本化的气体)

you want to be using callStatic on your contract, something like

await erc20.callStatic.getUser(account[0])

so that you call the function, instead of running a send which executes the transaction (costing gas)

蘑菇王子 2025-01-29 22:33:29

这是在其中一条评论中回答一个问题:EVM支持几种“呼叫”,您可以在此处的Yul文档中看到这些问题( https://docs.solitylanditylang.org/en/latest/yul.html.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

This is to answer a question in one of the comments: The EVM supports several kinds of "calls", which you can see in the Yul documentation here (https://docs.soliditylang.org/en/latest/yul.html#evm-dialect). A static call tells the EVM to expect no state changing instructions will be run (i.e., to enforce a call into a "view" function). The other call types are relevant to other types of calls (e.g., delegatecall() is at the core of supporting proxies).

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
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文