difftreelog
CORE-386 Implement eth methods
in: master
7 files changed
crates/evm-coder/src/solidity.rsdiffbeforeafterboth--- a/crates/evm-coder/src/solidity.rs
+++ b/crates/evm-coder/src/solidity.rs
@@ -455,7 +455,7 @@
}
}
-#[impl_for_tuples(0, 12)]
+#[impl_for_tuples(0, 24)]
impl SolidityFunctions for Tuple {
for_tuples!( where #( Tuple: SolidityFunctions ),* );
pallets/common/src/erc.rsdiffbeforeafterboth--- a/pallets/common/src/erc.rs
+++ b/pallets/common/src/erc.rs
@@ -23,7 +23,7 @@
use pallet_evm_coder_substrate::dispatch_to_evm;
use sp_core::{H160, U256, H256};
use sp_std::vec::Vec;
-use up_data_structs::{Property, SponsoringRateLimit, NestingRule, OwnerRestrictedSet};
+use up_data_structs::{Property, SponsoringRateLimit, NestingRule, OwnerRestrictedSet, AccessMode};
use alloc::format;
use crate::{Pallet, CollectionHandle, Config, CollectionProperties};
@@ -252,6 +252,42 @@
save(self);
Ok(())
}
+
+ fn set_access(&mut self, caller: caller, mode: string) -> Result<void> {
+ let caller = T::CrossAccountId::from_eth(caller);
+ self.check_is_owner_or_admin(&caller)
+ .map_err(dispatch_to_evm::<T>)?;
+ self.collection.permissions.access = Some(match mode.as_str() {
+ "Normal" => AccessMode::Normal,
+ "AllowList" => AccessMode::AllowList,
+ _ => return Err("Not supported access mode".into()),
+ });
+ save(self);
+ Ok(())
+ }
+
+ fn add_to_allow_list(&self, caller: caller, user: address) -> Result<void> {
+ let caller = check_is_owner_or_admin(caller, self)?;
+ let user = T::CrossAccountId::from_eth(user);
+ <Pallet<T>>::toggle_allowlist(self, &caller, &user, true)
+ .map_err(dispatch_to_evm::<T>)?;
+ Ok(())
+ }
+
+ fn remove_from_allow_list(&self, caller: caller, user: address) -> Result<void> {
+ let caller = check_is_owner_or_admin(caller, self)?;
+ let user = T::CrossAccountId::from_eth(user);
+ <Pallet<T>>::toggle_allowlist(self, &caller, &user, false)
+ .map_err(dispatch_to_evm::<T>)?;
+ Ok(())
+ }
+
+ fn set_mint_mode(&mut self, caller: caller, mode: bool) -> Result<void> {
+ check_is_owner_or_admin(caller, self)?;
+ self.collection.permissions.mint_mode = Some(mode);
+ save(self);
+ Ok(())
+ }
}
fn check_is_owner<T: Config>(caller: caller, collection: &CollectionHandle<T>) -> Result<()> {
@@ -262,6 +298,14 @@
Ok(())
}
+fn check_is_owner_or_admin<T: Config>(caller: caller, collection: &CollectionHandle<T>) -> Result<T::CrossAccountId> {
+ let caller = T::CrossAccountId::from_eth(caller);
+ collection
+ .check_is_owner_or_admin(&caller)
+ .map_err(pallet_evm_coder_substrate::dispatch_to_evm::<T>)?;
+ Ok(caller)
+}
+
fn save<T: Config>(collection: &CollectionHandle<T>) {
<crate::CollectionById<T>>::insert(collection.id, collection.collection.clone());
}
pallets/nonfungible/src/stubs/UniqueNFT.rawdiffbeforeafterbothbinary blob — no preview
pallets/nonfungible/src/stubs/UniqueNFT.soldiffbeforeafterboth--- a/pallets/nonfungible/src/stubs/UniqueNFT.sol
+++ b/pallets/nonfungible/src/stubs/UniqueNFT.sol
@@ -51,105 +51,6 @@
event MintingFinished();
}
-// Selector: 3a54513b
-contract Collection is Dummy, ERC165 {
- // Selector: setCollectionProperty(string,bytes) 2f073f66
- function setCollectionProperty(string memory key, bytes memory value)
- public
- {
- require(false, stub_error);
- key;
- value;
- dummy = 0;
- }
-
- // Selector: deleteCollectionProperty(string) 7b7debce
- function deleteCollectionProperty(string memory key) public {
- require(false, stub_error);
- key;
- dummy = 0;
- }
-
- // Throws error if key not found
- //
- // Selector: collectionProperty(string) cf24fd6d
- function collectionProperty(string memory key)
- public
- view
- returns (bytes memory)
- {
- require(false, stub_error);
- key;
- dummy;
- return hex"";
- }
-
- // Selector: ethSetSponsor(address) 8f9af356
- function ethSetSponsor(address sponsor) public {
- require(false, stub_error);
- sponsor;
- dummy = 0;
- }
-
- // Selector: ethConfirmSponsorship() a8580d1a
- function ethConfirmSponsorship() public {
- require(false, stub_error);
- dummy = 0;
- }
-
- // Selector: setLimit(string,uint32) 68db30ca
- function setLimit(string memory limit, uint32 value) public {
- require(false, stub_error);
- limit;
- value;
- dummy = 0;
- }
-
- // Selector: setLimit(string,bool) ea67e4c2
- function setLimit(string memory limit, bool value) public {
- require(false, stub_error);
- limit;
- value;
- dummy = 0;
- }
-
- // Selector: contractAddress() f6b4dfb4
- function contractAddress() public view returns (address) {
- require(false, stub_error);
- dummy;
- return 0x0000000000000000000000000000000000000000;
- }
-
- // Selector: addAdmin(address) 70480275
- function addAdmin(address newAdmin) public view {
- require(false, stub_error);
- newAdmin;
- dummy;
- }
-
- // Selector: removeAdmin(address) 1785f53c
- function removeAdmin(address admin) public view {
- require(false, stub_error);
- admin;
- dummy;
- }
-
- // Selector: setNesting(bool) e8fc50dd
- function setNesting(bool enable) public {
- require(false, stub_error);
- enable;
- dummy = 0;
- }
-
- // Selector: setNesting(bool,address[]) 7df12a9a
- function setNesting(bool enable, address[] memory collections) public {
- require(false, stub_error);
- enable;
- collections;
- dummy = 0;
- }
-}
-
// Selector: 41369377
contract TokenProperties is Dummy, ERC165 {
// Selector: setTokenPropertyPermission(string,bool,bool,bool) 222d97fa
@@ -479,6 +380,133 @@
}
}
+// Selector: f56cd7fa
+contract Collection is Dummy, ERC165 {
+ // Selector: setCollectionProperty(string,bytes) 2f073f66
+ function setCollectionProperty(string memory key, bytes memory value)
+ public
+ {
+ require(false, stub_error);
+ key;
+ value;
+ dummy = 0;
+ }
+
+ // Selector: deleteCollectionProperty(string) 7b7debce
+ function deleteCollectionProperty(string memory key) public {
+ require(false, stub_error);
+ key;
+ dummy = 0;
+ }
+
+ // Throws error if key not found
+ //
+ // Selector: collectionProperty(string) cf24fd6d
+ function collectionProperty(string memory key)
+ public
+ view
+ returns (bytes memory)
+ {
+ require(false, stub_error);
+ key;
+ dummy;
+ return hex"";
+ }
+
+ // Selector: ethSetSponsor(address) 8f9af356
+ function ethSetSponsor(address sponsor) public {
+ require(false, stub_error);
+ sponsor;
+ dummy = 0;
+ }
+
+ // Selector: ethConfirmSponsorship() a8580d1a
+ function ethConfirmSponsorship() public {
+ require(false, stub_error);
+ dummy = 0;
+ }
+
+ // Selector: setLimit(string,uint32) 68db30ca
+ function setLimit(string memory limit, uint32 value) public {
+ require(false, stub_error);
+ limit;
+ value;
+ dummy = 0;
+ }
+
+ // Selector: setLimit(string,bool) ea67e4c2
+ function setLimit(string memory limit, bool value) public {
+ require(false, stub_error);
+ limit;
+ value;
+ dummy = 0;
+ }
+
+ // Selector: contractAddress() f6b4dfb4
+ function contractAddress() public view returns (address) {
+ require(false, stub_error);
+ dummy;
+ return 0x0000000000000000000000000000000000000000;
+ }
+
+ // Selector: addAdmin(address) 70480275
+ function addAdmin(address newAdmin) public view {
+ require(false, stub_error);
+ newAdmin;
+ dummy;
+ }
+
+ // Selector: removeAdmin(address) 1785f53c
+ function removeAdmin(address admin) public view {
+ require(false, stub_error);
+ admin;
+ dummy;
+ }
+
+ // Selector: setNesting(bool) e8fc50dd
+ function setNesting(bool enable) public {
+ require(false, stub_error);
+ enable;
+ dummy = 0;
+ }
+
+ // Selector: setNesting(bool,address[]) 7df12a9a
+ function setNesting(bool enable, address[] memory collections) public {
+ require(false, stub_error);
+ enable;
+ collections;
+ dummy = 0;
+ }
+
+ // Selector: setAccess(string) 488f56aa
+ function setAccess(string memory mode) public {
+ require(false, stub_error);
+ mode;
+ dummy = 0;
+ }
+
+ // Selector: addToAllowList(address) 31f59102
+ function addToAllowList(address user) public view {
+ require(false, stub_error);
+ user;
+ dummy;
+ }
+
+ // Selector: removeFromAllowList(address) eba8dabc
+ function removeFromAllowList(address user) public view {
+ require(false, stub_error);
+ user;
+ dummy;
+ }
+
+ // Selector: setMintMode(bool) 5dea9bd5
+ function setMintMode(bool mode) public {
+ require(false, stub_error);
+ mode;
+ dummy = 0;
+ }
+}
+
contract UniqueNFT is
Dummy,
ERC165,
tests/src/eth/api/UniqueNFT.soldiffbeforeafterboth--- a/tests/src/eth/api/UniqueNFT.sol
+++ b/tests/src/eth/api/UniqueNFT.sol
@@ -42,51 +42,6 @@
event MintingFinished();
}
-// Selector: 3a54513b
-interface Collection is Dummy, ERC165 {
- // Selector: setCollectionProperty(string,bytes) 2f073f66
- function setCollectionProperty(string memory key, bytes memory value)
- external;
-
- // Selector: deleteCollectionProperty(string) 7b7debce
- function deleteCollectionProperty(string memory key) external;
-
- // Throws error if key not found
- //
- // Selector: collectionProperty(string) cf24fd6d
- function collectionProperty(string memory key)
- external
- view
- returns (bytes memory);
-
- // Selector: ethSetSponsor(address) 8f9af356
- function ethSetSponsor(address sponsor) external;
-
- // Selector: ethConfirmSponsorship() a8580d1a
- function ethConfirmSponsorship() external;
-
- // Selector: setLimit(string,uint32) 68db30ca
- function setLimit(string memory limit, uint32 value) external;
-
- // Selector: setLimit(string,bool) ea67e4c2
- function setLimit(string memory limit, bool value) external;
-
- // Selector: contractAddress() f6b4dfb4
- function contractAddress() external view returns (address);
-
- // Selector: addAdmin(address) 70480275
- function addAdmin(address newAdmin) external view;
-
- // Selector: removeAdmin(address) 1785f53c
- function removeAdmin(address admin) external view;
-
- // Selector: setNesting(bool) e8fc50dd
- function setNesting(bool enable) external;
-
- // Selector: setNesting(bool,address[]) 7df12a9a
- function setNesting(bool enable, address[] memory collections) external;
-}
-
// Selector: 41369377
interface TokenProperties is Dummy, ERC165 {
// Selector: setTokenPropertyPermission(string,bool,bool,bool) 222d97fa
@@ -258,6 +213,63 @@
returns (bool);
}
+// Selector: f56cd7fa
+interface Collection is Dummy, ERC165 {
+ // Selector: setCollectionProperty(string,bytes) 2f073f66
+ function setCollectionProperty(string memory key, bytes memory value)
+ external;
+
+ // Selector: deleteCollectionProperty(string) 7b7debce
+ function deleteCollectionProperty(string memory key) external;
+
+ // Throws error if key not found
+ //
+ // Selector: collectionProperty(string) cf24fd6d
+ function collectionProperty(string memory key)
+ external
+ view
+ returns (bytes memory);
+
+ // Selector: ethSetSponsor(address) 8f9af356
+ function ethSetSponsor(address sponsor) external;
+
+ // Selector: ethConfirmSponsorship() a8580d1a
+ function ethConfirmSponsorship() external;
+
+ // Selector: setLimit(string,uint32) 68db30ca
+ function setLimit(string memory limit, uint32 value) external;
+
+ // Selector: setLimit(string,bool) ea67e4c2
+ function setLimit(string memory limit, bool value) external;
+
+ // Selector: contractAddress() f6b4dfb4
+ function contractAddress() external view returns (address);
+
+ // Selector: addAdmin(address) 70480275
+ function addAdmin(address newAdmin) external view;
+
+ // Selector: removeAdmin(address) 1785f53c
+ function removeAdmin(address admin) external view;
+
+ // Selector: setNesting(bool) e8fc50dd
+ function setNesting(bool enable) external;
+
+ // Selector: setNesting(bool,address[]) 7df12a9a
+ function setNesting(bool enable, address[] memory collections) external;
+
+ // Selector: setAccess(string) 488f56aa
+ function setAccess(string memory mode) external;
+
+ // Selector: addToAllowList(address) 31f59102
+ function addToAllowList(address user) external view;
+
+ // Selector: removeFromAllowList(address) eba8dabc
+ function removeFromAllowList(address user) external view;
+
+ // Selector: setMintMode(bool) 5dea9bd5
+ function setMintMode(bool mode) external;
+}
+
interface UniqueNFT is
Dummy,
ERC165,
tests/src/eth/contractSponsoring.test.tsdiffbeforeafterboth--- a/tests/src/eth/contractSponsoring.test.ts
+++ b/tests/src/eth/contractSponsoring.test.ts
@@ -31,6 +31,7 @@
evmCollectionHelpers,
getCollectionAddressFromResult,
evmCollection,
+ ethBalanceViaSub,
} from './util/helpers';
import {
addCollectionAdminExpectSuccess,
@@ -221,66 +222,51 @@
});
//TODO: CORE-302 add eth methods
- itWeb3.skip('Sponsoring evm address from substrate collection', async ({api, web3}) => {
+ itWeb3('Sponsoring collection from evm address via access list', async ({api, web3}) => {
const owner = await createEthAccountWithBalance(api, web3);
const collectionHelpers = evmCollectionHelpers(web3, owner);
let result = await collectionHelpers.methods.createNonfungibleCollection('Sponsor collection', '1', '1').send();
const {collectionIdAddress, collectionId} = await getCollectionAddressFromResult(api, result);
const sponsor = await createEthAccountWithBalance(api, web3);
const collectionEvm = evmCollection(web3, owner, collectionIdAddress);
- result = await collectionEvm.methods.ethSetSponsor(sponsor).send();
+ result = await collectionEvm.methods.ethSetSponsor(sponsor).send({from: owner});
let collectionSub = (await getDetailedCollectionInfo(api, collectionId))!;
expect(collectionSub.sponsorship.isUnconfirmed).to.be.true;
expect(collectionSub.sponsorship.asUnconfirmed.toHuman()).to.be.eq(evmToAddress(sponsor));
await expect(collectionEvm.methods.ethConfirmSponsorship().call()).to.be.rejectedWith('Caller is not set as sponsor');
- const sponsorCollection = evmCollection(web3, sponsor, collectionIdAddress);
- await sponsorCollection.methods.ethConfirmSponsorship().send();
+ await collectionEvm.methods.ethConfirmSponsorship().send({from: sponsor});
collectionSub = (await getDetailedCollectionInfo(api, collectionId))!;
expect(collectionSub.sponsorship.isConfirmed).to.be.true;
expect(collectionSub.sponsorship.asConfirmed.toHuman()).to.be.eq(evmToAddress(sponsor));
const user = createEthAccount(web3);
- const userContract = evmCollection(web3, user, collectionIdAddress);
- const nextTokenId = await userContract.methods.nextTokenId().call();
-
+ const nextTokenId = await collectionEvm.methods.nextTokenId().call();
expect(nextTokenId).to.be.equal('1');
- await expect(userContract.methods.mintWithTokenURI(
- user,
- nextTokenId,
- 'Test URI',
- ).call()).to.be.rejectedWith('PublicMintingNotAllowed');
-
- // TODO: add this methods to eth
- // {
- // const tx = api.tx.unique.setPublicAccessMode(collectionId, 'AllowList');
- // const events = await submitTransactionAsync(owner, tx);
- // const result = getCreateCollectionResult(events);
- // expect(result.success).to.be.true;
- // }
- // {
- // const tx = api.tx.unique.addToAllowList(collectionId, {Ethereum: userEth});
- // const events = await submitTransactionAsync(owner, tx);
- // const result = getCreateCollectionResult(events);
- // expect(result.success).to.be.true;
- // }
- // {
- // const tx = api.tx.unique.setMintPermission(collectionId, true);
- // const events = await submitTransactionAsync(owner, tx);
- // const result = getCreateCollectionResult(events);
- // expect(result.success).to.be.true;
- // }
+ const oldPermissions = (await getDetailedCollectionInfo(api, collectionId))!.permissions.toHuman();
+ expect(oldPermissions.mintMode).to.be.false;
+ expect(oldPermissions.access).to.be.equal('Normal');
+
+ await collectionEvm.methods.setAccess('AllowList').send({from: owner});
+ await collectionEvm.methods.addToAllowList(user).send({from: owner});
+ await collectionEvm.methods.setMintMode(true).send({from: owner});
+
+ const newPermissions = (await getDetailedCollectionInfo(api, collectionId))!.permissions.toHuman();
+ expect(newPermissions.mintMode).to.be.true;
+ expect(newPermissions.access).to.be.equal('AllowList');
+
// const [alicesBalanceBefore] = await getBalance(api, [alicesPublicKey]);
{
- const nextTokenId = await userContract.methods.nextTokenId().call();
+ const nextTokenId = await collectionEvm.methods.nextTokenId().call();
expect(nextTokenId).to.be.equal('1');
- const result = await userContract.methods.mintWithTokenURI(
+ const result = await collectionEvm.methods.mintWithTokenURI(
user,
nextTokenId,
'Test URI',
- ).send();
+ ).call({from: user});
+ console.log(result);
const events = normalizeEvents(result.events);
expect(events).to.be.deep.equal([
@@ -295,37 +281,63 @@
},
]);
- expect(await userContract.methods.tokenURI(nextTokenId).call()).to.be.equal('Test URI');
+ expect(await collectionEvm.methods.tokenURI(nextTokenId).call()).to.be.equal('Test URI');
}
});
- //TODO: CORE-302 add eth methods
- itWeb3.skip('Check that transaction via EVM spend money from substrate address', async ({api, web3, privateKeyWrapper}) => {
- const owner = privateKeyWrapper('//Alice');
- const user = privateKeyWrapper(`//User/${Date.now()}`);
- const userEth = subToEth(user.address);
- const collectionId = await createCollectionExpectSuccess();
- await addCollectionAdminExpectSuccess(owner, collectionId, {Ethereum: userEth});
- await transferBalanceTo(api, owner, user.address);
+ itWeb3('Check that transaction via EVM spend money from sponsor address', async ({api, web3}) => {
+ const owner = await createEthAccountWithBalance(api, web3);
+ const collectionHelpers = evmCollectionHelpers(web3, owner);
+ let result = await collectionHelpers.methods.createNonfungibleCollection('Sponsor collection', '1', '1').send();
+ const {collectionIdAddress, collectionId} = await getCollectionAddressFromResult(api, result);
+ const sponsor = await createEthAccountWithBalance(api, web3);
+ const collectionEvm = evmCollection(web3, owner, collectionIdAddress);
+ result = await collectionEvm.methods.ethSetSponsor(sponsor).send();
+ let collectionSub = (await getDetailedCollectionInfo(api, collectionId))!;
+ expect(collectionSub.sponsorship.isUnconfirmed).to.be.true;
+ expect(collectionSub.sponsorship.asUnconfirmed.toHuman()).to.be.eq(evmToAddress(sponsor));
+ await expect(collectionEvm.methods.ethConfirmSponsorship().call()).to.be.rejectedWith('Caller is not set as sponsor');
+ const sponsorCollection = evmCollection(web3, sponsor, collectionIdAddress);
+ await sponsorCollection.methods.ethConfirmSponsorship().send();
+ collectionSub = (await getDetailedCollectionInfo(api, collectionId))!;
+ expect(collectionSub.sponsorship.isConfirmed).to.be.true;
+ expect(collectionSub.sponsorship.asConfirmed.toHuman()).to.be.eq(evmToAddress(sponsor));
+
+ const user = createEthAccount(web3);
+ await collectionEvm.methods.addAdmin(user).send();
+
+ const ownerBalanceBefore = await ethBalanceViaSub(api, owner);
+ const sponsorBalanceBefore = await ethBalanceViaSub(api, sponsor);
+
+
+ const userCollectionEvm = evmCollection(web3, user, collectionIdAddress);
+ const nextTokenId = await userCollectionEvm.methods.nextTokenId().call();
+ expect(nextTokenId).to.be.equal('1');
+ result = await userCollectionEvm.methods.mintWithTokenURI(
+ user,
+ nextTokenId,
+ 'Test URI',
+ ).send();
+ const events = normalizeEvents(result.events);
const address = collectionIdToAddress(collectionId);
- const contract = new web3.eth.Contract(nonFungibleAbi as any, address, {from: userEth, ...GAS_ARGS});
- const [userBalanceBefore] = await getBalance(api, [user.address]);
-
- {
- const nextTokenId = await contract.methods.nextTokenId().call();
- expect(nextTokenId).to.be.equal('1');
- await executeEthTxOnSub(web3, api, user, contract, m => m.mintWithTokenURI(
- userEth,
- nextTokenId,
- 'Test URI',
- ));
-
- expect(await contract.methods.tokenURI(nextTokenId).call()).to.be.equal('Test URI');
- }
-
- const [userBalanceAfter] = await getBalance(api, [user.address]);
- expect(userBalanceAfter < userBalanceBefore).to.be.true;
+ expect(events).to.be.deep.equal([
+ {
+ address,
+ event: 'Transfer',
+ args: {
+ from: '0x0000000000000000000000000000000000000000',
+ to: user,
+ tokenId: nextTokenId,
+ },
+ },
+ ]);
+ expect(await userCollectionEvm.methods.tokenURI(nextTokenId).call()).to.be.equal('Test URI');
+
+ const ownerBalanceAfter = await ethBalanceViaSub(api, owner);
+ expect(ownerBalanceAfter).to.be.eq(ownerBalanceBefore);
+ const sponsorBalanceAfter = await ethBalanceViaSub(api, sponsor);
+ expect(sponsorBalanceAfter < sponsorBalanceBefore).to.be.true;
});
});
tests/src/eth/nonFungibleAbi.jsondiffbeforeafterboth1[2 {3 "anonymous": false,4 "inputs": [5 {6 "indexed": true,7 "internalType": "address",8 "name": "owner",9 "type": "address"10 },11 {12 "indexed": true,13 "internalType": "address",14 "name": "approved",15 "type": "address"16 },17 {18 "indexed": true,19 "internalType": "uint256",20 "name": "tokenId",21 "type": "uint256"22 }23 ],24 "name": "Approval",25 "type": "event"26 },27 {28 "anonymous": false,29 "inputs": [30 {31 "indexed": true,32 "internalType": "address",33 "name": "owner",34 "type": "address"35 },36 {37 "indexed": true,38 "internalType": "address",39 "name": "operator",40 "type": "address"41 },42 {43 "indexed": false,44 "internalType": "bool",45 "name": "approved",46 "type": "bool"47 }48 ],49 "name": "ApprovalForAll",50 "type": "event"51 },52 {53 "anonymous": false,54 "inputs": [],55 "name": "MintingFinished",56 "type": "event"57 },58 {59 "anonymous": false,60 "inputs": [61 {62 "indexed": true,63 "internalType": "address",64 "name": "from",65 "type": "address"66 },67 {68 "indexed": true,69 "internalType": "address",70 "name": "to",71 "type": "address"72 },73 {74 "indexed": true,75 "internalType": "uint256",76 "name": "tokenId",77 "type": "uint256"78 }79 ],80 "name": "Transfer",81 "type": "event"82 },83 {84 "inputs": [85 { "internalType": "address", "name": "newAdmin", "type": "address" }86 ],87 "name": "addAdmin",88 "outputs": [],89 "stateMutability": "view",90 "type": "function"91 },92 {93 "inputs": [94 { "internalType": "address", "name": "approved", "type": "address" },95 { "internalType": "uint256", "name": "tokenId", "type": "uint256" }96 ],97 "name": "approve",98 "outputs": [],99 "stateMutability": "nonpayable",100 "type": "function"101 },102 {103 "inputs": [104 { "internalType": "address", "name": "owner", "type": "address" }105 ],106 "name": "balanceOf",107 "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],108 "stateMutability": "view",109 "type": "function"110 },111 {112 "inputs": [113 { "internalType": "uint256", "name": "tokenId", "type": "uint256" }114 ],115 "name": "burn",116 "outputs": [],117 "stateMutability": "nonpayable",118 "type": "function"119 },120 {121 "inputs": [122 { "internalType": "address", "name": "from", "type": "address" },123 { "internalType": "uint256", "name": "tokenId", "type": "uint256" }124 ],125 "name": "burnFrom",126 "outputs": [],127 "stateMutability": "nonpayable",128 "type": "function"129 },130 {131 "inputs": [{ "internalType": "string", "name": "key", "type": "string" }],132 "name": "collectionProperty",133 "outputs": [{ "internalType": "bytes", "name": "", "type": "bytes" }],134 "stateMutability": "view",135 "type": "function"136 },137 {138 "inputs": [],139 "name": "contractAddress",140 "outputs": [{ "internalType": "address", "name": "", "type": "address" }],141 "stateMutability": "view",142 "type": "function"143 },144 {145 "inputs": [{ "internalType": "string", "name": "key", "type": "string" }],146 "name": "deleteCollectionProperty",147 "outputs": [],148 "stateMutability": "nonpayable",149 "type": "function"150 },151 {152 "inputs": [153 { "internalType": "uint256", "name": "tokenId", "type": "uint256" },154 { "internalType": "string", "name": "key", "type": "string" }155 ],156 "name": "deleteProperty",157 "outputs": [],158 "stateMutability": "nonpayable",159 "type": "function"160 },161 {162 "inputs": [],163 "name": "ethConfirmSponsorship",164 "outputs": [],165 "stateMutability": "nonpayable",166 "type": "function"167 },168 {169 "inputs": [170 { "internalType": "address", "name": "sponsor", "type": "address" }171 ],172 "name": "ethSetSponsor",173 "outputs": [],174 "stateMutability": "nonpayable",175 "type": "function"176 },177 {178 "inputs": [],179 "name": "finishMinting",180 "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],181 "stateMutability": "nonpayable",182 "type": "function"183 },184 {185 "inputs": [186 { "internalType": "uint256", "name": "tokenId", "type": "uint256" }187 ],188 "name": "getApproved",189 "outputs": [{ "internalType": "address", "name": "", "type": "address" }],190 "stateMutability": "view",191 "type": "function"192 },193 {194 "inputs": [195 { "internalType": "address", "name": "owner", "type": "address" },196 { "internalType": "address", "name": "operator", "type": "address" }197 ],198 "name": "isApprovedForAll",199 "outputs": [{ "internalType": "address", "name": "", "type": "address" }],200 "stateMutability": "view",201 "type": "function"202 },203 {204 "inputs": [205 { "internalType": "address", "name": "to", "type": "address" },206 { "internalType": "uint256", "name": "tokenId", "type": "uint256" }207 ],208 "name": "mint",209 "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],210 "stateMutability": "nonpayable",211 "type": "function"212 },213 {214 "inputs": [215 { "internalType": "address", "name": "to", "type": "address" },216 { "internalType": "uint256[]", "name": "tokenIds", "type": "uint256[]" }217 ],218 "name": "mintBulk",219 "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],220 "stateMutability": "nonpayable",221 "type": "function"222 },223 {224 "inputs": [225 { "internalType": "address", "name": "to", "type": "address" },226 {227 "components": [228 { "internalType": "uint256", "name": "field_0", "type": "uint256" },229 { "internalType": "string", "name": "field_1", "type": "string" }230 ],231 "internalType": "struct Tuple0[]",232 "name": "tokens",233 "type": "tuple[]"234 }235 ],236 "name": "mintBulkWithTokenURI",237 "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],238 "stateMutability": "nonpayable",239 "type": "function"240 },241 {242 "inputs": [243 { "internalType": "address", "name": "to", "type": "address" },244 { "internalType": "uint256", "name": "tokenId", "type": "uint256" },245 { "internalType": "string", "name": "tokenUri", "type": "string" }246 ],247 "name": "mintWithTokenURI",248 "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],249 "stateMutability": "nonpayable",250 "type": "function"251 },252 {253 "inputs": [],254 "name": "mintingFinished",255 "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],256 "stateMutability": "view",257 "type": "function"258 },259 {260 "inputs": [],261 "name": "name",262 "outputs": [{ "internalType": "string", "name": "", "type": "string" }],263 "stateMutability": "view",264 "type": "function"265 },266 {267 "inputs": [],268 "name": "nextTokenId",269 "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],270 "stateMutability": "view",271 "type": "function"272 },273 {274 "inputs": [275 { "internalType": "uint256", "name": "tokenId", "type": "uint256" }276 ],277 "name": "ownerOf",278 "outputs": [{ "internalType": "address", "name": "", "type": "address" }],279 "stateMutability": "view",280 "type": "function"281 },282 {283 "inputs": [284 { "internalType": "uint256", "name": "tokenId", "type": "uint256" },285 { "internalType": "string", "name": "key", "type": "string" }286 ],287 "name": "property",288 "outputs": [{ "internalType": "bytes", "name": "", "type": "bytes" }],289 "stateMutability": "view",290 "type": "function"291 },292 {293 "inputs": [294 { "internalType": "address", "name": "admin", "type": "address" }295 ],296 "name": "removeAdmin",297 "outputs": [],298 "stateMutability": "view",299 "type": "function"300 },301 {302 "inputs": [303 { "internalType": "address", "name": "from", "type": "address" },304 { "internalType": "address", "name": "to", "type": "address" },305 { "internalType": "uint256", "name": "tokenId", "type": "uint256" }306 ],307 "name": "safeTransferFrom",308 "outputs": [],309 "stateMutability": "nonpayable",310 "type": "function"311 },312 {313 "inputs": [314 { "internalType": "address", "name": "from", "type": "address" },315 { "internalType": "address", "name": "to", "type": "address" },316 { "internalType": "uint256", "name": "tokenId", "type": "uint256" },317 { "internalType": "bytes", "name": "data", "type": "bytes" }318 ],319 "name": "safeTransferFromWithData",320 "outputs": [],321 "stateMutability": "nonpayable",322 "type": "function"323 },324 {325 "inputs": [326 { "internalType": "address", "name": "operator", "type": "address" },327 { "internalType": "bool", "name": "approved", "type": "bool" }328 ],329 "name": "setApprovalForAll",330 "outputs": [],331 "stateMutability": "nonpayable",332 "type": "function"333 },334 {335 "inputs": [336 { "internalType": "string", "name": "key", "type": "string" },337 { "internalType": "bytes", "name": "value", "type": "bytes" }338 ],339 "name": "setCollectionProperty",340 "outputs": [],341 "stateMutability": "nonpayable",342 "type": "function"343 },344 {345 "inputs": [346 { "internalType": "string", "name": "limit", "type": "string" },347 { "internalType": "uint32", "name": "value", "type": "uint32" }348 ],349 "name": "setLimit",350 "outputs": [],351 "stateMutability": "nonpayable",352 "type": "function"353 },354 {355 "inputs": [356 { "internalType": "string", "name": "limit", "type": "string" },357 { "internalType": "bool", "name": "value", "type": "bool" }358 ],359 "name": "setLimit",360 "outputs": [],361 "stateMutability": "nonpayable",362 "type": "function"363 },364 {365 "inputs": [366 { "internalType": "bool", "name": "enable", "type": "bool" },367 {368 "internalType": "address[]",369 "name": "collections",370 "type": "address[]"371 }372 ],373 "name": "setNesting",374 "outputs": [],375 "stateMutability": "nonpayable",376 "type": "function"377 },378 {379 "inputs": [{ "internalType": "bool", "name": "enable", "type": "bool" }],380 "name": "setNesting",381 "outputs": [],382 "stateMutability": "nonpayable",383 "type": "function"384 },385 {386 "inputs": [387 { "internalType": "uint256", "name": "tokenId", "type": "uint256" },388 { "internalType": "string", "name": "key", "type": "string" },389 { "internalType": "bytes", "name": "value", "type": "bytes" }390 ],391 "name": "setProperty",392 "outputs": [],393 "stateMutability": "nonpayable",394 "type": "function"395 },396 {397 "inputs": [398 { "internalType": "string", "name": "key", "type": "string" },399 { "internalType": "bool", "name": "isMutable", "type": "bool" },400 { "internalType": "bool", "name": "collectionAdmin", "type": "bool" },401 { "internalType": "bool", "name": "tokenOwner", "type": "bool" }402 ],403 "name": "setTokenPropertyPermission",404 "outputs": [],405 "stateMutability": "nonpayable",406 "type": "function"407 },408 {409 "inputs": [410 { "internalType": "bytes4", "name": "interfaceID", "type": "bytes4" }411 ],412 "name": "supportsInterface",413 "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],414 "stateMutability": "view",415 "type": "function"416 },417 {418 "inputs": [],419 "name": "symbol",420 "outputs": [{ "internalType": "string", "name": "", "type": "string" }],421 "stateMutability": "view",422 "type": "function"423 },424 {425 "inputs": [426 { "internalType": "uint256", "name": "index", "type": "uint256" }427 ],428 "name": "tokenByIndex",429 "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],430 "stateMutability": "view",431 "type": "function"432 },433 {434 "inputs": [435 { "internalType": "address", "name": "owner", "type": "address" },436 { "internalType": "uint256", "name": "index", "type": "uint256" }437 ],438 "name": "tokenOfOwnerByIndex",439 "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],440 "stateMutability": "view",441 "type": "function"442 },443 {444 "inputs": [445 { "internalType": "uint256", "name": "tokenId", "type": "uint256" }446 ],447 "name": "tokenURI",448 "outputs": [{ "internalType": "string", "name": "", "type": "string" }],449 "stateMutability": "view",450 "type": "function"451 },452 {453 "inputs": [],454 "name": "totalSupply",455 "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],456 "stateMutability": "view",457 "type": "function"458 },459 {460 "inputs": [461 { "internalType": "address", "name": "to", "type": "address" },462 { "internalType": "uint256", "name": "tokenId", "type": "uint256" }463 ],464 "name": "transfer",465 "outputs": [],466 "stateMutability": "nonpayable",467 "type": "function"468 },469 {470 "inputs": [471 { "internalType": "address", "name": "from", "type": "address" },472 { "internalType": "address", "name": "to", "type": "address" },473 { "internalType": "uint256", "name": "tokenId", "type": "uint256" }474 ],475 "name": "transferFrom",476 "outputs": [],477 "stateMutability": "nonpayable",478 "type": "function"479 }480]1[2 {3 "anonymous": false,4 "inputs": [5 {6 "indexed": true,7 "internalType": "address",8 "name": "owner",9 "type": "address"10 },11 {12 "indexed": true,13 "internalType": "address",14 "name": "approved",15 "type": "address"16 },17 {18 "indexed": true,19 "internalType": "uint256",20 "name": "tokenId",21 "type": "uint256"22 }23 ],24 "name": "Approval",25 "type": "event"26 },27 {28 "anonymous": false,29 "inputs": [30 {31 "indexed": true,32 "internalType": "address",33 "name": "owner",34 "type": "address"35 },36 {37 "indexed": true,38 "internalType": "address",39 "name": "operator",40 "type": "address"41 },42 {43 "indexed": false,44 "internalType": "bool",45 "name": "approved",46 "type": "bool"47 }48 ],49 "name": "ApprovalForAll",50 "type": "event"51 },52 {53 "anonymous": false,54 "inputs": [],55 "name": "MintingFinished",56 "type": "event"57 },58 {59 "anonymous": false,60 "inputs": [61 {62 "indexed": true,63 "internalType": "address",64 "name": "from",65 "type": "address"66 },67 {68 "indexed": true,69 "internalType": "address",70 "name": "to",71 "type": "address"72 },73 {74 "indexed": true,75 "internalType": "uint256",76 "name": "tokenId",77 "type": "uint256"78 }79 ],80 "name": "Transfer",81 "type": "event"82 },83 {84 "inputs": [85 { "internalType": "address", "name": "newAdmin", "type": "address" }86 ],87 "name": "addAdmin",88 "outputs": [],89 "stateMutability": "view",90 "type": "function"91 },92 {93 "inputs": [94 { "internalType": "address", "name": "user", "type": "address" }95 ],96 "name": "addToAllowList",97 "outputs": [],98 "stateMutability": "view",99 "type": "function"100 },101 {102 "inputs": [103 { "internalType": "address", "name": "approved", "type": "address" },104 { "internalType": "uint256", "name": "tokenId", "type": "uint256" }105 ],106 "name": "approve",107 "outputs": [],108 "stateMutability": "nonpayable",109 "type": "function"110 },111 {112 "inputs": [113 { "internalType": "address", "name": "owner", "type": "address" }114 ],115 "name": "balanceOf",116 "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],117 "stateMutability": "view",118 "type": "function"119 },120 {121 "inputs": [122 { "internalType": "uint256", "name": "tokenId", "type": "uint256" }123 ],124 "name": "burn",125 "outputs": [],126 "stateMutability": "nonpayable",127 "type": "function"128 },129 {130 "inputs": [131 { "internalType": "address", "name": "from", "type": "address" },132 { "internalType": "uint256", "name": "tokenId", "type": "uint256" }133 ],134 "name": "burnFrom",135 "outputs": [],136 "stateMutability": "nonpayable",137 "type": "function"138 },139 {140 "inputs": [{ "internalType": "string", "name": "key", "type": "string" }],141 "name": "collectionProperty",142 "outputs": [{ "internalType": "bytes", "name": "", "type": "bytes" }],143 "stateMutability": "view",144 "type": "function"145 },146 {147 "inputs": [],148 "name": "contractAddress",149 "outputs": [{ "internalType": "address", "name": "", "type": "address" }],150 "stateMutability": "view",151 "type": "function"152 },153 {154 "inputs": [{ "internalType": "string", "name": "key", "type": "string" }],155 "name": "deleteCollectionProperty",156 "outputs": [],157 "stateMutability": "nonpayable",158 "type": "function"159 },160 {161 "inputs": [162 { "internalType": "uint256", "name": "tokenId", "type": "uint256" },163 { "internalType": "string", "name": "key", "type": "string" }164 ],165 "name": "deleteProperty",166 "outputs": [],167 "stateMutability": "nonpayable",168 "type": "function"169 },170 {171 "inputs": [],172 "name": "ethConfirmSponsorship",173 "outputs": [],174 "stateMutability": "nonpayable",175 "type": "function"176 },177 {178 "inputs": [179 { "internalType": "address", "name": "sponsor", "type": "address" }180 ],181 "name": "ethSetSponsor",182 "outputs": [],183 "stateMutability": "nonpayable",184 "type": "function"185 },186 {187 "inputs": [],188 "name": "finishMinting",189 "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],190 "stateMutability": "nonpayable",191 "type": "function"192 },193 {194 "inputs": [195 { "internalType": "uint256", "name": "tokenId", "type": "uint256" }196 ],197 "name": "getApproved",198 "outputs": [{ "internalType": "address", "name": "", "type": "address" }],199 "stateMutability": "view",200 "type": "function"201 },202 {203 "inputs": [204 { "internalType": "address", "name": "owner", "type": "address" },205 { "internalType": "address", "name": "operator", "type": "address" }206 ],207 "name": "isApprovedForAll",208 "outputs": [{ "internalType": "address", "name": "", "type": "address" }],209 "stateMutability": "view",210 "type": "function"211 },212 {213 "inputs": [214 { "internalType": "address", "name": "to", "type": "address" },215 { "internalType": "uint256", "name": "tokenId", "type": "uint256" }216 ],217 "name": "mint",218 "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],219 "stateMutability": "nonpayable",220 "type": "function"221 },222 {223 "inputs": [224 { "internalType": "address", "name": "to", "type": "address" },225 { "internalType": "uint256[]", "name": "tokenIds", "type": "uint256[]" }226 ],227 "name": "mintBulk",228 "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],229 "stateMutability": "nonpayable",230 "type": "function"231 },232 {233 "inputs": [234 { "internalType": "address", "name": "to", "type": "address" },235 {236 "components": [237 { "internalType": "uint256", "name": "field_0", "type": "uint256" },238 { "internalType": "string", "name": "field_1", "type": "string" }239 ],240 "internalType": "struct Tuple0[]",241 "name": "tokens",242 "type": "tuple[]"243 }244 ],245 "name": "mintBulkWithTokenURI",246 "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],247 "stateMutability": "nonpayable",248 "type": "function"249 },250 {251 "inputs": [252 { "internalType": "address", "name": "to", "type": "address" },253 { "internalType": "uint256", "name": "tokenId", "type": "uint256" },254 { "internalType": "string", "name": "tokenUri", "type": "string" }255 ],256 "name": "mintWithTokenURI",257 "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],258 "stateMutability": "nonpayable",259 "type": "function"260 },261 {262 "inputs": [],263 "name": "mintingFinished",264 "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],265 "stateMutability": "view",266 "type": "function"267 },268 {269 "inputs": [],270 "name": "name",271 "outputs": [{ "internalType": "string", "name": "", "type": "string" }],272 "stateMutability": "view",273 "type": "function"274 },275 {276 "inputs": [],277 "name": "nextTokenId",278 "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],279 "stateMutability": "view",280 "type": "function"281 },282 {283 "inputs": [284 { "internalType": "uint256", "name": "tokenId", "type": "uint256" }285 ],286 "name": "ownerOf",287 "outputs": [{ "internalType": "address", "name": "", "type": "address" }],288 "stateMutability": "view",289 "type": "function"290 },291 {292 "inputs": [293 { "internalType": "uint256", "name": "tokenId", "type": "uint256" },294 { "internalType": "string", "name": "key", "type": "string" }295 ],296 "name": "property",297 "outputs": [{ "internalType": "bytes", "name": "", "type": "bytes" }],298 "stateMutability": "view",299 "type": "function"300 },301 {302 "inputs": [303 { "internalType": "address", "name": "admin", "type": "address" }304 ],305 "name": "removeAdmin",306 "outputs": [],307 "stateMutability": "view",308 "type": "function"309 },310 {311 "inputs": [312 { "internalType": "address", "name": "user", "type": "address" }313 ],314 "name": "removeFromAllowList",315 "outputs": [],316 "stateMutability": "view",317 "type": "function"318 },319 {320 "inputs": [321 { "internalType": "address", "name": "from", "type": "address" },322 { "internalType": "address", "name": "to", "type": "address" },323 { "internalType": "uint256", "name": "tokenId", "type": "uint256" }324 ],325 "name": "safeTransferFrom",326 "outputs": [],327 "stateMutability": "nonpayable",328 "type": "function"329 },330 {331 "inputs": [332 { "internalType": "address", "name": "from", "type": "address" },333 { "internalType": "address", "name": "to", "type": "address" },334 { "internalType": "uint256", "name": "tokenId", "type": "uint256" },335 { "internalType": "bytes", "name": "data", "type": "bytes" }336 ],337 "name": "safeTransferFromWithData",338 "outputs": [],339 "stateMutability": "nonpayable",340 "type": "function"341 },342 {343 "inputs": [{ "internalType": "string", "name": "mode", "type": "string" }],344 "name": "setAccess",345 "outputs": [],346 "stateMutability": "nonpayable",347 "type": "function"348 },349 {350 "inputs": [351 { "internalType": "address", "name": "operator", "type": "address" },352 { "internalType": "bool", "name": "approved", "type": "bool" }353 ],354 "name": "setApprovalForAll",355 "outputs": [],356 "stateMutability": "nonpayable",357 "type": "function"358 },359 {360 "inputs": [361 { "internalType": "string", "name": "key", "type": "string" },362 { "internalType": "bytes", "name": "value", "type": "bytes" }363 ],364 "name": "setCollectionProperty",365 "outputs": [],366 "stateMutability": "nonpayable",367 "type": "function"368 },369 {370 "inputs": [371 { "internalType": "string", "name": "limit", "type": "string" },372 { "internalType": "uint32", "name": "value", "type": "uint32" }373 ],374 "name": "setLimit",375 "outputs": [],376 "stateMutability": "nonpayable",377 "type": "function"378 },379 {380 "inputs": [381 { "internalType": "string", "name": "limit", "type": "string" },382 { "internalType": "bool", "name": "value", "type": "bool" }383 ],384 "name": "setLimit",385 "outputs": [],386 "stateMutability": "nonpayable",387 "type": "function"388 },389 {390 "inputs": [{ "internalType": "bool", "name": "mode", "type": "bool" }],391 "name": "setMintMode",392 "outputs": [],393 "stateMutability": "nonpayable",394 "type": "function"395 },396 {397 "inputs": [398 { "internalType": "bool", "name": "enable", "type": "bool" },399 {400 "internalType": "address[]",401 "name": "collections",402 "type": "address[]"403 }404 ],405 "name": "setNesting",406 "outputs": [],407 "stateMutability": "nonpayable",408 "type": "function"409 },410 {411 "inputs": [{ "internalType": "bool", "name": "enable", "type": "bool" }],412 "name": "setNesting",413 "outputs": [],414 "stateMutability": "nonpayable",415 "type": "function"416 },417 {418 "inputs": [419 { "internalType": "uint256", "name": "tokenId", "type": "uint256" },420 { "internalType": "string", "name": "key", "type": "string" },421 { "internalType": "bytes", "name": "value", "type": "bytes" }422 ],423 "name": "setProperty",424 "outputs": [],425 "stateMutability": "nonpayable",426 "type": "function"427 },428 {429 "inputs": [430 { "internalType": "string", "name": "key", "type": "string" },431 { "internalType": "bool", "name": "isMutable", "type": "bool" },432 { "internalType": "bool", "name": "collectionAdmin", "type": "bool" },433 { "internalType": "bool", "name": "tokenOwner", "type": "bool" }434 ],435 "name": "setTokenPropertyPermission",436 "outputs": [],437 "stateMutability": "nonpayable",438 "type": "function"439 },440 {441 "inputs": [442 { "internalType": "bytes4", "name": "interfaceID", "type": "bytes4" }443 ],444 "name": "supportsInterface",445 "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],446 "stateMutability": "view",447 "type": "function"448 },449 {450 "inputs": [],451 "name": "symbol",452 "outputs": [{ "internalType": "string", "name": "", "type": "string" }],453 "stateMutability": "view",454 "type": "function"455 },456 {457 "inputs": [458 { "internalType": "uint256", "name": "index", "type": "uint256" }459 ],460 "name": "tokenByIndex",461 "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],462 "stateMutability": "view",463 "type": "function"464 },465 {466 "inputs": [467 { "internalType": "address", "name": "owner", "type": "address" },468 { "internalType": "uint256", "name": "index", "type": "uint256" }469 ],470 "name": "tokenOfOwnerByIndex",471 "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],472 "stateMutability": "view",473 "type": "function"474 },475 {476 "inputs": [477 { "internalType": "uint256", "name": "tokenId", "type": "uint256" }478 ],479 "name": "tokenURI",480 "outputs": [{ "internalType": "string", "name": "", "type": "string" }],481 "stateMutability": "view",482 "type": "function"483 },484 {485 "inputs": [],486 "name": "totalSupply",487 "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],488 "stateMutability": "view",489 "type": "function"490 },491 {492 "inputs": [493 { "internalType": "address", "name": "to", "type": "address" },494 { "internalType": "uint256", "name": "tokenId", "type": "uint256" }495 ],496 "name": "transfer",497 "outputs": [],498 "stateMutability": "nonpayable",499 "type": "function"500 },501 {502 "inputs": [503 { "internalType": "address", "name": "from", "type": "address" },504 { "internalType": "address", "name": "to", "type": "address" },505 { "internalType": "uint256", "name": "tokenId", "type": "uint256" }506 ],507 "name": "transferFrom",508 "outputs": [],509 "stateMutability": "nonpayable",510 "type": "function"511 }512]