Oni Mansion Mint Contract
Introducing a new gaming standard: ERC721-AG
Hello Oni Frens,
Our mint for the Oni Mansion NFTs is now complete, and we wanted to share the tech and behind-the-scenes of our mint smart contract. Our dev team spent weeks testing and implementing various NFT-related standards to ensure all Oni Mansions would require as little gas as possible while maintaining flexibility for the future. We also compared two different approaches to allow-listing, Merkle trees, and signature verification, and ultimately decided upon signature verification for its lower gas requirements and flexibility in making updates to our allow-list off-chain.
Along the way, we also discovered less-known standards that we felt made sense for an NFT focused on gaming and combined them into a new standard we’re calling ERC-721AG (gaming).
First, is ERC-721A actually the best?
As some of you may be aware, the Azuki team created and popularized a significant improvement to the ERC-721 standard, naming it ERC-721A. This is now the industry standard for new mints, and justifiably so — it lowers gas costs by ~50% on a single mint alone, and each incremental mint in a batch costs very little.
However, other teams have also released other gas-optimized contracts, and we felt it was important for us to review them before settling on 721A as our base contract. Crypto Covens had a different approach to saving gas, and we also discovered another low-gas contract called “Gwei-Slim-721” used by a couple of other teams.
In summary, we found that while smart contract deployment gas fees were significantly lower with Gwei-Slim, that only helps the developer, and user mint costs would have been higher than 721A. Covens was a significant improvement over the old pre-Azuki 721 standard, but 721A was also still cheaper. The results weren’t too surprising, but we felt better about confirming that 721A would be the best low-gas NFT standard for the Oni community.
Extendability via a proxy management system
We’re a crypto gaming studio, and Oni Mansions are intended to have utility for future games. By building in and enabling proxy approvals in our Oni Mansion contract, users will be able to skip approval transactions for future game contracts that want to interact with Oni Mansions. This maximizes the Oni Mansion NFT’s future interoperability and essentially makes the contract plug-and-play.
How did we do this? A proxy account is basically another identifier of who you are (i.e. an account made with your favorite game or OpenSea account). It allows the developer / owner of the contract to make it easy for their contract to communicate and share data with other contracts. Otherwise, an explicit approval fee would be required by the holder the first time they want to use the NFT, even if there was no actual change of state.
To be clear, this addition does not mean that the proxy contract itself has access to the NFTs. Additionally, the proxy systems we put into place is equipped with the ability to turn off and remove proxies that we deem risky.
Proxies also help remove marketplace listing fees
Another benefit of proxy approvals is that we can adjust them to remove listing fee requirements on pre-approved marketplaces, such as OpenSea, and other marketplaces that become important.
Inserting Royalty Standards via EIP-2981
Finally, we thought it’d be immensely helpful to add royalty data to our contract, via EIP-2981. Currently, OpenSea collection owners update the royalty fee via a profile setting on OpenSea’s website, and that information is not on-chain. That royalty fee information is provided only to OpenSea, so we’d have to update that on LooksRare, Rarible, or any other marketplace platform in the future.
EIP-2981 helps solve this by making it easy for marketplaces to identify the desired royalty intended by the creators of the collection. A marketplace ultimately can ignore it, but we think it’s helpful as another way of future-proofing the contract.
For Developers
We open-sourced our smart contracts, and we’d love for the dev community to comment on, use, and extend it further!
OpenSea Contract:
0xa5409ec958C83C3f309868babACA7c86DCB077c1 is the OpenSea contract on Ethereum mainnet. We’re adding that to our proxy management system, so NFT owners don’t have to deal with an approval tx fee.
Here’s a code sample for our Oni Mansion minting contract. Make sure to set the address you want your royalties going to with the receiverAddress variable.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;import “@openzeppelin/contracts/security/ReentrancyGuard.sol”;
import “./ERC721AG.sol”;/**
* @title Oni Mansion Contract
* @author onisquad.gg
* @notice This contract handles minting for Oni Mansions.
*/
contract OniMansion is ERC721AG {
uint256 public mintPrice = 0.12 ether;
uint256 public maxSupply = 10000;bool setSupply;/**
* @notice Contract Constructor
*/
constructor(
string memory baseTokenURI_
) ERC721AG(“Oni Mansion NFT”, “OM”, baseTokenURI_) {
includedProxies.push(0xa5409ec958C83C3f309868babACA7c86DCB077c1);
proxyToApprove[0xa5409ec958C83C3f309868babACA7c86DCB077c1] = true;
receiverAddress = 0xe136FB79114C5dCf135091Dcba34f302DE8B1687;
}// Setters/**
* @notice Update mint price.
* @param _newPrice: amount to mint one oni mansion.
*/
function setMintingPrice(uint256 _newPrice) external onlyOwner() {
mintPrice = _newPrice;
}
Proxy Management System Overview:
Github repository here. Live contract address here.
In the contract, proxies are stored in the includedProxies
array. Whether the proxy is active or not is stored in the proxyToApprove
mapping.
mapping(address => bool) public proxyToApprove;
address[] public includedProxies;
We use the function flipProxyState
to turn a proxy on or off.
/**
* Function to disable gasless listings for security in case
* opensea or other contracts ever shut down or are compromised
*/
function flipProxyState(address proxyAddress)
public
onlyOwner
{
proxyToApprove[proxyAddress] = !proxyToApprove[proxyAddress];
}
We added in the functions addApprovedProxy
and removeApprovedProxyIndex
to add and remove proxies from the proxy management system.
function addApprovedProxy(address _newAddress) external onlyOwner() {
includedProxies.push(_newAddress);
}function removeApprovedProxyIndex(uint index) external onlyOwner() {
require(index < includedProxies.length, “Array does not have this index”);for (uint i = index; i < includedProxies.length — 1; i++){
includedProxies[i] = includedProxies[i+1];
}
includedProxies.pop();
}
The heart of the proxy management system is the isApprovedForAll
function. This function is what lets users skip approval fees on Opensea, other marketplaces, games, and any dapp that the owner of the contract deems worthy.
/**
* Override isApprovedForAll to allowlist user’s OpenSea proxy accounts to enable gas-less listings.
* and In addition, you can add other Proxy Approvals in the future.
* Perhaps, you can skip the approval tx for future NFT Marketplaces (coinbase, kraken) or games.
* This safeguards the collection for integrability.
*/
function isApprovedForAll(address owner, address operator)
public
view
override
returns (bool)
{
for (uint256 i = 0; i < includedProxies.length; i++) {
address currentProxy = includedProxies[i];
ProxyRegistry proxyRegistry = ProxyRegistry(currentProxy);
if (
proxyToApprove[currentProxy] &&
address(proxyRegistry.proxies(owner)) == operator
) {
return true;
}
}
return super.isApprovedForAll(owner, operator);
}
Let us know what you all think! If you need any help, feel free to ask questions or message us in our Discord.
Stay tuned for future updates on our roadmap and our next game :)
Thanks,
Pavan, Jason, and the Oni Squad team
Resources