Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
79 changes: 41 additions & 38 deletions apitest.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ const { expect } = chai;
chai.use(chaiHttp);
chai.use(chaiAsPromised);

const parseAddressValue = value => BigInt(value);
const expectedSenderAddress = 1390849295786071768276380950238675083608645509734n;

const testedZapps = [];
const zappLogs = new Map(); // Store logs for each zapp
const displayedZapps = new Set(); // Track which ZApps have already had logs displayed
Expand Down Expand Up @@ -1254,20 +1257,20 @@ describe('NFT_Escrow Zapp', () => {
});
it('Check values of commitment', async () => {
expect(
parseInt(res.NFT_Escrow[8].body.commitments[0].preimage.value, 10),
).to.equal(1390849295786071768276380950238675083608645509734);
parseAddressValue(res.NFT_Escrow[8].body.commitments[0].preimage.value),
).to.equal(expectedSenderAddress);
expect(
parseInt(res.NFT_Escrow[8].body.commitments[1].preimage.value, 10),
).to.equal(235);
parseAddressValue(res.NFT_Escrow[8].body.commitments[1].preimage.value),
).to.equal(235n);
expect(
parseInt(res.NFT_Escrow[9].body.commitments[0].preimage.value, 10),
).to.equal(1390849295786071768276380950238675083608645509734);
parseAddressValue(res.NFT_Escrow[9].body.commitments[0].preimage.value),
).to.equal(expectedSenderAddress);
expect(
parseInt(res.NFT_Escrow[10].body.commitments[0].preimage.value, 10),
).to.equal(1390849295786071768276380950238675083608645509734);
parseAddressValue(res.NFT_Escrow[10].body.commitments[0].preimage.value),
).to.equal(expectedSenderAddress);
expect(
parseInt(res.NFT_Escrow[10].body.commitments[1].preimage.value, 10),
).to.equal(578);
parseAddressValue(res.NFT_Escrow[10].body.commitments[1].preimage.value),
).to.equal(578n);
});
it('Check commitments are correct after deleting and restoring from backup', async () => {
expect(res.NFT_Escrow[12].body.commitments.length).to.equal(6);
Expand Down Expand Up @@ -1440,21 +1443,21 @@ describe('Swap Zapp', () => {
parseInt(res.Swap[6].body.commitments[4].preimage.value, 10),
).to.equal(170); // startSwap balance: 200-30
expect(res.Swap[6].body.commitments[6].name).to.equal("swapProposals");
expect(res.Swap[6].body.commitments[6].preimage.value).to.deep.equal({
swapAmountSent: '30',
swapTokenSent: '1',
swapTokenRecieved: '2',
swapInitiator: '1390849295786071768276380950238675083608645509734',
pendingStatus: '1',
});
expect(res.Swap[6].body.commitments[6].preimage.value.swapAmountSent).to.equal('30');
expect(res.Swap[6].body.commitments[6].preimage.value.swapTokenSent).to.equal('1');
expect(res.Swap[6].body.commitments[6].preimage.value.swapTokenRecieved).to.equal('2');
expect(
parseAddressValue(res.Swap[6].body.commitments[6].preimage.value.swapInitiator),
).to.equal(expectedSenderAddress);
expect(res.Swap[6].body.commitments[6].preimage.value.pendingStatus).to.equal('1');
expect(res.Swap[6].body.commitments[10].name).to.equal("swapProposals");
expect(res.Swap[6].body.commitments[10].preimage.value).to.deep.equal({
swapAmountSent: '0',
swapTokenSent: '1',
swapTokenRecieved: '2',
swapInitiator: '1390849295786071768276380950238675083608645509734',
pendingStatus: '0',
});
expect(res.Swap[6].body.commitments[10].preimage.value.swapAmountSent).to.equal('0');
expect(res.Swap[6].body.commitments[10].preimage.value.swapTokenSent).to.equal('1');
expect(res.Swap[6].body.commitments[10].preimage.value.swapTokenRecieved).to.equal('2');
expect(
parseAddressValue(res.Swap[6].body.commitments[10].preimage.value.swapInitiator),
).to.equal(expectedSenderAddress);
expect(res.Swap[6].body.commitments[10].preimage.value.pendingStatus).to.equal('0');
});
it('Check commitments are correct after deleting and restoring from backup', async () => {
// Note the order of the commitments has changed because some are decrypted with the shared secret key
Expand All @@ -1481,20 +1484,20 @@ describe('Swap Zapp', () => {
parseInt(res.Swap[8].body.commitments[4].preimage.value, 10),
).to.equal(170); // startSwap balance: 200-30
expect(res.Swap[8].body.commitments[9].name).to.equal("swapProposals");
expect(res.Swap[8].body.commitments[9].preimage.value).to.deep.equal({
swapAmountSent: '30',
swapTokenSent: '1',
swapTokenRecieved: '2',
swapInitiator: '1390849295786071768276380950238675083608645509734',
pendingStatus: '1',
});
expect(res.Swap[8].body.commitments[9].preimage.value.swapAmountSent).to.equal('30');
expect(res.Swap[8].body.commitments[9].preimage.value.swapTokenSent).to.equal('1');
expect(res.Swap[8].body.commitments[9].preimage.value.swapTokenRecieved).to.equal('2');
expect(
parseAddressValue(res.Swap[8].body.commitments[9].preimage.value.swapInitiator),
).to.equal(expectedSenderAddress);
expect(res.Swap[8].body.commitments[9].preimage.value.pendingStatus).to.equal('1');
expect(res.Swap[8].body.commitments[10].name).to.equal("swapProposals");
expect(res.Swap[8].body.commitments[10].preimage.value).to.deep.equal({
swapAmountSent: '0',
swapTokenSent: '1',
swapTokenRecieved: '2',
swapInitiator: '1390849295786071768276380950238675083608645509734',
pendingStatus: '0',
});
expect(res.Swap[8].body.commitments[10].preimage.value.swapAmountSent).to.equal('0');
expect(res.Swap[8].body.commitments[10].preimage.value.swapTokenSent).to.equal('1');
expect(res.Swap[8].body.commitments[10].preimage.value.swapTokenRecieved).to.equal('2');
expect(
parseAddressValue(res.Swap[8].body.commitments[10].preimage.value.swapInitiator),
).to.equal(expectedSenderAddress);
expect(res.Swap[8].body.commitments[10].preimage.value.pendingStatus).to.equal('0');
});
});
13 changes: 7 additions & 6 deletions doc/STATUS.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,10 @@ Do note that `LoanSimple.zol` don't currently compile - we are actively working
- Constructors are supported, but be aware that the output shield contract will contain a constructor combining the `.zol` constructor and some extra functionality.
- Functions can have any number of secret or public parameters of the types below.
- Any number of states, secret or public:
- Secret states can have types `uint256`, `bool`, `address`, `mapping`, `array` (one dimensional only), `struct`, or mappings to structs (e.g., `mapping(uint256 => MyStruct)`).
- Keys of secret mappings can be `uint256` or `address`.
- Arrays are only supported with element types `address` or `uint256`.
- Structs can only have properties with types `uint256`, `bool` or `address`.
- Secret states can have types `uint256`, `bool`, `address`, `bytes20`, `mapping`, `array` (one dimensional only), `struct`, or mappings to structs (e.g., `mapping(uint256 => MyStruct)`).
- Keys of secret mappings can be `uint256`, `bytes20` or `address`.
- Arrays are only supported with element types `uint256`, `address`, or `bytes20`.
- Structs can only have properties with types `uint256`, `bool`, `address`, or `bytes20`.
- All other types (e.g. `u32`), except for Enums, can be used as long as they aren't secret or interact with secret states. Enums are not supported, even if they are public and don't interact with secret states.
- Public and secret states *can* interact within functions, but this may break the output zApp or render its privacy useless.
- Secret states can be *overwritten* on each edit (i.e. they are whole) or *incremented* on each edit (i.e. they are partitioned) - the compiler will work this out for you based on what states are known or unknown to the caller.
Expand Down Expand Up @@ -70,7 +70,8 @@ Here we summarise the as of yet unsupported Solidity syntax.
- Conditions like `if(a)` or `if(flag)` are not supported. Use explicit comparisons, e.g., `if(a == true)`.
- **Logical expressions with mixed `&&` and `||` operators:**
- Nested logical operators without brackets (e.g., `if(a && b || c)`) are not supported. Use brackets to clarify logic, e.g., `if((a && b) || c)`.
- **Secret variables named `key` or starting with `_`:**
- Zokrates does not support secret variables named `key` or starting with an underscore (e.g., `_value`).
- **Variables with reserved names, and secret variables starting with `_`:**
- Zokrates does not support variables with these names: `key`, `secretKey`, `publicKey`, `sharedSecretKey`, `sharedPublicKey`, `keys`, `instance`, `contractAddr`, `web3`, `BackupData`, `msgSender`, `msgValue`, `allInputs`, `res`, `proof`, `txData`, `txParams`, `tx`, `signed`, `sendTxn`, `encEvent`, `encBackupEvent`, `publicReturns`.
- Zokrates also does not support secret variables starting with an underscore (e.g., `_value`).
- **Other limitations:**
- The compiler will throw errors for unsupported patterns, often with suggestions for workarounds.
2 changes: 1 addition & 1 deletion doc/WRITEUP.md
Original file line number Diff line number Diff line change
Expand Up @@ -519,7 +519,7 @@ myMapping[key] = value, is stored at storage slot `hash( key, id )`

