├── .env.example ├── .gitignore ├── README.md ├── api.js ├── chain └── buy-storage │ └── index.js ├── constants.js ├── index.js ├── nft ├── burn-nft │ └── index.js ├── change-mutable-data │ └── index.js ├── create-collection │ └── index.js ├── create-nft │ └── index.js ├── create-schema │ └── index.js ├── create-template │ └── index.js ├── get-listings │ └── index.js ├── get-marketplace-balances │ └── index.js ├── get-nfts-advanced │ └── index.js ├── get-nfts │ └── index.js ├── get-templates │ └── index.js ├── marketplace-buy │ └── index.js ├── marketplace-sell │ └── index.js ├── marketplace-unlist │ └── index.js ├── register-marketplace │ └── index.js ├── set-collection-data │ └── index.js ├── transfer-nft │ └── index.js └── withdraw-creator-balance │ └── index.js ├── package-lock.json ├── package.json ├── settings.json ├── token ├── create-token │ └── index.js ├── deploy-token │ ├── index.js │ ├── proton.token.abi │ └── proton.token.wasm ├── get-balance │ └── index.js ├── issue-token │ └── index.js └── transfer-token │ └── index.js ├── utils.js └── verification ├── verifyAnyData.ts └── verifyLogin.ts /.env.example: -------------------------------------------------------------------------------- 1 | PRIVATE_KEY=5KBxA5JPsc9bX7bQJd6R1qmrLVEdndHP59izHCAwJajH3LuLCtG -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # compiled output 3 | /dist 4 | /tmp 5 | /out-tsc 6 | 7 | # Runtime data 8 | pids 9 | *.pid 10 | *.seed 11 | *.pid.lock 12 | 13 | # Directory for instrumented libs generated by jscoverage/JSCover 14 | lib-cov 15 | 16 | # Coverage directory used by tools like istanbul 17 | coverage 18 | 19 | # nyc test coverage 20 | .nyc_output 21 | 22 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 23 | .grunt 24 | 25 | # Bower dependency directory (https://bower.io/) 26 | bower_components 27 | 28 | # node-waf configuration 29 | .lock-wscript 30 | 31 | # IDEs and editors 32 | .idea 33 | .project 34 | .classpath 35 | .c9/ 36 | *.launch 37 | .settings/ 38 | *.sublime-workspace 39 | 40 | # IDE - VSCode 41 | .vscode/* 42 | !.vscode/settings.json 43 | !.vscode/tasks.json 44 | !.vscode/launch.json 45 | !.vscode/extensions.json 46 | 47 | # misc 48 | .sass-cache 49 | connect.lock 50 | typings 51 | 52 | # Logs 53 | logs 54 | *.log 55 | npm-debug.log* 56 | yarn-debug.log* 57 | yarn-error.log* 58 | 59 | 60 | # Dependency directories 61 | node_modules/ 62 | jspm_packages/ 63 | 64 | # Optional npm cache directory 65 | .npm 66 | 67 | # Optional eslint cache 68 | .eslintcache 69 | 70 | # Optional REPL history 71 | .node_repl_history 72 | 73 | # Output of 'npm pack' 74 | *.tgz 75 | 76 | # Yarn Integrity file 77 | .yarn-integrity 78 | 79 | # dotenv environment variables file 80 | .env 81 | 82 | # next.js build output 83 | .next 84 | 85 | # Lerna 86 | lerna-debug.log 87 | 88 | # System Files 89 | .DS_Store 90 | Thumbs.db 91 | @jafri 92 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Proton Examples 2 | 3 | Shows the following: 4 | 1. Purchase blockchain storage 5 | 2. Deploying token contract like RANDOM 6 | 3. Create RANDOM 7 | 4. Issue RANDOM 8 | 5. Transfer RANDOM 9 | 6. Get RANDOM balance 10 | 7. Create NFT Collection 11 | 8. Create NFT Schema (data structure) 12 | 9. Create NFT Template 13 | 10. Create NFT 14 | 11. Get NFTs owned 15 | 12. Sell NFT for XPR 16 | 13. Get NFT listings 17 | 14. Buy NFT with XPR 18 | 15. Cancel NFT sale 19 | 16. Transfer NFT 20 | 17. Get Creator fee balances 21 | 18. Withdraw creator fees 22 | 23 | # Installation 24 | 1. Rename .env.example to .env and set your private key 25 | 2. Run `npm i ` 26 | 3. Modify index.js at root to run the functions you want 27 | 4. `node index.js` 28 | 29 | # Example index.js 30 | 31 | ```js 32 | const { buyStorage } = require('./chain/buy-storage') 33 | 34 | const main = async () => { 35 | // Buy Blockchain Storage 36 | // Costs 22 XPR / KB (~6,600 XPR for 300KB) 37 | await buyStorage({ 38 | bytes: 300000 39 | }) 40 | } 41 | 42 | main() 43 | ``` 44 | 45 | # Setup testnet 46 | 1. Go to https://monitor.testnet.protonchain.com/ 47 | 2. Create key pair (save this securely) 48 | 3. Create account with key pair 49 | 4. Faucet for some free testnet XPR! -------------------------------------------------------------------------------- /api.js: -------------------------------------------------------------------------------- 1 | const {JsonRpc, Api, JsSignatureProvider} = require('@proton/js') 2 | const {ENDPOINT} = require('./constants') 3 | const fetch = require('node-fetch') 4 | 5 | const rpc = new JsonRpc([ENDPOINT], { fetch: fetch }) 6 | const api = new Api({ rpc, signatureProvider: new JsSignatureProvider([process.env.PRIVATE_KEY])}) 7 | 8 | module.exports = { 9 | rpc, 10 | api, 11 | transact: (actions) => api.transact({actions}, { 12 | blocksBehind: 300, 13 | expireSeconds: 3000, 14 | }), 15 | fetch 16 | } -------------------------------------------------------------------------------- /chain/buy-storage/index.js: -------------------------------------------------------------------------------- 1 | const { transact } = require('../../api') 2 | const { SYSTEM, ACCOUNT, ACCOUNT_PERMISSION } = require('../../constants') 3 | 4 | const buyStorage = async ({ bytes }) => { 5 | await transact([{ 6 | account: SYSTEM, 7 | name: 'buyrambytes', 8 | data: { 9 | payer: ACCOUNT, 10 | receiver: ACCOUNT, 11 | bytes: bytes 12 | }, 13 | authorization: [{ actor: ACCOUNT, permission: ACCOUNT_PERMISSION }] 14 | }]) 15 | console.log(`${bytes} bytes of Blockchain Storage successfully purchased!`) 16 | } 17 | 18 | module.exports = { 19 | buyStorage 20 | } -------------------------------------------------------------------------------- /constants.js: -------------------------------------------------------------------------------- 1 | const ACCOUNT = process.env.ACCOUNT 2 | const ACCOUNT_PERMISSION = process.env.ACCOUNT_PERMISSION 3 | const CHAIN = process.env.CHAIN 4 | 5 | const ENDPOINT = CHAIN === 'proton' 6 | ? 'https://proton.eoscafeblock.com' 7 | : 'https://testnet.protonchain.com' 8 | 9 | const NFT_API = CHAIN === 'proton' 10 | ? 'https://proton.api.atomicassets.io' 11 | : 'https://test.proton.api.atomicassets.io' 12 | 13 | const SYSTEM = 'eosio' // don't change 14 | const XPR_TOKEN_CONTRACT = 'eosio.token' // don't change 15 | 16 | module.exports = { 17 | ACCOUNT, 18 | ACCOUNT_PERMISSION, 19 | SYSTEM, 20 | XPR_TOKEN_CONTRACT, 21 | CHAIN, 22 | ENDPOINT, 23 | NFT_API 24 | } -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | require('dotenv').config() 2 | 3 | const { buyStorage } = require('./chain/buy-storage') 4 | const { deployToken } = require('./token/deploy-token') 5 | const { createToken } = require('./token/create-token') 6 | const { issueToken } = require('./token/issue-token') 7 | const { transferToken } = require('./token/transfer-token') 8 | const { getBalance } = require('./token/get-balance') 9 | const { createCollection } = require('./nft/create-collection') 10 | const { setCollectionData } = require('./nft/set-collection-data') 11 | const { createSchema } = require('./nft/create-schema') 12 | const { createTemplate } = require('./nft/create-template') 13 | const { burnNft } = require('./nft/burn-nft') 14 | const { getTemplates } = require('./nft/get-templates') 15 | const { getNfts } = require('./nft/get-nfts') 16 | const { getNftsAdvanced } = require('./nft/get-nfts-advanced') 17 | const { getListings } = require('./nft/get-listings') 18 | const { setNftMutableData } = require('./nft/change-mutable-data') 19 | const { createNft } = require('./nft/create-nft') 20 | const { sellNft } = require('./nft/marketplace-sell') 21 | const { buyNft } = require('./nft/marketplace-buy') 22 | const { registerMarketplace } = require('./nft/register-marketplace') 23 | const { cancelNftSale } = require('./nft/marketplace-unlist') 24 | const { transferNft } = require('./nft/transfer-nft') 25 | const { getMarketplaceBalances } = require('./nft/get-marketplace-balances') 26 | const { withdrawCreatorBalance } = require('./nft/withdraw-creator-balance') 27 | const { ACCOUNT } = require('./constants') 28 | 29 | const main = async () => { 30 | /** 31 | * CHAIN 32 | */ 33 | // Buy Blockchain Storage 34 | // Costs 22 XPR / KB (~6,600 XPR for 300KB) 35 | await buyStorage({ 36 | bytes: 300000 37 | }) 38 | 39 | /** 40 | * TOKEN 41 | */ 42 | // Deploy Token 43 | await deployToken() 44 | 45 | // Create token 46 | // Note that the .0000 means precision is 4 for this token 47 | await createToken({ 48 | maximumSupply: '10000.0000 RANDOM' 49 | }) 50 | 51 | // Issue token 52 | await issueToken({ 53 | quantity: '10000.0000 RANDOM' 54 | }) 55 | 56 | // Transfer token 57 | await transferToken({ 58 | tokenContract: ACCOUNT, // Replace with eosio.token for XPR, xtokens for FOOBAR, etc 59 | to: 'syed', 60 | quantity: '1.0000 RANDOM', 61 | memo: '' 62 | }) 63 | 64 | // Get balance 65 | const balance = await getBalance({ 66 | account: 'syed', 67 | tokenContract: ACCOUNT, 68 | tokenSymbol: 'RANDOM' 69 | }) 70 | 71 | /** 72 | * NFT Creation 73 | */ 74 | const COLLECTION_NAME = 'testdeploy' 75 | // 1% from every sale 76 | const CREATOR_FEE = 0.01 77 | const SCHEMA_NAME = 'test' 78 | // uint16 has max value of 65535, use uint32 or uin64 for higher ranges 79 | const SCHEMA = { 80 | image: 'image', 81 | series: 'uint16', 82 | name: 'string', 83 | health: 'uint16', 84 | } 85 | // can only mint this many NFTs in the template (edition size) 86 | const MAX_SUPPLY_TEMPLATE = 100 87 | // This is template-level data that can NOT be modified 88 | // Use https://pinata.cloud/ to upload image and get IPFS hash 89 | const TEMPLATE_DATA = [ 90 | { key: 'image', value: ['string', 'QmPfkthP29F3a4RauRSZnGuMy4QV7bKfS4fvdkUTvGL7Hi'] }, 91 | { key: 'series', value: ['uint16', 1] }, 92 | { key: 'name', value: ['string', 'RandomNFT'] }, 93 | ] 94 | // This is NFT-level specific data that can NOT be modified 95 | const NFT_IMMUTABLE_DATA = [] 96 | // This is NFT-level specific data that can be modified 97 | const NFT_MUTABLE_DATA = [ 98 | { key: 'health', value: ['uint16', 1] }, 99 | ] 100 | 101 | // Create collection 102 | await createCollection({ 103 | collection_name: COLLECTION_NAME, 104 | creator_fee: CREATOR_FEE, 105 | data: [ 106 | {"key": "name", "value": ["string", "Proton Monsters"]}, 107 | {"key": "img", "value": ["ipfs", "QmejwojCLwjbNxqVNwBhyvKj5jUM4kGsm4tGM2U8CbniXy"]}, 108 | {"key": "description", "value": ["string", ""]}, 109 | {"key": "url", "value": ["string", "https://nft.protonchain.com"]}, 110 | ] 111 | }) 112 | 113 | // Change col data 114 | await setCollectionData({ 115 | collection_name: COLLECTION_NAME, 116 | data: [ 117 | {"key": "name", "value": ["string", "Proton Monsters"]}, 118 | {"key": "img", "value": ["ipfs", "QmejwojCLwjbNxqVNwBhyvKj5jUM4kGsm4tGM2U8CbniXy"]}, 119 | {"key": "description", "value": ["string", "Monsters on Proton!"]}, 120 | {"key": "url", "value": ["string", "https://nft.protonchain.com"]}, 121 | ] 122 | }) 123 | 124 | // Create schema 125 | await createSchema({ 126 | collection_name: COLLECTION_NAME, 127 | schema_name: SCHEMA_NAME, 128 | schema: SCHEMA 129 | }) 130 | 131 | // Create template 132 | await createTemplate({ 133 | collection_name: COLLECTION_NAME, 134 | schema_name: SCHEMA_NAME, 135 | max_supply: MAX_SUPPLY_TEMPLATE, 136 | immutable_data: TEMPLATE_DATA 137 | }) 138 | const templates = await getTemplates({ 139 | collection_name: COLLECTION_NAME 140 | }) 141 | 142 | // Create NFT 143 | await createNft({ 144 | collection_name: COLLECTION_NAME, 145 | schema_name: SCHEMA_NAME, 146 | template_id: templates[templates.length - 1].template_id, 147 | immutable_data: NFT_IMMUTABLE_DATA, 148 | mutable_data: NFT_MUTABLE_DATA 149 | }) 150 | 151 | // Get NFTs 152 | const nfts = await getNfts({ 153 | owner: ACCOUNT 154 | }) 155 | const nftsAdvanced = await getNftsAdvanced({ 156 | owner: ACCOUNT, 157 | collection_name: COLLECTION_NAME, 158 | page: 1, 159 | limit: 100 160 | }) 161 | 162 | // Change mutable property 163 | await setNftMutableData({ 164 | asset_owner: ACCOUNT, 165 | asset_id: nfts[0].asset_id, 166 | new_mutable_data: [ 167 | { key: 'health', value: ['uint16', 2] } 168 | ] 169 | }) 170 | 171 | // Burn NFT 172 | await burnNft({ 173 | asset_id: nfts[0].asset_id, 174 | }) 175 | 176 | /** 177 | * NFT Marketplace 178 | */ 179 | // Register marketplace (ONLY IF YOU ARE CREATING YOUR OWN MARKETPLACE WEBSITE) 180 | await registerMarketplace({ 181 | marketplace_name: ACCOUNT 182 | }) 183 | 184 | // Sell NFT 185 | const nft = nfts[0] 186 | await sellNft({ 187 | asset_ids: [nft.asset_id], 188 | listing_price: 1, 189 | settlement_symbol: '4,XPR', // 4 is the precision of XPR 190 | maker_marketplace: 'fees.market' // Only replace with your account if you have registered a marketplace 191 | }) 192 | 193 | // Get Listings 194 | const listings = await getListings({ 195 | seller: ACCOUNT, 196 | collection_name: COLLECTION_NAME 197 | }) 198 | const listing = listings[0] 199 | 200 | // Buy NFT 201 | await buyNft({ 202 | token_contract: listing.price.token_contract, 203 | quantity: `${(+listing.price.amount).toFixed(listing.price.token_precision)} ${listing.price.token_symbol}`, 204 | sale_id: listing.sale_id, 205 | taker_marketplace: 'fees.market' // Only replace with your account if you have registered a marketplace 206 | }) 207 | 208 | // Unlist NFT 209 | await cancelNftSale({ 210 | sale_id: listing.sale_id 211 | }) 212 | 213 | // Transfer NFT 214 | await transferNft({ 215 | to: 'syed', 216 | asset_ids: [nft.asset_id], 217 | memo: '' 218 | }) 219 | 220 | // Balance of creator fees (kept in contract until withdrawn) 221 | const creatorBalances = await getMarketplaceBalances({ 222 | collection_creator: ACCOUNT 223 | }) 224 | 225 | // Withdraw creator fees 226 | await withdrawCreatorBalance({ 227 | collection_creator: ACCOUNT, 228 | token_to_withdraw: '0.0001 XPR' 229 | }) 230 | } 231 | 232 | main() -------------------------------------------------------------------------------- /nft/burn-nft/index.js: -------------------------------------------------------------------------------- 1 | const { transact } = require('../../api') 2 | const { ACCOUNT, ACCOUNT_PERMISSION } = require('../../constants') 3 | 4 | const burnNft = async ({ 5 | asset_id 6 | }) => { 7 | await transact([{ 8 | account: "atomicassets", 9 | name: "burnasset", 10 | data: { 11 | asset_owner: ACCOUNT, 12 | asset_id: asset_id 13 | }, 14 | authorization: [{ actor: ACCOUNT, permission: ACCOUNT_PERMISSION }], 15 | }]) 16 | console.log(`NFT burned!`) 17 | } 18 | 19 | module.exports = { 20 | burnNft 21 | } -------------------------------------------------------------------------------- /nft/change-mutable-data/index.js: -------------------------------------------------------------------------------- 1 | const { transact } = require('../../api') 2 | const { ACCOUNT, ACCOUNT_PERMISSION } = require('../../constants') 3 | 4 | const setNftMutableData = async ({ 5 | asset_owner, 6 | asset_id, 7 | new_mutable_data 8 | }) => { 9 | await transact([{ 10 | account: "atomicassets", 11 | name: "setassetdata", 12 | data: { 13 | authorized_editor: ACCOUNT, 14 | asset_owner: asset_owner, 15 | asset_id: asset_id, 16 | new_mutable_data: new_mutable_data 17 | }, 18 | authorization: [{ actor: ACCOUNT, permission: ACCOUNT_PERMISSION }], 19 | }]) 20 | console.log(`NFT mutable data changed!`) 21 | } 22 | 23 | module.exports = { 24 | setNftMutableData 25 | } -------------------------------------------------------------------------------- /nft/create-collection/index.js: -------------------------------------------------------------------------------- 1 | const { transact } = require('../../api') 2 | const { ACCOUNT, ACCOUNT_PERMISSION } = require('../../constants') 3 | 4 | const createCollection = async ({ 5 | collection_name, 6 | creator_fee, 7 | data 8 | }) => { 9 | await transact([{ 10 | account: "atomicassets", 11 | name: "createcol", 12 | data: { 13 | author: ACCOUNT, 14 | collection_name: collection_name, 15 | allow_notify: true, 16 | authorized_accounts: [ACCOUNT], 17 | notify_accounts: [], 18 | market_fee: creator_fee, 19 | data: data 20 | }, 21 | authorization: [{ actor: ACCOUNT, permission: ACCOUNT_PERMISSION }], 22 | }]) 23 | console.log(`Collection ${collection_name} created!`) 24 | } 25 | 26 | module.exports = { 27 | createCollection 28 | } -------------------------------------------------------------------------------- /nft/create-nft/index.js: -------------------------------------------------------------------------------- 1 | const { transact } = require('../../api') 2 | const { ACCOUNT, ACCOUNT_PERMISSION } = require('../../constants') 3 | 4 | const createNft = async ({ 5 | collection_name, 6 | schema_name, 7 | template_id, 8 | immutable_data, 9 | mutable_data 10 | }) => { 11 | await transact([{ 12 | account: "atomicassets", 13 | name: "mintasset", 14 | data: { 15 | authorized_minter: ACCOUNT, 16 | collection_name: collection_name, 17 | schema_name: schema_name, 18 | template_id: template_id, 19 | new_asset_owner: ACCOUNT, 20 | immutable_data: immutable_data, 21 | mutable_data: mutable_data, 22 | tokens_to_back: [] 23 | }, 24 | authorization: [{ actor: ACCOUNT, permission: ACCOUNT_PERMISSION }], 25 | }]) 26 | console.log(`NFT created!`) 27 | } 28 | 29 | module.exports = { 30 | createNft 31 | } -------------------------------------------------------------------------------- /nft/create-schema/index.js: -------------------------------------------------------------------------------- 1 | const { transact } = require('../../api') 2 | const { ACCOUNT, ACCOUNT_PERMISSION } = require('../../constants') 3 | 4 | const createSchema = async ({ 5 | collection_name, 6 | schema_name, 7 | schema 8 | }) => { 9 | await transact([{ 10 | account: "atomicassets", 11 | name: "createschema", 12 | data: { 13 | authorized_creator: ACCOUNT, 14 | collection_name: collection_name, 15 | schema_name: schema_name, 16 | schema_format: Object.entries(schema).map(([key, type]) => ({ 17 | name: key, 18 | type: type 19 | })) 20 | }, 21 | authorization: [{ actor: ACCOUNT, permission: ACCOUNT_PERMISSION }], 22 | }]) 23 | console.log(`Schema created!`) 24 | } 25 | 26 | module.exports = { 27 | createSchema 28 | } -------------------------------------------------------------------------------- /nft/create-template/index.js: -------------------------------------------------------------------------------- 1 | const { transact } = require('../../api') 2 | const { ACCOUNT, ACCOUNT_PERMISSION } = require('../../constants') 3 | 4 | const createTemplate = async ({ 5 | collection_name, 6 | schema_name, 7 | max_supply, 8 | immutable_data 9 | }) => { 10 | await transact([{ 11 | account: "atomicassets", 12 | name: "createtempl", 13 | data: { 14 | authorized_creator: ACCOUNT, 15 | collection_name: collection_name, 16 | schema_name: schema_name, 17 | transferable: true, 18 | burnable: true, 19 | max_supply: max_supply, 20 | immutable_data: immutable_data 21 | }, 22 | authorization: [{ actor: ACCOUNT, permission: ACCOUNT_PERMISSION }], 23 | }]) 24 | console.log(`Template created!`) 25 | } 26 | 27 | module.exports = { 28 | createTemplate 29 | } -------------------------------------------------------------------------------- /nft/get-listings/index.js: -------------------------------------------------------------------------------- 1 | const { fetch } = require('../../api') 2 | const { NFT_API } = require('../../constants') 3 | 4 | const getListings = async ({ 5 | seller, 6 | collection_name 7 | }) => { 8 | const res = await fetch(`${NFT_API}/atomicmarket/v1/sales?seller=${seller}&collection_name=${collection_name}&state=1&page=1&limit=100&order=desc&sort=created`) 9 | const { data } = await res.json() 10 | return data 11 | } 12 | 13 | module.exports = { 14 | getListings 15 | } -------------------------------------------------------------------------------- /nft/get-marketplace-balances/index.js: -------------------------------------------------------------------------------- 1 | const { rpc } = require('../../api') 2 | 3 | const getMarketplaceBalances = async ({ 4 | collection_creator 5 | }) => { 6 | const { rows } = await rpc.get_table_rows({ 7 | code: 'atomicmarket', 8 | scope: 'atomicmarket', 9 | table: 'balances', 10 | lower_bound: collection_creator, 11 | upper_bound: collection_creator, 12 | limit: 1 13 | }) 14 | 15 | if (rows && rows.length) { 16 | return rows[0].quantities 17 | } else { 18 | return [] 19 | } 20 | } 21 | 22 | module.exports = { 23 | getMarketplaceBalances 24 | } -------------------------------------------------------------------------------- /nft/get-nfts-advanced/index.js: -------------------------------------------------------------------------------- 1 | const { fetch } = require('../../api') 2 | const { NFT_API } = require('../../constants') 3 | 4 | const getNftsAdvanced = async ({ 5 | owner, 6 | collection_name, 7 | page = 1, 8 | limit = 100 9 | }) => { 10 | const url = `${NFT_API}/atomicassets/v1/assets?owner=${owner}&collection_name=${collection_name}&state=1&page=${page}&limit=${limit}&order=desc&sort=created` 11 | const res = await fetch(url) 12 | const { data } = await res.json() 13 | return data 14 | } 15 | 16 | module.exports = { 17 | getNftsAdvanced 18 | } -------------------------------------------------------------------------------- /nft/get-nfts/index.js: -------------------------------------------------------------------------------- 1 | const { rpc } = require('../../api') 2 | const { ACCOUNT } = require('../../constants') 3 | 4 | const getNfts = async ({ 5 | owner 6 | }) => { 7 | const { rows } = await rpc.get_table_rows({ 8 | code: 'atomicassets', 9 | scope: owner, 10 | table: 'assets', 11 | limit: -1 12 | }) 13 | return rows 14 | } 15 | 16 | module.exports = { 17 | getNfts 18 | } -------------------------------------------------------------------------------- /nft/get-templates/index.js: -------------------------------------------------------------------------------- 1 | const { rpc } = require('../../api') 2 | const { ACCOUNT } = require('../../constants') 3 | 4 | const getTemplates = async ({ 5 | collection_name 6 | }) => { 7 | const { rows } = await rpc.get_table_rows({ 8 | code: 'atomicassets', 9 | scope: collection_name, 10 | table: 'templates', 11 | limit: -1 12 | }) 13 | return rows 14 | } 15 | 16 | module.exports = { 17 | getTemplates 18 | } -------------------------------------------------------------------------------- /nft/marketplace-buy/index.js: -------------------------------------------------------------------------------- 1 | const { transact } = require('../../api') 2 | const { ACCOUNT, ACCOUNT_PERMISSION } = require('../../constants') 3 | 4 | const buyNft = async ({ 5 | token_contract, 6 | quantity, 7 | sale_id, 8 | taker_marketplace 9 | }) => { 10 | await transact([ 11 | { 12 | account: token_contract, 13 | name: "transfer", 14 | data: { 15 | from: ACCOUNT, 16 | to: 'atomicmarket', 17 | quantity: quantity, 18 | memo: 'deposit' 19 | }, 20 | authorization: [{ actor: ACCOUNT, permission: ACCOUNT_PERMISSION }], 21 | }, 22 | { 23 | account: "atomicmarket", 24 | name: "purchasesale", 25 | data: { 26 | buyer: ACCOUNT, 27 | sale_id: sale_id, 28 | intended_delphi_median: 0, 29 | taker_marketplace: taker_marketplace 30 | }, 31 | authorization: [{ actor: ACCOUNT, permission: ACCOUNT_PERMISSION }], 32 | } 33 | ]) 34 | console.log(`NFT successfully bought for ${quantity}!`) 35 | } 36 | 37 | module.exports = { 38 | buyNft 39 | } -------------------------------------------------------------------------------- /nft/marketplace-sell/index.js: -------------------------------------------------------------------------------- 1 | const { transact } = require('../../api') 2 | const { ACCOUNT, ACCOUNT_PERMISSION } = require('../../constants') 3 | 4 | const sellNft = async ({ 5 | asset_ids, 6 | listing_price, 7 | settlement_symbol, 8 | maker_marketplace 9 | }) => { 10 | const [precision, symbol] = settlement_symbol.split(',') 11 | 12 | await transact([ 13 | { 14 | account: "atomicmarket", 15 | name: "announcesale", 16 | data: { 17 | seller: ACCOUNT, 18 | asset_ids: asset_ids, 19 | listing_price: `${listing_price.toFixed(precision)} ${symbol}`, 20 | settlement_symbol: settlement_symbol, 21 | maker_marketplace: maker_marketplace 22 | }, 23 | authorization: [{ actor: ACCOUNT, permission: ACCOUNT_PERMISSION }], 24 | }, 25 | { 26 | account: "atomicassets", 27 | name: "createoffer", 28 | data: { 29 | sender: ACCOUNT, 30 | recipient: 'atomicmarket', 31 | sender_asset_ids: asset_ids, 32 | recipient_asset_ids: [], 33 | memo: 'sale' 34 | }, 35 | authorization: [{ actor: ACCOUNT, permission: ACCOUNT_PERMISSION }], 36 | } 37 | ]) 38 | console.log(`NFT successfully listed for ${listing_price} ${symbol}!`) 39 | } 40 | 41 | module.exports = { 42 | sellNft 43 | } -------------------------------------------------------------------------------- /nft/marketplace-unlist/index.js: -------------------------------------------------------------------------------- 1 | const { transact } = require('../../api') 2 | const { ACCOUNT, ACCOUNT_PERMISSION } = require('../../constants') 3 | 4 | const cancelNftSale = async ({ 5 | sale_id 6 | }) => { 7 | await transact([ 8 | { 9 | account: "atomicmarket", 10 | name: "cancelsale", 11 | data: { 12 | sale_id: sale_id 13 | }, 14 | authorization: [{ actor: ACCOUNT, permission: ACCOUNT_PERMISSION }], 15 | } 16 | ]) 17 | console.log(`NFT successfully unlisted!`) 18 | } 19 | 20 | module.exports = { 21 | cancelNftSale 22 | } -------------------------------------------------------------------------------- /nft/register-marketplace/index.js: -------------------------------------------------------------------------------- 1 | const { transact } = require('../../api') 2 | const { ACCOUNT, ACCOUNT_PERMISSION } = require('../../constants') 3 | 4 | const registerMarketplace = async ({ 5 | marketplace_name 6 | }) => { 7 | await transact([ 8 | { 9 | account: "atomicmarket", 10 | name: "regmarket", 11 | data: { 12 | creator: marketplace_name, 13 | marketplace_name: marketplace_name, 14 | }, 15 | authorization: [{ actor: ACCOUNT, permission: ACCOUNT_PERMISSION }], 16 | }, 17 | ]) 18 | console.log(`Registered marketplace ${marketplace_name}!`) 19 | } 20 | 21 | module.exports = { 22 | registerMarketplace 23 | } -------------------------------------------------------------------------------- /nft/set-collection-data/index.js: -------------------------------------------------------------------------------- 1 | const { transact } = require('../../api') 2 | const { ACCOUNT, ACCOUNT_PERMISSION } = require('../../constants') 3 | 4 | const setCollectionData = async ({ 5 | collection_name, 6 | data 7 | }) => { 8 | await transact([{ 9 | account: "atomicassets", 10 | name: "setcoldata", 11 | data: { 12 | collection_name: collection_name, 13 | data: data 14 | }, 15 | authorization: [{ actor: ACCOUNT, permission: ACCOUNT_PERMISSION }], 16 | }]) 17 | console.log(`Collection ${collection_name} data updated!`) 18 | } 19 | 20 | module.exports = { 21 | setCollectionData 22 | } -------------------------------------------------------------------------------- /nft/transfer-nft/index.js: -------------------------------------------------------------------------------- 1 | const { transact } = require('../../api') 2 | const { ACCOUNT, ACCOUNT_PERMISSION } = require('../../constants') 3 | 4 | const transferNft = async ({ 5 | to, 6 | asset_ids, 7 | memo, 8 | }) => { 9 | await transact([ 10 | { 11 | account: "atomicassets", 12 | name: "transfer", 13 | data: { 14 | from: ACCOUNT, 15 | to: to, 16 | asset_ids: asset_ids, 17 | memo: memo 18 | }, 19 | authorization: [{ actor: ACCOUNT, permission: ACCOUNT_PERMISSION }], 20 | } 21 | ]) 22 | console.log(`NFT successfully transfered to ${to}!`) 23 | } 24 | 25 | module.exports = { 26 | transferNft 27 | } -------------------------------------------------------------------------------- /nft/withdraw-creator-balance/index.js: -------------------------------------------------------------------------------- 1 | const { transact } = require('../../api') 2 | 3 | const withdrawCreatorBalance = async ({ 4 | collection_creator, 5 | token_to_withdraw 6 | }) => { 7 | await transact([ 8 | { 9 | account: "atomicmarket", 10 | name: "withdraw", 11 | data: { 12 | owner: collection_creator, 13 | token_to_withdraw: token_to_withdraw 14 | }, 15 | authorization: [{ actor: collection_creator, permission: 'active' }], 16 | } 17 | ]) 18 | console.log(`Successfully withdrew ${token_to_withdraw} to creator (${collection_creator}) account!`) 19 | } 20 | 21 | module.exports = { 22 | withdrawCreatorBalance 23 | } -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "proton-examples", 3 | "version": "1.0.0", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "@proton/js": { 8 | "version": "22.0.45", 9 | "resolved": "https://registry.npmjs.org/@proton/js/-/js-22.0.45.tgz", 10 | "integrity": "sha512-VnH85B49QiicPn7e3WmvAWPxzN83qqiqqa/IAIcFWUq/PUF2ljG6bOMkoG4EhuA5zAgCHmbB7t0X+Armovuavg==", 11 | "requires": { 12 | "bn.js": "5.1.2", 13 | "bs58": "^4.0.1", 14 | "debug": "^4.3.1", 15 | "elliptic": "6.5.3", 16 | "fast-text-encoding": "^1.0.3", 17 | "hash.js": "1.1.7", 18 | "pako": "1.0.11", 19 | "ripemd-ts": "0.0.2" 20 | } 21 | }, 22 | "base-x": { 23 | "version": "3.0.8", 24 | "resolved": "https://registry.npmjs.org/base-x/-/base-x-3.0.8.tgz", 25 | "integrity": "sha512-Rl/1AWP4J/zRrk54hhlxH4drNxPJXYUaKffODVI53/dAsV4t9fBxyxYKAVPU1XBHxYwOWP9h9H0hM2MVw4YfJA==", 26 | "requires": { 27 | "safe-buffer": "^5.0.1" 28 | } 29 | }, 30 | "bn.js": { 31 | "version": "5.1.2", 32 | "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.1.2.tgz", 33 | "integrity": "sha512-40rZaf3bUNKTVYu9sIeeEGOg7g14Yvnj9kH7b50EiwX0Q7A6umbvfI5tvHaOERH0XigqKkfLkFQxzb4e6CIXnA==" 34 | }, 35 | "brorand": { 36 | "version": "1.1.0", 37 | "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", 38 | "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=" 39 | }, 40 | "bs58": { 41 | "version": "4.0.1", 42 | "resolved": "https://registry.npmjs.org/bs58/-/bs58-4.0.1.tgz", 43 | "integrity": "sha1-vhYedsNU9veIrkBx9j806MTwpCo=", 44 | "requires": { 45 | "base-x": "^3.0.2" 46 | } 47 | }, 48 | "debug": { 49 | "version": "4.3.1", 50 | "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", 51 | "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", 52 | "requires": { 53 | "ms": "2.1.2" 54 | } 55 | }, 56 | "dotenv": { 57 | "version": "8.2.0", 58 | "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-8.2.0.tgz", 59 | "integrity": "sha512-8sJ78ElpbDJBHNeBzUbUVLsqKdccaa/BXF1uPTw3GrvQTBgrQrtObr2mUrE38vzYd8cEv+m/JBfDLioYcfXoaw==" 60 | }, 61 | "elliptic": { 62 | "version": "6.5.3", 63 | "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.3.tgz", 64 | "integrity": "sha512-IMqzv5wNQf+E6aHeIqATs0tOLeOTwj1QKbRcS3jBbYkl5oLAserA8yJTT7/VyHUYG91PRmPyeQDObKLPpeS4dw==", 65 | "requires": { 66 | "bn.js": "^4.4.0", 67 | "brorand": "^1.0.1", 68 | "hash.js": "^1.0.0", 69 | "hmac-drbg": "^1.0.0", 70 | "inherits": "^2.0.1", 71 | "minimalistic-assert": "^1.0.0", 72 | "minimalistic-crypto-utils": "^1.0.0" 73 | }, 74 | "dependencies": { 75 | "bn.js": { 76 | "version": "4.12.0", 77 | "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", 78 | "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" 79 | } 80 | } 81 | }, 82 | "fast-text-encoding": { 83 | "version": "1.0.3", 84 | "resolved": "https://registry.npmjs.org/fast-text-encoding/-/fast-text-encoding-1.0.3.tgz", 85 | "integrity": "sha512-dtm4QZH9nZtcDt8qJiOH9fcQd1NAgi+K1O2DbE6GG1PPCK/BWfOH3idCTRQ4ImXRUOyopDEgDEnVEE7Y/2Wrig==" 86 | }, 87 | "hash.js": { 88 | "version": "1.1.7", 89 | "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", 90 | "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", 91 | "requires": { 92 | "inherits": "^2.0.3", 93 | "minimalistic-assert": "^1.0.1" 94 | } 95 | }, 96 | "hmac-drbg": { 97 | "version": "1.0.1", 98 | "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", 99 | "integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=", 100 | "requires": { 101 | "hash.js": "^1.0.3", 102 | "minimalistic-assert": "^1.0.0", 103 | "minimalistic-crypto-utils": "^1.0.1" 104 | } 105 | }, 106 | "inherits": { 107 | "version": "2.0.4", 108 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", 109 | "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" 110 | }, 111 | "minimalistic-assert": { 112 | "version": "1.0.1", 113 | "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", 114 | "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==" 115 | }, 116 | "minimalistic-crypto-utils": { 117 | "version": "1.0.1", 118 | "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", 119 | "integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=" 120 | }, 121 | "ms": { 122 | "version": "2.1.2", 123 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", 124 | "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" 125 | }, 126 | "node-fetch": { 127 | "version": "2.6.1", 128 | "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz", 129 | "integrity": "sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==" 130 | }, 131 | "pako": { 132 | "version": "1.0.11", 133 | "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", 134 | "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==" 135 | }, 136 | "ripemd-ts": { 137 | "version": "0.0.2", 138 | "resolved": "https://registry.npmjs.org/ripemd-ts/-/ripemd-ts-0.0.2.tgz", 139 | "integrity": "sha512-2XZ9cVFtjpQ3z6LmN+Kylz518XcPKmKHzxEXUEPJfqi8vZs+0reY65YU9wzhzrPGtqHzH3ARGZNnGNASlPaWfw==" 140 | }, 141 | "safe-buffer": { 142 | "version": "5.2.1", 143 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", 144 | "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" 145 | } 146 | } 147 | } 148 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "proton-examples", 3 | "version": "1.0.0", 4 | "description": "Modify .env with your private key and constants.js with your account name, etc", 5 | "main": "index.js", 6 | "dependencies": { 7 | "@proton/js": "^22.0.45", 8 | "dotenv": "^8.2.0", 9 | "node-fetch": "^2.6.1" 10 | }, 11 | "devDependencies": {}, 12 | "scripts": { 13 | "test": "echo \"Error: no test specified\" && exit 1" 14 | }, 15 | "repository": { 16 | "type": "git", 17 | "url": "git+https://github.com/ProtonProtocol/proton-examples.git" 18 | }, 19 | "author": "Syed Jafri", 20 | "license": "ISC", 21 | "bugs": { 22 | "url": "https://github.com/ProtonProtocol/proton-examples/issues" 23 | }, 24 | "homepage": "https://github.com/ProtonProtocol/proton-examples#readme" 25 | } 26 | -------------------------------------------------------------------------------- /settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "currentNetwork": { 3 | "chain": "proton-test", 4 | "endpoints": [ 5 | "https://protontestnet.greymass.com" 6 | ] 7 | } 8 | } -------------------------------------------------------------------------------- /token/create-token/index.js: -------------------------------------------------------------------------------- 1 | const { transact } = require('../../api') 2 | const { ACCOUNT, ACCOUNT_PERMISSION } = require('../../constants') 3 | 4 | const createToken = async ({ maximumSupply }) => { 5 | await transact([{ 6 | account: ACCOUNT, 7 | name: 'create', 8 | data: { 9 | issuer: ACCOUNT, 10 | maximum_supply: maximumSupply 11 | }, 12 | authorization: [{ actor: ACCOUNT, permission: ACCOUNT_PERMISSION }] 13 | }]) 14 | console.log(`Token successfully created with max supply ${maximumSupply}!`) 15 | } 16 | 17 | module.exports = { 18 | createToken 19 | } -------------------------------------------------------------------------------- /token/deploy-token/index.js: -------------------------------------------------------------------------------- 1 | const { readFileSync } = require('fs') 2 | const { Serialize } = require('@proton/js') 3 | const { api, transact } = require('../../api') 4 | const { getDeployableFilesFromDir } = require('../../utils') 5 | const { ACCOUNT, ACCOUNT_PERMISSION } = require('../../constants') 6 | 7 | const deployToken = async () => { 8 | const {wasmPath, abiPath} = getDeployableFilesFromDir(__dirname) 9 | 10 | // 1. Prepare SETCODE 11 | // read the file and make a hex string out of it 12 | const wasm = readFileSync(wasmPath).toString('hex') 13 | 14 | // 2. Prepare SETABI 15 | const abiBuffer = new Serialize.SerialBuffer() 16 | const abiDefinition = api.abiTypes.get('abi_def') 17 | abiDefinition.serialize( 18 | abiBuffer, 19 | abiDefinition.fields.reduce( 20 | (acc, {name: fieldName}) => { 21 | return Object.assign(acc, { 22 | [fieldName]: acc[fieldName] || [], 23 | }) 24 | }, JSON.parse(readFileSync(abiPath, 'utf8')) 25 | ) 26 | ) 27 | 28 | // 3. Set code 29 | try { 30 | await transact([{ 31 | account: 'eosio', 32 | name: 'setcode', 33 | data: { 34 | account: ACCOUNT, 35 | vmtype: 0, 36 | vmversion: 0, 37 | code: wasm, 38 | }, 39 | authorization: [{ 40 | actor: ACCOUNT, 41 | permission: ACCOUNT_PERMISSION, 42 | }], 43 | }]) 44 | console.log(`WASM successfully deployed!`) 45 | } catch (error) { 46 | console.log('Set WASM failed', error) 47 | } 48 | 49 | // 4. Set ABI 50 | try { 51 | await transact([{ 52 | account: 'eosio', 53 | name: 'setabi', 54 | data: { 55 | account: ACCOUNT, 56 | abi: Buffer.from(abiBuffer.asUint8Array()).toString('hex'), 57 | }, 58 | authorization: [{ 59 | actor: ACCOUNT, 60 | permission: ACCOUNT_PERMISSION, 61 | }], 62 | }]) 63 | console.log(`ABI successfully deployed!`) 64 | } catch (error) { 65 | console.log('Set abi failed', error) 66 | } 67 | } 68 | 69 | module.exports = { 70 | deployToken 71 | } -------------------------------------------------------------------------------- /token/deploy-token/proton.token.abi: -------------------------------------------------------------------------------- 1 | { 2 | "____comment": "This file was generated with eosio-abigen. DO NOT EDIT ", 3 | "version": "eosio::abi/1.1", 4 | "types": [], 5 | "structs": [ 6 | { 7 | "name": "account", 8 | "base": "", 9 | "fields": [ 10 | { 11 | "name": "balance", 12 | "type": "asset" 13 | } 14 | ] 15 | }, 16 | { 17 | "name": "close", 18 | "base": "", 19 | "fields": [ 20 | { 21 | "name": "owner", 22 | "type": "name" 23 | }, 24 | { 25 | "name": "symbol", 26 | "type": "symbol" 27 | } 28 | ] 29 | }, 30 | { 31 | "name": "create", 32 | "base": "", 33 | "fields": [ 34 | { 35 | "name": "issuer", 36 | "type": "name" 37 | }, 38 | { 39 | "name": "maximum_supply", 40 | "type": "asset" 41 | } 42 | ] 43 | }, 44 | { 45 | "name": "currency_stats", 46 | "base": "", 47 | "fields": [ 48 | { 49 | "name": "supply", 50 | "type": "asset" 51 | }, 52 | { 53 | "name": "max_supply", 54 | "type": "asset" 55 | }, 56 | { 57 | "name": "issuer", 58 | "type": "name" 59 | } 60 | ] 61 | }, 62 | { 63 | "name": "issue", 64 | "base": "", 65 | "fields": [ 66 | { 67 | "name": "to", 68 | "type": "name" 69 | }, 70 | { 71 | "name": "quantity", 72 | "type": "asset" 73 | }, 74 | { 75 | "name": "memo", 76 | "type": "string" 77 | } 78 | ] 79 | }, 80 | { 81 | "name": "open", 82 | "base": "", 83 | "fields": [ 84 | { 85 | "name": "owner", 86 | "type": "name" 87 | }, 88 | { 89 | "name": "symbol", 90 | "type": "symbol" 91 | }, 92 | { 93 | "name": "ram_payer", 94 | "type": "name" 95 | } 96 | ] 97 | }, 98 | { 99 | "name": "retire", 100 | "base": "", 101 | "fields": [ 102 | { 103 | "name": "quantity", 104 | "type": "asset" 105 | }, 106 | { 107 | "name": "memo", 108 | "type": "string" 109 | } 110 | ] 111 | }, 112 | { 113 | "name": "transfer", 114 | "base": "", 115 | "fields": [ 116 | { 117 | "name": "from", 118 | "type": "name" 119 | }, 120 | { 121 | "name": "to", 122 | "type": "name" 123 | }, 124 | { 125 | "name": "quantity", 126 | "type": "asset" 127 | }, 128 | { 129 | "name": "memo", 130 | "type": "string" 131 | } 132 | ] 133 | } 134 | ], 135 | "actions": [ 136 | { 137 | "name": "close", 138 | "type": "close", 139 | "ricardian_contract": "---\nspec_version: \"0.2.0\"\ntitle: Close Token Balance\nsummary: 'Close {{nowrap owner}}’s zero quantity balance'\nicon: https://raw.githubusercontent.com/EOSIO/eosio.contracts/master/contracts/icons/token.png#207ff68b0406eaa56618b08bda81d6a0954543f36adc328ab3065f31a5c5d654\n---\n\n{{owner}} agrees to close their zero quantity balance for the {{symbol_to_symbol_code symbol}} token.\n\nRAM will be refunded to the RAM payer of the {{symbol_to_symbol_code symbol}} token balance for {{owner}}." 140 | }, 141 | { 142 | "name": "create", 143 | "type": "create", 144 | "ricardian_contract": "---\nspec_version: \"0.2.0\"\ntitle: Create New Token\nsummary: 'Create a new token'\nicon: https://raw.githubusercontent.com/EOSIO/eosio.contracts/master/contracts/icons/token.png#207ff68b0406eaa56618b08bda81d6a0954543f36adc328ab3065f31a5c5d654\n---\n\n{{$action.account}} agrees to create a new token with symbol {{asset_to_symbol_code maximum_supply}} to be managed by {{issuer}}.\n\nThis action will not result any any tokens being issued into circulation.\n\n{{issuer}} will be allowed to issue tokens into circulation, up to a maximum supply of {{maximum_supply}}.\n\nRAM will deducted from {{$action.account}}’s resources to create the necessary records." 145 | }, 146 | { 147 | "name": "issue", 148 | "type": "issue", 149 | "ricardian_contract": "---\nspec_version: \"0.2.0\"\ntitle: Issue Tokens into Circulation\nsummary: 'Issue {{nowrap quantity}} into circulation and transfer into {{nowrap to}}’s account'\nicon: https://raw.githubusercontent.com/EOSIO/eosio.contracts/master/contracts/icons/token.png#207ff68b0406eaa56618b08bda81d6a0954543f36adc328ab3065f31a5c5d654\n---\n\nThe token manager agrees to issue {{quantity}} into circulation, and transfer it into {{to}}’s account.\n\n{{#if memo}}There is a memo attached to the transfer stating:\n{{memo}}\n{{/if}}\n\nIf {{to}} does not have a balance for {{asset_to_symbol_code quantity}}, or the token manager does not have a balance for {{asset_to_symbol_code quantity}}, the token manager will be designated as the RAM payer of the {{asset_to_symbol_code quantity}} token balance for {{to}}. As a result, RAM will be deducted from the token manager’s resources to create the necessary records.\n\nThis action does not allow the total quantity to exceed the max allowed supply of the token." 150 | }, 151 | { 152 | "name": "open", 153 | "type": "open", 154 | "ricardian_contract": "---\nspec_version: \"0.2.0\"\ntitle: Open Token Balance\nsummary: 'Open a zero quantity balance for {{nowrap owner}}'\nicon: https://raw.githubusercontent.com/EOSIO/eosio.contracts/master/contracts/icons/token.png#207ff68b0406eaa56618b08bda81d6a0954543f36adc328ab3065f31a5c5d654\n---\n\n{{ram_payer}} agrees to establish a zero quantity balance for {{owner}} for the {{symbol_to_symbol_code symbol}} token.\n\nIf {{owner}} does not have a balance for {{symbol_to_symbol_code symbol}}, {{ram_payer}} will be designated as the RAM payer of the {{symbol_to_symbol_code symbol}} token balance for {{owner}}. As a result, RAM will be deducted from {{ram_payer}}’s resources to create the necessary records." 155 | }, 156 | { 157 | "name": "retire", 158 | "type": "retire", 159 | "ricardian_contract": "---\nspec_version: \"0.2.0\"\ntitle: Remove Tokens from Circulation\nsummary: 'Remove {{nowrap quantity}} from circulation'\nicon: https://raw.githubusercontent.com/EOSIO/eosio.contracts/master/contracts/icons/token.png#207ff68b0406eaa56618b08bda81d6a0954543f36adc328ab3065f31a5c5d654\n---\n\nThe token manager agrees to remove {{quantity}} from circulation, taken from their own account.\n\n{{#if memo}} There is a memo attached to the action stating:\n{{memo}}\n{{/if}}" 160 | }, 161 | { 162 | "name": "transfer", 163 | "type": "transfer", 164 | "ricardian_contract": "---\nspec_version: \"0.2.0\"\ntitle: Transfer Tokens\nsummary: 'Send {{nowrap quantity}} from {{nowrap from}} to {{nowrap to}}'\nicon: https://raw.githubusercontent.com/EOSIO/eosio.contracts/master/contracts/icons/transfer.png#5dfad0df72772ee1ccc155e670c1d124f5c5122f1d5027565df38b418042d1dd\n---\n\n{{from}} agrees to send {{quantity}} to {{to}}.\n\n{{#if memo}}There is a memo attached to the transfer stating:\n{{memo}}\n{{/if}}\n\nIf {{from}} is not already the RAM payer of their {{asset_to_symbol_code quantity}} token balance, {{from}} will be designated as such. As a result, RAM will be deducted from {{from}}’s resources to refund the original RAM payer.\n\nIf {{to}} does not have a balance for {{asset_to_symbol_code quantity}}, {{from}} will be designated as the RAM payer of the {{asset_to_symbol_code quantity}} token balance for {{to}}. As a result, RAM will be deducted from {{from}}’s resources to create the necessary records." 165 | } 166 | ], 167 | "tables": [ 168 | { 169 | "name": "accounts", 170 | "type": "account", 171 | "index_type": "i64", 172 | "key_names": [], 173 | "key_types": [] 174 | }, 175 | { 176 | "name": "stat", 177 | "type": "currency_stats", 178 | "index_type": "i64", 179 | "key_names": [], 180 | "key_types": [] 181 | } 182 | ], 183 | "ricardian_clauses": [], 184 | "variants": [] 185 | } -------------------------------------------------------------------------------- /token/deploy-token/proton.token.wasm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XPRNetwork/xpr-backend-examples/40f506ea5b64d1b3768940e04a25c59768d8eddd/token/deploy-token/proton.token.wasm -------------------------------------------------------------------------------- /token/get-balance/index.js: -------------------------------------------------------------------------------- 1 | const { rpc } = require('../../api') 2 | 3 | const getBalance = async ({ 4 | account, 5 | tokenContract, 6 | tokenSymbol 7 | }) => { 8 | const [balance] = await rpc.get_currency_balance(tokenContract, account, tokenSymbol) 9 | 10 | if (balance) { 11 | return Number(balance.split(' ')[0]) 12 | } else { 13 | return 0 14 | } 15 | } 16 | 17 | module.exports = { 18 | getBalance 19 | } -------------------------------------------------------------------------------- /token/issue-token/index.js: -------------------------------------------------------------------------------- 1 | const { transact } = require('../../api') 2 | const { ACCOUNT, ACCOUNT_PERMISSION } = require('../../constants') 3 | 4 | const issueToken = async ({ quantity }) => { 5 | await transact([{ 6 | account: ACCOUNT, 7 | name: 'issue', 8 | data: { 9 | to: ACCOUNT, 10 | quantity: quantity, 11 | memo: '' 12 | }, 13 | authorization: [{ actor: ACCOUNT, permission: ACCOUNT_PERMISSION }] 14 | }]) 15 | 16 | console.log(`${quantity} successfully issued to ${ACCOUNT}`) 17 | } 18 | 19 | module.exports = { 20 | issueToken 21 | } -------------------------------------------------------------------------------- /token/transfer-token/index.js: -------------------------------------------------------------------------------- 1 | const { transact } = require('../../api') 2 | const { ACCOUNT, ACCOUNT_PERMISSION } = require('../../constants') 3 | 4 | const transferToken = async ({ tokenContract, to, quantity, memo }) => { 5 | await transact([{ 6 | account: tokenContract, 7 | name: 'transfer', 8 | data: { 9 | from: ACCOUNT, 10 | to, 11 | quantity, 12 | memo 13 | }, 14 | authorization: [{ actor: ACCOUNT, permission: ACCOUNT_PERMISSION }] 15 | }]) 16 | console.log(`${quantity} successfully transferred from ${ACCOUNT} to ${to}`) 17 | } 18 | 19 | module.exports = { 20 | transferToken 21 | } -------------------------------------------------------------------------------- /utils.js: -------------------------------------------------------------------------------- 1 | const { readdirSync } = require('fs') 2 | const { join } = require('path') 3 | 4 | const getDeployableFilesFromDir = (dir) => { 5 | const dirCont = readdirSync(dir) 6 | const wasmFileName = dirCont.find(filePath => filePath.match(/.*\.(wasm)$/gi)) 7 | const abiFileName = dirCont.find(filePath => filePath.match(/.*\.(abi)$/gi)) 8 | if (!wasmFileName) throw new Error(`Cannot find a ".wasm file" in ${dir}`) 9 | if (!abiFileName) throw new Error(`Cannot find an ".abi file" in ${dir}`) 10 | return { 11 | wasmPath: join(dir, wasmFileName), 12 | abiPath: join(dir, abiFileName), 13 | } 14 | } 15 | 16 | const wait = async (ms) => { 17 | return new Promise(resolve => { 18 | setTimeout(resolve, ms); 19 | }); 20 | } 21 | 22 | module.exports = { 23 | wait, 24 | getDeployableFilesFromDir 25 | } -------------------------------------------------------------------------------- /verification/verifyAnyData.ts: -------------------------------------------------------------------------------- 1 | const { JsonRpc, Api, JsSignatureProvider, Serialize } = require('@proton/js'); 2 | const { Crypto } = require('@peculiar/webcrypto'); 3 | const { createAbstractAuthParser } = require('@proton/wrap-constants'); 4 | const { recoverPersonalSignature } = require('eth-sig-util'); 5 | const z = require('zod'); 6 | 7 | const CONTRACT = 'kyc'; 8 | const ACTION = 'kyc'; 9 | 10 | const rpc = new JsonRpc(['https://proton.greymass.com']); 11 | const api = new Api({ 12 | rpc, 13 | crypto: new Crypto(), 14 | recoverPersonalSignature, 15 | signatureProvider: new JsSignatureProvider([ 16 | 'PVT_K1_2uRJiRffJUz4McQMXndqri6UV14uy6gMW8QKMEiLjDpFjEvVH1', 17 | ]), 18 | }); 19 | 20 | const mockFrontend = async () => { 21 | const ACCOUNT_NAME = 'testacc44'; 22 | const ACCOUNT_PERMISSION = 'active'; 23 | 24 | const result = await api.transact( 25 | { 26 | actions: [ 27 | { 28 | account: CONTRACT, 29 | name: ACTION, 30 | data: { 31 | data: 'randooom', 32 | }, 33 | authorization: [ 34 | { 35 | actor: ACCOUNT_NAME, 36 | permission: ACCOUNT_PERMISSION, 37 | }, 38 | ], 39 | }, 40 | ], 41 | }, 42 | { 43 | broadcast: false, 44 | useLastIrreversible: true, 45 | expireSeconds: 30, 46 | } 47 | ); 48 | 49 | const resolvedTransaction = { 50 | ...Serialize.createBaseResolvedTransaction(), 51 | ...result.transactionHeader, 52 | }; 53 | 54 | return { 55 | signer: { 56 | actor: ACCOUNT_NAME, 57 | permission: ACCOUNT_PERMISSION, 58 | }, 59 | signatures: result.signatures, 60 | transaction: resolvedTransaction, 61 | }; 62 | }; 63 | 64 | const backend = async () => { 65 | const rawData = await mockFrontend(); 66 | 67 | const kycDataParser = createAbstractAuthParser(CONTRACT, ACTION, { 68 | data: z.string(), 69 | }); 70 | 71 | // Can throw error 72 | const data = kycDataParser.parse(rawData); 73 | 74 | const isVerified = await api.checkIfKeysMatchTransaction({ 75 | actor: data.signer.actor, 76 | permission: data.signer.permission, 77 | transaction: data.transaction, 78 | signatures: data.signatures, 79 | }); 80 | 81 | // Action of interest 82 | const action = data.transaction.actions[0].data['trx'] 83 | ? ( 84 | await api.deserializeActions( 85 | data.transaction.actions[0].data['trx'].actions 86 | ) 87 | )[0] 88 | : data.transaction.actions[0]; 89 | 90 | console.log('action:', { 91 | signer: data.signer, 92 | isVerified: isVerified, 93 | ...action, 94 | }); 95 | }; 96 | 97 | backend(); -------------------------------------------------------------------------------- /verification/verifyLogin.ts: -------------------------------------------------------------------------------- 1 | const { JsonRpc, Api, JsSignatureProvider, Serialize } = require('@proton/js'); 2 | const { Crypto } = require('@peculiar/webcrypto'); 3 | const { generateAuthParser } = require('@proton/wrap-constants'); 4 | const { recoverPersonalSignature } = require('eth-sig-util'); 5 | 6 | const rpc = new JsonRpc(['https://proton.greymass.com']); 7 | const api = new Api({ 8 | rpc, 9 | crypto: new Crypto(), 10 | recoverPersonalSignature, 11 | signatureProvider: new JsSignatureProvider([ 12 | 'PVT_K1_2uRJiRffJUz4McQMXndqri6UV14uy6gMW8QKMEiLjDpFjEvVH1', 13 | ]), 14 | }); 15 | 16 | const mockFrontend = async () => { 17 | const ACCOUNT_NAME = 'testacc44'; 18 | const ACCOUNT_PERMISSION = 'active'; 19 | const CONTRACT = 'proton.wrap'; 20 | const ACTION = 'generateauth'; 21 | 22 | const result = await api.transact( 23 | { 24 | actions: [ 25 | { 26 | account: CONTRACT, 27 | name: ACTION, 28 | data: { 29 | time: new Date().toISOString().slice(0, -1), 30 | protonAccount: ACCOUNT_NAME, 31 | }, 32 | authorization: [ 33 | { 34 | actor: ACCOUNT_NAME, 35 | permission: ACCOUNT_PERMISSION, 36 | }, 37 | ], 38 | }, 39 | ], 40 | }, 41 | { 42 | broadcast: false, 43 | useLastIrreversible: true, 44 | expireSeconds: 30, 45 | } 46 | ); 47 | 48 | const resolvedTransaction = { 49 | ...Serialize.createBaseResolvedTransaction(), 50 | ...result.transactionHeader, 51 | }; 52 | 53 | return { 54 | signer: { 55 | actor: ACCOUNT_NAME, 56 | permission: ACCOUNT_PERMISSION, 57 | }, 58 | transaction: resolvedTransaction, 59 | signatures: result.signatures, 60 | }; 61 | }; 62 | 63 | const backend = async () => { 64 | const rawData = await mockFrontend(); 65 | 66 | // Can throw error 67 | const data = generateAuthParser.parse(rawData); 68 | 69 | const isVerified = await api.checkIfKeysMatchTransaction({ 70 | actor: data.signer.actor, 71 | permission: data.signer.permission, 72 | transaction: data.transaction, 73 | signatures: data.signatures, 74 | }); 75 | 76 | // Action of interest 77 | const action = data.transaction.actions[0].data['trx'] 78 | ? ( 79 | await api.deserializeActions( 80 | data.transaction.actions[0].data['trx'].actions 81 | ) 82 | )[0] 83 | : data.transaction.actions[0]; 84 | 85 | console.log('action:', { 86 | signer: data.signer, 87 | isVerified: isVerified, 88 | ...action, 89 | }); 90 | }; 91 | 92 | backend(); --------------------------------------------------------------------------------