--- /dev/null +++ b/examples/.gitignore @@ -0,0 +1 @@ +node_modules \ No newline at end of file --- /dev/null +++ b/examples/package.json @@ -0,0 +1,43 @@ +{ + "name": "SubstraPunks", + "version": "1.0.0", + "description": "Substrate Based Remake of CryptoPunks", + "main": "", + "directories": { + "test": "test" + }, + "devDependencies": { + "got": "^10.7.0" + }, + "scripts": { + "test": "" + }, + "author": "", + "license": "Apache 2.0", + "homepage": "", + "dependencies": { + "bn.js": "^5.1.2", + "body-parser": "^1.18.3", + "express": "^4.17.1", + "express-session": "^1.17.0", + "fs": "^0.0.1-security", + "path": "^0.12.7", + "png-crop": "^0.0.2", + "@polkadot/api": "1.27.1", + "@polkadot/api-contract": "1.27.1", + "@polkadot/extension-dapp": "0.31.1", + "pug": "^2.0.4", + "sprintf-js": "^1.1.2" + }, + "standard": { + "globals": [ + "it", + "assert", + "beforeEach", + "afterEach", + "describe", + "contract", + "artifacts" + ] + } +} --- /dev/null +++ b/examples/re-fungible/collection.txt @@ -0,0 +1,10 @@ +https://conv.darkbyte.ru/ + +Artwork +65 114 116 119 111 114 107 + +Collection of photos +67 111 108 108 101 99 116 105 111 110 32 111 102 32 112 104 111 116 111 115 + +ART +65 82 84 --- /dev/null +++ b/examples/re-fungible/config.js @@ -0,0 +1,19 @@ +// Local +// const config = { +// wsEndpoint : 'ws://127.0.0.1:9944', +// collectionDataSize: 0, +// decimalPoints: 4, + +// ownerSeed : '//Alice', +// }; + +// Production +const config = { + wsEndpoint : 'wss://unique.usetech.com', + collectionDataSize: 0, + decimalPoints: 4, + + ownerSeed : 'tunnel hair company air cage velvet egg crunch height fetch resource estate', +}; + +module.exports = config; \ No newline at end of file --- /dev/null +++ b/examples/re-fungible/create_collection.js @@ -0,0 +1,67 @@ +const { ApiPromise, WsProvider, Keyring } = require('@polkadot/api'); +const config = require('./config'); +const fs = require('fs'); + +function submitTransaction(sender, transaction) { + return new Promise(async function(resolve, reject) { + try { + const unsub = await transaction + .signAndSend(sender, (result) => { + console.log(`Current tx status is ${result.status}`); + + if (result.status.isInBlock) { + console.log(`Transaction included at blockHash ${result.status.asInBlock}`); + resolve(); + unsub(); + } else if (result.status.isFinalized) { + console.log(`Transaction finalized at blockHash ${result.status.asFinalized}`); + resolve(); + unsub(); + } + }); + } + catch (e) { + reject(e.toString()); + } + }); +} + +async function createCollectionAsync(api, alice) { + // Artwork + const name = [65, 114, 116, 119, 111, 114, 107]; + // Collection of photos + const description = [67, 111, 108, 108, 101, 99, 116, 105, 111, 110, 32, 111, 102, 32, 112, 104, 111, 116, 111, 115]; + // ART + const tokenPrefix = [65, 82, 84]; + + // Mode: Re-Fungible + const tx = api.tx.nft.createCollection(name, description, tokenPrefix, {"ReFungible": [config.collectionDataSize, config.decimalPoints]}); + await submitTransaction(alice, tx); + + const tx2 = api.tx.nft.setOffchainSchema(2, "https://ipfs-gateway.usetech.com/ipfs/QmUSv64cUmL2m44QYkUFWmH89qykC8VLPFwjhpeAScjejS/image{id}.jpg"); + await submitTransaction(alice, tx2); +} + +async function main() { + // Initialise the provider to connect to the node + const wsProvider = new WsProvider(config.wsEndpoint); + const rtt = JSON.parse(fs.readFileSync("runtime_types.json")); + + // Create the API and wait until ready + const api = await ApiPromise.create({ + provider: wsProvider, + types: rtt + }); + + // Owners's keypair + const keyring = new Keyring({ type: 'sr25519' }); + const owner = keyring.addFromUri(config.ownerSeed); + console.log("Collection owner address: ", owner.address); + + // Create collection as owner + console.log("=== Create collection ==="); + await createCollectionAsync(api, owner); + +} + +main().catch(console.error).finally(() => process.exit()); --- /dev/null +++ b/examples/re-fungible/ipfs.txt @@ -0,0 +1,4 @@ +https://ipfs-gateway.usetech.com/ipfs/QmUSv64cUmL2m44QYkUFWmH89qykC8VLPFwjhpeAScjejS/image{id}.jpg + +Orchids: +https://ipfs-gateway.usetech.com/ipfs/QmUSv64cUmL2m44QYkUFWmH89qykC8VLPFwjhpeAScjejS/image1.jpg \ No newline at end of file --- /dev/null +++ b/examples/re-fungible/runtime_types.json @@ -0,0 +1,64 @@ +{ + "Schedule": { + "version": "u32", + "put_code_per_byte_cost": "Gas", + "grow_mem_cost": "Gas", + "regular_op_cost": "Gas", + "return_data_per_byte_cost": "Gas", + "event_data_per_byte_cost": "Gas", + "event_per_topic_cost": "Gas", + "event_base_cost": "Gas", + "call_base_cost": "Gas", + "instantiate_base_cost": "Gas", + "dispatch_base_cost": "Gas", + "sandbox_data_read_cost": "Gas", + "sandbox_data_write_cost": "Gas", + "transfer_cost": "Gas", + "instantiate_cost": "Gas", + "max_event_topics": "u32", + "max_stack_height": "u32", + "max_memory_pages": "u32", + "max_table_size": "u32", + "enable_println": "bool", + "max_subject_len": "u32" + }, + "CollectionMode": { + "_enum": { + "Invalid": null, + "NFT": "u32", + "Fungible": "u32", + "ReFungible": "(u32, u32)" + } + }, + "NftItemType": { + "Collection": "u64", + "Owner": "AccountId", + "Data": "Vec" + }, + "Ownership": { + "owner": "AccountId", + "fraction": "u128" + }, + "ReFungibleItemType": { + "Collection": "u64", + "Owner": "Vec>", + "Data": "Vec" + }, + "CollectionType": { + "Owner": "AccountId", + "Mode": "CollectionMode", + "Access": "u8", + "DecimalPoints": "u32", + "Name": "Vec", + "Description": "Vec", + "TokenPrefix": "Vec", + "CustomDataSize": "u32", + "OffchainSchema": "Vec", + "Sponsor": "AccountId", + "UnconfirmedSponsor": "AccountId" + }, + "RawData": "Vec", + "Address": "AccountId", + "LookupSource": "AccountId", + "Weight": "u64" +} \ No newline at end of file --- /dev/null +++ b/examples/testnft/config.js @@ -0,0 +1,19 @@ +// Local +// const config = { +// wsEndpoint : 'ws://127.0.0.1:9944', +// collectionDataSize: 0, +// totalTokens: 10, + +// ownerSeed : '//Alice', +// }; + +// Testnet +const config = { + wsEndpoint : 'wss://unique.usetech.com', + collectionDataSize: 0, + totalTokens: 10, + + ownerSeed : 'tunnel hair company air cage velvet egg crunch height fetch resource estate', +}; + +module.exports = config; \ No newline at end of file --- /dev/null +++ b/examples/testnft/create_collection.js @@ -0,0 +1,69 @@ +const { ApiPromise, WsProvider, Keyring } = require('@polkadot/api'); +const config = require('./config'); +var BigNumber = require('bn.js'); +const fs = require('fs'); + +function submitTransaction(sender, transaction) { + return new Promise(async function(resolve, reject) { + try { + const unsub = await transaction + .signAndSend(sender, (result) => { + console.log(`Current tx status is ${result.status}`); + + if (result.status.isInBlock) { + console.log(`Transaction included at blockHash ${result.status.asInBlock}`); + resolve(); + unsub(); + } else if (result.status.isFinalized) { + console.log(`Transaction finalized at blockHash ${result.status.asFinalized}`); + resolve(); + unsub(); + } + }); + } + catch (e) { + reject(e.toString()); + } + }); +} + +async function createCollectionAsync(api, alice) { + // Test NFT + const name = [0x54, 0x65, 0x73, 0x74, 0x20, 0x4e, 0x46, 0x54]; + // Test NFT Collection + const description = [0x54, 0x65, 0x73, 0x74, 0x20, 0x4e, 0x46, 0x54, 0x20, 0x43, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e]; + // TestNFT + const tokenPrefix = [0x54, 0x65, 0x73, 0x74, 0x4e, 0x46, 0x54]; + + // Mode: NFT + const tx = api.tx.nft.createCollection(name, description, tokenPrefix, {"NFT": config.collectionDataSize}); + await submitTransaction(alice, tx); + + const collectionId = 1; + + const tx2 = api.tx.nft.setOffchainSchema(collectionId, "https://ipfs-gateway.usetech.com/ipfs/QmVdFFZjnq6i3fNDjm6FQe2tfAtUDnqMNkBh8e4sYWUmbH/images/image{id}.png"); + await submitTransaction(alice, tx2); +} + +async function main() { + // Initialise the provider to connect to the node + const wsProvider = new WsProvider(config.wsEndpoint); + const rtt = JSON.parse(fs.readFileSync("runtime_types.json")); + + // Create the API and wait until ready + const api = await ApiPromise.create({ + provider: wsProvider, + types: rtt + }); + + // Owners's keypair + const keyring = new Keyring({ type: 'sr25519' }); + const owner = keyring.addFromUri(config.ownerSeed); + console.log("Collection owner address: ", owner.address); + + // Create collection as owner + console.log("=== Create collection ==="); + await createCollectionAsync(api, owner); +} + +main().catch(console.error).finally(() => process.exit()); --- /dev/null +++ b/examples/testnft/create_tokens.js @@ -0,0 +1,77 @@ +const { ApiPromise, WsProvider, Keyring } = require('@polkadot/api'); +const config = require('./config'); +const fs = require('fs'); + +const collectionId = 1; + +function checkOwner(owner) { + for (let i=0; i<32; i++) { + if (owner[i] != 0) return true; + } + return false; +} + +function mintAsync(api, admin) { + return new Promise(async function(resolve, reject) { + const unsub = await api.tx.nft + .createItem(collectionId, "0x", admin.address) + .signAndSend(admin, (result) => { + console.log(`Current tx status is ${result.status}`); + + if (result.status.isInBlock) { + console.log(`Transaction included at blockHash ${result.status.asInBlock}`); + resolve(); + unsub(); + } else if (result.status.isFinalized) { + console.log(`Transaction finalized at blockHash ${result.status.asFinalized}`); + resolve(); + unsub(); + } + }); + }); +} + +async function main() { + // Initialise the provider to connect to the node + const wsProvider = new WsProvider(config.wsEndpoint); + const rtt = require("./runtime_types.json"); + + // Create the API and wait until ready + const api = await ApiPromise.create({ + provider: wsProvider, + types: rtt + }); + + // Retrieve the chain & node information information via rpc calls + const [chain, nodeName, nodeVersion, collection] = await Promise.all([ + api.rpc.system.chain(), + api.rpc.system.name(), + api.rpc.system.version(), + api.query.nft.collection(collectionId) + ]); + + console.log(`You are connected to chain ${chain} using ${nodeName} v${nodeVersion}`); + console.log(`Collection: ${collection}`); + + if (checkOwner(collection.Owner.toString())) { + // Import account from mnemonic phrase in config file + const keyring = new Keyring({ type: 'sr25519' }); + const owner = keyring.addFromUri(config.ownerSeed); + console.log("Owner address: ", owner.address) + + // Create Tokens + for (let i=0; i process.exit()); --- /dev/null +++ b/examples/testnft/info.txt @@ -0,0 +1,9 @@ +Collection ID: 3 + + +IPFS: +https://ipfs-gateway.usetech.com/ipfs/QmVdFFZjnq6i3fNDjm6FQe2tfAtUDnqMNkBh8e4sYWUmbH/images/image{id}.png + + + +https://conv.darkbyte.ru/ --- /dev/null +++ b/examples/testnft/runtime_types.json @@ -0,0 +1,64 @@ +{ + "Schedule": { + "version": "u32", + "put_code_per_byte_cost": "Gas", + "grow_mem_cost": "Gas", + "regular_op_cost": "Gas", + "return_data_per_byte_cost": "Gas", + "event_data_per_byte_cost": "Gas", + "event_per_topic_cost": "Gas", + "event_base_cost": "Gas", + "call_base_cost": "Gas", + "instantiate_base_cost": "Gas", + "dispatch_base_cost": "Gas", + "sandbox_data_read_cost": "Gas", + "sandbox_data_write_cost": "Gas", + "transfer_cost": "Gas", + "instantiate_cost": "Gas", + "max_event_topics": "u32", + "max_stack_height": "u32", + "max_memory_pages": "u32", + "max_table_size": "u32", + "enable_println": "bool", + "max_subject_len": "u32" + }, + "CollectionMode": { + "_enum": { + "Invalid": null, + "NFT": "u32", + "Fungible": "u32", + "ReFungible": "(u32, u32)" + } + }, + "NftItemType": { + "Collection": "u64", + "Owner": "AccountId", + "Data": "Vec" + }, + "Ownership": { + "owner": "AccountId", + "fraction": "u128" + }, + "ReFungibleItemType": { + "Collection": "u64", + "Owner": "Vec>", + "Data": "Vec" + }, + "CollectionType": { + "Owner": "AccountId", + "Mode": "CollectionMode", + "Access": "u8", + "DecimalPoints": "u32", + "Name": "Vec", + "Description": "Vec", + "TokenPrefix": "Vec", + "CustomDataSize": "u32", + "OffchainSchema": "Vec", + "Sponsor": "AccountId", + "UnconfirmedSponsor": "AccountId" + }, + "RawData": "Vec", + "Address": "AccountId", + "LookupSource": "AccountId", + "Weight": "u64" +} \ No newline at end of file