git.delta.rocks / unique-network / refs/commits / d7a043d9818f

difftreelog

CORE-302 Implement setSponsor method.

Trubnikov Sergey2022-04-20parent: #281abcb.patch.diff
in: master

10 files changed

modifiedMakefilediffbeforeafterboth
21TESTS_API=./tests/src/eth/api/21TESTS_API=./tests/src/eth/api/
2222
23.PHONY: regenerate_solidity23.PHONY: regenerate_solidity
24regenerate_solidity: UniqueFungible.sol UniqueNFT.sol ContractHelpers.sol24regenerate_solidity: UniqueFungible.sol UniqueNFT.sol ContractHelpers.sol Collection.sol
2525
26UniqueFungible.sol:26UniqueFungible.sol:
27 PACKAGE=pallet-fungible NAME=erc::gen_iface OUTPUT=$(TESTS_API)/$@ ./.maintain/scripts/generate_sol.sh27 PACKAGE=pallet-fungible NAME=erc::gen_iface OUTPUT=$(TESTS_API)/$@ ./.maintain/scripts/generate_sol.sh
36 PACKAGE=pallet-evm-contract-helpers NAME=eth::contract_helpers_impl OUTPUT=$(CONTRACT_HELPERS_STUBS)/$@ ./.maintain/scripts/generate_sol.sh36 PACKAGE=pallet-evm-contract-helpers NAME=eth::contract_helpers_impl OUTPUT=$(CONTRACT_HELPERS_STUBS)/$@ ./.maintain/scripts/generate_sol.sh
3737
38Collection.sol:38Collection.sol:
39 PACKAGE=pallet-evm-collection NAME=eth::contract_helpers_iface OUTPUT=$(TESTS_API)/$@ ./.maintain/scripts/generate_sol.sh39 PACKAGE=pallet-evm-collection NAME=eth::collection_iface OUTPUT=$(TESTS_API)/$@ ./.maintain/scripts/generate_sol.sh
40 PACKAGE=pallet-evm-collection NAME=eth::contract_helpers_impl OUTPUT=$(COLLECTION_STUBS)/$@ ./.maintain/scripts/generate_sol.sh40 PACKAGE=pallet-evm-collection NAME=eth::collection_impl OUTPUT=$(COLLECTION_STUBS)/$@ ./.maintain/scripts/generate_sol.sh
4141
42UniqueFungible: UniqueFungible.sol42UniqueFungible: UniqueFungible.sol
43 INPUT=$(FUNGIBLE_EVM_STUBS)/$< OUTPUT=$(FUNGIBLE_EVM_STUBS)/UniqueFungible.raw ./.maintain/scripts/compile_stub.sh43 INPUT=$(FUNGIBLE_EVM_STUBS)/$< OUTPUT=$(FUNGIBLE_EVM_STUBS)/UniqueFungible.raw ./.maintain/scripts/compile_stub.sh
modifiedpallets/common/src/lib.rsdiffbeforeafterboth
115 })115 })
116 }116 }
117
118 pub fn new_with_recorder(id: CollectionId, recorder: Rc<SubstrateRecorder<T>>) -> Option<Self> {
119 <CollectionById<T>>::get(id).map(|collection| Self {
120 id,
121 collection,
122 recorder,
123 })
124 }
125
117 pub fn new(id: CollectionId) -> Option<Self> {126 pub fn new(id: CollectionId) -> Option<Self> {
118 Self::new_with_gas_limit(id, u64::MAX)127 Self::new_with_gas_limit(id, u64::MAX)
141 Ok(())150 Ok(())
142 }151 }
152
153 pub fn set_sponsor(&mut self, sponsor: T::AccountId) {
154 self.collection.sponsorship = SponsorshipState::Unconfirmed(sponsor);
155 }
143}156}
144impl<T: Config> Deref for CollectionHandle<T> {157impl<T: Config> Deref for CollectionHandle<T> {
145 type Target = Collection<T::AccountId>;158 type Target = Collection<T::AccountId>;
modifiedpallets/evm-collection/src/eth.rsdiffbeforeafterboth
17use core::marker::PhantomData;17use core::marker::PhantomData;
18use evm_coder::{abi::AbiWriter, execution::*, generate_stubgen, solidity_interface, types::*, ToLog};18use evm_coder::{abi::AbiWriter, execution::*, generate_stubgen, solidity_interface, types::*, ToLog};
19use ethereum as _;19use ethereum as _;
20use pallet_common::CollectionById;20use pallet_common::{CollectionById, CollectionHandle};
21use pallet_evm_coder_substrate::{SubstrateRecorder, WithRecorder};21use pallet_evm_coder_substrate::{SubstrateRecorder, WithRecorder};
22use pallet_evm::{22use pallet_evm::{
23 ExitRevert, OnCreate, OnMethodCall, PrecompileResult, PrecompileFailure,23 ExitRevert, OnCreate, OnMethodCall, PrecompileResult, PrecompileFailure,
26use sp_core::H160;26use sp_core::H160;
27use up_data_structs::{27use up_data_structs::{
28 CreateCollectionData, MAX_COLLECTION_DESCRIPTION_LENGTH, MAX_TOKEN_PREFIX_LENGTH,28 CreateCollectionData, MAX_COLLECTION_DESCRIPTION_LENGTH, MAX_TOKEN_PREFIX_LENGTH,
29 MAX_COLLECTION_NAME_LENGTH,29 MAX_COLLECTION_NAME_LENGTH, SponsorshipState,
30};30};
31use crate::{Config, Pallet};31use crate::{Config, Pallet};
32use frame_support::traits::Get;32use frame_support::traits::Get;
102 Ok(address)103 Ok(address)
103 }104 }
104105
105 // fn set_sponsor(collection_id: address, sponsor: address) -> Result<void> {106 fn set_sponsor(
106 // let collection_id =107 &self,
107 // pallet_common::eth::map_eth_to_id(&collection_id).ok_or(Error::Revert("".into()))?;108 caller: caller,
108 // let mut collection = <CollectionById<T>>::get(collection_id).ok_or(Error::Revert("".into()))?;109 contract_address: address,
109 // let sponsor = T::CrossAccountId::from_eth(sponsor);110 sponsor: address,
110 // collection.sponsorship = SponsorshipState::Unconfirmed(sponsor.as_sub().clone());111 ) -> Result<void> {
111 // <CollectionById<T>>::insert(collection_id, collection);112 let collection_id =
112 // Ok(())113 pallet_common::eth::map_eth_to_id(&contract_address).ok_or(Error::Revert("".into()))?;
113 // }114 let mut collection =
115 pallet_common::CollectionHandle::new_with_recorder(collection_id, self.0.clone())
116 .ok_or(Error::Revert("".into()))?;
117
118 let caller = T::CrossAccountId::from_eth(caller);
119 collection.check_is_owner(&caller).map_err(|e| Error::Revert(format!("{:?}", e)))?;
120
121 let sponsor = T::CrossAccountId::from_eth(sponsor);
122 collection.set_sponsor(sponsor.as_sub().clone());
123 collection
124 .save()
125 .map_err(|e| Error::Revert(format!("{:?}", e)))
126 }
114127
115 // fn set_offchain_shema(shema: string) -> Result<void> {128 // fn set_offchain_shema(shema: string) -> Result<void> {
116 // Ok(())129 // Ok(())
modifiedpallets/evm-collection/src/stubs/Collection.rawdiffbeforeafterboth

binary blob — no preview

modifiedpallets/evm-collection/src/stubs/Collection.soldiffbeforeafterboth
21 }21 }
22}22}
2323
24// Selector: ee5467a824// Selector: 6503bbc2
25contract Collection is Dummy, ERC165 {25contract Collection is Dummy, ERC165 {
26 // Selector: contractOwner(address) 5152b14c26 // Selector: create721Collection(string,string,string) 951c0151
27 function contractOwner(address contractAddress)
28 public
29 view
30 returns (address)
31 {
32 require(false, stub_error);
33 contractAddress;
34 dummy;
35 return 0x0000000000000000000000000000000000000000;
36 }
37
38 // Selector: sponsoringEnabled(address) 6027dc61
39 function sponsoringEnabled(address contractAddress)27 function create721Collection(
40 public
41 view
42 returns (bool)
43 {
44 require(false, stub_error);28 string memory name,
45 contractAddress;
46 dummy;
47 return false;
48 }
49
50 // Deprecated
51 //
52 // Selector: toggleSponsoring(address,bool) fcac6d86
53 function toggleSponsoring(address contractAddress, bool enabled) public {29 string memory description,
54 require(false, stub_error);30 string memory tokenPrefix
55 contractAddress;
56 enabled;
57 dummy = 0;
58 }
59
60 // Selector: setSponsoringMode(address,uint8) fde8a560
61 function setSponsoringMode(address contractAddress, uint8 mode) public {
62 require(false, stub_error);
63 contractAddress;
64 mode;
65 dummy = 0;
66 }
67
68 // Selector: sponsoringMode(address) b70c7267
69 function sponsoringMode(address contractAddress)
70 public
71 view31 ) public view returns (address) {
72 returns (uint8)
73 {
74 require(false, stub_error);
75 contractAddress;
76 dummy;
77 return 0;
78 }
79
80 // Selector: setSponsoringRateLimit(address,uint32) 77b6c908
81 function setSponsoringRateLimit(address contractAddress, uint32 rateLimit)
82 public
83 {
84 require(false, stub_error);32 require(false, stub_error);
85 contractAddress;33 name;
86 rateLimit;34 description;
87 dummy = 0;
88 }
89
90 // Selector: getSponsoringRateLimit(address) 610cfabd
91 function getSponsoringRateLimit(address contractAddress)
92 public
93 view
94 returns (uint32)
95 {
96 require(false, stub_error);35 tokenPrefix;
97 contractAddress;
98 dummy;36 dummy;
99 return 0;37 return 0x0000000000000000000000000000000000000000;
100 }38 }
10139
102 // Selector: allowed(address,address) 5c65816540 // Selector: setSponsor(address,address) f01fba93
103 function allowed(address contractAddress, address user)41 function setSponsor(address contractAddress, address sponsor) public view {
104 public
105 view
106 returns (bool)
107 {
108 require(false, stub_error);42 require(false, stub_error);
109 contractAddress;43 contractAddress;
110 user;44 sponsor;
111 dummy;45 dummy;
112 return false;
113 }46 }
114
115 // Selector: allowlistEnabled(address) c772ef6c
116 function allowlistEnabled(address contractAddress)
117 public
118 view
119 returns (bool)
120 {
121 require(false, stub_error);
122 contractAddress;
123 dummy;
124 return false;
125 }
126
127 // Selector: toggleAllowlist(address,bool) 36de20f5
128 function toggleAllowlist(address contractAddress, bool enabled) public {
129 require(false, stub_error);
130 contractAddress;
131 enabled;
132 dummy = 0;
133 }
134
135 // Selector: toggleAllowed(address,address,bool) 4706cc1c
136 function toggleAllowed(
137 address contractAddress,
138 address user,
139 bool allowed
140 ) public {
141 require(false, stub_error);
142 contractAddress;
143 user;
144 allowed;
145 dummy = 0;
146 }
147
148 // Selector: create721Collection(string,string,string) 951c0151
149 function create721Collection(
150 string memory name,
151 string memory description,
152 string memory tokenPrefix
153 ) public view returns (address) {
154 require(false, stub_error);
155 name;
156 description;
157 tokenPrefix;
158 dummy;
159 return 0x0000000000000000000000000000000000000000;
160 }
161}47}
16248
modifiedpallets/unique/src/lib.rsdiffbeforeafterboth
520 let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;520 let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;
521 target_collection.check_is_owner(&sender)?;521 target_collection.check_is_owner(&sender)?;
522522
523 target_collection.sponsorship = SponsorshipState::Unconfirmed(new_sponsor.clone());523 target_collection.set_sponsor(new_sponsor.clone());
524524
525 <Pallet<T>>::deposit_event(Event::<T>::CollectionSponsorSet(525 <Pallet<T>>::deposit_event(Event::<T>::CollectionSponsorSet(
526 collection_id,526 collection_id,
modifiedtests/src/eth/api/Collection.soldiffbeforeafterboth
12 function supportsInterface(bytes4 interfaceID) external view returns (bool);12 function supportsInterface(bytes4 interfaceID) external view returns (bool);
13}13}
1414
15// Selector: ee5467a815// Selector: 6503bbc2
16interface Collection is Dummy, ERC165 {16interface Collection is Dummy, ERC165 {
17 // Selector: contractOwner(address) 5152b14c
18 function contractOwner(address contractAddress)
19 external
20 view
21 returns (address);
22
23 // Selector: sponsoringEnabled(address) 6027dc61
24 function sponsoringEnabled(address contractAddress)
25 external
26 view
27 returns (bool);
28
29 // Deprecated
30 //
31 // Selector: toggleSponsoring(address,bool) fcac6d86
32 function toggleSponsoring(address contractAddress, bool enabled) external;
33
34 // Selector: setSponsoringMode(address,uint8) fde8a560
35 function setSponsoringMode(address contractAddress, uint8 mode) external;
36
37 // Selector: sponsoringMode(address) b70c7267
38 function sponsoringMode(address contractAddress)
39 external
40 view
41 returns (uint8);
42
43 // Selector: setSponsoringRateLimit(address,uint32) 77b6c908
44 function setSponsoringRateLimit(address contractAddress, uint32 rateLimit)
45 external;
46
47 // Selector: getSponsoringRateLimit(address) 610cfabd
48 function getSponsoringRateLimit(address contractAddress)
49 external
50 view
51 returns (uint32);
52
53 // Selector: allowed(address,address) 5c658165
54 function allowed(address contractAddress, address user)
55 external
56 view
57 returns (bool);
58
59 // Selector: allowlistEnabled(address) c772ef6c
60 function allowlistEnabled(address contractAddress)
61 external
62 view
63 returns (bool);
64
65 // Selector: toggleAllowlist(address,bool) 36de20f5
66 function toggleAllowlist(address contractAddress, bool enabled) external;
67
68 // Selector: toggleAllowed(address,address,bool) 4706cc1c
69 function toggleAllowed(
70 address contractAddress,
71 address user,
72 bool allowed
73 ) external;
74
75 // Selector: create721Collection(string,string,string) 951c015117 // Selector: create721Collection(string,string,string) 951c0151
76 function create721Collection(18 function create721Collection(
79 string memory tokenPrefix21 string memory tokenPrefix
80 ) external view returns (address);22 ) external view returns (address);
23
24 // Selector: setSponsor(address,address) f01fba93
25 function setSponsor(address contractAddress, address sponsor) external view;
81}26}
8227
modifiedtests/src/eth/collectionAbi.jsondiffbeforeafterboth
1[1[
2 {
3 "inputs": [
4 {
5 "internalType": "address",
6 "name": "contractAddress",
7 "type": "address"
8 },
9 { "internalType": "address", "name": "user", "type": "address" }
10 ],
11 "name": "allowed",
12 "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
13 "stateMutability": "view",
14 "type": "function"
15 },
16 {
17 "inputs": [
18 {
19 "internalType": "address",
20 "name": "contractAddress",
21 "type": "address"
22 }
23 ],
24 "name": "allowlistEnabled",
25 "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
26 "stateMutability": "view",
27 "type": "function"
28 },
29 {
30 "inputs": [
31 {
32 "internalType": "address",
33 "name": "contractAddress",
34 "type": "address"
35 }
36 ],
37 "name": "contractOwner",
38 "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
39 "stateMutability": "view",
40 "type": "function"
41 },
42 {2 {
43 "inputs": [3 "inputs": [
44 { "internalType": "string", "name": "name", "type": "string" },4 { "internalType": "string", "name": "name", "type": "string" },
50 "stateMutability": "view",10 "stateMutability": "view",
51 "type": "function"11 "type": "function"
52 },12 },
53 {13 {
54 "inputs": [
55 {
56 "internalType": "address",
57 "name": "contractAddress",
58 "type": "address"
59 }
60 ],
61 "name": "getSponsoringRateLimit",
62 "outputs": [{ "internalType": "uint32", "name": "", "type": "uint32" }],
63 "stateMutability": "view",
64 "type": "function"
65 },
66 {
67 "inputs": [14 "inputs": [
68 {15 {
69 "internalType": "address",16 "internalType": "address",
70 "name": "contractAddress",17 "name": "contractAddress",
71 "type": "address"18 "type": "address"
72 },19 },
73 { "internalType": "uint8", "name": "mode", "type": "uint8" }20 { "internalType": "address", "name": "sponsor", "type": "address" }
74 ],21 ],
75 "name": "setSponsoringMode",22 "name": "setSponsor",
76 "outputs": [],23 "outputs": [],
77 "stateMutability": "nonpayable",
78 "type": "function"
79 },
80 {
81 "inputs": [
82 {
83 "internalType": "address",
84 "name": "contractAddress",
85 "type": "address"
86 },
87 { "internalType": "uint32", "name": "rateLimit", "type": "uint32" }
88 ],
89 "name": "setSponsoringRateLimit",
90 "outputs": [],
91 "stateMutability": "nonpayable",
92 "type": "function"
93 },
94 {
95 "inputs": [
96 {
97 "internalType": "address",
98 "name": "contractAddress",
99 "type": "address"
100 }
101 ],
102 "name": "sponsoringEnabled",
103 "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
104 "stateMutability": "view",24 "stateMutability": "view",
105 "type": "function"25 "type": "function"
106 },26 },
107 {
108 "inputs": [
109 {
110 "internalType": "address",
111 "name": "contractAddress",
112 "type": "address"
113 }
114 ],
115 "name": "sponsoringMode",
116 "outputs": [{ "internalType": "uint8", "name": "", "type": "uint8" }],
117 "stateMutability": "view",
118 "type": "function"
119 },
120 {27 {
121 "inputs": [28 "inputs": [
122 { "internalType": "bytes4", "name": "interfaceID", "type": "bytes4" }29 { "internalType": "bytes4", "name": "interfaceID", "type": "bytes4" }
125 "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],32 "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
126 "stateMutability": "view",33 "stateMutability": "view",
127 "type": "function"34 "type": "function"
128 },35 }
129 {
130 "inputs": [
131 {
132 "internalType": "address",
133 "name": "contractAddress",
134 "type": "address"
135 },
136 { "internalType": "address", "name": "user", "type": "address" },
137 { "internalType": "bool", "name": "allowed", "type": "bool" }
138 ],
139 "name": "toggleAllowed",
140 "outputs": [],
141 "stateMutability": "nonpayable",
142 "type": "function"
143 },
144 {
145 "inputs": [
146 {
147 "internalType": "address",
148 "name": "contractAddress",
149 "type": "address"
150 },
151 { "internalType": "bool", "name": "enabled", "type": "bool" }
152 ],
153 "name": "toggleAllowlist",
154 "outputs": [],
155 "stateMutability": "nonpayable",
156 "type": "function"
157 },
158 {
159 "inputs": [
160 {
161 "internalType": "address",
162 "name": "contractAddress",
163 "type": "address"
164 },
165 { "internalType": "bool", "name": "enabled", "type": "bool" }
166 ],
167 "name": "toggleSponsoring",
168 "outputs": [],
169 "stateMutability": "nonpayable",
170 "type": "function"
171 }
172]36]
17337
modifiedtests/src/eth/createCollection.test.tsdiffbeforeafterboth
14// You should have received a copy of the GNU General Public License14// You should have received a copy of the GNU General Public License
15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
1616
17import {ApiPromise} from '@polkadot/api';
18import {evmToAddress} from '@polkadot/util-crypto';
17import {expect} from 'chai';19import {expect} from 'chai';
18import {getCreatedCollectionCount, getDetailedCollectionInfo} from '../util/helpers';20import {getCreatedCollectionCount, getDetailedCollectionInfo} from '../util/helpers';
19import {collectionHelper, collectionIdFromAddress, contractHelpers, createEthAccountWithBalance, itWeb3} from './util/helpers';21import {collectionHelper, collectionIdFromAddress, createEthAccountWithBalance, itWeb3, normalizeAddress} from './util/helpers';
22
23async function getCollectionAddressFromResult(api: ApiPromise, result: any) {
24 const collectionIdAddress = normalizeAddress(result.events[0].raw.topics[2]);
25 const collectionId = collectionIdFromAddress(collectionIdAddress);
26 const collection = (await getDetailedCollectionInfo(api, collectionId))!;
27 return {collectionIdAddress, collectionId, collection};
28}
2029
21describe('Create collection from EVM', () => {30describe('Create collection from EVM', () => {
22 itWeb3('Create collection', async ({api, web3}) => {31 itWeb3('Create collection', async ({api, web3}) => {
23 const owner = await createEthAccountWithBalance(api, web3);32 const owner = await createEthAccountWithBalance(api, web3);
24 const helpers = collectionHelper(web3, owner);33 const helper = collectionHelper(web3, owner);
25 const collectionName = 'CollectionEVM';34 const collectionName = 'CollectionEVM';
26 const description = 'Some description';35 const description = 'Some description';
27 const tokenPrefix = 'token prefix';36 const tokenPrefix = 'token prefix';
28 37
29 const collectionCountBefore = await getCreatedCollectionCount(api);38 const collectionCountBefore = await getCreatedCollectionCount(api);
30 const result = await helpers.methods39 const result = await helper.methods
31 .create721Collection(collectionName, description, tokenPrefix)40 .create721Collection(collectionName, description, tokenPrefix)
32 .send();41 .send();
33 const collectionCountAfter = await getCreatedCollectionCount(api);42 const collectionCountAfter = await getCreatedCollectionCount(api);
34 43
35 const collectionId = collectionIdFromAddress(result.events[0].raw.topics[2]);44 const {collectionId, collection} = await getCollectionAddressFromResult(api, result);
36 expect(collectionCountAfter - collectionCountBefore).to.be.eq(1);45 expect(collectionCountAfter - collectionCountBefore).to.be.eq(1);
37 expect(collectionId).to.be.eq(collectionCountAfter);46 expect(collectionId).to.be.eq(collectionCountAfter);
38
39 const collection = (await getDetailedCollectionInfo(api, collectionId))!;
40 expect(collection.name.map(v => String.fromCharCode(v.toNumber())).join('')).to.be.eq(collectionName);47 expect(collection.name.map(v => String.fromCharCode(v.toNumber())).join('')).to.be.eq(collectionName);
41 expect(collection.description.map(v => String.fromCharCode(v.toNumber())).join('')).to.be.eq(description);48 expect(collection.description.map(v => String.fromCharCode(v.toNumber())).join('')).to.be.eq(description);
42 expect(collection.tokenPrefix.toHuman()).to.be.eq(tokenPrefix);49 expect(collection.tokenPrefix.toHuman()).to.be.eq(tokenPrefix);
43 expect(collection.schemaVersion.type).to.be.eq('ImageURL');50 expect(collection.schemaVersion.type).to.be.eq('ImageURL');
44 });51 });
52
53 itWeb3('Set sponsorship', async ({api, web3}) => {
54 const owner = await createEthAccountWithBalance(api, web3);
55 const helper = collectionHelper(web3, owner);
56 let result = await helper.methods.create721Collection('Sponsor collection', '1', '1').send();
57 const {collectionIdAddress, collectionId} = await getCollectionAddressFromResult(api, result);
58 const sponsor = await createEthAccountWithBalance(api, web3);
59 result = await helper.methods.setSponsor(collectionIdAddress, sponsor).send();
60 const collection = (await getDetailedCollectionInfo(api, collectionId))!;
61 expect(collection.sponsorship.isUnconfirmed).to.be.true;
62 expect(collection.sponsorship.asUnconfirmed.toHuman()).to.be.eq(evmToAddress(sponsor));
63 });
64
65
45});66});
modifiedtests/src/eth/util/helpers.tsdiffbeforeafterboth
74 return Web3.utils.toChecksumAddress('0x' + buf.toString('hex'));74 return Web3.utils.toChecksumAddress('0x' + buf.toString('hex'));
75}75}
76export function collectionIdFromAddress(address: string): number {76export function collectionIdFromAddress(address: string): number {
77 if (!address.startsWith('0x'))
78 throw 'address not starts with "0x"';
79 if (address.length > 42)
80 throw 'address length is more than 20 bytes';
77 return Number('0x' + address.substring(address.length - 8));81 return Number('0x' + address.substring(address.length - 8));
78}82}
83
84export function normalizeAddress(address: string): string {
85 return '0x' + address.substring(address.length - 40);
86}
7987
80export function tokenIdToAddress(collection: number, token: number): string {88export function tokenIdToAddress(collection: number, token: number): string {
81 const buf = Buffer.from([0xf8, 0x23, 0x8c, 0xcf, 0xff, 0x8e, 0xd8, 0x87, 0x46, 0x3f, 0xd5, 0xe0,89 const buf = Buffer.from([0xf8, 0x23, 0x8c, 0xcf, 0xff, 0x8e, 0xd8, 0x87, 0x46, 0x3f, 0xd5, 0xe0,