ethers/lib/utils#toUtf8String TypeScript Examples

The following examples show how to use ethers/lib/utils#toUtf8String. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: GethClient.ts    From tx2uml with MIT License 6 votes vote down vote up
parseReasonCode = (messageData: string): string => {
    // Get the length of the revert reason
    const strLen = parseInt(messageData.slice(8 + 64, 8 + 128), 16)
    // Using the length and known offset, extract and convert the revert reason
    const reasonCodeHex = messageData.slice(8 + 128, 8 + 128 + strLen * 2)
    // Convert reason from hex to string
    const reason = toUtf8String("0x" + reasonCodeHex)

    return reason
}
Example #2
Source File: transactionErrors.ts    From tx2uml with MIT License 6 votes vote down vote up
parseReasonCode = (messageData: string): string => {
    // Get the length of the revert reason
    const strLen = parseInt(messageData.slice(8 + 64, 8 + 128), 16)
    // Using the length and known offset, extract and convert the revert reason
    const reasonCodeHex = messageData.slice(8 + 128, 8 + 128 + strLen * 2)
    // Convert reason from hex to string
    const reason = toUtf8String("0x" + reasonCodeHex)

    return reason
}
Example #3
Source File: NFT1155.test.ts    From shoyu with MIT License 4 votes vote down vote up
describe("NFT part of NFT1155", () => {
    beforeEach(async () => {
        await ethers.provider.send("hardhat_reset", []);
    });

    it("should be that default values are set correctly with batch minting deploy", async () => {
        const { factory, nft1155, alice, royaltyVault } = await setupTest();

        await factory.setDeployerWhitelisted(AddressZero, true);
        await factory.upgradeNFT1155(nft1155.address);

        await factory.deployNFT1155AndMintBatch(alice.address, [0, 2, 4], [1, 3, 5], royaltyVault.address, 13);
        const nft1155_0 = await getNFT1155(factory);

        expect(await nft1155_0.PERMIT_TYPEHASH()).to.be.equal(
            convertToHash("Permit(address owner,address spender,uint256 nonce,uint256 deadline)")
        );
        expect(await nft1155_0.DOMAIN_SEPARATOR()).to.be.equal(
            await domainSeparator(ethers.provider, nft1155_0.address.toLowerCase(), nft1155_0.address)
        );
        expect(await nft1155_0.factory()).to.be.equal(factory.address);

        async function URI1155(nft: NFT1155V3, tokenId: number): Promise<string> {
            const baseURI = await factory.baseURI1155();
            const addy = nft.address.toLowerCase();
            return toUtf8String(solidityPack(["string", "string", "string"], [baseURI, addy, "/" + tokenId + ".json"]));
        }

        expect(await nft1155_0.uri(0)).to.be.equal(await URI1155(nft1155_0, 0));
        expect(await nft1155_0.uri(2)).to.be.equal(await URI1155(nft1155_0, 2));
        expect(await nft1155_0.uri(4)).to.be.equal(await URI1155(nft1155_0, 4));
        expect(await nft1155_0.uri(1)).to.be.equal(await URI1155(nft1155_0, 1));
        expect(await nft1155_0.uri(11759)).to.be.equal(await URI1155(nft1155_0, 11759));

        expect((await nft1155_0.royaltyInfo(0, 0))[0]).to.be.equal(royaltyVault.address);

        expect((await nft1155_0.royaltyInfo(0, 12345))[1]).to.be.equal(Math.floor((12345 * 13) / 1000));
    });

    it("should be that permit fuctions work well", async () => {
        const { factory, nft1155, alice, bob, carol, royaltyVault } = await setupTest();

        await factory.setDeployerWhitelisted(AddressZero, true);
        await factory.upgradeNFT1155(nft1155.address);

        const artist = ethers.Wallet.createRandom();

        await factory.deployNFT1155AndMintBatch(artist.address, [0, 1, 2], [5, 6, 7], royaltyVault.address, 10);
        const nft1155_0 = await getNFT1155(factory);

        const currentTime = await getBlockTimestamp();
        const deadline = currentTime + 100;
        const permitDigest0 = await getDigest(
            ethers.provider,
            nft1155_0.address.toLowerCase(),
            nft1155_0.address,
            getHash(
                ["bytes32", "address", "address", "uint256", "uint256"],
                [await nft1155_0.PERMIT_TYPEHASH(), artist.address, bob.address, 0, deadline]
            )
        );
        const { v: v0, r: r0, s: s0 } = sign(permitDigest0, artist);

        expect(await nft1155_0.isApprovedForAll(artist.address, bob.address)).to.be.false;
        await nft1155_0.permit(artist.address, bob.address, deadline, v0, r0, s0);
        expect(await nft1155_0.isApprovedForAll(artist.address, bob.address)).to.be.true;

        const { v: v1, r: r1, s: s1 } = sign(
            await getDigest(
                ethers.provider,
                nft1155_0.address.toLowerCase(),
                nft1155_0.address,
                getHash(
                    ["bytes32", "address", "address", "uint256", "uint256"],
                    [await nft1155_0.PERMIT_TYPEHASH(), artist.address, alice.address, 1, deadline]
                )
            ),
            artist
        );

        const { v: fv0, r: fr0, s: fs0 } = sign(
            await getDigest(
                ethers.provider,
                nft1155_0.address.toLowerCase(),
                nft1155_0.address,
                getHash(
                    ["bytes32", "address", "address", "uint256", "uint256"],
                    [await nft1155_0.PERMIT_TYPEHASH(), artist.address, alice.address, 111, deadline] //invalid nonce
                )
            ),
            artist
        );
        const { v: fv1, r: fr1, s: fs1 } = sign(
            await getDigest(
                ethers.provider,
                nft1155_0.address.toLowerCase(),
                nft1155_0.address,
                getHash(
                    ["bytes32", "address", "address", "uint256", "uint256"],
                    [await nft1155_0.PERMIT_TYPEHASH(), artist.address, alice.address, 3, deadline - 120] //deadline over
                )
            ),
            artist
        );
        const fakeSigner = ethers.Wallet.createRandom();
        const { v: fv2, r: fr2, s: fs2 } = sign(
            await getDigest(
                ethers.provider,
                nft1155_0.address.toLowerCase(),
                nft1155_0.address,
                getHash(
                    ["bytes32", "address", "address", "uint256", "uint256"],
                    [await nft1155_0.PERMIT_TYPEHASH(), artist.address, alice.address, 3, deadline] //fake signer
                )
            ),
            fakeSigner
        );

        await expect(nft1155_0.permit(artist.address, alice.address, deadline, fv0, fr0, fs0)).to.be.revertedWith(
            "SHOYU: UNAUTHORIZED"
        ); //invalid nonce
        await expect(nft1155_0.permit(artist.address, alice.address, deadline - 120, fv1, fr1, fs1)).to.be.revertedWith(
            "SHOYU: EXPIRED"
        ); //deadline over
        await expect(nft1155_0.permit(artist.address, carol.address, deadline, v1, r1, s1)).to.be.revertedWith(
            "SHOYU: UNAUTHORIZED"
        ); //wrong spender
        await expect(nft1155_0.permit(artist.address, alice.address, deadline, fv2, fr2, fs2)).to.be.revertedWith(
            "SHOYU: UNAUTHORIZED"
        ); //fake signer

        await nft1155_0.permit(artist.address, alice.address, deadline, v1, r1, s1); //wrong id
        expect(await nft1155_0.isApprovedForAll(artist.address, alice.address)).to.be.true;
    });

    it("should be that owner can only decrease royalty fee", async () => {
        const { factory, nft1155, alice, bob, royaltyVault } = await setupTest();

        await factory.setDeployerWhitelisted(AddressZero, true);
        await factory.upgradeNFT1155(nft1155.address);

        await factory.deployNFT1155AndMintBatch(alice.address, [7], [10], royaltyVault.address, 20);
        const nft1155_0 = await getNFT1155(factory);

        await expect(nft1155_0.setRoyaltyFee(10)).to.be.revertedWith("SHOYU: FORBIDDEN");
        await expect(nft1155_0.connect(alice).setRoyaltyFee(30)).to.be.revertedWith("SHOYU: INVALID_FEE");
        await nft1155_0.connect(alice).setRoyaltyFee(3);
        expect((await nft1155_0.royaltyInfo(0, 1000))[1]).to.be.equal(3);
        await nft1155_0.connect(alice).setRoyaltyFee(0);
        expect((await nft1155_0.royaltyInfo(0, 1000))[1]).to.be.equal(0);
        await expect(nft1155_0.connect(alice).setRoyaltyFee(1)).to.be.revertedWith("SHOYU: INVALID_FEE");

        await factory.deployNFT1155AndMintBatch(bob.address, [9, 11], [10, 50], royaltyVault.address, 0);
        const nft1155_1 = await getNFT1155(factory);
        expect((await nft1155_1.royaltyInfo(0, 1000))[1]).to.be.equal(0);
        await expect(nft1155_1.connect(bob).setRoyaltyFee(251)).to.be.revertedWith("SHOYU: INVALID_FEE");
        await nft1155_1.connect(bob).setRoyaltyFee(93);
        expect((await nft1155_1.royaltyInfo(0, 1000))[1]).to.be.equal(93);
        await expect(nft1155_1.connect(bob).setRoyaltyFee(111)).to.be.revertedWith("SHOYU: INVALID_FEE");
        await nft1155_1.connect(bob).setRoyaltyFee(0);
        expect((await nft1155_1.royaltyInfo(0, 1000))[1]).to.be.equal(0);
        await expect(nft1155_1.connect(bob).setRoyaltyFee(1)).to.be.revertedWith("SHOYU: INVALID_FEE");
    });

    it("should be that URI functions work well", async () => {
        const { factory, nft1155, alice, bob, royaltyVault } = await setupTest();

        await factory.setDeployerWhitelisted(AddressZero, true);
        await factory.upgradeNFT1155(nft1155.address);

        async function URI1155(nft: NFT1155V3, tokenId: number, _baseURI?: string): Promise<string> {
            if (_baseURI === undefined) {
                const baseURI = await factory.baseURI1155();
                const addy = nft.address.toLowerCase();
                return toUtf8String(
                    solidityPack(["string", "string", "string"], [baseURI, addy, "/" + tokenId + ".json"])
                );
            } else {
                return toUtf8String(solidityPack(["string", "string"], [_baseURI, tokenId + ".json"]));
            }
        }

        await factory.deployNFT1155AndMintBatch(alice.address, [10], [3], royaltyVault.address, 10);
        const nft1155_0 = await getNFT1155(factory);

        await expect(nft1155_0.connect(bob).setURI(0, "https://foo.bar/0.json")).to.be.revertedWith("SHOYU: FORBIDDEN");
        await nft1155_0.connect(alice).setURI(0, "https://foo.bar/0.json");
        await nft1155_0.connect(alice).setURI(1, "https://foo.bar/1.json");

        expect(await nft1155_0.uri(0)).to.be.equal("https://foo.bar/0.json");
        expect(await nft1155_0.uri(1)).to.be.equal("https://foo.bar/1.json");

        expect(await nft1155_0.uri(2)).to.be.equal(await URI1155(nft1155_0, 2));
        expect(await nft1155_0.uri(4)).to.be.equal(await URI1155(nft1155_0, 4));
        expect(await nft1155_0.uri(7)).to.be.equal(await URI1155(nft1155_0, 7));
        expect(await nft1155_0.uri(2)).to.be.not.equal(await URI1155(nft1155_0, 2, "https://foo.bar/"));
        expect(await nft1155_0.uri(4)).to.be.not.equal(await URI1155(nft1155_0, 4, "https://foo.bar/"));
        expect(await nft1155_0.uri(7)).to.be.not.equal(await URI1155(nft1155_0, 7, "https://foo.bar/"));

        await expect(nft1155_0.connect(bob).setBaseURI("https://foo.bar/")).to.be.revertedWith("SHOYU: FORBIDDEN");
        await nft1155_0.connect(alice).setBaseURI("https://foo.bar/");

        expect(await nft1155_0.uri(2)).to.be.equal(await URI1155(nft1155_0, 2, "https://foo.bar/"));
        expect(await nft1155_0.uri(4)).to.be.equal(await URI1155(nft1155_0, 4, "https://foo.bar/"));
        expect(await nft1155_0.uri(7)).to.be.equal(await URI1155(nft1155_0, 7, "https://foo.bar/"));
        expect(await nft1155_0.uri(2)).to.be.not.equal(await URI1155(nft1155_0, 2));
        expect(await nft1155_0.uri(4)).to.be.not.equal(await URI1155(nft1155_0, 4));
        expect(await nft1155_0.uri(7)).to.be.not.equal(await URI1155(nft1155_0, 7));
    });

    it("should be that mint/mintBatch functions work well", async () => {
        const { factory, nft1155, alice, bob, royaltyVault } = await setupTest();

        await factory.setDeployerWhitelisted(AddressZero, true);
        await factory.upgradeNFT1155(nft1155.address);

        await factory.deployNFT1155AndMintBatch(bob.address, [0, 2, 4], [5, 6, 7], royaltyVault.address, 10);
        const nft1155_0 = await getNFT1155(factory);

        await expect(nft1155_0.mint(alice.address, 1, 1, [])).to.be.revertedWith("SHOYU: FORBIDDEN");
        await expect(nft1155_0.connect(bob).mint(AddressZero, 1, 1, [])).to.be.revertedWith("SHOYU: INVALID_ADDRESS");
        await expect(nft1155_0.connect(bob).mint(factory.address, 1, 1, [])).to.be.revertedWith("SHOYU: NO_RECEIVER");

        await nft1155_0.connect(bob).mint(alice.address, 0, 100, []);
        await nft1155_0.connect(bob).mint(alice.address, 1, 100, []);

        await expect(nft1155_0.mintBatch(alice.address, [3, 5], [30, 50], [])).to.be.revertedWith("SHOYU: FORBIDDEN");
        await expect(nft1155_0.connect(bob).mintBatch(AddressZero, [3, 5], [33, 55], [])).to.be.revertedWith(
            "SHOYU: INVALID_ADDRESS"
        );

        await expect(nft1155_0.connect(bob).mintBatch(factory.address, [3, 5], [33, 55], [])).to.be.revertedWith(
            "SHOYU: NO_RECEIVER"
        );

        await nft1155_0.connect(bob).mintBatch(alice.address, [3, 5], [33, 55], []);
        await nft1155_0.connect(bob).mint(alice.address, [3, 5], [1, 3], []);
    });

    it("should be that burn/burnBatch functions work well", async () => {
        const { factory, nft1155, alice, bob, royaltyVault } = await setupTest();

        await factory.setDeployerWhitelisted(AddressZero, true);
        await factory.upgradeNFT1155(nft1155.address);

        await factory.deployNFT1155AndMintBatch(bob.address, [1, 2, 4], [10, 20, 40], royaltyVault.address, 10);
        const nft1155_0 = await getNFT1155(factory);
        await nft1155_0.connect(bob).safeBatchTransferFrom(bob.address, alice.address, [1, 2, 4], [1, 2, 4], []);

        await expect(nft1155_0.connect(bob).burn(6, 1, 0, HashZero)).to.be.revertedWith("SHOYU: INSUFFICIENT_BALANCE");
        await expect(nft1155_0.connect(alice).burn(4, 5, 0, HashZero)).to.be.revertedWith(
            "SHOYU: INSUFFICIENT_BALANCE"
        );
        await nft1155_0.connect(bob).burn(4, 33, 0, HashZero);
        await expect(nft1155_0.connect(bob).burn(4, 33, 0, HashZero)).to.be.revertedWith("SHOYU: INSUFFICIENT_BALANCE");

        await nft1155_0.connect(alice).burn(4, 4, 0, HashZero);
        //alice : 1-1 2-2 4-0  _  bob : 1-9 2-18 4-3

        await expect(nft1155_0.connect(bob).burnBatch([2, 4], [10, 4])).to.be.revertedWith(
            "SHOYU: INSUFFICIENT_BALANCE"
        );
        await expect(nft1155_0.connect(bob).burnBatch([2, 8], [10, 1])).to.be.revertedWith(
            "SHOYU: INSUFFICIENT_BALANCE"
        );
        await expect(nft1155_0.connect(bob).burnBatch([4, 8], [1, 4])).to.be.revertedWith(
            "SHOYU: INSUFFICIENT_BALANCE"
        );
        await expect(nft1155_0.connect(bob).burnBatch([5, 10], [1, 1])).to.be.revertedWith(
            "SHOYU: INSUFFICIENT_BALANCE"
        );

        await nft1155_0.connect(alice).burnBatch([1, 2], [1, 2]);
        await nft1155_0.connect(bob).burnBatch([1, 2, 4], [9, 18, 3]);
    });

    it("should be that static call functions work properly", async () => {
        const { factory, nft1155, alice, bob, royaltyVault } = await setupTest();

        await factory.setDeployerWhitelisted(AddressZero, true);
        await factory.upgradeNFT1155(nft1155.address);

        await factory.deployNFT1155AndMintBatch(bob.address, [1, 2, 4], [10, 20, 40], royaltyVault.address, 10);
        const nft1155_0 = await getNFT1155(factory);

        expect(await nft1155_0.target()).to.be.equal(AddressZero);
        
        const StaticCallMock = await ethers.getContractFactory("StaticCallMock");
        const target0 = (await StaticCallMock.deploy()) as StaticCallMock;

        let proxyNFT = (await StaticCallMock.attach(nft1155_0.address)) as StaticCallMock;
        await expect(proxyNFT.globalV()).to.be.reverted;
        await expect(proxyNFT.pureTest11(1)).to.be.reverted;

        await expect(nft1155_0.setTarget(target0.address)).to.be.revertedWith("SHOYU: FORBIDDEN");
        await nft1155_0.connect(bob).setTarget(target0.address);
        expect(await nft1155_0.target()).to.be.equal(target0.address);

        expect(await proxyNFT.globalV()).to.be.equal(target0.address);
        expect(await proxyNFT.pureTest11(1)).to.be.equal(1);
        expect((await proxyNFT.pureTest23(2, "abc"))[0]).to.be.equal(2);
        expect((await proxyNFT.pureTest23(2, "abc"))[1]).to.be.equal("0x0000000000000000000000000000000000000001");
        expect((await proxyNFT.pureTest23(2, "abc"))[2]).to.be.equal("abc");

        expect(await proxyNFT.viewTest11(10)).to.be.equal(0);
        await target0.setX(10, 123);
        expect(await proxyNFT.viewTest11(10)).to.be.equal(123);

        await target0.setY(11, "qwe");
        expect((await proxyNFT.viewTest13(11))[0]).to.be.equal(0);
        expect((await proxyNFT.viewTest13(11))[1]).to.be.equal(target0.address);
        expect((await proxyNFT.viewTest13(11))[2]).to.be.equal("qwe");

        await target0.setX(11, 77);
        await target0.setY(11, "zxc");
        expect((await proxyNFT.viewTest13(11))[0]).to.be.equal(77);
        expect((await proxyNFT.viewTest13(11))[1]).to.be.equal(target0.address);
        expect((await proxyNFT.viewTest13(11))[2]).to.be.equal("zxc");
    });
});
Example #4
Source File: NFT721.test.ts    From shoyu with MIT License 4 votes vote down vote up
describe("NFT part of NFT721", () => {
    beforeEach(async () => {
        await ethers.provider.send("hardhat_reset", []);
    });

    it("should be that default values are set correctly with batch minting deploy", async () => {
        const { factory, nft721, alice, royaltyVault } = await setupTest();

        await factory.setDeployerWhitelisted(AddressZero, true);
        await factory.upgradeNFT721(nft721.address);

        await factory.deployNFT721AndMintBatch(alice.address, "Name", "Symbol", [0, 2, 4], royaltyVault.address, 13);
        const nft721_0 = await getNFT721(factory);

        expect(await nft721_0.PERMIT_TYPEHASH()).to.be.equal(
            convertToHash("Permit(address spender,uint256 tokenId,uint256 nonce,uint256 deadline)")
        );
        expect(await nft721_0.PERMIT_ALL_TYPEHASH()).to.be.equal(
            convertToHash("Permit(address owner,address spender,uint256 nonce,uint256 deadline)")
        );
        expect(await nft721_0.DOMAIN_SEPARATOR()).to.be.equal(
            await domainSeparator(ethers.provider, "Name", nft721_0.address)
        );
        expect(await nft721_0.factory()).to.be.equal(factory.address);

        async function URI721(nft: NFT721V2, tokenId: number): Promise<string> {
            const baseURI = await factory.baseURI721();
            const addy = nft.address.toLowerCase();
            return toUtf8String(
                solidityPack(
                    ["string", "string", "string", "string", "string"],
                    [baseURI, addy, "/", tokenId.toString(), ".json"]
                )
            );
        }

        expect(await nft721_0.tokenURI(0)).to.be.equal(await URI721(nft721_0, 0));
        expect(await nft721_0.tokenURI(2)).to.be.equal(await URI721(nft721_0, 2));
        expect(await nft721_0.tokenURI(4)).to.be.equal(await URI721(nft721_0, 4));
        await expect(nft721_0.tokenURI(1)).to.be.revertedWith("SHOYU: INVALID_TOKEN_ID");

        expect((await nft721_0.royaltyInfo(0, 0))[0]).to.be.equal(royaltyVault.address);

        expect((await nft721_0.royaltyInfo(0, 12345))[1]).to.be.equal(Math.floor((12345 * 13) / 1000));

        for (let i = 0; i < 10; i++) {
            assert.isFalse(await nft721_0.parked(i));
        }
    });

    it("should be that default values are set correctly with parking deploy", async () => {
        const { factory, nft721, alice, royaltyVault } = await setupTest();

        await factory.setDeployerWhitelisted(AddressZero, true);
        await factory.upgradeNFT721(nft721.address);

        await factory.deployNFT721AndPark(alice.address, "Name", "Symbol", 7, royaltyVault.address, 13);
        const nft721_0 = await getNFT721(factory);

        expect(await nft721_0.PERMIT_TYPEHASH()).to.be.equal(
            convertToHash("Permit(address spender,uint256 tokenId,uint256 nonce,uint256 deadline)")
        );
        expect(await nft721_0.PERMIT_ALL_TYPEHASH()).to.be.equal(
            convertToHash("Permit(address owner,address spender,uint256 nonce,uint256 deadline)")
        );
        expect(await nft721_0.DOMAIN_SEPARATOR()).to.be.equal(
            await domainSeparator(ethers.provider, "Name", nft721_0.address)
        );
        expect(await nft721_0.factory()).to.be.equal(factory.address);

        async function URI721(nft: NFT721V2, tokenId: number): Promise<string> {
            const baseURI = await factory.baseURI721();
            const addy = nft.address.toLowerCase();
            return toUtf8String(
                solidityPack(
                    ["string", "string", "string", "string", "string"],
                    [baseURI, addy, "/", tokenId.toString(), ".json"]
                )
            );
        }

        expect(await nft721_0.tokenURI(0)).to.be.equal(await URI721(nft721_0, 0));
        expect(await nft721_0.tokenURI(3)).to.be.equal(await URI721(nft721_0, 3));
        expect(await nft721_0.tokenURI(6)).to.be.equal(await URI721(nft721_0, 6));
        await expect(nft721_0.tokenURI(7)).to.be.revertedWith("SHOYU: INVALID_TOKEN_ID");

        expect((await nft721_0.royaltyInfo(0, 0))[0]).to.be.equal(royaltyVault.address);

        expect((await nft721_0.royaltyInfo(0, 12345))[1]).to.be.equal(Math.floor((12345 * 13) / 1000));

        for (let i = 0; i <= 6; i++) {
            assert.isTrue(await nft721_0.parked(i));
        }
        assert.isFalse(await nft721_0.parked(7));
        assert.isFalse(await nft721_0.parked(8));
        assert.isFalse(await nft721_0.parked(9));
        assert.isFalse(await nft721_0.parked(10));
    });

    it("should be that permit/permitAll fuctions work well", async () => {
        const { factory, nft721, alice, bob, carol, royaltyVault } = await setupTest();

        await factory.setDeployerWhitelisted(AddressZero, true);
        await factory.upgradeNFT721(nft721.address);

        const artist = ethers.Wallet.createRandom();

        await factory.deployNFT721AndMintBatch(artist.address, "Name", "Symbol", [0, 1, 2], royaltyVault.address, 10);
        const nft721_0 = await getNFT721(factory);

        const currentTime = await getBlockTimestamp();
        let deadline = currentTime + 100;
        const permitDigest0 = await getDigest(
            ethers.provider,
            "Name",
            nft721_0.address,
            getHash(
                ["bytes32", "address", "uint256", "uint256", "uint256"],
                [await nft721_0.PERMIT_TYPEHASH(), bob.address, 1, 0, deadline]
            )
        );
        const { v: v0, r: r0, s: s0 } = sign(permitDigest0, artist);

        expect(await nft721_0.getApproved(1)).to.be.equal(AddressZero);
        await nft721_0.permit(bob.address, 1, deadline, v0, r0, s0);
        expect(await nft721_0.getApproved(1)).to.be.equal(bob.address);

        const { v: v1, r: r1, s: s1 } = sign(
            await getDigest(
                ethers.provider,
                "Name",
                nft721_0.address,
                getHash(
                    ["bytes32", "address", "uint256", "uint256", "uint256"],
                    [await nft721_0.PERMIT_TYPEHASH(), bob.address, 2, 1, deadline]
                )
            ),
            artist
        );

        const { v: fv0, r: fr0, s: fs0 } = sign(
            await getDigest(
                ethers.provider,
                "Name",
                nft721_0.address,
                getHash(
                    ["bytes32", "address", "uint256", "uint256", "uint256"],
                    [await nft721_0.PERMIT_TYPEHASH(), bob.address, 2, 5, deadline] //invalid nonce
                )
            ),
            artist
        );
        const { v: fv1, r: fr1, s: fs1 } = sign(
            await getDigest(
                ethers.provider,
                "Name",
                nft721_0.address,
                getHash(
                    ["bytes32", "address", "uint256", "uint256", "uint256"],
                    [await nft721_0.PERMIT_TYPEHASH(), bob.address, 2, 1, deadline - 120] //deadline over
                )
            ),
            artist
        );
        const fakeSigner = ethers.Wallet.createRandom();
        const { v: fv2, r: fr2, s: fs2 } = sign(
            await getDigest(
                ethers.provider,
                "Name",
                nft721_0.address,
                getHash(
                    ["bytes32", "address", "uint256", "uint256", "uint256"],
                    [await nft721_0.PERMIT_TYPEHASH(), bob.address, 2, 1, deadline] //fake signer
                )
            ),
            fakeSigner
        );

        await expect(nft721_0.permit(bob.address, 2, deadline, fv0, fr0, fs0)).to.be.revertedWith(
            "SHOYU: UNAUTHORIZED"
        ); //invalid nonce
        await expect(nft721_0.permit(bob.address, 2, deadline - 150, fv1, fr1, fs1)).to.be.revertedWith(
            "SHOYU: EXPIRED"
        ); //deadline over
        await expect(nft721_0.permit(bob.address, 5, deadline, v1, r1, s1)).to.be.revertedWith(
            "SHOYU: INVALID_TOKENID"
        ); //wrong id
        await expect(nft721_0.permit(carol.address, 2, deadline, v1, r1, s1)).to.be.revertedWith("SHOYU: UNAUTHORIZED"); //wrong spender
        await expect(nft721_0.permit(bob.address, 2, deadline, fv2, fr2, fs2)).to.be.revertedWith(
            "SHOYU: UNAUTHORIZED"
        ); //fake signer

        const permitAllDigest0 = await getDigest(
            ethers.provider,
            "Name",
            nft721_0.address,
            getHash(
                ["bytes32", "address", "address", "uint256", "uint256"],
                [await nft721_0.PERMIT_ALL_TYPEHASH(), artist.address, carol.address, 0, deadline]
            )
        );
        const { v: v2, r: r2, s: s2 } = sign(permitAllDigest0, artist);

        expect(await nft721_0.isApprovedForAll(artist.address, carol.address)).to.be.false;

        await expect(nft721_0.permitAll(artist.address, alice.address, deadline, v2, r2, s2)).to.be.revertedWith(
            "SHOYU: UNAUTHORIZED"
        );
        await nft721_0.permitAll(artist.address, carol.address, deadline, v2, r2, s2);

        expect(await nft721_0.isApprovedForAll(artist.address, carol.address)).to.be.true;
    });

    it("should be that owner can only decrease royalty fee", async () => {
        const { factory, nft721, alice, bob, royaltyVault } = await setupTest();

        await factory.setDeployerWhitelisted(AddressZero, true);
        await factory.upgradeNFT721(nft721.address);

        await factory.deployNFT721AndPark(alice.address, "Name", "Symbol", 7, royaltyVault.address, 20);
        const nft721_0 = await getNFT721(factory);

        await expect(nft721_0.setRoyaltyFee(10)).to.be.revertedWith("SHOYU: FORBIDDEN");
        await expect(nft721_0.connect(alice).setRoyaltyFee(30)).to.be.revertedWith("SHOYU: INVALID_FEE");
        await nft721_0.connect(alice).setRoyaltyFee(3);
        expect((await nft721_0.royaltyInfo(0, 1000))[1]).to.be.equal(3);
        await nft721_0.connect(alice).setRoyaltyFee(0);
        expect((await nft721_0.royaltyInfo(0, 1000))[1]).to.be.equal(0);
        await expect(nft721_0.connect(alice).setRoyaltyFee(1)).to.be.revertedWith("SHOYU: INVALID_FEE");

        await factory.deployNFT721AndMintBatch(bob.address, "Name", "Symbol", [9, 11], royaltyVault.address, 0);
        const nft721_1 = await getNFT721(factory);
        expect((await nft721_1.royaltyInfo(0, 1000))[1]).to.be.equal(0);
        await expect(nft721_1.connect(bob).setRoyaltyFee(251)).to.be.revertedWith("SHOYU: INVALID_FEE");
        await nft721_1.connect(bob).setRoyaltyFee(93);
        expect((await nft721_1.royaltyInfo(0, 1000))[1]).to.be.equal(93);
        await expect(nft721_1.connect(bob).setRoyaltyFee(111)).to.be.revertedWith("SHOYU: INVALID_FEE");
        await nft721_1.connect(bob).setRoyaltyFee(0);
        expect((await nft721_1.royaltyInfo(0, 1000))[1]).to.be.equal(0);
        await expect(nft721_1.connect(bob).setRoyaltyFee(1)).to.be.revertedWith("SHOYU: INVALID_FEE");
    });

    it("should be that URI functions work well", async () => {
        const { factory, nft721, alice, bob, royaltyVault } = await setupTest();

        await factory.setDeployerWhitelisted(AddressZero, true);
        await factory.upgradeNFT721(nft721.address);

        async function URI721(nft: NFT721V2, tokenId: number, _baseURI?: string): Promise<string> {
            if (_baseURI === undefined) {
                const baseURI = await factory.baseURI721();
                const addy = nft.address.toLowerCase();
                return toUtf8String(
                    solidityPack(
                        ["string", "string", "string", "string", "string"],
                        [baseURI, addy, "/", tokenId.toString(), ".json"]
                    )
                );
            } else {
                return toUtf8String(
                    solidityPack(["string", "string", "string"], [_baseURI, tokenId.toString(), ".json"])
                );
            }
        }

        await factory.deployNFT721AndPark(alice.address, "Name", "Symbol", 10, royaltyVault.address, 10);
        const nft721_0 = await getNFT721(factory);

        await expect(nft721_0.connect(bob).setTokenURI(0, "https://foo.bar/0.json")).to.be.revertedWith(
            "SHOYU: FORBIDDEN"
        );
        await nft721_0.connect(alice).setTokenURI(0, "https://foo.bar/0.json");
        await nft721_0.connect(alice).setTokenURI(1, "https://foo.bar/1.json");

        expect(await nft721_0.tokenURI(0)).to.be.equal("https://foo.bar/0.json");
        expect(await nft721_0.tokenURI(1)).to.be.equal("https://foo.bar/1.json");

        expect(await nft721_0.tokenURI(2)).to.be.equal(await URI721(nft721_0, 2));
        expect(await nft721_0.tokenURI(4)).to.be.equal(await URI721(nft721_0, 4));
        expect(await nft721_0.tokenURI(7)).to.be.equal(await URI721(nft721_0, 7));
        expect(await nft721_0.tokenURI(2)).to.be.not.equal(await URI721(nft721_0, 2, "https://foo.bar/"));
        expect(await nft721_0.tokenURI(4)).to.be.not.equal(await URI721(nft721_0, 4, "https://foo.bar/"));
        expect(await nft721_0.tokenURI(7)).to.be.not.equal(await URI721(nft721_0, 7, "https://foo.bar/"));

        await expect(nft721_0.connect(bob).setBaseURI("https://foo.bar/")).to.be.revertedWith("SHOYU: FORBIDDEN");
        await nft721_0.connect(alice).setBaseURI("https://foo.bar/");

        expect(await nft721_0.tokenURI(2)).to.be.equal(await URI721(nft721_0, 2, "https://foo.bar/"));
        expect(await nft721_0.tokenURI(4)).to.be.equal(await URI721(nft721_0, 4, "https://foo.bar/"));
        expect(await nft721_0.tokenURI(7)).to.be.equal(await URI721(nft721_0, 7, "https://foo.bar/"));
        expect(await nft721_0.tokenURI(2)).to.be.not.equal(await URI721(nft721_0, 2));
        expect(await nft721_0.tokenURI(4)).to.be.not.equal(await URI721(nft721_0, 4));
        expect(await nft721_0.tokenURI(7)).to.be.not.equal(await URI721(nft721_0, 7));
    });

    it("should be that parkTokenIds func work well", async () => {
        const { factory, nft721, alice, bob, royaltyVault } = await setupTest();

        await factory.setDeployerWhitelisted(AddressZero, true);
        await factory.upgradeNFT721(nft721.address);

        await factory.deployNFT721AndPark(alice.address, "Name", "Symbol", 50, royaltyVault.address, 10);
        const nft721_0 = await getNFT721(factory);

        await expect(nft721_0.connect(bob).parkTokenIds(100)).to.be.revertedWith("SHOYU: FORBIDDEN");
        await expect(nft721_0.connect(alice).parkTokenIds(30)).to.be.revertedWith("SHOYU: INVALID_TO_TOKEN_ID");
        await expect(nft721_0.connect(alice).parkTokenIds(50)).to.be.revertedWith("SHOYU: INVALID_TO_TOKEN_ID");
        await nft721_0.connect(alice).parkTokenIds(51);
        await nft721_0.connect(alice).parkTokenIds(100);
    });

    it("should be that mint/mintBatch functions work well", async () => {
        const { factory, nft721, alice, bob, royaltyVault } = await setupTest();

        await factory.setDeployerWhitelisted(AddressZero, true);
        await factory.upgradeNFT721(nft721.address);

        await factory.deployNFT721AndMintBatch(bob.address, "Name", "Symbol", [0, 2, 4], royaltyVault.address, 10);
        const nft721_0 = await getNFT721(factory);

        await expect(nft721_0.mint(alice.address, 1, [])).to.be.revertedWith("SHOYU: FORBIDDEN");
        await expect(nft721_0.connect(bob).mint(alice.address, 0, [])).to.be.revertedWith("SHOYU: ALREADY_MINTED");
        await expect(nft721_0.connect(bob).mint(AddressZero, 1, [])).to.be.revertedWith("SHOYU: INVALID_TO");
        await expect(nft721_0.connect(bob).mint(factory.address, 1, [])).to.be.revertedWith("SHOYU: INVALID_RECEIVER");

        await nft721_0.connect(bob).mint(alice.address, 1, []); //0,1,2,4 are minted

        await expect(nft721_0.mintBatch(alice.address, [3, 5], [])).to.be.revertedWith("SHOYU: FORBIDDEN");
        await expect(nft721_0.connect(bob).mintBatch(alice.address, [3, 4], [])).to.be.revertedWith(
            "SHOYU: ALREADY_MINTED"
        );
        await expect(nft721_0.connect(bob).mintBatch(AddressZero, [3, 5], [])).to.be.revertedWith("SHOYU: INVALID_TO");
        await expect(nft721_0.connect(bob).mintBatch(factory.address, [3, 5], [])).to.be.revertedWith(
            "SHOYU: INVALID_RECEIVER"
        );

        await nft721_0.connect(bob).mint(alice.address, [3, 5], []); //0,1,2,3,4,5 are minted

        await factory.deployNFT721AndPark(alice.address, "Name", "Symbol", 50, royaltyVault.address, 10);
        const nft721_1 = await getNFT721(factory); //nothing is minted. 0-49 are parked

        await expect(nft721_1.mint(bob.address, 1, [])).to.be.revertedWith("SHOYU: FORBIDDEN");
        await expect(nft721_1.connect(alice).mint(AddressZero, 1, [])).to.be.revertedWith("SHOYU: INVALID_TO");
        await expect(nft721_1.connect(alice).mint(factory.address, 1, [])).to.be.revertedWith(
            "SHOYU: INVALID_RECEIVER"
        );

        await nft721_1.connect(alice).mint(bob.address, 1, []);
        await nft721_1.connect(alice).mint(bob.address, 50, []); //1,50 are minted. 0-49 are parked

        await expect(nft721_1.mintBatch(bob.address, [3, 5, 7], [])).to.be.revertedWith("SHOYU: FORBIDDEN");
        await expect(nft721_1.connect(alice).mintBatch(bob.address, [1, 5, 7], [])).to.be.revertedWith(
            "SHOYU: ALREADY_MINTED"
        );
        await expect(nft721_1.connect(alice).mintBatch(AddressZero, [3, 5, 7], [])).to.be.revertedWith(
            "SHOYU: INVALID_TO"
        );
        await expect(nft721_1.connect(alice).mintBatch(factory.address, [3, 5, 7], [])).to.be.revertedWith(
            "SHOYU: INVALID_RECEIVER"
        );

        await nft721_1.connect(alice).mint(bob.address, [3, 5, 7], []); //1,3,5,7,50 are minted. 0-49 are parked
        await nft721_1.connect(alice).mint(bob.address, [40, 55], []); //1,3,5,7,40,50,55 are minted. 0-49 are parked
        await nft721_1.connect(alice).mint(bob.address, [80, 100], []); //1,3,5,7,40,50,55,80,100 are minted. 0-49 are parked
    });

    it("should be that burn/burnBatch functions work well", async () => {
        const { factory, nft721, alice, bob, royaltyVault } = await setupTest();

        await factory.setDeployerWhitelisted(AddressZero, true);
        await factory.upgradeNFT721(nft721.address);

        await factory.deployNFT721AndMintBatch(
            bob.address,
            "Name",
            "Symbol",
            [0, 2, 4, 6, 8, 10],
            royaltyVault.address,
            10
        );
        const nft721_0 = await getNFT721(factory);
        await nft721_0.connect(bob).transferFrom(bob.address, alice.address, 6);
        await nft721_0.connect(bob).transferFrom(bob.address, alice.address, 8);
        await nft721_0.connect(bob).transferFrom(bob.address, alice.address, 10);
        //bob : owner & 0,2,4 _  alice : notOwner & 6,8,10

        await expect(nft721_0.connect(bob).burn(6, 0, HashZero)).to.be.revertedWith("SHOYU: FORBIDDEN");
        await expect(nft721_0.connect(alice).burn(4, 0, HashZero)).to.be.revertedWith("SHOYU: FORBIDDEN");
        await nft721_0.connect(bob).burn(0, 0, HashZero); //0 is burned

        await expect(nft721_0.connect(bob).burn(0, 0, HashZero)).to.be.revertedWith("SHOYU: FORBIDDEN");

        await nft721_0.connect(alice).burn(6, 0, HashZero); //0,6 is burned

        //bob : owner & 2,4 _  alice : notOwner & 8,10
        await expect(nft721_0.connect(bob).burnBatch([2, 3])).to.be.revertedWith("SHOYU: FORBIDDEN");
        await expect(nft721_0.connect(bob).burnBatch([2, 8])).to.be.revertedWith("SHOYU: FORBIDDEN");
        await expect(nft721_0.connect(bob).burnBatch([3, 8])).to.be.revertedWith("SHOYU: FORBIDDEN");
        await expect(nft721_0.connect(bob).burnBatch([8, 10])).to.be.revertedWith("SHOYU: FORBIDDEN");

        await nft721_0.connect(alice).burnBatch([8, 10]);
        await nft721_0.connect(bob).burnBatch([2]);
    });

    it("should be that static call functions work properly", async () => {
        const { factory, nft721, alice, bob, royaltyVault } = await setupTest();

        await factory.setDeployerWhitelisted(AddressZero, true);
        await factory.upgradeNFT721(nft721.address);

        await factory.deployNFT721AndMintBatch(
            bob.address,
            "Name",
            "Symbol",
            [0, 2, 4, 6, 8, 10],
            royaltyVault.address,
            10
        );
        const nft721_0 = await getNFT721(factory);

        expect(await nft721_0.target()).to.be.equal(AddressZero);
        
        const StaticCallMock = await ethers.getContractFactory("StaticCallMock");
        const target0 = (await StaticCallMock.deploy()) as StaticCallMock;

        let proxyNFT = (await StaticCallMock.attach(nft721_0.address)) as StaticCallMock;
        await expect(proxyNFT.globalV()).to.be.reverted;
        await expect(proxyNFT.pureTest11(1)).to.be.reverted;

        await expect(nft721_0.setTarget(target0.address)).to.be.revertedWith("SHOYU: FORBIDDEN");
        await nft721_0.connect(bob).setTarget(target0.address);
        expect(await nft721_0.target()).to.be.equal(target0.address);

        expect(await proxyNFT.globalV()).to.be.equal(target0.address);
        expect(await proxyNFT.pureTest11(1)).to.be.equal(1);
        expect((await proxyNFT.pureTest23(2, "abc"))[0]).to.be.equal(2);
        expect((await proxyNFT.pureTest23(2, "abc"))[1]).to.be.equal("0x0000000000000000000000000000000000000001");
        expect((await proxyNFT.pureTest23(2, "abc"))[2]).to.be.equal("abc");

        expect(await proxyNFT.viewTest11(10)).to.be.equal(0);
        await target0.setX(10, 123);
        expect(await proxyNFT.viewTest11(10)).to.be.equal(123);

        await target0.setY(11, "qwe");
        expect((await proxyNFT.viewTest13(11))[0]).to.be.equal(0);
        expect((await proxyNFT.viewTest13(11))[1]).to.be.equal(target0.address);
        expect((await proxyNFT.viewTest13(11))[2]).to.be.equal("qwe");

        await target0.setX(11, 77);
        await target0.setY(11, "zxc");
        expect((await proxyNFT.viewTest13(11))[0]).to.be.equal(77);
        expect((await proxyNFT.viewTest13(11))[1]).to.be.equal(target0.address);
        expect((await proxyNFT.viewTest13(11))[2]).to.be.equal("zxc");
    });
});