UPDATE:
After doing a lot of reading and experimenting, I think I’ve sorted out what the real issue is, but have yet to figure out how to actually fix things. In the js-sdk documention for makeAssetCreateTxnWithSuggestedParams
, the metadata hash field must be a “Uint8Array or UTF-8 string representation of a hash commitment with respect to the asset. Must be exactly 32 bytes long.” So, my goal is to create a sha256 hash of some metadata (just a string for testing right now) so that it will be exactly 32 bytes (256 bits) long.
Here’s how I generate my hash (using node.js):
const metadata = 'metadata json goes here';
const metadataBuffer = crypto.createHash('sha256').update(metadata, 'utf8').digest();
const metadataHash = new Uint8Array(metadataBuffer);
I’m able to pass this Uint8Array version of the hash into makeAssetCreateTxnWithSuggestedParams
and the transaction is generated without error since it’s a 32-byte Uint8Array.
However, I’m unable to create the transaction if I instead try to pass in a string. I understand that the string needs to be in utf8 representation, but the issue is that when I convert the buffer into a utf8 encoded string (using metadataBuffer.toString('utf8')
), I end up with non-printable/invalid/non-ascii (unsure of the exact term) characters. This seems to cause the sdk to throw an error. My understanding is that the only way to avoid these characters would be to use a binary-to-text encoding like hex or base64. The problem with this is that doing so gives a string that’s longer than 32 characters (64 for hex and 44 for base64). So, it seems like I can’t avoid these kinds of characters when creating the 32 byte utf8 string, which suggests I should just use the Uint8Array and move on from the issue.
I’m totally fine just using the Uint8Array from above (it works after all), but the second issue is that the hash I generate doesn’t seem to match up the hash found in algoexplorer when I look at the created asset.
My code to create the hash
const metadata = 'metadata json goes here';
const metadataBuffer = crypto.createHash('sha256').update(metadata, 'utf8').digest();
const metadataHash = new Uint8Array(metadataBuffer);
console.log(metadataBuffer)
console.log(metadataHash)
console.log(metadataBuffer.toString('utf8'))
console.log(metadataBuffer.toString('base64'))
console.log(metadataBuffer.toString('hex'))
gives the following
<Buffer d6 f0 a1 ea 70 9e 24 3f cd 30 72 ef 87 a9 b2 71 0e b0 02 15 f1 fa c9 08 ee 66 f7 6e 2b 6e 30 03>
Uint8Array(32) [
214, 240, 161, 234, 112, 158, 36, 63,
205, 48, 114, 239, 135, 169, 178, 113,
14, 176, 2, 21, 241, 250, 201, 8,
238, 102, 247, 110, 43, 110, 48, 3
]
���p�$?�0r�q����f�n+n0
1vCh6nCeJD/NMHLvh6mycQ6wAhXx+skI7mb3bituMAM=
d6f0a1ea709e243fcd3072ef87a9b2710eb00215f1fac908ee66f76e2b6e3003
When I create the asset, the transaction assetMetadataHash field matches the Uint8Array of my hash. I submit the transaction and everything goes through. However, when I look on algoexplorer at my asset (Asset ID: 44524145), the metadata hash field doesn’t match any of the console.log() outputs from my code—I see: MXZDaDZuQ2VKRC9OTUhMdmg2bXljUTZ3QWhYeCtza0k3bWIzYml0dU1BTT0=
. It’s also particularly strange that the hash on algoexplorer is 60 characters. I’ve created this asset twice and the incorrect hash is at least the same both times.
I tried to be clever and also made the note field equal to the same Uint8Array as the metadata hash. Interestingly, this seems to not be corrupted??? On algoexplorer, I see 1vCh6nCeJD/NMHLvh6mycQ6wAhXx+skI7mb3bituMAM=
, which matches the base64 encoding of the has from my console.log() output above.
One other thing to note is that for the purposes of getting up and running quickly, I’m using the algoexplorer API to interact with the blockchain instead of using an algod client for now. I’m not sure if somehow the API is mucking up the hash somehow. To test this, I just did the exact same thing, but instead of using a real sha256 hash, I just used 32 characters (this is a total of 32 characters
) as my “hash.” In doing so, I don’t have any issues when I create the string and pass the string to makeAssetCreateTxnWithSuggestedParams
since all the characters are printable. When I look on algoexplorer at my new asset (Asset ID: 44526747), I again see that the metadata hash doesn’t match. This seems to suggest that either the API is mucking up something with the metadata hash when I submit it or that the hash displayed on algoexplorer is encoded in some way that isn’t clear to me (it looks like base64?).