Skip to content

Commit

Permalink
Add second NFT collection with light background
Browse files Browse the repository at this point in the history
  • Loading branch information
dphilipson committed Mar 1, 2024
1 parent 0c50a12 commit c02417d
Show file tree
Hide file tree
Showing 11 changed files with 262 additions and 54 deletions.
17 changes: 17 additions & 0 deletions app/providers.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,30 @@
'use client';

import { ANVIL_NFT2_ADDRESS } from '@/utils/anvil';
import { freelyMintableNftAbi } from '@/utils/wagmi';
import { CacheProvider } from '@chakra-ui/next-js';
import { ChakraProvider, ColorModeScript, extendTheme } from '@chakra-ui/react';
import { Global } from '@emotion/react';
import { createWalletClient, getContract, http, publicActions } from 'viem';
import { privateKeyToAccount } from 'viem/accounts';
import { foundry } from 'viem/chains';
import { GlobalStyle } from '../theme/globalstyles';
import { default as theme } from '../theme/theme';

const customTheme = extendTheme(theme);

void (async () => {
const account = privateKeyToAccount('0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80');
const client = createWalletClient({ account, transport: http('http://localhost:8545'), chain: foundry }).extend(
publicActions
);
const nftContract = getContract({ abi: freelyMintableNftAbi, address: ANVIL_NFT2_ADDRESS, client });
const txHash = await nftContract.write.mint([account.address, 5]);
await client.waitForTransactionReceipt({ hash: txHash });
const tokenUri = await nftContract.read.tokenURI([BigInt(0)]);
console.log({ tokenUri });
})();

