Smart contracts fallback as a catch all delegatecall - blockchain

I am practicing some vulnerabilities in smart contracts for my lecture in the university.
The contracts that I am practicing on are;
contract Company is CompanyInterface {
address public ceo;
...
function setCeo(address newCeo){
ceo = newCeo;
}
...
}
contract MainCompany is CompanyInterface {
address public ceo;
address public lib; // address of Company contract
...
function() payable external {
if(!lib.delegatecall(msg.data)) {
revert();
}
}
...
}
Here, I try to make myself ceo of the MainCompany. However, I couldn't figure out how to call setCeo here. As I know that when an attacker calls MainCompany.setCeo(attacker), MainCompany's fallback function should be triggered when the function (setCeo) can't be found in the MainCompany contract. However, it doesn't happen.
My approach is to create an attacker contract. In that contract, I created a function that does the following;
<addressOfMainCompany>.call.value(1)(bytes4(keccak256("setCeo(address)")), address(0x4b9...));
But ceo is still same. What is the correct way of changing ceo of the MainCompany here?
Thanks

Related

How to automate a ChainLink Job to call a smart-contract function that requires the caller to be a given admin address?

ChainLink automation enables conditional execution of smart contracts functions. However, when calling function from the smart contract, it is the ChainLink registry contract that calls the function, and not the address that registered the UpKeep.
Therefore, it is likely that the call will fail if the function to call has a require that forces the caller (msg.sender) to be a given address (admin address for example).
Is it possible to automate such kind of functions (with msg.sender set to a needed address) with ChainLink Automation ?
As an example:
mapping() private _balance;
address public admin;
constructor {
admin = msg.sender;
}
modifier onlyAdmin {
require(msg.sender == admin, "Only admin");
_;
}
function pay(address _account, uint256 _amount) public onlyAdmin {
_balance[_account] += _amount;
}
function getBalance(address _account) public view returns(uint256) {
return _balance[_account];
}
update a balance through Chainlink automation. I expect the balance of _account to update to its previous value + _amount.
_balance[account] = _balance[account] + _amount;
As you said transaction sent by Chainlink automation is signed with Chainlink Registry contract, and as far as I know it is impossible to replace the signature with consumer contract's owner's signature.
I think the better way to do this is to modify the modifier onlyAdmin to add address of registry contract.

transfer token out of contract

i had a small question that i creast a contract A and there is 1 busd token in the contract A, now i want to transfer the 1 busd out of contract by owner address
how to set the contractA?
i have use this code to deploy and test
pragma solidity ^0.8;
interface IERC20 {
function transfer(address to, uint256 amount) external returns (bool);
}
contract MyContract {
address owner = 0xFAD69bCefb704c1803A9Bf8f04BC314E78838F88;
function withdrawToken(address tokenContract, uint256 amount) external {
// send `amount` of tokens
// from the balance of this contract
// to the `owner` address
IERC20(tokenContract).transfer(owner, amount);
}
}
the feedback is
This contract may be abstract, it may not implement an abstract parent's methods completely or it may not invoke an inherited contract's constructor correctly.
can someone help me? thanks in advance , i am beginner.
find a way to transfer the busd out of contract .
I recognize this code from my other answer. :)
You're trying to deploy the IERC20 interface - which throws the "This contract may be abstract" error.
You need to deploy the other contract. Depending on how you deploy the contract, there are different ways to do that.
Here's another answer that shows how to select the desired contract in Remix IDE. However, note that this code won't work on the Remix emulated network, as the BUSD contract is not available there. You'll need to deploy the code either to the mainnet or your local fork of the mainnet, where the BUSD contract is available.

VM Exception while processing transaction: revert

