Solidity secure user withdrawal with checks/effects/patterns - security

Can the checks/effects/interactions pattern be used for refunding users securely (in place of a separate withdraw function)?
EG in the case of a bidding system, where if user 2 outbids user 1 and user 1 receives their money back, is the checks/effects/patterns sufficiently secure to send user 1's money back?
For instance, something like
contract auction {
address highestBidder;
uint highestBid;
function bid() payable external {
require(msg.value >= highestBid);
prevHighestBidder = highestBidder
prevHighestBid = highestBid
highestBidder = msg.sender;
highestBid = msg.value;
(bool success, ) = prevHighestBidder.call.value(prevHighestBid)("");
require(success, "Transfer failed.")
}
}
I understand that creating a separate withdraw function is preferred, but I'm hoping to reduce gas costs for users.

What if the receiver (prevHighestBidder) is a contract that rejects the transaction? That would effectively break your game as no one after them could successfully call the bid() function.
Their contract might be as simple as
contract BlockBids {
function callBid() payable {
// call the bid() function with value
address(<yourContract>).call{value: msg.value}('0x1998aeef');
}
receive () external payable {
revert();
}
}
My recommendation is to NOT check whether the prevHighestBidder received the ETH. Or to add a fallback mechanism that withdraws the ETH to your address in case the receiver rejects the transaction, so that you can send it to them after they prove ownership of the winning address (e.g. by signing a message).

Related

What are the ways to automatically receive an updated Ethereum wallet balance?

