diff --git a/algorand/Dockerfile b/algorand/Dockerfile index 3a3a9f3a1..3d6d80a16 100644 --- a/algorand/Dockerfile +++ b/algorand/Dockerfile @@ -19,5 +19,6 @@ RUN pipenv install RUN mkdir teal COPY *.py . +COPY test/*.json . COPY deploy.sh deploy.sh COPY .env .env diff --git a/algorand/admin.py b/algorand/admin.py index 383c5e2ba..595555258 100644 --- a/algorand/admin.py +++ b/algorand/admin.py @@ -1,5 +1,6 @@ # python3 -m pip install pycryptodomex uvarint pyteal web3 coincurve +import os from os.path import exists from time import time, sleep from eth_abi import encode_single, encode_abi @@ -1187,6 +1188,65 @@ class PortalCore: self.client.send_transactions(signedTxns) print("Sent some ALGO to: " + wallet) + print("Creating a Token...") + txn = transaction.AssetConfigTxn( + sender=a.getAddress(), + sp=suggestedParams, + total=1000000, + default_frozen=False, + unit_name="NORIUM", + asset_name="ChuckNorium", + manager=a.getAddress(), + reserve=a.getAddress(), + freeze=a.getAddress(), + clawback=a.getAddress(), + strict_empty_address_check=False, + decimals=6) + stxn = txn.sign(a.getPrivateKey()) + txid = self.client.send_transaction(stxn) + print("NORIUM creation transaction ID: {}".format(txid)) + confirmed_txn = transaction.wait_for_confirmation(self.client, txid, 4) + print("TXID: ", txid) + print("Result confirmed in round: {}".format(confirmed_txn['confirmed-round'])) + + print("Creating an NFT...") + # JSON file + dir_path = os.path.dirname(os.path.realpath(__file__)) + f = open (dir_path + 'cnNftMetadata.json', "r") + + # Reading from file + metadataJSON = json.loads(f.read()) + metadataStr = json.dumps(metadataJSON) + + hash = hashlib.new("sha512_256") + hash.update(b"arc0003/amj") + hash.update(metadataStr.encode("utf-8")) + json_metadata_hash = hash.digest() + print("json_metadata_hash: ", hash.hexdigest()) + + # Create transaction + txn = transaction.AssetConfigTxn( + sender=a.getAddress(), + sp=suggestedParams, + total=1, + default_frozen=False, + unit_name="CNART", + asset_name="ChuckNoriumArtwork@arc3", + manager=a.getAddress(), + reserve=a.getAddress(), + freeze=a.getAddress(), + clawback=a.getAddress(), + strict_empty_address_check=False, + url="file://cnNftMetadata.json", + metadata_hash=json_metadata_hash, + decimals=0) + stxn = txn.sign(a.getPrivateKey()) + txid = self.client.send_transaction(stxn) + print("NORIUM NFT creation transaction ID: {}".format(txid)) + confirmed_txn = transaction.wait_for_confirmation(self.client, txid, 4) + print("TXID: ", txid) + print("Result confirmed in round: {}".format(confirmed_txn['confirmed-round'])) + if exists(self.args.env): if self.gt == None: self.gt = GenTest(False) diff --git a/algorand/test/cnNftMetadata.json b/algorand/test/cnNftMetadata.json new file mode 100644 index 000000000..8fc7f4444 --- /dev/null +++ b/algorand/test/cnNftMetadata.json @@ -0,0 +1,25 @@ +{ + "name": "CNART", + "description": "ChuckNoriumArtwork", + "image": "https://pngimg.com/image/31756", + "image_integrity": "sha256-/tih/7ew0eziEZIVD4qoTWb0YrElAuRG3b40SnEstyk=", + "properties": { + "simple_property": "ChuckNorium artwork", + "rich_property": { + "name": "ChuckNoriumArt", + "value": "001", + "display_value": "001", + "class": "emphasis", + "css": { + "color": "#ffffff", + "font-weight": "bold", + "text-decoration": "underline" + } + }, + "array_property": { + "name": "Artwork", + "value": [1, 2, 3, 4], + "class": "emphasis" + } + } +} diff --git a/sdk/js/src/algorand/__tests__/testHelpers.ts b/sdk/js/src/algorand/__tests__/testHelpers.ts index f533069de..d852b5344 100644 --- a/sdk/js/src/algorand/__tests__/testHelpers.ts +++ b/sdk/js/src/algorand/__tests__/testHelpers.ts @@ -204,21 +204,21 @@ export async function getBalances( ): Promise> { let balances = new Map(); const accountInfo = await client.accountInformation(account).do(); - // console.log("Account Info:", accountInfo); - // console.log("Account Info|created-assets:", accountInfo["created-assets"]); + console.log("Account Info:", accountInfo); + console.log("Account Info|created-assets:", accountInfo["created-assets"]); // Put the algo balance in key 0 balances.set(0, accountInfo.amount); const assets: Array = accountInfo.assets; - // console.log("assets", assets); + console.log("assets", assets); assets.forEach(function (asset) { - // console.log("inside foreach", asset); + console.log("inside foreach", asset); const assetId = asset["asset-id"]; const amount = asset.amount; balances.set(assetId, amount); }); - // console.log("balances", balances); + console.log("balances", balances); return balances; } @@ -267,11 +267,13 @@ export async function createAsset(account: Account): Promise { // Used to display asset units to user const unitName = "NORIUM"; // Friendly name of the asset - const assetName = "chuckNorium"; + const assetName = "ChuckNorium"; // Optional string pointing to a URL relating to the asset - const assetURL = "http://www.chucknorris.com"; + // const assetURL = "http://www.chucknorris.com"; + const assetURL = ""; // Optional hash commitment of some sort relating to the asset. 32 character length. - const assetMetadataHash = "16efaa3924a6fd9d3a4824799a4ac65d"; + // const assetMetadataHash = "16efaa3924a6fd9d3a4824799a4ac65d"; + const assetMetadataHash = ""; // The following parameters are the only ones // that can be changed, and they have to be changed // by the current manager @@ -323,6 +325,74 @@ export async function createAsset(account: Account): Promise { return assetID; } +export async function createNFT(account: Account): Promise { + console.log("Creating NFT..."); + const aClient = getAlgoClient(); + const params = await aClient.getTransactionParams().do(); + // Asset creation specific parameters + const addr = account.addr; + // Whether user accounts will need to be unfrozen before transacting + const defaultFrozen = false; + // integer number of decimals for asset unit calculation + const decimals = 0; + // total number of this asset available for circulation + const total = 1; + // Used to display asset units to user + const unitName = "CNART"; + // Friendly name of the asset + const assetName = "ChuckNoriumArtwork@arc3"; + // Optional string pointing to a URL relating to the asset + const assetURL = "http://www.chucknorris.com"; + // Optional hash commitment of some sort relating to the asset. 32 character length. + const assetMetadataHash = "16efaa3924a6fd9d3a4824799a4ac65d"; + // The following parameters are the only ones + // that can be changed, and they have to be changed + // by the current manager + // Specified address can change reserve, freeze, clawback, and manager + const manager = account.addr; + // Specified address is considered the asset reserve + // (it has no special privileges, this is only informational) + const reserve = account.addr; + // Specified address can freeze or unfreeze user asset holdings + const freeze = account.addr; + // Specified address can revoke user asset holdings and send + // them to other addresses + const clawback = account.addr; + + // signing and sending "txn" allows "addr" to create an asset + const txn = algosdk.makeAssetCreateTxnWithSuggestedParamsFromObject({ + from: addr, + total, + decimals, + assetName, + unitName, + assetURL, + assetMetadataHash, + defaultFrozen, + freeze, + manager, + clawback, + reserve, + suggestedParams: params, + }); + + const rawSignedTxn = txn.signTxn(account.sk); + // console.log("rawSignedTxn:", rawSignedTxn); + const tx = await aClient.sendRawTransaction(rawSignedTxn).do(); + + // wait for transaction to be confirmed + const ptx = await algosdk.waitForConfirmation(aClient, tx.txId, 4); + // Get the new asset's information from the creator account + const assetID: number = ptx["asset-index"]; + console.log( + "createNFT() - Transaction " + + tx.txId + + " confirmed in round " + + ptx["confirmed-round"] + ); + return assetID; +} + export async function getForeignAssetFromVaaAlgorand( client: Algodv2, tokenBridgeId: bigint, diff --git a/sdk/js/src/algorand/__tests__/unit.ts b/sdk/js/src/algorand/__tests__/unit.ts index b9804289d..797f3e4b0 100644 --- a/sdk/js/src/algorand/__tests__/unit.ts +++ b/sdk/js/src/algorand/__tests__/unit.ts @@ -12,7 +12,12 @@ import { optin, _parseVAAAlgorand, } from "../Algorand"; -import { getAlgoClient, getTempAccounts } from "./testHelpers"; +import { + createNFT, + getAlgoClient, + getBalances, + getTempAccounts, +} from "./testHelpers"; import { PopulateData, TmplSig } from "../TmplSig"; const CORE_ID = BigInt(4); @@ -171,5 +176,24 @@ describe("Unit Tests", () => { done(); })(); }); + test("Create NFT", (done) => { + (async () => { + try { + console.log("Starting account exists..."); + const client: algosdk.Algodv2 = getAlgoClient(); + const tempAccts: Account[] = await getTempAccounts(); + const numAccts: number = tempAccts.length; + expect(numAccts).toBeGreaterThan(0); + const wallet: Account = tempAccts[0]; + const b = await getBalances(client, wallet.addr); + const nftId = await createNFT(wallet); + const balances = await getBalances(client, wallet.addr); + } catch (e) { + console.error("Create NFT error:", e); + expect(false).toBe(true); + } + done(); + })(); + }); }); });