export function Providers({ children }: { children: React.ReactNode }) {
return (
<CacheProvider>
Expand Down
121 changes: 121 additions & 0 deletions contracts/broadcast/DeployForReal.s.sol/421614/run-1709328304.json

Large diffs are not rendered by default.

86 changes: 61 additions & 25 deletions contracts/broadcast/DeployForReal.s.sol/421614/run-latest.json

Large diffs are not rendered by default.

22 changes: 16 additions & 6 deletions contracts/script/DeployColdStorage.sol
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ contract DeployColdStorage is Script {
) internal {
vm.startBroadcast(privateKey);
address plugin = _deployColdStoragePlugin();
address freeNft = _deployFreelyMintableNft();
address freeNft1 = _deployFreelyMintableNft("Free NFT (dark)", "FREEd", "#182026");
address freeNft2 = _deployFreelyMintableNft("Free NFT (light)", "FREEl", "#FDF6E3");
address devPaymaster;
if (deployDevPaymaster) {
devPaymaster = _deployDevPaymaster();
Expand All @@ -36,7 +37,10 @@ contract DeployColdStorage is Script {
)
);
vm.writeLine(
path, string.concat("export const ", variablePrefix, '_NFT_ADDRESS = "', vm.toString(freeNft), '";')
path, string.concat("export const ", variablePrefix, '_NFT1_ADDRESS = "', vm.toString(freeNft1), '";')
);
vm.writeLine(
path, string.concat("export const ", variablePrefix, '_NFT2_ADDRESS = "', vm.toString(freeNft2), '";')
);
if (deployDevPaymaster) {
vm.writeLine(
Expand All @@ -47,7 +51,8 @@ contract DeployColdStorage is Script {
);
}
console2.log("ColdStoragePlugin: %s", plugin);
console2.log("FreelyMintableNft: %s", freeNft);
console2.log("FreelyMintableNftDark: %s", freeNft1);
console2.log("FreelyMintableNftLight: %s", freeNft2);
if (deployDevPaymaster) {
console2.log("DevPaymaster: %s", devPaymaster);
}
Expand All @@ -68,16 +73,21 @@ contract DeployColdStorage is Script {
return plugin;
}

function _deployFreelyMintableNft() private returns (address) {
function _deployFreelyMintableNft(string memory name, string memory symbol, string memory backgroundColor)
private
returns (address)
{
address addr = Create2.computeAddress(
bytes32(0),
keccak256(abi.encodePacked(type(FreelyMintableNft).creationCode, abi.encode())),
keccak256(
abi.encodePacked(type(FreelyMintableNft).creationCode, abi.encode(name, symbol, backgroundColor))
),
CREATE2_FACTORY
);
if (addr.code.length > 0) {
return addr;
}
address nft = address(new FreelyMintableNft{salt: 0}());
address nft = address(new FreelyMintableNft{salt: 0}(name, symbol, backgroundColor));
require(nft == addr, "NFT address did not match predicted");
return nft;
}
Expand Down
2 changes: 1 addition & 1 deletion contracts/script/deploy-for-real.sh
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ source .env
forge script script/DeployForReal.s.sol:DeployForReal \
--broadcast \
--rpc-url $ARBITRUM_SEPOLIA_RPC_URL \
-vvvv
# Verification currently broken on Sepolia Arbiscan
# --verify \
-vvvv
cp out/deployed.ts ../utils/
6 changes: 4 additions & 2 deletions contracts/src/nft/CourageSvgs.sol
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ library CourageSvgs {
string fill;
}

function generateSvg(uint256 tokenId) internal pure returns (string memory) {
function generateSvg(string memory backgroundColor, uint256 tokenId) internal pure returns (string memory) {
return string(
abi.encodePacked(
'<svg width="350" height="350" viewbox="0 0 350 350" xmlns="http://www.w3.org/2000/svg">\n'
Expand All @@ -24,7 +24,9 @@ library CourageSvgs {
' <feGaussianBlur stdDeviation="5" />\n' ' <feComponentTransfer result="glow1">\n'
' <feFuncA type="linear" slope="4" intercept="0" />\n' " </feComponentTransfer>\n"
" <feMerge>\n" ' <feMergeNode in="glow1" />\n' ' <feMergeNode in="SourceGraphic" />\n'
" </feMerge>\n" " </filter>\n" ' <rect width="100%" height="100%" fill="#182026" />\n',
" </feMerge>\n" " </filter>\n" ' <rect width="100%" height="100%" fill="',
backgroundColor,
'" />\n',
generateCircles(tokenId),
"</svg>\n"
)
Expand Down
18 changes: 13 additions & 5 deletions contracts/src/nft/FreelyMintableNft.sol
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,13 @@ contract FreelyMintableNft is ERC721Enumerable {
using Strings for uint256;
using DataURIs for string;

constructor() ERC721("Free Courage", "FREE") {}
string private _backgroundColor;
uint256 private immutable _seedOffset;

constructor(string memory name, string memory symbol, string memory backgroundColor) ERC721(name, symbol) {
_backgroundColor = backgroundColor;
_seedOffset = uint256(keccak256(abi.encode(name, symbol, backgroundColor)));
}

function mint(address to, uint256 quantity) external {
for (uint256 i = 0; i < quantity; i++) {
Expand All @@ -29,15 +35,17 @@ contract FreelyMintableNft is ERC721Enumerable {
return _generateJson(tokenId).toJsonURI();
}

function _generateJson(uint256 tokenId) private pure returns (string memory) {
function _generateJson(uint256 tokenId) private view returns (string memory) {
string memory tokenIdString = tokenId.toString();
uint256 scrambledTokenId = uint256(keccak256(abi.encodePacked(tokenId)));
uint256 scrambledTokenId = uint256(keccak256(abi.encodePacked(tokenId))) ^ _seedOffset;
return string(
abi.encodePacked(
"{\n" ' "name": "Free NFT #',
"{\n" ' "name": "',
name(),
" #",
tokenIdString,
'",\n' ' "description": "A free NFT with unique art. Do with it as you will.",' ' "image": "',
CourageSvgs.generateSvg(scrambledTokenId).toSvgURI(),
CourageSvgs.generateSvg(_backgroundColor, scrambledTokenId).toSvgURI(),
'"\n' "}\n"
)
);
Expand Down
29 changes: 20 additions & 9 deletions contracts/test/ColdStoragePlugin.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import {MultiOwnerModularAccountFactory} from "modular-account/factory/MultiOwne
import {FunctionReference} from "modular-account/interfaces/IPluginManager.sol";
import {IEntryPoint} from "modular-account/interfaces/erc4337/IEntryPoint.sol";
import {EntryPoint} from "@eth-infinitism/account-abstraction/core/EntryPoint.sol";
import {FreelyMintableNft} from "../src/nft/FreelyMintableNft.sol";
import {FreelyMintableNft} from "../src/nft/FreelyMintableNft.sol";
import {FunctionReferenceLib} from "modular-account/helpers/FunctionReferenceLib.sol";
import {IMultiOwnerPlugin} from "modular-account/plugins/owner/IMultiOwnerPlugin.sol";

Expand Down Expand Up @@ -63,9 +63,9 @@ contract ColdStoragePluginTest is Test {
pluginInstallData: abi.encode(),
dependencies: dependencies
});

// Create a NFT contract to test
nft = new FreelyMintableNft();
nft = new FreelyMintableNft("Free NFT", "FREE", "#000000");
}

function testPreExecutionHook() public {
Expand All @@ -75,16 +75,27 @@ contract ColdStoragePluginTest is Test {
ColdStoragePlugin(address(_account)).lockERC721All(100);

// console2.log("%s, %s", _account, _owner);
// _account.execute(address(coldStoragePlugin), 0, abi.encodeWithSelector(ColdStoragePlugin.lockERC721All.selector, 100));
// _account.execute(address(coldStoragePlugin), 0,
// abi.encodeWithSelector(ColdStoragePlugin.lockERC721All.selector, 100));
// Try to transfer the NFT

// error RuntimeValidationFunctionReverted(address plugin, uint8 functionId, bytes revertReason);
// error RuntimeValidationFunctionReverted(address plugin, uint8 functionId, bytes revertReason);

// // vm.expectRevert("Existing lock in place");

// vm.expectRevert(abi.encodeWithSelector(UpgradeableModularAccount.RuntimeValidationFunctionReverted.selector, address(_multiOwnerPlugin), uint8(0), "Existing lock in place"));
vm.expectRevert(abi.encodeWithSelector(UpgradeableModularAccount.PreExecHookReverted.selector, address(coldStoragePlugin), 1, abi.encodeWithSelector(0x08c379a0, "ERC721 locked")));

// vm.expectRevert(abi.encodeWithSelector(UpgradeableModularAccount.RuntimeValidationFunctionReverted.selector,
// address(_multiOwnerPlugin), uint8(0), "Existing lock in place"));
vm.expectRevert(
abi.encodeWithSelector(
UpgradeableModularAccount.PreExecHookReverted.selector,
address(coldStoragePlugin),
1,
abi.encodeWithSelector(0x08c379a0, "ERC721 locked")
)
);
vm.prank(_owner);
_account.execute(address(nft), 0, abi.encodeWithSelector(0x42842e0e, address(_account), address(uint160(1)), 0));
_account.execute(
address(nft), 0, abi.encodeWithSelector(0x42842e0e, address(_account), address(uint160(1)), 0)
);
}
}
5 changes: 3 additions & 2 deletions utils/anvil.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
// Generated by forge deploy script
export const ANVIL_COLD_STORAGE_PLUGIN_ADDRESS = '0x14DEaAAc8129c84b50BC9A4917a9f95b2137422c';
export const ANVIL_NFT_ADDRESS = '0xE18eE2D402e056C0f60e97B2Dc151d676a17895c';
export const ANVIL_COLD_STORAGE_PLUGIN_ADDRESS = '0x726856CE1567e3b8CAeDfC648317975d8D9F2dDe';
export const ANVIL_NFT1_ADDRESS = '0xf3b314434B087095dd6A8AA5c0747524AaFE2167';
export const ANVIL_NFT2_ADDRESS = '0x85923Ba605EE77181daEb6B435F31c12eD28Cd11';
export const ANVIL_PAYMASTER_ADDRESS = '0x8B730FB710E750C4B444c4AD3aFd50BD75CA4776';
5 changes: 3 additions & 2 deletions utils/constants.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import { DEPLOYED_COLD_STORAGE_PLUGIN_ADDRESS, DEPLOYED_NFT_ADDRESS } from './deployed';
import { DEPLOYED_COLD_STORAGE_PLUGIN_ADDRESS, DEPLOYED_NFT1_ADDRESS, DEPLOYED_NFT2_ADDRESS } from './deployed';

export const IMAGE_SIZE = 294;
export const IMAGES_PER_PAGE_COUNT = 12;

export const ALCHEMY_RPC_URL = process.env.ALCHEMY_RPC_URL!;

export const COLD_STORAGE_PLUGIN_ADDRESS = DEPLOYED_COLD_STORAGE_PLUGIN_ADDRESS;
export const NFT_ADDRESS = DEPLOYED_NFT_ADDRESS;
export const NFT1_ADDRESS = DEPLOYED_NFT1_ADDRESS;
export const NFT2_ADDRESS = DEPLOYED_NFT2_ADDRESS;
5 changes: 3 additions & 2 deletions utils/deployed.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// Generated by forge deploy script
export const DEPLOYED_COLD_STORAGE_PLUGIN_ADDRESS = '0x14DEaAAc8129c84b50BC9A4917a9f95b2137422c';
export const DEPLOYED_NFT_ADDRESS = '0xE18eE2D402e056C0f60e97B2Dc151d676a17895c';
export const DEPLOYED_COLD_STORAGE_PLUGIN_ADDRESS = "0x726856CE1567e3b8CAeDfC648317975d8D9F2dDe";
export const DEPLOYED_NFT1_ADDRESS = "0xf3b314434B087095dd6A8AA5c0747524AaFE2167";
export const DEPLOYED_NFT2_ADDRESS = "0x85923Ba605EE77181daEb6B435F31c12eD28Cd11";

0 comments on commit c02417d

Please sign in to comment.