node.js - Solana 程序发送多个lamport 传输并发出事件

标签 node.js ethereum solidity solana solana-web3js

我正在构建一个程序,旨在通过一次调用来管理多次付款。该程序需要完成以下步骤:

  • 接受一定数量的 lamport
  • 将收到的lamport的一部分支付到指定钱包,以便收到的金额用完
  • 发出包含收据的事件

我已经使用以太坊智能合约构建了这个逻辑,并且工作得非常好,但是当尝试使用 Solang 编写 Solana 程序时和 @solana/solidity ,我遇到了很多问题。

我遇到的第一个问题就是 @solana/solidity似乎不是为前端使用而构建的(交易需要私钥作为参数,而不是由像 Phantom 这样的钱包签名),所以我构建了 a fork of the repository公开要签名的交易对象。我还发现签名者的 key 需要手动添加到交易指令中的 key 数组中 - 请参阅this Stack Overflow post了解更多信息,包括用于签名和发送交易的前端代码。

但是,在这篇文章之后我遇到了更多错误,例如:

Transaction simulation failed: Attempt to debit an account but found no record of a prior credit.
Transaction simulation failed: Error processing Instruction 0: instruction changed the balance of a read-only account 
    Program jdN1wZjg5P4xi718DG2HraGuxVx1mM7ebjXpxbJ5R3N invoke [1]
    Program data: PO+eZwYByRZpDC4BOjWoKPj20gquFc/JtyxU9NsuG/Y= DEjYtM7vwjNW3HPewJU3dvG4aiov5tUUlrD6Zz5ylBgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADppnQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAATEtAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAVNC02S0gyMV9Sa3RZZVJIb3FKOFpFAAAAAAAAAAAAAAA=
    Program jdN1wZjg5P4xi718DG2HraGuxVx1mM7ebjXpxbJ5R3N consumed 3850 of 200000 compute units
    Program jdN1wZjg5P4xi718DG2HraGuxVx1mM7ebjXpxbJ5R3N success
    failed to verify account 11111111111111111111111111111111: instruction changed the balance of a read-only account

错误消息似乎不一致,尽管代码中唯一的更改是服务器重新启动或重新安装库,但某些尝试抛出了不同的错误。

虽然我们将非常感谢对之前错误的解决方案,但此时我更倾向于更广泛地询问我想要做的事情是否可能,并且提供源代码,以帮助理解我需要什么使其发挥作用。

以下是我的以太坊合约的工作源代码:

// SPDX-License-Identifier: MIT
pragma solidity >=0.8.4;

contract MyContract {
    event Receipt(
        address From,
                address Token,
        address[] Receivers,
        uint256[] Amounts,
        string Payment
    );

    function send( 
        address[] calldata _receivers,
        uint256[] calldata _amounts,
        string calldata _payment
    ) external payable {
        require(
            _receivers.length == _amounts.length,
            "Receiver count does not match amount count."
        );

        uint256 total;
        for (uint8 i; i < _receivers.length; i++) {
            total += _amounts[i];
        }
        require(
            total == msg.value,
            "Total payment value does not match ether sent"
        );

        for (uint8 i; i < _receivers.length; i++) {
            (bool sent, ) = _receivers[i].call{value: _amounts[i]}("");
            require(sent, "Transfer failed.");
        }

        emit Receipt(
            msg.sender,
            0x0000000000000000000000000000000000000000,
            _receivers,
            _amounts,
            _payment
        );
    }
}

此代码与我的 Solana 程序代码之间的唯一区别是类型和用于传输 lamport 的方法。所有对uint256的引用都被uint64替换,占位符 token 地址从空地址更改为系统公钥(地址“11111111111111111111111111111111” ),支付循环改为如下:

for (uint8 i = 0; i < _receivers.length; i++) {
    payable(_receivers[i]).transfer(_amounts[i]); // Using .send() throws the same error
}

用于将程序部署到 Solana 测试验证器的代码如下,仅对 @solana/solidity 提供的示例稍加修改:

const { Connection, LAMPORTS_PER_SOL, Keypair, PublicKey } = require('@solana/web3.js');
const { Contract } = require('@solana/solidity');
const { readFileSync } = require('fs');

const PROGRAM_ABI = JSON.parse(readFileSync('./build/sol/MyProgram.abi', 'utf8'));
const BUNDLE_SO = readFileSync('./build/sol/bundle.so');

(async function () {
  console.log('Connecting to your local Solana node');
  const connection = new Connection('http://localhost:8899', 'confirmed');

  const payer = Keypair.generate();

  async function airdrop(pubkey, amnt) {
    const sig = await connection.requestAirdrop(pubkey, amnt * LAMPORTS_PER_SOL);
    return connection.confirmTransaction(sig);
  }

  console.log('Airdropping SOL to a new wallet');
  await airdrop(payer.publicKey, 100);

  const program = new Keypair({
    publicKey: new Uint8Array([...]),
    secretKey: new Uint8Array([...])
  });

  const storage = new Keypair({
    publicKey: new Uint8Array([...]),
    secretKey: new Uint8Array([...])
  });

  const contract = new Contract(connection, program.publicKey, storage.publicKey, PROGRAM_ABI, payer);

  console.log('Loading the program');
  await contract.load(program, BUNDLE_SO);

  console.log('Deploying the program');
  await contract.deploy('MyProgram', [], program, storage, 4096 * 8);

  console.log('Program deployed!');

  process.exit(0);
})();

我在这里有什么误解或误用吗?我很难相信以太坊区 block 链上如此简单的行为无法在 Solana 上复制——特别是考虑到社区已经竭尽全力让 Solana 编程可以通过 Solidity 访问。如果我在这段代码中做错了什么,我很乐意学习。提前非常感谢您。

编辑:升级我的 solang 版本后,第一个错误已修复。但是,我现在收到另一个错误:

Error: failed to send transaction: Transaction simulation failed: Error processing Instruction 0: instruction changed the balance of a read-only account

我不确定哪个帐户应该是只读的,因为它没有在错误响应中列出,但我很确定涉及的唯一只读帐户是程序,因为它是可执行的。如何避免这个错误?

最佳答案

当您尝试空投超过 1 SOL 时,会发生尝试借记账户但未发现先前贷记记录错误。如果您希望拥有超过 1 个 SOL,请循环空投 1 个 SOL,直到您拥有足够的 SOL。

关于node.js - Solana 程序发送多个lamport 传输并发出事件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/71898736/

相关文章:

javascript - CryptoCurrency NODE.js Web3 Ethereum - 无法连接到 TESTRPC

ethereum - 如何创建和部署带有以太币的合约?

javascript - 在 TypeScript 2.0 中正确使用 React.Events?

node.js - 在 Nodejs 中将值推送到 Mongodb 模型中

java - Web3J 仲裁 RawTransaction

blockchain - 从其地址获取智能合约实例

javascript - 无法将 Solidity 合约部署到 Rinkeby 网络(无效的 asm.js : Invalid member of stdlib)

node.js - Redis 的 WebPack 问题

node.js - Windows 7 中的 npm install 命令 weinre 失败

blockchain - 我们可以在智能合约中使用 Solidity 获取过去区 block 中记录的交易信息吗?