I looked at a lot of options on Google and besides how to subscribe to the event web3.eth.subscribe("newBlockHeaders"... didn't find anything or just didn't work. But I think this solution is the most resource-intensive and inefficient.
Tell me this is the only way I can implement? Are there any paid solutions?
My task is to track the balance of wallets and notify the user in case of an update.
By updating the balance, I mean when events occur in the wallet:
Transfer received
Transfer sent
This is a sample contract that has two functions that emit, "TransferReceived" and "TransferSent".
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.9;
contract Sample {
event TransferReceived(address sender, uint amount);
event TransferSent(address sender, uint amount);
function SendTransfer() public payable{
emit TransferSent(msg.sender, msg.value);
}
function ReceiveTransfer(uint amount) public {
emit TransferReceived(msg.sender, amount);
}
}
This is the Javascript code to listen for both events on the sample contract. This example uses etherjs:
const contractAddress = process.env.CONTRACT_ADDRESS;
const provider = new ethers.providers.WebSocketProvider(process.env.WEB_SOCKET);
const contract = new ethers.Contract(contractAddress, abi, provider);
export async function handleEvents() {
contract.on("TransferReceived", async (sender, amount,event) => {
//Do Something
})
contract.on("TransferSent", async (sender, amount, event) => {
//Do something
});
}
You can get a WebSocket URL from node providers like Alchemy or Infura.
I hope this helps
Ogubuike Alex's answer is one solution and I commend him for it, but it also remains a resource intensive solution.
I also came across this library, which, through a smart contract, returns the balance of different tokens in the network.
https://www.npmjs.com/package/eth-balance-checker
And I came up with another option:
Using cron to send requests to the blockchain, which is more optimal and not costly in terms of resources.

How to pay rent fee when creating solana wallet in nodejs

hello I create solana wallet with the following code on my nodejs server.
const SolanaWeb3 = require("#solana/web3.js");
SolanaWeb3.Keypair.generate();
I don't think this is an active wallet. Because I haven't paid the rent fee for this account.
**So I want to know when is the moment when this inactive account pays the rent fee.
(I want to know if it is activated when a transaction in which sol is deposited into this account occurs, or whether this account should generate a transaction that sends solana to another place.)
And I want to know if there is a javascript function that gives rent fee when account is created.**
thank you for your reply.
To your second question
And I want to know if there is a javascript function that gives rent fee when account is created
Yes there is. Assuming you just want a system account that holds SOL versus an account that has data:
// amount of space to reserve for the account. system accounts are 0 space
const space = 0;
// Get the rent, in lamports, for exemption
const rentExemptionAmount =
await connection.getMinimumBalanceForRentExemption(space);
To your first question
If you already have a funded account (fromKeyPair), you can use that accounts public key to fund the new account you want to create:
const newAccountKeypair = SolanaWeb3.Keypair.generate();
const createAccountParams = {
fromPubkey: fromKeyPair.publicKey,
newAccountPubkey: newAccountKeypair.publicKey,
lamports: rentExemptionAmount,
space,
programId: SolanaWeb3.SystemProgram.programId,
};
const createAccountTransaction = new SolanaWeb3.Transaction().add(
SolanaWeb3.SystemProgram.createAccount(createAccountParams)
);
await SolanaWeb3.sendAndConfirmTransaction(connection, createAccountTransaction, [
fromKeyPair,
newAccountKeypair,
]);

Solana program to send multiple lamport transfers and emit event

I’m building a program intended to manage multiple payments with one call. The program needs to complete the following steps:
Accept a certain amount of lamports
Pay a portion of the received lamports to specified wallets, such that the amount received is exhausted
Emit an event containing the receipt
I’ve built this logic with an Ethereum smart contract and it works perfectly fine, however when attempting to write a Solana program with Solang and #solana/solidity, I’m running into a number of issues.
The first issue I encountered was simply that #solana/solidity seems to not be built for front end use (transactions required a private key as an argument, rather than being signed by a wallet like Phantom) so I built a fork of the repository that exposes the transaction object to be signed. I also found that the signer’s key needed to be manually added to the array of keys in the transaction instruction — see this Stack Overflow post for more information, including the front end code used to sign and send the transaction.
However, after this post I ran into more errors, take the following for example:
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
The error messages seemed to be inconsistent, with some attempts throwing different errors despite the only changes in the code being a server restarting or a library being reinstalled.
Although solutions to the previous errors would be greatly appreciated, at this point I’m more inclined to ask more broadly if what I’m trying to do is possible, and, providing the source code, for help understanding what I need to do to make it work.
Below is the working source code for my Ethereum contract:
// 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
);
}
}
The only differences between this code and my Solana program code are types and the method used to transfer lamports. All references to uint256 is replaced by uint64, the placeholder token address is changed from the null address to the system public key (address"11111111111111111111111111111111"), and the payment loop is changed to the following:
for (uint8 i = 0; i < _receivers.length; i++) {
payable(_receivers[i]).transfer(_amounts[i]); // Using .send() throws the same error
}
The code used to then deploy the program to the Solana test validator is as follows, only slightly modified from the example provided by #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);
})();
Is there something I’m misunderstanding or misusing here? I find it hard to believe that such simple behavior on the Ethereum blockchain couldn’t be replicated on Solana — especially given the great lengths the community has gone to to make Solana programming accessible through Solidity. If there’s something I’m doing wrong with this code I’d love to learn. Thank you so much in advance.
Edit: After upgrading my solang version, the first error was fixed. However, I'm now getting another error:
Error: failed to send transaction: Transaction simulation failed: Error processing Instruction 0: instruction changed the balance of a read-only account
I'm not sure which account is supposedly read-only, as it isn't listed in the error response, but I'm pretty sure the only read-only account involved is the program as it's executable. How can I avoid this error?
The error Attempt to debit an account but found no record of a prior credit happens when you attempt to airdrop more than 1 SOL. If you wish to have more than 1 SOL, then airdrop 1 SOL in a loop until you have enough.

How to get list of charge ids for CONNECTED ACCOUNT payout object in stripe

