Skip to content
Draft
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
377 changes: 377 additions & 0 deletions scripts/nft-escrow-e2e.sh
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think for the merge into Starlight, this file could be deleted?

Large diffs are not rendered by default.

13 changes: 9 additions & 4 deletions src/boilerplate/circuit/zokrates/nodes/BoilerplateGenerator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -377,10 +377,15 @@ class BoilerplateGenerator {

encryption = () => ({});

mapping = (bpSection) => ({
mappingName: this.mappingName,
mappingKeyName: bpSection === 'postStatements' ? this.mappingKeyName : bpSection === 'parameters' ? this.mappingKeyName.split('.')[0] : this.mappingKeyName.replace('.', 'dot'),
});
mapping = (bpSection) => {
// Get perParameters from the binding's node
const perParameters = this.indicators?.binding?.node?.perParameters || this.indicators?.node?.perParameters || [];
return {
mappingName: this.mappingName,
mappingKeyName: bpSection === 'postStatements' ? this.mappingKeyName : bpSection === 'parameters' ? this.mappingKeyName.split('.')[0] : this.mappingKeyName.replace('.', 'dot'),
...(perParameters.length > 0 && { perParameters }),
};
};

/** Partitioned states need boilerplate for an incrementation/decrementation, because it's so weird and different from `a = a - b`. Whole states inherit directly from the AST, so don't need boilerplate here. */
incrementation = (extraParams) => {
Expand Down
71 changes: 61 additions & 10 deletions src/boilerplate/circuit/zokrates/raw/BoilerplateGenerator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -495,26 +495,77 @@ class BoilerplateGenerator {
];
},

parameters({ mappingKeyName: k, mappingKeyTypeName: t }): string[] {
if (t === 'local') return [];
return [
`private ${t ? t : 'field'} ${k}`, // must be a field, in case we need to do arithmetic on it.
];
/**
* Generate circuit parameters for mapping
* Includes domain parameters if present
*/
parameters({ mappingKeyName: k, mappingKeyTypeName: t, perParameters = [] }): string[] {
const params: string[] = [];

// Add domain parameters as private inputs
for (const domainParam of perParameters) {
params.push(`private field ${domainParam.name}`);
}

// Add mapping key parameter
if (t !== 'local') {
params.push(`private ${t ? t : 'field'} ${k}`);
}

return params;
},

preStatements({ id: mappingId, mappingName: m }): string[] {
return [
/**
* Generate pre-statements for mapping
* Includes domain parameter hashing if present
*/
preStatements({ id: mappingId, mappingName: m, perParameters = [] }): string[] {
const statements: string[] = [
`
// We need to hard-code the mappingId's of mappings into the circuit:
field ${m}_mappingId = ${mappingId};`,
];

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe just fix the indenting here

// Generate chained MiMC hashing for domain parameters
if (perParameters.length > 0) {
let currentHash = `${m}_mappingId`;

for (let i = 0; i < perParameters.length; i++) {
const domainParam = perParameters[i];
const nextHashVar = `${m}_perHash_${i}`;

statements.push(
`
// Chain domain parameter: ${domainParam.name}
field ${nextHashVar} = mimc2([${currentHash}, ${domainParam.name}]);`,
);

currentHash = nextHashVar;
}

statements.push(
`
// Final domain-chained hash
field ${m}_domainChainedId = ${currentHash};`,
);
}

return statements;
},

postStatements({ name: x, mappingName: m, mappingKeyName: k }): string[] {
// const x = `${m}_${k}`;
/**
* Generate post-statements for mapping
* Calculates final stateVarId with domain parameter support
*/
postStatements({ name: x, mappingName: m, mappingKeyName: k, perParameters = [] }): string[] {
// Use chained hash if domain parameters exist, otherwise use mappingId
const baseId = perParameters.length > 0
? `${m}_domainChainedId`
: `${m}_mappingId`;

return [
`
field ${x}_stateVarId_field = mimc2([${m}_mappingId, ${k}]);`,
field ${x}_stateVarId_field = mimc2([${baseId}, ${k}]);`,
];
},
};
Expand Down
53 changes: 47 additions & 6 deletions src/boilerplate/common/commitment-storage.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -35,19 +35,33 @@ export function formatCommitment (commitment) {
preimage.value = generalise(commitment.preimage.value).all
? generalise(commitment.preimage.value).all.integer
: generalise(commitment.preimage.value).integer

// Format domain parameters if they exist
const domainParameters = commitment.domainParameters
? Object.fromEntries(
Object.entries(commitment.domainParameters).map(([key, value]) => [
key,
generalise(value).integer
])
)
: null;

data = {
_id: commitment.hash.hex(32),
name: commitment.name,
source: commitment.source,
mappingKey: commitment.mappingKey ? commitment.mappingKey : null,
domainParameters,
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}`)
} catch (error) {
console.error('Error --->', error)
console.error('Error formatting commitment --->', error)
console.error('Commitment object:', JSON.stringify(commitment, null, 2))
throw error
}
return data
}
Expand All @@ -58,9 +72,20 @@ export async function persistCommitment (data) {
return db.collection(COMMITMENTS_COLLECTION).insertOne(data)
}
// function to format a commitment for a mongo db and store it
export async function storeCommitment (commitment) {
const data = formatCommitment(commitment)
return persistCommitment(data)
export async function storeCommitment (commitment, context) {
const data = formatCommitment(commitment, context)
if (!data) {
console.error('formatCommitment returned undefined/null data')
throw new Error('Failed to format commitment')
}
try {
const result = await persistCommitment(data)
logger.debug(`Successfully persisted commitment ${data._id}`)
return result
} catch (error) {
console.error('Error persisting commitment:', error)
throw error
}
}

// function to retrieve commitment with a specified stateVarId
Expand All @@ -86,11 +111,19 @@ export async function getCurrentWholeCommitment(id) {
}

// function to retrieve commitment with a specified stateName
export async function getCommitmentsByState(name, mappingKey = null) {
export async function getCommitmentsByState(name, mappingKey = null, domainParameters = null) {
const connection = await mongo.connection(MONGO_URL);
const db = connection.db(COMMITMENTS_DB);
const query = { name: name };
if (mappingKey) query['mappingKey'] = generalise(mappingKey).integer;

// Add domain parameter filters if provided
if (domainParameters) {
for (const [key, value] of Object.entries(domainParameters)) {
query[`domainParameters.${key}`] = generalise(value).integer;
}
}

const commitments = await db
.collection(COMMITMENTS_COLLECTION)
.find(query)
Expand Down Expand Up @@ -139,11 +172,19 @@ export async function getBalance() {
return sumOfValues;
}

export async function getBalanceByState(name, mappingKey = null) {
export async function getBalanceByState(name, mappingKey = null, domainParameters = null) {
const connection = await mongo.connection(MONGO_URL);
const db = connection.db(COMMITMENTS_DB);
const query = { name: name };
if (mappingKey) query['mappingKey'] = generalise(mappingKey).integer;

// Add domain parameter filters if provided
if (domainParameters) {
for (const [key, value] of Object.entries(domainParameters)) {
query[`domainParameters.${key}`] = generalise(value).integer;
}
}

const commitments = await db
.collection(COMMITMENTS_COLLECTION)
.find(query)
Expand Down
8 changes: 7 additions & 1 deletion src/boilerplate/common/contract.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,13 @@ export async function getContractInstance(contractName, deployedAddress) {

export async function getContractBytecode(contractName) {
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this change necessary?

const contractInterface = await getContractInterface(contractName);
return contractInterface.evm.bytecode.object;
// Support both Hardhat format (bytecode) and Truffle/Solc format (evm.bytecode.object)
if (contractInterface.bytecode) {
return contractInterface.bytecode;
} else if (contractInterface.evm?.bytecode?.object) {
return contractInterface.evm.bytecode.object;
}
throw new Error(`Bytecode not found for contract ${contractName}`);
}

export async function deploy(
Expand Down
8 changes: 6 additions & 2 deletions src/boilerplate/common/migrations/metadata.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,11 +48,15 @@ function saveMetadata (
// console.log("hardhatArtifactPath: ", hardhatArtifactPath);

const compilationData = fs.readFileSync(hardhatArtifactPath, 'utf-8')
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are these changes necessary?

const abi = JSON.parse(compilationData).abi
const contractNameFromHardhat = JSON.parse(compilationData).contractName
const compiledContract = JSON.parse(compilationData)
const abi = compiledContract.abi
const contractNameFromHardhat = compiledContract.contractName
const bytecode = compiledContract.bytecode

deployedMetadata.abi = abi
deployedMetadata.contractName = contractNameFromHardhat
// Save bytecode for runtime deployment (needed for deployNFT endpoint)
deployedMetadata.bytecode = bytecode
deployedPositionMetadata.address = contractDeployedAddress
deployedPositionMetadata.blockNumber = blockNumber
deployedPositionMetadata.transactionHash = transactionHash
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,15 @@ export function buildPrivateStateNode(nodeType: string, fields: any = {}): any {
switch (nodeType) {
case 'InitialisePreimage': {
const { privateStateName, id, accessedOnly = false, indicator = {} } = fields;
// For MappingKey indicators, access binding through container
const binding = indicator.binding || indicator.container?.binding;
return {
privateStateName,
stateVarId: id,
accessedOnly,
mappingKey: indicator.isMapping ? indicator.referencedKeyName || indicator.keyPath.node.name : null,
mappingName: indicator.isMapping ? indicator.node?.name : null,
perParameters: indicator.isMapping && binding?.node?.perParameters ? binding.node.perParameters : undefined,
structProperties: indicator.isStruct ? Object.keys(indicator.structProperties) : null,
};
}
Expand All @@ -29,6 +32,8 @@ export function buildPrivateStateNode(nodeType: string, fields: any = {}): any {
accessedOnly,
indicator = {},
} = fields;
// For MappingKey indicators, access binding through container
const binding = indicator.binding || indicator.container?.binding;
return {
increment,
stateVarId: id,
Expand All @@ -38,6 +43,7 @@ export function buildPrivateStateNode(nodeType: string, fields: any = {}): any {
structProperties: indicator.isStruct ? Object.keys(indicator.structProperties) : null,
mappingKey: indicator.isMapping ? indicator.referencedKeyName || indicator.keyPath.node.name : null,
mappingName: indicator.isMapping ? indicator.node?.name : null,
perParameters: indicator.isMapping && binding?.node?.perParameters ? binding.node.perParameters : undefined,
nullifierRequired: indicator.isNullified,
reinitialisedOnly,
accessedOnly,
Expand All @@ -56,6 +62,8 @@ export function buildPrivateStateNode(nodeType: string, fields: any = {}): any {
}
case 'WritePreimage': {
const { id, increment, burnedOnly, reinitialisedOnly, indicator = {} } = fields
// For MappingKey indicators, access binding through container
const binding = indicator.binding || indicator.container?.binding;
return {
increment,
stateVarId: id,
Expand All @@ -65,6 +73,7 @@ export function buildPrivateStateNode(nodeType: string, fields: any = {}): any {
structProperties: indicator.isStruct ? indicator.referencingPaths[0]?.getStructDeclaration()?.members.map(m => m.name) : null,
mappingKey: indicator.isMapping ? indicator.referencedKeyName || indicator.keyPath.node.name : null,
mappingName: indicator.isMapping ? indicator.node?.name : null,
perParameters: indicator.isMapping && binding?.node?.perParameters ? binding.node.perParameters : undefined,
nullifierRequired: indicator.isNullified,
burnedOnly,
reinitialisedOnly,
Expand Down Expand Up @@ -132,6 +141,8 @@ export function buildPrivateStateNode(nodeType: string, fields: any = {}): any {
}
case 'CalculateCommitment': {
const { id, increment, privateStateName, indicator = {} } = fields;
// For MappingKey indicators, access binding through container
const binding = indicator.binding || indicator.container?.binding;
return {
privateStateName,
stateVarId: id,
Expand All @@ -141,6 +152,7 @@ export function buildPrivateStateNode(nodeType: string, fields: any = {}): any {
isPartitioned: indicator.isPartitioned,
nullifierRequired: indicator.isNullified,
structProperties: indicator.isStruct ? indicator.referencingPaths[0]?.getStructDeclaration()?.members.map(m => m.name) : null,
perParameters: indicator.isMapping && binding?.node?.perParameters ? binding.node.perParameters : undefined,
isOwned: indicator.isOwned,
mappingOwnershipType: indicator.mappingOwnershipType,
owner: indicator.isOwned
Expand All @@ -163,6 +175,8 @@ export function buildPrivateStateNode(nodeType: string, fields: any = {}): any {
localMappingKey,
} = fields;
const structProperties = !indicator.isStruct ? null : indicator.isAccessed ? indicator.referencingPaths[0]?.getStructDeclaration()?.members.map(m => m.name) : Object.keys(indicator.structProperties);
// For MappingKey indicators, access binding through container
const binding = indicator.binding || indicator.container?.binding;
return {
privateStateName,
stateVarId: id,
Expand All @@ -174,6 +188,7 @@ export function buildPrivateStateNode(nodeType: string, fields: any = {}): any {
increment,
structProperties,
isMapping: indicator.isMapping,
perParameters: indicator.isMapping && binding?.node?.perParameters ? binding.node.perParameters : undefined,
isWhole: indicator.isWhole,
isPartitioned: indicator.isPartitioned,
isOwned: indicator.isOwned,
Expand All @@ -192,12 +207,15 @@ export function buildPrivateStateNode(nodeType: string, fields: any = {}): any {

case 'EncryptBackupPreimage': {
const { id, increment, privateStateName, indicator = {} } = fields;
// For MappingKey indicators, access binding through container
const binding = indicator.binding || indicator.container?.binding;
return {
privateStateName,
stateVarId: id,
increment,
mappingKey: indicator.isMapping ? indicator.referencedKeyName || indicator.keyPath.node.name : null,
mappingName: indicator.isMapping ? indicator.node?.name : null,
perParameters: indicator.isMapping && binding?.node?.perParameters ? binding.node.perParameters : undefined,
isWhole: indicator.isWhole,
isPartitioned: indicator.isPartitioned,
nullifierRequired: indicator.isNullified,
Expand Down Expand Up @@ -235,12 +253,15 @@ export function buildPrivateStateNode(nodeType: string, fields: any = {}): any {

case 'buildBoilerplateReciever': {
const { id, increment, privateStateName, indicator = {} } = fields;
// For MappingKey indicators, access binding through container
const binding = indicator.binding || indicator.container?.binding;
return {
privateStateName,
stateVarId: id,
increment,
mappingKey: indicator.isMapping ? indicator.referencedKeyName || indicator.keyPath.node.name : null,
mappingName: indicator.isMapping ? indicator.node?.name : null,
perParameters: indicator.isMapping && binding?.node?.perParameters ? binding.node.perParameters : undefined,
isWhole: indicator.isWhole,
isPartitioned: indicator.isPartitioned,
structProperties: indicator.isStruct ? indicator.referencingPaths[0]?.getStructDeclaration()?.members.map(m => m.name) : null,
Expand Down Expand Up @@ -283,11 +304,12 @@ export function buildBoilerplateNode(nodeType: string, fields: any = {}): any {
};
}
case 'ReadPreimage': {
const { contractName, privateStates = {} } = fields;
const { contractName, privateStates = {}, inputParameters = [] } = fields;
return {
nodeType,
privateStates,
contractName,
inputParameters,
};
}
case 'WritePreimage': {
Expand Down
Loading
Loading