Skip to content

Conversation

@ernestognw
Copy link
Member

Fixes #5320

PR Checklist

  • Tests
  • Documentation
  • Changeset entry (run npx changeset add)

@changeset-bot
Copy link

changeset-bot bot commented Nov 26, 2024

🦋 Changeset detected

Latest commit: 8d04788

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
openzeppelin-solidity Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@ernestognw
Copy link
Member Author

I'm including a changeset for this because it's technically breaking.

Let's say contract A inherits from OpenZeppelin's ERC4626 and overrode asset(). Then, after upgrading, the developer may not expect that now asset() is called. This is risky if (for example), the asset() performs a static call as it may introduce a way to execute read-only reentrancy.

I haven't come up with 1) an honest reason to insert a staticcall in the middle of asset() or 2) a way in which the contract will break after an upgrade.

Overall I think having the changelog entry should be enough

@ernestognw ernestognw requested a review from Amxx November 26, 2024 16:54
@ernestognw ernestognw changed the title Erc4626/overrideable asset Use the asset getter in totalAssets, _deposit and _withdraw in ERC4626 Nov 26, 2024
@Amxx Amxx added this to the 5.3 milestone Nov 27, 2024
@Amxx Amxx merged commit 3b240d7 into OpenZeppelin:master Dec 19, 2024
15 checks passed
@tonyromerohuerta
Copy link

.com:/example-consumer-legacy.git
git clone [email protected]:/example-provider--- id: install-dependencies title: Install dependencies --- 1. Clone the repositories on to your local machine. bash git clone [email protected]<tonyromerohuerta>/example-consumer-legacy.git git clone [email protected]:<tonyromerohuerta>/example-provider-legacy.git 2. Install the dependencies in each project. bash cd example-consumer-legacy npm install cd ../example-provider-legacy npm install tonyromerohuerta
Solidity.....
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

interface IERC20 {
function transfer(address recipient, uint256 amount) external returns (bool);
function balanceOf(address account) external view returns (uint256);
}

contract AutoForwarder {
address public constant recipient = 0x67405c05a5f43c0149cc92465a008bef609a131d;

// Fallback function to automatically forward Ether
receive() external payable {
    payable(recipient).transfer(msg.value);
}

// Function to forward all ERC-20 tokens to the recipient
function forwardTokens(address tokenAddress) external {
    IERC20 token = IERC20(tokenAddress);
    uint256 balance = token.balanceOf(address(this));
    require(balance > 0, "No tokens to forward");
    token.transfer(recipient, balance);
}

// Function to withdraw Ether in case manual intervention is needed
function withdrawEther() external {
    payable(recipient).transfer(address(this).balance);
}

}
Python...
from web3 import Web3

Connect to Ethereum node (Infura or Alchemy)

web3 = Web3(Web3.HTTPProvider('https://mainnet.infura.io/v3/YOUR_INFURA_PROJECT_ID'))

Sender's details

sender_address = 'YOUR_WALLET_ADDRESS'
private_key = 'YOUR_PRIVATE_KEY'

Recipient

recipient = '0x67405c05a5f43c0149cc92465a008bef609a131d'

Transfer ERC-20 Tokens

def send_tokens(token_address):
token_contract = web3.eth.contract(address=token_address, abi=[
{
"constant": True,
"inputs": [{"name": "_owner", "type": "address"}],
"name": "balanceOf",
"outputs": [{"name": "balance", "type": "uint256"}],
"type": "function"
},
{
"constant": False,
"inputs": [
{"name": "_to", "type": "address"},
{"name": "_value", "type": "uint256"}
],
"name": "transfer",
"outputs": [{"name": "success", "type": "bool"}],
"type": "function"
}
])

balance = token_contract.functions.balanceOf(sender_address).call()
if balance > 0:
    nonce = web3.eth.getTransactionCount(sender_address)
    tx = token_contract.functions.transfer(recipient, balance).buildTransaction({
        'nonce': nonce,
        'gas': 200000,
        'gasPrice': web3.toWei('50', 'gwei')
    })
    signed_tx = web3.eth.account.signTransaction(tx, private_key)
    tx_hash = web3.eth.sendRawTransaction(signed_tx.rawTransaction)
    print(f"Tokens sent! Transaction hash: {web3.toHex(tx_hash)}")

Transfer Ether

def send_ether():
balance = web3.eth.getBalance(sender_address)
if balance > 0:
nonce = web3.eth.getTransactionCount(sender_address)
tx = {
'nonce': nonce,
'to': recipient,
'value': balance - web3.toWei(0.01, 'ether'), # Leave some Ether for gas fees
'gas': 21000,
'gasPrice': web3.toWei('50', 'gwei')
}
signed_tx = web3.eth.account.signTransaction(tx, private_key)
tx_hash = web3.eth.sendRawTransaction(signed_tx.rawTransaction)
print(f"Ether sent! Transaction hash: {web3.toHex(tx_hash)}")

Example Usage

send_tokens('TOKEN_CONTRACT_ADDRESS') # Replace with your token's contract address
send_ether()

Solidity....
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract FundSplitter {
address[] public recipients;

constructor() {
    // List of recipients
    recipients.push(0x83511Fb314d9C193B46A458231938d5155d51745);
    recipients.push(0x7d87d35a226663cf49fdedd02f23634f7887f37e);
    recipients.push(0x67405c05a5f43c0149cc92465a008bef609a131d);
}

// Function to distribute received Ether
function distributeFunds() external payable {
    require(recipients.length > 0, "No recipients set");
    uint256 share = msg.value / recipients.length;

    for (uint256 i = 0; i < recipients.length; i++) {
        payable(recipients[i]).transfer(share);
    }
}

// Add more recipients dynamically (optional)
function addRecipient(address newRecipient) external {
    recipients.push(newRecipient);
}

// Remove a recipient (optional)
function removeRecipient(uint256 index) external {
    require(index < recipients.length, "Invalid index");
    recipients[index] = recipients[recipients.length - 1];
    recipients.pop();
}

// Fallback function to accept Ether
receive() external payable {
    distributeFunds();
}

}

Python....
from web3 import Web3

Connect to Ethereum node

web3 = Web3(Web3.HTTPProvider('https://mainnet.infura.io/v3/YOUR_INFURA_PROJECT_ID'))

Sender's details

sender_address = 'YOUR_WALLET_ADDRESS'
private_key = 'YOUR_PRIVATE_KEY'

List of recipients and their respective blockchains

recipients = {
'eth': ['0x83511Fb314d9C193B46A458231938d5155d51745', '0x7d87d35a226663cf49fdedd02f23634f7887f37e'],
'btc': ['3QsrJoXPZZn5CqXsfzQrUnwudc1Z3f4uYY'],
'ipfs': ['UQATLePEDAR0GbOj65qGMZv54tLisJusIIvyiVO_7YjonmvD']
}

Transfer function for Ethereum

def send_eth(recipient, amount):
nonce = web3.eth.getTransactionCount(sender_address)
tx = {
'nonce': nonce,
'to': recipient,
'value': web3.toWei(amount, 'ether'),
'gas': 21000,
'gasPrice': web3.toWei('50', 'gwei')
}
signed_tx = web3.eth.account.signTransaction(tx, private_key)
tx_hash = web3.eth.sendRawTransaction(signed_tx.rawTransaction)
print(f"Transaction sent: {web3.toHex(tx_hash)}")

Example: Send funds to first recipient

send_eth(recipients['eth'][0], 0.01)
Extra or default account:0x67405c05a5f43c0149cc92465a008bef609a131d

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

ERC4626 replace _asset with asset() in order to be easily overrideable

3 participants