I store the id from each Charge and associate with a purchase.
I have connected accounts in my application. I want to show them the breakdown of purchases per payout. To do that I need a way to get the list of charge_ids per payout.
I received an official response from stripe, there is no way to do it in one query but there is a way.
1) a charge ch_xxxx and a related transaction (txn_xxxxxx) is created
on platform account
After the platform receives the charge, platform account will create a
transfer to the connected account (tr_xxxxxx) and the transfer object
is on Platform Account as well
2) When connected account received the transfer, an payment object
will be created (py_xxxxxx) and a related transaction (txn_xxxxx) On
the connected account, these payment transactions will be grouped
together and paid out in a "po_xxxxxx"
So between platform account and connected account, from connected
account payout to charge, the overall flow looks like this:
payout (po_xxxx) -> transactions (txn_xxxx) -> payment(py_xxxx) ->
transfer(tr_xxxx) -> charge (ch_xxxxx)
public static void ListTransactionsForPayout(String payout) throws StripeException {
//1. Get a list of transactions for payout in Connected account
Map<String, Object> balancetransactionParams = new HashMap<String, Object>();
balancetransactionParams.put("limit", 20);
balancetransactionParams.put("payout", "po_1Dy8ZfKxxxxxx");
List<String> expandList = new LinkedList<String>();
expandList.add("data.source");
balancetransactionParams.put("expand", expandList);
RequestOptions requestOptions = RequestOptions.builder()
.setStripeAccount("acct_connected_account")
.build();
BalanceTransactionCollection transactions = BalanceTransaction.list(balancetransactionParams, requestOptions);
for (BalanceTransaction txn : transactions.autoPagingIterable()) {
if (txn.getType().equals("payment")) {
Charge charge = (Charge) txn.getSourceObject();
// 2. Get transfers from payment and get charge from transfer
Transfer transfer = Transfer.retrieve(charge.getSourceTransfer());
System.out.printf("txn %s -> payment %s -> transfer %s -> charge %s\n", txn.getId(), txn.getSource(), transfer.getId(), transfer.getSourceTransaction());
}
}
}

Facebook Messenger Bot, can someone tell me how i catch the answer of a something i asked

So i working on my Facebook Messenger Bot.
I want to know ho can i catch a answer for a question like
Bot: Enter your E-mail
User: enters e-mail
Bot: adress was added
My code looks like the sample app from Facebook
app.post('/webhook', function (req, res) {
var data = req.body;
// Make sure this is a page subscription
if (data.object == 'page') {
// Iterate over each entry
// There may be multiple if batched
data.entry.forEach(function(pageEntry) {
var pageID = pageEntry.id;
var timeOfEvent = pageEntry.time;
// Iterate over each messaging event
pageEntry.messaging.forEach(function(messagingEvent) {
if (messagingEvent.optin) {
receivedAuthentication(messagingEvent);
} else if (messagingEvent.message) {
receivedMessage(messagingEvent);
} else if (messagingEvent.delivery) {
receivedDeliveryConfirmation(messagingEvent);
} else if (messagingEvent.postback) {
receivedPostback(messagingEvent);
} else {
console.log("Webhook received unknown messagingEvent: ", messagingEvent);
}
});
});
// Assume all went well.
//
// You must send back a 200, within 20 seconds, to let us know you've
// successfully received the callback. Otherwise, the request will time out.
res.sendStatus(200);
}
});
You can set a flag for their ID that the E-Mail prompt was sent, and then after they respond check to see if it's an E-mail, and if so, then save it and echo it back to them.
If the bot is based on question/answer, what I normally do to handle response tracking is treat the bot like a finite state automata. Assign every "state" your bot can be in to some unique state identifier, and use said state identifier to determine what the user is replying to. You could also store callbacks instead of state ids, but high level this will behave the same way.
For Example:
First define a finite automata. In this case, lets assume it's:
0 --> 1 --> 2
Where 0 means new user, 1 means waiting for email response, 2 means user successfully completed registration.
User messages bot
We check our database and see it's a new user. We assume
state==0.
Because state is 0, we ignore what was sent and prompt for email
Change state to 1 to denote the email was prompted.
User replies with email.
We check database and see state==1. We use the "1" routine to do fancy stuff to verify the email and store it.
Change state to 2 to denote the email was received and the program has ended.
Note:
If the conversation id for the platform you're targeting is reset
after a certain amount of inactivity (or if you just want the bot to
mimic real conversations), store the time of each user's last
interaction and purge all inactive conversations well after the
conversation has been terminated.

Resources