我正在构建一个程序,旨在通过一次调用来管理多次付款。该程序需要完成以下步骤:
- 接受一定数量的 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/