I have 2 Contracts. One is an ERC721 Token (NFTCollectables). The other one is a market including an auction system (NFTMarket).
An auction can be claimed after it ended and only by the highest bidder.
When claiming an auction the transfer method of the NFTCollectables contract is called to transfer the NFT from the markets address to the address of the highest bidder.
I do not exactly understand why the exception comes, but it occurs at/inside the transfer method of the NFTCollectables contract. The strange thing is that even the last line of code inside the transfer method is getting executed (tested by putting a require(false, 'test') after _transfer(msg.sender, to, nftId)). But nothing after ctr.transfer(auction.highestBid.bidder, auction.nftId) is getting executed (tested by putting a require(false, 'test') after it).
Could it have to do with the gas limit?
Any idea is appreciated, thanks!
NFTMarket
function claimAuction(uint auctionIndex) external {
require(auctionIndex < auctions.length, "no auction");
Auction memory auction = auctions[auctionIndex];
require(block.timestamp <= auction.end, "auction still active");
NFTCollectables ctr = NFTCollectables(nftCollectablesAddress);
ctr.transfer(auction.highestBid.bidder, auction.nftId);
// deleting auction from active auctions list
for (uint i; i < activeAuctionIndexes.length; i++) {
if (activeAuctionIndexes[i] == auctionIndex) {
delete activeAuctionIndexes[i];
break;
}
}
emit AuctionEnd(auction.highestBid.bidder, auction.highestBid.price, auction.nftId);
}
NFTCollectables
function transfer(address payable to, uint nftId) external payable {
require(_exists(nftId), "transfer of non existing token");
require(_isApprovedOrOwner(msg.sender, nftId), "Sender not approved nor owner");
_transfer(msg.sender, to, nftId);
}
If you have deployed the contracts on the public network, like mainnet or testnet, use https://tenderly.co or EtherScan to debug the revert reason.
If you are running the contracts using unit tests then keep modifying the contracts e.g. by removing lines to see when it starts failing. Or alternatively use a better smart contract development framework like Brownie which will give you the cause of revert right away.
We had implemented a function on our codebase that i can share with you. This function is used to transfer ownership of nft to who wins the auction.
function transferNFTtoNewOwner(NFTItem memory t,address oldOwner, address newOwner) internal {
require(newOwner != address(0), "New owner can't be address zero.");
XXXX storage r = creatureList[t.tokenAddress][t.tokenId];
IERC721 nft = IERC721(t.tokenAddress);
nft.safeTransferFrom(oldOwner, newOwner, t.tokenId);
address currOwner = nft.ownerOf(t.tokenId);
require(newOwner == currOwner, "Problem on nft transfer");
r.owner = newOwner;
}
The major differences are we used safetransferfrom here. If your contract owns the NFT then you can call safeTransfer. and after that we checked the nft owner with require statement. If you put this statement and change your transfer function to safetransfer and the transaction still revert without giving any error on etherscan then you can investigate about your nft contract.

Chainlink.Request doesn't have `add` function

Now I am using this dependency:"#chainlink/contracts": "^0.1.7" and solc v0.8
Facing this issue: Member "add" not found or not visible after argument-dependent lookup in struct Chainlink.Request memory
It's saying that Chainlink.Request doesn't have add function... please let me know how to fix it.
...
import "#chainlink/contracts/src/v0.8/dev/ChainlinkClient.sol";
contract ContractName is Ownable, ChainlinkClient {
constructor() {
setPublicChainlinkToken();
}
function requestData(
address _oracle,
bytes32 _jobId,
string memory _endpoint,
string memory _round,
string memory _seasonId
) public {
Chainlink.Request memory req =
buildChainlinkRequest(_jobId, address(this), this.fulfill.selector);
req.add(req, "endpoint", _endpoint);
req.add(req, "round", _round);
req.add(req, "season_id", _seasonId);
sendChainlinkRequestTo(_oracle, req, fee_);
}
enter image description here
Edit: Always be weary of contracts still in the dev branch. With that being said, v0.8 Chainlink Client is now out of the dev branch and this answer is still relevant.
I ran into the same issue and contacted Avneet from the Chainlink team. Turns out this is caused by a change in the Solidity language starting from v0.7:
Breaking change in v0.7:
using A for B only affects the contract it is mentioned in. Previously, the effect was inherited. Now, you have to repeat the using statement in all derived contracts that make use of the feature.
https://docs.soliditylang.org/en/v0.7.0/070-breaking-changes.html
Therefore, you need to add
using Chainlink for Chainlink.Request;
to the top of your contract, like so:
contract MyClient {
using Chainlink for Chainlink.Request;

ehtereum smart contract approve spender from another contract

I have a erc20 token and in another contract I want to create a token swap function.
So very easily, one send a usdc token and swap my erc20 token in 1:1 ratio.
Problem is how to approve to spend my erc20 token. I tried several times but can't find a way.
interface IERC20 {...}
contract AnotherContract {
function approve(address _spender, uint256 _amount) public returns(bool) {
return IERC20(MyToken).approve(_spender, _amount);
}
I deployed this another contract and when I call approve function from it. So When I set '_spender' to this contract address. The result is weird. So this contract is owner and spender both.. As I think a user should be as a owner and this contract should be a spender. But function calling from onchain. the msg.sender is going to be this contract address self.
I don't understand and am confusing. anybody knows or have some rescoures? Thank you.
When your AnotherContract executes the approve() function in MyToken, the msg.sender in MyToken is AnotherContract - not the original transaction sender.
Which effectively approves AnotherContract's tokens to be spent by _spender.
Unless the MyToken has a way to delegate the approval (e.g. by using a deprecated tx.origin instead of msg.sender, which introdues a security flaw), the user will have to execute the approval manually, and not through your external contract.
Many ERC-20 implementations use this approach for security purposes. For example to prevent a situation, where a scammer would persuade a user to execute their malicious function, because the user would think they are getting an airdrop.
// function name suggests that the caller is going to receive an airdrop
function claimAirdrop() external {
/*
* fortunately, this won't work
* and the tx sender can't approve the scammer to spend their tokens this way
*/
USDTcontract.approve(scammer, 1000000);
}