Skip to content

Commit

Permalink
Merge pull request #93 from ArtBlocks/bug-fix--generic-bytes-string-v…
Browse files Browse the repository at this point in the history
…alidity-check

Bug fix: JSON Bytes string validity check
  • Loading branch information
ryley-o committed Sep 10, 2022
2 parents 9bb0e38 + aade988 commit 175ce31
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 8 deletions.
19 changes: 15 additions & 4 deletions src/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -177,10 +177,21 @@ export function arrayToJSONValue(value: string): JSONValue {
// If byte data is parseable to a valid unicode string then do so
// otherwise parse the byte data to a hex string
export function bytesToJSONValue(value: Bytes): JSONValue {
// If the bytes cannot be
let result = json.try_fromString('["' + value.toString() + '"]');
if (result.isError) {
result = json.try_fromString('["' + value.toHexString() + '"]');
// fallback - assume the data is a hex string (always valid)
let result = json.try_fromString('["' + value.toHexString() + '"]');
// If the bytes can be parsed as a string, then losslessly re-encoded into
// UTF-8 bytes, then consider a valid UTF-8 encoded string and store
// string value in json.
// note: Bytes.toString() uses WTF-8 encoding as opposed to UTF-8. Solidity
// encodes UTF-8 strings, so safe assume any string data are UTF-8 encoded.
let stringValue: string = value.toString();
let reEncodedBytesValue: Bytes = Bytes.fromUTF8(stringValue);
if (reEncodedBytesValue.toHexString() == value.toHexString()) {
// if the bytes are the same then the string was valid UTF-8
let potentialResult = json.try_fromString('["' + stringValue + '"]');
if (potentialResult.isOk) {
result = potentialResult;
}
}
return result.value.toArray()[0];
}
Expand Down
3 changes: 2 additions & 1 deletion src/minter-suite-mapping.ts
Original file line number Diff line number Diff line change
Expand Up @@ -727,7 +727,8 @@ export function handleAddManyValueGeneric<T, C>(
) {
stringVal = event.params._value.toHexString();
} else {
stringVal = event.params._value.toString();
// for Bytes, use method to determine if string or hexString
stringVal = bytesToJSONValue(event.params._value).toString();
}
arr.push(stringToJSONString(stringVal));
newValue = arrayToJSONValue(arr.toString());
Expand Down
33 changes: 30 additions & 3 deletions tests/subgraph/minter-suite/minter-suite-mapping.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1620,7 +1620,11 @@ test("handleSetValue should set all values to a designated key in extraMinterDet

// If the bytes are not intended to be a human readable string
// we should instead convert to their hex string representation
const eventValue = randomAddressGenerator.generateRandomAddress();
// Always use the following hex string because valid WTF-8 but not valid
// UTF-8, which is a somewhat common edge-case when dealing with bytes
let eventValue = Bytes.fromHexString(
"0x57e32bd396b7c3337dd6b4a672e6d99b47865e56"
);
const configValueSetEvent4: ConfigValueSetBytes = changetype<
ConfigValueSetBytes
>(newMockEvent());
Expand Down Expand Up @@ -1820,13 +1824,36 @@ test("handleAddManyBytesValue should add a value to an array at a designated key
'{"array":["im bytes"]}'
);

handleAddManyBytesValue(configValueSetEvent);
// add another value, this time with bytes that should format to hex string
const configValueSetEvent2: ConfigValueAddedToSetBytes = changetype<
ConfigValueAddedToSetBytes
>(newMockEvent());
// Always use the following hex string because valid WTF-8 but not valid
// UTF-8, which is a somewhat common edge-case when dealing with bytes
let eventValue = Bytes.fromHexString(
"0x57e32bd396b7c3337dd6b4a672e6d99b47865e56"
);
configValueSetEvent2.address = minterAddress;
configValueSetEvent2.parameters = [
new ethereum.EventParam(
"_projectId",
ethereum.Value.fromUnsignedBigInt(projectId)
),
new ethereum.EventParam(
"_key",
ethereum.Value.fromBytes(Bytes.fromUTF8("array"))
),
new ethereum.EventParam("_value", ethereum.Value.fromBytes(eventValue))
];
configValueSetEvent2.block.timestamp = CURRENT_BLOCK_TIMESTAMP;

handleAddManyBytesValue(configValueSetEvent2);

assert.fieldEquals(
PROJECT_MINTER_CONFIGURATION_ENTITY_TYPE,
getProjectMinterConfigId(minterAddress.toHexString(), project.id),
"extraMinterDetails",
'{"array":["im bytes","im bytes"]}'
'{"array":["im bytes","0x57e32bd396b7c3337dd6b4a672e6d99b47865e56"]}'
);
});
test("handleRemoveValue should remove the key/value from extraMinterDetails", () => {
Expand Down

0 comments on commit 175ce31

Please sign in to comment.