@coti-io/coti-contracts-examples
Version:
Example smart contracts demonstrating the use of COTI's GC technology, including integrations with MPC, private ERC20, and ERC721 contracts.
223 lines (167 loc) • 7.34 kB
text/typescript
import hre from "hardhat"
import { expect } from "chai"
import { setupAccounts } from "./utils/accounts"
import { ContractTransactionReceipt } from "ethers"
import { itString, Wallet } from "@coti-io/coti-ethers"
const gasLimit = 12000000
async function deploy() {
const [owner, otherAccount] = await setupAccounts()
const factory = await hre.ethers.getContractFactory("PrivateNFT")
const contract = await factory.connect(owner).deploy({ gasLimit })
await contract.waitForDeployment()
return { contract, contractAddress: await contract.getAddress(), owner, otherAccount }
}
describe("Private NFT", function () {
let deployment: Awaited<ReturnType<typeof deploy>>
before(async function () {
deployment = await deploy()
})
describe("Deployment", function () {
it("Deployed address should be a valid Ethereum address", async function () {
expect(hre.ethers.isAddress(deployment.contractAddress)).to.eq(true)
})
it("Name should match deployment name", async function () {
expect(await deployment.contract.name()).to.equal("Example")
})
it("Symbol should match deployment symbol", async function () {
expect(await deployment.contract.symbol()).to.equal("EXL")
})
})
describe("Minting", function () {
const tokenURI = 'https://api.pudgypenguins.io/lil/18707'
describe("Successful mint", function () {
let tx: ContractTransactionReceipt | null
before(async function () {
const { contract, contractAddress, owner, otherAccount } = deployment
const encryptedTokenURI = await owner.encryptValue(tokenURI, contractAddress, contract.mint.fragment.selector) as itString
const res = await contract
.connect(owner)
.mint(
otherAccount.address,
encryptedTokenURI,
{ gasLimit })
tx = await res.wait()
})
it("Should emit a 'Minted' event", async function () {
const { contract } = deployment
expect(tx).to.emit(contract, "Minted")
})
it("Should update the owners mapping", async function () {
const { contract, otherAccount } = deployment
expect(await contract.ownerOf(BigInt(0))).to.equal(otherAccount.address)
})
it("Should update the balances mapping", async function () {
const { contract, otherAccount } = deployment
expect(await contract.balanceOf(otherAccount.address)).to.equal(BigInt(1))
})
})
it("Should fail to mint if the encrypted token URI is faulty", async function () {
const { contract, contractAddress, otherAccount, owner } = deployment
const ownerEncryptedTokenURI = await owner.encryptValue(tokenURI, contractAddress, contract.mint.fragment.selector) as itString
const otherAccountEncryptedTokenURI = await otherAccount.encryptValue(tokenURI, contractAddress, contract.mint.fragment.selector) as itString
const encryptedTokenURI = {
ciphertext: ownerEncryptedTokenURI.ciphertext,
signature: otherAccountEncryptedTokenURI.signature
}
const tx = await contract
.connect(otherAccount)
.mint(
otherAccount.address,
encryptedTokenURI,
{ gasLimit }
)
expect(tx).to.be.reverted
})
})
describe("URI", function () {
it("should return 0 for token URI if not set", async function () {
const { contract, owner } = deployment
const tokenId = BigInt(1)
const ctURI = await contract.connect(owner).tokenURI(tokenId)
const uri = await owner.decryptValue(ctURI)
expect(uri).to.equal("")
})
})
describe("Transfers", function () {
describe("Successful transfer", function () {
const tokenId = BigInt(0)
const tokenURI = 'https://api.pudgypenguins.io/lil/18707'
before(async function () {
const { contract, owner, otherAccount } = deployment
await (await contract.connect(otherAccount).approve(owner.address, tokenId, { gasLimit })).wait()
await (
await contract
.connect(owner)
.transferFrom(otherAccount.address, owner.address, tokenId, { gasLimit })
).wait()
})
it("Should transfer token to other account", async function () {
const { contract, owner, otherAccount } = deployment
expect(await contract.ownerOf(tokenId)).to.equal(owner.address)
expect(await contract.balanceOf(owner.address)).to.equal(BigInt(1))
expect(await contract.balanceOf(otherAccount.address)).to.equal(BigInt(0))
})
it("Should allow the new owner to decrypt the token URI", async function () {
const { contract, owner } = deployment
const encryptedTokenURI = await contract.tokenURI(tokenId)
const decryptedTokenURI = await owner.decryptValue(encryptedTokenURI)
expect(decryptedTokenURI).to.equal(tokenURI)
})
it("Should not allow the previous owner to decrypt the token URI", async function () {
const { contract, otherAccount } = deployment
const encryptedTokenURI = await contract.tokenURI(tokenId)
const decryptedTokenURI = await otherAccount.decryptValue(encryptedTokenURI)
expect(decryptedTokenURI).to.not.equal(tokenURI)
})
})
describe("Failed transfers", function () {
const tokenURI = 'https://api.pudgypenguins.io/lil/9040'
it("Should fail transfer token to other account for when no allowance", async function () {
const { contract, contractAddress, owner, otherAccount } = deployment
const encryptedTokenURI = await owner.encryptValue(tokenURI, contractAddress, contract.mint.fragment.selector) as itString
const tokenId = await deployment.contract.totalSupply()
await (
await contract
.connect(owner)
.mint(
owner.address,
encryptedTokenURI,
{ gasLimit }
)
).wait()
const tx = await contract
.connect(otherAccount)
.transferFrom(owner.address, otherAccount.address, tokenId, { gasLimit })
let reverted = true
try {
await tx.wait()
reverted = false
} catch (error) {}
expect(reverted).to.eq(true, "Should have reverted")
})
it("Should fail to transfer from non-owner", async function () {
const { contract, contractAddress, owner, otherAccount } = deployment
const encryptedTokenURI = await owner.encryptValue(tokenURI, contractAddress, contract.mint.fragment.selector) as itString
const tokenId = await deployment.contract.totalSupply()
await (
await contract
.connect(owner)
.mint(
owner.address,
encryptedTokenURI,
{ gasLimit }
)
).wait()
const tx = await contract
.connect(otherAccount)
.transferFrom(owner.address, otherAccount.address, tokenId, { gasLimit })
let reverted = true
try {
await tx.wait()
reverted = false
} catch (error) {}
expect(reverted).to.eq(true, "Should have reverted")
})
})
})
})