#### zApps' commitment structures

For our current phase of work, we support `uint256` and `address` basic types, `structs`, `arrays`, and `mapping` (including mappings to structs).
For our current phase of work, we support `uint256`, `bool`, `address`, and `bytes20` basic types, plus `structs`, `arrays`, and `mapping` (including mappings to structs).

Consider this incomplete `.zol` contract:

Expand Down
32 changes: 23 additions & 9 deletions src/boilerplate/common/backup-encrypted-data-listener.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -252,15 +252,25 @@ export default class BackupEncryptedDataEventListener {
eventData.returnValues.encPreimages[i];
let { varName } = eventData.returnValues.encPreimages[i];
const name = varName.split(' ')[0];
const structProperties = varName.split('props:')[1]?.trim();
const structMetadata = varName.split('props:')[1]?.trim();
const structProperties = structMetadata?.split(' types:')[0]?.trim();
const structTypeNames =
structMetadata
?.split(' types:')[1]
?.trim()
?.split(' ')
.filter(Boolean) || null;
varName = varName.split('props:')[0]?.trim();
let isArray = false;
let isStruct = false;
if (varName.includes(' a')) {
isArray = true;
}
if (varName.includes(' s')) {
isStruct = true;
const flags = varName.split(' ').slice(1);
const isArray = flags.includes('a');
const isStruct = flags.includes('s');
const isBytes20 = flags.includes('b20');
const isAddress = flags.includes('addr');
let commitmentType = null;
if (isBytes20) {
commitmentType = 'bytes20';
} else if (isAddress) {
commitmentType = 'address';
}
const plainText = decrypt(cipherText, kp.secretKey.hex(32), [
decompressStarlightKey(generalise(ephPublicKey))[0].hex(32),
Expand Down Expand Up @@ -299,7 +309,9 @@ export default class BackupEncryptedDataEventListener {
if (isStruct) {
value = {};
count = isArray ? 3 : 2;
for (const prop of structProperties.split(' ')) {
for (
const prop of structProperties?.split(' ').filter(Boolean) || []
) {
value[prop] = plainText[count];
count++;
}
Expand Down Expand Up @@ -377,6 +389,8 @@ export default class BackupEncryptedDataEventListener {
hash: newCommitment,
name,
mappingKey: mappingKey?.integer,
type: commitmentType,
typeNames: structTypeNames,
preimage: {
stateVarId,
value,
Expand Down
80 changes: 64 additions & 16 deletions src/boilerplate/common/commitment-storage.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -21,35 +21,83 @@ const { generalise } = gen;
const keyDb =
process.env.KEY_DB_PATH || '/app/orchestration/common/db/key.json';

export function formatCommitment (commitment) {
let data
const PRINTABLE_ASCII_REGEX = /^[\x20-\x7E]*$/;

const formatPreimageValue = (rawValue, typeName = null) => {
const generalisedValue = generalise(rawValue);
if (typeName === 'bytes20') {
const asciiValue = generalisedValue.all
? generalisedValue.all.ascii
: generalisedValue.ascii;
if (
typeof asciiValue === 'string' &&
PRINTABLE_ASCII_REGEX.test(asciiValue)
) {
return asciiValue;
}
return generalisedValue.all
? generalisedValue.all.hex(20)
: generalisedValue.hex(20);
}
if (typeName === 'address') {
return generalisedValue.all
? generalisedValue.all.hex(32)
: generalisedValue.hex(32);
}
return generalisedValue.all
? generalisedValue.all.integer
: generalisedValue.integer;
};

export function formatCommitment(commitment) {
let data;
try {
const nullifierHash = commitment.secretKey
? poseidonHash([
BigInt(commitment.preimage.stateVarId.hex(32)),
BigInt(commitment.secretKey.hex(32)),
BigInt(commitment.preimage.salt.hex(32))
])
: ''
const preimage = generalise(commitment.preimage).all.hex(32)
preimage.value = generalise(commitment.preimage.value).all
? generalise(commitment.preimage.value).all.integer
: generalise(commitment.preimage.value).integer
BigInt(commitment.preimage.stateVarId.hex(32)),
BigInt(commitment.secretKey.hex(32)),
BigInt(commitment.preimage.salt.hex(32)),
])
: '';
const preimage = generalise(commitment.preimage).all.hex(32);
if (
Array.isArray(commitment.typeNames) &&
commitment.typeNames.length > 0
) {
preimage.value = {};
const rawStructValue = commitment.preimage.value || {};
const structKeys = Object.keys(rawStructValue);
structKeys.forEach((propertyName, index) => {
preimage.value[propertyName] = formatPreimageValue(
rawStructValue[propertyName],
commitment.typeNames[index],
);
});
} else {
preimage.value = formatPreimageValue(
commitment.preimage.value,
commitment.type,
);
}
data = {
_id: commitment.hash.hex(32),
name: commitment.name,
source: commitment.source,
type: commitment.type ?? null,
typeNames: Array.isArray(commitment.typeNames)
? commitment.typeNames
: null,
mappingKey: commitment.mappingKey ? commitment.mappingKey : null,
secretKey: commitment.secretKey ? commitment.secretKey.hex(32) : null,
preimage,
isNullified: commitment.isNullified,
nullifier: commitment.secretKey ? nullifierHash.hex(32) : null
}
logger.debug(`Storing commitment ${data._id}`)
nullifier: commitment.secretKey ? nullifierHash.hex(32) : null,
};
logger.debug(`Storing commitment ${data._id}`);
} catch (error) {
console.error('Error --->', error)
console.error('Error --->', error);
}
return data
return data;
}

export async function persistCommitment (data) {
Expand Down
Loading
Loading