├── .env.cep47.example ├── .github └── workflows │ ├── build-casper-contracts-js-clients.yml │ └── publish-casper-contracts-js-clients.yml ├── .gitignore ├── README.md ├── e2e ├── cep47 │ ├── install.ts │ └── usage.ts └── utils.ts ├── lerna.json ├── package-lock.json ├── package.json ├── packages └── cep47-client │ ├── README.md │ ├── package-lock.json │ ├── package.json │ ├── src │ └── index.ts │ ├── tsconfig.build.json │ └── tsconfig.json └── tsconfig.build.json /.env.cep47.example: -------------------------------------------------------------------------------- 1 | WASM_PATH=/your-path/casper-nft-cep47/target/wasm32-unknown-unknown/release/cep47-token.wasm 2 | 3 | CHAIN_NAME=casper-net-1 4 | NODE_ADDRESS=http://localhost:11101/rpc 5 | EVENT_STREAM_ADDRESS=http://localhost:18101/events/main 6 | MASTER_KEY_PAIR_PATH=/your-path/casper-node/utils/nctl/assets/net-1/faucet 7 | USER_KEY_PAIR_PATH=/your-path/casper-node/utils/nctl/assets/net-1/users/user-1 8 | 9 | TOKEN_NAME=my_token 10 | CONTRACT_NAME=my_contract 11 | TOKEN_SYMBOL=MY 12 | TOKEN_META=1 one,2 two 13 | INSTALL_PAYMENT_AMOUNT=115000000000 14 | 15 | MINT_ONE_PAYMENT_AMOUNT=2000000000 16 | MINT_COPIES_PAYMENT_AMOUNT=100000000000 17 | BURN_ONE_PAYMENT_AMOUNT=12000000000 18 | MINT_ONE_META_SIZE=1 19 | MINT_COPIES_META_SIZE=10 20 | MINT_COPIES_COUNT=20 21 | MINT_MANY_META_SIZE=5 22 | MINT_MANY_META_COUNT=5 23 | TRANSFER_ONE_PAYMENT_AMOUNT=2000000000 24 | -------------------------------------------------------------------------------- /.github/workflows/build-casper-contracts-js-clients.yml: -------------------------------------------------------------------------------- 1 | # This workflow will do a clean install of node dependencies, build the source code and run tests across different versions of node 2 | # For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions 3 | 4 | name: build-casper-contracts-js-clients 5 | 6 | on: 7 | pull_request: 8 | branches: [ master ] 9 | paths-ignore: 10 | - '**.md' 11 | 12 | jobs: 13 | build: 14 | runs-on: ubuntu-22.04 15 | strategy: 16 | matrix: 17 | # See supported Node.js release schedule at https://nodejs.org/en/about/releases/ 18 | node-version: [18.x] 19 | 20 | steps: 21 | - name: Checkout 🛎️ 22 | uses: actions/checkout@v2 23 | - name: Use Node.js ${{ matrix.node-version }} 24 | uses: actions/setup-node@v2 25 | with: 26 | node-version: ${{ matrix.node-version }} 27 | - name: Install Build & Test 🔧 28 | run: | 29 | npm install 30 | npm test 31 | npm run dist 32 | -------------------------------------------------------------------------------- /.github/workflows/publish-casper-contracts-js-clients.yml: -------------------------------------------------------------------------------- 1 | name: publish-casper-contracts-js-clients 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | paths-ignore: 7 | - '**.md' 8 | 9 | jobs: 10 | publish: 11 | runs-on: ubuntu-22.04 12 | 13 | strategy: 14 | matrix: 15 | # See supported Node.js release schedule at https://nodejs.org/en/about/releases/ 16 | node-version: [18.x] 17 | 18 | steps: 19 | - uses: actions/checkout@v2 20 | with: 21 | fetch-depth: 0 22 | ref: master 23 | - name: Use Node.js ${{ matrix.node-version }} 24 | uses: actions/setup-node@v2 25 | with: 26 | node-version: ${{ matrix.node-version }} 27 | - run: git fetch --tags 28 | - run: echo //registry.npmjs.org/:_authToken=${NPM_TOKEN} > .npmrc 29 | env: 30 | NPM_TOKEN: ${{ secrets.NPM_TOKEN }} 31 | - run: npm install 32 | - run: npm run dist 33 | - run: npm run publish:ci 34 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | DS_Store 2 | node_modules/ 3 | dist/ 4 | .env.cep47 5 | .env.erc20 6 | .npmrc 7 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # casper-contracts-js-clients 2 | 3 | This project contains a library that will help you create clients for Casper contracts and a few implementations of such clients dedicated to interacting with smart contracts on Casper. You will find these clients published in `npm`: 4 | 5 | - A [Casper CEP-47 (NFT)](https://github.com/casper-ecosystem/casper-nft-cep47) client in JavaScript: [casper-cep47-js-client](https://www.npmjs.com/package/casper-cep47-js-client) 6 | 7 | > Looking for CEP-18(ERC20) client? Please check [here](https://github.com/casper-ecosystem/cep18/tree/master/client-js) 8 | 9 | ## Usage examples 10 | 11 | In this project, you will find end-to-end (e2e) tests, which you can also use as examples of interacting and using the contracts. The tests are well documented and can give you an overview of all contract functionality. 12 | 13 | Before running an e2e test, run `npm i' inside the project's root directory: 14 | 15 | ``` 16 | cd packages/cep47-js-client 17 | npm i 18 | npm run bootstrap 19 | npm run dist 20 | ``` 21 | 22 | ### CEP-47 client usage 23 | 24 | Before running this example client, you must specify all the environment variables in the `.env.cep47` file. If you need help, reference the `.env.cep47.example` file. 25 | 26 | **Steps:** 27 | 28 | - Open the [CEP-47 client example](packages/cep47-client) 29 | - Set the environment variables in the `.env.cep47` file 30 | - Run the [install script](e2e/cep47/install.ts) 31 | - View the [client usage example](e2e/cep47/usage.ts) 32 | - Install the contract: 33 | 34 | ``` 35 | npm run e2e:cep47:install 36 | ``` 37 | 38 | - Run the test example: 39 | 40 | ``` 41 | npm run e2e:cep47:usage 42 | ``` 43 | -------------------------------------------------------------------------------- /e2e/cep47/install.ts: -------------------------------------------------------------------------------- 1 | import { config } from "dotenv"; 2 | config({ path: ".env.cep47" }); 3 | import { CEP47Client } from "casper-cep47-js-client"; 4 | import { parseTokenMeta, sleep, getDeploy, getAccountInfo, getAccountNamedKeyValue } from "../utils"; 5 | import * as fs from "fs"; 6 | 7 | import { 8 | CLValueBuilder, 9 | Keys, 10 | CLPublicKey, 11 | CLPublicKeyType, 12 | } from "casper-js-sdk"; 13 | 14 | const { 15 | NODE_ADDRESS, 16 | EVENT_STREAM_ADDRESS, 17 | CHAIN_NAME, 18 | WASM_PATH, 19 | MASTER_KEY_PAIR_PATH, 20 | TOKEN_NAME, 21 | CONTRACT_NAME, 22 | TOKEN_SYMBOL, 23 | CONTRACT_HASH, 24 | INSTALL_PAYMENT_AMOUNT, 25 | MINT_ONE_PAYMENT_AMOUNT, 26 | MINT_COPIES_PAYMENT_AMOUNT, 27 | BURN_ONE_PAYMENT_AMOUNT, 28 | MINT_ONE_META_SIZE, 29 | MINT_COPIES_META_SIZE, 30 | MINT_COPIES_COUNT, 31 | MINT_MANY_META_SIZE, 32 | MINT_MANY_META_COUNT, 33 | } = process.env; 34 | 35 | export const getBinary = (pathToBinary: string) => { 36 | return new Uint8Array(fs.readFileSync(pathToBinary, null).buffer); 37 | }; 38 | 39 | const TOKEN_META = new Map(parseTokenMeta(process.env.TOKEN_META!)); 40 | 41 | const KEYS = Keys.Ed25519.parseKeyFiles( 42 | `${MASTER_KEY_PAIR_PATH}/public_key.pem`, 43 | `${MASTER_KEY_PAIR_PATH}/secret_key.pem` 44 | ); 45 | 46 | const test = async () => { 47 | const cep47 = new CEP47Client( 48 | NODE_ADDRESS!, 49 | CHAIN_NAME! 50 | ); 51 | 52 | const installDeployHash = cep47.install( 53 | getBinary(WASM_PATH!), 54 | { 55 | name: TOKEN_NAME!, 56 | contractName: CONTRACT_NAME!, 57 | symbol: TOKEN_SYMBOL!, 58 | meta: TOKEN_META 59 | }, 60 | INSTALL_PAYMENT_AMOUNT!, 61 | KEYS.publicKey, 62 | [KEYS], 63 | ); 64 | 65 | const hash = await installDeployHash.send(NODE_ADDRESS!); 66 | 67 | console.log(`... Contract installation deployHash: ${hash}`); 68 | 69 | await getDeploy(NODE_ADDRESS!, hash); 70 | 71 | console.log(`... Contract installed successfully.`); 72 | 73 | let accountInfo = await getAccountInfo(NODE_ADDRESS!, KEYS.publicKey); 74 | 75 | console.log(`... Account Info: `); 76 | console.log(JSON.stringify(accountInfo, null, 2)); 77 | 78 | const contractHash = await getAccountNamedKeyValue( 79 | accountInfo, 80 | `${CONTRACT_NAME!}_contract_hash` 81 | ); 82 | 83 | console.log(`... Contract Hash: ${contractHash}`); 84 | }; 85 | 86 | test(); 87 | 88 | -------------------------------------------------------------------------------- /e2e/cep47/usage.ts: -------------------------------------------------------------------------------- 1 | import { config } from "dotenv"; 2 | config({ path: ".env.cep47" }); 3 | import { CEP47Client, CEP47Events, CEP47EventParser } from "casper-cep47-js-client"; 4 | import { parseTokenMeta, sleep, getDeploy, getAccountInfo, getAccountNamedKeyValue } from "../utils"; 5 | 6 | import { 7 | CLValueBuilder, 8 | Keys, 9 | CLPublicKey, 10 | CLAccountHash, 11 | CLPublicKeyType, 12 | DeployUtil, 13 | EventStream, 14 | EventName, 15 | CLValueParsers, 16 | CLMap, 17 | } from "casper-js-sdk"; 18 | 19 | const { 20 | NODE_ADDRESS, 21 | EVENT_STREAM_ADDRESS, 22 | CHAIN_NAME, 23 | WASM_PATH, 24 | MASTER_KEY_PAIR_PATH, 25 | USER_KEY_PAIR_PATH, 26 | TOKEN_NAME, 27 | CONTRACT_NAME, 28 | TOKEN_SYMBOL, 29 | CONTRACT_HASH, 30 | INSTALL_PAYMENT_AMOUNT, 31 | MINT_ONE_PAYMENT_AMOUNT, 32 | MINT_COPIES_PAYMENT_AMOUNT, 33 | TRANSFER_ONE_PAYMENT_AMOUNT, 34 | BURN_ONE_PAYMENT_AMOUNT, 35 | MINT_ONE_META_SIZE, 36 | MINT_COPIES_META_SIZE, 37 | MINT_COPIES_COUNT, 38 | MINT_MANY_META_SIZE, 39 | MINT_MANY_META_COUNT, 40 | } = process.env; 41 | 42 | const KEYS = Keys.Ed25519.parseKeyFiles( 43 | `${MASTER_KEY_PAIR_PATH}/public_key.pem`, 44 | `${MASTER_KEY_PAIR_PATH}/secret_key.pem` 45 | ); 46 | 47 | const KEYS_USER = Keys.Ed25519.parseKeyFiles( 48 | `${USER_KEY_PAIR_PATH}/public_key.pem`, 49 | `${USER_KEY_PAIR_PATH}/secret_key.pem` 50 | ); 51 | 52 | const test = async () => { 53 | const cep47 = new CEP47Client( 54 | NODE_ADDRESS!, 55 | CHAIN_NAME! 56 | ); 57 | 58 | let accountInfo = await getAccountInfo(NODE_ADDRESS!, KEYS.publicKey); 59 | 60 | console.log(`... Account Info: `); 61 | console.log(JSON.stringify(accountInfo, null, 2)); 62 | 63 | const contractHash = await getAccountNamedKeyValue( 64 | accountInfo, 65 | `${CONTRACT_NAME!}_contract_hash` 66 | ); 67 | 68 | const contractPackageHash = await getAccountNamedKeyValue( 69 | accountInfo, 70 | `${CONTRACT_NAME!}_contract_package_hash` 71 | ); 72 | 73 | console.log(`... Contract Hash: ${contractHash}`); 74 | console.log(`... Contract Package Hash: ${contractPackageHash}`); 75 | 76 | await cep47.setContractHash(contractHash, contractPackageHash); 77 | 78 | await sleep(5 * 1000); 79 | 80 | const es = new EventStream(EVENT_STREAM_ADDRESS!); 81 | 82 | es.subscribe(EventName.DeployProcessed, (event) => { 83 | const parsedEvents = CEP47EventParser({ 84 | contractPackageHash, 85 | eventNames: [ 86 | CEP47Events.MintOne, 87 | CEP47Events.TransferToken, 88 | CEP47Events.BurnOne, 89 | CEP47Events.MetadataUpdate, 90 | CEP47Events.ApproveToken 91 | ] 92 | }, event); 93 | 94 | if (parsedEvents && parsedEvents.success) { 95 | console.log("*** EVENT ***"); 96 | console.log(parsedEvents.data); 97 | console.log("*** ***"); 98 | } 99 | }); 100 | 101 | es.start(); 102 | 103 | const name = await cep47.name(); 104 | console.log(`... Contract name: ${name}`); 105 | 106 | const symbol = await cep47.symbol(); 107 | console.log(`... Contract symbol: ${symbol}`); 108 | 109 | const meta = await cep47.meta(); 110 | console.log(`... Contract meta: ${JSON.stringify(meta)}`); 111 | 112 | let totalSupply = await cep47.totalSupply(); 113 | console.log(`... Total supply: ${totalSupply}`); 114 | 115 | 116 | //****************// 117 | //* Mint Section *// 118 | //****************// 119 | console.log('\n*************************\n'); 120 | 121 | console.log('... Mint token one \n'); 122 | 123 | const mintDeploy = await cep47.mint( 124 | KEYS.publicKey, 125 | ["1"], 126 | [new Map([['number', 'one']])], 127 | MINT_ONE_PAYMENT_AMOUNT!, 128 | KEYS.publicKey, 129 | [KEYS] 130 | ); 131 | 132 | const mintDeployHash = await mintDeploy.send(NODE_ADDRESS!); 133 | 134 | console.log("...... Mint deploy hash: ", mintDeployHash); 135 | 136 | await getDeploy(NODE_ADDRESS!, mintDeployHash); 137 | console.log("...... Token minted successfully"); 138 | 139 | //* Checks after mint *// 140 | const balanceOf1 = await cep47.balanceOf(KEYS.publicKey); 141 | 142 | console.log('...... Balance of master account: ', balanceOf1); 143 | 144 | const ownerOfTokenOne = await cep47.getOwnerOf("1"); 145 | 146 | console.log('...... Owner of token one: ', ownerOfTokenOne); 147 | 148 | const tokenOneMeta = await cep47.getTokenMeta("1"); 149 | 150 | console.log('...... Token five metadata: ', tokenOneMeta); 151 | 152 | const indexByToken1 = await cep47.getIndexByToken(KEYS.publicKey, "1"); 153 | console.log('...... index of token one: ', indexByToken1); 154 | 155 | const tokenByIndex1 = await cep47.getTokenByIndex(KEYS.publicKey, indexByToken1); 156 | console.log('...... token one id: ', tokenByIndex1); 157 | 158 | //****************// 159 | //* Burn section *// 160 | //****************// 161 | console.log('\n*************************\n'); 162 | 163 | console.log('... Burn token one \n'); 164 | 165 | const burnDeploy = await cep47.burn( 166 | KEYS.publicKey, 167 | ["1"], 168 | MINT_ONE_PAYMENT_AMOUNT!, 169 | KEYS.publicKey, 170 | [KEYS] 171 | ); 172 | 173 | const burnDeployHash = await burnDeploy.send(NODE_ADDRESS!); 174 | 175 | console.log("... Burn deploy hash: ", burnDeployHash); 176 | 177 | await getDeploy(NODE_ADDRESS!, burnDeployHash); 178 | console.log("... Token burned successfully"); 179 | 180 | //***************// 181 | //* Mint Copies *// 182 | //***************// 183 | console.log('\n*************************\n'); 184 | 185 | console.log('... Mint copies #1\n'); 186 | 187 | const mintCopiesDeploy = await cep47.mintCopies( 188 | KEYS.publicKey, 189 | ["2", "3", "4", "5"], 190 | new Map([['number', 'from-series']]), 191 | 4, 192 | MINT_COPIES_PAYMENT_AMOUNT!, 193 | KEYS.publicKey, 194 | [KEYS] 195 | ); 196 | 197 | const mintCopiesDeployHash = await mintCopiesDeploy.send(NODE_ADDRESS!); 198 | 199 | console.log("...... Mint deploy hash: ", mintCopiesDeployHash); 200 | 201 | await getDeploy(NODE_ADDRESS!, mintCopiesDeployHash); 202 | console.log("...... Token minted successfully"); 203 | 204 | //* Checks after mint *// 205 | const balanceOf2 = await cep47.balanceOf(KEYS.publicKey); 206 | 207 | console.log('...... Balance of master account: ', balanceOf2); 208 | 209 | let ownerOfTokenFive = await cep47.getOwnerOf("5"); 210 | 211 | console.log('...... Owner of token five: ', ownerOfTokenFive); 212 | 213 | const tokenFiveMeta = await cep47.getTokenMeta("5"); 214 | 215 | console.log('...... Token five metadata: ', tokenFiveMeta); 216 | 217 | const indexByToken5 = await cep47.getIndexByToken(KEYS.publicKey, "5"); 218 | console.log('...... index of token five: ', indexByToken5); 219 | 220 | const tokenByIndex5 = await cep47.getTokenByIndex(KEYS.publicKey, indexByToken5); 221 | console.log('...... token five id: ', tokenByIndex5); 222 | 223 | //************// 224 | //* Transfer *// 225 | //************// 226 | 227 | console.log('\n*************************\n'); 228 | 229 | console.log('... Transfer #1\n'); 230 | 231 | let ownerOfTokenTwo = await cep47.getOwnerOf("2"); 232 | console.log(`...... Owner of token "2" is ${ownerOfTokenTwo}`); 233 | 234 | const transferOneRecipient = CLPublicKey.fromHex("016e5ee177b4008a538d5c9df7f8beb392a890a06418e5b9729231b077df9d7215"); 235 | const transferOneDeploy = await cep47.transfer(transferOneRecipient, ["2"], TRANSFER_ONE_PAYMENT_AMOUNT!, KEYS.publicKey, [KEYS]); 236 | 237 | console.log(`...... Transfer from ${KEYS.publicKey.toAccountHashStr()} to ${transferOneRecipient.toAccountHashStr()}`); 238 | 239 | const transferOneHash = await transferOneDeploy.send(NODE_ADDRESS!); 240 | 241 | console.log("...... Transfer #1 deploy hash: ", transferOneHash); 242 | 243 | await getDeploy(NODE_ADDRESS!, transferOneHash); 244 | console.log("...... Token transfered successfully"); 245 | 246 | ownerOfTokenTwo = await cep47.getOwnerOf("2"); 247 | console.log(`...... Owner of token "2" is ${ownerOfTokenTwo}`); 248 | 249 | console.log('\n*************************\n'); 250 | 251 | 252 | //********************// 253 | //* Approval section *// 254 | //********************// 255 | console.log('\n*************************\n'); 256 | 257 | console.log('... Approve\n'); 258 | 259 | const allowedAccount = KEYS_USER!.publicKey; 260 | 261 | const approveDeploy = await cep47.approve( 262 | allowedAccount, 263 | ["5"], 264 | MINT_ONE_PAYMENT_AMOUNT!, 265 | KEYS.publicKey, 266 | [KEYS] 267 | ); 268 | 269 | const approveDeployHash = await approveDeploy.send(NODE_ADDRESS!); 270 | 271 | console.log("...... Approval deploy hash: ", approveDeployHash); 272 | 273 | await getDeploy(NODE_ADDRESS!, approveDeployHash); 274 | console.log("...... Token approved successfully"); 275 | 276 | // ** Checks after approval **// 277 | const allowanceOfTokenFive = await cep47.getAllowance(KEYS.publicKey, "5"); 278 | console.log(`...... Allowance of token 5 ${allowanceOfTokenFive}`); 279 | 280 | 281 | //*****************// 282 | //* Transfer From *// 283 | //*****************// 284 | 285 | console.log('\n*************************\n'); 286 | 287 | console.log('... Transfer From #1\n'); 288 | 289 | ownerOfTokenFive = await cep47.getOwnerOf("5"); 290 | console.log(`...... Owner of token "5" is ${ownerOfTokenFive}`); 291 | 292 | // NOTE: Some random address 293 | const transferFromRecipient = CLPublicKey.fromHex("019548b4f31b06d1ce81ab4fd90c9a88e4a5aee9d71cac97044280905707248da4"); 294 | 295 | console.log(`...... Transfer from ${KEYS.publicKey.toAccountHashStr()} to ${transferFromRecipient.toAccountHashStr()}`); 296 | 297 | const transferFromDeploy = await cep47.transferFrom( 298 | transferFromRecipient, 299 | KEYS.publicKey, 300 | ["5"], 301 | TRANSFER_ONE_PAYMENT_AMOUNT!, 302 | KEYS_USER.publicKey, [KEYS_USER]); 303 | 304 | 305 | const transferFromHash = await transferFromDeploy.send(NODE_ADDRESS!); 306 | 307 | console.log("...... Transfer From #1 deploy hash: ", transferFromHash); 308 | 309 | await getDeploy(NODE_ADDRESS!, transferFromHash); 310 | console.log("...... Token transfered successfully"); 311 | 312 | ownerOfTokenFive = await cep47.getOwnerOf("5"); 313 | console.log(`...... Owner of token "5" is ${ownerOfTokenFive}`); 314 | 315 | console.log('\n*************************\n'); 316 | 317 | //*******************// 318 | //* Update Metadata *// 319 | //*******************// 320 | 321 | console.log('\n*************************\n'); 322 | 323 | console.log('... Update metadata of token 4 \n'); 324 | 325 | let tokenFourMeta = await cep47.getTokenMeta("4"); 326 | 327 | console.log('...... Token 4 metadata: ', tokenFourMeta); 328 | 329 | const updateMetadataDeploy = await cep47.updateTokenMeta( 330 | "4", 331 | new Map([["name", "four"]]), 332 | TRANSFER_ONE_PAYMENT_AMOUNT!, 333 | KEYS_USER.publicKey, 334 | [KEYS_USER] 335 | ); 336 | 337 | const updateMetadataHash = await updateMetadataDeploy.send(NODE_ADDRESS!); 338 | 339 | console.log("...... Update metadata deploy hash: ", updateMetadataHash); 340 | 341 | await getDeploy(NODE_ADDRESS!, updateMetadataHash); 342 | console.log("...... Token metadata updated successfully"); 343 | 344 | tokenFourMeta = await cep47.getTokenMeta("4"); 345 | 346 | console.log('...... Token 4 metadata: ', tokenFourMeta); 347 | 348 | console.log('\n*************************\n'); 349 | }; 350 | 351 | test(); 352 | -------------------------------------------------------------------------------- /e2e/utils.ts: -------------------------------------------------------------------------------- 1 | import { CasperClient, CLPublicKey, Keys, CasperServiceByJsonRPC } from "casper-js-sdk"; 2 | 3 | export const parseTokenMeta = (str: string): Array<[string, string]> => 4 | str.split(",").map((s) => { 5 | const map = s.split(" "); 6 | return [map[0], map[1]]; 7 | }); 8 | 9 | export const sleep = (ms: number) => { 10 | return new Promise((resolve) => setTimeout(resolve, ms)); 11 | }; 12 | 13 | /** 14 | * Returns a set ECC key pairs - one for each NCTL user account. 15 | * @param {String} pathToUsers - Path to NCTL user directories. 16 | * @return {Array} An array of assymmetric keys. 17 | */ 18 | export const getKeyPairOfUserSet = (pathToUsers: string) => { 19 | return [1, 2, 3, 4, 5].map((userID) => { 20 | return Keys.Ed25519.parseKeyFiles( 21 | `${pathToUsers}/user-${userID}/public_key.pem`, 22 | `${pathToUsers}/user-${userID}/secret_key.pem` 23 | ); 24 | }); 25 | }; 26 | 27 | export const getDeploy = async (NODE_URL: string, deployHash: string) => { 28 | const client = new CasperClient(NODE_URL); 29 | let i = 300; 30 | while (i != 0) { 31 | const [deploy, raw] = await client.getDeploy(deployHash); 32 | if (raw.execution_results.length !== 0) { 33 | // @ts-ignore 34 | if (raw.execution_results[0].result.Success) { 35 | return deploy; 36 | } else { 37 | // @ts-ignore 38 | throw Error( 39 | "Contract execution: " + 40 | // @ts-ignore 41 | raw.execution_results[0].result.Failure.error_message 42 | ); 43 | } 44 | } else { 45 | i--; 46 | await sleep(1000); 47 | continue; 48 | } 49 | } 50 | throw Error("Timeout after " + i + "s. Something's wrong"); 51 | }; 52 | 53 | export const getAccountInfo: any = async ( 54 | nodeAddress: string, 55 | publicKey: CLPublicKey 56 | ) => { 57 | const client = new CasperServiceByJsonRPC(nodeAddress); 58 | const stateRootHash = await client.getStateRootHash(); 59 | const accountHash = publicKey.toAccountHashStr(); 60 | const blockState = await client.getBlockState(stateRootHash, accountHash, []); 61 | return blockState.Account; 62 | }; 63 | 64 | /** 65 | * Returns a value under an on-chain account's storage. 66 | * @param accountInfo - On-chain account's info. 67 | * @param namedKey - A named key associated with an on-chain account. 68 | */ 69 | export const getAccountNamedKeyValue = (accountInfo: any, namedKey: string) => { 70 | const found = accountInfo.namedKeys.find((i: any) => i.name === namedKey); 71 | if (found) { 72 | return found.key; 73 | } 74 | return undefined; 75 | }; 76 | -------------------------------------------------------------------------------- /lerna.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "independent", 3 | "command": { 4 | "publish": { 5 | "ignoreChanges": ["*.md"] 6 | }, 7 | "bootstrap": { 8 | "npmClientArgs": ["--no-package-lock"] 9 | } 10 | }, 11 | "packages": [ 12 | "packages/*" 13 | ] 14 | } 15 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "casper-contracts", 3 | "description": "casper-contracts-js-clients", 4 | "private": true, 5 | "devDependencies": { 6 | "dotenv": "^10.0.0", 7 | "lerna": "^6.4.1", 8 | "typescript": "^4.4.3" 9 | }, 10 | "scripts": { 11 | "bootstrap": "lerna bootstrap", 12 | "test": "npm run dist && lerna run test --stream", 13 | "dist": "lerna run dist --include-dependencies", 14 | "publish:ci": "lerna publish from-package --yes --no-verify-access", 15 | "e2e:cep47:install": "ts-node ./e2e/cep47/install.ts", 16 | "e2e:cep47:usage": "ts-node ./e2e/cep47/usage.ts" 17 | }, 18 | "keywords": [], 19 | "author": "Jan Hoffmann ", 20 | "license": "ISC", 21 | "dependencies": { 22 | "casper-cep47-js-client": "file:./packages/cep47-client", 23 | "casper-js-sdk": "2.10.2", 24 | "ts-node": "^10.2.1" 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /packages/cep47-client/README.md: -------------------------------------------------------------------------------- 1 | # `casper-cep47-js-client` 2 | 3 | This client gives you an easy way to install and interact with the [Casper CEP-47 (NFT)](https://github.com/casper-ecosystem/casper-nft-cep47) smart contract. 4 | 5 | ## Installation 6 | 7 | Run this command to install the CEP-47 JavaScript client: 8 | 9 | ``` 10 | npm i casper-cep47-js-client 11 | ``` 12 | 13 | ## Usage 14 | 15 | ### Methods 16 | 17 | This description is work in progress. 18 | 19 | ## Event stream handling 20 | 21 | This description is work in progress. 22 | -------------------------------------------------------------------------------- /packages/cep47-client/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "casper-cep47-js-client", 3 | "version": "1.0.4", 4 | "lockfileVersion": 3, 5 | "requires": true, 6 | "packages": { 7 | "": { 8 | "name": "casper-cep47-js-client", 9 | "version": "1.0.4", 10 | "license": "ISC", 11 | "dependencies": { 12 | "blakejs": "1.2.1", 13 | "casper-js-sdk": "^2.10.2" 14 | } 15 | }, 16 | "node_modules/@ethersproject/bignumber": { 17 | "version": "5.7.0", 18 | "resolved": "https://registry.npmjs.org/@ethersproject/bignumber/-/bignumber-5.7.0.tgz", 19 | "integrity": "sha512-n1CAdIHRWjSucQO3MC1zPSVgV/6dy/fjL9pMrPP9peL+QxEg9wOsVqwD4+818B6LUEtaXzVHQiuivzRoxPxUGw==", 20 | "funding": [ 21 | { 22 | "type": "individual", 23 | "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" 24 | }, 25 | { 26 | "type": "individual", 27 | "url": "https://www.buymeacoffee.com/ricmoo" 28 | } 29 | ], 30 | "dependencies": { 31 | "@ethersproject/bytes": "^5.7.0", 32 | "@ethersproject/logger": "^5.7.0", 33 | "bn.js": "^5.2.1" 34 | } 35 | }, 36 | "node_modules/@ethersproject/bytes": { 37 | "version": "5.7.0", 38 | "resolved": "https://registry.npmjs.org/@ethersproject/bytes/-/bytes-5.7.0.tgz", 39 | "integrity": "sha512-nsbxwgFXWh9NyYWo+U8atvmMsSdKJprTcICAkvbBffT75qDocbuggBU0SJiVK2MuTrp0q+xvLkTnGMPK1+uA9A==", 40 | "funding": [ 41 | { 42 | "type": "individual", 43 | "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" 44 | }, 45 | { 46 | "type": "individual", 47 | "url": "https://www.buymeacoffee.com/ricmoo" 48 | } 49 | ], 50 | "dependencies": { 51 | "@ethersproject/logger": "^5.7.0" 52 | } 53 | }, 54 | "node_modules/@ethersproject/constants": { 55 | "version": "5.7.0", 56 | "resolved": "https://registry.npmjs.org/@ethersproject/constants/-/constants-5.7.0.tgz", 57 | "integrity": "sha512-DHI+y5dBNvkpYUMiRQyxRBYBefZkJfo70VUkUAsRjcPs47muV9evftfZ0PJVCXYbAiCgght0DtcF9srFQmIgWA==", 58 | "funding": [ 59 | { 60 | "type": "individual", 61 | "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" 62 | }, 63 | { 64 | "type": "individual", 65 | "url": "https://www.buymeacoffee.com/ricmoo" 66 | } 67 | ], 68 | "dependencies": { 69 | "@ethersproject/bignumber": "^5.7.0" 70 | } 71 | }, 72 | "node_modules/@ethersproject/logger": { 73 | "version": "5.7.0", 74 | "resolved": "https://registry.npmjs.org/@ethersproject/logger/-/logger-5.7.0.tgz", 75 | "integrity": "sha512-0odtFdXu/XHtjQXJYA3u9G0G8btm0ND5Cu8M7i5vhEcE8/HmF4Lbdqanwyv4uQTr2tx6b7fQRmgLrsnpQlmnig==", 76 | "funding": [ 77 | { 78 | "type": "individual", 79 | "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" 80 | }, 81 | { 82 | "type": "individual", 83 | "url": "https://www.buymeacoffee.com/ricmoo" 84 | } 85 | ] 86 | }, 87 | "node_modules/@noble/curves": { 88 | "version": "1.2.0", 89 | "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.2.0.tgz", 90 | "integrity": "sha512-oYclrNgRaM9SsBUBVbb8M6DTV7ZHRTKugureoYEncY5c65HOmRzvSiTE3y5CYaPYJA/GVkrhXEoF0M3Ya9PMnw==", 91 | "dependencies": { 92 | "@noble/hashes": "1.3.2" 93 | }, 94 | "funding": { 95 | "url": "https://paulmillr.com/funding/" 96 | } 97 | }, 98 | "node_modules/@noble/ed25519": { 99 | "version": "1.7.3", 100 | "resolved": "https://registry.npmjs.org/@noble/ed25519/-/ed25519-1.7.3.tgz", 101 | "integrity": "sha512-iR8GBkDt0Q3GyaVcIu7mSsVIqnFbkbRzGLWlvhwunacoLwt4J3swfKhfaM6rN6WY+TBGoYT1GtT1mIh2/jGbRQ==", 102 | "funding": [ 103 | { 104 | "type": "individual", 105 | "url": "https://paulmillr.com/funding/" 106 | } 107 | ] 108 | }, 109 | "node_modules/@noble/hashes": { 110 | "version": "1.3.2", 111 | "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.2.tgz", 112 | "integrity": "sha512-MVC8EAQp7MvEcm30KWENFjgR+Mkmf+D189XJTkFIlwohU5hcBbn1ZkKq7KVTi2Hme3PMGF390DaL52beVrIihQ==", 113 | "engines": { 114 | "node": ">= 16" 115 | }, 116 | "funding": { 117 | "url": "https://paulmillr.com/funding/" 118 | } 119 | }, 120 | "node_modules/@noble/secp256k1": { 121 | "version": "1.7.1", 122 | "resolved": "https://registry.npmjs.org/@noble/secp256k1/-/secp256k1-1.7.1.tgz", 123 | "integrity": "sha512-hOUk6AyBFmqVrv7k5WAw/LpszxVbj9gGN4JRkIX52fdFAj1UA61KXmZDvqVEm+pOyec3+fIeZB02LYa/pWOArw==", 124 | "funding": [ 125 | { 126 | "type": "individual", 127 | "url": "https://paulmillr.com/funding/" 128 | } 129 | ] 130 | }, 131 | "node_modules/@open-rpc/client-js": { 132 | "version": "1.8.1", 133 | "resolved": "https://registry.npmjs.org/@open-rpc/client-js/-/client-js-1.8.1.tgz", 134 | "integrity": "sha512-vV+Hetl688nY/oWI9IFY0iKDrWuLdYhf7OIKI6U1DcnJV7r4gAgwRJjEr1QVYszUc0gjkHoQJzqevmXMGLyA0g==", 135 | "dependencies": { 136 | "isomorphic-fetch": "^3.0.0", 137 | "isomorphic-ws": "^5.0.0", 138 | "strict-event-emitter-types": "^2.0.0", 139 | "ws": "^7.0.0" 140 | } 141 | }, 142 | "node_modules/@scure/base": { 143 | "version": "1.1.2", 144 | "resolved": "https://registry.npmjs.org/@scure/base/-/base-1.1.2.tgz", 145 | "integrity": "sha512-sSCrnIdaUZQHhBxZThMuk7Wm1TWzMD3uJNdGgx3JS23xSqevu0tAOsg8k66nL3R2NwQe65AI9GgqpPOgZys/eA==", 146 | "funding": { 147 | "url": "https://paulmillr.com/funding/" 148 | } 149 | }, 150 | "node_modules/@scure/bip32": { 151 | "version": "1.3.2", 152 | "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.3.2.tgz", 153 | "integrity": "sha512-N1ZhksgwD3OBlwTv3R6KFEcPojl/W4ElJOeCZdi+vuI5QmTFwLq3OFf2zd2ROpKvxFdgZ6hUpb0dx9bVNEwYCA==", 154 | "dependencies": { 155 | "@noble/curves": "~1.2.0", 156 | "@noble/hashes": "~1.3.2", 157 | "@scure/base": "~1.1.2" 158 | }, 159 | "funding": { 160 | "url": "https://paulmillr.com/funding/" 161 | } 162 | }, 163 | "node_modules/@scure/bip39": { 164 | "version": "1.2.1", 165 | "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.2.1.tgz", 166 | "integrity": "sha512-Z3/Fsz1yr904dduJD0NpiyRHhRYHdcnyh73FZWiV+/qhWi83wNJ3NWolYqCEN+ZWsUz2TWwajJggcRE9r1zUYg==", 167 | "dependencies": { 168 | "@noble/hashes": "~1.3.0", 169 | "@scure/base": "~1.1.0" 170 | }, 171 | "funding": { 172 | "url": "https://paulmillr.com/funding/" 173 | } 174 | }, 175 | "node_modules/@types/bn.js": { 176 | "version": "5.1.1", 177 | "resolved": "https://registry.npmjs.org/@types/bn.js/-/bn.js-5.1.1.tgz", 178 | "integrity": "sha512-qNrYbZqMx0uJAfKnKclPh+dTwK33KfLHYqtyODwd5HnXOjnkhc4qgn3BrK6RWyGZm5+sIFE7Q7Vz6QQtJB7w7g==", 179 | "dependencies": { 180 | "@types/node": "*" 181 | } 182 | }, 183 | "node_modules/@types/elliptic": { 184 | "version": "6.4.14", 185 | "resolved": "https://registry.npmjs.org/@types/elliptic/-/elliptic-6.4.14.tgz", 186 | "integrity": "sha512-z4OBcDAU0GVwDTuwJzQCiL6188QvZMkvoERgcVjq0/mPM8jCfdwZ3x5zQEVoL9WCAru3aG5wl3Z5Ww5wBWn7ZQ==", 187 | "dependencies": { 188 | "@types/bn.js": "*" 189 | } 190 | }, 191 | "node_modules/@types/node": { 192 | "version": "20.5.7", 193 | "resolved": "https://registry.npmjs.org/@types/node/-/node-20.5.7.tgz", 194 | "integrity": "sha512-dP7f3LdZIysZnmvP3ANJYTSwg+wLLl8p7RqniVlV7j+oXSXAbt9h0WIBFmJy5inWZoX9wZN6eXx+YXd9Rh3RBA==" 195 | }, 196 | "node_modules/@types/ws": { 197 | "version": "8.5.5", 198 | "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.5.tgz", 199 | "integrity": "sha512-lwhs8hktwxSjf9UaZ9tG5M03PGogvFaH8gUgLNbN9HKIg0dvv6q+gkSuJ8HN4/VbyxkuLzCjlN7GquQ0gUJfIg==", 200 | "dependencies": { 201 | "@types/node": "*" 202 | } 203 | }, 204 | "node_modules/asn1.js": { 205 | "version": "5.4.1", 206 | "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-5.4.1.tgz", 207 | "integrity": "sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA==", 208 | "dependencies": { 209 | "bn.js": "^4.0.0", 210 | "inherits": "^2.0.1", 211 | "minimalistic-assert": "^1.0.0", 212 | "safer-buffer": "^2.1.0" 213 | } 214 | }, 215 | "node_modules/asn1.js/node_modules/bn.js": { 216 | "version": "4.12.0", 217 | "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", 218 | "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" 219 | }, 220 | "node_modules/balanced-match": { 221 | "version": "1.0.2", 222 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", 223 | "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" 224 | }, 225 | "node_modules/blakejs": { 226 | "version": "1.2.1", 227 | "resolved": "https://registry.npmjs.org/blakejs/-/blakejs-1.2.1.tgz", 228 | "integrity": "sha512-QXUSXI3QVc/gJME0dBpXrag1kbzOqCjCX8/b54ntNyW6sjtoqxqRk3LTmXzaJoh71zMsDCjM+47jS7XiwN/+fQ==" 229 | }, 230 | "node_modules/bn.js": { 231 | "version": "5.2.1", 232 | "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.1.tgz", 233 | "integrity": "sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==" 234 | }, 235 | "node_modules/brace-expansion": { 236 | "version": "1.1.11", 237 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", 238 | "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", 239 | "dependencies": { 240 | "balanced-match": "^1.0.0", 241 | "concat-map": "0.0.1" 242 | } 243 | }, 244 | "node_modules/brorand": { 245 | "version": "1.1.0", 246 | "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", 247 | "integrity": "sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==" 248 | }, 249 | "node_modules/casper-js-sdk": { 250 | "version": "2.15.2", 251 | "resolved": "https://registry.npmjs.org/casper-js-sdk/-/casper-js-sdk-2.15.2.tgz", 252 | "integrity": "sha512-q0UlXeJuyVMR5I07OQMLTn2LXMzYcN+eC+QxTUP4JkUGgSMaJKpNxLKaS9uRQeY24BpqVjV6SNBFw0dfeq7AoQ==", 253 | "dependencies": { 254 | "@ethersproject/bignumber": "^5.0.8", 255 | "@ethersproject/bytes": "^5.0.5", 256 | "@ethersproject/constants": "^5.0.5", 257 | "@noble/ed25519": "^1.7.3", 258 | "@noble/hashes": "^1.2.0", 259 | "@noble/secp256k1": "^1.7.1", 260 | "@open-rpc/client-js": "^1.8.1", 261 | "@scure/bip32": "^1.1.5", 262 | "@scure/bip39": "^1.2.0", 263 | "@types/ws": "^8.2.2", 264 | "glob": "^7.1.6", 265 | "humanize-duration": "^3.24.0", 266 | "key-encoder": "^2.0.3", 267 | "lodash": "^4.17.21", 268 | "node-fetch": "^2.6.11", 269 | "reflect-metadata": "^0.1.13", 270 | "ts-results": "npm:@casperlabs/ts-results@^3.3.4", 271 | "typedjson": "^1.6.0-rc2" 272 | } 273 | }, 274 | "node_modules/concat-map": { 275 | "version": "0.0.1", 276 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", 277 | "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" 278 | }, 279 | "node_modules/elliptic": { 280 | "version": "6.5.4", 281 | "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz", 282 | "integrity": "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==", 283 | "dependencies": { 284 | "bn.js": "^4.11.9", 285 | "brorand": "^1.1.0", 286 | "hash.js": "^1.0.0", 287 | "hmac-drbg": "^1.0.1", 288 | "inherits": "^2.0.4", 289 | "minimalistic-assert": "^1.0.1", 290 | "minimalistic-crypto-utils": "^1.0.1" 291 | } 292 | }, 293 | "node_modules/elliptic/node_modules/bn.js": { 294 | "version": "4.12.0", 295 | "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", 296 | "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" 297 | }, 298 | "node_modules/fs.realpath": { 299 | "version": "1.0.0", 300 | "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", 301 | "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" 302 | }, 303 | "node_modules/glob": { 304 | "version": "7.2.3", 305 | "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", 306 | "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", 307 | "dependencies": { 308 | "fs.realpath": "^1.0.0", 309 | "inflight": "^1.0.4", 310 | "inherits": "2", 311 | "minimatch": "^3.1.1", 312 | "once": "^1.3.0", 313 | "path-is-absolute": "^1.0.0" 314 | }, 315 | "engines": { 316 | "node": "*" 317 | }, 318 | "funding": { 319 | "url": "https://github.com/sponsors/isaacs" 320 | } 321 | }, 322 | "node_modules/hash.js": { 323 | "version": "1.1.7", 324 | "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", 325 | "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", 326 | "dependencies": { 327 | "inherits": "^2.0.3", 328 | "minimalistic-assert": "^1.0.1" 329 | } 330 | }, 331 | "node_modules/hmac-drbg": { 332 | "version": "1.0.1", 333 | "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", 334 | "integrity": "sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==", 335 | "dependencies": { 336 | "hash.js": "^1.0.3", 337 | "minimalistic-assert": "^1.0.0", 338 | "minimalistic-crypto-utils": "^1.0.1" 339 | } 340 | }, 341 | "node_modules/humanize-duration": { 342 | "version": "3.29.0", 343 | "resolved": "https://registry.npmjs.org/humanize-duration/-/humanize-duration-3.29.0.tgz", 344 | "integrity": "sha512-G5wZGwYTLaQAmYqhfK91aw3xt6wNbJW1RnWDh4qP1PvF4T/jnkjx2RVhG5kzB2PGsYGTn+oSDBQp+dMdILLxcg==" 345 | }, 346 | "node_modules/inflight": { 347 | "version": "1.0.6", 348 | "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", 349 | "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", 350 | "dependencies": { 351 | "once": "^1.3.0", 352 | "wrappy": "1" 353 | } 354 | }, 355 | "node_modules/inherits": { 356 | "version": "2.0.4", 357 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", 358 | "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" 359 | }, 360 | "node_modules/isomorphic-fetch": { 361 | "version": "3.0.0", 362 | "resolved": "https://registry.npmjs.org/isomorphic-fetch/-/isomorphic-fetch-3.0.0.tgz", 363 | "integrity": "sha512-qvUtwJ3j6qwsF3jLxkZ72qCgjMysPzDfeV240JHiGZsANBYd+EEuu35v7dfrJ9Up0Ak07D7GGSkGhCHTqg/5wA==", 364 | "dependencies": { 365 | "node-fetch": "^2.6.1", 366 | "whatwg-fetch": "^3.4.1" 367 | } 368 | }, 369 | "node_modules/isomorphic-ws": { 370 | "version": "5.0.0", 371 | "resolved": "https://registry.npmjs.org/isomorphic-ws/-/isomorphic-ws-5.0.0.tgz", 372 | "integrity": "sha512-muId7Zzn9ywDsyXgTIafTry2sV3nySZeUDe6YedVd1Hvuuep5AsIlqK+XefWpYTyJG5e503F2xIuT2lcU6rCSw==", 373 | "peerDependencies": { 374 | "ws": "*" 375 | } 376 | }, 377 | "node_modules/key-encoder": { 378 | "version": "2.0.3", 379 | "resolved": "https://registry.npmjs.org/key-encoder/-/key-encoder-2.0.3.tgz", 380 | "integrity": "sha512-fgBtpAGIr/Fy5/+ZLQZIPPhsZEcbSlYu/Wu96tNDFNSjSACw5lEIOFeaVdQ/iwrb8oxjlWi6wmWdH76hV6GZjg==", 381 | "dependencies": { 382 | "@types/elliptic": "^6.4.9", 383 | "asn1.js": "^5.0.1", 384 | "bn.js": "^4.11.8", 385 | "elliptic": "^6.4.1" 386 | } 387 | }, 388 | "node_modules/key-encoder/node_modules/bn.js": { 389 | "version": "4.12.0", 390 | "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", 391 | "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" 392 | }, 393 | "node_modules/lodash": { 394 | "version": "4.17.21", 395 | "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", 396 | "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" 397 | }, 398 | "node_modules/minimalistic-assert": { 399 | "version": "1.0.1", 400 | "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", 401 | "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==" 402 | }, 403 | "node_modules/minimalistic-crypto-utils": { 404 | "version": "1.0.1", 405 | "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", 406 | "integrity": "sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==" 407 | }, 408 | "node_modules/minimatch": { 409 | "version": "3.1.2", 410 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", 411 | "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", 412 | "dependencies": { 413 | "brace-expansion": "^1.1.7" 414 | }, 415 | "engines": { 416 | "node": "*" 417 | } 418 | }, 419 | "node_modules/node-fetch": { 420 | "version": "2.7.0", 421 | "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", 422 | "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", 423 | "dependencies": { 424 | "whatwg-url": "^5.0.0" 425 | }, 426 | "engines": { 427 | "node": "4.x || >=6.0.0" 428 | }, 429 | "peerDependencies": { 430 | "encoding": "^0.1.0" 431 | }, 432 | "peerDependenciesMeta": { 433 | "encoding": { 434 | "optional": true 435 | } 436 | } 437 | }, 438 | "node_modules/once": { 439 | "version": "1.4.0", 440 | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", 441 | "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", 442 | "dependencies": { 443 | "wrappy": "1" 444 | } 445 | }, 446 | "node_modules/path-is-absolute": { 447 | "version": "1.0.1", 448 | "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", 449 | "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", 450 | "engines": { 451 | "node": ">=0.10.0" 452 | } 453 | }, 454 | "node_modules/reflect-metadata": { 455 | "version": "0.1.13", 456 | "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.13.tgz", 457 | "integrity": "sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg==" 458 | }, 459 | "node_modules/safer-buffer": { 460 | "version": "2.1.2", 461 | "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", 462 | "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" 463 | }, 464 | "node_modules/strict-event-emitter-types": { 465 | "version": "2.0.0", 466 | "resolved": "https://registry.npmjs.org/strict-event-emitter-types/-/strict-event-emitter-types-2.0.0.tgz", 467 | "integrity": "sha512-Nk/brWYpD85WlOgzw5h173aci0Teyv8YdIAEtV+N88nDB0dLlazZyJMIsN6eo1/AR61l+p6CJTG1JIyFaoNEEA==" 468 | }, 469 | "node_modules/tr46": { 470 | "version": "0.0.3", 471 | "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", 472 | "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" 473 | }, 474 | "node_modules/ts-results": { 475 | "name": "@casperlabs/ts-results", 476 | "version": "3.3.5", 477 | "resolved": "https://registry.npmjs.org/@casperlabs/ts-results/-/ts-results-3.3.5.tgz", 478 | "integrity": "sha512-ymSQqqb4mOSet592li02u1Gd28LoOFJUm6R3jkdNQ+nqsnbHvN+izBigtP4aYmNwh6gFyCwDgjYporEJgDT4eA==", 479 | "dependencies": { 480 | "tslib": "^2.4.1" 481 | } 482 | }, 483 | "node_modules/tslib": { 484 | "version": "2.6.2", 485 | "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", 486 | "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==" 487 | }, 488 | "node_modules/typedjson": { 489 | "version": "1.8.0", 490 | "resolved": "https://registry.npmjs.org/typedjson/-/typedjson-1.8.0.tgz", 491 | "integrity": "sha512-taVJVGebQDagEmVc3Cu6vVVLkWLnxqPcTrkVgbpAsI02ZDDrnHy5zvt1JVqXv4/yztBgZAX1oR07+bkiusGJLQ==", 492 | "dependencies": { 493 | "tslib": "^2.0.1" 494 | } 495 | }, 496 | "node_modules/webidl-conversions": { 497 | "version": "3.0.1", 498 | "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", 499 | "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" 500 | }, 501 | "node_modules/whatwg-fetch": { 502 | "version": "3.6.18", 503 | "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-3.6.18.tgz", 504 | "integrity": "sha512-ltN7j66EneWn5TFDO4L9inYC1D+Czsxlrw2SalgjMmEMkLfA5SIZxEFdE6QtHFiiM6Q7WL32c7AkI3w6yxM84Q==" 505 | }, 506 | "node_modules/whatwg-url": { 507 | "version": "5.0.0", 508 | "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", 509 | "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", 510 | "dependencies": { 511 | "tr46": "~0.0.3", 512 | "webidl-conversions": "^3.0.0" 513 | } 514 | }, 515 | "node_modules/wrappy": { 516 | "version": "1.0.2", 517 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", 518 | "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" 519 | }, 520 | "node_modules/ws": { 521 | "version": "7.5.9", 522 | "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz", 523 | "integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==", 524 | "engines": { 525 | "node": ">=8.3.0" 526 | }, 527 | "peerDependencies": { 528 | "bufferutil": "^4.0.1", 529 | "utf-8-validate": "^5.0.2" 530 | }, 531 | "peerDependenciesMeta": { 532 | "bufferutil": { 533 | "optional": true 534 | }, 535 | "utf-8-validate": { 536 | "optional": true 537 | } 538 | } 539 | } 540 | } 541 | } 542 | -------------------------------------------------------------------------------- /packages/cep47-client/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "casper-cep47-js-client", 3 | "version": "1.0.4", 4 | "author": "Jan Hoffmann ", 5 | "homepage": "", 6 | "license": "ISC", 7 | "main": "dist/index.js", 8 | "types": "dist/index.d.ts", 9 | "files": [ 10 | "dist" 11 | ], 12 | "publishConfig": { 13 | "access": "public" 14 | }, 15 | "dependencies": { 16 | "blakejs": "1.2.1", 17 | "casper-js-sdk": "^2.10.2" 18 | }, 19 | "scripts": { 20 | "dist": "npm run clean && npm run build", 21 | "clean": "rm -rf dist/", 22 | "build": "tsc -p tsconfig.build.json", 23 | "test": "echo \"add tests\" && exit 0" 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /packages/cep47-client/src/index.ts: -------------------------------------------------------------------------------- 1 | import { 2 | CLValue, 3 | CLPublicKey, 4 | CLKey, 5 | CLMap, 6 | RuntimeArgs, 7 | CasperClient, 8 | Contracts, 9 | Keys, 10 | CLKeyParameters, 11 | CLValueBuilder, 12 | CLValueParsers, 13 | CLTypeTag 14 | } from "casper-js-sdk"; 15 | import { concat } from "@ethersproject/bytes"; 16 | import blake from "blakejs"; 17 | 18 | const { Contract, toCLMap, fromCLMap } = Contracts; 19 | 20 | /** 21 | * CEP47 installation parameters. 22 | * 23 | * @param name Name of the token. 24 | * @param contractName Name of the contract. 25 | * @param symbol Symbol of the token. 26 | * @param meta A Map built with Strings containing contract metadata. 27 | */ 28 | export interface CEP47InstallArgs { 29 | name: string, 30 | contractName: string, 31 | symbol: string, 32 | meta: Map 33 | }; 34 | 35 | /** 36 | * CEP47 possible events. 37 | */ 38 | export enum CEP47Events { 39 | MintOne = "cep47_mint_one", 40 | TransferToken = "cep47_transfer_token", 41 | BurnOne = "cep47_burn_one", 42 | MetadataUpdate = 'cep47_metadata_update', 43 | ApproveToken = 'cep47_approve_token' 44 | } 45 | 46 | /** 47 | * CEP47 event parser. 48 | * It can be used with the `EventStream` from the `casper-js-sdk`. 49 | * 50 | * @param params Object containing a contractPackageHash (prefixed with "hash-") and eventNames (a list of CEP47Events). 51 | * @param value A data object returned by the EventStream. 52 | * 53 | * @returns Object containing { error: boolean, success: boolean, data: Object }. 54 | * If success is set to true, the data object contains a list of parsed events. 55 | */ 56 | export const CEP47EventParser = ( 57 | { 58 | contractPackageHash, 59 | eventNames, 60 | }: { contractPackageHash: string; eventNames: CEP47Events[] }, 61 | value: any 62 | ) => { 63 | if (value.body.DeployProcessed.execution_result.Success) { 64 | const { transforms } = 65 | value.body.DeployProcessed.execution_result.Success.effect; 66 | 67 | const cep47Events = transforms.reduce((acc: any, val: any) => { 68 | if ( 69 | val.transform.hasOwnProperty("WriteCLValue") && 70 | typeof val.transform.WriteCLValue.parsed === "object" && 71 | val.transform.WriteCLValue.parsed !== null 72 | ) { 73 | const maybeCLValue = CLValueParsers.fromJSON( 74 | val.transform.WriteCLValue 75 | ); 76 | const clValue = maybeCLValue.unwrap(); 77 | if (clValue && clValue.clType().tag === CLTypeTag.Map) { 78 | const hash = (clValue as CLMap).get( 79 | CLValueBuilder.string("contract_package_hash") 80 | ); 81 | const event = (clValue as CLMap).get(CLValueBuilder.string("event_type")); 82 | if ( 83 | hash && 84 | // NOTE: Calling toLowerCase() because currently the JS-SDK doesn't support checksumed hashes and returns all lower-case values 85 | // Remove it after updating the SDK 86 | hash.value() === contractPackageHash.slice(5).toLowerCase() && 87 | event && 88 | eventNames.includes(event.value()) 89 | ) { 90 | acc = [...acc, { name: event.value(), clValue }]; 91 | } 92 | } 93 | } 94 | return acc; 95 | }, []); 96 | 97 | return { error: null, success: !!cep47Events.length, data: cep47Events }; 98 | } 99 | 100 | return null; 101 | }; 102 | 103 | const keyAndValueToHex = (key: CLValue, value: CLValue) => { 104 | const aBytes = CLValueParsers.toBytes(key).unwrap(); 105 | const bBytes = CLValueParsers.toBytes(value).unwrap(); 106 | 107 | const blaked = blake.blake2b(concat([aBytes, bBytes]), undefined, 32); 108 | const hex = Buffer.from(blaked).toString('hex'); 109 | 110 | return hex; 111 | } 112 | 113 | export class CEP47Client { 114 | casperClient: CasperClient; 115 | contractClient: Contracts.Contract; 116 | 117 | constructor(public nodeAddress: string, public networkName: string) { 118 | this.casperClient = new CasperClient(nodeAddress); 119 | this.contractClient = new Contract(this.casperClient); 120 | } 121 | 122 | /** 123 | * Installs the CEP47 contract. 124 | * 125 | * @param wasm Uin8Array with contents of the WASM file. 126 | * @param args CEP47 installation args (see CEP47InstallArgs). 127 | * @param paymentAmount The payment amount that will be used for this Deploy. 128 | * @param deploySender The PublicKey of the Deploy sender. 129 | * @param keys Optional parameter containing a list of keys that can be used to sign the Deploy. 130 | * 131 | * @returns Deploy that can be signed and sent to the network. 132 | */ 133 | public install( 134 | wasm: Uint8Array, 135 | args: CEP47InstallArgs, 136 | paymentAmount: string, 137 | deploySender: CLPublicKey, 138 | keys?: Keys.AsymmetricKey[] 139 | ) { 140 | const runtimeArgs = RuntimeArgs.fromMap({ 141 | name: CLValueBuilder.string(args.name), 142 | contract_name: CLValueBuilder.string(args.contractName), 143 | symbol: CLValueBuilder.string(args.symbol), 144 | meta: toCLMap(args.meta), 145 | }); 146 | 147 | return this.contractClient.install(wasm, runtimeArgs, paymentAmount, deploySender, this.networkName, keys || []); 148 | } 149 | 150 | /** 151 | * Sets the contract hash of a client. 152 | * 153 | * @param contractHash Contract hash. 154 | * @param contractPackageHash Contract package hash. 155 | */ 156 | public setContractHash(contractHash: string, contractPackageHash?: string) { 157 | this.contractClient.setContractHash(contractHash, contractPackageHash); 158 | } 159 | 160 | /** 161 | * Returns the contract name. 162 | * 163 | * @returns String 164 | */ 165 | public async name() { 166 | return this.contractClient.queryContractData(['name']); 167 | } 168 | 169 | /** 170 | * Returns the contract symbol. 171 | * 172 | * @returns String 173 | */ 174 | public async symbol() { 175 | return this.contractClient.queryContractData(['symbol']); 176 | } 177 | 178 | /** 179 | * Returns the contract metadata. 180 | * 181 | * @returns String 182 | */ 183 | public async meta() { 184 | return this.contractClient.queryContractData(['meta']); 185 | } 186 | 187 | /** 188 | * Returns the contract total supply. 189 | * 190 | * @returns String 191 | */ 192 | public async totalSupply() { 193 | return this.contractClient.queryContractData(['total_supply']); 194 | } 195 | 196 | /** 197 | * Returns the balance of tokens assigned to specific public key. 198 | * 199 | * @param account CLPublicKey of the account. 200 | * 201 | * @returns String containing the number of tokens stored for this account. 202 | */ 203 | public async balanceOf(account: CLPublicKey) { 204 | const result = await this.contractClient 205 | .queryContractDictionary('balances', account.toAccountHashStr().slice(13)); 206 | 207 | const maybeValue = result.value().unwrap(); 208 | 209 | return maybeValue.value().toString(); 210 | } 211 | 212 | /** 213 | * Returns the owner of a specific token. 214 | * 215 | * @param tokenId String an ID of a token. 216 | * 217 | * @returns String containing the prefixed account hash of the account owning this specific token. 218 | */ 219 | public async getOwnerOf(tokenId: string) { 220 | const result = await this.contractClient 221 | .queryContractDictionary('owners', tokenId); 222 | 223 | const maybeValue = result.value().unwrap(); 224 | 225 | return `account-hash-${Buffer.from(maybeValue.value().value()).toString( 226 | "hex" 227 | )}`; 228 | } 229 | 230 | /** 231 | * Returns the metadata of a specific token. 232 | * 233 | * @param tokenId String an ID of a token. 234 | * 235 | * @returns Map containing all the metadata related to this specific token. 236 | */ 237 | public async getTokenMeta(tokenId: string) { 238 | const result = await this.contractClient 239 | .queryContractDictionary('metadata', tokenId); 240 | 241 | const maybeValue = result.value().unwrap().value(); 242 | 243 | return fromCLMap(maybeValue); 244 | } 245 | 246 | /** 247 | * Returns the tokenId of a specific token assigned to an account and queried by index. 248 | * 249 | * @param owner CLPublicKey of the token owner. 250 | * @param index String which represents the token index. 251 | * 252 | * @returns String ID of a token. 253 | */ 254 | public async getTokenByIndex(owner: CLPublicKey, index: string) { 255 | const hex = keyAndValueToHex(CLValueBuilder.key(owner), CLValueBuilder.u256(index)); 256 | const result = await this.contractClient.queryContractDictionary('owned_tokens_by_index', hex); 257 | 258 | const maybeValue = result.value().unwrap(); 259 | 260 | return maybeValue.value().toString(); 261 | } 262 | 263 | /** 264 | * Returns the index of a specific token assigned to an account and queried by ID. 265 | * 266 | * @param owner CLPublicKey of the token owner. 267 | * @param tokenId String which represents the tokenId. 268 | * 269 | * @returns String index of a token for this specific account. 270 | */ 271 | public async getIndexByToken( 272 | owner: CLKeyParameters, 273 | tokenId: string 274 | ) { 275 | const hex = keyAndValueToHex(CLValueBuilder.key(owner), CLValueBuilder.u256(tokenId)); 276 | const result = await this.contractClient.queryContractDictionary('owned_indexes_by_token', hex); 277 | 278 | const maybeValue = result.value().unwrap(); 279 | 280 | return maybeValue.value().toString(); 281 | } 282 | 283 | /** 284 | * Returns the allowance related with a specific token. 285 | * 286 | * @param owner CLPublicKey of the owner of a token. 287 | * @param tokenId String which represents tokenId. 288 | * 289 | * @returns String containing the prefixed account hash of the account owning this token. 290 | */ 291 | public async getAllowance( 292 | owner: CLKeyParameters, 293 | tokenId: string 294 | ) { 295 | const hex = keyAndValueToHex(CLValueBuilder.key(owner), CLValueBuilder.string(tokenId)); 296 | const result = await this.contractClient.queryContractDictionary('allowances', hex); 297 | 298 | const maybeValue = result.value().unwrap(); 299 | 300 | return `account-hash-${Buffer.from(maybeValue.value().value()).toString( 301 | "hex" 302 | )}`; 303 | } 304 | 305 | /** 306 | * Gives another account the right to spend tokens from this account. 307 | * 308 | * @param spender The account that can spend tokens from the owner account. 309 | * @param ids The token IDs that can be spent. 310 | * @param paymentAmount The payment amount that will be used for this Deploy. 311 | * @param deploySender The PublicKey of the Deploy sender. 312 | * @param keys Optional parameter containing a list of keys that can be used to sign the Deploy. 313 | * 314 | * @returns The Deploy that can be sent to the network. 315 | */ 316 | public async approve( 317 | spender: CLKeyParameters, 318 | ids: string[], 319 | paymentAmount: string, 320 | deploySender: CLPublicKey, 321 | keys?: Keys.AsymmetricKey[] 322 | ) { 323 | const runtimeArgs = RuntimeArgs.fromMap({ 324 | spender: CLValueBuilder.key(spender), 325 | token_ids: CLValueBuilder.list(ids.map(id => CLValueBuilder.u256(id))) 326 | }); 327 | 328 | return this.contractClient.callEntrypoint( 329 | 'approve', 330 | runtimeArgs, 331 | deploySender, 332 | this.networkName, 333 | paymentAmount, 334 | keys 335 | ); 336 | } 337 | 338 | /** 339 | * Creates new tokens for a specific recipient, given the token IDs and their metadata, paired in order. 340 | * 341 | * @param recipient The account for which tokens will be minted. 342 | * @param ids The token IDs that will be minted for this account. 343 | * @param metas The corresponding metadata for each minted token. 344 | * @param paymentAmount The payment amount that will be used for this Deploy. 345 | * @param deploySender The PublicKey of the Deploy sender. 346 | * @param keys Optional parameter containing a list of keys that can be used to sign the Deploy. 347 | * 348 | * @returns The Deploy that can be sent to the network. 349 | */ 350 | public async mint( 351 | recipient: CLKeyParameters, 352 | ids: string[], 353 | metas: Map[], 354 | paymentAmount: string, 355 | deploySender: CLPublicKey, 356 | keys?: Keys.AsymmetricKey[] 357 | ) { 358 | const runtimeArgs = RuntimeArgs.fromMap({ 359 | recipient: CLValueBuilder.key(recipient), 360 | token_ids: CLValueBuilder.list(ids.map(id => CLValueBuilder.u256(id))), 361 | token_metas: CLValueBuilder.list(metas.map(meta => toCLMap(meta))) 362 | }); 363 | 364 | return this.contractClient.callEntrypoint( 365 | 'mint', 366 | runtimeArgs, 367 | deploySender, 368 | this.networkName, 369 | paymentAmount, 370 | keys 371 | ); 372 | } 373 | 374 | /** 375 | * Creates several new tokens with specific IDs but with the same metadata. 376 | * 377 | * @param recipient The account for which tokens will be minted. 378 | * @param ids The token IDs that will be minted for this account. 379 | * @param meta The metadata that will be used for each minted token. 380 | * @param count Number of tokens to be minted. 381 | * @param paymentAmount The payment amount that will be used for this Deploy. 382 | * @param deploySender The PublicKey of the Deploy sender. 383 | * @param keys Optional parameter containing a list of keys that can be used to sign the Deploy. 384 | * 385 | * @returns The Deploy that can be sent to the network. 386 | */ 387 | public async mintCopies( 388 | recipient: CLKeyParameters, 389 | ids: string[], 390 | meta: Map, 391 | count: number, 392 | paymentAmount: string, 393 | deploySender: CLPublicKey, 394 | keys?: Keys.AsymmetricKey[] 395 | ) { 396 | const runtimeArgs = RuntimeArgs.fromMap({ 397 | recipient: CLValueBuilder.key(recipient), 398 | token_ids: CLValueBuilder.list(ids.map(id => CLValueBuilder.u256(id))), 399 | token_meta: toCLMap(meta), 400 | count: CLValueBuilder.u32(count) 401 | }); 402 | 403 | return this.contractClient.callEntrypoint( 404 | 'mint_copies', 405 | runtimeArgs, 406 | deploySender, 407 | this.networkName, 408 | paymentAmount, 409 | keys 410 | ); 411 | } 412 | 413 | /** 414 | * Destroys the given tokens for the account specified. 415 | * 416 | * @param owner The account for which tokens will be burned. 417 | * @param ids Token IDs that will be burned for this account. 418 | * @param paymentAmount The payment amount that will be used for this Deploy. 419 | * @param deploySender The PublicKey of the Deploy sender. 420 | * @param keys Optional parameter containing a list of keys that can be used to sign the Deploy. 421 | * 422 | * @returns The Deploy that can be sent to the network. 423 | */ 424 | public async burn( 425 | owner: CLKeyParameters, 426 | ids: string[], 427 | paymentAmount: string, 428 | deploySender: CLPublicKey, 429 | keys?: Keys.AsymmetricKey[] 430 | ) { 431 | const runtimeArgs = RuntimeArgs.fromMap({ 432 | owner: CLValueBuilder.key(owner), 433 | token_ids: CLValueBuilder.list(ids.map(id => CLValueBuilder.u256(id))), 434 | }); 435 | 436 | return this.contractClient.callEntrypoint( 437 | 'burn', 438 | runtimeArgs, 439 | deploySender, 440 | this.networkName, 441 | paymentAmount, 442 | keys 443 | ); 444 | } 445 | 446 | /** 447 | * Transfers tokens from a given account to another account. 448 | * 449 | * @param recipient The account that will receive tokens from the token owner. 450 | * @param owner The account that owns the tokens to be transferred. 451 | * @param ids Token IDs that will be transferred to the recipient. 452 | * @param paymentAmount The payment amount that will be used for this Deploy. 453 | * @param deploySender The PublicKey of the Deploy sender. 454 | * @param keys Optional parameter containing a list of keys that can be used to sign the Deploy. 455 | * 456 | * @returns The Deploy that can be sent to the network. 457 | */ 458 | public async transferFrom( 459 | recipient: CLKeyParameters, 460 | owner: CLKeyParameters, 461 | ids: string[], 462 | paymentAmount: string, 463 | deploySender: CLPublicKey, 464 | keys?: Keys.AsymmetricKey[] 465 | ) { 466 | const runtimeArgs = RuntimeArgs.fromMap({ 467 | recipient: CLValueBuilder.key(recipient), 468 | sender: CLValueBuilder.key(owner), 469 | token_ids: CLValueBuilder.list(ids.map(id => CLValueBuilder.u256(id))), 470 | }); 471 | 472 | return this.contractClient.callEntrypoint( 473 | 'transfer_from', 474 | runtimeArgs, 475 | deploySender, 476 | this.networkName, 477 | paymentAmount, 478 | keys 479 | ); 480 | } 481 | 482 | /** 483 | * Transfers tokens from the caller's account to another account. 484 | * 485 | * @param recipient The account that will receive the tokens transferred from the caller. 486 | * @param ids Token IDs that will be transferred. 487 | * @param paymentAmount The payment amount that will be used for this Deploy. 488 | * @param deploySender The PublicKey of the Deploy sender. 489 | * @param keys Optional parameter containing a list of keys that can be used to sign the Deploy. 490 | * 491 | * @returns The Deploy that can be sent to the network. 492 | */ 493 | public async transfer( 494 | recipient: CLKeyParameters, 495 | ids: string[], 496 | paymentAmount: string, 497 | deploySender: CLPublicKey, 498 | keys?: Keys.AsymmetricKey[] 499 | ) { 500 | const runtimeArgs = RuntimeArgs.fromMap({ 501 | recipient: CLValueBuilder.key(recipient), 502 | token_ids: CLValueBuilder.list(ids.map(id => CLValueBuilder.u256(id))), 503 | }); 504 | 505 | return this.contractClient.callEntrypoint( 506 | 'transfer', 507 | runtimeArgs, 508 | deploySender, 509 | this.networkName, 510 | paymentAmount, 511 | keys 512 | ); 513 | } 514 | 515 | /** 516 | * Updates the metadata of a token. 517 | * 518 | * @param id The ID of the token to be updated. 519 | * @param meta The new metadata for the token specified. 520 | * @param paymentAmount The payment amount that will be used for this Deploy. 521 | * @param deploySender The PublicKey of the Deploy sender. 522 | * @param keys Optional parameter containing a list of keys that can be used to sign the Deploy. 523 | * 524 | * @returns The Deploy that can be sent to the network. 525 | */ 526 | public async updateTokenMeta( 527 | id: string, 528 | meta: Map, 529 | paymentAmount: string, 530 | deploySender: CLPublicKey, 531 | keys?: Keys.AsymmetricKey[] 532 | ) { 533 | const runtimeArgs = RuntimeArgs.fromMap({ 534 | token_id: CLValueBuilder.u256(id), 535 | token_meta: toCLMap(meta), 536 | }); 537 | 538 | return this.contractClient.callEntrypoint( 539 | 'update_token_meta', 540 | runtimeArgs, 541 | deploySender, 542 | this.networkName, 543 | paymentAmount, 544 | keys 545 | ); 546 | } 547 | } 548 | 549 | -------------------------------------------------------------------------------- /packages/cep47-client/tsconfig.build.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.build.json", 3 | 4 | "compilerOptions": { 5 | "outDir": "./dist", 6 | "baseUrl": "." 7 | }, 8 | 9 | "include": [ 10 | "src/**/*" 11 | ] 12 | } 13 | 14 | -------------------------------------------------------------------------------- /packages/cep47-client/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.build.json", 3 | } 4 | -------------------------------------------------------------------------------- /tsconfig.build.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "allowSyntheticDefaultImports": true, 4 | "noImplicitAny": false, 5 | "noImplicitReturns": true, 6 | "noImplicitThis": true, 7 | "noImplicitUseStrict": true, 8 | "removeComments": true, 9 | "declaration": true, 10 | "target": "es5", 11 | "lib": ["es2015", "dom"], 12 | "module": "commonjs", 13 | "sourceMap": true, 14 | "resolveJsonModule": true, 15 | "typeRoots": ["node_modules/@types"], 16 | "esModuleInterop": true, 17 | "moduleResolution": "node", 18 | "skipLibCheck": true 19 | }, 20 | "exclude": [ 21 | "node_modules", 22 | "**/*.spec..ts" 23 | ] 24 | } 25 | --------------------------------------------------------------------------------